48template<Array L, Array R,
typename Op>
57 bool check_zero_divisor =
false)
59 auto checked_op = [&](
const auto& left,
const auto& right)
61 if (check_zero_divisor)
63 stratax::core::validation::require_valid_division(left, right);
66 return op(left, right);
69 using result_value_type =
71 typename L::value_type,
72 typename R::value_type>;
74 return stratax::core::broadcasted_op<result_value_type>(
99template<Array A, Numeric Scalar,
typename Op>
100auto binary_scalar_op(
const A& lhs,
const Scalar& rhs, Op op,
bool check_zero_divisor =
false)
102 if (check_zero_divisor && rhs == Scalar{})
107 auto checked_op = [&](
const auto& left,
const auto& right)
109 if (check_zero_divisor)
111 stratax::core::validation::require_valid_division(left, right);
113 return op(left, right);
137template<Numeric Scalar, Array A,
typename Op>
138auto binary_scalar_op(
const Scalar& lhs,
const A& rhs, Op op,
bool check_zero_divisor =
false)
140 auto checked_op = [&](
const auto& left,
const auto& right)
142 if (check_zero_divisor)
144 stratax::core::validation::require_valid_division(left, right);
147 return op(left, right);
180template<Array L, Array R,
typename Op>
189 bool check_zero_divisor =
false)
191 const auto result_shape =
192 stratax::core::broadcast_detail::array_result_shape(lhs, rhs);
195 if (result_shape != lhs.shape())
198 "In-place broadcasting cannot change the left operand's shape.");
202 if (check_zero_divisor)
204 for (std::size_t i = 0; i < lhs.size(); ++i)
206 const auto rhs_index = stratax::core::broadcast_detail::flat_operand_index(
207 i, lhs.shape(), rhs.shape());
208 stratax::core::validation::require_valid_division(lhs[i], rhs[rhs_index]);
212 constexpr bool stage = !stratax::core::compound_detail::owns_storage<L> ||
213 !stratax::core::compound_detail::owns_storage<R>;
214 return stratax::core::compound_detail::write_results<stage>(lhs, [&](std::size_t i)
216 const auto rhs_index = stratax::core::broadcast_detail::flat_operand_index(
217 i, lhs.shape(), rhs.shape());
218 return op(lhs[i], rhs[rhs_index]);
245template<Array A, Numeric S,
typename Op>
250 bool check_zero_divisor =
false)
252 const S scalar = rhs;
253 if (check_zero_divisor)
259 for (std::size_t i = 0; i < lhs.size(); ++i)
261 stratax::core::validation::require_valid_division(lhs[i], scalar);
265 return stratax::core::compound_detail::write_results<
266 !stratax::core::compound_detail::owns_storage<A>>(lhs, [&](std::size_t i)
268 return op(lhs[i], scalar);
273template<Array L, Array R>
278auto operator+(
const L& lhs,
const R& rhs)
280 return binary_op(lhs, rhs, std::plus<>{});
284template<Array L, Array R>
289auto operator-(
const L& lhs,
const R& rhs)
291 return binary_op(lhs, rhs, std::minus<>{});
295template<Array L, Array R>
300auto operator*(
const L& lhs,
const R& rhs)
302 return binary_op(lhs, rhs, std::multiplies<>{});
306template<Array L, Array R>
311auto operator/(
const L& lhs,
const R& rhs)
313 return binary_op(lhs, rhs, std::divides<>{},
true);
317template<Array A, Numeric Scalar>
325template<Array A, Numeric Scalar>
333template<Array A, Numeric Scalar>
341template<Array A, Numeric Scalar>
349template<Numeric Scalar, Array A>
357template<Numeric Scalar, Array A>
364template<Numeric Scalar, Array A>
372template<Numeric Scalar, Array A>
380template<Array L, Array R>
385L&
operator+=(L& lhs,
const R& rhs)
391template<Array L, Array R>
396L&
operator-=(L& lhs,
const R& rhs)
402template<Array L, Array R>
407L&
operator*=(L& lhs,
const R& rhs)
413template<Array L, Array R>
418L&
operator/=(L& lhs,
const R& rhs)
420 return compound_op(lhs, rhs, std::divides<>{},
true);
424template<Array A, Numeric S>
432template<Array A, Numeric S>
440template<Array A, Numeric S>
448template<Array A, Numeric S>
464 return arr *
typename A::value_type{-1};
L & compound_op(L &lhs, const R &rhs, Op op, bool check_zero_divisor=false)
Applies an arithmetic callable in place using array broadcasting.
auto operator*(const L &lhs, const R &rhs)
Multiplies two broadcast-compatible arrays element-wise.
L & operator/=(L &lhs, const R &rhs)
Divides by a broadcast-compatible array in place.
L & operator-=(L &lhs, const R &rhs)
Subtracts a broadcast-compatible array in place.
L & operator*=(L &lhs, const R &rhs)
Multiplies by a broadcast-compatible array in place.
auto operator+(const L &lhs, const R &rhs)
Adds two broadcast-compatible arrays.
L & operator+=(L &lhs, const R &rhs)
Adds a broadcast-compatible array in place.
auto binary_op(const L &lhs, const R &rhs, Op op, bool check_zero_divisor=false)
Applies an arithmetic callable to two broadcast-compatible arrays.
auto operator-(const L &lhs, const R &rhs)
Subtracts two broadcast-compatible arrays.
auto operator/(const L &lhs, const R &rhs)
Divides two broadcast-compatible arrays element-wise.
auto binary_scalar_op(const A &lhs, const Scalar &rhs, Op op, bool check_zero_divisor=false)
Applies an arithmetic callable to an array and a right scalar. The returned array preserves the conta...
A & compound_scalar_op(A &lhs, const S &rhs, Op op, bool check_zero_divisor=false)
Applies an arithmetic callable in place with a right scalar.
Trailing-axis shape compatibility and element projection.
auto broadcasted_op(const L &lhs, const S &rhs, Op op)
Applies a binary callable to every array element and a right scalar.
Internal result staging for compound operations on aliased arrays.
Dtype and array interface concepts.
Stratax exception types derived from std::runtime_error.
Shared validation for division operands and integral shift counts.
Operands cannot broadcast to the requested result.
An explicitly checked divisor is zero.
Supported integer, floating-point, or complex dtype, excluding bool.