source: src/RandomNumbers/RandomNumberGeneratorFactory.cpp@ 3f9eba

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 3f9eba was 3f9eba, checked in by Frederik Heber <heber@…>, 15 years ago

New classes for random number generation.

  • we use boost::random as a basis. It implements a lot of pseudo-random engines and various distributions. However, everything is templated and there are no base classes to store prototypes of the instances in a map. We need these such that we are able to offer the user at run-time every choice possible.
  • Hence, we need to encapsulate all engines, distributions and (engine, distribution) tuples: RandomNumber..._Encapsulation classes.
  • each with an abstract base class as the interface: RandomNumber... classes.
  • RandomNumberGeneratorFactory is then a singleton that contains all the Maps and tables:
    • from string (user input is string) to enum (storing enum is more efficient that a lengthy string)
    • from enum to instance (of the abstract class).
  • RandomNumberGeneratorFactory is a singleton to allow for global control of what kind of numbers are generated, hence there are also two new Actions:
  • The user in the end only uses two classes: RandomNumberGeneratorFactory and RandomNumberGenerator. The first only for obtaining a specific variant of the latter and the latter to generate the numbers (operator() is passed on to boost::variate_generator::operator()).
  • There is a unit test on the RandomNumberGeneratorFactory that checks some of the table entries and whether one of the RandomNumberGenerator is working (uniform_smallint so far).

Details:

  • As there are ~25 engines and ~15 distributions this makes an enormous amount of possible combinations. To automatically construct these, we use some stuff from boost::preprocessor in order to generate enums, tables and maps automatically just from a sequence of the typenames.
  • we have be-friended the unit test a lot to allow for easier testing, e.g. we need access to internal ..._type to test whether their type is correct.
  • cleanUp() purges the instance of RandomNumberGeneratorFactory.
  • in RandomNumber..._Encapsulation::name() functions are only used for the unit tests.
  • this all resides in its own subfolder RandomNumbers. So far, it is completely independent of everything else.
  • Property mode set to 100644
File size: 8.4 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/*
9 * RandomNumberGeneratorFactory.cpp
10 *
11 * Created on: Dec 31, 2010
12 * Author: heber
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include "CodePatterns/MemDebug.hpp"
21
22#include <utility>
23#include "CodePatterns/Singleton_impl.hpp"
24#include "CodePatterns/Assert.hpp"
25
26#include "TemplatePowerSetGenerator.hpp"
27
28#include "RandomNumberEngine_Encapsulation.hpp"
29#include "RandomNumberDistribution_Encapsulation.hpp"
30#include "RandomNumberGenerator_Encapsulation.hpp"
31
32#include <boost/preprocessor/facilities/empty.hpp>
33#include <boost/preprocessor/punctuation/paren.hpp>
34
35#include "RandomNumberGeneratorFactory.hpp"
36#include "RandomNumberGeneratorFactory.def"
37
38enum RandomNumberGeneratorFactory::Engine RandomNumberGeneratorFactory::engine = (enum RandomNumberGeneratorFactory::Engine) 0;
39enum RandomNumberGeneratorFactory::Distribution RandomNumberGeneratorFactory::distribution = (enum RandomNumberGeneratorFactory::Distribution) 0;
40RandomNumberGeneratorFactory::EngineMap RandomNumberGeneratorFactory::engines;
41RandomNumberGeneratorFactory::EngineNamesMap RandomNumberGeneratorFactory::engineNames;
42RandomNumberGeneratorFactory::DistributionMap RandomNumberGeneratorFactory::distributions;
43RandomNumberGeneratorFactory::DistributionNamesMap RandomNumberGeneratorFactory::distributionNames;
44RandomNumberGeneratorFactory::EngineTable RandomNumberGeneratorFactory::EnginePrototypeTable;
45RandomNumberGeneratorFactory::DistributionTable RandomNumberGeneratorFactory::DistributionPrototypeTable;
46RandomNumberGeneratorFactory::EngineDistributionTable RandomNumberGeneratorFactory::GeneratorPrototypeTable;
47
48
49RandomNumberGeneratorFactory::RandomNumberGeneratorFactory()
50{
51 // insert all known engines
52#define BOOST_PP_LOCAL_MACRO(n) seqitems_as_string_enum_map(~, n, engine_seq, engines)
53#define BOOST_PP_LOCAL_LIMITS (0, BOOST_PP_SEQ_SIZE(engine_seq)-1 )
54#include BOOST_PP_LOCAL_ITERATE()
55#define BOOST_PP_LOCAL_MACRO(n) seqitems_as_string_enum_map(~, n, engine_seq_a, engines)
56#define BOOST_PP_LOCAL_LIMITS (0, BOOST_PP_SEQ_SIZE(engine_seq_a)-1 )
57#include BOOST_PP_LOCAL_ITERATE()
58 for (EngineMap::const_iterator iter = engines.begin();
59 iter != engines.end();
60 ++iter) {
61 engineNames.insert(make_pair(iter->second, iter->first));
62 }
63
64 // insert all known distributions
65#define BOOST_PP_LOCAL_MACRO(n) seqitems_as_string_enum_map(~, n, distribution_seq, distributions)
66#define BOOST_PP_LOCAL_LIMITS (0, BOOST_PP_SEQ_SIZE(distribution_seq)-1 )
67#include BOOST_PP_LOCAL_ITERATE()
68 for (DistributionMap::const_iterator iter = distributions.begin();
69 iter != distributions.end();
70 ++iter) {
71 distributionNames.insert(make_pair(iter->second, iter->first));
72 }
73
74 FillPrototypeTables();
75}
76
77/** Removes all pointers to instances from a table while free'ing memory.
78 *
79 * I.e. we assume class T to be a map of some key with its values pointers to
80 * some classes that have to be free'd.
81 *
82 * \param _PrototypeTable table to empty
83 */
84template <class T>
85void EmptyPrototypeTable(T &_PrototypeTable)
86{
87 for (typename T::iterator iter = _PrototypeTable.begin();
88 !_PrototypeTable.empty();
89 iter = _PrototypeTable.begin()) {
90 delete (iter->second);
91 _PrototypeTable.erase(iter);
92 }
93 _PrototypeTable.clear();
94}
95
96
97
98RandomNumberGeneratorFactory::~RandomNumberGeneratorFactory()
99{
100 // clear out factories map to allow boost::shared_ptr to do their work (i.e. to release mem)
101 // this is necessary as factories is a object
102 engines.clear();
103 engineNames.clear();
104 EmptyPrototypeTable<EngineTable> (EnginePrototypeTable);
105 distributions.clear();
106 distributionNames.clear();
107 EmptyPrototypeTable<DistributionTable> (DistributionPrototypeTable);
108 for (EngineDistributionTable::iterator iter = GeneratorPrototypeTable.begin();
109 !GeneratorPrototypeTable.empty();
110 iter = GeneratorPrototypeTable.begin()) {
111 EmptyPrototypeTable< std::map<enum Distribution,RandomNumberGenerator *> > (iter->second);
112 GeneratorPrototypeTable.erase(iter);
113 }
114 GeneratorPrototypeTable.clear();
115}
116
117void RandomNumberGeneratorFactory::FillPrototypeTables()
118{
119 // fill EnginePrototypeTable
120#define BOOST_PP_LOCAL_MACRO(n) seqitems_as_enum_key_map(~, n, engine_seq, EnginePrototypeTable, new RandomNumberEngine_Encapsulation, boost::, )
121#define BOOST_PP_LOCAL_LIMITS (0, BOOST_PP_SEQ_SIZE(engine_seq)-1 )
122#include BOOST_PP_LOCAL_ITERATE()
123#define BOOST_PP_LOCAL_MACRO(n) seqitems_as_enum_key_map(~, n, engine_seq_a, EnginePrototypeTable, new RandomNumberEngine_Encapsulation, boost::, )
124#define BOOST_PP_LOCAL_LIMITS (0, BOOST_PP_SEQ_SIZE(engine_seq_a)-1 )
125#include BOOST_PP_LOCAL_ITERATE()
126
127 // fill DistributionPrototypeTable
128#define BOOST_PP_LOCAL_MACRO(n) seqitems_as_enum_key_map(~, n, distribution_seq, DistributionPrototypeTable, new RandomNumberDistribution_Encapsulation, boost::, <>)
129#define BOOST_PP_LOCAL_LIMITS (0, BOOST_PP_SEQ_SIZE(distribution_seq)-1 )
130#include BOOST_PP_LOCAL_ITERATE()
131
132 // fill GeneratorPrototypeTable
133#define DoubleElementSequenceElementizer(z,data,elem) ((data)(elem))
134
135#define seqseqiterate(z,n,seq) BOOST_PP_SEQ_FOR_EACH(DoubleElementSequenceElementizer, BOOST_PP_SEQ_ELEM(n,seq), distribution_seq)
136
137#define distributionengine_seqseq BOOST_PP_REPEAT( \
138 BOOST_PP_SEQ_SIZE(engine_seq), seqseqiterate, engine_seq )
139
140#define distributionengine_seqseq_a BOOST_PP_REPEAT( \
141 BOOST_PP_SEQ_SIZE(engine_seq_a), seqseqiterate, engine_seq_a )
142
143#define suffixseq ()(<>)
144#define tableseq (*EnginePrototypeTable)(*DistributionPrototypeTable)
145
146#define TableItemPrinter(z,n,sequence) \
147 BOOST_PP_COMMA_IF(n) \
148 boost:: \
149 BOOST_PP_SEQ_ELEM(n,sequence) \
150 BOOST_PP_SEQ_ELEM(n,suffixseq)
151
152#define ParamItemPrinter(z,n,sequence) \
153 BOOST_PP_COMMA_IF(n) \
154 BOOST_PP_SEQ_ELEM(n,tableseq) \
155 [ \
156 BOOST_PP_SEQ_ELEM(n,sequence) \
157 ]
158
159#define BOOST_PP_LOCAL_MACRO(n) seqitems_as_enum_key_multidimmap(~, n, distributionengine_seqseq, GeneratorPrototypeTable, new RandomNumberGenerator_Encapsulation, TableItemPrinter, ParamItemPrinter)
160#define BOOST_PP_LOCAL_LIMITS (0, BOOST_PP_SEQ_SIZE(distributionengine_seqseq)-1 )
161#include BOOST_PP_LOCAL_ITERATE()
162
163#define BOOST_PP_LOCAL_MACRO(n) seqitems_as_enum_key_multidimmap(~, n, distributionengine_seqseq_a, GeneratorPrototypeTable, new RandomNumberGenerator_Encapsulation, TableItemPrinter, ParamItemPrinter)
164#define BOOST_PP_LOCAL_LIMITS (0, BOOST_PP_SEQ_SIZE(distributionengine_seqseq_a)-1 )
165#include BOOST_PP_LOCAL_ITERATE()
166}
167
168RandomNumberGenerator& RandomNumberGeneratorFactory::makeRandomNumberGenerator() const
169{
170 // Instantiate and return (implicitly creates a copy of the stored prototype)
171 return *GeneratorPrototypeTable[engine][distribution];
172}
173
174RandomNumberGenerator& RandomNumberGeneratorFactory::makeRandomNumberGenerator(std::string engine_type, std::string distribution_type) const
175{
176 enum Engine eng_type;
177 enum Distribution dis_type;
178
179 // Instantiate and return (implicitly creates a copy of the stored prototype)
180 if (!engine_type.empty()) {
181 ASSERT(engines.count(engine_type) != 0,
182 "RandomNumberGeneratorFactory::makeRandomNumberGenerator() - Selected engine "+engine_type+"is not registered.");
183 eng_type = engines[engine_type];
184 } else
185 eng_type = engine;
186 if (!distribution_type.empty()) {
187 ASSERT(distributions.count(distribution_type) != 0,
188 "RandomNumberGeneratorFactory::makeRandomNumberGenerator() - Selected distribution "+distribution_type+"is not registered.");
189 dis_type = distributions[distribution_type];
190 } else
191 dis_type = distribution;
192 return *GeneratorPrototypeTable[ eng_type ][ dis_type ];
193}
194
195void RandomNumberGeneratorFactory::setEngine(std::string engine_type)
196{
197 ASSERT(engines.count(engine_type) != 0,"Selected engine "+engine_type+"is not registered.");
198 engine = engines[engine_type];
199}
200
201const std::string &RandomNumberGeneratorFactory::getEngine() const
202{
203 return engineNames[engine];
204}
205
206void RandomNumberGeneratorFactory::setDistribution(std::string distribution_type)
207{
208 ASSERT(distributions.count(distribution_type) != 0 ,"Selected distribution "+distribution_type+"is not registered.");
209 distribution = distributions[distribution_type];
210}
211
212const std::string &RandomNumberGeneratorFactory::getDistribution() const
213{
214 return distributionNames[distribution];
215}
216
217CONSTRUCT_SINGLETON(RandomNumberGeneratorFactory)
218
219#include "RandomNumberGeneratorFactory.undef"
220
Note: See TracBrowser for help on using the repository browser.