tatami
C++ API for different matrix representations
Loading...
Searching...
No Matches
arithmetic_helpers.hpp
Go to the documentation of this file.
1#ifndef TATAMI_ISOMETRIC_UNARY_ARITHMETIC_HELPERS_H
2#define TATAMI_ISOMETRIC_UNARY_ARITHMETIC_HELPERS_H
3
6#include <vector>
7#include <limits>
8#include <type_traits>
9
16namespace tatami {
17
21template<ArithmeticOperation op_, bool right_, typename InputValue_, typename Index_, typename Scalar_, typename OutputValue_>
22void delayed_arithmetic_run_simple(const InputValue_* input, const Index_ length, const Scalar_ scalar, OutputValue_* const output) {
23 if constexpr(std::is_same<InputValue_, OutputValue_>::value) {
24 input = output; // basically an assertion to the compiler to skip aliasing protection.
25 }
26 for (Index_ i = 0; i < length; ++i) {
27 output[i] = delayed_arithmetic<op_, right_>(input[i], scalar);
28 }
29}
30
31// The '*_actual_sparse' and '*_zero' functions should be mirrors of each other;
32// we enforce this by putting their logic all in the same place.
33template<bool check_only_, ArithmeticOperation op_, bool right_, typename OutputValue_, typename InputValue_, typename Scalar_>
34auto delayed_arithmetic_zeroish(const Scalar_ scalar) {
35 if constexpr(has_unsafe_divide_by_zero<op_, right_, InputValue_, Scalar_>()) {
36 if constexpr(right_) {
37 if (scalar) {
38 const OutputValue_ val = delayed_arithmetic<op_, right_, InputValue_, Scalar_>(0, scalar);
39 if constexpr(check_only_) {
40 return val == 0;
41 } else {
42 return val;
43 }
44 }
45 }
46
47 if constexpr(check_only_) {
48 return false;
49 } else {
50 throw std::runtime_error("division by zero is not supported");
51 return 0;
52 }
53
54 } else {
55 const OutputValue_ val = delayed_arithmetic<op_, right_, InputValue_, Scalar_>(0, scalar);
56 if constexpr(check_only_) {
57 return val == 0;
58 } else {
59 return val;
60 }
61 }
62}
63
64template<ArithmeticOperation op_, bool right_, typename OutputValue_, typename InputValue_, typename Scalar_>
65bool delayed_arithmetic_actual_sparse(const Scalar_ scalar) {
66 return delayed_arithmetic_zeroish<true, op_, right_, OutputValue_, InputValue_, Scalar_>(scalar);
67}
68
69template<ArithmeticOperation op_, bool right_, typename OutputValue_, typename InputValue_, typename Scalar_>
70OutputValue_ delayed_arithmetic_zero(const Scalar_ scalar) {
71 return delayed_arithmetic_zeroish<false, op_, right_, OutputValue_, InputValue_, Scalar_>(scalar);
72}
92template<ArithmeticOperation op_, bool right_, typename OutputValue_, typename InputValue_, typename Index_, typename Scalar_>
93class DelayedUnaryIsometricArithmeticScalarHelper final : public DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> {
94public:
98 DelayedUnaryIsometricArithmeticScalarHelper(const Scalar_ scalar) : my_scalar(scalar) {
99 my_sparse = delayed_arithmetic_actual_sparse<op_, right_, OutputValue_, InputValue_>(my_scalar);
100 }
101
102private:
103 Scalar_ my_scalar;
104 bool my_sparse;
105
106public:
107 std::optional<Index_> nrow() const {
108 return std::nullopt;
109 }
110
111 std::optional<Index_> ncol() const {
112 return std::nullopt;
113 }
114
115public:
116 bool zero_depends_on_row() const {
117 return false;
118 }
119
121 return false;
122 }
123
125 return false;
126 }
127
129 return false;
130 }
131
132public:
133 void dense(const bool, const Index_, const Index_, const Index_ length, const InputValue_* const input, OutputValue_* const output) const {
134 delayed_arithmetic_run_simple<op_, right_>(input, length, my_scalar, output);
135 }
136
137 void dense(const bool, const Index_, const std::vector<Index_>& indices, const InputValue_* const input, OutputValue_* const output) const {
138 delayed_arithmetic_run_simple<op_, right_>(input, static_cast<Index_>(indices.size()), my_scalar, output);
139 }
140
141public:
142 bool is_sparse() const {
143 return my_sparse;
144 }
145
146 void sparse(const bool, const Index_, const Index_ number, const InputValue_* const input_value, const Index_* const, OutputValue_* const output_value) const {
147 delayed_arithmetic_run_simple<op_, right_>(input_value, number, my_scalar, output_value);
148 }
149
150 OutputValue_ fill(const bool, const Index_) const {
151 // We perform the operation with the InputValue_ before casting it to
152 // the OutputValue_, which is consistent with the behavior of all other
153 // methods. See ../arithmetic_utils.hpp for some comments about the
154 // safety of this cast when the value is known at compile time.
155 return delayed_arithmetic_zero<op_, right_, OutputValue_, InputValue_>(my_scalar);
156 }
157};
158
167template<typename OutputValue_, typename InputValue_, typename Index_, typename Scalar_>
169
179template<bool right_, typename OutputValue_, typename InputValue_, typename Index_, typename Scalar_>
181
190template<typename OutputValue_, typename InputValue_, typename Index_, typename Scalar_>
192
202template<bool right_, typename OutputValue_, typename InputValue_, typename Index_, typename Scalar_>
204
214template<bool right_, typename OutputValue_, typename InputValue_, typename Index_, typename Scalar_>
216
226template<bool right_, typename OutputValue_, typename InputValue_, typename Index_, typename Scalar_>
228
238template<bool right_, typename OutputValue_, typename InputValue_, typename Index_, typename Scalar_>
240
244// Back-compatibility only.
245template<typename OutputValue_ = double, typename InputValue_ = double, typename Index_ = int, typename Scalar_>
246std::shared_ptr<DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> > make_DelayedUnaryIsometricAddScalar(Scalar_ scalar) {
247 return std::make_shared<DelayedUnaryIsometricAddScalarHelper<OutputValue_, InputValue_, Index_, Scalar_> >(std::move(scalar));
248}
249
250template<bool right_, typename OutputValue_ = double, typename InputValue_ = double, typename Index_ = int, typename Scalar_>
251std::shared_ptr<DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> > make_DelayedUnaryIsometricSubtractScalar(Scalar_ scalar) {
252 return std::make_shared<DelayedUnaryIsometricSubtractScalarHelper<right_, OutputValue_, InputValue_, Index_, Scalar_> >(std::move(scalar));
253}
254
255template<typename OutputValue_ = double, typename InputValue_ = double, typename Index_ = int, typename Scalar_>
256std::shared_ptr<DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> > make_DelayedUnaryIsometricMultiplyScalar(Scalar_ scalar) {
257 return std::make_shared<DelayedUnaryIsometricMultiplyScalarHelper<OutputValue_, InputValue_, Index_, Scalar_> >(std::move(scalar));
258}
259
260template<bool right_, typename OutputValue_ = double, typename InputValue_ = double, typename Index_ = int, typename Scalar_>
261std::shared_ptr<DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> > make_DelayedUnaryIsometricDivideScalar(Scalar_ scalar) {
262 return std::make_shared<DelayedUnaryIsometricDivideScalarHelper<right_, OutputValue_, InputValue_, Index_, Scalar_> >(std::move(scalar));
263}
264
265template<bool right_, typename OutputValue_ = double, typename InputValue_ = double, typename Index_ = int, typename Scalar_>
266std::shared_ptr<DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> > make_DelayedUnaryIsometricModuloScalar(Scalar_ scalar) {
267 return std::make_shared<DelayedUnaryIsometricModuloScalarHelper<right_, OutputValue_, InputValue_, Index_, Scalar_> >(std::move(scalar));
268}
269
270template<bool right_, typename OutputValue_ = double, typename InputValue_ = double, typename Index_ = int, typename Scalar_>
271std::shared_ptr<DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> > make_DelayedUnaryIsometricPowerScalar(Scalar_ scalar) {
272 return std::make_shared<DelayedUnaryIsometricPowerScalarHelper<right_, OutputValue_, InputValue_, Index_, Scalar_> >(std::move(scalar));
273}
274
275template<bool right_, typename OutputValue_ = double, typename InputValue_ = double, typename Index_ = int, typename Scalar_>
276std::shared_ptr<DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> > make_DelayedUnaryIsometricIntegerDivideScalar(Scalar_ scalar) {
277 return std::make_shared<DelayedUnaryIsometricIntegerDivideScalarHelper<right_, OutputValue_, InputValue_, Index_, Scalar_> >(std::move(scalar));
278}
299template<ArithmeticOperation op_, bool right_, typename OutputValue_, typename InputValue_, typename Index_, typename Vector_>
300class DelayedUnaryIsometricArithmeticVectorHelper final : public DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> {
301public:
309 DelayedUnaryIsometricArithmeticVectorHelper(Vector_ vector, const bool by_row) : my_vector(std::move(vector)), my_by_row(by_row) {
310 for (const auto x : my_vector) {
311 if (!delayed_arithmetic_actual_sparse<op_, right_, OutputValue_, InputValue_>(x)) {
312 my_sparse = false;
313 break;
314 }
315 }
316 }
317
318private:
319 Vector_ my_vector;
320 bool my_by_row;
321 bool my_sparse = true;
322
323public:
324 std::optional<Index_> nrow() const {
325 if (my_by_row) {
326 return my_vector.size();
327 } else {
328 return std::nullopt;
329 }
330 }
331
332 std::optional<Index_> ncol() const {
333 if (my_by_row) {
334 return std::nullopt;
335 } else {
336 return my_vector.size();
337 }
338 }
339
340public:
341 bool zero_depends_on_row() const {
342 return my_by_row;
343 }
344
346 return !my_by_row;
347 }
348
350 return my_by_row;
351 }
352
354 return !my_by_row;
355 }
356
357public:
358 void dense(const bool row, const Index_ idx, const Index_ start, const Index_ length, const InputValue_* input, OutputValue_* const output) const {
359 if (row == my_by_row) {
360 delayed_arithmetic_run_simple<op_, right_>(input, length, my_vector[idx], output);
361 } else {
362 if constexpr(std::is_same<InputValue_, OutputValue_>::value) {
363 input = output; // basically an assertion to the compiler to skip aliasing protection.
364 }
365 for (Index_ i = 0; i < length; ++i) {
366 output[i] = delayed_arithmetic<op_, right_>(input[i], my_vector[i + start]);
367 }
368 }
369 }
370
371 void dense(const bool row, const Index_ idx, const std::vector<Index_>& indices, const InputValue_* input, OutputValue_* const output) const {
372 if (row == my_by_row) {
373 delayed_arithmetic_run_simple<op_, right_>(input, static_cast<Index_>(indices.size()), my_vector[idx], output);
374 } else {
375 if constexpr(std::is_same<InputValue_, OutputValue_>::value) {
376 input = output; // basically an assertion to the compiler to skip aliasing protection.
377 }
378 Index_ length = indices.size();
379 for (Index_ i = 0; i < length; ++i) {
380 output[i] = delayed_arithmetic<op_, right_>(input[i], my_vector[indices[i]]);
381 }
382 }
383 }
384
385public:
386 bool is_sparse() const {
387 return my_sparse;
388 }
389
390 void sparse(
391 const bool row,
392 const Index_ idx,
393 const Index_ number,
394 const InputValue_* input_value,
395 const Index_* const index,
396 OutputValue_* const output_value)
397 const {
398 if (row == my_by_row) {
399 delayed_arithmetic_run_simple<op_, right_>(input_value, number, my_vector[idx], output_value);
400 } else {
401 if constexpr(std::is_same<InputValue_, OutputValue_>::value) {
402 input_value = output_value; // basically an assertion to the compiler to skip aliasing protection.
403 }
404 for (Index_ i = 0; i < number; ++i) {
405 output_value[i] = delayed_arithmetic<op_, right_>(input_value[i], my_vector[index[i]]);
406 }
407 }
408 }
409
410 OutputValue_ fill(const bool row, const Index_ idx) const {
411 if (row == my_by_row) {
412 return delayed_arithmetic_zero<op_, right_, OutputValue_, InputValue_>(my_vector[idx]);
413 } else {
414 // We should only get to this point if it's sparse, otherwise no
415 // single fill value would work across the length of my_vector.
416 return 0;
417 }
418 }
419};
420
429template<typename OutputValue_, typename InputValue_, typename Index_, typename Vector_>
431
441template<bool right_, typename OutputValue_, typename InputValue_, typename Index_, typename Vector_>
443
452template<typename OutputValue_, typename InputValue_, typename Index_, typename Vector_>
454
464template<bool right_, typename OutputValue_, typename InputValue_, typename Index_, typename Vector_>
466
476template<bool right_, typename OutputValue_, typename InputValue_, typename Index_, typename Vector_>
478
488template<bool right_, typename OutputValue_, typename InputValue_, typename Index_, typename Vector_>
490
500template<bool right_, typename OutputValue_, typename InputValue_, typename Index_, typename Vector_>
502
506// Back-compatibility only.
507template<typename OutputValue_ = double, typename InputValue_ = double, typename Index_ = int, typename Vector_>
508std::shared_ptr<DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> > make_DelayedUnaryIsometricAddVector(Vector_ vector, bool by_row) {
509 return std::make_shared<DelayedUnaryIsometricAddVectorHelper<OutputValue_, InputValue_, Index_, Vector_> >(std::move(vector), by_row);
510}
511
512template<bool right_, typename OutputValue_ = double, typename InputValue_ = double, typename Index_ = int, typename Vector_>
513std::shared_ptr<DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> > make_DelayedUnaryIsometricSubtractVector(Vector_ vector, bool by_row) {
514 return std::make_shared<DelayedUnaryIsometricSubtractVectorHelper<right_, OutputValue_, InputValue_, Index_, Vector_> >(std::move(vector), by_row);
515}
516
517template<typename OutputValue_ = double, typename InputValue_ = double, typename Index_ = int, typename Vector_>
518std::shared_ptr<DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> > make_DelayedUnaryIsometricMultiplyVector(Vector_ vector, bool by_row) {
519 return std::make_shared<DelayedUnaryIsometricMultiplyVectorHelper<OutputValue_, InputValue_, Index_, Vector_> >(std::move(vector), by_row);
520}
521
522template<bool right_, typename OutputValue_ = double, typename InputValue_ = double, typename Index_ = int, typename Vector_>
523std::shared_ptr<DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> > make_DelayedUnaryIsometricDivideVector(Vector_ vector, bool by_row) {
524 return std::make_shared<DelayedUnaryIsometricDivideVectorHelper<right_, OutputValue_, InputValue_, Index_, Vector_> >(std::move(vector), by_row);
525}
526
527template<bool right_, typename OutputValue_ = double, typename InputValue_ = double, typename Index_ = int, typename Vector_>
528std::shared_ptr<DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> > make_DelayedUnaryIsometricModuloVector(Vector_ vector, bool by_row) {
529 return std::make_shared<DelayedUnaryIsometricModuloVectorHelper<right_, OutputValue_, InputValue_, Index_, Vector_> >(std::move(vector), by_row);
530}
531
532template<bool right_, typename OutputValue_ = double, typename InputValue_ = double, typename Index_ = int, typename Vector_>
533std::shared_ptr<DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> > make_DelayedUnaryIsometricPowerVector(Vector_ vector, bool by_row) {
534 return std::make_shared<DelayedUnaryIsometricPowerVectorHelper<right_, OutputValue_, InputValue_, Index_, Vector_> >(std::move(vector), by_row);
535}
536
537template<bool right_, typename OutputValue_ = double, typename InputValue_ = double, typename Index_ = int, typename Vector_>
538std::shared_ptr<DelayedUnaryIsometricOperationHelper<OutputValue_, InputValue_, Index_> > make_DelayedUnaryIsometricIntegerDivideVector(Vector_ vector, bool by_row) {
539 return std::make_shared<DelayedUnaryIsometricIntegerDivideVectorHelper<right_, OutputValue_, InputValue_, Index_, Vector_> >(std::move(vector), by_row);
540}
545}
546
547#endif
Utilities for delayed arithmetic operations.
Helper for delayed unary isometric scalar arithmetic.
Definition arithmetic_helpers.hpp:93
bool zero_depends_on_row() const
Definition arithmetic_helpers.hpp:116
DelayedUnaryIsometricArithmeticScalarHelper(const Scalar_ scalar)
Definition arithmetic_helpers.hpp:98
void dense(const bool, const Index_, const Index_, const Index_ length, const InputValue_ *const input, OutputValue_ *const output) const
Definition arithmetic_helpers.hpp:133
bool non_zero_depends_on_row() const
Definition arithmetic_helpers.hpp:124
OutputValue_ fill(const bool, const Index_) const
Definition arithmetic_helpers.hpp:150
std::optional< Index_ > nrow() const
Definition arithmetic_helpers.hpp:107
bool is_sparse() const
Definition arithmetic_helpers.hpp:142
void dense(const bool, const Index_, const std::vector< Index_ > &indices, const InputValue_ *const input, OutputValue_ *const output) const
Definition arithmetic_helpers.hpp:137
bool zero_depends_on_column() const
Definition arithmetic_helpers.hpp:120
std::optional< Index_ > ncol() const
Definition arithmetic_helpers.hpp:111
void sparse(const bool, const Index_, const Index_ number, const InputValue_ *const input_value, const Index_ *const, OutputValue_ *const output_value) const
Definition arithmetic_helpers.hpp:146
bool non_zero_depends_on_column() const
Definition arithmetic_helpers.hpp:128
Helper for delayed unary isometric vector arithmetic.
Definition arithmetic_helpers.hpp:300
bool is_sparse() const
Definition arithmetic_helpers.hpp:386
void dense(const bool row, const Index_ idx, const Index_ start, const Index_ length, const InputValue_ *input, OutputValue_ *const output) const
Definition arithmetic_helpers.hpp:358
OutputValue_ fill(const bool row, const Index_ idx) const
Definition arithmetic_helpers.hpp:410
bool non_zero_depends_on_column() const
Definition arithmetic_helpers.hpp:353
std::optional< Index_ > nrow() const
Definition arithmetic_helpers.hpp:324
bool non_zero_depends_on_row() const
Definition arithmetic_helpers.hpp:349
bool zero_depends_on_column() const
Definition arithmetic_helpers.hpp:345
std::optional< Index_ > ncol() const
Definition arithmetic_helpers.hpp:332
DelayedUnaryIsometricArithmeticVectorHelper(Vector_ vector, const bool by_row)
Definition arithmetic_helpers.hpp:309
void dense(const bool row, const Index_ idx, const std::vector< Index_ > &indices, const InputValue_ *input, OutputValue_ *const output) const
Definition arithmetic_helpers.hpp:371
void sparse(const bool row, const Index_ idx, const Index_ number, const InputValue_ *input_value, const Index_ *const index, OutputValue_ *const output_value) const
Definition arithmetic_helpers.hpp:390
bool zero_depends_on_row() const
Definition arithmetic_helpers.hpp:341
Helper operation interface for DelayedUnaryIsometricOperation.
Definition helper_interface.hpp:27
Flexible representations for matrix data.
Definition Extractor.hpp:15
Interface for tatami::DelayedUnaryIsometricOperation helpers.