According to the boost website, an accumulator is:
[…] a primitive computational entity that accepts data one sample at a time and maintains some internal state. These accumulators may offload some of their computations on other accumulators, on which they depend. Accumulators are grouped within an accumulator set.
I was slightly bored by the idea of starting my blog with this framework. As a video game developer, what much use could be statistics? The feeling went away quickly as I reminded myself how important they are if only during debugging and optimization phases. For instance: FPS (Frame-Per-Seconds) analysis.
The main object we deal with is the accumulator set, configured to handle an arbitrary set of statistic computations. Once created, all is needed is to push data into it, and query the computed results as we please. Some computations are immediate (as the data are pushed in) or lazy (only when queried).
Boost comes with quite an extensive collection of pre-defined statistical accumulators, like mean, median, moment, etc. Most of them with weighted versions, various quantiles types, etc. But the framework also provide an interface to create new accumulators.
Here’s a simple example of an FPS accumulator set to keep track of the median, mean, min and max frame rate over a course of time.
First we need to include:
// Default headers #include <boost/accumulators/accumulators.hpp> #include <boost/accumulators/statistics/stats.hpp> // Headers specifics to the computations we need #include <boost/accumulators/statistics/median.hpp> #include <boost/accumulators/statistics/mean.hpp> #include <boost/accumulators/statistics/min.hpp> #include <boost/accumulators/statistics/max.hpp> using namespace boost::accumulators;
We initialize our FPS accumulator set like so:
accumulator_set<double, stats< tag::median(with_p_square_quantile), tag::mean, tag::min, tag::max > > fpsStats;
The first template argument specify in which type we are going to work with. For some reason I’m getting a build error when I try to pass float, but is working just fine with double or int.
It is followed by the stats block where we list all the accumulator computations we need. In this case I went for median, average (mean), min & max.
With the fpsStats object in hand, all we need is to push in the data. Here’s for testing purpose:
fpsStats(5); fpsStats(32); fpsStats(41); fpsStats(68); fpsStats(12); fpsStats(12); fpsStats(37);
Each accumulator type provides an extractor to read their computation results. In our FPS example, we could display the statistics like so:
std::cout << "Median: " << median(fpsStats) << std::endl; std::cout << "Mean: " << mean(fpsStats) << std::endl; std::cout << "Min: " << min(fpsStats) << std::endl; std::cout << "Max: " << max(fpsStats) << std::endl;
Which, according to the previous set of data we pushed in, would give us:
Median: 32 Mean: 29.5714 Min: 5 Max: 68
That’s it, pretty simple! Now if only I was a better mathematician to help me understand all those provided statistical accumulators…