3#include <stratax/core/dtypes/Concepts.hpp>
4#include <stratax/exceptions/Exceptions.hpp>
5#include <stratax/ops/Broadcasting.hpp>
32template<Array L, Array R,
typename Op>
41 bool check_zero_divisor =
false)
43 auto checked_op = [&](
const auto& left,
const auto& right)
45 if (check_zero_divisor &&
46 right ==
typename R::value_type{})
49 "Array division divisor element cannot be zero.");
52 return op(left, right);
55 using result_value_type =
56 stratax::core::promote_t<
57 typename L::value_type,
58 typename R::value_type>;
60 return stratax::core::broadcasted_op<result_value_type>(
84template<Array A, Numeric Scalar,
typename Op>
85auto binary_scalar_op(
const A& lhs,
const Scalar& rhs, Op op,
bool check_zero_divisor =
false)
87 if (check_zero_divisor && rhs == Scalar{})
92 return broadcasted_op(lhs, rhs, op);
113template<Numeric Scalar, Array A,
typename Op>
114auto binary_scalar_op(
const Scalar& lhs,
const A& rhs, Op op,
bool check_zero_divisor =
false)
116 auto checked_op = [&](
const auto& left,
const auto& right)
118 if (check_zero_divisor && right ==
typename A::value_type{})
123 return op(left, right);
126 return broadcasted_op(lhs, rhs, checked_op);
151template<Array L, Array R,
typename Op>
160 bool check_zero_divisor =
false)
162 const auto result_shape =
163 broadcasted_shape(lhs.shape(), rhs.shape());
166 if (result_shape != lhs.shape())
169 "Compound assignment cannot change the left-hand shape.");
172 for (std::size_t i = 0; i < lhs.size(); ++i)
174 const std::size_t rhs_index =
175 stratax::core::broadcast_detail::flat_operand_index(
180 if (check_zero_divisor &&
181 rhs[rhs_index] ==
typename R::value_type{})
184 "Compound division divisor element cannot be zero.");
187 lhs[i] =
static_cast<typename L::value_type
>(
188 op(lhs[i], rhs[rhs_index]));
212template<Array A, Numeric S,
typename Op>
213A& compound_scalar_op(
217 bool check_zero_divisor =
false)
219 if (check_zero_divisor && rhs == S{})
222 "Compound division scalar divisor cannot be zero.");
225 for (std::size_t i = 0; i < lhs.size(); ++i)
227 lhs[i] =
static_cast<typename A::value_type
>(
235template<Array L, Array R>
240auto operator+(
const L& lhs,
const R& rhs)
242 return binary_op(lhs, rhs, std::plus<>{});
246template<Array L, Array R>
251auto operator-(
const L& lhs,
const R& rhs)
253 return binary_op(lhs, rhs, std::minus<>{});
257template<Array L, Array R>
262auto operator*(
const L& lhs,
const R& rhs)
264 return binary_op(lhs, rhs, std::multiplies<>{});
268template<Array L, Array R>
273auto operator/(
const L& lhs,
const R& rhs)
275 return binary_op(lhs, rhs, std::divides<>{},
true);
279template<Array A, Numeric Scalar>
281auto operator+(
const A& lhs,
const Scalar& rhs)
283 return binary_scalar_op(lhs, rhs, std::plus<>{});
287template<Array A, Numeric Scalar>
289auto operator-(
const A& lhs,
const Scalar& rhs)
291 return binary_scalar_op(lhs, rhs, std::minus<>{});
295template<Array A, Numeric Scalar>
297auto operator*(
const A& lhs,
const Scalar& rhs)
299 return binary_scalar_op(lhs, rhs, std::multiplies<>{});
303template<Array A, Numeric Scalar>
305auto operator/(
const A& lhs,
const Scalar& rhs)
307 return binary_scalar_op(lhs, rhs, std::divides<>{},
true);
311template<Numeric Scalar, Array A>
313auto operator+(
const Scalar& lhs,
const A& rhs)
319template<Numeric Scalar, Array A>
320auto operator-(
const Scalar& lhs,
const A& rhs)
322 return binary_scalar_op(lhs, rhs, std::minus<>{});
326template<Numeric Scalar, Array A>
328auto operator*(
const Scalar& lhs,
const A& rhs)
334template<Numeric Scalar, Array A>
336auto operator/(
const Scalar& lhs,
const A& rhs)
338 return binary_scalar_op(lhs, rhs, std::divides<>{},
true);
342template<Array L, Array R>
347L&
operator+=(L& lhs,
const R& rhs)
349 return compound_op(lhs, rhs, std::plus<>{});
353template<Array L, Array R>
358L&
operator-=(L& lhs,
const R& rhs)
360 return compound_op(lhs, rhs, std::minus<>{});
364template<Array L, Array R>
369L&
operator*=(L& lhs,
const R& rhs)
371 return compound_op(lhs, rhs, std::multiplies<>{});
375template<Array L, Array R>
380L&
operator/=(L& lhs,
const R& rhs)
382 return compound_op(lhs, rhs, std::divides<>{},
true);
386template<Array A, Numeric S>
388A& operator+=(A& lhs,
const S& rhs)
390 return compound_scalar_op(lhs, rhs, std::plus<>{});
394template<Array A, Numeric S>
396A& operator-=(A& lhs,
const S& rhs)
398 return compound_scalar_op(lhs, rhs, std::minus<>{});
402template<Array A, Numeric S>
404A& operator*=(A& lhs,
const S& rhs)
406 return compound_scalar_op(lhs, rhs, std::multiplies<>{});
410template<Array A, Numeric S>
412A& operator/=(A& lhs,
const S& rhs)
414 return compound_scalar_op(lhs, rhs, std::divides<>{},
true);
419A operator-(
const A& arr)
421 return arr *
typename A::value_type{-1};
426A operator+(
const A& arr)