1#ifndef TATAMI_DELAYED_SUBSET_HPP
2#define TATAMI_DELAYED_SUBSET_HPP
22namespace DelayedSubset_internal {
24template<
typename Index_>
25struct DenseParallelResults {
26 std::vector<Index_> collapsed;
27 std::vector<Index_> reindex;
30template<
typename Index_,
class SubsetStorage_,
class ToIndex_>
31DenseParallelResults<Index_> format_dense_parallel_base(
const SubsetStorage_& subset, Index_ len, ToIndex_ to_index) {
32 std::vector<std::pair<Index_, Index_> > collected;
33 collected.reserve(len);
34 for (Index_ i = 0; i < len; ++i) {
35 collected.emplace_back(subset[to_index(i)], i);
37 std::sort(collected.begin(), collected.end());
39 DenseParallelResults<Index_> output;
40 if (collected.size()) {
41 output.collapsed.reserve(len);
42 output.reindex.resize(len);
44 Index_ last = collected.front().first;
45 output.collapsed.push_back(last);
46 output.reindex[collected.front().second] = 0;
49 for (Index_ i = 1; i < len; ++i) {
50 const auto& pp = collected[i];
51 if (pp.first != last) {
53 output.collapsed.push_back(last);
56 output.reindex[pp.second] = counter;
63template<
bool oracle_,
typename Value_,
typename Index_>
64class ParallelDense final :
public DenseExtractor<oracle_, Value_, Index_> {
66 template<
class SubsetStorage_>
67 ParallelDense(
const Matrix<Value_, Index_>* matrix,
const SubsetStorage_& subset,
bool row, MaybeOracle<oracle_, Index_> oracle,
const Options& opt) {
68 auto processed = format_dense_parallel_base<Index_>(subset, subset.size(), [&](Index_ i) -> Index_ { return i; });
69 initialize(matrix, std::move(processed), row, std::move(oracle), opt);
72 template<
class SubsetStorage_>
73 ParallelDense(
const Matrix<Value_, Index_>* matrix,
const SubsetStorage_& subset,
bool row, MaybeOracle<oracle_, Index_> oracle, Index_ block_start, Index_ block_length,
const Options& opt) {
74 auto processed = format_dense_parallel_base<Index_>(subset, block_length, [&](Index_ i) -> Index_ {
return i + block_start; });
75 initialize(matrix, std::move(processed), row, std::move(oracle), opt);
78 template<
class SubsetStorage_>
79 ParallelDense(
const Matrix<Value_, Index_>* matrix,
const SubsetStorage_& subset,
bool row, MaybeOracle<oracle_, Index_> oracle, VectorPtr<Index_> indices_ptr,
const Options& opt) {
80 const auto& indices = *indices_ptr;
81 auto processed = format_dense_parallel_base<Index_>(subset, indices.size(), [&](Index_ i) -> Index_ { return indices[i]; });
82 initialize(matrix, std::move(processed), row, std::move(oracle), opt);
86 void initialize(
const Matrix<Value_, Index_>* matrix, DenseParallelResults<Index_> processed,
bool row, MaybeOracle<oracle_, Index_> oracle,
const Options& opt) {
87 my_holding_vbuffer.resize(processed.collapsed.size());
88 my_ext = new_extractor<false, oracle_>(matrix, row, std::move(oracle), std::move(processed.collapsed), opt);
89 my_reindex.swap(processed.reindex);
93 const Value_* fetch(Index_ i, Value_* buffer) {
94 auto src = my_ext->fetch(i, my_holding_vbuffer.data());
98 for (
auto p : my_reindex) {
107 std::unique_ptr<DenseExtractor<oracle_, Value_, Index_> > my_ext;
108 std::vector<Value_> my_holding_vbuffer;
109 std::vector<Index_> my_reindex;
112template<
typename Index_>
113struct SparseParallelReindex {
120 std::vector<Index_> pool_ptrs;
121 std::vector<Index_> pool_indices;
125template<
typename Index_>
126struct SparseParallelResults {
127 std::vector<Index_> collapsed;
128 SparseParallelReindex<Index_> reindex;
131template<
typename Index_,
class SubsetStorage_,
class ToIndex_>
132SparseParallelResults<Index_> format_sparse_parallel_base(
const SubsetStorage_& indices, Index_ len, ToIndex_ to_index) {
133 std::vector<std::pair<Index_, Index_> > collected;
134 collected.reserve(len);
135 for (Index_ i = 0; i < len; ++i) {
136 auto curdex = to_index(i);
137 collected.emplace_back(indices[curdex], curdex);
139 std::sort(collected.begin(), collected.end());
141 SparseParallelResults<Index_> output;
143 if (collected.size()) {
144 output.collapsed.reserve(len);
145 output.reindex.pool_indices.reserve(len);
146 Index_ first = collected.front().first;
155 output.reindex.offset = first;
156 auto allocation = collected.back().first - output.reindex.offset + 1;
157 output.reindex.pool_ptrs.resize(allocation + 1);
160 output.reindex.pool_ptrs[counter] = 0;
162 output.reindex.pool_indices.push_back(collected.front().second);
163 output.reindex.pool_ptrs[counter] = 1;
164 output.collapsed.push_back(first);
167 for (Index_ i = 1; i < len; ++i) {
168 const auto& pp = collected[i];
169 auto current = pp.first;
170 if (current == last) {
171 output.reindex.pool_indices.push_back(pp.second);
172 ++(output.reindex.pool_ptrs[counter]);
176 Index_ pool_size = output.reindex.pool_indices.size();
177 counter = current - output.reindex.offset;
178 output.reindex.pool_ptrs[counter] = pool_size;
180 output.reindex.pool_indices.push_back(pp.second);
181 output.reindex.pool_ptrs[counter] = pool_size + 1;
182 output.collapsed.push_back(current);
190template<
bool oracle_,
typename Value_,
typename Index_>
191class ParallelSparse final :
public SparseExtractor<oracle_, Value_, Index_> {
193 template<
class SubsetStorage_>
194 ParallelSparse(
const Matrix<Value_, Index_>* mat,
const SubsetStorage_& subset,
bool row, MaybeOracle<oracle_, Index_> oracle,
const Options& opt) {
195 auto processed = format_sparse_parallel_base<Index_>(subset, subset.size(), [](Index_ i) -> Index_ { return i; });
196 initialize(mat, std::move(processed), subset.size(), row, std::move(oracle), opt);
199 template<
class SubsetStorage_>
200 ParallelSparse(
const Matrix<Value_, Index_>* mat,
const SubsetStorage_& subset,
bool row, MaybeOracle<oracle_, Index_> oracle, Index_ block_start, Index_ block_length,
const Options& opt) {
201 auto processed = format_sparse_parallel_base<Index_>(subset, block_length, [&](Index_ i) -> Index_ {
return i + block_start; });
202 initialize(mat, std::move(processed), block_length, row, std::move(oracle), opt);
205 template<
class SubsetStorage_>
206 ParallelSparse(
const Matrix<Value_, Index_>* mat,
const SubsetStorage_& subset,
bool row, MaybeOracle<oracle_, Index_> oracle, VectorPtr<Index_> indices_ptr,
const Options& opt) {
207 const auto& indices = *indices_ptr;
208 auto processed = format_sparse_parallel_base<Index_>(subset, indices.size(), [&](Index_ i) -> Index_ { return indices[i]; });
209 initialize(mat, std::move(processed), indices.size(), row, std::move(oracle), opt);
213 void initialize(
const Matrix<Value_, Index_>* mat, SparseParallelResults<Index_> processed, std::size_t extent,
bool row, MaybeOracle<oracle_, Index_> oracle, Options opt) {
214 my_shift = extent - processed.collapsed.size();
216 my_needs_value = opt.sparse_extract_value;
217 my_needs_index = opt.sparse_extract_index;
218 my_needs_sort = opt.sparse_ordered_index;
220 if (my_needs_sort && my_needs_value) {
221 my_sortspace.reserve(extent);
226 opt.sparse_extract_index =
true;
227 if (!my_needs_index) {
228 my_holding_ibuffer.resize(processed.collapsed.size());
231 my_ext = new_extractor<true, oracle_>(mat, row, std::move(oracle), std::move(processed.collapsed), opt);
232 my_reindex = std::move(processed.reindex);
236 SparseRange<Value_, Index_> fetch(Index_ i, Value_* vbuffer, Index_* ibuffer) {
237 auto vinit = (my_needs_value ? vbuffer + my_shift : NULL);
238 auto iinit = (my_needs_index ? ibuffer + my_shift : my_holding_ibuffer.data());
239 auto input = my_ext->fetch(i, vinit, iinit);
241 if (!my_needs_sort) {
250 auto vcopy = vbuffer;
251 auto icopy = ibuffer;
253 auto vsrc = input.value;
254 bool replace_value = my_needs_value && vsrc != vcopy;
256 for (Index_ i = 0; i < input.number; ++i) {
257 auto lookup = input.index[i] - my_reindex.offset;
258 auto start = my_reindex.pool_ptrs[lookup];
259 auto num = my_reindex.pool_ptrs[lookup + 1] - start;
264 std::fill_n(vcopy, num, val);
267 replace_value = (vcopy != vsrc);
270 if (my_needs_index) {
275 std::copy_n(my_reindex.pool_indices.begin() + start, num, icopy);
280 input.number = count;
281 if (my_needs_value) {
282 input.value = vbuffer;
284 if (my_needs_index) {
285 input.index = ibuffer;
290 }
else if (my_needs_value) {
294 my_sortspace.clear();
295 for (Index_ i = 0; i < input.number; ++i) {
296 auto val = input.value[i];
297 auto lookup = input.index[i] - my_reindex.offset;
298 auto start = my_reindex.pool_ptrs[lookup];
299 auto end = my_reindex.pool_ptrs[lookup + 1];
300 for (Index_ j = start; j < end; ++j) {
301 my_sortspace.emplace_back(my_reindex.pool_indices[j], val);
304 std::sort(my_sortspace.begin(), my_sortspace.end());
305 input.number = my_sortspace.size();
307 auto vcopy = vbuffer;
308 for (
const auto& ss : my_sortspace) {
312 input.value = vbuffer;
314 if (my_needs_index) {
315 auto icopy = ibuffer;
316 for (
const auto& ss : my_sortspace) {
320 input.index = ibuffer;
331 auto icopy = ibuffer;
333 for (Index_ i = 0; i < input.number; ++i) {
334 auto lookup = input.index[i] - my_reindex.offset;
335 auto start = my_reindex.pool_ptrs[lookup];
336 auto num = my_reindex.pool_ptrs[lookup + 1] - start;
339 if (my_needs_index) {
340 std::copy_n(my_reindex.pool_indices.begin() + start, num, icopy);
345 input.number = count;
346 if (my_needs_index) {
347 std::sort(ibuffer, ibuffer + count);
348 input.index = ibuffer;
358 std::unique_ptr<SparseExtractor<oracle_, Value_, Index_> > my_ext;
359 bool my_needs_value, my_needs_index, my_needs_sort;
360 SparseParallelReindex<Index_> my_reindex;
361 std::vector<std::pair<Index_, Value_> > my_sortspace;
362 std::vector<Index_> my_holding_ibuffer;
363 std::size_t my_shift;
382template<
typename Value_,
typename Index_,
class SubsetStorage_>
393 my_matrix(std::move(matrix)), my_subset(std::move(subset)), my_by_row(by_row) {}
396 std::shared_ptr<const Matrix<Value_, Index_> > my_matrix;
397 SubsetStorage_ my_subset;
403 return my_subset.size();
405 return my_matrix->nrow();
411 return my_matrix->ncol();
413 return my_subset.size();
418 return my_matrix->is_sparse();
422 return my_matrix->is_sparse_proportion();
426 return my_matrix->prefer_rows();
430 return my_matrix->prefer_rows_proportion();
434 return my_matrix->uses_oracle(row);
445 template<
typename ... Args_>
446 std::unique_ptr<MyopicDenseExtractor<Value_, Index_> > populate_myopic_dense(
bool row, Args_&& ... args)
const {
447 if (row == my_by_row) {
448 return std::make_unique<subset_utils::MyopicPerpendicularDense<Value_, Index_, SubsetStorage_> >(my_matrix.get(), my_subset, row, std::forward<Args_>(args)...);
450 return std::make_unique<DelayedSubset_internal::ParallelDense<false, Value_, Index_> >(my_matrix.get(), my_subset, row,
false, std::forward<Args_>(args)...);
455 std::unique_ptr<MyopicDenseExtractor<Value_, Index_> >
dense(
bool row,
const Options& opt)
const {
456 return populate_myopic_dense(row, opt);
459 std::unique_ptr<MyopicDenseExtractor<Value_, Index_> >
dense(
bool row, Index_ block_start, Index_ block_length,
const Options& opt)
const {
460 return populate_myopic_dense(row, block_start, block_length, opt);
464 return populate_myopic_dense(row, std::move(my_subset_ptr), opt);
471 template<
typename ... Args_>
472 std::unique_ptr<MyopicSparseExtractor<Value_, Index_> > populate_myopic_sparse(
bool row, Args_&& ... args)
const {
473 if (row == my_by_row) {
474 return std::make_unique<subset_utils::MyopicPerpendicularSparse<Value_, Index_, SubsetStorage_> >(my_matrix.get(), my_subset, row, std::forward<Args_>(args)...);
476 return std::make_unique<DelayedSubset_internal::ParallelSparse<false, Value_, Index_> >(my_matrix.get(), my_subset, row,
false, std::forward<Args_>(args)...);
481 std::unique_ptr<MyopicSparseExtractor<Value_, Index_> >
sparse(
bool row,
const Options& opt)
const {
482 return populate_myopic_sparse(row, opt);
485 std::unique_ptr<MyopicSparseExtractor<Value_, Index_> >
sparse(
bool row, Index_ block_start, Index_ block_length,
const Options& opt)
const {
486 return populate_myopic_sparse(row, block_start, block_length, opt);
490 return populate_myopic_sparse(row, std::move(my_subset_ptr), opt);
497 template<
typename ... Args_>
498 std::unique_ptr<OracularDenseExtractor<Value_, Index_> > populate_oracular_dense(
bool row, std::shared_ptr<
const Oracle<Index_> > oracle, Args_&& ... args)
const {
499 if (row == my_by_row) {
500 return std::make_unique<subset_utils::OracularPerpendicularDense<Value_, Index_> >(my_matrix.get(), my_subset, row, std::move(oracle), std::forward<Args_>(args)...);
502 return std::make_unique<DelayedSubset_internal::ParallelDense<true, Value_, Index_> >(my_matrix.get(), my_subset, row, std::move(oracle), std::forward<Args_>(args)...);
507 std::unique_ptr<OracularDenseExtractor<Value_, Index_> >
dense(
bool row, std::shared_ptr<
const Oracle<Index_> > oracle,
const Options& opt)
const {
508 return populate_oracular_dense(row, std::move(oracle), opt);
511 std::unique_ptr<OracularDenseExtractor<Value_, Index_> >
dense(
bool row, std::shared_ptr<
const Oracle<Index_> > oracle, Index_ block_start, Index_ block_length,
const Options& opt)
const {
512 return populate_oracular_dense(row, std::move(oracle), block_start, block_length, opt);
516 return populate_oracular_dense(row, std::move(oracle), std::move(my_subset_ptr), opt);
523 template<
typename ... Args_>
524 std::unique_ptr<OracularSparseExtractor<Value_, Index_> > populate_oracular_sparse(
bool row, std::shared_ptr<
const Oracle<Index_> > oracle, Args_&& ... args)
const {
525 if (row == my_by_row) {
526 return std::make_unique<subset_utils::OracularPerpendicularSparse<Value_, Index_> >(my_matrix.get(), my_subset, row, std::move(oracle), std::forward<Args_>(args)...);
528 return std::make_unique<DelayedSubset_internal::ParallelSparse<true, Value_, Index_> >(my_matrix.get(), my_subset, row, std::move(oracle), std::forward<Args_>(args)...);
533 std::unique_ptr<OracularSparseExtractor<Value_, Index_> >
sparse(
bool row, std::shared_ptr<
const Oracle<Index_> > oracle,
const Options& opt)
const {
534 return populate_oracular_sparse(row, std::move(oracle), opt);
537 std::unique_ptr<OracularSparseExtractor<Value_, Index_> >
sparse(
bool row, std::shared_ptr<
const Oracle<Index_> > oracle, Index_ block_start, Index_ block_length,
const Options& opt)
const {
538 return populate_oracular_sparse(row, std::move(oracle), block_start, block_length, opt);
542 return populate_oracular_sparse(row, std::move(oracle), std::move(my_subset_ptr), opt);
Delayed subsetting of a matrix with general indices.
Definition DelayedSubset.hpp:383
bool uses_oracle(bool row) const
Definition DelayedSubset.hpp:433
std::unique_ptr< OracularSparseExtractor< Value_, Index_ > > sparse(bool row, std::shared_ptr< const Oracle< Index_ > > oracle, VectorPtr< Index_ > my_subset_ptr, const Options &opt) const
Definition DelayedSubset.hpp:541
std::unique_ptr< MyopicDenseExtractor< Value_, Index_ > > dense(bool row, Index_ block_start, Index_ block_length, const Options &opt) const
Definition DelayedSubset.hpp:459
std::unique_ptr< MyopicSparseExtractor< Value_, Index_ > > sparse(bool row, Index_ block_start, Index_ block_length, const Options &opt) const
Definition DelayedSubset.hpp:485
std::unique_ptr< OracularSparseExtractor< Value_, Index_ > > sparse(bool row, std::shared_ptr< const Oracle< Index_ > > oracle, const Options &opt) const
Definition DelayedSubset.hpp:533
Index_ ncol() const
Definition DelayedSubset.hpp:409
bool prefer_rows() const
Definition DelayedSubset.hpp:425
std::unique_ptr< OracularDenseExtractor< Value_, Index_ > > dense(bool row, std::shared_ptr< const Oracle< Index_ > > oracle, Index_ block_start, Index_ block_length, const Options &opt) const
Definition DelayedSubset.hpp:511
std::unique_ptr< MyopicSparseExtractor< Value_, Index_ > > sparse(bool row, VectorPtr< Index_ > my_subset_ptr, const Options &opt) const
Definition DelayedSubset.hpp:489
std::unique_ptr< MyopicSparseExtractor< Value_, Index_ > > sparse(bool row, const Options &opt) const
Definition DelayedSubset.hpp:481
std::unique_ptr< OracularDenseExtractor< Value_, Index_ > > dense(bool row, std::shared_ptr< const Oracle< Index_ > > oracle, const Options &opt) const
Definition DelayedSubset.hpp:507
DelayedSubset(std::shared_ptr< const Matrix< Value_, Index_ > > matrix, SubsetStorage_ subset, bool by_row)
Definition DelayedSubset.hpp:392
double prefer_rows_proportion() const
Definition DelayedSubset.hpp:429
std::unique_ptr< OracularDenseExtractor< Value_, Index_ > > dense(bool row, std::shared_ptr< const Oracle< Index_ > > oracle, VectorPtr< Index_ > my_subset_ptr, const Options &opt) const
Definition DelayedSubset.hpp:515
std::unique_ptr< MyopicDenseExtractor< Value_, Index_ > > dense(bool row, const Options &opt) const
Definition DelayedSubset.hpp:455
Index_ nrow() const
Definition DelayedSubset.hpp:401
std::unique_ptr< OracularSparseExtractor< Value_, Index_ > > sparse(bool row, std::shared_ptr< const Oracle< Index_ > > oracle, Index_ block_start, Index_ block_length, const Options &opt) const
Definition DelayedSubset.hpp:537
bool is_sparse() const
Definition DelayedSubset.hpp:417
double is_sparse_proportion() const
Definition DelayedSubset.hpp:421
std::unique_ptr< MyopicDenseExtractor< Value_, Index_ > > dense(bool row, VectorPtr< Index_ > my_subset_ptr, const Options &opt) const
Definition DelayedSubset.hpp:463
Virtual class for a matrix.
Definition Matrix.hpp:59
Predict future access requests on the target dimension.
Definition Oracle.hpp:23
Flexible representations for matrix data.
Definition Extractor.hpp:15
std::shared_ptr< const std::vector< Index_ > > VectorPtr
Definition Matrix.hpp:26
typename std::conditional< oracle_, OracularDenseExtractor< Value_, Index_ >, MyopicDenseExtractor< Value_, Index_ > >::type DenseExtractor
Definition Extractor.hpp:273
Options for accessing data from a Matrix instance.
Definition Options.hpp:30