Stratax 0.2.0
Loading...
Searching...
No Matches
Arithmetic.hpp
1#pragma once
2
3#include <stratax/core/Concepts.hpp>
4#include <stratax/core/Exceptions.hpp>
6
7#include <functional>
8
17template<Array A>
18void require_same_arithmetic_shape(const A& lhs, const A& rhs)
19{
20 stratax::core::validation::require_same_shape(
21 lhs,
22 rhs,
23 "Arithmetic operands must have the same shape.");
24}
25
39template<Array A, typename Op>
40A binary_op(const A& lhs, const A& rhs, Op op, bool check_zero_divisor = false)
41{
42 require_same_arithmetic_shape(lhs, rhs);
43
44 A result(lhs.shape());
45
46 auto it1 = lhs.begin();
47 auto it2 = rhs.begin();
48 auto it3 = result.begin();
49
50 for (; it1 != lhs.end(); ++it1, ++it2, ++it3)
51 {
52 if (check_zero_divisor && *it2 == typename A::value_type{})
53 {
54 throw Exceptions::ZeroDivisionError("Array division divisor element cannot be zero.");
55 }
56
57 *it3 = op(*it1, *it2);
58 }
59
60 return result;
61}
62
75template<Array A, Numeric Scalar, typename Op>
76A binary_scalar_op(const A& lhs, const Scalar& rhs, Op op, bool check_zero_divisor = false)
77{
78 A result(lhs.shape());
79
80 auto out = result.begin();
81
82 if (check_zero_divisor && rhs == Scalar{})
83 {
84 throw Exceptions::ZeroDivisionError("Array division scalar divisor cannot be zero.");
85 }
86
87 for (auto it = lhs.begin(); it != lhs.end(); ++it, ++out)
88 {
89 *out = op(*it, rhs);
90 }
91
92 return result;
93}
94
107template<Numeric Scalar, Array A, typename Op>
108A binary_scalar_op(const Scalar& lhs, const A& rhs, Op op, bool check_zero_divisor = false)
109{
110 A result(rhs.shape());
111
112 auto out = result.begin();
113
114 for (auto it = rhs.begin(); it != rhs.end(); ++it, ++out)
115 {
116 if (check_zero_divisor && *it == typename A::value_type{})
117 {
118 throw Exceptions::ZeroDivisionError("Scalar division divisor element cannot be zero.");
119 }
120
121 *out = op(lhs, *it);
122 }
123
124 return result;
125}
126
137template<Array A>
138A operator+(const A& lhs, const A& rhs)
139{
140 return binary_op(lhs, rhs, std::plus<>{});
141}
142
153template<Array A>
154A operator-(const A& lhs, const A& rhs)
155{
156 return binary_op(lhs, rhs, std::minus<>{});
157}
158
169template<Array A>
170A operator*(const A& lhs, const A& rhs)
171{
172 return binary_op(lhs, rhs, std::multiplies<>{});
173}
174
186template<Array A>
187A operator/(const A& lhs, const A& rhs)
188{
189 return binary_op(lhs, rhs, std::divides<>{}, true);
190}
191
200template<Array A, Numeric Scalar>
201A operator+(const A& lhs, const Scalar& rhs)
202{
203 return binary_scalar_op(lhs, rhs, std::plus<>{});
204}
205
214template<Array A, Numeric Scalar>
215A operator-(const A& lhs, const Scalar& rhs)
216{
217 return binary_scalar_op(lhs, rhs, std::minus<>{});
218}
219
228template<Array A, Numeric Scalar>
229A operator*(const A& lhs, const Scalar& rhs)
230{
231 return binary_scalar_op(lhs, rhs, std::multiplies<>{});
232}
233
244template<Array A, Numeric Scalar>
245A operator/(const A& lhs, const Scalar& rhs)
246{
247 return binary_scalar_op(lhs, rhs, std::divides<>{}, true);
248}
249
258template<Numeric Scalar, Array A>
259A operator+(const Scalar& lhs, const A& rhs)
260{
261 return rhs + lhs;
262}
263
272template<Numeric Scalar, Array A>
273A operator-(const Scalar& lhs, const A& rhs)
274{
275 return binary_scalar_op(lhs, rhs, std::minus<>{});
276}
277
286template<Numeric Scalar, Array A>
287A operator*(const Scalar& lhs, const A& rhs)
288{
289 return rhs * lhs;
290}
291
302template<Numeric Scalar, Array A>
303A operator/(const Scalar& lhs, const A& rhs)
304{
305 return binary_scalar_op(lhs, rhs, std::divides<>{}, true);
306}
307
317template<Array A>
318A& operator+=(A& lhs, const A& rhs)
319{
320 lhs = lhs + rhs;
321 return lhs;
322}
323
333template<Array A>
334A& operator-=(A& lhs, const A& rhs)
335{
336 lhs = lhs - rhs;
337 return lhs;
338}
339
349template<Array A>
350A& operator*=(A& lhs, const A& rhs)
351{
352 lhs = lhs * rhs;
353 return lhs;
354}
355
366template<Array A>
367A& operator/=(A& lhs, const A& rhs)
368{
369 lhs = lhs / rhs;
370 return lhs;
371}
372
381template<Array A, Numeric Scalar>
382A& operator+=(A& lhs, const Scalar& rhs)
383{
384 lhs = lhs + rhs;
385 return lhs;
386}
387
396template<Array A, Numeric Scalar>
397A& operator-=(A& lhs, const Scalar& rhs)
398{
399 lhs = lhs - rhs;
400 return lhs;
401}
402
411template<Array A, Numeric Scalar>
412A& operator*=(A& lhs, const Scalar& rhs)
413{
414 lhs = lhs * rhs;
415 return lhs;
416}
417
427template<Array A, Numeric Scalar>
428A& operator/=(A& lhs, const Scalar& rhs)
429{
430 lhs = lhs / rhs;
431 return lhs;
432}
433
441template<Array A>
442A operator-(const A& arr)
443{
444 return arr * typename A::value_type{-1};
445}
446
454template<Array A>
455A operator+(const A& arr)
456{
457 return arr;
458}
459
Shared runtime validation helpers.
Signals a division by zero.
Alias for any scalar type accepted by Stratax numeric containers.
Definition Concepts.hpp:162