trick/trick_source/sim_services/MonteCarlo/include/StlRandomGeneratorSub.hh
Alex Lin 14a75508a3 Cleaning up once include variables and copyright cleanup.
Changed all header file once include variables to follow the same naming
convention and not start with any underscores.  Also deleted old
incorrect copyright notices.  Also removed $Id: tags from all files.

Fixes #14.  Fixes #22.
2015-03-23 16:03:14 -05:00

271 lines
9.7 KiB
C++

// NOTE: This file is intended to be included into the StlRandomGenerator.hh header
#ifndef STLRANDOMGENERATORSUB_HH
#define STLRANDOMGENERATORSUB_HH
#ifdef _HAVE_STL_RANDOM
///@brief return the correct param_type loaded with the input values
///
///@details Provides a way for a common input interface to return the correct param_type
/// for all implemented distributions, without the calling code having to hardcode the distribution.
/// (Because multiple hardcodes won't work for templated distributions where the
/// initialization signatures aren't all the same.
///
/// Common signature of static wrapper methods for all implemented 'Distribution' types:
///
/// Distribution::param_type param(Distribution&, double, double=0.0)
///
///
/// This allows user to use a single call: dist.param( ParamWrapper::param(dist, a,b) )
/// and the compiler will choose the correct ParamWrapper method to match dist.param's
/// need for a Distribution::param_type class object, based on the type of the 'dist' input argument.
///
/// (Otherwise, it is difficult to use the param_type system without knowing the
/// distribution type at compile time.)
///
class ParamWrapper {
public:
///@name Parameter wrappers
///@brief These methods return the appropriate param_type per the input distribution (which is otherwise unused).
///@note Implement one per distribution implemented
///@{
static std::uniform_real_distribution<double>::param_type
param(__attribute__((unused)) const std::uniform_real_distribution<double>& dist, double min, double max = 0.0)
{ return std::uniform_real_distribution<double>::param_type(min,max); }
static std::normal_distribution<double>::param_type
param(__attribute__((unused)) const std::normal_distribution<double>& dist, double mean, double std_dev = 0.0)
{ return std::normal_distribution<double>::param_type(mean,std_dev); }
static std::poisson_distribution<STL_POISSON_TEMPLATE_TYPES>::param_type
param(__attribute__((unused)) const std::poisson_distribution<STL_POISSON_TEMPLATE_TYPES>& dist, double mean, __attribute__((unused)) double unused = 0.0)
{ return std::poisson_distribution<STL_POISSON_TEMPLATE_TYPES>::param_type(mean); }
///@}
private:
ParamWrapper();
~ParamWrapper();
};
#endif
#if (defined(_HAVE_TR1_RANDOM) || defined(_HAVE_STL_RANDOM))
///@brief Return the appropriate union bit pattern for each distribution
///@note Implement one for each available distribution type.
class StlReturnWrapper {
public:
#ifdef _HAVE_TR1_RANDOM
static TRICK_GSL_RETURN_TYPE return_value(__attribute__((unused)) const std::uniform_real<double>& dist, double ret_val)
#endif
#ifdef _HAVE_STL_RANDOM
static TRICK_GSL_RETURN_TYPE return_value(__attribute__((unused)) const std::uniform_real_distribution<double>& dist, double ret_val)
#endif
{
TRICK_GSL_RETURN_TYPE output;
output.d = ret_val;
return output;
}
static TRICK_GSL_RETURN_TYPE return_value(__attribute__((unused)) const std::normal_distribution<double>& dist, double ret_val)
{
TRICK_GSL_RETURN_TYPE output;
output.d = ret_val;
return output;
}
static TRICK_GSL_RETURN_TYPE return_value(__attribute__((unused)) const std::poisson_distribution<STL_POISSON_TEMPLATE_TYPES>& dist, int ret_val)
{
TRICK_GSL_RETURN_TYPE output;
output.ii = ret_val;
return output;
}
};
#endif
///@brief Sub class for object that includes a <random> engine and a distribution
///
///@note partial specialization exists for Distribution = std::poisson_distribution<int>
/// because TR1 doesn't implement param_type system, thus has no way to generally
/// init the class! (No way to use a common 2 parameter interface and ignore the
/// second parameter for single parameter param_type distributions.)
///
///@note The partial specialization is NOT required when c++0x support is dropped.
///
/// Also, TR1 Distributions can not have their parameters changed after construction.
/// This results in the need for template full method specialization to provide the type specific init.
///
template <class Engine, class Distribution>
class StlRandomGeneratorSub : public StlRandomGenerator
{
public:
#ifdef _HAVE_STD_RANDOM // (Concept doesn't exist in TR1)
typedef typename Distribution::param_type ParamType;
#endif
///@note The input in_engine_type and in_dist_type must match the template parameters.
/// This is intended to be assured by using StlRandomGeneratorFactory for construction.
///
explicit StlRandomGeneratorSub(
double in_param_a = 0.0,
double in_param_b = 1.0,
unsigned long in_seed = 12345,
StlRandomGenerator::StlDistribution in_dist_type = FLAT,
StlRandomGenerator::StlEngine in_engine_type = TRICK_DEFAULT_ENGINE
)
: StlRandomGenerator(in_param_a, in_param_b, in_seed, in_dist_type, in_engine_type),
engine(in_seed)
{
// (Note: distribution member can't be input initialized in the initializer list
// because various distributions have different signatures.
//
// NOTE: For the TR1 implementation, The set_param method
// _re-constructs_ the object with the desired parameters.
// (TR1 Distributions can only be initialized at construction time.)
//
set_param(in_param_a, in_param_b);
}
virtual ~StlRandomGeneratorSub() { }
///@brief return next pseudo-random number
virtual TRICK_GSL_RETURN_TYPE operator()()
{
#if (defined(_HAVE_TR1_RANDOM) || defined(_HAVE_STL_RANDOM))
return StlReturnWrapper::return_value(distribution, distribution(engine));
#else
// without either, won't ever be called. But to compile, return zero.
TRICK_GSL_RETURN_TYPE output;
output.d = 0.0;
return output;
#endif
}
///@brief reset seed for underlying uniform pseudo-random number generator
virtual void set_seed(unsigned long in_seed)
{
initialSeed = in_seed;
engine.seed(initialSeed);
}
///@brief reset parameters for the distribution
///
///@param a is min for FLAT, mean for GAUSSION and POISSON
///@param b is max for FLAT, sigma for GAUSSION and unused for POISSON
///
///@note For the TR1 implementation, The set_param method
/// _re-constructs_ the object with the desired parameters.
///
/// (C++11 allows changing the parameters on the fly.)
///
virtual void set_param(double a, double b = 0.0)
{
param_a = a;
param_b = b;
#ifdef _HAVE_STL_RANDOM
// (this param_type interface is not provided in TR1)
distribution.param( ParamWrapper::param(distribution, a,b) );
#else
// TR1 implementation must use this hokey
// full template specialization solution.
tr1_init_distribution(a, b);
#endif
}
protected:
Engine engine; /**< -- STL random number engine object */
Distribution distribution; /**< -- STL random number distribution object */
private:
#ifdef _HAVE_TR1_RANDOM
///@brief For TR1, replace the default initialized distribution with a new one.
///
///@details because TR1 only allows initialization of Distribution parameters at
/// construction time (C++11 provides the param_type system for doing this post-construction),
/// this method with full template specializations is used to get around this
/// lack of generality for the few so-far implemented distribution options.
///
/// Once C++11 is required, these can be removed and the simpler C++11 set_param
/// method used for all.
///
void tr1_init_distribution(double a, double b)
{
// All two parameter signature distributions can use this method.
// Deviant sets must implement a full template specialization for this method.
distribution = Distribution(a, b);
}
#endif
};
#ifdef _HAVE_TR1_RANDOM
// implement one of these template FULL specializations
// for each implemented TR1 StlRandomGenerator::StlEngine enums
//
// So far, only the Poisson distribution requires a single parameter,
// causing the issue.
/*
// these engines are no longer allowed for TR1 (caused infinite loops in normal_distribution)
template<>
inline
void
StlRandomGeneratorSub<std::minstd_rand,
std::poisson_distribution<STL_POISSON_TEMPLATE_TYPES>
>::tr1_init_distribution(double a, double __attribute__((unused)) b)
{
distribution = std::poisson_distribution<STL_POISSON_TEMPLATE_TYPES>(a);
}
template<>
inline
void
StlRandomGeneratorSub<std::mt19937,
std::poisson_distribution<STL_POISSON_TEMPLATE_TYPES>
>::tr1_init_distribution(double a, double __attribute__((unused)) b)
{
distribution = std::poisson_distribution<STL_POISSON_TEMPLATE_TYPES>(a);
}
*/
template<>
inline
void
StlRandomGeneratorSub<std::ranlux_base_01,
std::poisson_distribution<STL_POISSON_TEMPLATE_TYPES>
>::tr1_init_distribution(double a, double __attribute__((unused)) b)
{
distribution = std::poisson_distribution<STL_POISSON_TEMPLATE_TYPES>(a);
}
template<>
inline
void
StlRandomGeneratorSub<std::ranlux64_base_01,
std::poisson_distribution<STL_POISSON_TEMPLATE_TYPES>
>::tr1_init_distribution(double a, double __attribute__((unused)) b)
{
distribution = std::poisson_distribution<STL_POISSON_TEMPLATE_TYPES>(a);
}
#endif
#endif