JPL Spatial
Sound spatialization and propagation library
Loading...
Searching...
No Matches
Algorithm.h
Go to the documentation of this file.
1//
2// ██╗██████╗ ██╗ ██╗██████╗ ███████╗
3// ██║██╔══██╗ ██║ ██║██╔══██╗██╔════╝ ** JPLSpatial **
4// ██║██████╔╝ ██║ ██║██████╔╝███████╗
5// ██ ██║██╔═══╝ ██║ ██║██╔══██╗╚════██║ https://github.com/Jaytheway/JPLSpatial
6// ╚█████╔╝██║ ███████╗██║██████╔╝███████║
7// ╚════╝ ╚═╝ ╚══════╝╚═╝╚═════╝ ╚══════╝
8//
9// Copyright 2024 Jaroslav Pevno, JPLSpatial is offered under the terms of the ISC license:
10//
11// Permission to use, copy, modify, and/or distribute this software for any purpose with or
12// without fee is hereby granted, provided that the above copyright notice and this permission
13// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
14// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
16// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
17// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20#pragma once
21
22#include "JPLSpatial/Core.h"
24
25#include <iterator>
26#include <type_traits>
27#include <utility>
28#include <functional>
29#include <numeric>
30#include <algorithm>
31#include <ranges>
32#include <random>
33
34namespace JPL::Algo
35{
36 namespace Internal
37 {
38 template<class ContainerType>
39 using ElementTypeOf = std::remove_cvref_t<decltype(*std::declval<ContainerType>().begin())>;
40 }
41
42 //==========================================================================
44 template<class RangeType, class T, class Fn = std::plus<T>>
45 [[nodiscard]] JPL_INLINE constexpr T Accumulate(RangeType&& range, T initialValue, Fn reduceOp = {})
46 {
47 return std::accumulate(range.begin(), range.end(), std::move(initialValue), reduceOp);
48 }
49
50 //==========================================================================
52 template <class T = void>
53 struct AccPow2
54 {
55 [[nodiscard]] JPL_INLINE constexpr T operator()(const T& acc, const T& value) const noexcept
56 {
57 return acc + value * value;
58 }
59 };
60
62 template <class T = void>
63 struct AccAbs
64 {
65 [[nodiscard]] JPL_INLINE constexpr T operator()(const T& acc, const T& value) const noexcept
66 {
67 return acc + Math::Abs(value);
68 }
69 };
70
72 template <class T = void>
74 {
75 T mMultiplier;
76 public:
77 explicit Multiply(T multiplier) : mMultiplier(multiplier) {}
78
79 JPL_INLINE constexpr void operator()(T& value) const noexcept
80 {
81 value *= mMultiplier;
82 }
83 };
84
85 //==========================================================================
87 template<class ContainerType>
88 JPL_INLINE constexpr void NormalizeL1(ContainerType&& data)
89 {
91 const ElementType sum = Accumulate(std::forward<ContainerType>(data), ElementType(0), AccAbs<ElementType>{});
92 const float invSum = 1.0f / static_cast<float>(sum);
93 std::ranges::for_each(std::forward<ContainerType>(data), Multiply(invSum));
94 }
95
97 template<class ContainerType>
98 JPL_INLINE constexpr void NormalizeL2(ContainerType&& data)
99 {
100 using ElementType = Internal::ElementTypeOf<ContainerType>;
101 const ElementType sum2 = Accumulate(std::forward<ContainerType>(data), ElementType(0), AccPow2<ElementType>{});
102 const float invLength = Math::InvSqrt(static_cast<float>(sum2));
103 std::ranges::for_each(std::forward<ContainerType>(data), Multiply(invLength));
104 }
105
106 template<class ContainerType>
107 [[nodiscard]] JPL_INLINE constexpr bool IsNormalizedL1(const ContainerType& data, float tolerance = JPL_FLOAT_EPS)
108 {
109 using ElementType = Internal::ElementTypeOf<ContainerType>;
110 ElementType sum = Accumulate(data, ElementType(0), AccAbs<ElementType>{});
111 return Math::IsNearlyEqual(static_cast<float>(sum), 1.0f, tolerance);
112 }
113
114 template<class ContainerType>
115 [[nodiscard]] JPL_INLINE constexpr bool IsNormalizedL2(const ContainerType& data, float tolerance = JPL_FLOAT_EPS)
116 {
117 using ElementType = Internal::ElementTypeOf<ContainerType>;
118 const ElementType sum2 = Accumulate(data, ElementType(0), AccPow2<ElementType>{});
119 return Math::IsNearlyEqual(static_cast<float>(sum2), 1.0f, tolerance);
120 }
121
128 template<std::random_access_iterator I, std::sentinel_for<I> S, class Gen> requires std::permutable<I> && std::uniform_random_bit_generator<std::remove_reference_t<Gen>>
129 constexpr I PartialShuffle(I first, S last, std::size_t count, Gen&& gen)
130 {
131 using diff_t = std::iter_difference_t<I>;
132 using distr_t = std::uniform_int_distribution<diff_t>;
133 using param_t = typename distr_t::param_type;
134
135 const diff_t n = std::ranges::distance(first, last);
136 const diff_t k = std::min<diff_t>(count, n);
138
139 for (diff_t i = 0; i < k; ++i)
140 {
141 const diff_t j = dist(gen, param_t(i, n - 1));
142 std::ranges::iter_swap(first + i, first + j);
143 }
144
145 return first + k;
146 }
147
154 template<std::ranges::random_access_range R, class Gen> requires std::permutable<std::ranges::iterator_t<R>> and std::uniform_random_bit_generator<std::remove_reference_t<Gen>>
155 JPL_INLINE constexpr std::ranges::borrowed_iterator_t<R> PartialShuffle(R&& r, std::size_t count, Gen&& gen)
156 {
157 return PartialShuffle(std::ranges::begin(r), std::ranges::end(r), count, std::forward<Gen>(gen));
158 }
159} // namespace JPL::Algo
functor for for_each (and similar) to multiply elements by a multiplier
Definition Algorithm.h:74
Multiply(T multiplier)
Definition Algorithm.h:77
JPL_INLINE constexpr void operator()(T &value) const noexcept
Definition Algorithm.h:79
std::remove_cvref_t< decltype(*std::declval< ContainerType >().begin())> ElementTypeOf
Definition Algorithm.h:39
Definition Algorithm.h:35
constexpr I PartialShuffle(I first, S last, std::size_t count, Gen &&gen)
Definition Algorithm.h:129
JPL_INLINE constexpr void NormalizeL2(ContainerType &&data)
Apply unit vector scaling, so that the magnitude of the vector = 1.
Definition Algorithm.h:98
JPL_INLINE constexpr bool IsNormalizedL1(const ContainerType &data, float tolerance=JPL_FLOAT_EPS)
Definition Algorithm.h:107
JPL_INLINE constexpr T Accumulate(RangeType &&range, T initialValue, Fn reduceOp={})
Just a wrapper for a range, to not have to type begin and end iterators.
Definition Algorithm.h:45
JPL_INLINE constexpr void NormalizeL1(ContainerType &&data)
Normalize so that the sum = 1.
Definition Algorithm.h:88
JPL_INLINE constexpr bool IsNormalizedL2(const ContainerType &data, float tolerance=JPL_FLOAT_EPS)
Definition Algorithm.h:115
JPL_INLINE constexpr T InvSqrt(T x) noexcept
Definition Math.h:283
JPL_INLINE constexpr bool IsNearlyEqual(T a, T b, T tolerance=JPL_FLOAT_EPS_V< T >) noexcept
Definition Math.h:152
JPL_INLINE constexpr auto Abs(const T &value) noexcept
Standard abs is not constexpr in C++20.
Definition Math.h:87
JPL_INLINE simd min(const simd &a, const simd &b) noexcept
Element-wise min.
Definition SIMD.h:1813
functor for std::accumulate (and similar) to accumulate absolute values
Definition Algorithm.h:64
JPL_INLINE constexpr T operator()(const T &acc, const T &value) const noexcept
Definition Algorithm.h:65
functor for std::accumulate (and similar) to accumulate sum of value squares
Definition Algorithm.h:54
JPL_INLINE constexpr T operator()(const T &acc, const T &value) const noexcept
Definition Algorithm.h:55