1 /*
2  *  random_manager.h
3  *
4  *  This file is part of NEST.
5  *
6  *  Copyright (C) 2004 The NEST Initiative
7  *
8  *  NEST is free software: you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation, either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  NEST is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with NEST.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #ifndef RANDOM_MANAGER_H
24 #define RANDOM_MANAGER_H
25 
26 // Generated includes:
27 #include "config.h"
28 
29 // C++ includes:
30 #include <string>
31 #include <vector>
32 
33 // Includes from libnestutil:
34 #include "manager_interface.h"
35 
36 // Includes from nestkernel:
37 #include "dictdatum.h"
38 #include "nest_types.h"
39 #include "random_generators.h"
40 
41 namespace nest
42 {
43 
44 /**
45  * Manage the kernel's random number generators.
46  *
47  * This manager provides one random number generator per thread plus
48  * the global RNG. It also handles selection of RNG type and seeding.
49  */
50 class RandomManager : public ManagerInterface
51 {
52 public:
53   RandomManager();
54   ~RandomManager();
55 
56   /**
57    * Register available RNG types, set default RNG type and create RNGs.
58    */
59   virtual void initialize();
60   virtual void finalize();
61 
62   virtual void set_status( const DictionaryDatum& );
63   virtual void get_status( DictionaryDatum& );
64 
65   /**
66    * Get rank-synchronized random number generator.
67    *
68    * The rank-synchronized generator provides identical random number
69    * sequences on all MPI ranks. It may be used only by the master thread
70    * on each rank and must be used in lock-step across all ranks. Synchronization
71    * is checked by MPI exchange at certain points during a simulation.
72    **/
73   RngPtr get_rank_synced_rng() const;
74 
75   /**
76    * Get VP-synchronized random number generator.
77    *
78    * The kernel maintains one instance of a synchronized random number generator
79    * for each thread (and thus, across ranks, for each VP). The purpose of these
80    * synchronized generators is to provide identical random number sequences on
81    * each VP while VPs execute in parallel. All VPs (ie all threads on all ranks)
82    * must use the generators in lock-step to maintain synchrony. Synchronization
83    * is checked by MPI exchange at certain points during a simulation.
84    *
85    * @param tid ID of thread requesting generator
86    **/
87   RngPtr get_vp_synced_rng( thread tid ) const;
88 
89   /**
90    * Get VP-specific random number generator.
91    *
92    * Each VP (thread) can use this RNG freely and will receive an independent
93    * random number sequence.
94    */
95   RngPtr get_vp_specific_rng( thread tid ) const;
96 
97   /**
98    * Confirm that rank- and thread-synchronized RNGs are in sync.
99    *
100    * @throws KernelException if RNGs are out of sync.
101    */
102   void check_rng_synchrony() const;
103 
104   /**
105    * Register new random number generator type with manager.
106    *
107    * This allows NEST modules to add new RNG types.
108    *
109    * @param RNG_TYPE Class fulfilling requirements of C++ RNG.
110    **/
111   template < typename RNG_TYPE >
112   void register_rng_type( std::string name );
113 
114 private:
115   /** Available RNG types. */
116   std::map< std::string, BaseRandomGeneratorFactory* > rng_types_;
117 
118   /** Name of currently used RNG type. */
119   std::string current_rng_type_;
120 
121   /** Base seed used when RNGs were last created. */
122   std::uint32_t base_seed_;
123 
124   /** Random number generator synchronized across ranks. */
125   RngPtr rank_synced_rng_;
126 
127   /** Random number generators synchronized across VPs. */
128   std::vector< RngPtr > vp_synced_rngs_;
129 
130   /** Random number generators specific to VPs. */
131   std::vector< RngPtr > vp_specific_rngs_;
132 
133   /**
134    * Replace current RNGs with newly seeded generators.
135    *
136    * The new generators will be of type `current_rng_type_` and will be
137    * seeded using `base_seed_`.
138    **/
139   void reset_rngs_();
140 
141   /** RNG type used by default. */
142   static const std::string DEFAULT_RNG_TYPE_;
143 
144   /** Base seed used by default. */
145   static const std::uint32_t DEFAULT_BASE_SEED_;
146 
147   /** Rank-synchronized seed-sequence initializer component. */
148   static const std::uint32_t RANK_SYNCED_SEEDER_;
149 
150   /** Thread-synchronized seed-sequence initializer component. */
151   static const std::uint32_t THREAD_SYNCED_SEEDER_;
152 
153   /** Thread-specific seed-sequence initializer component. */
154   static const std::uint32_t THREAD_SPECIFIC_SEEDER_;
155 };
156 
157 inline RngPtr
get_rank_synced_rng()158 nest::RandomManager::get_rank_synced_rng() const
159 {
160   return rank_synced_rng_;
161 }
162 
163 inline RngPtr
get_vp_synced_rng(thread tid)164 nest::RandomManager::get_vp_synced_rng( thread tid ) const
165 {
166   assert( tid >= 0 );
167   assert( tid < static_cast< thread >( vp_specific_rngs_.size() ) );
168   return vp_synced_rngs_[ tid ];
169 }
170 
171 inline RngPtr
get_vp_specific_rng(thread tid)172 nest::RandomManager::get_vp_specific_rng( thread tid ) const
173 {
174   assert( tid >= 0 );
175   assert( tid < static_cast< thread >( vp_specific_rngs_.size() ) );
176   return vp_specific_rngs_[ tid ];
177 }
178 
179 } // namespace nest
180 
181 #endif /* RANDOM_MANAGER_H */
182