1#ifndef TATAMI_CONVERT_TO_COMPRESSED_SPARSE_H
2#define TATAMI_CONVERT_TO_COMPRESSED_SPARSE_H
11#include "convert_to_sparse_utils.hpp"
29template<
typename Value_,
typename Index_,
typename Count_>
30void count_compressed_sparse_non_zeros_consistent(
33 const Index_ secondary,
38 sanisizer::cast<Count_>(secondary);
42 opt.sparse_extract_value =
false;
43 opt.sparse_extract_index =
false;
44 opt.sparse_ordered_index =
false;
46 parallelize([&](
const int,
const Index_ start,
const Index_ length) ->
void {
48 for (Index_ x = 0; x < length; ++x) {
49 const auto range = wrk->fetch(NULL, NULL);
50 output[start + x] = range.number;
55 parallelize([&](
const int,
const Index_ start,
const Index_ length) ->
void {
58 for (Index_ p = start, pe = start + length; p < pe; ++p) {
59 const auto ptr = wrk->fetch(buffer_v.data());
61 for (Index_ s = 0; s < secondary; ++s) {
62 count += (ptr[s] != 0);
73struct CountCompressedSparseNonZerosOptions {
78template<
typename Value_,
typename Index_,
typename Count_>
79void count_compressed_sparse_non_zeros(
83 const CountCompressedSparseNonZerosOptions& options
85 const Index_ NR = matrix.
nrow();
86 const Index_ NC = matrix.
ncol();
87 const Index_ primary = (row ? NR : NC);
88 const Index_ secondary = (row ? NC : NR);
91 count_compressed_sparse_non_zeros_consistent(matrix, primary, secondary, row, output, options.num_threads);
93 std::fill_n(output, primary, 0);
94 count_sparse_non_zeros_inconsistent(matrix, primary, secondary, row, output, options.num_threads);
98template<
typename InputValue_,
typename InputIndex_,
typename Po
inter_,
typename StoredValue_,
typename StoredIndex_>
99void fill_compressed_sparse_matrix_consistent(
101 const InputIndex_ primary,
102 const InputIndex_ secondary,
104 const Pointer_*
const pointers,
105 StoredValue_*
const output_value,
106 StoredIndex_*
const output_index,
111 opt.sparse_ordered_index =
false;
113 parallelize([&](
const int,
const InputIndex_ start,
const InputIndex_ length) ->
void {
118 for (InputIndex_ p = start, pe = start + length; p < pe; ++p) {
124 const auto range = wrk->fetch(buffer_v.data(), buffer_i.data());
125 const auto offset = pointers[p];
126 std::copy_n(range.value, range.number, output_value + offset);
127 std::copy_n(range.index, range.number, output_index + offset);
129 }, primary, threads);
132 parallelize([&](
const int,
const InputIndex_ start,
const InputIndex_ length) ->
void {
136 for (InputIndex_ p = start, pe = start + length; p < pe; ++p) {
137 const auto ptr = wrk->fetch(buffer_v.data());
138 auto offset = pointers[p];
139 for (InputIndex_ s = 0; s < secondary; ++s) {
140 const auto val = ptr[s];
142 output_value[offset] = val;
143 output_index[offset] = s;
148 }, primary, threads);
152template<
typename InputValue_,
typename InputIndex_,
typename Po
inter_,
typename StoredValue_,
typename StoredIndex_>
153void fill_compressed_sparse_matrix_inconsistent(
155 const InputIndex_ primary,
156 const InputIndex_ secondary,
158 const Pointer_*
const output_ptrs,
159 StoredValue_*
const output_value,
160 StoredIndex_*
const output_index,
161 std::optional<CountNonZerosPerThread<InputIndex_, Pointer_> >& per_thread
163 const bool is_sparse = matrix.
is_sparse();
164 if (per_thread.has_value()) {
166 auto& offsets = per_thread->counts;
167 Pointer_ accumulant = 0;
168 static_assert(std::is_same<I<
decltype(per_thread->counts[0][0])>, Pointer_>::value);
169 for (InputIndex_ i = 0; i < primary; ++i) {
170 for (
auto& pt : offsets) {
171 const auto count = pt[i];
177 parallelize([&](
const int,
const int th_start,
const int th_length) ->
void {
178 for (
int t = 0; t < th_length; ++t) {
179 auto& offsets = (per_thread->counts)[t + th_start];
180 const auto actual_start = (per_thread->starts)[t + th_start];
181 const auto actual_length = (per_thread->lengths)[t + th_start];
190 opt.sparse_ordered_index =
false;
194 for (InputIndex_ x = 0; x < actual_length; ++x) {
195 const auto range = wrk->fetch(buffer_v.data(), buffer_i.data());
196 for (InputIndex_ i = 0; i < range.number; ++i) {
197 auto& pos = offsets[range.index[i]];
198 output_value[pos] = range.value[i];
199 output_index[pos] = x + actual_start;
207 for (InputIndex_ x = 0; x < actual_length; ++x) {
208 const auto ptr = wrk->fetch(buffer_v.data());
209 for (InputIndex_ p = 0; p < primary; ++p) {
210 const auto val = ptr[p];
212 auto& pos = offsets[p];
213 output_value[pos] = val;
214 output_index[pos] = x + actual_start;
221 }, per_thread->counts.size(), per_thread->counts.size());
224 std::vector<Pointer_> offsets(output_ptrs, output_ptrs + primary);
228 opt.sparse_ordered_index =
false;
232 for (InputIndex_ s = 0; s < secondary; ++s) {
233 const auto range = wrk->fetch(buffer_v.data(), buffer_i.data());
234 for (InputIndex_ i = 0; i < range.number; ++i) {
235 auto& pos = offsets[range.index[i]];
236 output_value[pos] = range.value[i];
237 output_index[pos] = s;
245 for (InputIndex_ s = 0; s < secondary; ++s) {
246 const auto ptr = wrk->fetch(buffer_v.data());
247 for (InputIndex_ p = 0; p < primary; ++p) {
248 const auto val = ptr[p];
250 auto& pos = offsets[p];
251 output_value[pos] = val;
252 output_index[pos] = s;
263struct FillCompressedSparseContentsOptions {
268template<
typename InputValue_,
typename InputIndex_,
typename Po
inter_,
typename StoredValue_,
typename StoredIndex_>
269void fill_compressed_sparse_contents(
272 const Pointer_*
const pointers,
273 StoredValue_*
const output_value,
274 StoredIndex_*
const output_index,
275 const FillCompressedSparseContentsOptions& options
277 const InputIndex_ NR = matrix.
nrow();
278 const InputIndex_ NC = matrix.
ncol();
279 const InputIndex_ primary = (row ? NR : NC);
280 const InputIndex_ secondary = (row ? NC : NR);
283 fill_compressed_sparse_matrix_consistent(matrix, primary, secondary, row, pointers, output_value, output_index, options.num_threads);
285 std::optional<CountNonZerosPerThread<InputIndex_, Pointer_> > empty;
286 fill_compressed_sparse_matrix_inconsistent(
312template<
typename Value_,
typename Index_,
typename Po
inter_>
364template<
typename StoredValue_,
typename StoredIndex_,
typename StoredPo
inter_ = std::
size_t,
typename InputValue_,
typename InputIndex_>
374 auto& output_v = output.
value;
375 auto& output_i = output.
index;
378 const InputIndex_ NR = matrix.
nrow();
379 const InputIndex_ NC = matrix.
ncol();
380 const InputIndex_ primary = (row ? NR : NC);
381 const InputIndex_ secondary = (row ? NC : NR);
383 output_p.resize(sanisizer::sum<I<
decltype(output_p.size())> >(attest_for_Index(primary), 1));
387 std::vector<std::vector<InputValue_> > store_v;
388 std::vector<std::vector<InputIndex_> > store_i;
389 auto original_ranges = extract_sparse_matrix(matrix, store_v, store_i, options.
num_threads);
392 if (use_rows == row) {
394 for (InputIndex_ p = 0; p < primary; ++p) {
395 output_p[p + 1] = sanisizer::sum<StoredPointer_>(output_p[p], original_ranges[p].number);
398 output_v.reserve(output_p.back());
399 output_i.reserve(output_p.back());
400 for (InputIndex_ p = 0; p < primary; ++p) {
401 output_v.insert(output_v.end(), original_ranges[p].value, original_ranges[p].value + original_ranges[p].number);
402 output_i.insert(output_i.end(), original_ranges[p].index, original_ranges[p].index + original_ranges[p].number);
407 for (InputIndex_ s = 0; s < secondary; ++s) {
408 const auto& range = original_ranges[s];
409 for (InputIndex_ x = 0; x < range.number; ++x) {
410 output_p[range.index[x] + 1] += 1;
413 for (InputIndex_ p = 0; p < primary; ++p) {
414 output_p[p + 1] = sanisizer::sum<StoredPointer_>(output_p[p + 1], output_p[p]);
417 sanisizer::resize(output_v, output_p.back());
418 sanisizer::resize(output_i, output_p.back());
419 std::vector<StoredPointer_> offsets(output_p.begin(), output_p.begin() + primary);
420 for (InputIndex_ s = 0; s < secondary; ++s) {
421 const auto& range = original_ranges[s];
422 for (InputIndex_ i = 0; i < range.number; ++i) {
423 auto& pos = offsets[range.index[i]];
424 output_v[pos] = range.value[i];
433 count_compressed_sparse_non_zeros_consistent(matrix, primary, secondary, row, output_p.data() + 1, options.
num_threads);
434 for (InputIndex_ i = 1; i <= primary; ++i) {
435 output_p[i] = sanisizer::sum<StoredPointer_>(output_p[i], output_p[i - 1]);
439 sanisizer::resize(output_v, output_p.back());
440 sanisizer::resize(output_i, output_p.back());
441 fill_compressed_sparse_matrix_consistent(
454 auto per_thread = count_sparse_non_zeros_inconsistent(matrix, primary, secondary, row, output_p.data() + 1, options.
num_threads);
455 for (InputIndex_ i = 1; i <= primary; ++i) {
456 output_p[i] = sanisizer::sum<StoredPointer_>(output_p[i], output_p[i - 1]);
460 sanisizer::resize(output_v, output_p.back());
461 sanisizer::resize(output_i, output_p.back());
462 fill_compressed_sparse_matrix_inconsistent(
514 typename StoredValue_ = Value_,
515 typename StoredIndex_ = Index_,
516 typename StoredPointer_ = std::size_t,
517 typename InputValue_,
535 return std::shared_ptr<Matrix<Value_, Index_> >(
539 std::vector<StoredValue_>,
540 std::vector<StoredIndex_>,
541 std::vector<StoredPointer_>
545 std::move(comp.value),
546 std::move(comp.index),
547 std::move(comp.pointers),
550 CompressedSparseMatrixOptions copt;
562template<
typename Value_,
typename Index_,
typename Count_>
564 return count_compressed_sparse_non_zeros(
569 CountCompressedSparseNonZerosOptions copt;
570 copt.num_threads = threads;
576template<
typename InputValue_,
typename InputIndex_,
typename Po
inter_,
typename StoredValue_,
typename StoredIndex_>
579 const Pointer_* pointers,
580 StoredValue_* output_value,
581 StoredIndex_* output_index,
584 fill_compressed_sparse_contents(
591 FillCompressedSparseContentsOptions fopt;
592 fopt.num_threads = threads;
598template<
typename StoredValue_,
typename StoredIndex_,
typename StoredPo
inter_ = std::
size_t,
typename InputValue_,
typename InputIndex_>
599CompressedSparseContents<StoredValue_, StoredIndex_, StoredPointer_>
retrieve_compressed_sparse_contents(
const Matrix<InputValue_, InputIndex_>* matrix,
bool row,
bool two_pass,
int threads = 1) {
604 RetrieveCompressedSparseContentsOptions opt;
605 opt.two_pass = two_pass;
606 opt.num_threads = threads;
612template<
typename Value_ =
double,
typename Index_ =
int,
typename StoredValue_ = Value_,
typename StoredIndex_ = Index_,
typename InputValue_,
typename InputIndex_>
613std::shared_ptr<Matrix<Value_, Index_> >
convert_to_compressed_sparse(
const Matrix<InputValue_, InputIndex_>* matrix,
bool row,
bool two_pass =
false,
int threads = 1) {
618 ConvertToCompressedSparseOptions opt;
619 opt.two_pass = two_pass;
620 opt.num_threads = threads;
626template <
bool row_,
typename Value_,
typename Index_,
typename InputValue_,
typename InputIndex_>
631template <
bool row_,
typename Value_,
typename Index_,
typename StoredValue_ = Value_,
typename StoredIndex_ = Index_,
typename InputValue_,
typename InputIndex_>
632std::shared_ptr<Matrix<Value_, Index_> >
convert_to_compressed_sparse(
const Matrix<InputValue_, InputIndex_>* matrix,
bool two_pass =
false,
int threads = 1) {
Compressed sparse matrix representation.
Convert index type to container size.
Compressed sparse matrix representation.
Definition CompressedSparseMatrix.hpp:580
Virtual class for a matrix.
Definition Matrix.hpp:59
virtual Index_ ncol() const =0
virtual Index_ nrow() const =0
virtual bool prefer_rows() const =0
virtual bool is_sparse() const =0
Convert a matrix into a fragmented sparse format.
Copy data from one buffer to another.
Flexible representations for matrix data.
Definition Extractor.hpp:15
CompressedSparseContents< StoredValue_, StoredIndex_, StoredPointer_ > retrieve_compressed_sparse_contents(const Matrix< InputValue_, InputIndex_ > &matrix, const bool row, const RetrieveCompressedSparseContentsOptions &options)
Definition convert_to_compressed_sparse.hpp:365
int parallelize(Function_ fun, const Index_ tasks, const int workers)
Definition parallelize.hpp:58
Container_ create_container_of_Index_size(const Index_ x, Args_ &&... args)
Definition Index_to_container.hpp:82
std::shared_ptr< Matrix< Value_, Index_ > > convert_to_compressed_sparse(const Matrix< InputValue_, InputIndex_ > &matrix, const bool row, const ConvertToCompressedSparseOptions &options)
Definition convert_to_compressed_sparse.hpp:520
auto consecutive_extractor(const Matrix< Value_, Index_ > &matrix, const bool row, const Index_ iter_start, const Index_ iter_length, Args_ &&... args)
Definition consecutive_extractor.hpp:35
Parallelized iteration over a tatami::Matrix.
Compressed sparse contents.
Definition convert_to_compressed_sparse.hpp:313
std::vector< Index_ > index
Definition convert_to_compressed_sparse.hpp:322
std::vector< Value_ > value
Definition convert_to_compressed_sparse.hpp:317
std::vector< Pointer_ > pointers
Definition convert_to_compressed_sparse.hpp:327
Options for convert_to_compressed_sparse().
Definition convert_to_compressed_sparse.hpp:480
bool two_pass
Definition convert_to_compressed_sparse.hpp:486
int num_threads
Definition convert_to_compressed_sparse.hpp:491
Options for retrieve_compressed_sparse_contents().
Definition convert_to_compressed_sparse.hpp:333
int num_threads
Definition convert_to_compressed_sparse.hpp:344
bool two_pass
Definition convert_to_compressed_sparse.hpp:339