Belle II Software  release-08-01-10
RandomGenerator.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include "framework/core/RandomGenerator.h"
10 #include "framework/utilities/sha3hash/Hash.h"
11 #include "framework/logging/Logger.h"
12 #include "framework/datastore/StoreObjPtr.h"
13 #include "framework/dataobjects/EventMetaData.h"
14 #include <sstream>
15 #include <iomanip>
16 #include <algorithm>
17 
18 using namespace Belle2;
19 
20 namespace {
25  template<class T> void addValueToBuffer(std::vector<unsigned char>& buffer, const T& value)
26  {
27  static_assert(std::is_integral<T>::value, "integral type required");
28  constexpr int bytes = sizeof(T);
29  for (int i = bytes - 1; i >= 0; --i) {
30  buffer.push_back((value >> (i * 8)) & 0xFF);
31  }
32  }
33 };
34 
35 RandomGenerator::RandomGenerator(const std::string& name): TRandom(), m_state{0}, m_index(0), m_barrier(0),
36  m_mode(c_independent)
37 {
38  SetName(name.c_str());
39  SetTitle("Belle2 Random Generator");
40 }
41 
42 void RandomGenerator::setSeed(const unsigned char* seed, unsigned int n)
43 {
44  //Copy the seed information and set the seed length
45  m_seed.resize(n);
46  std::copy_n(seed, n, m_seed.data());
47  //reinit the state but ignore missing EventMetaInfo
48  setState(0);
49 }
50 
51 void RandomGenerator::setState(int barrier)
52 {
53  //Reset the internal state position
54  m_index = 0;
55  //Set the barrier to the requested value
57  //Create a SHA-3 hash structrure
59  //If we have a seed info, add it to the hash
60  if (m_seed.size() > 0) hash.update(m_seed.size(), m_seed.data());
61  //Create a byte buffer to store event dependent data to feed to the hash
62  std::vector<unsigned char> buffer;
63  //estimated size of event dependent info in bytes. vector will make sure it
64  //works even if this changes but we like to avoid unnecessary relocations
65  buffer.reserve(28);
66  //add the barrier to the buffer
67  addValueToBuffer(buffer, m_barrier);
68  //do we want to use EventMetaData at all?
69  if (m_mode != c_independent) {
70  //check if we have event data
72  if (!evt) {
73  //no event data, this should not be
74  B2ERROR("No EventMetaData, cannot set state of RandomGenerator from event data");
75  } else {
76  //ok, add event data to buffer
77  addValueToBuffer(buffer, evt->getExperiment());
78  addValueToBuffer(buffer, evt->getRun());
79  // and if we are in run dependent mode add also event number to the hash
80  if (m_mode == c_eventDependent) {
81  addValueToBuffer(buffer, evt->getEvent());
82  }
83  }
84  }
85 
86  hash.update(buffer.size(), buffer.data());
87  //Extract 1024bit hash from the hash structure and write it into the
88  //internal state
89  hash.getHash(sizeof(m_state), (unsigned char*) m_state);
90 
91  //Only prepare debugoutput if we actually want to show it. This is almost
92  //equivalent to B2DEBUG(200, ...); but we need to loop over states for
93  //printing so we could not put it in a normal B2DEBUG statement easily.
94 #ifndef LOG_NO_B2DEBUG
95  if (Belle2::LogSystem::Instance().isLevelEnabled(Belle2::LogConfig::c_Debug, 200, PACKAGENAME())) {
96  std::stringstream info;
97  info << "Random Generator '" << GetName() << "' State info:\n";
98  info << " seed (" << std::dec << m_seed.size() << "):\n ";
99  for (auto c : m_seed) { info << std::setw(2) << std::setfill('0') << std::hex << (int)c << " "; }
100  info << "\n event info (mode=" << m_mode << "): \n";
101  info << " barrier:" << std::dec << m_barrier;
102  if (m_mode != c_independent) {
104  info << " EXP:" << evt->getExperiment() << " RUN:" << evt->getRun();
105  if (m_mode == c_eventDependent) {
106  info << " EVT:" << evt->getEvent();
107  }
108  }
109  info << "\n event bytes (" << std::dec << buffer.size() << "):\n ";
110  for (auto c : buffer) { info << std::setw(2) << std::setfill('0') << std::hex << (int)c << " "; }
111  info << "\n state (index=" << m_index << "): ";
112  for (int i = 0; i < 16; ++i) {
113  info << ((i % 4 == 0) ? "\n " : " ") << std::setw(16) << std::setfill('0') << std::hex << m_state[i];
114  }
115  _B2LOGMESSAGE(Belle2::LogConfig::c_Debug, 200, info.str(), PACKAGENAME(), FUNCTIONNAME(), __FILE__, __LINE__);
116  }
117 #endif
118 }
119 
120 void RandomGenerator::RndmArray(Int_t n, unsigned char* array)
121 {
122  //First we fill the array using 64bit blocks
123  RndmArray(n / sizeof(ULong64_t), (ULong64_t*)array);
124  const Int_t remainder = n % sizeof(ULong64_t);
125  //If the size is not divisible by 8 we fill the remainder from one additional
126  //random value
127  if (remainder) {
128  const ULong64_t r = random64();
129  std::copy_n((unsigned char*)&r, remainder, array + (n - remainder - 1));
130  }
131 }
@ c_Debug
Debug: for code development.
Definition: LogConfig.h:26
static LogSystem & Instance()
Static method to get a reference to the LogSystem instance.
Definition: LogSystem.cc:31
void setState(int barrier)
Set the state of the random number generator.
@ c_eventDependent
Use experiment, run and event number to generate state.
@ c_independent
Don't use event info to generate state.
uint64_t m_state[16]
Internal state of the random number generator.
unsigned int m_index
currently active index in the internal state
int m_barrier
current barrier index.
EGeneratorMode m_mode
Current generator mode.
void setSeed(const unsigned char *seed, unsigned int n)
Set the seed information.
std::vector< unsigned char > m_seed
seed information
RandomGenerator(const std::string &name="Belle2 Random Generator")
Default constructor, does not initialize the generator.
void barrier()
increase the barrier index.
Simple interface to calculate SHAKE256 hash sum (FIPS 202 draft) with variable size from given data i...
Definition: Hash.h:58
@ c_SHAKE256
variable hash size with up to 256 bit collision resistance
Definition: Hash.h:63
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:96
void update(int n, unsigned char *buff)
update the internal state by adding n bytes of data from buff
Definition: Hash.cc:100
uint64_t random64()
Generate one 64bit unsigned integer between 0 and UINT64_MAX (both inclusive).
void RndmArray(Int_t n, Float_t *array)
Fill an array of floats with random values in (0,1), both limits excluded.
void getHash(int n, unsigned char *buff)
obtain the hash value with a length of n bytes into buff
Definition: Hash.cc:105
Abstract base class for different kinds of events.