Walker test code coverage report
Current view: top level - RNGTest - TestU01Props.hpp (source / functions) Hit Total Coverage
Commit: test_coverage.info Lines: 64 71 90.1 %
Date: 2022-09-21 18:57:21 Functions: 133 462 28.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 48 98 49.0 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/RNGTest/TestU01Props.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     TestU01 statistical test properties class
       9                 :            :   \details   This file defines a generic TestU01 statistical test properties
      10                 :            :     class, used to initialize, interface, and evaluate TestU01 RNG statistical
      11                 :            :     tests by the TestU01 library.
      12                 :            : */
      13                 :            : // *****************************************************************************
      14                 :            : #ifndef TestU01Props_h
      15                 :            : #define TestU01Props_h
      16                 :            : 
      17                 :            : #include <vector>
      18                 :            : #include <functional>
      19                 :            : 
      20                 :            : #include "Macro.hpp"
      21                 :            : #include "RNG.hpp"
      22                 :            : #include "Timer.hpp"
      23                 :            : #include "Options/RNG.hpp"
      24                 :            : #include "TestU01Util.hpp"
      25                 :            : #include "TestStack.hpp"
      26                 :            : #include "TestU01Wrappers.hpp"
      27                 :            : #include "WalkerBuildConfig.hpp"
      28                 :            : 
      29                 :            : namespace rngtest {
      30                 :            : 
      31                 :            : extern TestStack g_testStack;
      32                 :            : 
      33                 :            : //! \brief TestU01 properties used to initialize TestU01 tests.
      34                 :            : //! \details This class is used to abstract away the initialization for TestU01
      35                 :            : //!   statistical tests. Needed because of the move semantics and variadic
      36                 :            : //!   templates, since Charm++ chares do not support these yet. TestU01Props is
      37                 :            : //!   therefore not a chare, but TestU01, initialized with a TestU01Props
      38                 :            : //!   object, is. Note that TestU01Props still needs to be migratable, i.e.,
      39                 :            : //!   defines the pack/unpack operator, as it is an argument to chare TestU01's
      40                 :            : //!   constructor.
      41                 :            : template< class Test,                 //!< Statistical test tag, struct{}
      42                 :            :           class Proxy,                //!< Host proxy type
      43                 :            :           class Result,               //!< Results type
      44                 :            :           Result* (*Creator)(void),   //!< Results creator function pointer type
      45                 :            :           void (*Deleter)(Result *),  //!< Results deleter function pointer type
      46                 :            :           typename... Ts >            //!< Extra test runner argument types
      47                 :            : class TestU01Props {
      48                 :            : 
      49                 :            :   public:
      50                 :            :     //! Test extra arguments type
      51                 :            :     using Xargs = std::tuple< Ts... >;
      52                 :            :     //! Test runner function pointer type
      53                 :            :     using RunFn = std::vector<double> (*)( unif01_Gen*, Result*, const Xargs& );
      54                 :            :     //! TestU01 results type with a custom deleter by TestU01
      55                 :            :     using ResultPtr = TestU01Ptr< Result, Deleter >;
      56                 :            : 
      57                 :            :     //! \brief Default constructor taking no arguments
      58                 :            :     //! \details Required as migratable. Called by Charm++. Initialize what we
      59                 :            :     //!    can.
      60                 :        120 :     explicit TestU01Props() :
      61                 :            :       m_proxy(),
      62                 :            :       m_rng( tk::ctr::RNGType::NO_RNG ),
      63                 :            :       m_names(),
      64                 :            :       m_xargs(),
      65                 :            :       m_gen( nullptr ),
      66                 :        120 :       m_runner( g_testStack.TestU01.runner.get<Test>() ),
      67                 :            :       m_res( ResultPtr(Creator()) ),
      68         [ +  - ]:        120 :       m_time( 0.0 ) {}
      69                 :            : 
      70                 :            :     //! \brief Initializer constructor
      71                 :            :     //! \details None of the state data is const since the this class is
      72                 :            :     //!   designed to be migratable over the network by the Charm++ runtime
      73                 :            :     //!   system.
      74                 :            :     //! \param[in] host Host proxy facilitating call-back to host object chare.
      75                 :            :     //! \param[in] rng Random number generator ID enum to be tested
      76                 :            :     //! \param[in] n Vector of statisical test names (can be more than one
      77                 :            :     //!   associated with a given test, since a test can contain more than one
      78                 :            :     //!   statistical test evaluation, yielding multiple p-values)
      79                 :            :     //! \param[in] gen Raw function pointer to TestU01 statistical test
      80                 :            :     //! \param[in] xargs Extra arguments to test-run
      81                 :        120 :     explicit TestU01Props( Proxy& host,
      82                 :            :                            tk::ctr::RNGType rng,
      83                 :            :                            std::vector< std::string >&& n,
      84                 :            :                            unif01_Gen* gen,
      85                 :            :                            Ts&&... xargs ) :
      86                 :            :       m_proxy( host ),
      87                 :            :       m_rng( rng ),
      88                 :        120 :       m_names( std::move(n) ),
      89                 :            :       m_xargs( std::forward<Ts>(xargs)... ),
      90                 :            :       m_gen( gen ),
      91                 :        120 :       m_runner( g_testStack.TestU01.runner.get<Test>() ),
      92                 :            :       m_res( ResultPtr(Creator()) ),
      93         [ +  - ]:        120 :       m_time( 0.0 ) {}
      94                 :            : 
      95                 :            :     //! Copy assignment
      96                 :        240 :     TestU01Props& operator=( const TestU01Props& x) {
      97                 :        240 :       m_proxy = x.m_proxy;
      98                 :        240 :       m_rng = x.m_rng;
      99                 :        240 :       m_names = x.m_names;
     100                 :        240 :       m_xargs = x.m_xargs;
     101                 :        240 :       m_gen = x.m_gen;
     102                 :        240 :       m_runner = x.m_runner;
     103                 :        240 :       m_res = ResultPtr(Creator());
     104                 :        240 :       m_time = x.m_time;
     105                 :        240 :       return *this;
     106                 :            :     }
     107                 :            : 
     108                 :            :     //! Copy constructor: in terms of copy assignment
     109         [ +  - ]:        240 :     TestU01Props( const TestU01Props& x ) { operator=(x); }
     110                 :            : 
     111                 :            :     //! Move assignment
     112                 :            :     TestU01Props& operator=( TestU01Props&& ) = default;
     113                 :            :     //! Move constructor
     114                 :        360 :     TestU01Props( TestU01Props&& ) = default;
     115                 :            : 
     116                 :            :     /** @name Pack/Unpack: Serialize Term object for Charm++ */
     117                 :            :     ///@{
     118                 :            :     //! Pack/Unpack serialize member function
     119                 :            :     //! \param[in,out] p Charm++'s PUP::er serializer object reference
     120                 :        360 :     void pup( PUP::er& p ) {
     121                 :        360 :       p | m_proxy;
     122                 :        360 :       p | m_rng;
     123                 :        360 :       p | m_names;
     124                 :        360 :       p | m_xargs;
     125         [ +  + ]:        360 :       if (p.isUnpacking()) {
     126                 :        120 :         m_gen = g_testStack.TestU01.generator( m_rng );
     127                 :        120 :         m_runner = g_testStack.TestU01.runner.get< Test >();
     128                 :        120 :         m_res = ResultPtr( Creator() );
     129                 :            :       }
     130                 :        360 :       p | m_time;
     131                 :        360 :     }
     132                 :            :     //! \brief Pack/Unpack serialize operator|
     133                 :            :     //! \param[in,out] p Charm++'s PUP::er serializer object reference
     134                 :            :     //! \param[in,out] c TestU01Props object reference
     135                 :        360 :     friend void operator|( PUP::er& p, TestU01Props& c ) { c.pup(p); }
     136                 :            :     ///@}
     137                 :            : 
     138                 :            :     //! Host proxy accessor
     139                 :            :     //! \return Host proxy
     140                 :        320 :     Proxy& proxy() noexcept { return m_proxy; }
     141                 :            : 
     142                 :            :     //! Number of results/test (i.e., p-values) accessor
     143                 :            :     //! \return Number of p-values this test yields
     144                 :         40 :     std::size_t npval() const { return m_names.size(); }
     145                 :            : 
     146                 :            :     //! Test name(s) accessor
     147                 :            :     //! \return Vector of test names (there can be more than one)
     148                 :         40 :     std::vector< std::string > names() const { return m_names; }
     149                 :            : 
     150                 :            :     //! \brief Run test and return its status as a vector of vector of strings.
     151                 :            :     //! \details The return type could potentially be a more specific type,
     152                 :            :     //!   e.g., a struct with fields RNGType, and a vector of strings for the
     153                 :            :     //!   p-values, and the names. Instead, we return a more generic vector of
     154                 :            :     //!   vector of strings type. This helps keeping the corresponding argument
     155                 :            :     //!   to Battery::evaluate() generic, which may come in handy when other
     156                 :            :     //!   test libraries are added in the future. The return value is thus the
     157                 :            :     //!   following in a vector of vectors:
     158                 :            :     //! - 0: Name(s) of statistics (note that a test may produce more than one
     159                 :            :     //!   statistics and thus p-values)
     160                 :            :     //! - 1: p-value strings: "pass" or "fail, p-value = ..." for all tests run
     161                 :            :     //!   (note that a test may produce more than one statistics and thus
     162                 :            :     //!   p-values)
     163                 :            :     //! - 2: RNG name used to run the test: sub-vector length = 1
     164                 :        120 :     std::vector< std::vector< std::string > > run() {
     165                 :            :       // Run and time statistical test
     166                 :        120 :       tk::Timer timer;
     167         [ +  - ]:        240 :       const auto pvals = m_runner( m_gen, m_res.get(), m_xargs );
     168         [ +  - ]:        120 :       m_time = timer.dsec();
     169                 :            :       // Construct status
     170                 :        120 :       std::vector< std::string > pvalstrs;
     171         [ +  + ]:        300 :       for (std::size_t p=0; p<m_names.size(); ++p) {
     172         [ +  + ]:        180 :         if ( fail(pvals[p]) )
     173 [ +  - ][ +  - ]:          7 :           pvalstrs.emplace_back( "fail, p-value = " + pval( pvals[p] ) );
                 [ +  - ]
     174                 :            :         else
     175         [ +  - ]:        173 :           pvalstrs.emplace_back( "pass" );
     176                 :            :       }
     177 [ +  - ][ +  - ]:        840 :       return { m_names, pvalstrs, { tk::ctr::RNG().name(m_rng) } };
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
         [ +  + ][ -  - ]
                 [ -  - ]
     178                 :            :     }
     179                 :            : 
     180                 :            :     //! Test time accessor
     181                 :            :     //! \return Time it took to run the test with the associated RNG name
     182                 :        120 :     std::pair< std::string, tk::real > time()
     183 [ +  - ][ +  - ]:        240 :     { return { tk::ctr::RNG().name(m_rng), m_time }; }
     184                 :            : 
     185                 :            :   private:
     186                 :            :     //! \brief Pack/Unpack TestU01 external generator pointer
     187                 :            :     //! \details Admittedly, the code below is ugly and looks stupid at first
     188                 :            :     //!   sight. However, this is a translation of runtime information (a
     189                 :            :     //!   user-selected RNG that this statistical test exercises) to
     190                 :            :     //!   compile-time information: associating an RNG id from an enum class,
     191                 :            :     //!   tk::ctr::RNGType::value, to a compile-time constant, underlying_type
     192                 :            :     //!   value, facilitating a different global-scope TestU01 external
     193                 :            :     //!   generator with code reuse. Note that createTestU01Gen() must be
     194                 :            :     //!   global-scope as it is used to create a different external generator to
     195                 :            :     //!   TestU01, depending on the RNG. Templating createTestU01Gen on the id
     196                 :            :     //!   enables the compiler to generate a different wrapper for a different
     197                 :            :     //!   RNG facilitating simultaneous calls to any or all wrappers as they are
     198                 :            :     //!   unique functions.
     199                 :            :     //! \param[in,out] p Charm++'s PUP::er serializer object reference
     200                 :            :     //! \param[in,out] g Reference to raw function pointer to TestU01
     201                 :            :     //!   statistical test
     202                 :            :     void pup( [[maybe_unused]] PUP::er& p, unif01_Gen*& g ) {
     203                 :            :       using tk::ctr::RNGType;
     204                 :            :       using tk::ctr::raw;
     205                 :            :       const auto& rngname = tk::ctr::RNG().name(m_rng);
     206                 :            :       Assert( !rngname.empty(), "Empty RNG name not allowed");
     207                 :            :       Assert( m_rng != RNGType::NO_RNG, "No RNG type not allowed");
     208                 :            :       #ifdef HAS_MKL
     209                 :            :       if (m_rng == RNGType::MKL_MCG31)
     210                 :            :         g = createTestU01Gen< raw(RNGType::MKL_MCG31) >( rngname );
     211                 :            :       else if (m_rng == RNGType::MKL_R250)
     212                 :            :         g = createTestU01Gen< raw(RNGType::MKL_R250) >( rngname );
     213                 :            :       else if (m_rng == RNGType::MKL_MRG32K3A)
     214                 :            :         g = createTestU01Gen< raw(RNGType::MKL_MRG32K3A) >( rngname );
     215                 :            :       else if (m_rng == RNGType::MKL_MCG59)
     216                 :            :         g = createTestU01Gen< raw(RNGType::MKL_MCG59) >( rngname );
     217                 :            :       else if (m_rng == RNGType::MKL_WH) 
     218                 :            :         g = createTestU01Gen< raw(RNGType::MKL_WH) >( rngname );
     219                 :            :       else if (m_rng == RNGType::MKL_MT19937)
     220                 :            :         g = createTestU01Gen< raw(RNGType::MKL_MT19937) >( rngname );
     221                 :            :       else if (m_rng == RNGType::MKL_MT2203)
     222                 :            :         g = createTestU01Gen< raw(RNGType::MKL_MT2203) >( rngname );
     223                 :            :       else if (m_rng == RNGType::MKL_SFMT19937)
     224                 :            :         g = createTestU01Gen< raw(RNGType::MKL_SFMT19937) >( rngname );
     225                 :            :       else if (m_rng == RNGType::MKL_SOBOL)
     226                 :            :         g = createTestU01Gen< raw(RNGType::MKL_SOBOL) >( rngname );
     227                 :            :       else if (m_rng == RNGType::MKL_NIEDERR)
     228                 :            :         g = createTestU01Gen< raw(RNGType::MKL_NIEDERR) >( rngname );
     229                 :            :       //else if (m_rng == RNGType::MKL_IABSTRACT)
     230                 :            :       //  g = createTestU01Gen< raw(RNGType::MKL_IABSTRACT) >( rngname );
     231                 :            :       //else if (m_rng == RNGType::MKL_DABSTRACT)
     232                 :            :       //  g = createTestU01Gen< raw(RNGType::MKL_DABSTRACT) >( rngname );
     233                 :            :       //else if (m_rng == RNGType::MKL_SABSTRACT)
     234                 :            :       //  g = createTestU01Gen< raw(RNGType::MKL_SABSTRACT) >( rngname );
     235                 :            :       else if (m_rng == RNGType::MKL_NONDETERM)
     236                 :            :         g = createTestU01Gen< raw(RNGType::MKL_NONDETERM) >( rngname );
     237                 :            :       else
     238                 :            :       #endif
     239                 :            :       #ifdef HAS_RNGSSE2
     240                 :            :       if (m_rng == RNGType::RNGSSE_GM19)
     241                 :            :         g = createTestU01Gen< raw(RNGType::RNGSSE_GM19) >( rngname );
     242                 :            :       else if (m_rng == RNGType::RNGSSE_GM29)
     243                 :            :         g = createTestU01Gen< raw(RNGType::RNGSSE_GM29) >( rngname );
     244                 :            :       else if (m_rng == RNGType::RNGSSE_GM31)
     245                 :            :         g = createTestU01Gen< raw(RNGType::RNGSSE_GM31) >( rngname );
     246                 :            :       else if (m_rng == RNGType::RNGSSE_GM55)
     247                 :            :         g = createTestU01Gen< raw(RNGType::RNGSSE_GM55) >( rngname );
     248                 :            :       else if (m_rng == RNGType::RNGSSE_GM61)
     249                 :            :         g = createTestU01Gen< raw(RNGType::RNGSSE_GM61) >( rngname );
     250                 :            :       else if (m_rng == RNGType::RNGSSE_GQ581)
     251                 :            :         g = createTestU01Gen< raw(RNGType::RNGSSE_GQ581) >( rngname );
     252                 :            :       else if (m_rng == RNGType::RNGSSE_GQ583)
     253                 :            :         g = createTestU01Gen< raw(RNGType::RNGSSE_GQ583) >( rngname );
     254                 :            :       else if (m_rng == RNGType::RNGSSE_GQ584)
     255                 :            :         g = createTestU01Gen< raw(RNGType::RNGSSE_GQ584) >( rngname );
     256                 :            :       else if (m_rng == RNGType::RNGSSE_MT19937)
     257                 :            :         g = createTestU01Gen< raw(RNGType::RNGSSE_MT19937) >( rngname );
     258                 :            :       else if (m_rng == RNGType::RNGSSE_LFSR113)
     259                 :            :         g = createTestU01Gen< raw(RNGType::RNGSSE_LFSR113) >( rngname );
     260                 :            :       else if (m_rng == RNGType::RNGSSE_MRG32K3A)
     261                 :            :         g = createTestU01Gen< raw(RNGType::RNGSSE_MRG32K3A) >( rngname );
     262                 :            :       else
     263                 :            :       #endif
     264                 :            :       if (m_rng == RNGType::R123_THREEFRY)
     265                 :            :         g = createTestU01Gen< raw(RNGType::R123_THREEFRY) >( rngname );
     266                 :            :       else if (m_rng == RNGType::R123_PHILOX)
     267                 :            :         g = createTestU01Gen< raw(RNGType::R123_PHILOX) >( rngname );
     268                 :            :     }
     269                 :            : 
     270                 :            :     //! Query whether test is failed
     271                 :            :     //! \param[in] val p-value returned from test
     272                 :            :     //! \return true if the RNG has failed the statistical test
     273                 :        180 :     bool fail( double val ) const {
     274 [ +  + ][ +  + ]:        180 :       if ((val <= gofw_Suspectp) || (val >= 1.0-gofw_Suspectp))
     275                 :          7 :         return true;
     276                 :            :       else
     277                 :        173 :         return false;
     278                 :            :     }
     279                 :            : 
     280                 :            :     //! Return human-readable p-value (ala TestU01::bbattery.c::WritePval)
     281                 :            :     //! \param[in] val p-value returned from test
     282                 :            :     //! \return Human-readable p-value (ala TestU01::bbattery.c::WritePval)
     283                 :          7 :     std::string pval( double val ) const {
     284         [ +  - ]:         14 :       std::stringstream ss;
     285         [ +  + ]:          7 :       if (val < gofw_Suspectp) {
     286                 :            : 
     287 [ -  + ][ -  - ]:          4 :         if ((val >= 0.01) && (val <= 0.99))
     288         [ -  - ]:          0 :           ss << val;
     289         [ +  + ]:          4 :         else if (val < gofw_Epsilonp)
     290         [ +  - ]:          3 :           ss << "eps";
     291         [ +  - ]:          1 :         else if (val < 0.01)
     292         [ +  - ]:          1 :           ss << val;
     293         [ -  - ]:          0 :         else if (val >= 1.0 - gofw_Epsilonp1)
     294         [ -  - ]:          0 :           ss << "1 - eps1";
     295         [ -  - ]:          0 :         else if (val < 1.0 - 1.0e-4)
     296         [ -  - ]:          0 :           ss << val;
     297                 :            :         else
     298         [ -  - ]:          0 :           ss << 1.0 - val;
     299                 :            : 
     300         [ +  - ]:          3 :       } else if (val > 1.0 - gofw_Suspectp) {
     301                 :            : 
     302         [ +  + ]:          3 :         if (val >= 1.0 - gofw_Epsilonp1)
     303         [ +  - ]:          2 :           ss << "1 - eps1";
     304         [ -  + ]:          1 :         else if (val >= 1.0 - 1.0e-4)
     305 [ -  - ][ -  - ]:          0 :           ss << "1 - " << 1.0 - val;
     306                 :            :         else
     307         [ +  - ]:          1 :           ss << val;
     308                 :            : 
     309                 :            :       }
     310         [ +  - ]:         14 :       return ss.str();
     311                 :            :     }
     312                 :            : 
     313                 :            :     Proxy m_proxy;                      //!< Host proxy
     314                 :            :     tk::ctr::RNGType m_rng;             //!< RNG id
     315                 :            :     std::vector< std::string > m_names; //!< Name(s) of tests
     316                 :            :     Xargs m_xargs;                      //!< Extra args for run()
     317                 :            :     unif01_Gen* m_gen;                  //!< Pointer to generator
     318                 :            :     RunFn m_runner;                     //!< Test runner function
     319                 :            :     ResultPtr m_res;                    //!< TestU01 results
     320                 :            :     tk::real m_time;                    //!< Test run time measured in seconds
     321                 :            : };
     322                 :            : 
     323                 :            : } // rngtest::
     324                 :            : 
     325                 :            : #endif // TestU01Props_h

Generated by: LCOV version 1.14