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
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 // Construct my_ext here, because we need to get the size for my_extent before moving indices_ptr.
373 my_ext = new_extractor<true, oracle_>(matrix, my_row, std::move(oracle), std::move(indices_ptr), opt);
374
375 if constexpr(!same_value) {
376 resize_container_to_Index_size(my_result_vbuffer, my_extent);
377 }
378 }
379
380private:
381 const Helper_& my_helper;
382
383 bool my_row;
384 DelayedIsometricOperation_internal::MaybeOracleDepends<oracle_, Helper_, Index_> my_oracle;
385 Index_ my_extent;
386
387 std::vector<InputValue_> my_vbuffer;
388 std::vector<Index_> my_ibuffer;
389
390 std::vector<Index_> my_remapping;
391 Index_ my_remapping_offset = 0;
392 std::unique_ptr<SparseExtractor<oracle_, InputValue_, Index_> > my_ext;
393
394 static constexpr bool same_value = std::is_same<OutputValue_, InputValue_>::value;
395 typename std::conditional<!same_value, std::vector<OutputValue_>, bool>::type my_result_vbuffer;
396
397public:
398 const OutputValue_* fetch(Index_ i, OutputValue_* const buffer) {
399 const auto vbuffer = my_vbuffer.data();
400 const auto range = my_ext->fetch(i, vbuffer, my_ibuffer.data());
401
402 i = my_oracle.get(i);
403 if constexpr(same_value) {
404 copy_n(range.value, range.number, vbuffer);
405 my_helper.sparse(my_row, i, range.number, vbuffer, range.index, vbuffer);
406 } else {
407 my_helper.sparse(my_row, i, range.number, range.value, range.index, my_result_vbuffer.data());
408 }
409
410 // avoid calling fill() if possible, as this might throw zero-related errors with non-IEEE-float types.
411 if (range.number < my_extent) {
412 std::fill_n(buffer, my_extent, my_helper.fill(my_row, i));
413 }
414
415 if constexpr(same_value) {
416 for (Index_ i = 0; i < range.number; ++i) {
417 buffer[my_remapping[range.index[i] - my_remapping_offset]] = vbuffer[i];
418 }
419 } else {
420 for (Index_ i = 0; i < range.number; ++i) {
421 buffer[my_remapping[range.index[i] - my_remapping_offset]] = my_result_vbuffer[i];
422 }
423 }
424
425 return buffer;
426 }
427};
428
436template<bool oracle_, typename OutputValue_, typename InputValue_, typename Index_, class Helper_>
437class SparseSimple final : public SparseExtractor<oracle_, OutputValue_, Index_> {
438public:
439 SparseSimple(
440 const Matrix<InputValue_, Index_>& matrix,
441 const Helper_& helper,
442 const bool row,
443 MaybeOracle<oracle_, Index_> oracle,
444 const Options& opt) :
445 my_helper(helper),
446 my_row(row),
447 my_oracle(oracle, my_helper, row),
448 my_ext(new_extractor<true, oracle_>(matrix, row, std::move(oracle), opt))
449 {
450 initialize(opt, row ? matrix.ncol() : matrix.nrow());
451 }
452
453 SparseSimple(
454 const Matrix<InputValue_, Index_>& matrix,
455 const Helper_& helper,
456 const bool row,
457 MaybeOracle<oracle_, Index_> oracle,
458 const Index_ block_start,
459 const Index_ block_length,
460 const Options& opt) :
461 my_helper(helper),
462 my_row(row),
463 my_oracle(oracle, my_helper, row),
464 my_ext(new_extractor<true, oracle_>(matrix, row, std::move(oracle), block_start, block_length, opt))
465 {
466 initialize(opt, block_length);
467 }
468
469 SparseSimple(
470 const Matrix<InputValue_, Index_>& matrix,
471 const Helper_& helper,
472 const bool row,
473 MaybeOracle<oracle_, Index_> oracle,
474 VectorPtr<Index_> indices_ptr,
475 const Options& opt) :
476 my_helper(helper),
477 my_row(row),
478 my_oracle(oracle, my_helper, row)
479 {
480 initialize(opt, indices_ptr->size());
481
482 // Need to construct this here so that indices_ptr isn't moved until after calling initialize().
483 my_ext = new_extractor<true, oracle_>(matrix, row, std::move(oracle), std::move(indices_ptr), opt);
484 }
485
486private:
487 const Helper_& my_helper;
488
489 bool my_row;
490 DelayedIsometricOperation_internal::MaybeOracleDepends<oracle_, Helper_, Index_> my_oracle;
491
492 std::unique_ptr<SparseExtractor<oracle_, InputValue_, Index_> > my_ext;
493
494 static constexpr bool same_value = std::is_same<OutputValue_, InputValue_>::value;
495 typename std::conditional<!same_value, std::vector<InputValue_>, bool>::type my_holding_vbuffer;
496
497 void initialize(const Options& opt, const Index_ extent) {
498 if constexpr(!same_value) {
499 if (opt.sparse_extract_value) {
500 resize_container_to_Index_size(my_holding_vbuffer, extent);
501 }
502 }
503 }
504
505public:
506 SparseRange<OutputValue_, Index_> fetch(const Index_ i, OutputValue_* const value_buffer, Index_* const index_buffer) {
507 if constexpr(same_value) {
508 auto raw = my_ext->fetch(i, value_buffer, index_buffer);
509 if (raw.value) {
510 copy_n(raw.value, raw.number, value_buffer);
511 my_helper.sparse(my_row, my_oracle.get(i), raw.number, value_buffer, raw.index, value_buffer);
512 raw.value = value_buffer;
513 }
514 return raw;
515 } else {
516 const auto raw = my_ext->fetch(i, my_holding_vbuffer.data(), index_buffer);
517
518 SparseRange<OutputValue_, Index_> output(raw.number);
519 output.index = raw.index;
520 if (raw.value) {
521 my_helper.sparse(my_row, my_oracle.get(i), raw.number, raw.value, raw.index, value_buffer);
522 output.value = value_buffer;
523 }
524
525 return output;
526 }
527 }
528};
529
537template<bool oracle_, typename OutputValue_, typename InputValue_, typename Index_, class Helper_>
538class SparseNeedsIndices final : public SparseExtractor<oracle_, OutputValue_, Index_> {
539public:
540 SparseNeedsIndices(
541 const Matrix<InputValue_, Index_>& matrix,
542 const Helper_& helper,
543 const bool row,
544 MaybeOracle<oracle_, Index_> oracle,
545 Options opt) :
546 my_helper(helper),
547 my_row(row),
548 my_oracle(oracle, my_helper, row)
549 {
550 initialize(opt, row ? matrix.ncol() : matrix.nrow());
551 my_ext = new_extractor<true, oracle_>(matrix, row, std::move(oracle), opt);
552 }
553
554 SparseNeedsIndices(
555 const Matrix<InputValue_, Index_>& matrix,
556 const Helper_& helper,
557 const bool row,
558 MaybeOracle<oracle_, Index_> oracle,
559 const Index_ block_start,
560 const Index_ block_length,
561 Options opt) :
562 my_helper(helper),
563 my_row(row),
564 my_oracle(oracle, my_helper, row)
565 {
566 initialize(opt, block_length);
567 my_ext = new_extractor<true, oracle_>(matrix, row, std::move(oracle), block_start, block_length, opt);
568 }
569
570 SparseNeedsIndices(
571 const Matrix<InputValue_, Index_>& matrix,
572 const Helper_& helper,
573 const bool row,
574 MaybeOracle<oracle_, Index_> oracle,
575 VectorPtr<Index_> indices_ptr,
576 Options opt) :
577 my_helper(helper),
578 my_row(row),
579 my_oracle(oracle, my_helper, row)
580 {
581 initialize(opt, indices_ptr->size());
582
583 // Construct my_ext here, because we need to get the number of indices first before moving indices_ptr.
584 my_ext = new_extractor<true, oracle_>(matrix, row, std::move(oracle), std::move(indices_ptr), opt);
585 }
586
587private:
588 void initialize(Options& opt, const Index_ extent) {
589 my_report_value = opt.sparse_extract_value;
590 my_report_index = opt.sparse_extract_index;
591
592 // The index is not required if we don't even want the values,
593 // in which case Helper_::is_sparse() isn't even called.
594 if (my_report_value) {
595 opt.sparse_extract_index = true;
596
597 // We only need an internal ibuffer if the user wants the
598 // values but didn't provide enough space to store the indices
599 // (which we need to pass to Helper_::is_sparse()).
600 if (!my_report_index) {
601 resize_container_to_Index_size(my_ibuffer, extent);
602 }
603 }
604
605 if constexpr(!same_value) {
606 if (my_report_value) {
607 resize_container_to_Index_size(my_holding_vbuffer, extent);
608 }
609 }
610 }
611
612private:
613 const Helper_& my_helper;
614
615 bool my_row;
616 DelayedIsometricOperation_internal::MaybeOracleDepends<oracle_, Helper_, Index_> my_oracle;
617
618 bool my_report_value, my_report_index;
619 std::vector<Index_> my_ibuffer;
620
621 std::unique_ptr<SparseExtractor<oracle_, InputValue_, Index_> > my_ext;
622
623 static constexpr bool same_value = std::is_same<OutputValue_, InputValue_>::value;
624 typename std::conditional<!same_value, std::vector<InputValue_>, bool>::type my_holding_vbuffer;
625
626public:
627 SparseRange<OutputValue_, Index_> fetch(const Index_ i, OutputValue_* const value_buffer, Index_* const index_buffer) {
628 const auto iptr = my_report_index ? index_buffer : my_ibuffer.data();
629
630 if constexpr(same_value) {
631 auto raw = my_ext->fetch(i, value_buffer, iptr);
632 if (my_report_value) {
633 copy_n(raw.value, raw.number, value_buffer);
634 my_helper.sparse(my_row, my_oracle.get(i), raw.number, value_buffer, raw.index, value_buffer);
635 raw.value = value_buffer;
636 }
637 if (!my_report_index) {
638 raw.index = NULL;
639 }
640 return raw;
641
642 } else {
643 const auto raw = my_ext->fetch(i, my_holding_vbuffer.data(), iptr);
644 SparseRange<OutputValue_, Index_> output(raw.number, NULL, (my_report_index ? raw.index : NULL));
645 if (my_report_value) {
646 my_helper.sparse(my_row, my_oracle.get(i), raw.number, raw.value, raw.index, value_buffer);
647 output.value = value_buffer;
648 }
649 return output;
650 }
651 }
652};
653
654}
673template<typename OutputValue_, typename InputValue_, typename Index_, class Helper_ = DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> >
674class DelayedUnaryIsometricOperation final : public Matrix<OutputValue_, Index_> {
675public:
681 std::shared_ptr<const Matrix<InputValue_, Index_> > matrix,
682 std::shared_ptr<const Helper_> helper
683 ) :
684 my_matrix(std::move(matrix)),
685 my_helper(std::move(helper))
686 {
687 const auto expected_rows = my_helper->nrow();
688 if (expected_rows.has_value() && *expected_rows != my_matrix->nrow()) {
689 throw std::runtime_error("number of rows in 'matrix' is not consistent with those expected by 'helper'");
690 }
691 const auto expected_cols = my_helper->ncol();
692 if (expected_cols.has_value() && *expected_cols != my_matrix->ncol()) {
693 throw std::runtime_error("number of columns in 'matrix' is not consistent with those expected by 'helper'");
694 }
695 }
696
697private:
698 std::shared_ptr<const Matrix<InputValue_, Index_> > my_matrix;
699 std::shared_ptr<const Helper_> my_helper;
700
701public:
702 Index_ nrow() const {
703 return my_matrix->nrow();
704 }
705
706 Index_ ncol() const {
707 return my_matrix->ncol();
708 }
709
710 bool is_sparse() const {
711 if (my_helper->is_sparse()) {
712 return my_matrix->is_sparse();
713 }
714 return false;
715 }
716
717 double is_sparse_proportion() const {
718 if (my_helper->is_sparse()) {
719 return my_matrix->is_sparse_proportion();
720 }
721 return 0;
722 }
723
724 bool prefer_rows() const {
725 return my_matrix->prefer_rows();
726 }
727
728 double prefer_rows_proportion() const {
729 return my_matrix->prefer_rows_proportion();
730 }
731
732 bool uses_oracle(const bool row) const {
733 return my_matrix->uses_oracle(row);
734 }
735
736 using Matrix<OutputValue_, Index_>::dense;
737
738 using Matrix<OutputValue_, Index_>::sparse;
739
740 /********************
741 *** Myopic dense ***
742 ********************/
743private:
744 template<bool oracle_>
745 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_basic_internal(
746 const bool row,
748 const Options& opt
749 ) const {
750 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseBasicFull<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
751 *my_matrix,
752 *my_helper,
753 row,
754 std::move(oracle),
755 opt
756 );
757 }
758
759 template<bool oracle_>
760 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_basic_internal(
761 const bool row,
763 const Index_ block_start,
764 const Index_ block_length,
765 const Options& opt
766 ) const {
767 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseBasicBlock<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
768 *my_matrix,
769 *my_helper,
770 row,
771 std::move(oracle),
772 block_start,
773 block_length,
774 opt
775 );
776 }
777
778 template<bool oracle_>
779 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_basic_internal(
780 const bool row,
782 VectorPtr<Index_> indices_ptr,
783 const Options& opt
784 ) const {
785 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseBasicIndex<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
786 *my_matrix,
787 *my_helper,
788 row,
789 std::move(oracle),
790 std::move(indices_ptr),
791 opt
792 );
793 }
794
795 template<bool oracle_>
796 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_expanded_internal(
797 const bool row,
799 const Options& opt
800 ) const {
801 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseExpandedFull<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
802 *my_matrix,
803 *my_helper,
804 row,
805 std::move(oracle),
806 opt
807 );
808 }
809
810 template<bool oracle_>
811 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_expanded_internal(
812 const bool row,
814 const Index_ block_start,
815 const Index_ block_length,
816 const Options& opt
817 ) const {
818 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseExpandedBlock<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
819 *my_matrix,
820 *my_helper,
821 row,
822 std::move(oracle),
823 block_start,
824 block_length,
825 opt
826 );
827 }
828
829 template<bool oracle_>
830 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_expanded_internal(
831 const bool row,
833 VectorPtr<Index_> indices_ptr,
834 const Options& opt
835 ) const {
836 return std::make_unique<DelayedUnaryIsometricOperation_internal::DenseExpandedIndex<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
837 *my_matrix,
838 *my_helper,
839 row,
840 std::move(oracle),
841 std::move(indices_ptr),
842 opt
843 );
844 }
845
846 template<bool oracle_, typename ... Args_>
847 std::unique_ptr<DenseExtractor<oracle_, OutputValue_, Index_> > dense_internal(
848 const bool row,
849 Args_&& ... args
850 ) const {
851 if (my_matrix->is_sparse()) {
852 if (DelayedIsometricOperation_internal::can_dense_expand(*my_helper, row)) {
853 return dense_expanded_internal<oracle_>(row, std::forward<Args_>(args)...);
854 }
855 }
856 return dense_basic_internal<oracle_>(row, std::forward<Args_>(args)...);
857 }
858
859public:
860 std::unique_ptr<MyopicDenseExtractor<OutputValue_, Index_> > dense(
861 const bool row,
862 const Options& opt
863 ) const {
864 return dense_internal<false>(row, false, opt);
865 }
866
867 std::unique_ptr<MyopicDenseExtractor<OutputValue_, Index_> > dense(
868 const bool row,
869 const Index_ block_start,
870 const Index_ block_length,
871 const Options& opt
872 ) const {
873 return dense_internal<false>(row, false, block_start, block_length, opt);
874 }
875
876 std::unique_ptr<MyopicDenseExtractor<OutputValue_, Index_> > dense(
877 const bool row,
878 VectorPtr<Index_> indices_ptr,
879 const Options& opt
880 ) const {
881 return dense_internal<false>(row, false, std::move(indices_ptr), opt);
882 }
883
884 /*********************
885 *** Myopic sparse ***
886 *********************/
887private:
888 template<bool oracle_, typename ... Args_>
889 std::unique_ptr<SparseExtractor<oracle_, OutputValue_, Index_> > sparse_to_dense_internal(
890 const bool row,
892 const Options& opt
893 ) const {
894 return std::make_unique<FullSparsifiedWrapper<oracle_, OutputValue_, Index_> >(
895 dense_internal<oracle_>(row, std::move(oracle), opt),
896 (row ? my_matrix->ncol() : my_matrix->nrow()),
897 opt
898 );
899 }
900
901 template<bool oracle_, typename ... Args_>
902 std::unique_ptr<SparseExtractor<oracle_, OutputValue_, Index_> > sparse_to_dense_internal(
903 const bool row,
905 const Index_ block_start,
906 const Index_ block_length,
907 const Options& opt
908 ) const {
909 return std::make_unique<BlockSparsifiedWrapper<oracle_, OutputValue_, Index_> >(
910 dense_internal<oracle_>(row, std::move(oracle), block_start, block_length, opt),
911 block_start,
912 block_length,
913 opt
914 );
915 }
916
917 template<bool oracle_, typename ... Args_>
918 std::unique_ptr<SparseExtractor<oracle_, OutputValue_, Index_> > sparse_to_dense_internal(
919 const bool row,
921 VectorPtr<Index_> indices_ptr,
922 const Options& opt
923 ) const {
924 return std::make_unique<IndexSparsifiedWrapper<oracle_, OutputValue_, Index_> >(
925 dense_internal<oracle_>(row, std::move(oracle), indices_ptr, opt),
926 indices_ptr,
927 opt
928 );
929 }
930
931 template<bool oracle_, typename ... Args_>
932 std::unique_ptr<SparseExtractor<oracle_, OutputValue_, Index_> > sparse_internal(
933 const bool row,
935 Args_&& ... args
936 ) const {
937 if (my_helper->is_sparse() && my_matrix->is_sparse()) {
938 if (DelayedIsometricOperation_internal::needs_sparse_indices(*my_helper, row)) {
939 return std::make_unique<DelayedUnaryIsometricOperation_internal::SparseNeedsIndices<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
940 *my_matrix,
941 *my_helper,
942 row,
943 std::move(oracle),
944 std::forward<Args_>(args)...
945 );
946
947 } else {
948 return std::make_unique<DelayedUnaryIsometricOperation_internal::SparseSimple<oracle_, OutputValue_, InputValue_, Index_, Helper_> >(
949 *my_matrix,
950 *my_helper,
951 row,
952 std::move(oracle),
953 std::forward<Args_>(args)...
954 );
955 }
956 }
957 return sparse_to_dense_internal<oracle_>(row, std::move(oracle), std::forward<Args_>(args)...);
958 }
959
960public:
961 std::unique_ptr<MyopicSparseExtractor<OutputValue_, Index_> > sparse(
962 const bool row,
963 const Options& opt
964 ) const {
965 return sparse_internal<false>(row, false, opt);
966 }
967
968 std::unique_ptr<MyopicSparseExtractor<OutputValue_, Index_> > sparse(
969 const bool row,
970 const Index_ block_start,
971 const Index_ block_length,
972 const Options& opt
973 ) const {
974 return sparse_internal<false>(row, false, block_start, block_length, opt);
975 }
976
977 std::unique_ptr<MyopicSparseExtractor<OutputValue_, Index_> > sparse(
978 const bool row,
979 VectorPtr<Index_> indices_ptr,
980 const Options& opt
981 ) const {
982 return sparse_internal<false>(row, false, std::move(indices_ptr), opt);
983 }
984
985 /**********************
986 *** Oracular dense ***
987 **********************/
988public:
989 std::unique_ptr<OracularDenseExtractor<OutputValue_, Index_> > dense(
990 const bool row,
991 std::shared_ptr<const Oracle<Index_> > oracle,
992 const Options& opt
993 ) const {
994 return dense_internal<true>(row, std::move(oracle), opt);
995 }
996
997 std::unique_ptr<OracularDenseExtractor<OutputValue_, Index_> > dense(
998 const bool row,
999 std::shared_ptr<const Oracle<Index_> > oracle,
1000 const Index_ block_start,
1001 const Index_ block_length,
1002 const Options& opt
1003 ) const {
1004 return dense_internal<true>(row, std::move(oracle), block_start, block_length, opt);
1005 }
1006
1007 std::unique_ptr<OracularDenseExtractor<OutputValue_, Index_> > dense(
1008 const bool row,
1009 std::shared_ptr<const Oracle<Index_> > oracle,
1010 VectorPtr<Index_> indices_ptr,
1011 const Options& opt
1012 ) const {
1013 return dense_internal<true>(row, std::move(oracle), std::move(indices_ptr), opt);
1014 }
1015
1016 /***********************
1017 *** Oracular sparse ***
1018 ***********************/
1019public:
1020 std::unique_ptr<OracularSparseExtractor<OutputValue_, Index_> > sparse(
1021 const bool row,
1022 std::shared_ptr<const Oracle<Index_> > oracle,
1023 const Options& opt
1024 ) const {
1025 return sparse_internal<true>(row, std::move(oracle), opt);
1026 }
1027
1028 std::unique_ptr<OracularSparseExtractor<OutputValue_, Index_> > sparse(
1029 const bool row,
1030 std::shared_ptr<const Oracle<Index_> > oracle,
1031 const Index_ block_start,
1032 const Index_ block_length,
1033 const Options& opt
1034 ) const {
1035 return sparse_internal<true>(row, std::move(oracle), block_start, block_length, opt);
1036 }
1037
1038 std::unique_ptr<OracularSparseExtractor<OutputValue_, Index_> > sparse(
1039 const bool row,
1040 std::shared_ptr<const Oracle<Index_> > oracle,
1041 VectorPtr<Index_> indices_ptr,
1042 const Options& opt
1043 ) const {
1044 return sparse_internal<true>(row, std::move(oracle), std::move(indices_ptr), opt);
1045 }
1046};
1047
1051// For back-compatibility.
1052template<typename OutputValue_ = double, typename InputValue_, typename Index_, class Helper_>
1053std::shared_ptr<Matrix<OutputValue_, Index_> > make_DelayedUnaryIsometricOperation(std::shared_ptr<const Matrix<InputValue_, Index_> > matrix, std::shared_ptr<const Helper_> helper) {
1054 return std::shared_ptr<Matrix<OutputValue_, Index_> >(new DelayedUnaryIsometricOperation<OutputValue_, InputValue_, Index_, Helper_>(std::move(matrix), std::move(helper)));
1055}
1056
1057template<typename OutputValue_ = double, typename InputValue_, typename Index_, class Helper_>
1058std::shared_ptr<Matrix<OutputValue_, Index_> > make_DelayedUnaryIsometricOperation(std::shared_ptr<Matrix<InputValue_, Index_> > matrix, std::shared_ptr<Helper_> helper) {
1059 return std::shared_ptr<Matrix<OutputValue_, Index_> >(new DelayedUnaryIsometricOperation<OutputValue_, InputValue_, Index_, Helper_>(std::move(matrix), std::move(helper)));
1060}
1061
1062template<typename ... Args_>
1063auto make_DelayedIsometricOperation(Args_&&... args) {
1064 return make_DelayedUnaryIsometricOperation(std::forward<Args_>(args)...);
1065}
1066
1067template<typename OutputValue_, typename Index_, class Helper_>
1068using DelayedIsometricOperation = DelayedUnaryIsometricOperation<OutputValue_, Index_, Helper_, OutputValue_>;
1073}
1074
1075#endif
Convert index type to container size.
Virtual class for a matrix of some numeric type.
Delayed isometric operation on a single matrix.
Definition DelayedUnaryIsometricOperation.hpp:674
std::unique_ptr< MyopicSparseExtractor< OutputValue_, Index_ > > sparse(const bool row, VectorPtr< Index_ > indices_ptr, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:977
bool prefer_rows() const
Definition DelayedUnaryIsometricOperation.hpp:724
double is_sparse_proportion() const
Definition DelayedUnaryIsometricOperation.hpp:717
std::unique_ptr< OracularDenseExtractor< OutputValue_, Index_ > > dense(const bool row, std::shared_ptr< const Oracle< Index_ > > oracle, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:989
bool uses_oracle(const bool row) const
Definition DelayedUnaryIsometricOperation.hpp:732
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:968
Index_ ncol() const
Definition DelayedUnaryIsometricOperation.hpp:706
std::unique_ptr< MyopicDenseExtractor< OutputValue_, Index_ > > dense(const bool row, VectorPtr< Index_ > indices_ptr, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:876
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:1038
std::unique_ptr< OracularSparseExtractor< OutputValue_, Index_ > > sparse(const bool row, std::shared_ptr< const Oracle< Index_ > > oracle, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:1020
double prefer_rows_proportion() const
Definition DelayedUnaryIsometricOperation.hpp:728
DelayedUnaryIsometricOperation(std::shared_ptr< const Matrix< InputValue_, Index_ > > matrix, std::shared_ptr< const Helper_ > helper)
Definition DelayedUnaryIsometricOperation.hpp:680
bool is_sparse() const
Definition DelayedUnaryIsometricOperation.hpp:710
std::unique_ptr< MyopicDenseExtractor< OutputValue_, Index_ > > dense(const bool row, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:860
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:1007
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:997
std::unique_ptr< MyopicSparseExtractor< OutputValue_, Index_ > > sparse(const bool row, const Options &opt) const
Definition DelayedUnaryIsometricOperation.hpp:961
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:1028
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:867
Index_ nrow() const
Definition DelayedUnaryIsometricOperation.hpp:702
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:99
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:65
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.