tatami
C++ API for different matrix representations
Loading...
Searching...
No Matches
DelayedUnaryIsometricOperation.hpp
Go to the documentation of this file.
1#ifndef TATAMI_DELAYED_UNARY_ISOMETRIC_OPERATION_H
2#define TATAMI_DELAYED_UNARY_ISOMETRIC_OPERATION_H
3
7#include "../../utils/Index_to_container.hpp"
8#include "../depends_utils.hpp"
10
11#include <memory>
12#include <algorithm>
13#include <vector>
14#include <type_traits>
15#include <cstddef>
16
23namespace tatami {
24
28namespace DelayedUnaryIsometricOperation_internal {
29
40template<bool oracle_, typename OutputValue_, typename InputValue_, typename Index_, class Helper_>
41class DenseBasicFull final : public DenseExtractor<oracle_, OutputValue_, Index_> {
42public:
43 DenseBasicFull(
44 const Matrix<InputValue_, Index_>& matrix,
45 const Helper_& helper,
46 bool row,
47 MaybeOracle<oracle_, Index_> oracle,
48 const Options& opt) :
49 my_helper(helper),
50 my_row(row),
51 my_oracle(oracle, my_helper, row),
52 my_extent(row ? matrix.ncol() : matrix.nrow()),
53 my_ext(new_extractor<false, oracle_>(matrix, row, std::move(oracle), opt))
54 {
55 if constexpr(!same_value) {
56 resize_container_to_Index_size(my_holding_buffer, my_extent);
57 }
58 }
59
60private:
61 const Helper_& my_helper;
62
63 bool my_row;
64 DelayedIsometricOperation_internal::MaybeOracleDepends<oracle_, Helper_, Index_> my_oracle;
65 Index_ my_extent;
66
67 std::unique_ptr<DenseExtractor<oracle_, InputValue_, Index_> > my_ext;
68
69 static constexpr bool same_value = std::is_same<OutputValue_, InputValue_>::value;
70 typename std::conditional<!same_value, std::vector<InputValue_>, bool>::type my_holding_buffer;
71
72public:
73 const OutputValue_* fetch(Index_ i, OutputValue_* buffer) {
74 if constexpr(same_value) {
75 auto ptr = my_ext->fetch(i, buffer);
76 copy_n(ptr, my_extent, buffer);
77 my_helper.dense(my_row, my_oracle.get(i), static_cast<Index_>(0), my_extent, buffer, buffer);
78 } else {
79 auto ptr = my_ext->fetch(i, my_holding_buffer.data());
80 my_helper.dense(my_row, my_oracle.get(i), static_cast<Index_>(0), my_extent, ptr, buffer);
81 }
82 return buffer;
83 }
84};
85
86template<bool oracle_, typename OutputValue_, typename InputValue_, typename Index_, class Helper_>
87class DenseBasicBlock final : public DenseExtractor<oracle_, OutputValue_, Index_> {
88public:
89 DenseBasicBlock(
90 const Matrix<InputValue_, Index_>& matrix,
91 const Helper_& helper,
92 bool row,
93 MaybeOracle<oracle_, Index_> oracle,
94 Index_ block_start,
95 Index_ block_length,
96 const Options& opt) :
97 my_helper(helper),
98 my_row(row),
99 my_oracle(oracle, my_helper, row),
100 my_block_start(block_start),
101 my_block_length(block_length),
102 my_ext(new_extractor<false, oracle_>(matrix, row, std::move(oracle), block_start, block_length, opt))
103 {
104 if constexpr(!same_value) {
105 resize_container_to_Index_size(my_holding_buffer, my_block_length);
106 }
107 }
108
109private:
110 const Helper_& my_helper;
111
112 bool my_row;
113 DelayedIsometricOperation_internal::MaybeOracleDepends<oracle_, Helper_, Index_> my_oracle;
114 Index_ my_block_start, my_block_length;
115
116 std::unique_ptr<DenseExtractor<oracle_, InputValue_, Index_> > my_ext;
117
118 static constexpr bool same_value = std::is_same<OutputValue_, InputValue_>::value;
119 typename std::conditional<!same_value, std::vector<InputValue_>, bool>::type my_holding_buffer;
120
121public:
122 const OutputValue_* fetch(Index_ i, OutputValue_* buffer) {
123 if constexpr(same_value) {
124 auto ptr = my_ext->fetch(i, buffer);
125 copy_n(ptr, my_block_length, buffer);
126 my_helper.dense(my_row, my_oracle.get(i), my_block_start, my_block_length, buffer, buffer);
127 } else {
128 auto ptr = my_ext->fetch(i, my_holding_buffer.data());
129 my_helper.dense(my_row, my_oracle.get(i), my_block_start, my_block_length, ptr, buffer);
130 }
131 return buffer;
132 }
133};
134
135template<bool oracle_, typename OutputValue_, typename InputValue_, typename Index_, class Helper_>
136class DenseBasicIndex final : public DenseExtractor<oracle_, OutputValue_, Index_> {
137public:
138 DenseBasicIndex(
139 const Matrix<InputValue_, Index_>& matrix,
140 const Helper_& helper,
141 bool row,
142 MaybeOracle<oracle_, Index_> oracle,
143 VectorPtr<Index_> indices_ptr,
144 const Options& opt) :
145 my_helper(helper),
146 my_row(row),
147 my_oracle(oracle, my_helper, row),
148 my_indices_ptr(indices_ptr),
149 my_ext(new_extractor<false, oracle_>(matrix, row, std::move(oracle), std::move(indices_ptr), opt))
150 {
151 if constexpr(!same_value) {
152 resize_container_to_Index_size(my_holding_buffer, my_indices_ptr->size());
153 }
154 }
155
156private:
157 const Helper_& my_helper;
158
159 bool my_row;
160 DelayedIsometricOperation_internal::MaybeOracleDepends<oracle_, Helper_, Index_> my_oracle;
161 VectorPtr<Index_> my_indices_ptr;
162
163 std::unique_ptr<DenseExtractor<oracle_, InputValue_, Index_> > my_ext;
164
165 static constexpr bool same_value = std::is_same<OutputValue_, InputValue_>::value;
166 typename std::conditional<!same_value, std::vector<InputValue_>, bool>::type my_holding_buffer;
167
168public:
169 const OutputValue_* fetch(Index_ i, OutputValue_* buffer) {
170 const auto& indices = *my_indices_ptr;
171 if constexpr(same_value) {
172 auto ptr = my_ext->fetch(i, buffer);
173 copy_n(ptr, indices.size(), buffer);
174 my_helper.dense(my_row, my_oracle.get(i), indices, buffer, buffer);
175 } else {
176 auto ptr = my_ext->fetch(i, my_holding_buffer.data());
177 my_helper.dense(my_row, my_oracle.get(i), indices, ptr, buffer);
178 }
179 return buffer;
180 }
181};
182
194template<bool oracle_, typename OutputValue_, typename InputValue_, typename Index_, class Helper_>
195class DenseExpandedFull final : public DenseExtractor<oracle_, OutputValue_, Index_> {
196public:
197 DenseExpandedFull(
198 const Matrix<InputValue_, Index_>& matrix,
199 const Helper_& helper,
200 bool row,
201 MaybeOracle<oracle_, Index_> oracle,
202 Options opt) :
203 my_helper(helper),
204 my_row(row),
205 my_oracle(oracle, my_helper, row),
206 my_extent(row ? matrix.ncol() : matrix.nrow()),
207 my_vbuffer(cast_Index_to_container_size<decltype(my_vbuffer)>(my_extent)),
208 my_ibuffer(cast_Index_to_container_size<decltype(my_ibuffer)>(my_extent))
209 {
210 opt.sparse_extract_value = true;
211 opt.sparse_extract_index = true;
212 my_ext = new_extractor<true, oracle_>(matrix, my_row, std::move(oracle), opt);
213
214 if constexpr(!same_value) {
215 resize_container_to_Index_size(my_result_vbuffer, my_extent);
216 }
217 }
218
219private:
220 const Helper_& my_helper;
221
222 bool my_row;
223 DelayedIsometricOperation_internal::MaybeOracleDepends<oracle_, Helper_, Index_> my_oracle;
224 Index_ my_extent;
225
226 std::vector<InputValue_> my_vbuffer;
227 std::vector<Index_> my_ibuffer;
228 std::unique_ptr<SparseExtractor<oracle_, InputValue_, Index_> > my_ext;
229
230 static constexpr bool same_value = std::is_same<OutputValue_, InputValue_>::value;
231 typename std::conditional<!same_value, std::vector<OutputValue_>, bool>::type my_result_vbuffer;
232
233public:
234 const OutputValue_* fetch(Index_ i, OutputValue_* buffer) {
235 auto vbuffer = my_vbuffer.data();
236 auto range = my_ext->fetch(i, vbuffer, my_ibuffer.data());
237
238 i = my_oracle.get(i);
239 if constexpr(same_value) {
240 copy_n(range.value, range.number, vbuffer);
241 my_helper.sparse(my_row, i, range.number, vbuffer, range.index, vbuffer);
242 } else {
243 my_helper.sparse(my_row, i, range.number, range.value, range.index, my_result_vbuffer.data());
244 }
245
246 // avoid calling fill() if possible, as this might throw zero-related errors with non-IEEE-float types.
247 if (range.number < my_extent) {
248 std::fill_n(buffer, my_extent, my_helper.fill(my_row, i));
249 }
250
251 if constexpr(same_value) {
252 for (Index_ i = 0; i < range.number; ++i) {
253 buffer[range.index[i]] = vbuffer[i];
254 }
255 } else {
256 for (Index_ i = 0; i < range.number; ++i) {
257 buffer[range.index[i]] = my_result_vbuffer[i];
258 }
259 }
260
261 return buffer;
262 }
263};
264
265template<bool oracle_, typename OutputValue_, typename InputValue_, typename Index_, class Helper_>
266class DenseExpandedBlock final : public DenseExtractor<oracle_, OutputValue_, Index_> {
267public:
268 DenseExpandedBlock(
269 const Matrix<InputValue_, Index_>& matrix,
270 const Helper_& helper,
271 bool row,
272 MaybeOracle<oracle_, Index_> oracle,
273 Index_ block_start,
274 Index_ block_length,
275 Options opt) :
276 my_helper(helper),
277 my_row(row),
278 my_oracle(oracle, my_helper, row),
279 my_block_start(block_start),
280 my_block_length(block_length),
281 my_vbuffer(cast_Index_to_container_size<decltype(my_vbuffer)>(block_length)),
282 my_ibuffer(cast_Index_to_container_size<decltype(my_ibuffer)>(block_length))
283 {
284 opt.sparse_extract_value = true;
285 opt.sparse_extract_index = true;
286 my_ext = new_extractor<true, oracle_>(matrix, row, std::move(oracle), block_start, block_length, opt);
287
288 if constexpr(!same_value) {
289 resize_container_to_Index_size(my_result_vbuffer, my_block_length);
290 }
291 }
292
293private:
294 const Helper_& my_helper;
295
296 bool my_row;
297 DelayedIsometricOperation_internal::MaybeOracleDepends<oracle_, Helper_, Index_> my_oracle;
298 Index_ my_block_start, my_block_length;
299
300 std::vector<InputValue_> my_vbuffer;
301 std::vector<Index_> my_ibuffer;
302 std::unique_ptr<SparseExtractor<oracle_, InputValue_, Index_> > my_ext;
303
304 static constexpr bool same_value = std::is_same<OutputValue_, InputValue_>::value;
305 typename std::conditional<!same_value, std::vector<OutputValue_>, bool>::type my_result_vbuffer;
306
307public:
308 const OutputValue_* fetch(Index_ i, OutputValue_* buffer) {
309 auto vbuffer = my_vbuffer.data();
310 auto range = my_ext->fetch(i, vbuffer, my_ibuffer.data());
311
312 i = my_oracle.get(i);
313 if constexpr(same_value) {
314 copy_n(range.value, range.number, vbuffer);
315 my_helper.sparse(my_row, i, range.number, vbuffer, range.index, vbuffer);
316 } else {
317 my_helper.sparse(my_row, i, range.number, range.value, range.index, my_result_vbuffer.data());
318 }
319
320 // avoid calling fill() if possible, as this might throw zero-related errors with non-IEEE-float types.
321 if (range.number < my_block_length) {
322 std::fill_n(buffer, my_block_length, my_helper.fill(my_row, i));
323 }
324
325 if constexpr(same_value) {
326 for (Index_ i = 0; i < range.number; ++i) {
327 buffer[range.index[i] - my_block_start] = vbuffer[i];
328 }
329 } else {
330 for (Index_ i = 0; i < range.number; ++i) {
331 buffer[range.index[i] - my_block_start] = my_result_vbuffer[i];
332 }
333 }
334
335 return buffer;
336 }
337};
338
339template<bool oracle_, typename OutputValue_, typename InputValue_, typename Index_, class Helper_>
340class DenseExpandedIndex final : public DenseExtractor<oracle_, OutputValue_, Index_> {
341public:
342 DenseExpandedIndex(
343 const Matrix<InputValue_, Index_>& matrix,
344 const Helper_& helper,
345 bool row,
346 MaybeOracle<oracle_, Index_> oracle,
347 VectorPtr<Index_> indices_ptr,
348 Options opt) :
349 my_helper(helper),
350 my_row(row),
351 my_oracle(oracle, my_helper, row)
352 {
353 opt.sparse_extract_value = true;
354 opt.sparse_extract_index = true;
355
356 const auto& indices = *indices_ptr;
357 my_extent = indices.size();
358 resize_container_to_Index_size(my_vbuffer, my_extent);
359 resize_container_to_Index_size(my_ibuffer, my_extent);
360
361 // Create a remapping vector to map the extracted indices back to the
362 // dense buffer. We use the 'remapping_offset' to avoid allocating the
363 // full extent of the dimension.
364 if (my_extent) {
365 my_remapping_offset = indices.front();
366 resize_container_to_Index_size(my_remapping, indices.back() - my_remapping_offset + 1);
367 for (Index_ i = 0; i < my_extent; ++i) {
368 my_remapping[indices[i] - my_remapping_offset] = i;
369 }
370 }
371
372 my_ext = new_extractor<true, oracle_>(matrix, my_row, std::move(oracle), std::move(indices_ptr), opt);
373
374 if constexpr(!same_value) {
375 resize_container_to_Index_size(my_result_vbuffer, my_extent);
376 }
377 }
378
379private:
380 const Helper_& my_helper;
381
382 bool my_row;
383 DelayedIsometricOperation_internal::MaybeOracleDepends<oracle_, Helper_, Index_> my_oracle;
384 Index_ my_extent;
385
386 std::vector<InputValue_> my_vbuffer;
387 std::vector<Index_> my_ibuffer;
388
389 std::vector<Index_> my_remapping;
390 Index_ my_remapping_offset = 0;
391 std::unique_ptr<SparseExtractor<oracle_, InputValue_, Index_> > my_ext;
392
393 static constexpr bool same_value = std::is_same<OutputValue_, InputValue_>::value;
394 typename std::conditional<!same_value, std::vector<OutputValue_>, bool>::type my_result_vbuffer;
395
396public:
397 const OutputValue_* fetch(Index_ i, OutputValue_* buffer) {
398 auto vbuffer = my_vbuffer.data();
399 auto range = my_ext->fetch(i, vbuffer, my_ibuffer.data());
400
401 i = my_oracle.get(i);
402 if constexpr(same_value) {
403 copy_n(range.value, range.number, vbuffer);
404 my_helper.sparse(my_row, i, range.number, vbuffer, range.index, vbuffer);
405 } else {
406 my_helper.sparse(my_row, i, range.number, range.value, range.index, my_result_vbuffer.data());
407 }
408
409 // avoid calling fill() if possible, as this might throw zero-related errors with non-IEEE-float types.
410 if (range.number < my_extent) {
411 std::fill_n(buffer, my_extent, my_helper.fill(my_row, i));
412 }
413
414 if constexpr(same_value) {
415 for (Index_ i = 0; i < range.number; ++i) {
416 buffer[my_remapping[range.index[i] - my_remapping_offset]] = vbuffer[i];
417 }
418 } else {
419 for (Index_ i = 0; i < range.number; ++i) {
420 buffer[my_remapping[range.index[i] - my_remapping_offset]] = my_result_vbuffer[i];
421 }
422 }
423
424 return buffer;
425 }
426};
427
435template<bool oracle_, typename OutputValue_, typename InputValue_, typename Index_, class Helper_>
436class SparseSimple final : public SparseExtractor<oracle_, OutputValue_, Index_> {
437public:
438 SparseSimple(
439 const Matrix<InputValue_, Index_>& matrix,
440 const Helper_& helper,
441 bool row,
442 MaybeOracle<oracle_, Index_> oracle,
443 const Options& opt) :
444 my_helper(helper),
445 my_row(row),
446 my_oracle(oracle, my_helper, row),
447 my_ext(new_extractor<true, oracle_>(matrix, row, std::move(oracle), opt))
448 {
449 initialize(opt, row ? matrix.ncol() : matrix.nrow());
450 }
451
452 SparseSimple(
453 const Matrix<InputValue_, Index_>& matrix,
454 const Helper_& helper,
455 bool row,
456 MaybeOracle<oracle_, Index_> oracle,
457 Index_ block_start,
458 Index_ block_length,
459 const Options& opt) :
460 my_helper(helper),
461 my_row(row),
462 my_oracle(oracle, my_helper, row),
463 my_ext(new_extractor<true, oracle_>(matrix, row, std::move(oracle), block_start, block_length, opt))
464 {
465 initialize(opt, block_length);
466 }
467
468 SparseSimple(
469 const Matrix<InputValue_, Index_>& matrix,
470 const Helper_& helper,
471 bool row,
472 MaybeOracle<oracle_, Index_> oracle,
473 VectorPtr<Index_> indices_ptr,
474 const Options& opt) :
475 my_helper(helper),
476 my_row(row),
477 my_oracle(oracle, my_helper, row)
478 {
479 initialize(opt, indices_ptr->size());
480
481 // Need to construct this here so that indices_ptr isn't moved until after calling initialize().
482 my_ext = new_extractor<true, oracle_>(matrix, row, std::move(oracle), std::move(indices_ptr), opt);
483 }
484
485private:
486 const Helper_& my_helper;
487
488 bool my_row;
489 DelayedIsometricOperation_internal::MaybeOracleDepends<oracle_, Helper_, Index_> my_oracle;
490
491 std::unique_ptr<SparseExtractor<oracle_, InputValue_, Index_> > my_ext;
492
493 static constexpr bool same_value = std::is_same<OutputValue_, InputValue_>::value;
494 typename std::conditional<!same_value, std::vector<InputValue_>, bool>::type my_holding_vbuffer;
495
496 void initialize(const Options& opt, Index_ extent) {
497 if constexpr(!same_value) {
498 if (opt.sparse_extract_value) {
499 resize_container_to_Index_size(my_holding_vbuffer, extent);
500 }
501 }
502 }
503
504public:
505 SparseRange<OutputValue_, Index_> fetch(Index_ i, OutputValue_* value_buffer, Index_* index_buffer) {
506 if constexpr(same_value) {
507 auto raw = my_ext->fetch(i, value_buffer, index_buffer);
508 if (raw.value) {
509 copy_n(raw.value, raw.number, value_buffer);
510 my_helper.sparse(my_row, my_oracle.get(i), raw.number, value_buffer, raw.index, value_buffer);
511 raw.value = value_buffer;
512 }
513 return raw;
514 } else {
515 auto raw = my_ext->fetch(i, my_holding_vbuffer.data(), index_buffer);
516
517 SparseRange<OutputValue_, Index_> output(raw.number);
518 output.index = raw.index;
519 if (raw.value) {
520 my_helper.sparse(my_row, my_oracle.get(i), raw.number, raw.value, raw.index, value_buffer);
521 output.value = value_buffer;
522 }
523
524 return output;
525 }
526 }
527};
528
536template<bool oracle_, typename OutputValue_, typename InputValue_, typename Index_, class Helper_>
537class SparseNeedsIndices final : public SparseExtractor<oracle_, OutputValue_, Index_> {
538public:
539 SparseNeedsIndices(
540 const Matrix<InputValue_, Index_>& matrix,
541 const Helper_& helper,
542 bool row,
543 MaybeOracle<oracle_, Index_> oracle,
544 Options opt) :
545 my_helper(helper),
546 my_row(row),
547 my_oracle(oracle, my_helper, row)
548 {
549 initialize(opt, row ? matrix.ncol() : matrix.nrow());
550 my_ext = new_extractor<true, oracle_>(matrix, row, std::move(oracle), opt);
551 }
552
553 SparseNeedsIndices(
554 const Matrix<InputValue_, Index_>& matrix,
555 const Helper_& helper,
556 bool row,
557 MaybeOracle<oracle_, Index_> oracle,
558 Index_ block_start,
559 Index_ block_length,
560 Options opt) :
561 my_helper(helper),
562 my_row(row),
563 my_oracle(oracle, my_helper, row)
564 {
565 initialize(opt, block_length);
566 my_ext = new_extractor<true, oracle_>(matrix, row, std::move(oracle), block_start, block_length, opt);
567 }
568
569 SparseNeedsIndices(
570 const Matrix<InputValue_, Index_>& matrix,
571 const Helper_& helper,
572 bool row,
573 MaybeOracle<oracle_, Index_> oracle,
574 VectorPtr<Index_> indices_ptr,
575 Options opt) :
576 my_helper(helper),
577 my_row(row),
578 my_oracle(oracle, my_helper, row)
579 {
580 initialize(opt, indices_ptr->size());
581 my_ext = new_extractor<true, oracle_>(matrix, row, std::move(oracle), std::move(indices_ptr), opt);
582 }
583
584private:
585 void initialize(Options& opt, Index_ extent) {
586 my_report_value = opt.sparse_extract_value;
587 my_report_index = opt.sparse_extract_index;
588
589 // The index is not required if we don't even want the values,
590 // in which case Helper_::is_sparse() isn't even called.
591 if (my_report_value) {
592 opt.sparse_extract_index = true;
593
594 // We only need an internal ibuffer if the user wants the
595 // values but didn't provide enough space to store the indices
596 // (which we need to pass to Helper_::is_sparse()).
597 if (!my_report_index) {
598 resize_container_to_Index_size(my_ibuffer, extent);
599 }
600 }
601
602 if constexpr(!same_value) {
603 if (my_report_value) {
604 resize_container_to_Index_size(my_holding_vbuffer, extent);
605 }
606 }
607 }
608
609private:
610 const Helper_& my_helper;
611
612 bool my_row;
613 DelayedIsometricOperation_internal::MaybeOracleDepends<oracle_, Helper_, Index_> my_oracle;
614
615 bool my_report_value, my_report_index;
616 std::vector<Index_> my_ibuffer;
617
618 std::unique_ptr<SparseExtractor<oracle_, InputValue_, Index_> > my_ext;
619
620 static constexpr bool same_value = std::is_same<OutputValue_, InputValue_>::value;
621 typename std::conditional<!same_value, std::vector<InputValue_>, bool>::type my_holding_vbuffer;
622
623public:
624 SparseRange<OutputValue_, Index_> fetch(Index_ i, OutputValue_* value_buffer, Index_* index_buffer) {
625 auto iptr = my_report_index ? index_buffer : my_ibuffer.data();
626
627 if constexpr(same_value) {
628 auto raw = my_ext->fetch(i, value_buffer, iptr);
629 if (my_report_value) {
630 copy_n(raw.value, raw.number, value_buffer);
631 my_helper.sparse(my_row, my_oracle.get(i), raw.number, value_buffer, raw.index, value_buffer);
632 raw.value = value_buffer;
633 }
634 if (!my_report_index) {
635 raw.index = NULL;
636 }
637 return raw;
638
639 } else {
640 auto raw = my_ext->fetch(i, my_holding_vbuffer.data(), iptr);
641 SparseRange<OutputValue_, Index_> output(raw.number, NULL, (my_report_index ? raw.index : NULL));
642 if (my_report_value) {
643 my_helper.sparse(my_row, my_oracle.get(i), raw.number, raw.value, raw.index, value_buffer);
644 output.value = value_buffer;
645 }
646 return output;
647 }
648 }
649};
650
651}
670template<typename OutputValue_, typename InputValue_, typename Index_, class Helper_ = DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> >
671class DelayedUnaryIsometricOperation final : public Matrix<OutputValue_, Index_> {
672public:
678 std::shared_ptr<const Matrix<InputValue_, Index_> > matrix,
679 std::shared_ptr<const Helper_> helper
680 ) :
681 my_matrix(std::move(matrix)),
682 my_helper(std::move(helper))
683 {
684 auto expected_rows = my_helper->nrow();
685 if (expected_rows.has_value() && *expected_rows != my_matrix->nrow()) {
686 throw std::runtime_error("number of rows in 'matrix' is not consistent with those expected by 'helper'");
687 }
688 auto expected_cols = my_helper->ncol();
689 if (expected_cols.has_value() && *expected_cols != my_matrix->ncol()) {
690 throw std::runtime_error("number of columns in 'matrix' is not consistent with those expected by 'helper'");
691 }
692 }
693
694private:
695 std::shared_ptr<const Matrix<InputValue_, Index_> > my_matrix;
696 std::shared_ptr<const Helper_> my_helper;
697
698public:
699 Index_ nrow() const {
700 return my_matrix->nrow();
701 }
702
703 Index_ ncol() const {
704 return my_matrix->ncol();
705 }
706
707 bool is_sparse() const {
708 if (my_helper->is_sparse()) {
709 return my_matrix->is_sparse();
710 }
711 return false;
712 }
713
714 double is_sparse_proportion() const {
715 if (my_helper->is_sparse()) {
716 return my_matrix->is_sparse_proportion();
717 }
718 return 0;
719 }
720
721 bool prefer_rows() const {
722 return my_matrix->prefer_rows();
723 }
724
725 double prefer_rows_proportion() const {
726 return my_matrix->prefer_rows_proportion();
727 }
728
729 bool uses_oracle(bool row) const {
730 return my_matrix->uses_oracle(row);
731 }
732
733 using Matrix<OutputValue_, Index_>::dense;
734
735 using Matrix<OutputValue_, Index_>::sparse;
736
737 /********************
738 *** Myopic dense ***
739 ********************/
740private:
741 template<bool oracle_>
742 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_basic_internal(bool row, MaybeOracle<oracle_, Index_> oracle, const Options& opt) const {
743 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseBasicFull<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
744 *my_matrix,
745 *my_helper,
746 row,
747 std::move(oracle),
748 opt
749 );
750 }
751
752 template<bool oracle_>
753 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_basic_internal(bool row, MaybeOracle<oracle_, Index_> oracle, Index_ block_start, Index_ block_length, const Options& opt) const {
754 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseBasicBlock<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
755 *my_matrix,
756 *my_helper,
757 row,
758 std::move(oracle),
759 block_start,
760 block_length,
761 opt
762 );
763 }
764
765 template<bool oracle_>
766 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_basic_internal(bool row, MaybeOracle<oracle_, Index_> oracle, VectorPtr<Index_> indices_ptr, const Options& opt) const {
767 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseBasicIndex<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
768 *my_matrix,
769 *my_helper,
770 row,
771 std::move(oracle),
772 std::move(indices_ptr),
773 opt
774 );
775 }
776
777 template<bool oracle_>
778 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_expanded_internal(bool row, MaybeOracle<oracle_, Index_> oracle, const Options& opt) const {
779 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseExpandedFull<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
780 *my_matrix,
781 *my_helper,
782 row,
783 std::move(oracle),
784 opt
785 );
786 }
787
788 template<bool oracle_>
789 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_expanded_internal(bool row, MaybeOracle<oracle_, Index_> oracle, Index_ block_start, Index_ block_length, const Options& opt) const {
790 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseExpandedBlock<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
791 *my_matrix,
792 *my_helper,
793 row,
794 std::move(oracle),
795 block_start,
796 block_length,
797 opt
798 );
799 }
800
801 template<bool oracle_>
802 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_expanded_internal(bool row, MaybeOracle<oracle_, Index_> oracle, VectorPtr<Index_> indices_ptr, const Options& opt) const {
803 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseExpandedIndex<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
804 *my_matrix,
805 *my_helper,
806 row,
807 std::move(oracle),
808 std::move(indices_ptr),
809 opt
810 );
811 }
812
813 template<bool oracle_, typename ... Args_>
814 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_internal(bool row, Args_&& ... args) const {
815 if (my_matrix->is_sparse()) {
816 if (DelayedIsometricOperation_internal::can_dense_expand(*my_helper, row)) {
817 return dense_expanded_internal<oracle_>(row, std::forward<Args_>(args)...);
818 }
819 }
820 return dense_basic_internal<oracle_>(row, std::forward<Args_>(args)...);
821 }
822
823public:
824 std::unique_ptr<MyopicDenseExtractor<OutputValue_, Index_> > dense(bool row, const Options& opt) const {
825 return dense_internal<false>(row, false, opt);
826 }
827
828 std::unique_ptr<MyopicDenseExtractor<OutputValue_, Index_> > dense(bool row, Index_ block_start, Index_ block_length, const Options& opt) const {
829 return dense_internal<false>(row, false, block_start, block_length, opt);
830 }
831
832 std::unique_ptr<MyopicDenseExtractor<OutputValue_, Index_> > dense(bool row, VectorPtr<Index_> indices_ptr, const Options& opt) const {
833 return dense_internal<false>(row, false, std::move(indices_ptr), opt);
834 }
835
836 /*********************
837 *** Myopic sparse ***
838 *********************/
839private:
840 template<bool oracle_, typename ... Args_>
841 std::unique_ptr<SparseExtractor<oracle_, OutputValue_, Index_> > sparse_to_dense_internal(bool row, MaybeOracle<oracle_, Index_> oracle, const Options& opt) const {
842 return std::make_unique<FullSparsifiedWrapper<oracle_, OutputValue_, Index_> >(
843 dense_internal<oracle_>(row, std::move(oracle), opt),
844 (row ? my_matrix->ncol() : my_matrix->nrow()),
845 opt
846 );
847 }
848
849 template<bool oracle_, typename ... Args_>
850 std::unique_ptr<SparseExtractor<oracle_, OutputValue_, Index_> > sparse_to_dense_internal(bool row, MaybeOracle<oracle_, Index_> oracle, Index_ block_start, Index_ block_length, const Options& opt) const {
851 return std::make_unique<BlockSparsifiedWrapper<oracle_, OutputValue_, Index_> >(
852 dense_internal<oracle_>(row, std::move(oracle), block_start, block_length, opt),
853 block_start,
854 block_length,
855 opt
856 );
857 }
858
859 template<bool oracle_, typename ... Args_>
860 std::unique_ptr<SparseExtractor<oracle_, OutputValue_, Index_> > sparse_to_dense_internal(bool row, MaybeOracle<oracle_, Index_> oracle, VectorPtr<Index_> indices_ptr, const Options& opt) const {
861 return std::make_unique<IndexSparsifiedWrapper<oracle_, OutputValue_, Index_> >(
862 dense_internal<oracle_>(row, std::move(oracle), indices_ptr, opt),
863 indices_ptr,
864 opt
865 );
866 }
867
868 template<bool oracle_, typename ... Args_>
869 std::unique_ptr<SparseExtractor<oracle_, OutputValue_, Index_> > sparse_internal(bool row, MaybeOracle<oracle_, Index_> oracle, Args_&& ... args) const {
870 if (my_helper->is_sparse() && my_matrix->is_sparse()) {
871 if (DelayedIsometricOperation_internal::needs_sparse_indices(*my_helper, row)) {
872 return std::make_unique<DelayedUnaryIsometricOperation_internal::SparseNeedsIndices<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
873 *my_matrix,
874 *my_helper,
875 row,
876 std::move(oracle),
877 std::forward<Args_>(args)...
878 );
879
880 } else {
881 return std::make_unique<DelayedUnaryIsometricOperation_internal::SparseSimple<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
882 *my_matrix,
883 *my_helper,
884 row,
885 std::move(oracle),
886 std::forward<Args_>(args)...
887 );
888 }
889 }
890 return sparse_to_dense_internal<oracle_>(row, std::move(oracle), std::forward<Args_>(args)...);
891 }
892
893public:
894 std::unique_ptr<MyopicSparseExtractor<OutputValue_, Index_> > sparse(bool row, const Options& opt) const {
895 return sparse_internal<false>(row, false, opt);
896 }
897
898 std::unique_ptr<MyopicSparseExtractor<OutputValue_, Index_> > sparse(bool row, Index_ block_start, Index_ block_length, const Options& opt) const {
899 return sparse_internal<false>(row, false, block_start, block_length, opt);
900 }
901
902 std::unique_ptr<MyopicSparseExtractor<OutputValue_, Index_> > sparse(bool row, VectorPtr<Index_> indices_ptr, const Options& opt) const {
903 return sparse_internal<false>(row, false, std::move(indices_ptr), opt);
904 }
905
906 /**********************
907 *** Oracular dense ***
908 **********************/
909public:
910 std::unique_ptr<OracularDenseExtractor<OutputValue_, Index_> > dense(bool row, std::shared_ptr<const Oracle<Index_> > oracle, const Options& opt) const {
911 return dense_internal<true>(row, std::move(oracle), opt);
912 }
913
914 std::unique_ptr<OracularDenseExtractor<OutputValue_, Index_> > dense(bool row, std::shared_ptr<const Oracle<Index_> > oracle, Index_ block_start, Index_ block_length, const Options& opt) const {
915 return dense_internal<true>(row, std::move(oracle), block_start, block_length, opt);
916 }
917
918 std::unique_ptr<OracularDenseExtractor<OutputValue_, Index_> > dense(bool row, std::shared_ptr<const Oracle<Index_> > oracle, VectorPtr<Index_> indices_ptr, const Options& opt) const {
919 return dense_internal<true>(row, std::move(oracle), std::move(indices_ptr), opt);
920 }
921
922 /***********************
923 *** Oracular sparse ***
924 ***********************/
925public:
926 std::unique_ptr<OracularSparseExtractor<OutputValue_, Index_> > sparse(bool row, std::shared_ptr<const Oracle<Index_> > oracle, const Options& opt) const {
927 return sparse_internal<true>(row, std::move(oracle), opt);
928 }
929
930 std::unique_ptr<OracularSparseExtractor<OutputValue_, Index_> > sparse(bool row, std::shared_ptr<const Oracle<Index_> > oracle, Index_ block_start, Index_ block_length, const Options& opt) const {
931 return sparse_internal<true>(row, std::move(oracle), block_start, block_length, opt);
932 }
933
934 std::unique_ptr<OracularSparseExtractor<OutputValue_, Index_> > sparse(bool row, std::shared_ptr<const Oracle<Index_> > oracle, VectorPtr<Index_> indices_ptr, const Options& opt) const {
935 return sparse_internal<true>(row, std::move(oracle), std::move(indices_ptr), opt);
936 }
937};
938
942// For back-compatibility.
943template<typename OutputValue_ = double, typename InputValue_, typename Index_, class Helper_>
944std::shared_ptr<Matrix<OutputValue_, Index_> > make_DelayedUnaryIsometricOperation(std::shared_ptr<const Matrix<InputValue_, Index_> > matrix, std::shared_ptr<const Helper_> helper) {
945 return std::shared_ptr<Matrix<OutputValue_, Index_> >(new DelayedUnaryIsometricOperation<OutputValue_, InputValue_, Index_, Helper_>(std::move(matrix), std::move(helper)));
946}
947
948template<typename OutputValue_ = double, typename InputValue_, typename Index_, class Helper_>
949std::shared_ptr<Matrix<OutputValue_, Index_> > make_DelayedUnaryIsometricOperation(std::shared_ptr<Matrix<InputValue_, Index_> > matrix, std::shared_ptr<Helper_> helper) {
950 return std::shared_ptr<Matrix<OutputValue_, Index_> >(new DelayedUnaryIsometricOperation<OutputValue_, InputValue_, Index_, Helper_>(std::move(matrix), std::move(helper)));
951}
952
953template<typename ... Args_>
954auto make_DelayedIsometricOperation(Args_&&... args) {
955 return make_DelayedUnaryIsometricOperation(std::forward<Args_>(args)...);
956}
957
958template<typename OutputValue_, typename Index_, class Helper_>
959using DelayedIsometricOperation = DelayedUnaryIsometricOperation<OutputValue_, Index_, Helper_, OutputValue_>;
964}
965
966#endif
Virtual class for a matrix of some numeric type.
Delayed isometric operation on a single matrix.
Definition DelayedUnaryIsometricOperation.hpp:671
bool prefer_rows() const
Definition DelayedUnaryIsometricOperation.hpp:721
double is_sparse_proportion() const
Definition DelayedUnaryIsometricOperation.hpp:714
std::unique_ptr< OracularDenseExtractor< OutputValue_, Index_ > > dense(bool row, std::shared_ptr< const Oracle< Index_ > > oracle, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:910
std::unique_ptr< MyopicDenseExtractor< OutputValue_, Index_ > > dense(bool row, VectorPtr< Index_ > indices_ptr, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:832
std::unique_ptr< MyopicDenseExtractor< OutputValue_, Index_ > > dense(bool row, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:824
Index_ ncol() const
Definition DelayedUnaryIsometricOperation.hpp:703
std::unique_ptr< OracularDenseExtractor< OutputValue_, Index_ > > dense(bool row, std::shared_ptr< const Oracle< Index_ > > oracle, VectorPtr< Index_ > indices_ptr, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:918
std::unique_ptr< OracularSparseExtractor< OutputValue_, Index_ > > sparse(bool row, std::shared_ptr< const Oracle< Index_ > > oracle, VectorPtr< Index_ > indices_ptr, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:934
bool uses_oracle(bool row) const
Definition DelayedUnaryIsometricOperation.hpp:729
std::unique_ptr< OracularSparseExtractor< OutputValue_, Index_ > > sparse(bool row, std::shared_ptr< const Oracle< Index_ > > oracle, Index_ block_start, Index_ block_length, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:930
double prefer_rows_proportion() const
Definition DelayedUnaryIsometricOperation.hpp:725
DelayedUnaryIsometricOperation(std::shared_ptr< const Matrix< InputValue_, Index_ > > matrix, std::shared_ptr< const Helper_ > helper)
Definition DelayedUnaryIsometricOperation.hpp:677
bool is_sparse() const
Definition DelayedUnaryIsometricOperation.hpp:707
std::unique_ptr< MyopicSparseExtractor< OutputValue_, Index_ > > sparse(bool row, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:894
std::unique_ptr< MyopicDenseExtractor< OutputValue_, Index_ > > dense(bool row, Index_ block_start, Index_ block_length, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:828
std::unique_ptr< OracularDenseExtractor< OutputValue_, Index_ > > dense(bool row, std::shared_ptr< const Oracle< Index_ > > oracle, Index_ block_start, Index_ block_length, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:914
std::unique_ptr< OracularSparseExtractor< OutputValue_, Index_ > > sparse(bool row, std::shared_ptr< const Oracle< Index_ > > oracle, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:926
std::unique_ptr< MyopicSparseExtractor< OutputValue_, Index_ > > sparse(bool row, VectorPtr< Index_ > indices_ptr, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:902
Index_ nrow() const
Definition DelayedUnaryIsometricOperation.hpp:699
std::unique_ptr< MyopicSparseExtractor< OutputValue_, Index_ > > sparse(bool row, Index_ block_start, Index_ block_length, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:898
Virtual class for a matrix.
Definition Matrix.hpp:59
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
decltype(std::declval< Container_ >().size()) cast_Index_to_container_size(Index_ x)
Definition Index_to_container.hpp:54
void resize_container_to_Index_size(Container_ &container, Index_ x, Args_ &&... args)
Definition Index_to_container.hpp:88
typename std::conditional< oracle_, std::shared_ptr< const Oracle< Index_ > >, bool >::type MaybeOracle
Definition new_extractor.hpp:20
typename std::conditional< oracle_, OracularDenseExtractor< Value_, Index_ >, MyopicDenseExtractor< Value_, Index_ > >::type DenseExtractor
Definition Extractor.hpp:273
Value_ * copy_n(const Value_ *input, Size_ n, Value_ *output)
Definition copy.hpp:26
auto new_extractor(const Matrix< Value_, Index_ > &matrix, bool row, MaybeOracle< oracle_, Index_ > oracle, Args_ &&... args)
Definition new_extractor.hpp:42
Templated construction of a new extractor.
Options for accessing data from a Matrix instance.
Definition Options.hpp:30
Interface for tatami::DelayedUnaryIsometricOperation helpers.