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 : : 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 : 870142 : std::size_t operator()( const key_type& key ) const { 44 : 870142 : 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 : 157554 : 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 : 24 : explicit BiPDF( const std::vector< tk::real >& bs ) : 61 : 24 : 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 : 229429 : std::size_t nsample() const noexcept { return m_nsample; } 66 : : 67 : : //! Add sample to bivariate PDF 68 : : //! \param[in] sample Sample to add 69 : 340000 : void add( std::array< tk::real, dim > sample ) { 70 : 340000 : ++m_nsample; 71 : 340000 : ++m_pdf[ {{ std::lround( sample[0] / m_binsize[0] ), 72 [ + - ]: 680000 : std::lround( sample[1] / m_binsize[1] ) }} ]; 73 : 340000 : } 74 : : 75 : : //! Add multiple samples from a PDF 76 : : //! \param[in] p PDF whose samples to add 77 : 220542 : void addPDF( const BiPDF& p ) { 78 : 220542 : m_binsize = p.binsize(); 79 : 220542 : m_nsample += p.nsample(); 80 [ + + ][ + - ]: 526560 : for (const auto& e : p.map()) m_pdf[ e.first ] += e.second; 81 : 220542 : } 82 : : 83 : : //! Zero bins 84 : 126072 : 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 : 220554 : 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 : 220554 : const std::array< tk::real, dim >& binsize() const noexcept 93 : 220554 : { 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 : 12 : std::array< long, 2*dim > extents() const { 99 [ - + ][ - - ]: 12 : Assert( !m_pdf.empty(), "PDF empty" ); [ - - ][ - - ] 100 : 24 : auto x = std::minmax_element( begin(m_pdf), end(m_pdf), 101 : 13311 : []( const pair_type& a, const pair_type& b ) 102 [ + - ]: 13323 : { return a.first[0] < b.first[0]; } ); 103 : 24 : auto y = std::minmax_element( begin(m_pdf), end(m_pdf), 104 : 13311 : []( const pair_type& a, const pair_type& b ) 105 [ + - ]: 13323 : { return a.first[1] < b.first[1]; } ); 106 : 24 : return {{ x.first->first[0], x.second->first[0], 107 : 24 : 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 : 472590 : void pup( PUP::er& p ) { 115 : 472590 : p | m_binsize; 116 : 472590 : p | m_nsample; 117 : 472590 : p | m_pdf; 118 : 472590 : } 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 : 472590 : 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