statistics.hh 6.24 KB
Newer Older
1
2
3
#pragma once

#include <typed-geometry/detail/utility.hh>
Philip Trettner's avatar
Philip Trettner committed
4
5
#include <typed-geometry/feature/assert.hh>
#include <typed-geometry/functions/basic/minmax.hh>
6
7
8
9
10
11
12
#include <typed-geometry/types/span.hh>

/*
 * This header provides summary statistics and operations on ranges
 *
 * - min_element
 * - max_element
13
14
 * - max_index
 * - min_index
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 * - average (same as arithmetic_mean)
 * - mean    (same as arithmetic_mean)
 * - arithmetic_mean
 * - geometric_mean (TODO)
 * - sum
 * - product
 * - variance
 * - standard_deviation
 * - count (TODO)
 *
 * Usage:
 *   auto s = tg::sum(a);         // a can be anything with range-based-for
 *   auto s = tg::mean<float>(a); // explicit element type (converts)
 */

namespace tg
{
namespace detail
{
template <class T = void, class RangeT, class TransformF, class ReduceF>
35
[[nodiscard]] constexpr auto fold_right(RangeT const& values, TransformF&& t, ReduceF&& f)
36
37
38
39
40
{
    TG_CONTRACT(tg::begin(values) != tg::end(values) && "values must not be empty");
    using R = same_or<T, element_type<RangeT>>;

    auto it = tg::begin(values);
41
    using U = std::decay_t<decltype(f(t(R(*it)), t(R(*it))))>;
42
    auto const e = tg::end(values);
43
    U r = t(R(*it));
44
    ++it;
45
46
    while (it != e)
    {
47
        r = f(r, t(R(*it)));
48
        ++it;
49
50
51
52
53
    }
    return r;
}
}

54
template <class RangeT, class KeyT>
55
[[nodiscard]] constexpr auto min_by(RangeT const& values, KeyT&& key = {})
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
{
    TG_CONTRACT(tg::begin(values) != tg::end(values) && "values must not be empty");
    auto it = tg::begin(values);
    auto const e = tg::end(values);

    auto min_e = it;
    auto min_v = key(*it);

    it++;
    while (it != e)
    {
        auto v = key(*it);
        if (v < min_v)
        {
            min_v = v;
            min_e = it;
        }
        it++;
    }

Kersten Schuster's avatar
Kersten Schuster committed
76
    return *min_e;
77
78
79
}

template <class RangeT, class KeyT>
80
[[nodiscard]] constexpr auto max_by(RangeT const& values, KeyT&& key = {})
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
{
    TG_CONTRACT(tg::begin(values) != tg::end(values) && "values must not be empty");
    auto it = tg::begin(values);
    auto const e = tg::end(values);

    auto max_e = it;
    auto max_v = key(*it);

    it++;
    while (it != e)
    {
        auto v = key(*it);
        if (v > max_v)
        {
            max_v = v;
            max_e = it;
        }
        it++;
    }

Kersten Schuster's avatar
Kersten Schuster committed
101
    return *max_e;
102
103
}

104
template <class RangeT, class TransformT = identity_fun>
105
[[nodiscard]] constexpr auto min_element(RangeT const& values, TransformT&& transform = {})
106
107
108
109
110
{
    return detail::fold_right(values, transform, [](auto&& a, auto&& b) { return min(a, b); });
}

template <class RangeT, class TransformT = identity_fun>
111
[[nodiscard]] constexpr auto max_element(RangeT const& values, TransformT&& transform = {})
112
113
114
115
{
    return detail::fold_right(values, transform, [](auto&& a, auto&& b) { return max(a, b); });
}

116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/// returns the index of the max element
template <class RangeT, class TransformT = identity_fun>
[[nodiscard]] constexpr size_t max_index(RangeT const& values, TransformT&& transform = {})
{
    TG_CONTRACT(tg::begin(values) != tg::end(values) && "values must not be empty");
    size_t curr_idx = 0;
    auto it = tg::begin(values);
    auto const end = tg::end(values);

    auto max_v = transform(*it);
    size_t max_idx = curr_idx;

    ++it;
    ++curr_idx;
    while (it != end)
    {
        auto v = transform(*it);
        if (v > max_v)
        {
            max_v = v;
            max_idx = curr_idx;
        }
        ++it;
        ++curr_idx;
    }
    return max_idx;
}

/// returns the index of the min element
template <class RangeT, class TransformT = identity_fun>
[[nodiscard]] constexpr size_t min_index(RangeT const& values, TransformT&& transform = {})
{
    TG_CONTRACT(tg::begin(values) != tg::end(values) && "values must not be empty");
    size_t curr_idx = 0;
    auto it = tg::begin(values);
    auto const end = tg::end(values);

    auto min_v = transform(*it);
    size_t min_idx = curr_idx;

    ++it;
    ++curr_idx;
    while (it != end)
    {
        auto v = transform(*it);
        if (v < min_v)
        {
            min_v = v;
            min_idx = curr_idx;
        }
        ++it;
        ++curr_idx;
    }
    return min_idx;
}


173
template <class T = void, class RangeT = void, class TransformT = identity_fun>
174
[[nodiscard]] constexpr auto sum(RangeT const& values, TransformT&& transform = {})
175
176
177
178
179
{
    return detail::fold_right<T>(values, transform, [](auto&& a, auto&& b) { return a + b; });
}

template <class T = void, class RangeT = void, class TransformT = identity_fun>
180
[[nodiscard]] constexpr auto product(RangeT const& values, TransformT&& transform = {})
181
182
183
184
185
{
    return detail::fold_right<T>(values, transform, [](auto&& a, auto&& b) { return a * b; });
}

template <class T = void, class RangeT = void, class TransformT = identity_fun>
186
[[nodiscard]] constexpr auto arithmetic_mean(RangeT const& values, TransformT&& transform = {})
187
188
{
    auto const s = sum<T>(values, transform);
Julius Nehring-Wirxel's avatar
Julius Nehring-Wirxel committed
189
190
191
192
193
194
195
196
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wsign-conversion"
#endif
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4244) // possible loss of data
#endif
197
    return s / tg::container_size(values);
Julius Nehring-Wirxel's avatar
Julius Nehring-Wirxel committed
198
199
200
201
202
203
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#ifdef _MSC_VER
#pragma warning(pop)
#endif
204
205
206
}

template <class T = void, class RangeT = void, class TransformT = identity_fun>
207
[[nodiscard]] constexpr auto average(RangeT const& values, TransformT&& transform = {})
208
209
210
211
212
{
    return arithmetic_mean<T>(values, transform);
}

template <class T = void, class RangeT = void, class TransformT = identity_fun>
213
[[nodiscard]] constexpr auto mean(RangeT const& values, TransformT&& transform = {})
214
215
216
217
218
{
    return arithmetic_mean<T>(values, transform);
}

template <class T = void, class RangeT = void, class TransformT = identity_fun>
219
[[nodiscard]] constexpr auto variance(RangeT const& values, TransformT&& transform = {})
220
221
222
223
224
225
226
227
228
229
230
231
{
    using R = same_or<T, element_type<RangeT>>;

    auto const avg = arithmetic_mean<T>(values, transform);

    return arithmetic_mean<T>(values, [&](auto&& v) {
        auto const d = transform(R(v)) - avg;
        return d * d;
    });
}

template <class T = void, class RangeT = void, class TransformT = identity_fun>
232
[[nodiscard]] constexpr auto standard_deviation(RangeT const& values, TransformT&& transform = {})
233
{
234
    return sqrt(variance<T>(values, transform));
235
236
}
}