7#include <stratax/core/dtypes/Concepts.hpp>
8#include <stratax/exceptions/Exceptions.hpp>
9#include <stratax/core/Shape.hpp>
10#include <stratax/core/ArrayTraits.hpp>
11#include <stratax/core/dtypes/Promotion.hpp>
13namespace stratax::core::broadcast_detail {
29inline std::size_t dimension_from_right(
33 return offset < shape.rank()
34 ? shape[shape.rank() - 1 - offset]
61inline std::size_t flat_operand_index(
62 std::size_t result_index,
66 std::size_t operand_index = 0;
67 std::size_t operand_stride = 1;
69 for (std::size_t result_axis = result_shape.rank(); result_axis-- > 0;)
71 const std::size_t coordinate =
72 result_index % result_shape[result_axis];
73 result_index /= result_shape[result_axis];
75 const std::size_t offset = result_shape.rank() - 1 - result_axis;
76 if (offset >= operand_shape.
rank())
81 const std::size_t operand_axis = operand_shape.
rank() - 1 - offset;
82 const std::size_t operand_dimension = operand_shape[operand_axis];
83 const std::size_t operand_coordinate =
84 operand_dimension == 1 ? 0 : coordinate;
86 operand_index += operand_coordinate * operand_stride;
87 operand_stride *= operand_dimension;
111inline bool broadcastable(
116 const std::size_t result_rank = std::max(shape1.
rank(), shape2.
rank());
118 for (std::size_t offset = 0; offset < result_rank; ++offset)
120 const std::size_t left =
121 stratax::core::broadcast_detail::dimension_from_right(shape1, offset);
122 const std::size_t right =
123 stratax::core::broadcast_detail::dimension_from_right(shape2, offset);
125 if (left != right && left != 1 && right != 1)
154 if (!broadcastable(shape1, shape2))
159 const std::size_t result_rank = std::max(shape1.
rank(), shape2.
rank());
160 std::vector<std::size_t> result(result_rank);
162 for (std::size_t offset = 0; offset < result_rank; ++offset)
164 const std::size_t left =
165 stratax::core::broadcast_detail::dimension_from_right(shape1, offset);
166 const std::size_t right =
167 stratax::core::broadcast_detail::dimension_from_right(shape2, offset);
169 result[result_rank - 1 - offset] = left == 1 ? right : left;
175namespace stratax::core {
188 promote_array_t<L, R, Result>;
190 const auto result_shape =
191 broadcasted_shape(lhs.shape(), rhs.shape());
193 result_type result(result_shape);
195 for (std::size_t i = 0; i < result.size(); ++i)
197 const auto lhs_index =
198 broadcast_detail::flat_operand_index(
203 const auto rhs_index =
204 broadcast_detail::flat_operand_index(
209 result[i] =
static_cast<Result
>(
210 op(lhs[lhs_index], rhs[rhs_index]));
227template<Array L, Array R,
typename Op>
237 using result_value_type =
239 typename L::value_type,
240 typename R::value_type>;
242 return broadcasted_op<result_value_type>(
274template<Array L, Numeric S,
typename Op>
275auto broadcasted_op(
const L& lhs,
const S& rhs, Op op)
277 using result_value_type =
278 stratax::core::promote_t<
279 typename L::value_type,
283 stratax::core::rebind_array_t<
287 result_type result(lhs.shape());
289 for (std::size_t i = 0; i < result.size(); ++i)
291 result[i] =
static_cast<result_value_type
>(
323template<Numeric S, Array R,
typename Op>
324auto broadcasted_op(
const S& lhs,
const R& rhs, Op op)
326 using result_value_type =
327 stratax::core::promote_t<
329 typename R::value_type>;
332 stratax::core::rebind_array_t<
336 result_type result(rhs.shape());
338 for (std::size_t i = 0; i < result.size(); ++i)
340 result[i] =
static_cast<result_value_type
>(
Stores the dimensions of a multidimensional array.
size_type rank() const noexcept
Returns the number of dimensions.
Identifies array-like types through their common logical interface.