Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
stat_utils.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
95#ifndef STAT_UTILS_H
96#define STAT_UTILS_H
97
98#include <cmath>
99#include <limits>
100#include <algorithm>
101#include <vector>
102#include <map>
103#include <stdexcept>
104#include <tpl_sort_utils.H>
105#include <tpl_dynArray.H>
106
107namespace Aleph {
108
109// =============================================================================
110// Stats Result Structure
111// =============================================================================
112
121template <typename T>
122struct Stats
123{
124 size_t count = 0;
125 T sum = T();
126 T mean = T();
128 T stddev = T();
129 T median = T();
130 T min = T();
131 T max = T();
132 T q1 = T();
133 T q3 = T();
134 T iqr = T();
138
143 [[nodiscard]] bool is_valid() const noexcept { return count > 0; }
144
149 [[nodiscard]] T range() const noexcept { return max - min; }
150};
151
152// =============================================================================
153// Basic Statistical Functions
154// =============================================================================
155
163template <typename Container>
164[[nodiscard]] auto sum(const Container & data)
165 -> std::decay_t<decltype(*std::begin(data))>
166{
167 using T = std::decay_t<decltype(*std::begin(data))>;
168 T result = T();
169 for (const auto & x : data)
170 result += x;
171 return result;
172}
173
182template <typename Container>
183[[nodiscard]] auto mean(const Container & data)
184 -> std::decay_t<decltype(*std::begin(data))>
185{
186 using T = std::decay_t<decltype(*std::begin(data))>;
187 size_t n = 0;
188 T s = T();
189 for (const auto & x : data)
190 {
191 s += x;
192 ++n;
193 }
194 if (n == 0)
195 throw std::invalid_argument("mean: empty container");
196 return s / static_cast<T>(n);
197}
198
214template <typename Container>
215[[nodiscard]] auto variance(const Container & data, bool population = false)
216 -> std::decay_t<decltype(*std::begin(data))>
217{
218 using T = std::decay_t<decltype(*std::begin(data))>;
219
220 size_t n = 0;
221 T m = T(); // Running mean
222 T m2 = T(); // Sum of squared differences from mean
223
224 // Welford's online algorithm
225 for (const auto & x : data)
226 {
227 ++n;
228 T delta = x - m;
229 m += delta / static_cast<T>(n);
230 T delta2 = x - m;
231 m2 += delta * delta2;
232 }
233
234 if (population)
235 {
236 if (n == 0)
237 throw std::invalid_argument("variance: empty container");
238 return m2 / static_cast<T>(n);
239 }
240 else
241 {
242 if (n < 2)
243 throw std::invalid_argument("variance: need at least 2 elements for sample variance");
244 return m2 / static_cast<T>(n - 1);
245 }
246}
247
256template <typename Container>
257[[nodiscard]] auto stddev(const Container & data, bool population = false)
258 -> std::decay_t<decltype(*std::begin(data))>
259{
260 return std::sqrt(variance(data, population));
261}
262
271template <typename Container>
272[[nodiscard]] auto min_value(const Container & data)
273 -> std::decay_t<decltype(*std::begin(data))>
274{
275 auto it = std::begin(data);
276 auto end = std::end(data);
277 if (it == end)
278 throw std::invalid_argument("min_value: empty container");
279
280 auto result = *it;
281 for (++it; it != end; ++it)
282 if (*it < result)
283 result = *it;
284 return result;
285}
286
295template <typename Container>
296[[nodiscard]] auto max_value(const Container & data)
297 -> std::decay_t<decltype(*std::begin(data))>
298{
299 auto it = std::begin(data);
300 auto end = std::end(data);
301 if (it == end)
302 throw std::invalid_argument("max_value: empty container");
303
304 auto result = *it;
305 for (++it; it != end; ++it)
306 if (*it > result)
307 result = *it;
308 return result;
309}
310
319template <typename Container>
320[[nodiscard]] auto min_max(const Container & data)
321 -> std::pair<std::decay_t<decltype(*std::begin(data))>,
322 std::decay_t<decltype(*std::begin(data))>>
323{
324 using T = std::decay_t<decltype(*std::begin(data))>;
325 auto it = std::begin(data);
326 auto end = std::end(data);
327 if (it == end)
328 throw std::invalid_argument("min_max: empty container");
329
330 T min_val = *it;
331 T max_val = *it;
332 for (++it; it != end; ++it)
333 {
334 if (*it < min_val)
335 min_val = *it;
336 if (*it > max_val)
337 max_val = *it;
338 }
339 return {min_val, max_val};
340}
341
342// =============================================================================
343// Percentile and Median Functions
344// =============================================================================
345
357template <typename Container>
358[[nodiscard]] auto percentile(const Container & data, double p)
359 -> std::decay_t<decltype(*std::begin(data))>
360{
361 using T = std::decay_t<decltype(*std::begin(data))>;
362
363 if (p < 0 or p > 100)
364 throw std::invalid_argument("percentile: p must be in [0, 100]");
365
366 // Copy to vector for sorting
367 std::vector<T> sorted(std::begin(data), std::end(data));
368 if (sorted.empty())
369 throw std::invalid_argument("percentile: empty container");
370
371 std::sort(sorted.begin(), sorted.end());
372
373 if (p == 0)
374 return sorted.front();
375 if (p == 100)
376 return sorted.back();
377
378 // Calculate index
379 double index = (p / 100.0) * (sorted.size() - 1);
380 size_t lower = static_cast<size_t>(std::floor(index));
381 size_t upper = static_cast<size_t>(std::ceil(index));
382
383 if (lower == upper)
384 return sorted[lower];
385
386 // Linear interpolation
387 double fraction = index - lower;
388 return static_cast<T>(sorted[lower] * (1 - fraction) + sorted[upper] * fraction);
389}
390
399template <typename Container>
400[[nodiscard]] auto median(const Container & data)
401 -> std::decay_t<decltype(*std::begin(data))>
402{
403 return percentile(data, 50);
404}
405
413template <typename Container>
414[[nodiscard]] auto quartiles(const Container & data)
415 -> std::tuple<std::decay_t<decltype(*std::begin(data))>,
416 std::decay_t<decltype(*std::begin(data))>,
417 std::decay_t<decltype(*std::begin(data))>>
418{
419 using T = std::decay_t<decltype(*std::begin(data))>;
420 T q1 = percentile(data, 25);
421 T q2 = percentile(data, 50);
422 T q3 = percentile(data, 75);
423 return {q1, q2, q3};
424}
425
433template <typename Container>
434[[nodiscard]] auto iqr(const Container & data)
435 -> std::decay_t<decltype(*std::begin(data))>
436{
437 return percentile(data, 75) - percentile(data, 25);
438}
439
440// =============================================================================
441// Mode
442// =============================================================================
443
455template <typename Container>
456[[nodiscard]] auto mode(const Container & data)
457 -> std::decay_t<decltype(*std::begin(data))>
458{
459 using T = std::decay_t<decltype(*std::begin(data))>;
460
461 auto it = std::begin(data);
462 auto end = std::end(data);
463 if (it == end)
464 throw std::invalid_argument("mode: empty container");
465
466 std::map<T, size_t> freq;
467 for (const auto & x : data)
468 ++freq[x];
469
470 T mode_val = freq.begin()->first;
471 size_t max_count = freq.begin()->second;
472
473 for (const auto & [val, count] : freq)
474 {
475 if (count > max_count)
476 {
478 mode_val = val;
479 }
480 }
481
482 return mode_val;
483}
484
492template <typename Container>
493[[nodiscard]] bool is_multimodal(const Container & data)
494{
495 using T = std::decay_t<decltype(*std::begin(data))>;
496
497 std::map<T, size_t> freq;
498 for (const auto & x : data)
499 ++freq[x];
500
501 if (freq.empty())
502 return false;
503
504 size_t max_count = 0;
505 for (const auto & [val, count] : freq)
506 if (count > max_count)
508
509 size_t modes = 0;
510 for (const auto & [val, count] : freq)
511 if (count == max_count)
512 ++modes;
513
514 return modes > 1;
515}
516
517// =============================================================================
518// Higher Moments
519// =============================================================================
520
535template <typename Container>
536[[nodiscard]] auto skewness(const Container & data)
537 -> std::decay_t<decltype(*std::begin(data))>
538{
539 using T = std::decay_t<decltype(*std::begin(data))>;
540
541 T m = mean(data);
542 T s = stddev(data);
543
544 if (s == T())
545 return T(); // All values are equal
546
547 size_t n = 0;
548 T sum3 = T();
549 for (const auto & x : data)
550 {
551 T diff = (x - m) / s;
552 sum3 += diff * diff * diff;
553 ++n;
554 }
555
556 if (n < 3)
557 throw std::invalid_argument("skewness: need at least 3 elements");
558
559 // Adjusted Fisher-Pearson coefficient
560 T factor = static_cast<T>(n) / ((n - 1) * (n - 2));
561 return factor * sum3;
562}
563
578template <typename Container>
579[[nodiscard]] auto kurtosis(const Container & data)
580 -> std::decay_t<decltype(*std::begin(data))>
581{
582 using T = std::decay_t<decltype(*std::begin(data))>;
583
584 T m = mean(data);
585 T s = stddev(data);
586
587 if (s == T())
588 return T(); // All values are equal
589
590 size_t n = 0;
591 T sum4 = T();
592 for (const auto & x : data)
593 {
594 T diff = (x - m) / s;
595 T diff2 = diff * diff;
596 sum4 += diff2 * diff2;
597 ++n;
598 }
599
600 if (n < 4)
601 throw std::invalid_argument("kurtosis: need at least 4 elements");
602
603 // Excess kurtosis with bias correction
604 T n_t = static_cast<T>(n);
605 T factor1 = (n_t * (n_t + 1)) / ((n_t - 1) * (n_t - 2) * (n_t - 3));
606 T factor2 = (3 * (n_t - 1) * (n_t - 1)) / ((n_t - 2) * (n_t - 3));
607
608 return factor1 * sum4 - factor2;
609}
610
621template <typename Container>
623 -> std::decay_t<decltype(*std::begin(data))>
624{
625 using T = std::decay_t<decltype(*std::begin(data))>;
626 T m = mean(data);
627 if (m == T())
628 throw std::invalid_argument("coefficient_of_variation: mean is zero");
629 return stddev(data) / std::abs(m);
630}
631
632// =============================================================================
633// Correlation and Covariance
634// =============================================================================
635
647template <typename Container1, typename Container2>
648[[nodiscard]] auto covariance(const Container1 & x, const Container2 & y,
649 bool population = false)
650 -> std::decay_t<decltype(*std::begin(x))>
651{
652 using T = std::decay_t<decltype(*std::begin(x))>;
653
654 auto it_x = std::begin(x);
655 auto it_y = std::begin(y);
656 auto end_x = std::end(x);
657 auto end_y = std::end(y);
658
659 // Welford-style online algorithm for covariance
660 size_t n = 0;
661 T mean_x = T();
662 T mean_y = T();
663 T c = T(); // Co-moment
664
665 while (it_x != end_x and it_y != end_y)
666 {
667 ++n;
668 T dx = *it_x - mean_x;
669 mean_x += dx / static_cast<T>(n);
670 T dy = *it_y - mean_y;
671 mean_y += dy / static_cast<T>(n);
672 c += dx * (*it_y - mean_y);
673
674 ++it_x;
675 ++it_y;
676 }
677
678 if (it_x != end_x or it_y != end_y)
679 throw std::invalid_argument("covariance: containers have different sizes");
680
681 if (population)
682 {
683 if (n == 0)
684 throw std::invalid_argument("covariance: empty containers");
685 return c / static_cast<T>(n);
686 }
687 else
688 {
689 if (n < 2)
690 throw std::invalid_argument("covariance: need at least 2 elements");
691 return c / static_cast<T>(n - 1);
692 }
693}
694
710template <typename Container1, typename Container2>
711[[nodiscard]] auto correlation(const Container1 & x, const Container2 & y)
712 -> std::decay_t<decltype(*std::begin(x))>
713{
714 using T = std::decay_t<decltype(*std::begin(x))>;
715
716 T cov = covariance(x, y, true); // Use population covariance
717 T sx = stddev(x, true); // Population stddev
718 T sy = stddev(y, true);
719
720 if (sx == T() or sy == T())
721 throw std::invalid_argument("correlation: one or both datasets have zero variance");
722
723 return cov / (sx * sy);
724}
725
726// =============================================================================
727// Histogram
728// =============================================================================
729
739template <typename Container>
740[[nodiscard]] auto histogram(const Container & data, size_t num_bins)
741 -> std::vector<std::pair<std::decay_t<decltype(*std::begin(data))>,
742 size_t>>
743{
744 using T = std::decay_t<decltype(*std::begin(data))>;
745
746 if (num_bins == 0)
747 throw std::invalid_argument("histogram: num_bins must be > 0");
748
749 auto [min_val, max_val] = min_max(data);
751
752 if (range == T())
753 {
754 // All values are equal
755 return {{min_val, std::distance(std::begin(data), std::end(data))}};
756 }
757
758 T bin_width = range / static_cast<T>(num_bins);
759
760 std::vector<size_t> counts(num_bins, 0);
761
762 for (const auto & x : data)
763 {
764 size_t bin = static_cast<size_t>((x - min_val) / bin_width);
765 if (bin >= num_bins)
766 bin = num_bins - 1; // Handle max value
767 ++counts[bin];
768 }
769
770 std::vector<std::pair<T, size_t>> result;
771 result.reserve(num_bins);
772
773 for (size_t i = 0; i < num_bins; ++i)
774 {
775 T center = min_val + (i + 0.5) * bin_width;
776 result.emplace_back(center, counts[i]);
777 }
778
779 return result;
780}
781
782// =============================================================================
783// Comprehensive Stats Function
784// =============================================================================
785
793template <typename Container>
795 -> Stats<std::decay_t<decltype(*std::begin(data))>>
796{
797 using T = std::decay_t<decltype(*std::begin(data))>;
798 Stats<T> s;
799
800 // Count elements
801 for (const auto & x : data)
802 {
803 s.sum += x;
804 ++s.count;
805 }
806
807 if (s.count == 0)
808 return s;
809
810 s.mean = s.sum / static_cast<T>(s.count);
811
812 // Min/Max
813 auto [min_val, max_val] = min_max(data);
814 s.min = min_val;
815 s.max = max_val;
816
817 // Variance and stddev (need at least 2 elements)
818 if (s.count >= 2)
819 {
820 s.variance = variance(data, false);
821 s.stddev = std::sqrt(s.variance);
822
823 // Coefficient of variation
824 if (s.mean != T())
825 s.coef_variation = s.stddev / std::abs(s.mean);
826 }
827
828 // Percentiles
829 s.median = percentile(data, 50);
830 s.q1 = percentile(data, 25);
831 s.q3 = percentile(data, 75);
832 s.iqr = s.q3 - s.q1;
833
834 // Higher moments (need at least 3/4 elements)
835 if (s.count >= 3)
836 s.skewness = skewness(data);
837
838 if (s.count >= 4)
839 s.kurtosis = kurtosis(data);
840
841 return s;
842}
843
844// =============================================================================
845// Legacy API (backward compatible)
846// =============================================================================
847
871template <class T>
872void compute_stats(T * data, int l, int r,
873 T & avg, T & var, T & med,
874 T & _min, T & _max)
875{
876 if (l > r)
877 {
878 avg = var = med = _min = _max = T();
879 return;
880 }
881
882 // Sort the array for quantiles
883 std::sort(data + l, data + r + 1);
884
885 _min = data[l];
886 _max = data[r];
887
888 // Calculate median (correctly using l offset)
889 int n = r - l + 1;
890 int mid = l + n / 2;
891 if (n % 2 == 0)
892 med = (data[mid - 1] + data[mid]) / 2;
893 else
894 med = data[mid];
895
896 // Welford's algorithm for mean and variance
897 T m = T();
898 T m2 = T();
899 for (int i = l; i <= r; ++i)
900 {
901 int k = i - l + 1;
902 T delta = data[i] - m;
903 m += delta / static_cast<T>(k);
904 T delta2 = data[i] - m;
905 m2 += delta * delta2;
906 }
907
908 avg = m;
909 var = (n > 1) ? m2 / static_cast<T>(n - 1) : T();
910}
911
925 template <typename Container>
926 void compute_stats(const Container & data,
927 std::decay_t<decltype(*std::begin(data))> & avg,
928 std::decay_t<decltype(*std::begin(data))> & var,
929 std::decay_t<decltype(*std::begin(data))> & med,
930 std::decay_t<decltype(*std::begin(data))> & _min,
931 std::decay_t<decltype(*std::begin(data))> & _max)
932 {
933 using T = std::decay_t<decltype(*std::begin(data))>;
934
935 std::vector<T> sorted(std::begin(data), std::end(data));
936 if (sorted.empty())
937 {
938 avg = var = med = _min = _max = T();
939 return;
940 }
941
942 std::sort(sorted.begin(), sorted.end());
943
944 _min = sorted.front();
945 _max = sorted.back();
946
947 const size_t n = sorted.size();
948 const size_t mid = n / 2;
949 if (n % 2 == 0)
950 med = (sorted[mid - 1] + sorted[mid]) / 2;
951 else
952 med = sorted[mid];
953
954 // Welford's algorithm for mean and variance
955 T m = T();
956 T m2 = T();
957 size_t k = 0;
958 for (const auto & x : sorted)
959 {
960 ++k;
961 T delta = x - m;
962 m += delta / static_cast<T>(k);
963 T delta2 = x - m;
964 m2 += delta * delta2;
965 }
966
967 avg = m;
968 var = (n > 1) ? m2 / static_cast<T>(n - 1) : T();
969 }
970
971} // namespace Aleph
972
973// Export commonly used functions to global namespace
974using Aleph::Stats;
977using Aleph::sum;
978using Aleph::mean;
979using Aleph::variance;
980using Aleph::stddev;
981using Aleph::median;
983using Aleph::quartiles;
984using Aleph::iqr;
985using Aleph::mode;
986using Aleph::skewness;
987using Aleph::kurtosis;
991using Aleph::histogram;
992using Aleph::min_value;
993using Aleph::max_value;
994using Aleph::min_max;
995
996#endif // STAT_UTILS_H
void empty() noexcept
empty the list
Definition htlist.H:1689
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
iterator end() noexcept
Return an STL-compatible end iterator.
iterator begin() noexcept
Return an STL-compatible iterator to the first element.
static mpfr_t y
Definition mpfr_mul_d.c:3
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
auto percentile(const Container &data, double p) -> std::decay_t< decltype(*std::begin(data))>
Compute a percentile value.
Definition stat_utils.H:358
auto histogram(const Container &data, size_t num_bins) -> std::vector< std::pair< std::decay_t< decltype(*std::begin(data))>, size_t > >
Compute a histogram of the data.
Definition stat_utils.H:740
auto variance(const Container &data, bool population=false) -> std::decay_t< decltype(*std::begin(data))>
Compute variance using Welford's numerically stable algorithm.
Definition stat_utils.H:215
auto kurtosis(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute excess kurtosis (measure of tailedness).
Definition stat_utils.H:579
const T * median(const T &a, const T &b, const T &c, const Compare &cmp=Compare())
Return a pointer to the median value among three elements.
Definition ahUtils.H:84
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:107
auto covariance(const Container1 &x, const Container2 &y, bool population=false) -> std::decay_t< decltype(*std::begin(x))>
Compute covariance between two datasets.
Definition stat_utils.H:648
auto stddev(const Container &data, bool population=false) -> std::decay_t< decltype(*std::begin(data))>
Compute standard deviation.
Definition stat_utils.H:257
auto mean(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute the arithmetic mean.
Definition stat_utils.H:183
bool diff(const C1 &c1, const C2 &c2, Eq e=Eq())
Check if two containers differ.
auto min_max(const Container &data) -> std::pair< std::decay_t< decltype(*std::begin(data))>, std::decay_t< decltype(*std::begin(data))> >
Compute minimum and maximum values in one pass.
Definition stat_utils.H:320
auto min_value(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute minimum value.
Definition stat_utils.H:272
auto skewness(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute skewness (measure of asymmetry).
Definition stat_utils.H:536
auto iqr(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute the interquartile range (IQR = Q3 - Q1).
Definition stat_utils.H:434
auto compute_all_stats(const Container &data) -> Stats< std::decay_t< decltype(*std::begin(data))> >
Compute all statistics for a dataset.
Definition stat_utils.H:794
auto correlation(const Container1 &x, const Container2 &y) -> std::decay_t< decltype(*std::begin(x))>
Compute Pearson correlation coefficient.
Definition stat_utils.H:711
Container< T > range(const T start, const T end, const T step=1)
Generate a range of values [start, end] with a given step.
bool is_multimodal(const Container &data)
Check if data is multimodal.
Definition stat_utils.H:493
auto coefficient_of_variation(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute coefficient of variation (CV = stddev / mean).
Definition stat_utils.H:622
auto mode(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute the mode (most frequent value).
Definition stat_utils.H:456
auto quartiles(const Container &data) -> std::tuple< std::decay_t< decltype(*std::begin(data))>, std::decay_t< decltype(*std::begin(data))>, std::decay_t< decltype(*std::begin(data))> >
Compute quartiles (Q1, Q2, Q3).
Definition stat_utils.H:414
auto max_value(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute maximum value.
Definition stat_utils.H:296
void compute_stats(T *data, int l, int r, T &avg, T &var, T &med, T &_min, T &_max)
Compute basic descriptive statistics for an array range.
Definition stat_utils.H:872
DynList< T > maps(const C &c, Op op)
Classic map operation.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
Container for comprehensive statistical results.
Definition stat_utils.H:123
T q1
First quartile (25th percentile)
Definition stat_utils.H:132
size_t count
Number of elements.
Definition stat_utils.H:124
T min
Minimum value.
Definition stat_utils.H:130
T mean
Arithmetic mean.
Definition stat_utils.H:126
T skewness
Skewness (asymmetry)
Definition stat_utils.H:135
T q3
Third quartile (75th percentile)
Definition stat_utils.H:133
T variance
Sample variance.
Definition stat_utils.H:127
T coef_variation
Coefficient of variation (stddev/mean)
Definition stat_utils.H:137
T max
Maximum value.
Definition stat_utils.H:131
T median
Median (50th percentile)
Definition stat_utils.H:129
bool is_valid() const noexcept
Check if statistics are valid.
Definition stat_utils.H:143
T iqr
Interquartile range (Q3 - Q1)
Definition stat_utils.H:134
T range() const noexcept
Get the range (max - min).
Definition stat_utils.H:149
T kurtosis
Excess kurtosis (tailedness)
Definition stat_utils.H:136
T stddev
Standard deviation.
Definition stat_utils.H:128
T sum
Sum of all values.
Definition stat_utils.H:125
Lazy and scalable dynamic array implementation.
Comprehensive sorting algorithms and search utilities for Aleph-w.
DynList< int > l