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{})
51 return op(left, right);
54 using result_value_type =
55 stratax::core::promote_t<
56 typename L::value_type,
57 typename R::value_type>;
59 return stratax::core::broadcasted_op<result_value_type>(
83template<Array A, Numeric Scalar,
typename Op>
84auto binary_scalar_op(
const A& lhs,
const Scalar& rhs, Op op,
bool check_zero_divisor =
false)
86 if (check_zero_divisor && rhs == Scalar{})
91 return broadcasted_op(lhs, rhs, op);
112template<Numeric Scalar, Array A,
typename Op>
113auto binary_scalar_op(
const Scalar& lhs,
const A& rhs, Op op,
bool check_zero_divisor =
false)
115 auto checked_op = [&](
const auto& left,
const auto& right)
117 if (check_zero_divisor && right ==
typename A::value_type{})
122 return op(left, right);
125 return broadcasted_op(lhs, rhs, checked_op);
150template<Array L, Array R,
typename Op>
159 bool check_zero_divisor =
false)
161 const auto result_shape =
162 broadcasted_shape(lhs.shape(), rhs.shape());
165 if (result_shape != lhs.shape())
168 "In-place broadcasting cannot change the left operand's shape.");
171 for (std::size_t i = 0; i < lhs.size(); ++i)
173 const std::size_t rhs_index =
174 stratax::core::broadcast_detail::flat_operand_index(
179 if (check_zero_divisor &&
180 rhs[rhs_index] ==
typename R::value_type{})
185 lhs[i] =
static_cast<typename L::value_type
>(
186 op(lhs[i], rhs[rhs_index]));
210template<Array A, Numeric S,
typename Op>
211A& compound_scalar_op(
215 bool check_zero_divisor =
false)
217 if (check_zero_divisor && rhs == S{})
222 for (std::size_t i = 0; i < lhs.size(); ++i)
224 lhs[i] =
static_cast<typename A::value_type
>(
232template<Array L, Array R>
237auto operator+(
const L& lhs,
const R& rhs)
239 return binary_op(lhs, rhs, std::plus<>{});
243template<Array L, Array R>
248auto operator-(
const L& lhs,
const R& rhs)
250 return binary_op(lhs, rhs, std::minus<>{});
254template<Array L, Array R>
259auto operator*(
const L& lhs,
const R& rhs)
261 return binary_op(lhs, rhs, std::multiplies<>{});
265template<Array L, Array R>
270auto operator/(
const L& lhs,
const R& rhs)
272 return binary_op(lhs, rhs, std::divides<>{},
true);
276template<Array A, Numeric Scalar>
278auto operator+(
const A& lhs,
const Scalar& rhs)
280 return binary_scalar_op(lhs, rhs, std::plus<>{});
284template<Array A, Numeric Scalar>
286auto operator-(
const A& lhs,
const Scalar& rhs)
288 return binary_scalar_op(lhs, rhs, std::minus<>{});
292template<Array A, Numeric Scalar>
294auto operator*(
const A& lhs,
const Scalar& rhs)
296 return binary_scalar_op(lhs, rhs, std::multiplies<>{});
300template<Array A, Numeric Scalar>
302auto operator/(
const A& lhs,
const Scalar& rhs)
304 return binary_scalar_op(lhs, rhs, std::divides<>{},
true);
308template<Numeric Scalar, Array A>
310auto operator+(
const Scalar& lhs,
const A& rhs)
316template<Numeric Scalar, Array A>
317auto operator-(
const Scalar& lhs,
const A& rhs)
319 return binary_scalar_op(lhs, rhs, std::minus<>{});
323template<Numeric Scalar, Array A>
325auto operator*(
const Scalar& lhs,
const A& rhs)
331template<Numeric Scalar, Array A>
333auto operator/(
const Scalar& lhs,
const A& rhs)
335 return binary_scalar_op(lhs, rhs, std::divides<>{},
true);
339template<Array L, Array R>
344L&
operator+=(L& lhs,
const R& rhs)
346 return compound_op(lhs, rhs, std::plus<>{});
350template<Array L, Array R>
355L&
operator-=(L& lhs,
const R& rhs)
357 return compound_op(lhs, rhs, std::minus<>{});
361template<Array L, Array R>
366L&
operator*=(L& lhs,
const R& rhs)
368 return compound_op(lhs, rhs, std::multiplies<>{});
372template<Array L, Array R>
377L&
operator/=(L& lhs,
const R& rhs)
379 return compound_op(lhs, rhs, std::divides<>{},
true);
383template<Array A, Numeric S>
385A& operator+=(A& lhs,
const S& rhs)
387 return compound_scalar_op(lhs, rhs, std::plus<>{});
391template<Array A, Numeric S>
393A& operator-=(A& lhs,
const S& rhs)
395 return compound_scalar_op(lhs, rhs, std::minus<>{});
399template<Array A, Numeric S>
401A& operator*=(A& lhs,
const S& rhs)
403 return compound_scalar_op(lhs, rhs, std::multiplies<>{});
407template<Array A, Numeric S>
409A& operator/=(A& lhs,
const S& rhs)
411 return compound_scalar_op(lhs, rhs, std::divides<>{},
true);
416A operator-(
const A& arr)
418 return arr *
typename A::value_type{-1};
423A operator+(
const A& arr)