123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- /* Copyright 2024 Joaquin M Lopez Munoz.
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or copy at
- * http://www.boost.org/LICENSE_1_0.txt)
- *
- * See https://www.boost.org/libs/unordered for library home page.
- */
- #ifndef BOOST_UNORDERED_DETAIL_FOA_CUMULATIVE_STATS_HPP
- #define BOOST_UNORDERED_DETAIL_FOA_CUMULATIVE_STATS_HPP
- #include <array>
- #include <boost/config.hpp>
- #include <boost/mp11/tuple.hpp>
- #include <cmath>
- #include <cstddef>
- #if defined(BOOST_HAS_THREADS)
- #include <boost/unordered/detail/foa/rw_spinlock.hpp>
- #include <mutex>
- #endif
- namespace boost{
- namespace unordered{
- namespace detail{
- namespace foa{
- /* Cumulative one-pass calculation of the average, variance and deviation of
- * running sequences.
- */
- struct sequence_stats_data
- {
- double m=0.0;
- double m_prior=0.0;
- double s=0.0;
- };
- struct welfords_algorithm /* 0-based */
- {
- template<typename T>
- int operator()(T&& x,sequence_stats_data& d)const noexcept
- {
- static_assert(
- noexcept(static_cast<double>(x)),
- "Argument conversion to double must not throw.");
- d.m_prior=d.m;
- d.m+=(static_cast<double>(x)-d.m)/static_cast<double>(n);
- d.s+=(n!=1)*
- (static_cast<double>(x)-d.m_prior)*(static_cast<double>(x)-d.m);
- return 0; /* mp11::tuple_transform requires that return type not be void */
- }
- std::size_t n;
- };
- struct sequence_stats_summary
- {
- double average;
- double variance;
- double deviation;
- };
- /* Stats calculated jointly for N same-sized sequences to save the space
- * for count.
- */
- template<std::size_t N>
- class cumulative_stats
- {
- public:
- struct summary
- {
- std::size_t count;
- std::array<sequence_stats_summary,N> sequence_summary;
- };
- void reset()noexcept{*this=cumulative_stats();}
-
- template<typename... Ts>
- void add(Ts&&... xs)noexcept
- {
- static_assert(
- sizeof...(Ts)==N,"A sample must be provided for each sequence.");
- if(BOOST_UNLIKELY(++n==0)){ /* wraparound */
- reset();
- n=1;
- }
- mp11::tuple_transform(
- welfords_algorithm{n},
- std::forward_as_tuple(std::forward<Ts>(xs)...),
- data);
- }
-
- summary get_summary()const noexcept
- {
- summary res;
- res.count=n;
- for(std::size_t i=0;i<N;++i){
- double average=data[i].m,
- variance=n!=0?data[i].s/static_cast<double>(n):0.0, /* biased */
- deviation=std::sqrt(variance);
- res.sequence_summary[i]={average,variance,deviation};
- }
- return res;
- }
- private:
- std::size_t n=0;
- std::array<sequence_stats_data,N> data;
- };
- #if defined(BOOST_HAS_THREADS)
- template<std::size_t N>
- class concurrent_cumulative_stats:cumulative_stats<N>
- {
- using super=cumulative_stats<N>;
- using lock_guard=std::lock_guard<rw_spinlock>;
- public:
- using summary=typename super::summary;
- concurrent_cumulative_stats()noexcept:super{}{}
- concurrent_cumulative_stats(const concurrent_cumulative_stats& x)noexcept:
- concurrent_cumulative_stats{x,lock_guard{x.mut}}{}
- concurrent_cumulative_stats&
- operator=(const concurrent_cumulative_stats& x)noexcept
- {
- auto x1=x;
- lock_guard lck{mut};
- static_cast<super&>(*this)=x1;
- return *this;
- }
- void reset()noexcept
- {
- lock_guard lck{mut};
- super::reset();
- }
-
- template<typename... Ts>
- void add(Ts&&... xs)noexcept
- {
- lock_guard lck{mut};
- super::add(std::forward<Ts>(xs)...);
- }
-
- summary get_summary()const noexcept
- {
- lock_guard lck{mut};
- return super::get_summary();
- }
- private:
- concurrent_cumulative_stats(const super& x,lock_guard&&):super{x}{}
- mutable rw_spinlock mut;
- };
- #else
- template<std::size_t N>
- using concurrent_cumulative_stats=cumulative_stats<N>;
- #endif
- } /* namespace foa */
- } /* namespace detail */
- } /* namespace unordered */
- } /* namespace boost */
- #endif
|