12#if __cpp_lib_ranges_zip >= 202110L
13#define GUANAQO_SPARSE_SUPPORTS_SORTING 1
15#define GUANAQO_SPARSE_SUPPORTS_SORTING 0
22 auto &&inner_idx,
auto &&outer_ptr,
24 using Index = std::remove_cvref_t<
decltype(*std::begin(inner_idx))>;
25 using IndexFrom = std::remove_cvref_t<
decltype(*std::begin(cols))>;
26 using StorageIndex = std::remove_cvref_t<
decltype(*std::begin(outer_ptr))>;
27 static_assert(std::is_same_v<
decltype(idx_0), IndexFrom>);
29 assert(std::size(rows) == std::size(inner_idx));
30 auto cvt_rows = [&](
auto r) {
31 return static_cast<Index
>(r) -
static_cast<Index
>(idx_0);
33 std::ranges::ref_view rows_vw = rows;
34 std::ranges::transform(rows_vw, std::begin(inner_idx), cvt_rows);
36 auto num_cols =
static_cast<IndexFrom
>(std::size(outer_ptr));
37 auto cols_iter = std::begin(cols);
38 for (IndexFrom c = 0; c < num_cols; ++c) {
39 cols_iter = std::lower_bound(cols_iter, std::end(cols), c + idx_0);
40 auto cz =
static_cast<size_t>(c);
41 outer_ptr[cz] =
static_cast<StorageIndex
>(cols_iter - std::begin(cols));
45#if GUANAQO_SPARSE_SUPPORTS_SORTING
48template <
auto cmp,
class... Ts>
50 auto indices = std::views::zip(std::ranges::ref_view{triplets}...);
51 std::ranges::sort(indices, cmp);
60 static constexpr auto cmp = [](
const auto &a,
const auto &b) {
61 return std::tie(std::get<1>(a), std::get<0>(a)) <
62 std::tie(std::get<1>(b), std::get<0>(b));
72 static constexpr auto cmp = [](
const auto &a,
const auto &b) {
73 return std::get<1>(a) < std::get<1>(b);
81template <
class Outer,
class... Inners>
83 if (outer_ptr.size() == 0)
86 static constexpr auto cmp = [](
const auto &a,
const auto &b) {
87 return std::get<0>(a) < std::get<0>(b);
90 for (
decltype(outer_ptr.size()) c = 0; c < outer_ptr.size() - 1; ++c) {
91 auto inner_start = outer_ptr[c];
92 auto inner_end = outer_ptr[c + 1];
93 auto indices = std::views::zip(
94 std::ranges::subrange{std::ranges::begin(inners) + inner_start,
95 std::ranges::begin(inners) + inner_end}...);
96 std::ranges::sort(indices, cmp);
103template <
class... Ts>
105 auto indices = std::views::zip(std::ranges::ref_view{triplets}...);
106 return std::ranges::adjacent_find(indices, std::equal_to<>{}) ==
107 std::ranges::end(indices);
115template <
class Outer,
class Inner>
117 if (outer_ptr.size() == 0)
119 auto is_unique_col = [&](
auto &inner_start) {
120 auto inner_end = (&inner_start)[1];
122 std::ranges::subrange{std::ranges::begin(inner) + inner_start,
123 std::ranges::begin(inner) + inner_end};
124 return std::ranges::adjacent_find(indices, std::equal_to<>{}) ==
125 std::ranges::end(indices);
127 return std::transform_reduce(std::begin(outer_ptr), std::end(outer_ptr) - 1,
128 true, std::logical_and<>{}, is_unique_col);
void sort_triplets(Ts &&...triplets)
Sort the (row, column, value) triplets, by column index first, then row.
bool check_uniqueness_csc(const Outer &outer_ptr, const Inner inner)
Check that no two entries with the same row and column index exist in the given sparse compressed-col...
void convert_triplets_to_ccs(const auto &rows, const auto &cols, auto &&inner_idx, auto &&outer_ptr, auto idx_0=0)
bool check_uniqueness_triplets(Ts &&...triplets)
Check that no two entries with the same row and column index exist in the given sparse coordinate lis...
void sort_rows_csc(const Outer &outer_ptr, Inners &&...inners)
Given a sparse compressed-column storage matrix, sort all row indices within each column.
void sort_triplets_col(Ts &&...triplets)
Sort the (row, column, value) triplets by column index.
void sort_triplets_impl(Ts &&...triplets)