Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/Statistics/BiPDF.hpp
4 : : \copyright 2012-2015 J. Bakosi,
5 : : 2016-2018 Los Alamos National Security, LLC.,
6 : : 2019-2021 Triad National Security, LLC.
7 : : All rights reserved. See the LICENSE file for details.
8 : : \brief Joint bivariate PDF estimator
9 : : \details Joint bivariate PDF estimator. This class can be used to estimate a
10 : : joint probability density function (PDF) of two scalar variables from an
11 : : ensemble. The implementation uses the standard container std::unordered_map,
12 : : which is a hash-based associative container with linear algorithmic
13 : : complexity for insertion of a new sample.
14 : : */
15 : : // *****************************************************************************
16 : : #ifndef BiPDF_h
17 : : #define BiPDF_h
18 : :
19 : : #include <array>
20 : : #include <unordered_map>
21 : : #include <algorithm>
22 : :
23 : : #include "Types.hpp"
24 : : #include "PUPUtil.hpp"
25 : :
26 : : namespace tk {
27 : :
28 : : //! Joint bivariate PDF estimator
29 : 420076 : class BiPDF {
30 : :
31 : : public:
32 : : //! Number of sample space dimensions
33 : : static const std::size_t dim = 2;
34 : :
35 : : //! Key type
36 : : using key_type = std::array< long, dim >;
37 : :
38 : : //! Pair type
39 : : using pair_type = std::pair< const key_type, tk::real >;
40 : :
41 : : // Hash functor for key_type
42 : : struct key_hash {
43 : : std::size_t operator()( const key_type& key ) const {
44 : 777060 : return std::hash< long >()( key[0] ) ^ std::hash< long >()( key[1] );
45 : : }
46 : : };
47 : :
48 : : //! \brief Joint bivariate PDF
49 : : //! \details The underlying container type is an unordered_map where the key
50 : : //! is two bin ids corresponding to the two sample space dimensions, and
51 : : //! the mapped value is the sample counter. The hasher functor, defined by
52 : : //! key_hash provides an XORed hash of the two bin ids.
53 : : using map_type = std::unordered_map< key_type, tk::real, key_hash >;
54 : :
55 : : //! Empty constructor for Charm++
56 [ + - ]: 210040 : explicit BiPDF() : m_binsize( {{ 0, 0 }} ), m_nsample( 0 ), m_pdf() {}
57 : :
58 : : //! Constructor: Initialize joint bivariate PDF container
59 : : //! \param[in] bs Sample space bin size in both directions
60 : 32 : explicit BiPDF( const std::vector< tk::real >& bs ) :
61 : 32 : m_binsize( {{ bs[0], bs[1] }} ), m_nsample( 0 ), m_pdf() {}
62 : :
63 : : //! Accessor to number of samples
64 : : //! \return Number of samples collected
65 : : std::size_t nsample() const noexcept { return m_nsample; }
66 : :
67 : : //! Add sample to bivariate PDF
68 : : //! \param[in] sample Sample to add
69 : 120000 : void add( std::array< tk::real, dim > sample ) {
70 : 120000 : ++m_nsample;
71 : 240000 : ++m_pdf[ {{ std::lround( sample[0] / m_binsize[0] ),
72 : 120000 : std::lround( sample[1] / m_binsize[1] ) }} ];
73 : 120000 : }
74 : :
75 : : //! Add multiple samples from a PDF
76 : : //! \param[in] p PDF whose samples to add
77 : 315060 : void addPDF( const BiPDF& p ) {
78 : 315060 : m_binsize = p.binsize();
79 : 315060 : m_nsample += p.nsample();
80 [ + + ]: 705324 : for (const auto& e : p.map()) m_pdf[ e.first ] += e.second;
81 : 315060 : }
82 : :
83 : : //! Zero bins
84 : 168096 : void zero() noexcept { m_nsample = 0; m_pdf.clear(); }
85 : :
86 : : //! Constant accessor to underlying PDF map
87 : : //! \return Constant reference to underlying map
88 : : const map_type& map() const noexcept { return m_pdf; }
89 : :
90 : : //! Constant accessor to bin sizes
91 : : //! \return Constant reference to sample space bin sizes
92 : : const std::array< tk::real, dim >& binsize() const noexcept
93 : : { return m_binsize; }
94 : :
95 : : //! Return minimum and maximum bin ids of sample space in both dimensions
96 : : //! \return {xmin,xmax,ymin,ymax} Minima and maxima of the bin ids in a
97 : : //! std::array
98 : 8 : std::array< long, 2*dim > extents() const {
99 : : Assert( !m_pdf.empty(), "PDF empty" );
100 : : auto x = std::minmax_element( begin(m_pdf), end(m_pdf),
101 : : []( const pair_type& a, const pair_type& b )
102 [ + + ][ + - ]: 2587 : { return a.first[0] < b.first[0]; } );
[ - + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
103 : : auto y = std::minmax_element( begin(m_pdf), end(m_pdf),
104 : : []( const pair_type& a, const pair_type& b )
105 [ + + ][ + - ]: 2588 : { return a.first[1] < b.first[1]; } );
[ - + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
106 : : return {{ x.first->first[0], x.second->first[0],
107 : 8 : y.first->first[1], y.second->first[1] }};
108 : : }
109 : :
110 : : /** @name Pack/Unpack: Serialize BiPDF object for Charm++ */
111 : : ///@{
112 : : //! Pack/Unpack serialize member function
113 : : //! \param[in,out] p Charm++'s PUP::er serializer object reference
114 : 630120 : void pup( PUP::er& p ) {
115 : : p | m_binsize;
116 : 630120 : p | m_nsample;
117 : 630120 : p | m_pdf;
118 : 630120 : }
119 : : //! \brief Pack/Unpack serialize operator|
120 : : //! \param[in,out] p Charm++'s PUP::er serializer object reference
121 : : //! \param[in,out] c BiPDF object reference
122 [ + - ]: 630120 : friend void operator|( PUP::er& p, BiPDF& c ) { c.pup(p); }
123 : : ///@}
124 : :
125 : : private:
126 : : std::array< tk::real, dim > m_binsize; //!< Sample space bin sizes
127 : : std::size_t m_nsample; //!< Number of samples collected
128 : : map_type m_pdf; //!< Probability density function
129 : : };
130 : :
131 : : } // tk::
132 : :
133 : : #endif // BiPDF_h
|