6#include <stratax/core/dtypes/Concepts.hpp>
7#include <stratax/exceptions/Exceptions.hpp>
8#include <stratax/core/Shape.hpp>
9#include <stratax/core/validation/Validation.hpp>
10#include <stratax/containers/Tensor.hpp>
11#include <stratax/containers/Matrix.hpp>
12#include <stratax/containers/Vector.hpp>
13#include <stratax/core/Slice.hpp>
14#include <stratax/indexing/Slicing.hpp>
15#include <stratax/algorithms/Conversion.hpp>
16#include <stratax/core/ReductionTraits.hpp>
38 const stratax::core::Shape& shape,
39 std::vector<std::size_t>& indices)
41 for (std::size_t d = shape.
rank(); d-- > 0;)
45 if (indices[d] < shape[d])
67inline int normalize_axis(
const A& arr,
int axis)
90inline std::vector<std::size_t> result_shape(
const A& arr,
int axis,
bool keepdims)
92 stratax::core::Shape input_shape = arr.shape();
94 std::vector<std::size_t> result_dimensions;
98 for (std::size_t dimension = 0; dimension < input_shape.
rank(); ++dimension)
100 if (dimension ==
static_cast<std::size_t
>(axis))
102 result_dimensions.push_back(1);
107 result_dimensions.push_back(input_shape[dimension]);
114 for (std::size_t dimension = 0; dimension < input_shape.
rank(); ++dimension)
116 if (dimension !=
static_cast<std::size_t
>(axis))
118 result_dimensions.push_back(input_shape[dimension]);
123 return result_dimensions;
132template<Array A,
typename Func>
133using axis_reduce_value_t =
134 decltype(std::declval<Func>()(
135 std::declval<const stratax::container::Tensor<typename A::value_type>&>()));
164template<Array A,
typename Func>
165stratax::container::Tensor<detail::axis_reduce_value_t<A, Func>>
166axis_reduce(
const A& array,
int axis, Func func,
bool keepdims =
false)
168 using ResultType = detail::axis_reduce_value_t<A, Func>;
170 int Axis = detail::normalize_axis(array, axis);
172 if (Axis < 0 || Axis >=
static_cast<int>(array.rank()))
174 throw Exceptions::AxisError(
"axis is out of range.");
177 stratax::container::Tensor<typename A::value_type> arr =
178 stratax::conversion::to_tensor(array);
180 const stratax::core::Shape input_shape = arr.
shape();
182 std::vector<std::size_t> result_dims =
183 detail::result_shape(array, Axis, keepdims);
187 if (result_dims.empty())
189 ResultType scalar_result = func(arr);
190 return stratax::container::Tensor<ResultType>(stratax::core::Shape{1}, scalar_result);
193 stratax::container::Tensor<ResultType> result(stratax::core::Shape{result_dims});
199 std::vector<std::size_t> output_index(result.rank(), 0);
200 std::vector<stratax::core::Slice> slices;
204 std::size_t output_position = 0;
205 for (std::size_t dimension = 0; dimension < input_shape.
rank(); ++dimension)
207 if (
static_cast<int>(dimension) == Axis)
209 slices.push_back(stratax::core::Slice{
static_cast<std::ptrdiff_t
>(0),
210 static_cast<std::ptrdiff_t
>(input_shape[dimension])});
215 const std::size_t index = keepdims
216 ? output_index[dimension]
217 : output_index[output_position++];
219 slices.push_back(stratax::core::Slice{
220 static_cast<std::ptrdiff_t
>(index),
221 static_cast<std::ptrdiff_t
>(index + 1)
225 auto s = stratax::indexing::slice(arr, slices);
226 ResultType value = func(s);
227 result(output_index) = value;
229 while (detail::advance(result.shape(), output_index));
245requires Numeric<typename A::value_type>
246auto sum(
const A& arr)
249 reduction_sum_t<typename A::value_type>;
251 return std::accumulate(
266requires Numeric<typename A::value_type>
267auto prod(
const A& arr)
270 reduction_prod_t<typename A::value_type>;
272 return std::accumulate(
276 std::multiplies<result_type>{});
288requires Ordered<typename A::value_type>
289auto max(
const A& arr)
293 throw Exceptions::IndexError(
294 "Maximum is undefined for an empty array.");
297 auto result = std::max_element(
314requires Ordered<typename A::value_type>
315auto min(
const A& arr)
319 throw Exceptions::IndexError(
320 "Minimum is undefined for an empty array.");
323 auto result = std::min_element(
340requires Ordered<typename A::value_type>
341auto argmax(
const A& arr)
345 throw Exceptions::IndexError(
346 "Argmax is undefined for an empty array.");
349 auto result = std::max_element(
354 return static_cast<std::size_t
>(std::distance(arr.begin(), result));
366requires Ordered<typename A::value_type>
367auto argmin(
const A& arr)
371 throw Exceptions::IndexError(
372 "Argmin is undefined for an empty array.");
375 auto result = std::min_element(
380 return static_cast<std::size_t
>(std::distance(arr.begin(), result));
393 Numeric<typename A::value_type> &&
394 Ordered<typename A::value_type>
396double mean(
const A& arr)
400 throw Exceptions::ZeroDivisionError(
401 "Mean is undefined for an empty array.");
404 return static_cast<double>(sum(arr)) /
static_cast<double>(arr.size());
417 Numeric<typename A::value_type> &&
418 Ordered<typename A::value_type>
420double var(
const A& arr)
424 throw Exceptions::ZeroDivisionError(
425 "Variance is undefined for an empty array.");
429 double mean_value = 0.0;
432 for (
const auto& value : arr)
435 const double delta =
static_cast<double>(value) - mean_value;
436 mean_value += delta / count;
437 const double delta2 =
static_cast<double>(value) - mean_value;
438 m2 += delta * delta2;
454 Numeric<typename A::value_type> &&
455 Ordered<typename A::value_type>
457double std(
const A& arr)
459 auto vars = var(arr);
460 return std::sqrt(vars);
476requires Numeric<typename A::value_type>
477auto sum(
const A& arr,
int axis)
483 return reduction::sum(s);
498requires Numeric<typename A::value_type>
499auto sum(
const A& arr,
int axis,
bool keepdims)
505 return reduction::sum(s);
520requires Numeric<typename A::value_type>
521auto prod(
const A& arr,
int axis)
527 return reduction::prod(s);
542requires Numeric<typename A::value_type>
543auto prod(
const A& arr,
int axis,
bool keepdims)
549 return reduction::prod(s);
563requires Ordered<typename A::value_type>
564auto max(
const A& arr,
int axis)
567 arr, axis, [](
const auto& s) {
return reduction::max(s); });
580requires Ordered<typename A::value_type>
581auto max(
const A& arr,
int axis,
bool keepdims)
586 [](
const auto& s) {
return reduction::max(s); },
599requires Ordered<typename A::value_type>
600auto min(
const A& arr,
int axis)
603 arr, axis, [](
const auto& s) {
return reduction::min(s); });
616requires Ordered<typename A::value_type>
617auto min(
const A& arr,
int axis,
bool keepdims)
622 [](
const auto& s) {
return reduction::min(s); },
635requires Ordered<typename A::value_type>
636auto argmax(
const A& arr,
int axis)
639 arr, axis, [](
const auto& s) {
return reduction::argmax(s); });
652requires Ordered<typename A::value_type>
653auto argmax(
const A& arr,
int axis,
bool keepdims)
658 [](
const auto& s) {
return reduction::argmax(s); },
671requires Ordered<typename A::value_type>
672auto argmin(
const A& arr,
int axis)
675 arr, axis, [](
const auto& s) {
return reduction::argmin(s); });
688requires Ordered<typename A::value_type>
689auto argmin(
const A& arr,
int axis,
bool keepdims)
694 [](
const auto& s) {
return reduction::argmin(s); },
709 Numeric<typename A::value_type> &&
710 Ordered<typename A::value_type>
712stratax::container::Tensor<double>
713mean(
const A& arr,
int axis,
bool keepdims)
718 [](
const auto& s) {
return reduction::mean(s); },
732 Numeric<typename A::value_type> &&
733 Ordered<typename A::value_type>
735stratax::container::Tensor<double>
736mean(
const A& arr,
int axis)
739 arr, axis, [](
const auto& s) {
return reduction::mean(s); });
753 Numeric<typename A::value_type> &&
754 Ordered<typename A::value_type>
756stratax::container::Tensor<double>
757var(
const A& arr,
int axis,
bool keepdims)
762 [](
const auto& s) {
return reduction::var(s); },
776 Numeric<typename A::value_type> &&
777 Ordered<typename A::value_type>
779stratax::container::Tensor<double>
780var(
const A& arr,
int axis)
783 arr, axis, [](
const auto& s) {
return reduction::var(s); });
797 Numeric<typename A::value_type> &&
798 Ordered<typename A::value_type>
800stratax::container::Tensor<double>
801std(
const A& arr,
int axis,
bool keepdims)
806 [](
const auto& s) {
return reduction::std(s); },
820 Numeric<typename A::value_type> &&
821 Ordered<typename A::value_type>
823stratax::container::Tensor<double>
824std(
const A& arr,
int axis)
827 arr, axis, [](
const auto& s) {
return reduction::std(s); });
const Shape & shape() const noexcept
Returns the logical shape metadata.
size_type rank() const noexcept
Returns the number of dimensions.