MCKL
Monte Carlo Kernel Library
counter.hpp
Go to the documentation of this file.
1 //============================================================================
2 // MCKL/include/mckl/random/counter.hpp
3 //----------------------------------------------------------------------------
4 // MCKL: Monte Carlo Kernel Library
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2018, Yan Zhou
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimer.
14 //
15 // Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimer in the documentation
17 // and/or other materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 // POSSIBILITY OF SUCH DAMAGE.
30 //============================================================================
31 
32 #ifndef MCKL_RANDOM_COUNTER_HPP
33 #define MCKL_RANDOM_COUNTER_HPP
34 
37 
38 namespace mckl {
39 
40 MCKL_PUSH_CLANG_WARNING("-Wpadded")
61 template <typename ResultType, typename Generator>
63 {
64  static_assert(std::is_unsigned<ResultType>::value,
65  "**CounterEngine** used with ResultType other than unsigned intger "
66  "types");
67 
68  static_assert(Generator::size() % sizeof(ResultType) == 0,
69  "**CounterEngine** used with Generator::size() not divisible by "
70  "sizeof(ResultType)");
71 
72  public:
73  using result_type = ResultType;
74  using generator_type = Generator;
75  using ctr_type = typename generator_type::ctr_type;
76  using key_type = typename generator_type::key_type;
77  using skip_type = typename ctr_type::value_type;
78 
79  private:
80  template <typename T>
81  using is_seed_seq = internal::is_seed_seq<T,
83 
84  public:
85  explicit CounterEngine(result_type s = 1) : index_(M_) { seed(s); }
86 
87  template <typename SeedSeq>
88  explicit CounterEngine(SeedSeq &seq,
89  std::enable_if_t<is_seed_seq<SeedSeq>::value> * = nullptr)
90  : index_(M_)
91  {
92  seed(seq);
93  }
94 
95  explicit CounterEngine(const key_type &k) : index_(M_) { seed(k); }
96 
97  void seed(result_type s)
98  {
99  key_type key;
100  std::fill(key.begin(), key.end(), 0);
101  key.front() = static_cast<typename key_type::value_type>(s);
102  reset(key);
103  }
104 
105  template <typename SeedSeq>
106  void seed(SeedSeq &seq,
107  std::enable_if_t<is_seed_seq<SeedSeq>::value> * = nullptr)
108  {
109  key_type key;
110  seq.generator(key.begin(), key.end());
111  reset(key);
112  }
113 
114  void seed(const key_type &key) { reset(key); }
115 
116  key_type key() const { return generator_.key(); }
117 
118  ctr_type ctr() const { return ctr_; }
119 
120  void key(const key_type &k) { reset(k); }
121 
122  void ctr(const ctr_type &c)
123  {
124  ctr_ = c;
125  index_ = M_;
126  }
127 
128  generator_type &generator() { return generator_; }
129 
130  const generator_type &generator() const { return generator_; }
131 
133  {
134  if (index_ == M_) {
135  generator_(ctr_, result_.data());
136  index_ = 0;
137  }
138 
139  return result_[index_++];
140  }
141 
142  void operator()(std::size_t n, result_type *r)
143  {
144  const std::size_t remain = static_cast<std::size_t>(M_ - index_);
145 
146  if (n <= remain) {
147  std::memcpy(r, result_.data() + index_, sizeof(result_type) * n);
148  index_ += static_cast<unsigned>(n);
149  return;
150  }
151 
152  std::memcpy(r, result_.data() + index_, sizeof(result_type) * remain);
153  r += remain;
154  n -= remain;
155  index_ = M_;
156 
157  const std::size_t m = n / M_;
158  generator_(ctr_, m, r);
159  r += m * M_;
160  n -= m * M_;
161 
162  generator_(ctr_, result_.data());
163  std::memcpy(r, result_.data(), sizeof(result_type) * n);
164  index_ = static_cast<unsigned>(n);
165  }
166 
170  std::size_t discard()
171  {
172  const std::size_t remain = static_cast<std::size_t>(M_ - index_);
173  index_ = M_;
174 
175  return remain;
176  }
177 
178  void discard(skip_type nskip)
179  {
180  if (nskip == 0) {
181  return;
182  }
183 
184  const skip_type remain = static_cast<skip_type>(M_ - index_);
185  if (nskip <= remain) {
186  index_ += static_cast<unsigned>(nskip);
187  return;
188  }
189  nskip -= remain;
190  index_ = M_;
191 
192  skip_type M = static_cast<skip_type>(M_);
193  std::size_t res_size = sizeof(result_type) * M_;
194  std::size_t ctr_size = sizeof(ctr_type);
195  skip_type rate = static_cast<skip_type>(res_size / ctr_size);
196  increment(ctr_, nskip / M * rate);
197  generator_(ctr_, result_.data());
198  index_ = static_cast<unsigned>(nskip % M);
199  }
200 
201  static constexpr result_type min()
202  {
203  return std::numeric_limits<result_type>::min();
204  }
205 
206  static constexpr result_type max()
207  {
208  return std::numeric_limits<result_type>::max();
209  }
210 
211  friend bool operator==(const CounterEngine<ResultType, Generator> &eng1,
212  const CounterEngine<ResultType, Generator> &eng2)
213  {
214  if (eng1.result_ != eng2.result_) {
215  return false;
216  }
217  if (eng1.ctr_ != eng2.ctr_) {
218  return false;
219  }
220  if (eng1.generator_ != eng2.generator_) {
221  return false;
222  }
223  if (eng1.index_ != eng2.index_) {
224  return false;
225  }
226  return true;
227  }
228 
229  friend bool operator!=(const CounterEngine<ResultType, Generator> &eng1,
230  const CounterEngine<ResultType, Generator> &eng2)
231  {
232  return !(eng1 == eng2);
233  }
234 
235  template <typename CharT, typename Traits>
236  friend std::basic_ostream<CharT, Traits> &operator<<(
237  std::basic_ostream<CharT, Traits> &os,
238  const CounterEngine<ResultType, Generator> &eng)
239  {
240  if (!os) {
241  return os;
242  }
243 
244  os << eng.result_ << ' ';
245  os << eng.ctr_ << ' ';
246  os << eng.generator_ << ' ';
247  os << eng.index_;
248 
249  return os;
250  }
251 
252  template <typename CharT, typename Traits>
253  friend std::basic_istream<CharT, Traits> &operator>>(
254  std::basic_istream<CharT, Traits> &is,
255  CounterEngine<ResultType, Generator> &eng)
256  {
257  if (!is) {
258  return is;
259  }
260 
261  CounterEngine<ResultType, Generator> eng_tmp;
262  is >> std::ws >> eng_tmp.result_;
263  is >> std::ws >> eng_tmp.ctr_;
264  is >> std::ws >> eng_tmp.generator_;
265  is >> std::ws >> eng_tmp.index_;
266 
267  if (is) {
268  eng = std::move(eng_tmp);
269  }
270 
271  return is;
272  }
273 
274  private:
275  static constexpr unsigned M_ = Generator::size() / sizeof(ResultType);
276 
277  std::array<result_type, M_> result_;
278  ctr_type ctr_;
279  generator_type generator_;
280  unsigned index_;
281 
282  void reset(const key_type key)
283  {
284  std::fill(ctr_.begin(), ctr_.end(), 0);
285  generator_.reset(key);
286  index_ = M_;
287  }
288 }; // class CounterEngine
290 
291 template <typename ResultType, typename Generator>
292 class SeedTrait<CounterEngine<ResultType, Generator>>
293 {
294  public:
296 }; // class SeedTrait
297 
298 template <typename ResultType, typename Generator>
299 inline void rand(
300  CounterEngine<ResultType, Generator> &rng, std::size_t n, ResultType *r)
301 {
302  rng(n, r);
303 }
304 
305 } // namespace mckl
306 
307 #endif // MCKL_RANDOM_COUNTER_HPP
ResultType result_type
Definition: counter.hpp:73
void seed(SeedSeq &seq, std::enable_if_t< is_seed_seq< SeedSeq >::value > *=nullptr)
Definition: counter.hpp:106
Counter based RNG engine.
Definition: counter.hpp:62
void discard(skip_type nskip)
Definition: counter.hpp:178
friend bool operator==(const CounterEngine< ResultType, Generator > &eng1, const CounterEngine< ResultType, Generator > &eng2)
Definition: counter.hpp:211
void ctr(const ctr_type &c)
Definition: counter.hpp:122
#define MCKL_PUSH_CLANG_WARNING(warning)
Definition: compiler.h:63
void operator()(std::size_t n, result_type *r)
Definition: counter.hpp:142
typename generator_type::key_type key_type
Definition: counter.hpp:76
void seed(const key_type &key)
Definition: counter.hpp:114
friend bool operator!=(const CounterEngine< ResultType, Generator > &eng1, const CounterEngine< ResultType, Generator > &eng2)
Definition: counter.hpp:229
void key(const key_type &k)
Definition: counter.hpp:120
typename ctr_type::value_type skip_type
Definition: counter.hpp:77
CounterEngine(const key_type &k)
Definition: counter.hpp:95
void seed(result_type s)
Definition: counter.hpp:97
static constexpr result_type min()
Definition: counter.hpp:201
result_type operator()()
Definition: counter.hpp:132
typename generator_type::ctr_type ctr_type
Definition: counter.hpp:75
ctr_type ctr() const
Definition: counter.hpp:118
std::integral_constant< bool, std::is_class< T >::value &&!std::is_convertible< T, RNGType >::value &&!std::is_convertible< T, typename RNGType::result_type >::value &&!std::is_convertible< T, KeyType >::value > is_seed_seq
Definition: traits.hpp:187
void increment(std::array< T, K > &ctr, std::integral_constant< T, NSkip >)
Increment a counter by given steps.
CounterEngine(SeedSeq &seq, std::enable_if_t< is_seed_seq< SeedSeq >::value > *=nullptr)
Definition: counter.hpp:88
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const CounterEngine< ResultType, Generator > &eng)
Definition: counter.hpp:236
Definition: mcmc.hpp:40
void rand(RNGType &rng, ArcsineDistribution< RealType > &distribution, std::size_t N, RealType *r)
#define MCKL_POP_CLANG_WARNING
Definition: compiler.h:66
Generator generator_type
Definition: counter.hpp:74
typename CounterEngine< ResultType, Generator >::key_type type
Definition: counter.hpp:295
const generator_type & generator() const
Definition: counter.hpp:130
CounterEngine(result_type s=1)
Definition: counter.hpp:85
static constexpr result_type max()
Definition: counter.hpp:206
key_type key() const
Definition: counter.hpp:116
generator_type & generator()
Definition: counter.hpp:128
std::size_t discard()
Discard the result.
Definition: counter.hpp:170
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, CounterEngine< ResultType, Generator > &eng)
Definition: counter.hpp:253