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