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 const 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(const Index_ i, OutputValue_* const buffer) {
74 if constexpr(same_value) {
75 const 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 const 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 const bool row,
93 MaybeOracle<oracle_, Index_> oracle,
94 const Index_ block_start,
95 const 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(const Index_ i, OutputValue_* const buffer) {
123 if constexpr(same_value) {
124 const 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 const 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 const 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(const Index_ i, OutputValue_* const buffer) {
170 const auto& indices = *my_indices_ptr;
171 if constexpr(same_value) {
172 const 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 const 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 const 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<I<decltype(my_vbuffer)> >(my_extent)),
208 my_ibuffer(cast_Index_to_container_size<I<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_* const buffer) {
235 const auto vbuffer = my_vbuffer.data();
236 const 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 const bool row,
272 MaybeOracle<oracle_, Index_> oracle,
273 const Index_ block_start,
274 const 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<I<decltype(my_vbuffer)> >(block_length)),
282 my_ibuffer(cast_Index_to_container_size<I<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_* const buffer) {
309 const auto vbuffer = my_vbuffer.data();
310 const 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 const 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_* const buffer) {
398 const auto vbuffer = my_vbuffer.data();
399 const 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 const 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 const bool row,
456 MaybeOracle<oracle_, Index_> oracle,
457 const Index_ block_start,
458 const 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 const 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, const 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(const Index_ i, OutputValue_* const value_buffer, Index_* const 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 const 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 const 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 const bool row,
557 MaybeOracle<oracle_, Index_> oracle,
558 const Index_ block_start,
559 const 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 const 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, const 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(const Index_ i, OutputValue_* const value_buffer, Index_* const index_buffer) {
625 const 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 const 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 const 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 const 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(const 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(
743 const bool row,
745 const Options& opt
746 ) const {
747 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseBasicFull<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
748 *my_matrix,
749 *my_helper,
750 row,
751 std::move(oracle),
752 opt
753 );
754 }
755
756 template<bool oracle_>
757 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_basic_internal(
758 const bool row,
760 const Index_ block_start,
761 const Index_ block_length,
762 const Options& opt
763 ) const {
764 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseBasicBlock<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
765 *my_matrix,
766 *my_helper,
767 row,
768 std::move(oracle),
769 block_start,
770 block_length,
771 opt
772 );
773 }
774
775 template<bool oracle_>
776 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_basic_internal(
777 const bool row,
779 VectorPtr<Index_> indices_ptr,
780 const Options& opt
781 ) const {
782 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseBasicIndex<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
783 *my_matrix,
784 *my_helper,
785 row,
786 std::move(oracle),
787 std::move(indices_ptr),
788 opt
789 );
790 }
791
792 template<bool oracle_>
793 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_expanded_internal(
794 const bool row,
796 const Options& opt
797 ) const {
798 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseExpandedFull<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
799 *my_matrix,
800 *my_helper,
801 row,
802 std::move(oracle),
803 opt
804 );
805 }
806
807 template<bool oracle_>
808 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_expanded_internal(
809 const bool row,
811 const Index_ block_start,
812 const Index_ block_length,
813 const Options& opt
814 ) const {
815 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseExpandedBlock<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
816 *my_matrix,
817 *my_helper,
818 row,
819 std::move(oracle),
820 block_start,
821 block_length,
822 opt
823 );
824 }
825
826 template<bool oracle_>
827 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_expanded_internal(
828 const bool row,
830 VectorPtr<Index_> indices_ptr,
831 const Options& opt
832 ) const {
833 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseExpandedIndex<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
834 *my_matrix,
835 *my_helper,
836 row,
837 std::move(oracle),
838 std::move(indices_ptr),
839 opt
840 );
841 }
842
843 template<bool oracle_, typename ... Args_>
844 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_internal(
845 const bool row,
846 Args_&& ... args
847 ) const {
848 if (my_matrix->is_sparse()) {
849 if (DelayedIsometricOperation_internal::can_dense_expand(*my_helper, row)) {
850 return dense_expanded_internal<oracle_>(row, std::forward<Args_>(args)...);
851 }
852 }
853 return dense_basic_internal<oracle_>(row, std::forward<Args_>(args)...);
854 }
855
856public:
857 std::unique_ptr<MyopicDenseExtractor<OutputValue_, Index_> > dense(
858 const bool row,
859 const Options& opt
860 ) const {
861 return dense_internal<false>(row, false, opt);
862 }
863
864 std::unique_ptr<MyopicDenseExtractor<OutputValue_, Index_> > dense(
865 const bool row,
866 const Index_ block_start,
867 const Index_ block_length,
868 const Options& opt
869 ) const {
870 return dense_internal<false>(row, false, block_start, block_length, opt);
871 }
872
873 std::unique_ptr<MyopicDenseExtractor<OutputValue_, Index_> > dense(
874 const bool row,
875 VectorPtr<Index_> indices_ptr,
876 const Options& opt
877 ) const {
878 return dense_internal<false>(row, false, std::move(indices_ptr), opt);
879 }
880
881 /*********************
882 *** Myopic sparse ***
883 *********************/
884private:
885 template<bool oracle_, typename ... Args_>
886 std::unique_ptr<SparseExtractor<oracle_, OutputValue_, Index_> > sparse_to_dense_internal(
887 const bool row,
889 const Options& opt
890 ) const {
891 return std::make_unique<FullSparsifiedWrapper<oracle_, OutputValue_, Index_> >(
892 dense_internal<oracle_>(row, std::move(oracle), opt),
893 (row ? my_matrix->ncol() : my_matrix->nrow()),
894 opt
895 );
896 }
897
898 template<bool oracle_, typename ... Args_>
899 std::unique_ptr<SparseExtractor<oracle_, OutputValue_, Index_> > sparse_to_dense_internal(
900 const bool row,
902 const Index_ block_start,
903 const Index_ block_length,
904 const Options& opt
905 ) const {
906 return std::make_unique<BlockSparsifiedWrapper<oracle_, OutputValue_, Index_> >(
907 dense_internal<oracle_>(row, std::move(oracle), block_start, block_length, opt),
908 block_start,
909 block_length,
910 opt
911 );
912 }
913
914 template<bool oracle_, typename ... Args_>
915 std::unique_ptr<SparseExtractor<oracle_, OutputValue_, Index_> > sparse_to_dense_internal(
916 const bool row,
918 VectorPtr<Index_> indices_ptr,
919 const Options& opt
920 ) const {
921 return std::make_unique<IndexSparsifiedWrapper<oracle_, OutputValue_, Index_> >(
922 dense_internal<oracle_>(row, std::move(oracle), indices_ptr, opt),
923 indices_ptr,
924 opt
925 );
926 }
927
928 template<bool oracle_, typename ... Args_>
929 std::unique_ptr<SparseExtractor<oracle_, OutputValue_, Index_> > sparse_internal(
930 const bool row,
932 Args_&& ... args
933 ) const {
934 if (my_helper->is_sparse() && my_matrix->is_sparse()) {
935 if (DelayedIsometricOperation_internal::needs_sparse_indices(*my_helper, row)) {
936 return std::make_unique<DelayedUnaryIsometricOperation_internal::SparseNeedsIndices<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
937 *my_matrix,
938 *my_helper,
939 row,
940 std::move(oracle),
941 std::forward<Args_>(args)...
942 );
943
944 } else {
945 return std::make_unique<DelayedUnaryIsometricOperation_internal::SparseSimple<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
946 *my_matrix,
947 *my_helper,
948 row,
949 std::move(oracle),
950 std::forward<Args_>(args)...
951 );
952 }
953 }
954 return sparse_to_dense_internal<oracle_>(row, std::move(oracle), std::forward<Args_>(args)...);
955 }
956
957public:
958 std::unique_ptr<MyopicSparseExtractor<OutputValue_, Index_> > sparse(
959 const bool row,
960 const Options& opt
961 ) const {
962 return sparse_internal<false>(row, false, opt);
963 }
964
965 std::unique_ptr<MyopicSparseExtractor<OutputValue_, Index_> > sparse(
966 const bool row,
967 const Index_ block_start,
968 const Index_ block_length,
969 const Options& opt
970 ) const {
971 return sparse_internal<false>(row, false, block_start, block_length, opt);
972 }
973
974 std::unique_ptr<MyopicSparseExtractor<OutputValue_, Index_> > sparse(
975 const bool row,
976 VectorPtr<Index_> indices_ptr,
977 const Options& opt
978 ) const {
979 return sparse_internal<false>(row, false, std::move(indices_ptr), opt);
980 }
981
982 /**********************
983 *** Oracular dense ***
984 **********************/
985public:
986 std::unique_ptr<OracularDenseExtractor<OutputValue_, Index_> > dense(
987 const bool row,
988 std::shared_ptr<const Oracle<Index_> > oracle,
989 const Options& opt
990 ) const {
991 return dense_internal<true>(row, std::move(oracle), opt);
992 }
993
994 std::unique_ptr<OracularDenseExtractor<OutputValue_, Index_> > dense(
995 const bool row,
996 std::shared_ptr<const Oracle<Index_> > oracle,
997 const Index_ block_start,
998 const Index_ block_length,
999 const Options& opt
1000 ) const {
1001 return dense_internal<true>(row, std::move(oracle), block_start, block_length, opt);
1002 }
1003
1004 std::unique_ptr<OracularDenseExtractor<OutputValue_, Index_> > dense(
1005 const bool row,
1006 std::shared_ptr<const Oracle<Index_> > oracle,
1007 VectorPtr<Index_> indices_ptr,
1008 const Options& opt
1009 ) const {
1010 return dense_internal<true>(row, std::move(oracle), std::move(indices_ptr), opt);
1011 }
1012
1013 /***********************
1014 *** Oracular sparse ***
1015 ***********************/
1016public:
1017 std::unique_ptr<OracularSparseExtractor<OutputValue_, Index_> > sparse(
1018 const bool row,
1019 std::shared_ptr<const Oracle<Index_> > oracle,
1020 const Options& opt
1021 ) const {
1022 return sparse_internal<true>(row, std::move(oracle), opt);
1023 }
1024
1025 std::unique_ptr<OracularSparseExtractor<OutputValue_, Index_> > sparse(
1026 const bool row,
1027 std::shared_ptr<const Oracle<Index_> > oracle,
1028 const Index_ block_start,
1029 const Index_ block_length,
1030 const Options& opt
1031 ) const {
1032 return sparse_internal<true>(row, std::move(oracle), block_start, block_length, opt);
1033 }
1034
1035 std::unique_ptr<OracularSparseExtractor<OutputValue_, Index_> > sparse(
1036 const bool row,
1037 std::shared_ptr<const Oracle<Index_> > oracle,
1038 VectorPtr<Index_> indices_ptr,
1039 const Options& opt
1040 ) const {
1041 return sparse_internal<true>(row, std::move(oracle), std::move(indices_ptr), opt);
1042 }
1043};
1044
1048// For back-compatibility.
1049template<typename OutputValue_ = double, typename InputValue_, typename Index_, class Helper_>
1050std::shared_ptr<Matrix<OutputValue_, Index_> > make_DelayedUnaryIsometricOperation(std::shared_ptr<const Matrix<InputValue_, Index_> > matrix, std::shared_ptr<const Helper_> helper) {
1051 return std::shared_ptr<Matrix<OutputValue_, Index_> >(new DelayedUnaryIsometricOperation<OutputValue_, InputValue_, Index_, Helper_>(std::move(matrix), std::move(helper)));
1052}
1053
1054template<typename OutputValue_ = double, typename InputValue_, typename Index_, class Helper_>
1055std::shared_ptr<Matrix<OutputValue_, Index_> > make_DelayedUnaryIsometricOperation(std::shared_ptr<Matrix<InputValue_, Index_> > matrix, std::shared_ptr<Helper_> helper) {
1056 return std::shared_ptr<Matrix<OutputValue_, Index_> >(new DelayedUnaryIsometricOperation<OutputValue_, InputValue_, Index_, Helper_>(std::move(matrix), std::move(helper)));
1057}
1058
1059template<typename ... Args_>
1060auto make_DelayedIsometricOperation(Args_&&... args) {
1061 return make_DelayedUnaryIsometricOperation(std::forward<Args_>(args)...);
1062}
1063
1064template<typename OutputValue_, typename Index_, class Helper_>
1065using DelayedIsometricOperation = DelayedUnaryIsometricOperation<OutputValue_, Index_, Helper_, OutputValue_>;
1070}
1071
1072#endif
Virtual class for a matrix of some numeric type.
Delayed isometric operation on a single matrix.
Definition DelayedUnaryIsometricOperation.hpp:671
std::unique_ptr< MyopicSparseExtractor< OutputValue_, Index_ > > sparse(const bool row, VectorPtr< Index_ > indices_ptr, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:974
bool prefer_rows() const
Definition DelayedUnaryIsometricOperation.hpp:721
double is_sparse_proportion() const
Definition DelayedUnaryIsometricOperation.hpp:714
std::unique_ptr< OracularDenseExtractor< OutputValue_, Index_ > > dense(const bool row, std::shared_ptr< const Oracle< Index_ > > oracle, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:986
bool uses_oracle(const bool row) const
Definition DelayedUnaryIsometricOperation.hpp:729
std::unique_ptr< MyopicSparseExtractor< OutputValue_, Index_ > > sparse(const bool row, const Index_ block_start, const Index_ block_length, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:965
Index_ ncol() const
Definition DelayedUnaryIsometricOperation.hpp:703
std::unique_ptr< MyopicDenseExtractor< OutputValue_, Index_ > > dense(const bool row, VectorPtr< Index_ > indices_ptr, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:873
std::unique_ptr< OracularSparseExtractor< OutputValue_, Index_ > > sparse(const bool row, std::shared_ptr< const Oracle< Index_ > > oracle, VectorPtr< Index_ > indices_ptr, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:1035
std::unique_ptr< OracularSparseExtractor< OutputValue_, Index_ > > sparse(const bool row, std::shared_ptr< const Oracle< Index_ > > oracle, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:1017
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< MyopicDenseExtractor< OutputValue_, Index_ > > dense(const bool row, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:857
std::unique_ptr< OracularDenseExtractor< OutputValue_, Index_ > > dense(const bool row, std::shared_ptr< const Oracle< Index_ > > oracle, VectorPtr< Index_ > indices_ptr, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:1004
std::unique_ptr< OracularDenseExtractor< OutputValue_, 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 DelayedUnaryIsometricOperation.hpp:994
std::unique_ptr< MyopicSparseExtractor< OutputValue_, Index_ > > sparse(const bool row, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:958
std::unique_ptr< OracularSparseExtractor< OutputValue_, 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 DelayedUnaryIsometricOperation.hpp:1025
std::unique_ptr< MyopicDenseExtractor< OutputValue_, Index_ > > dense(const bool row, const Index_ block_start, const Index_ block_length, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:864
Index_ nrow() const
Definition DelayedUnaryIsometricOperation.hpp:699
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
auto new_extractor(const Matrix< Value_, Index_ > &matrix, const bool row, MaybeOracle< oracle_, Index_ > oracle, Args_ &&... args)
Definition new_extractor.hpp:42
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_, 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
I< decltype(std::declval< Container_ >().size())> cast_Index_to_container_size(const Index_ x)
Definition Index_to_container.hpp:56
Value_ * copy_n(const Value_ *const input, const Size_ n, Value_ *const output)
Definition copy.hpp:37
Templated construction of a new extractor.
Options for accessing data from a Matrix instance.
Definition Options.hpp:30
Interface for tatami::DelayedUnaryIsometricOperation helpers.