tatami
C++ API for different matrix representations
Loading...
Searching...
No Matches
DelayedSubsetUnique.hpp
Go to the documentation of this file.
1#ifndef TATAMI_DELAYED_SUBSET_UNIQUE_HPP
2#define TATAMI_DELAYED_SUBSET_UNIQUE_HPP
3
4#include "utils.hpp"
5#include "../base/Matrix.hpp"
6#include "../utils/copy.hpp"
7
8#include <algorithm>
9#include <numeric>
10#include <memory>
11
18namespace tatami {
19
23namespace DelayedSubsetUnique_internal {
24
25template<typename Index_>
26struct DenseParallelResults {
27 std::vector<Index_> sorted;
28 std::vector<Index_> permutation;
29};
30
31template<typename Index_, class SubsetStorage_, class ToIndex_>
32DenseParallelResults<Index_> format_dense_parallel(const SubsetStorage_& subset, const Index_ len, const ToIndex_ to_index) {
33 std::vector<std::pair<Index_, Index_> > collected;
34 collected.reserve(len);
35 for (Index_ i = 0; i < len; ++i) {
36 collected.emplace_back(subset[to_index(i)], i);
37 }
38 std::sort(collected.begin(), collected.end());
39
40 DenseParallelResults<Index_> output;
41 output.sorted.reserve(len);
42 output.permutation.reserve(len);
43 for (const auto& pp : collected) {
44 output.sorted.push_back(pp.first);
45 output.permutation.push_back(pp.second);
46 }
47
48 return output;
49}
50
51template<bool oracle_, typename Value_, typename Index_>
52class ParallelDense final : public DenseExtractor<oracle_, Value_, Index_> {
53public:
54 template<class SubsetStorage_>
55 ParallelDense(
56 const Matrix<Value_, Index_>& matrix,
57 const SubsetStorage_& subset,
58 const bool row,
59 MaybeOracle<oracle_, Index_> oracle,
60 const Options& opt
61 ) {
62 auto processed = format_dense_parallel<Index_>(subset, subset.size(), [&](Index_ i) -> Index_ { return i; });
63 initialize(matrix, std::move(processed), row, std::move(oracle), opt);
64 }
65
66 template<class SubsetStorage_>
67 ParallelDense(
68 const Matrix<Value_, Index_>& matrix,
69 const SubsetStorage_& subset,
70 const bool row,
71 MaybeOracle<oracle_, Index_> oracle,
72 const Index_ block_start,
73 const Index_ block_length,
74 const Options& opt
75 ) {
76 auto processed = format_dense_parallel<Index_>(subset, block_length, [&](Index_ i) -> Index_ { return i + block_start; });
77 initialize(matrix, std::move(processed), row, std::move(oracle), opt);
78 }
79
80 template<class SubsetStorage_>
81 ParallelDense(
82 const Matrix<Value_, Index_>& matrix,
83 const SubsetStorage_& subset,
84 const bool row,
85 MaybeOracle<oracle_, Index_> oracle,
86 VectorPtr<Index_> indices_ptr,
87 const Options& opt
88 ) {
89 const auto& indices = *indices_ptr;
90 auto processed = format_dense_parallel<Index_>(subset, indices.size(), [&](Index_ i) -> Index_ { return indices[i]; });
91 initialize(matrix, std::move(processed), row, std::move(oracle), opt);
92 }
93
94private:
95 void initialize(
96 const Matrix<Value_, Index_>& matrix,
97 DenseParallelResults<Index_> processed,
98 const bool row,
99 MaybeOracle<oracle_, Index_> oracle,
100 const Options& opt
101 ) {
102 resize_container_to_Index_size(my_holding_vbuffer, processed.sorted.size()); // processed.sorted.size() should fit in an Index_, hence the cast is safe.
103 my_ext = new_extractor<false, oracle_>(matrix, row, std::move(oracle), std::move(processed.sorted), opt);
104 my_permutation = std::move(processed.permutation);
105 }
106
107public:
108 const Value_* fetch(const Index_ i, Value_* const buffer) {
109 auto src = my_ext->fetch(i, my_holding_vbuffer.data());
110
111 // 'input' and 'output' should not point to the same array. In theory, it
112 // is possible to do an in-place permutation, but this requires another
113 // array anyway to track the permutation status, so we'll just keep it simple.
114 for (const auto p : my_permutation) {
115 buffer[p] = *src;
116 ++src;
117 }
118
119 return buffer;
120 }
121
122private:
123 std::unique_ptr<DenseExtractor<oracle_, Value_, Index_> > my_ext;
124 std::vector<Value_> my_holding_vbuffer;
125 std::vector<Index_> my_permutation;
126};
127
128template<typename Index_, class SubsetStorage_, class ToIndex_>
129std::vector<Index_> format_sparse_parallel(const SubsetStorage_& subset, const Index_ len, const ToIndex_ to_index) {
130 std::vector<Index_> collected;
131 collected.reserve(len);
132 for (Index_ i = 0; i < len; ++i) {
133 collected.emplace_back(subset[to_index(i)]);
134 }
135 std::sort(collected.begin(), collected.end());
136 return collected;
137}
138
139template<bool oracle_, typename Value_, typename Index_>
140class ParallelSparse final : public SparseExtractor<oracle_, Value_, Index_> {
141public:
142 template<class SubsetStorage_>
143 ParallelSparse(
144 const Matrix<Value_, Index_>& matrix,
145 const SubsetStorage_& subset,
146 const std::vector<Index_>& remap,
147 const bool row,
148 MaybeOracle<oracle_, Index_> oracle,
149 const Options& opt
150 ) :
151 my_remapping(remap)
152 {
153 auto processed = format_sparse_parallel<Index_>(subset, subset.size(), [](Index_ i) -> Index_ { return i; });
154 initialize(matrix, std::move(processed), row, std::move(oracle), opt);
155 }
156
157 template<class SubsetStorage_>
158 ParallelSparse(
159 const Matrix<Value_, Index_>& matrix,
160 const SubsetStorage_& subset,
161 const std::vector<Index_>& remap,
162 const bool row,
163 MaybeOracle<oracle_, Index_> oracle,
164 const Index_ block_start,
165 const Index_ block_length,
166 const Options& opt
167 ) :
168 my_remapping(remap)
169 {
170 auto processed = format_sparse_parallel<Index_>(subset, block_length, [&](Index_ i) -> Index_ { return i + block_start; });
171 initialize(matrix, std::move(processed), row, std::move(oracle), opt);
172 }
173
174 template<class SubsetStorage_>
175 ParallelSparse(
176 const Matrix<Value_, Index_>& matrix,
177 const SubsetStorage_& subset,
178 const std::vector<Index_>& remap,
179 const bool row,
180 MaybeOracle<oracle_, Index_> oracle,
181 VectorPtr<Index_> indices_ptr,
182 const Options& opt
183 ) :
184 my_remapping(remap)
185 {
186 const auto& indices = *indices_ptr;
187 auto processed = format_sparse_parallel<Index_>(subset, indices.size(), [&](Index_ i) -> Index_ { return indices[i]; });
188 initialize(matrix, std::move(processed), row, std::move(oracle), opt);
189 }
190
191private:
192 void initialize(const Matrix<Value_, Index_>& matrix, std::vector<Index_> sorted, const bool row, MaybeOracle<oracle_, Index_> oracle, Options opt) {
193 my_needs_value = opt.sparse_extract_value;
194 my_needs_index = opt.sparse_extract_index;
195 my_needs_sort = opt.sparse_ordered_index;
196
197 // The conditionals here mirror those in 'fetch',
198 // to self-document the case where each of the temporaries are needed.
199 if (!my_needs_sort) {
200 if (my_needs_index) {
201 ; // no 'my_holding_ibuffer' required as a user-provided 'index_buffer' should be available.
202 }
203
204 } else if (my_needs_value) {
205 opt.sparse_extract_index = true;
206 my_sortspace.reserve(sorted.size());
207 if (my_needs_index) {
208 // no 'my_holding_ibuffer' required as a user-provided 'index_buffer' should be available.
209 } else {
210 // Needs 'my_holding_ibuffer' as user-provided 'index_buffer' may be NULL.
211 resize_container_to_Index_size(my_holding_ibuffer, sorted.size()); // sorted.size() should fit in an Index_, hence the cast is safe.
212 }
213
214 } else if (my_needs_index) {
215 ; // no 'my_holding_ibuffer' required as a user-provided 'index_buffer' should be available.
216 }
217
218 my_ext = new_extractor<true, oracle_>(matrix, row, std::move(oracle), std::move(sorted), opt);
219 }
220
221public:
222 SparseRange<Value_, Index_> fetch(const Index_ i, Value_* const value_buffer, Index_* const index_buffer) {
223 auto input = my_ext->fetch(i, value_buffer, (my_holding_ibuffer.empty() ? index_buffer : my_holding_ibuffer.data()));
224
225 // Pointers in 'input' and the 'buffer' pointers may point to the same array,
226 // as we're either just modifiying in place or we're copying to 'my_sortspace'.
227 if (!my_needs_sort) {
228 if (my_needs_index) {
229 for (Index_ i = 0; i < input.number; ++i) {
230 index_buffer[i] = my_remapping[input.index[i]];
231 }
232 input.index = index_buffer;
233 }
234
235 } else if (my_needs_value) {
236 // We assume that the indices have already been extracted for sorting
237 // purposes, even if they weren't actually requested.
238 my_sortspace.clear();
239 for (Index_ i = 0; i < input.number; ++i) {
240 my_sortspace.emplace_back(my_remapping[input.index[i]], input.value[i]);
241 }
242 std::sort(my_sortspace.begin(), my_sortspace.end());
243
244 auto vcopy = value_buffer;
245 for (const auto& ss : my_sortspace) {
246 *vcopy = ss.second;
247 ++vcopy;
248 }
249 input.value = value_buffer;
250
251 if (my_needs_index) {
252 auto icopy = index_buffer;
253 for (const auto& ss : my_sortspace) {
254 *icopy = ss.first;
255 ++icopy;
256 }
257 input.index = index_buffer;
258 } else {
259 input.index = NULL;
260 }
261
262 } else if (my_needs_index) {
263 for (Index_ i = 0; i < input.number; ++i) {
264 index_buffer[i] = my_remapping[input.index[i]];
265 }
266 std::sort(index_buffer, index_buffer + input.number);
267 input.index = index_buffer;
268 }
269
270 return input;
271 }
272
273private:
274 const std::vector<Index_>& my_remapping;
275 std::unique_ptr<SparseExtractor<oracle_, Value_, Index_> > my_ext;
276 bool my_needs_value, my_needs_index, my_needs_sort;
277 std::vector<std::pair<Index_, Value_> > my_sortspace;
278 std::vector<Index_> my_holding_ibuffer;
279};
280
281}
297template<typename Value_, typename Index_, class SubsetStorage_>
298class DelayedSubsetUnique final : public Matrix<Value_, Index_> {
299public:
309 std::shared_ptr<const Matrix<Value_, Index_> > matrix,
310 SubsetStorage_ subset,
311 const bool by_row,
312 const bool check = true
313 ) :
314 my_matrix(std::move(matrix)),
315 my_subset(std::move(subset)),
316 my_by_row(by_row)
317 {
318 const Index_ fulldim = my_by_row ? my_matrix->nrow() : my_matrix->ncol();
319 const auto nsub = my_subset.size();
320
321 if (check) {
323 for (I<decltype(nsub)> i = 0; i < nsub; ++i) {
324 auto& found = checks[my_subset[i]];
325 if (found) {
326 throw std::runtime_error("my_subset should be unique");
327 }
328 found = 1;
329 }
330 }
331
332 resize_container_to_Index_size(my_mapping_single, fulldim);
333 for (I<decltype(nsub)> i = 0; i < nsub; ++i) {
334 my_mapping_single[my_subset[i]] = i;
335 }
336 }
337
338private:
339 std::shared_ptr<const Matrix<Value_, Index_> > my_matrix;
340 SubsetStorage_ my_subset;
341 bool my_by_row;
342 std::vector<Index_> my_mapping_single;
343
344public:
345 Index_ nrow() const {
346 if (my_by_row) {
347 return my_subset.size();
348 } else {
349 return my_matrix->nrow();
350 }
351 }
352
353 Index_ ncol() const {
354 if (my_by_row) {
355 return my_matrix->ncol();
356 } else {
357 return my_subset.size();
358 }
359 }
360
361 bool is_sparse() const {
362 return my_matrix->is_sparse();
363 }
364
365 double is_sparse_proportion() const {
366 return my_matrix->is_sparse_proportion();
367 }
368
369 bool prefer_rows() const {
370 return my_matrix->prefer_rows();
371 }
372
373 double prefer_rows_proportion() const {
374 return my_matrix->prefer_rows_proportion();
375 }
376
377 bool uses_oracle(const bool row) const {
378 return my_matrix->uses_oracle(row);
379 }
380
381 using Matrix<Value_, Index_>::dense_column;
382
383 using Matrix<Value_, Index_>::dense_row;
384
385 using Matrix<Value_, Index_>::sparse_column;
386
387 using Matrix<Value_, Index_>::sparse_row;
388
389 /********************
390 *** Myopic dense ***
391 ********************/
392private:
393 template<typename ... Args_>
394 std::unique_ptr<MyopicDenseExtractor<Value_, Index_> > populate_myopic_dense(
395 const bool row,
396 Args_&& ... args
397 ) const {
398 if (row == my_by_row) {
399 return std::make_unique<subset_utils::MyopicPerpendicularDense<Value_, Index_, SubsetStorage_> >(
400 *my_matrix,
401 my_subset,
402 row,
403 std::forward<Args_>(args)...
404 );
405 } else {
406 return std::make_unique<DelayedSubsetUnique_internal::ParallelDense<false, Value_, Index_> >(
407 *my_matrix,
408 my_subset,
409 row,
410 false,
411 std::forward<Args_>(args)...
412 );
413 }
414 }
415
416public:
417 std::unique_ptr<MyopicDenseExtractor<Value_, Index_> > dense(
418 const bool row,
419 const Options& opt
420 ) const {
421 return populate_myopic_dense(row, opt);
422 }
423
424 std::unique_ptr<MyopicDenseExtractor<Value_, Index_> > dense(
425 const bool row,
426 const Index_ block_start,
427 const Index_ block_length,
428 const Options& opt
429 ) const {
430 return populate_myopic_dense(row, block_start, block_length, opt);
431 }
432
433 std::unique_ptr<MyopicDenseExtractor<Value_, Index_> > dense(
434 const bool row,
435 VectorPtr<Index_> indices_ptr,
436 const Options& opt
437 ) const {
438 return populate_myopic_dense(row, std::move(indices_ptr), opt);
439 }
440
441 /*********************
442 *** Myopic sparse ***
443 *********************/
444private:
445 template<typename ... Args_>
446 std::unique_ptr<MyopicSparseExtractor<Value_, Index_> > populate_myopic_sparse(
447 const bool row,
448 Args_&& ... args
449 ) const {
450 if (row == my_by_row) {
451 return std::make_unique<subset_utils::MyopicPerpendicularSparse<Value_, Index_, SubsetStorage_> >(
452 *my_matrix,
453 my_subset,
454 row,
455 std::forward<Args_>(args)...
456 );
457 } else {
458 return std::make_unique<DelayedSubsetUnique_internal::ParallelSparse<false, Value_, Index_> >(
459 *my_matrix,
460 my_subset,
461 my_mapping_single,
462 row,
463 false,
464 std::forward<Args_>(args)...
465 );
466 }
467 }
468
469public:
470 std::unique_ptr<MyopicSparseExtractor<Value_, Index_> > sparse(
471 const bool row,
472 const Options& opt
473 ) const {
474 return populate_myopic_sparse(row, opt);
475 }
476
477 std::unique_ptr<MyopicSparseExtractor<Value_, Index_> > sparse(
478 const bool row,
479 const Index_ block_start,
480 const Index_ block_length,
481 const Options& opt
482 ) const {
483 return populate_myopic_sparse(row, block_start, block_length, opt);
484 }
485
486 std::unique_ptr<MyopicSparseExtractor<Value_, Index_> > sparse(
487 const bool row,
488 VectorPtr<Index_> indices_ptr,
489 const Options& opt
490 ) const {
491 return populate_myopic_sparse(row, std::move(indices_ptr), opt);
492 }
493
494 /**********************
495 *** Oracular dense ***
496 **********************/
497private:
498 template<typename ... Args_>
499 std::unique_ptr<OracularDenseExtractor<Value_, Index_> > populate_oracular_dense(
500 const bool row,
501 std::shared_ptr<const Oracle<Index_> > oracle,
502 Args_&& ... args
503 ) const {
504 if (row == my_by_row) {
505 return std::make_unique<subset_utils::OracularPerpendicularDense<Value_, Index_> >(
506 *my_matrix,
507 my_subset,
508 row,
509 std::move(oracle),
510 std::forward<Args_>(args)...
511 );
512 } else {
513 return std::make_unique<DelayedSubsetUnique_internal::ParallelDense<true, Value_, Index_> >(
514 *my_matrix,
515 my_subset,
516 row,
517 std::move(oracle),
518 std::forward<Args_>(args)...
519 );
520 }
521 }
522
523public:
524 std::unique_ptr<OracularDenseExtractor<Value_, Index_> > dense(
525 const bool row,
526 std::shared_ptr<const Oracle<Index_> > oracle,
527 const Options& opt
528 ) const {
529 return populate_oracular_dense(row, std::move(oracle), opt);
530 }
531
532 std::unique_ptr<OracularDenseExtractor<Value_, Index_> > dense(
533 const bool row,
534 std::shared_ptr<const Oracle<Index_> > oracle,
535 const Index_ block_start,
536 const Index_ block_length,
537 const Options& opt
538 ) const {
539 return populate_oracular_dense(row, std::move(oracle), block_start, block_length, opt);
540 }
541
542 std::unique_ptr<OracularDenseExtractor<Value_, Index_> > dense(
543 const bool row,
544 std::shared_ptr<const Oracle<Index_> > oracle,
545 VectorPtr<Index_> indices_ptr,
546 const Options& opt
547 ) const {
548 return populate_oracular_dense(row, std::move(oracle), std::move(indices_ptr), opt);
549 }
550
551 /***********************
552 *** Oracular sparse ***
553 ***********************/
554private:
555 template<typename ... Args_>
556 std::unique_ptr<OracularSparseExtractor<Value_, Index_> > populate_oracular_sparse(
557 const bool row,
558 std::shared_ptr<const Oracle<Index_> > oracle,
559 Args_&& ... args
560 ) const {
561 if (row == my_by_row) {
562 return std::make_unique<subset_utils::OracularPerpendicularSparse<Value_, Index_> >(
563 *my_matrix,
564 my_subset,
565 row,
566 std::move(oracle),
567 std::forward<Args_>(args)...
568 );
569 } else {
570 return std::make_unique<DelayedSubsetUnique_internal::ParallelSparse<true, Value_, Index_> >(
571 *my_matrix,
572 my_subset,
573 my_mapping_single,
574 row,
575 std::move(oracle),
576 std::forward<Args_>(args)...
577 );
578 }
579 }
580
581public:
582 std::unique_ptr<OracularSparseExtractor<Value_, Index_> > sparse(
583 const bool row,
584 std::shared_ptr<const Oracle<Index_> > oracle,
585 const Options& opt
586 ) const {
587 return populate_oracular_sparse(row, std::move(oracle), opt);
588 }
589
590 std::unique_ptr<OracularSparseExtractor<Value_, Index_> > sparse(
591 const bool row,
592 std::shared_ptr<const Oracle<Index_> > oracle,
593 const Index_ block_start,
594 const Index_ block_length,
595 const Options& opt
596 ) const {
597 return populate_oracular_sparse(row, std::move(oracle), block_start, block_length, opt);
598 }
599
600 std::unique_ptr<OracularSparseExtractor<Value_, Index_> > sparse(
601 const bool row,
602 std::shared_ptr<const Oracle<Index_> > oracle,
603 VectorPtr<Index_> indices_ptr,
604 const Options& opt
605 ) const {
606 return populate_oracular_sparse(row, std::move(oracle), std::move(indices_ptr), opt);
607 }
608};
609
610}
611
612#endif
Virtual class for a matrix of some numeric type.
Delayed subsetting of a matrix with unique indices.
Definition DelayedSubsetUnique.hpp:298
bool prefer_rows() const
Definition DelayedSubsetUnique.hpp:369
Index_ ncol() const
Definition DelayedSubsetUnique.hpp:353
double is_sparse_proportion() const
Definition DelayedSubsetUnique.hpp:365
bool is_sparse() const
Definition DelayedSubsetUnique.hpp:361
std::unique_ptr< MyopicSparseExtractor< Value_, Index_ > > sparse(const bool row, const Index_ block_start, const Index_ block_length, const Options &opt) const
Definition DelayedSubsetUnique.hpp:477
double prefer_rows_proportion() const
Definition DelayedSubsetUnique.hpp:373
std::unique_ptr< OracularSparseExtractor< Value_, Index_ > > sparse(const bool row, std::shared_ptr< const Oracle< Index_ > > oracle, const Options &opt) const
Definition DelayedSubsetUnique.hpp:582
std::unique_ptr< OracularDenseExtractor< Value_, Index_ > > dense(const bool row, std::shared_ptr< const Oracle< Index_ > > oracle, const Index_ block_start, const Index_ block_length, const Options &opt) const
Definition DelayedSubsetUnique.hpp:532
std::unique_ptr< MyopicDenseExtractor< Value_, Index_ > > dense(const bool row, const Index_ block_start, const Index_ block_length, const Options &opt) const
Definition DelayedSubsetUnique.hpp:424
std::unique_ptr< MyopicDenseExtractor< Value_, Index_ > > dense(const bool row, const Options &opt) const
Definition DelayedSubsetUnique.hpp:417
bool uses_oracle(const bool row) const
Definition DelayedSubsetUnique.hpp:377
std::unique_ptr< OracularSparseExtractor< Value_, Index_ > > sparse(const bool row, std::shared_ptr< const Oracle< Index_ > > oracle, VectorPtr< Index_ > indices_ptr, const Options &opt) const
Definition DelayedSubsetUnique.hpp:600
std::unique_ptr< OracularDenseExtractor< Value_, Index_ > > dense(const bool row, std::shared_ptr< const Oracle< Index_ > > oracle, const Options &opt) const
Definition DelayedSubsetUnique.hpp:524
std::unique_ptr< OracularDenseExtractor< Value_, Index_ > > dense(const bool row, std::shared_ptr< const Oracle< Index_ > > oracle, VectorPtr< Index_ > indices_ptr, const Options &opt) const
Definition DelayedSubsetUnique.hpp:542
std::unique_ptr< MyopicDenseExtractor< Value_, Index_ > > dense(const bool row, VectorPtr< Index_ > indices_ptr, const Options &opt) const
Definition DelayedSubsetUnique.hpp:433
std::unique_ptr< MyopicSparseExtractor< Value_, Index_ > > sparse(const bool row, VectorPtr< Index_ > indices_ptr, const Options &opt) const
Definition DelayedSubsetUnique.hpp:486
Index_ nrow() const
Definition DelayedSubsetUnique.hpp:345
DelayedSubsetUnique(std::shared_ptr< const Matrix< Value_, Index_ > > matrix, SubsetStorage_ subset, const bool by_row, const bool check=true)
Definition DelayedSubsetUnique.hpp:308
std::unique_ptr< OracularSparseExtractor< Value_, Index_ > > sparse(const bool row, std::shared_ptr< const Oracle< Index_ > > oracle, const Index_ block_start, const Index_ block_length, const Options &opt) const
Definition DelayedSubsetUnique.hpp:590
std::unique_ptr< MyopicSparseExtractor< Value_, Index_ > > sparse(const bool row, const Options &opt) const
Definition DelayedSubsetUnique.hpp:470
Virtual class for a matrix.
Definition Matrix.hpp:59
std::unique_ptr< MyopicDenseExtractor< Value_, Index_ > > dense_row() const
Definition Matrix.hpp:295
std::unique_ptr< MyopicDenseExtractor< Value_, Index_ > > dense_column() const
Definition Matrix.hpp:336
std::unique_ptr< MyopicSparseExtractor< Value_, Index_ > > sparse_column() const
Definition Matrix.hpp:545
std::unique_ptr< MyopicSparseExtractor< Value_, Index_ > > sparse_row() const
Definition Matrix.hpp:504
Predict future access requests on the target dimension.
Definition Oracle.hpp:29
Copy data from one buffer to another.
Flexible representations for matrix data.
Definition Extractor.hpp:15
std::shared_ptr< const std::vector< Index_ > > VectorPtr
Definition Matrix.hpp:26
void resize_container_to_Index_size(Container_ &container, const Index_ x, Args_ &&... args)
Definition Index_to_container.hpp:92
typename std::conditional< oracle_, OracularDenseExtractor< Value_, Index_ >, MyopicDenseExtractor< Value_, Index_ > >::type DenseExtractor
Definition Extractor.hpp:273
Container_ create_container_of_Index_size(const Index_ x, Args_ &&... args)
Definition Index_to_container.hpp:73
Options for accessing data from a Matrix instance.
Definition Options.hpp:30