RandomSeedPolicyBase.h
Go to the documentation of this file.
1 /**
2  * @file RandomSeedPolicyBase.h
3  * @brief Defines an interface for random seed assignment policies
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date 20150211
6  * @see SeedMaster.h
7  *
8  * No code in this files is directly serviceable.
9  * Documentation is up to date though.
10  *
11  * Also a few additional feature extensions are implemented here.
12  */
13 
14 #ifndef NUTOOLS_RANDOMUTILS_PROVIDERS_RANDOMSEEDPOLICYBASE_H
15 #define NUTOOLS_RANDOMUTILS_PROVIDERS_RANDOMSEEDPOLICYBASE_H 1
16 
17 // C/C++ standard libraries
18 #include <vector>
19 #include <array>
20 #include <string>
21 #include <bitset>
22 #include <algorithm> // std::find()
23 #include <sstream>
24 #include <ostream> // std::endl
25 
26 // From art and its tool chain
28 #include "fhiclcpp/ParameterSet.h"
29 
30 // Art include files
32 
33 // Some helper classes
34 #include "nutools/RandomUtils/Providers/EngineId.h"
35 #include "nutools/RandomUtils/Providers/EventSeedInputData.h"
36 
37 
38 namespace rndm {
39 
40  namespace details {
41 
42  //--------------------------------------------------------------------------
43  /// Class storing a seed in the valid range
44  template <typename SEED>
45  class ValidSeed {
46  public:
47  using seed_t = SEED; ///< type of random seed
48 
49  static constexpr seed_t Min = 1; ///< Smallest allowed seed
50  static constexpr seed_t Max = 900000000; ///< Largest allowed seed
51 
52  /// Forces the specified value into the allowed seed range
53  template <typename T>
54  static constexpr seed_t MakeValid(T s)
55  { return BounceUp(Min + seed_t(s) % (Max - Min + 1), Min, Max); }
56 
57  /// Returns whether the specified seed is valid
58  template <typename T>
59  static constexpr bool isValid(T s) { return (s >= Min) && (s <= Max); }
60 
61 
62  /// Constructor: converts from a value
63  template <typename T>
65 
66  ValidSeed(const ValidSeed&) = delete;
67  ValidSeed(ValidSeed&&) = default;
68  ValidSeed& operator= (const ValidSeed&) = delete;
69  ValidSeed& operator= (ValidSeed&&) = default;
70 
71  /// Return the converted seeda
72  operator seed_t() const { return seed; }
73 
74  protected:
75  seed_t seed; ///< the converted seed
76 
77  private:
78  /// May be merged into MakeValid() with C++14
79  template <typename T>
80  static constexpr seed_t BounceUp(T s, T min, T max)
81  { return (s < min)? s + (max - min + 1): s; }
82 
83  }; // class ValidSeed
84 
85  //--------------------------------------------------------------------------
86  /// Interface for a policy implementation
87  template <typename SEED>
88  class RandomSeedPolicyBase {
89  public:
90  using seed_t = SEED; ///< type of the random seed
91 
92  /// type of data used for event seeds
94 
95  /// An invalid seed
96  static constexpr seed_t InvalidSeed = 0;
97 
98  /// Constructor; requires the policy name
100  name(policy_name) {}
101 
102  // Virtual destructor
104 
105  /// Configure this policy
106  virtual void configure(fhicl::ParameterSet const&) {}
107 
108  /// Returns the next random number
110  { return createSeed(id); }
111 
112  /// Returns a random number specific to an event
113  virtual seed_t getEventSeed
114  (SeedMasterHelper::EngineId const& id, EventData_t const& eventInfo)
115  { return createEventSeed(id, eventInfo); }
116 
117  /// Returns the given name of the policy
118  std::string getName() const { return name; }
119 
120  /// Prints information on the configuration of this policy
121  virtual void print(std::ostream& out) const
122  { out << "Random policy: '" << getName() << "'"; }
123 
124  /// Returns whether the returned seed should be unique
125  virtual bool yieldsUniqueSeeds() const { return true; }
126 
127  protected:
128  std::string name; ///< name of the policy
129 
130  /// Extracts the next random number seed
131  virtual seed_t createSeed(SeedMasterHelper::EngineId const&) = 0;
132 
133  /// Extracts a seed for specified event information; returns InvalidSeed
134  virtual seed_t createEventSeed
136  { return InvalidSeed; }
137 
138  }; // class RandomSeedPolicyBase
139 
140 
141 
142  /// Helper class to support range checking
143  template <typename SEED>
144  class RangeCheckHelper {
145  public:
146  using seed_t = SEED;
147 
148  /// Constructor; specify configuration labels
150  std::string maxSeedsLabel = "maxUniqueEngines",
151  std::string baseSeedLabel = "baseSeed",
152  std::string checkRangeLabel = "checkRange"
153  )
154  { SetConfigLabels(maxSeedsLabel, baseSeedLabel, checkRangeLabel); }
155 
156 
157  void SetConfigLabels(
158  std::string maxSeedsLabel = "maxUniqueEngines",
159  std::string baseSeedLabel = "baseSeed",
160  std::string checkRangeLabel = "checkRange"
161  );
162 
163  /// Configures from a parameter set
164  /// @return if the configuration after the call is complete
165  bool configure(fhicl::ParameterSet const& pset);
166 
167 
168  /// Sets whether to perform the check or not
169  void SetCheck(bool doCheck = true)
170  { bCheck = doCheck; hasParameters.set(pmDoCheck); }
171 
172  /// Sets the base seed directly
173  void SetBaseSeed(seed_t base_seed)
174  { BaseSeed = base_seed; hasParameters.set(pmBaseSeed); }
175 
176  /// Sets the number of seeds directly
177  void SetNSeeds(seed_t nSeeds)
178  { MaxSeeds = nSeeds; hasParameters.set(pmMaxSeeds); }
179 
180  /// Performs the check on the specified seed
181  bool operator() (seed_t seed) const
182  {
183  return
184  !bCheck || ((seed >= BaseSeed) && (seed < BaseSeed + MaxSeeds));
185  } // operator()
186 
187  /// Throws an exception if the range check on seed fails
188  void EnsureRange
190  const;
191 
192  /// Returns whether all the parameters are configured
193  bool isConfigured() const;
194 
195  /// Returns the items currently not configured
196  std::vector<std::string> missingConfig() const;
197 
198  /// Prints the configuration int the specified stream
199  template <typename STREAM>
200  void print(STREAM& out, std::string indent = std::string()) const;
201 
202  protected:
203  typedef enum {
204  pmMaxSeeds,
205  pmBaseSeed,
206  pmDoCheck,
207  pmNParams
208  } Params_t;
209  static constexpr unsigned int NParams = (unsigned int) pmNParams;
210 
211  std::array<std::string, NParams> paramLabels;
212  std::bitset<NParams> hasParameters;
213 
214  bool bCheck = true; ///< should we perform the check?
215  seed_t BaseSeed; ///< minimum valid seed
216  seed_t MaxSeeds; ///< number of valid seeds
217 
218  }; // class RangeCheckHelper
219 
220 
221  template <typename SEED>
223  std::string maxSeedsLabel /* = "maxUniqueEngines" */,
224  std::string baseSeedLabel /* = "baseSeed" */,
225  std::string checkRangeLabel /* = "checkRange" */
226  ) {
227  paramLabels[pmMaxSeeds] = maxSeedsLabel;
228  paramLabels[pmBaseSeed] = baseSeedLabel;
229  paramLabels[pmDoCheck] = checkRangeLabel;
230  } // RangeCheckHelper::SetConfigLabels()
231 
232 
233  template <typename SEED>
235  if (!paramLabels[pmMaxSeeds].empty()) {
236  seed_t seed;
237  if (pset.get_if_present(paramLabels[pmMaxSeeds], seed)) SetNSeeds(seed);
238  }
239  if (!paramLabels[pmBaseSeed].empty()) {
240  seed_t seed;
241  if (pset.get_if_present(paramLabels[pmBaseSeed], seed))
242  SetBaseSeed(seed);
243  }
244  if (!paramLabels[pmDoCheck].empty()) {
245  bool flag;
246  if (pset.get_if_present(paramLabels[pmDoCheck], flag)) SetCheck(flag);
247  }
248  return isConfigured();
249  } // RangeCheckHelper<SEED>::configure()
250 
251 
252  template <typename SEED>
254  return (hasParameters.test(pmDoCheck) && !bCheck) || hasParameters.all();
255  } // RangeCheckHelper<SEED>::isConfigured()
256 
257 
258  template <typename SEED>
260  std::string policy,
262  ) const {
263  if (operator()(seed)) return;
264  seed_t offset = seed - BaseSeed;
266  << "NuRandomService (policy: " << policy << ") for engine: "
267  << id << " the offset of seed " << seed << " is: " << offset << "."
268  "\nAllowed seed offsets are in the range 0....(N-1) where N is: "
269  << MaxSeeds << " (as configured in maxUniqueEngines)";
270  } // RangeCheckHelper<SEED>::EnsureRange()
271 
272 
273  template <typename SEED> template <typename STREAM>
275  (STREAM& out, std::string indent /* = "" */) const
276  {
277  if (!isConfigured())
278  out << indent << "seed range checker not configured!";
279  else if (bCheck)
280  out << indent << "maximum number of seeds: " << MaxSeeds;
281  else
282  out << indent << "no limit on number of seeds.";
283  } // RangeCheckHelper<SEED>::print()
284 
285 
286  template <typename SEED>
287  std::vector<std::string> RangeCheckHelper<SEED>::missingConfig() const {
288  if (hasParameters.test(pmDoCheck) && !bCheck) return {};
289  std::vector<std::string> missing;
290  for (unsigned int i = 0; i < NParams; ++i)
291  if (!hasParameters.test(i)) missing.push_back(paramLabels[i]);
292  return missing;
293  } // RangeCheckHelper<SEED>::missingConfig()
294 
295 
296 
297  /// Range-checked policy (abstract)
298  template <typename SEED>
299  class CheckedRangePolicy: public RandomSeedPolicyBase<SEED> {
300  public:
303  using seed_t = typename base_t::seed_t;
304 
305  /// Constructor; requires the policy name
307  (std::string policy_name, fhicl::ParameterSet const& pset):
308  base_t(policy_name)
309  { this_t::configure(pset); }
310 
311  /**
312  * @brief Configure this policy
313  * @param pset the parameter set for the configuration
314  *
315  * Parameters:
316  * - *baseSeed* (unsigned integer): the first seed to be delivered
317  * - *checkRange* (boolean, default: true): whether to verify that each
318  * seed is within the expected range
319  * - *maxUniqueEngines* (unsigned integer, mandatory if /checkRange/ is
320  * true) the maximum number on seeds we expect to create
321  */
322  virtual void configure(fhicl::ParameterSet const& pset) override
323  { base_t::configure(pset); static_configure(pset); }
324 
325  /// Returns the next random number
326  virtual seed_t getSeed(SeedMasterHelper::EngineId const& id) override
327  {
328  seed_t seed = this->createSeed(id);
329  ensureRange(id, seed);
330  return seed;
331  } // getSeed()
332 
333  /// Prints information on the configuration of this policy
334  virtual void print(std::ostream& out) const override
335  {
336  base_t::print(out);
337  range_check.print(out << "\n", " ");
338  } // print()
339 
340  protected:
341  RangeCheckHelper<seed_t> range_check;
342 
343  /// Lets the derived class to start configuration
344  CheckedRangePolicy(std::string policy_name): base_t(policy_name) {}
345 
346  /// Performs the range checks and complains if needed
347  virtual void ensureRange
348  (SeedMasterHelper::EngineId const& id, seed_t seed) const
349  { range_check.EnsureRange(this->getName(), id, seed); }
350 
351  /// Check that the configuration is complete
352  void CheckRangeConfiguration() const;
353 
354  /// Local configuration; does not require the range config to be complete
355  void static_configure(fhicl::ParameterSet const& pset);
356 
357  }; // class CheckedRangePolicy
358 
359 
360  template <typename SEED>
362  (fhicl::ParameterSet const& pset)
363  {
364  range_check.configure(pset);
365  } // CheckedRangePolicy<SEED>::static_configure()
366 
367  template <typename SEED>
369  if (!range_check.isConfigured()) {
370  std::ostringstream sstr;
371  sstr << "configuration of policy '" << this->getName()
372  << "' incomplete:";
373  for (std::string const& name: range_check.missingConfig())
374  sstr << " " << name;
375  throw art::Exception(art::errors::Configuration) << sstr.str();
376  }
377  } // CheckedRangePolicy<SEED>::CheckRangeConfiguration()
378 
379 
380 
381  /** ************************************************************************
382  * @brief Base class for policies reacting at engine instance level
383  * @see CheckedRangePolicy
384  *
385  */
386  template <typename SEED>
387  class PerInstancePolicy: public CheckedRangePolicy<SEED> {
388  public:
391  using seed_t = typename base_t::seed_t;
392 
393  /// Configures from a parameter set
394  /// @see configure()
396  base_t(name)
397  { this_t::configure(pset); }
398 
399  /**
400  * @brief Configure this policy
401  * @param pset the parameter set for the configuration
402  *
403  */
404  virtual void configure(fhicl::ParameterSet const& pset) override
405  { base_t::configure(pset); static_configure(pset); }
406 
407  protected:
408  fhicl::ParameterSet parameters; ///< configuration parameters
409 
410  /// Internal constructor: does not configure. For use in derived classes
412 
413  /// Retrieves the parameter (seed) for the specified engine ID
415  { return getInstanceParameter<seed_t>(parameters, id); }
416 
417 
418  /// Retrieves the parameter (seed) for the specified engine ID
419  template <typename T>
420  static T getInstanceParameter
421  (fhicl::ParameterSet const& pset, SeedMasterHelper::EngineId const& id);
422 
423 
424  void static_configure(fhicl::ParameterSet const& pset);
425 
426  }; // class PerInstancePolicy<>
427 
428 
429  template <typename SEED>
431  (fhicl::ParameterSet const& pset)
432  {
433  parameters = pset; // copy the parameters locally
434  } // PerInstancePolicy<SEED>::configure()
435 
436 
437  // This method reads a element of type T from the instance configuration
438  template <typename SEED> template <typename T>
440  fhicl::ParameterSet const& pset, SeedMasterHelper::EngineId const& id
441  ) {
442 
443  // first check if the instance is actually global;
444  // if so, look for it directly in the parameter set
445  if (id.isGlobal()) {
446  // We expect the element to be just an item.
447  if (pset.is_key_to_table(id.instanceName)) {
448  // this is mostly a limitation of the FHiCL syntax,
449  // that we can overcome with some cumbersomeness if we need to.
451  << "A seed for the global instance '" << id
452  << "' was requested, but the configuration sets named instances ("
453  << pset.get<fhicl::ParameterSet>(id.instanceName).to_compact_string()
454  << ").\n";
455  }
456  T param;
457  if (!pset.get_if_present(id.instanceName, param)) {
459  << "NuRandomService: unable to find the parameter for global instance'"
460  << id << "'\n";
461  }
462  return param;
463  } // if global
464 
465  // there must be /some/ configuration for the module
466  if (!pset.has_key(id.moduleLabel)) {
468  << "A seed for the instance '" << id
469  << "' was requested, but there is no configuration at all for '"
470  << id.moduleLabel << "' module label.";
471  }
472 
473  T param;
474  if (!id.hasInstanceName()) { // Case 1: no instance name.
475  // We expect the element to be just an item.
476  if (pset.is_key_to_table(id.moduleLabel)) {
477  // this is mostly a limitation of the FHiCL syntax,
478  // that we can overcome with some cumbersomeness if we need to.
480  << "A seed for the nameless instance '" << id
481  << "' was requested, but the configuration sets named instances ("
482  << pset.get<fhicl::ParameterSet>(id.moduleLabel).to_compact_string()
483  << ").\nNameless and named engine instances can't coexist.";
484  }
485  if (!pset.get_if_present(id.moduleLabel, param)) {
487  << "NuRandomService: unable to find the parameter for '" << id << "'";
488  }
489  } // if no instance name
490  else { // Case 2: instance name is given.
491 
492  if (pset.is_key_to_atom(id.moduleLabel)) {
493  // see above
495  << "A seed for '" << std::string(id) << "' was requested,"
496  " but the configuration sets a nameless instance of '"
497  << id.moduleLabel << "'.\n"
498  << "Nameless and named engine instances can't coexist.";
499  }
500  fhicl::ParameterSet subSet;
501  if (!pset.get_if_present(id.moduleLabel, subSet)) {
503  << "NuRandomService: unable to find the parameter block for: '"
504  << id << "'";
505  }
506 
507  if (!subSet.get_if_present(id.instanceName, param)) {
509  << "NuRandomService: unable to find the parameter value for: '"
510  << id << "'";
511  }
512  } // if instance name
513 
514  return param;
515  } // PerInstancePolicy<SEED>::getInstanceParameter<>()
516 
517 
518  } // namespace details
519 
520 } // namespace rndm
521 
522 
523 #endif // NUTOOLS_RANDOMUTILS_PROVIDERS_RANDOMSEEDPOLICYBASE_H
static QCString name
Definition: declinfo.cpp:673
Base class for policies reacting at engine instance level.
Definition: BasePolicies.h:510
seed_t getInstanceSeed(SeedMasterHelper::EngineId const &id) const
Retrieves the parameter (seed) for the specified engine ID.
PerInstancePolicy(std::string name)
Internal constructor: does not configure. For use in derived classes.
SEED seed_t
type of random seed
SEED seed_t
type of the random seed
Definition: BasePolicies.h:45
std::string string
Definition: nybbler.cc:12
std::vector< std::string > missingConfig() const
Returns the items currently not configured.
Definition: BasePolicies.h:242
bool isConfigured() const
Returns whether all the parameters are configured.
Definition: BasePolicies.h:208
unsigned long seed_t
static constexpr bool isValid(T s)
Returns whether the specified seed is valid.
Simple data structure with data needed to extract a seed from a event.
ValidSeed & operator=(const ValidSeed &)=delete
virtual void print(std::ostream &out) const
Prints information on the configuration of this policy.
static constexpr seed_t Max
Largest allowed seed.
virtual seed_t getSeed(SeedMasterHelper::EngineId const &id)
Returns the next random number.
void SetCheck(bool doCheck=true)
Sets whether to perform the check or not.
virtual void print(std::ostream &out) const override
Prints information on the configuration of this policy.
CheckedRangePolicy(std::string policy_name)
Lets the derived class to start configuration.
bool is_key_to_table(std::string const &key) const
Definition: ParameterSet.h:149
bool configure(fhicl::ParameterSet const &pset)
Definition: BasePolicies.h:189
void SetNSeeds(seed_t nSeeds)
Sets the number of seeds directly.
Interface for a policy implementation.
Definition: BasePolicies.h:43
static constexpr seed_t Min
Smallest allowed seed.
Helper class to support range checking.
Definition: BasePolicies.h:99
T get(std::string const &key) const
Definition: ParameterSet.h:231
RangeCheckHelper(std::string maxSeedsLabel="maxUniqueEngines", std::string baseSeedLabel="baseSeed", std::string checkRangeLabel="checkRange")
Constructor; specify configuration labels.
virtual void configure(fhicl::ParameterSet const &pset) override
Configure this policy.
RandomSeedPolicyBase(std::string policy_name)
Constructor; requires the policy name.
Identifier for a engine, made of module name and optional instance name.
Definition: EngineId.h:22
bool get_if_present(std::string const &key, T &value) const
Definition: ParameterSet.h:208
void print(STREAM &out, std::string indent=std::string()) const
Prints the configuration int the specified stream.
Definition: BasePolicies.h:230
virtual bool yieldsUniqueSeeds() const
Returns whether the returned seed should be unique.
bool has_key(std::string const &key) const
static int max(int a, int b)
virtual void configure(fhicl::ParameterSet const &pset) override
Configure this policy.
static constexpr seed_t BounceUp(T s, T min, T max)
May be merged into MakeValid() with C++14.
virtual seed_t getSeed(SeedMasterHelper::EngineId const &id) override
Returns the next random number.
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
ValidSeed(T s)
Constructor: converts from a value.
virtual void configure(fhicl::ParameterSet const &)
Configure this policy.
void static_configure(fhicl::ParameterSet const &pset)
Local configuration; does not require the range config to be complete.
Definition: BasePolicies.h:317
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
PerInstancePolicy(std::string name, fhicl::ParameterSet const &pset)
Class storing a seed in the valid range.
Range-checked policy (abstract)
Definition: BasePolicies.h:254
bool is_key_to_atom(std::string const &key) const
Definition: ParameterSet.h:161
void EnsureRange(std::string policy, SeedMasterHelper::EngineId const &id, seed_t seed) const
Throws an exception if the range check on seed fails.
Definition: BasePolicies.h:214
seed_t seed
the converted seed
void SetConfigLabels(std::string maxSeedsLabel="maxUniqueEngines", std::string baseSeedLabel="baseSeed", std::string checkRangeLabel="checkRange")
Definition: BasePolicies.h:177
static constexpr seed_t MakeValid(T s)
Forces the specified value into the allowed seed range.
void SetBaseSeed(seed_t base_seed)
Sets the base seed directly.
std::string getName() const
Returns the given name of the policy.
static QCString * s
Definition: config.cpp:1042
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:97
void CheckRangeConfiguration() const
Check that the configuration is complete.
Definition: BasePolicies.h:323
void static_configure(fhicl::ParameterSet const &pset)
Definition: BasePolicies.h:554
static T getInstanceParameter(fhicl::ParameterSet const &pset, SeedMasterHelper::EngineId const &id)
Retrieves the parameter (seed) for the specified engine ID.
Definition: BasePolicies.h:562