13#if !defined(ULTRA_DISTRIBUTION_H)
14# error "Don't include this file directly, include the specific .h instead"
17#if !defined(ULTRA_DISTRIBUTION_TCC)
18#define ULTRA_DISTRIBUTION_TCC
23template<ArithmeticFloatingType T>
24void distribution<T>::clear()
26 *
this = distribution();
32template<ArithmeticFloatingType T>
33bool distribution<T>::empty() const noexcept
41template<ArithmeticFloatingType T>
42std::size_t distribution<T>::size() const noexcept
50template<ArithmeticFloatingType T>
51T distribution<T>::max() const noexcept
60template<ArithmeticFloatingType T>
61T distribution<T>::min() const noexcept
70template<ArithmeticFloatingType T>
71T distribution<T>::mean() const noexcept
80template<ArithmeticFloatingType T>
81T distribution<T>::variance()
const
84 return m2_ /
static_cast<T
>(size());
95template<ArithmeticFloatingType T>
96void distribution<T>::add(T val)
103 min_ = max_ = mean_ = val;
104 else if (val < min())
106 else if (val > max())
122 ++seen_[round_to(val)];
124 update_variance(val);
127template<ArithmeticFloatingType T>
128const std::map<T, std::uintmax_t> &distribution<T>::seen()
const
149template<ArithmeticFloatingType T>
150double distribution<T>::entropy()
const
155 const double c(1.0 / std::log(2.0));
158 for (
const auto &f : seen())
160 const auto p(
static_cast<double>(f.second) /
static_cast<double>(size()));
162 h -= p * std::log(p) * c;
183template<ArithmeticFloatingType T>
184void distribution<T>::update_variance(T val)
189 static const auto kahan_add([](T &acc, T &comp, T x)
199 comp = (t - acc) - y;
205 const T delta(val - mean_);
207 kahan_add(mean_, mean_comp_, delta /
static_cast<T
>(size_));
208 kahan_add(m2_, m2_comp_, delta * (val - mean_));
214template<ArithmeticFloatingType T>
215T distribution<T>::standard_deviation()
const
222 return sqrt(variance());
231template<ArithmeticFloatingType T>
232bool distribution<T>::save(std::ostream &
out)
const
234 out << size() <<
'\n';
240 out << std::scientific
241 << std::setprecision(std::numeric_limits<T>::digits10 + 1)
247 out << seen().size() <<
'\n';
248 for (
const auto &elem : seen())
249 out << elem.first <<
' ' << elem.second <<
'\n';
264template<ArithmeticFloatingType T>
265bool distribution<T>::load(std::istream &in)
267 distribution<T> temp;
269 if (!(in >> temp.size_))
280 in >> std::scientific
281 >> std::setprecision(std::numeric_limits<T>::digits10 + 1);
283 if (!(in >> temp.mean_))
286 if (!(in >> temp.min_))
289 if (!(in >> temp.max_))
292 if (!(in >> temp.m2_))
295 typename decltype(seen_)::size_type n;
299 for (
decltype(n) i(0); i < n; ++i)
301 typename decltype(seen_)::key_type key;
302 typename decltype(seen_)::mapped_type val;
303 if (!(in >> key >> val))
306 temp.seen_[key] = val;
309 if (!temp.is_valid())
312 *
this = std::move(temp);
319template<ArithmeticFloatingType T>
320bool distribution<T>::is_valid()
const
324 distribution<T> empty_dist;
326 return seen_ == empty_dist.seen_ && issmall(m2_ - empty_dist.m2_)
327 && issmall(m2_comp_ - empty_dist.m2_comp_)
328 && issmall(mean_ - empty_dist.mean_)
329 && issmall(mean_comp_ - empty_dist.mean_comp_)
330 && issmall(max_ - empty_dist.max_) && issmall(min_ - empty_dist.min_);
339 if (isfinite(min()) && isfinite(mean()) && min() > mean())
341 ultraERROR(
"Distribution: min={} > mean={}",
342 internal::streamed(min()),
343 internal::streamed(mean()));
347 if (isfinite(max()) && isfinite(mean()) && max() < mean())
349 ultraERROR(
"Distribution: max={} < mean={}",
350 internal::streamed(max()),
351 internal::streamed(mean()));
355 if (isnan(variance()) || !isnonnegative(variance()))
357 ultraERROR(
"Distribution: negative variance");
361 std::size_t total(0);
362 for (
const auto values(seen_ | std::views::values);
auto v : values)
366 ultraERROR(
"Seen histogram contains zero-count bin");
370 if (v > std::numeric_limits<std::size_t>::max() - total)
372 ultraERROR(
"Seen histogram total overflow");
381 ultraERROR(
"Seen histogram total {} does not match distribution size {}",
399template<ArithmeticFloatingType T>
400void distribution<T>::merge(
const distribution<T> &d2)
411 const auto max1(max());
412 const auto max2(d2.max());
414 const auto min1(min());
415 const auto min2(d2.min());
417 const auto size1(size());
418 const auto size2(d2.size());
419 const auto new_size(size1 + size2);
421 const auto n1(
static_cast<T
>(size1));
422 const auto n2(
static_cast<T
>(size2));
423 const auto n(
static_cast<T
>(new_size));
425 const auto delta(d2.mean() - mean());
426 const auto new_mean(size1 >= size2
427 ? mean() + delta * (n2 / n)
428 : d2.mean() - delta * (n1 / n));
430 m2_ += d2.m2_ + delta * delta * (n1 * n2 / n);
436 max_ = std::max(max1, max2);
437 min_ = std::min(min1, min2);
441 for (
auto &[k, v] : d2.seen_)
fitnd sqrt(fitnd f)
Definition fitness.cc:411