diff --git a/src/common/aka_random_generator.hh b/src/common/aka_random_generator.hh index 816173a6a..3fada453f 100644 --- a/src/common/aka_random_generator.hh +++ b/src/common/aka_random_generator.hh @@ -1,261 +1,265 @@ /** * @file aka_random_generator.hh * * @author Nicolas Richart * * @date creation: Thu Feb 21 2013 * @date last modification: Wed Nov 11 2015 * * @brief generic random generator * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_RANDOM_GENERATOR_HH__ #define __AKANTU_AKA_RANDOM_GENERATOR_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* List of available distributions */ /* -------------------------------------------------------------------------- */ // clang-format off #define AKANTU_RANDOM_DISTRIBUTION_TYPES \ ((uniform , std::uniform_real_distribution )) \ ((exponential , std::exponential_distribution )) \ ((gamma , std::gamma_distribution )) \ ((weibull , std::weibull_distribution )) \ ((extreme_value, std::extreme_value_distribution)) \ ((normal , std::normal_distribution )) \ ((lognormal , std::lognormal_distribution )) \ ((chi_squared , std::chi_squared_distribution )) \ ((cauchy , std::cauchy_distribution )) \ ((fisher_f , std::fisher_f_distribution )) \ ((student_t , std::student_t_distribution )) // clang-format on #define AKANTU_RANDOM_DISTRIBUTION_TYPES_PREFIX(elem) BOOST_PP_CAT(_rdt_, elem) #define AKANTU_RANDOM_DISTRIBUTION_PREFIX(s, data, elem) \ AKANTU_RANDOM_DISTRIBUTION_TYPES_PREFIX(BOOST_PP_TUPLE_ELEM(2, 0, elem)) enum RandomDistributionType { BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(AKANTU_RANDOM_DISTRIBUTION_PREFIX, _, AKANTU_RANDOM_DISTRIBUTION_TYPES)), _rdt_not_defined }; /* -------------------------------------------------------------------------- */ /* Generator */ /* -------------------------------------------------------------------------- */ template class RandomGenerator { /* ------------------------------------------------------------------------ */ public: inline T operator()() { return generator(); } /// function to print the contain of the class virtual void printself(std::ostream & stream, int) const { stream << "RandGenerator [seed=" << _seed << "]"; } /* ------------------------------------------------------------------------ */ public: static void seed(long int s) { _seed = s; generator.seed(_seed); } static long int seed() { return _seed; } static constexpr T min() { return generator.min(); } static constexpr T max() { return generator.max(); } /* ------------------------------------------------------------------------ */ private: static long int _seed; static std::default_random_engine generator; }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #undef AKANTU_RANDOM_DISTRIBUTION_PREFIX #define AKANTU_RANDOM_DISTRIBUTION_TYPE_PRINT_CASE(r, data, elem) \ case AKANTU_RANDOM_DISTRIBUTION_TYPES_PREFIX( \ BOOST_PP_TUPLE_ELEM(2, 0, elem)): { \ stream << BOOST_PP_STRINGIZE(AKANTU_RANDOM_DISTRIBUTION_TYPES_PREFIX( \ BOOST_PP_TUPLE_ELEM(2, 0, elem))); \ break; \ } inline std::ostream & operator<<(std::ostream & stream, RandomDistributionType type) { switch (type) { BOOST_PP_SEQ_FOR_EACH(AKANTU_RANDOM_DISTRIBUTION_TYPE_PRINT_CASE, _, AKANTU_RANDOM_DISTRIBUTION_TYPES) default: stream << UInt(type) << " not a RandomDistributionType"; break; } return stream; } #undef AKANTU_RANDOM_DISTRIBUTION_TYPE_PRINT_CASE /* -------------------------------------------------------------------------- */ /* Some Helper */ /* -------------------------------------------------------------------------- */ template class RandomDistributionTypeHelper { enum { value = _rdt_not_defined }; }; /* -------------------------------------------------------------------------- */ #define AKANTU_RANDOM_DISTRIBUTION_TYPE_GET_TYPE(r, data, elem) \ template \ struct RandomDistributionTypeHelper> { \ enum { \ value = AKANTU_RANDOM_DISTRIBUTION_TYPES_PREFIX( \ BOOST_PP_TUPLE_ELEM(2, 0, elem)) \ }; \ + \ + static void printself(std::ostream & stream) { \ + stream << BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(2, 0, elem)); \ + } \ }; BOOST_PP_SEQ_FOR_EACH(AKANTU_RANDOM_DISTRIBUTION_TYPE_GET_TYPE, _, AKANTU_RANDOM_DISTRIBUTION_TYPES) #undef AKANTU_RANDOM_DISTRIBUTION_TYPE_GET_TYPE /* -------------------------------------------------------------------------- */ template class RandomDistribution { public: virtual T operator()(RandomGenerator & gen) = 0; virtual std::unique_ptr> make_unique() const = 0; virtual void printself(std::ostream & stream, int = 0) const = 0; }; template class RandomDistributionProxy : public RandomDistribution { public: explicit RandomDistributionProxy(Distribution dist) : distribution(std::move(dist)) {} T operator()(RandomGenerator & gen) override { return distribution(gen); } std::unique_ptr> make_unique() const override { return std::make_unique>( distribution); } void printself(std::ostream & stream, int = 0) const override { - stream << RandomDistributionTypeHelper::value << " [ " - << distribution << " ]"; + RandomDistributionTypeHelper::printself(stream); + stream << " [ " << distribution << " ]"; } private: Distribution distribution; }; /* -------------------------------------------------------------------------- */ /* RandomParameter */ /* -------------------------------------------------------------------------- */ template class RandomParameter { public: template explicit RandomParameter(T base_value, Distribution dist) : base_value(base_value), type(RandomDistributionType( RandomDistributionTypeHelper::value)), distribution_proxy( std::make_unique>( std::move(dist))) {} explicit RandomParameter(T base_value) : base_value(base_value), type(RandomDistributionType( RandomDistributionTypeHelper< T, std::uniform_real_distribution>::value)), distribution_proxy( std::make_unique< RandomDistributionProxy>>( std::uniform_real_distribution(0., 0.))) {} RandomParameter(const RandomParameter & other) : base_value(other.base_value), type(other.type), distribution_proxy(other.distribution_proxy->make_unique()) {} RandomParameter & operator=(const RandomParameter & other) { distribution_proxy = other.distribution_proxy->make_unique(); base_value = other.base_value; type = other.type; return *this; } inline void setBaseValue(const T & value) { this->base_value = value; } inline T getBaseValue() const { return this->base_value; } template