Project Alice
Loading...
Searching...
No Matches
Engine.hpp
Go to the documentation of this file.
1/*
2Copyright 2010-2011, D. E. Shaw Research.
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are
7met:
8
9* Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12* Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15
16* Neither the name of D. E. Shaw Research nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
19
20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*/
32#ifndef __Engine_dot_hpp_
33#define __Engine_dot_hpp_
34
35#include "../features/compilerfeatures.h"
36#include "../array.h"
37#include <limits>
38#include <stdexcept>
39#include <sstream>
40#include <algorithm>
41#include <vector>
42#if R123_USE_CXX11_TYPE_TRAITS
43#include <type_traits>
44#endif
45
46namespace r123 {
67template<typename CBRNG>
68struct Engine {
69 typedef CBRNG cbrng_type;
70 typedef typename CBRNG::ctr_type ctr_type;
71 typedef typename CBRNG::key_type key_type;
72 typedef typename CBRNG::ukey_type ukey_type;
73 typedef typename ctr_type::value_type result_type;
74
75protected:
80
82 if(v.back() != 0) {
83 result_type vv = v.back();
84 v = b(c, key);
85 v.back() = vv;
86 }
87 }
88
89public:
90 explicit Engine() : b(), c() {
91 ukey_type x = {{}};
92 v.back() = 0;
93 key = x;
94 }
95 explicit Engine(result_type r) : b(), c() {
96 ukey_type x = {{typename ukey_type::value_type(r)}};
97 v.back() = 0;
98 key = x;
99 }
100 // 26.5.3 says that the SeedSeq templates shouldn't particpate in
101 // overload resolution unless the type qualifies as a SeedSeq.
102 // How that is determined is unspecified, except that "as a
103 // minimum a type shall not qualify as a SeedSeq if it is
104 // implicitly convertible to a result_type."
105 //
106 // First, we make sure that even the non-const copy constructor
107 // works as expected. In addition, if we've got C++11
108 // type_traits, we use enable_if and is_convertible to implement
109 // the convertible-to-result_type restriction. Otherwise, the
110 // template is unconditional and will match in some surpirsing
111 // and undesirable situations.
112 Engine(Engine& e) : b(e.b), key(e.key), c(e.c) {
113 v.back() = e.v.back();
115 }
116 Engine(Engine const& e) : b(e.b), key(e.key), c(e.c) {
117 v.back() = e.v.back();
119 }
120#if __cplusplus >= 201103L
121 Engine& operator=(Engine const&) = default;
122 Engine& operator=(Engine&&) = default;
123#endif
124
125 template<typename SeedSeq>
126 explicit Engine(SeedSeq& s
128 ,
129 typename std::enable_if<!std::is_convertible<SeedSeq, result_type>::value>::type* = 0
130#endif
131 )
132 : b(), c() {
133 ukey_type ukey = ukey_type::seed(s);
134 key = ukey;
135 v.back() = 0;
136 }
138 *this = Engine(r);
139 }
140 template<typename SeedSeq>
141 void seed(SeedSeq& s
143 ,
144 typename std::enable_if<!std::is_convertible<SeedSeq, result_type>::value>::type* = 0
145#endif
146 ) {
147 *this = Engine(s);
148 }
149 void seed() {
150 *this = Engine();
151 }
152 friend bool operator==(Engine const& lhs, Engine const& rhs) {
153 return lhs.c == rhs.c && lhs.v.back() == rhs.v.back() && lhs.key == rhs.key;
154 }
155 friend bool operator!=(Engine const& lhs, Engine const& rhs) {
156 return lhs.c != rhs.c || lhs.v.back() != rhs.v.back() || lhs.key != rhs.key;
157 }
158
159 friend std::ostream& operator<<(std::ostream& os, Engine const& be) {
160 return os << be.c << " " << be.key << " " << be.v.back();
161 }
162
163 friend std::istream& operator>>(std::istream& is, Engine& be) {
164 is >> be.c >> be.key >> be.v.back();
165 be.fix_invariant();
166 return is;
167 }
168
169 // The <random> shipped with MacOS Xcode 4.5.2 imposes a
170 // non-standard requirement that URNGs also have static data
171 // members: _Min and _Max. Later versions of libc++ impose the
172 // requirement only when constexpr isn't supported. Although the
173 // Xcode 4.5.2 requirement is clearly non-standard, it is unlikely
174 // to be fixed and it is very easy work around. We certainly
175 // don't want to go to great lengths to accommodate every buggy
176 // library we come across, but in this particular case, the effort
177 // is low and the benefit is high, so it's worth doing. Thanks to
178 // Yan Zhou for pointing this out to us. See similar code in
179 // ../MicroURNG.hpp
180 const static result_type _Min = 0;
181 const static result_type _Max = ~((result_type)0);
182
183 static R123_CONSTEXPR result_type min R123_NO_MACRO_SUBST() {
184 return _Min;
185 }
186 static R123_CONSTEXPR result_type max R123_NO_MACRO_SUBST() {
187 return _Max;
188 }
189
191 if(c.size() == 1) // short-circuit the scalar case. Compilers aren't mind-readers.
192 return b(c.incr(), key)[0];
193 result_type& elem = v.back();
194 if(elem == 0) {
195 v = b(c.incr(), key);
196 result_type ret = v.back();
197 elem = c.size() - 1;
198 return ret;
199 }
200 return v[--elem];
201 }
202
204 // don't forget: elem counts down
205 size_t nelem = c.size();
206 size_t sub = skip % nelem;
207 result_type& elem = v.back();
208 skip /= nelem;
209 if(elem < sub) {
210 elem += nelem;
211 skip++;
212 }
213 elem -= sub;
214 c.incr(skip);
216 }
217
218 //--------------------------
219 // Some bonus methods, not required for a Random Number
220 // Engine
221
222 // Constructors and seed() method for ukey_type seem useful
223 // We need const and non-const to supersede the SeedSeq template.
224 explicit Engine(ukey_type const& uk) : key(uk), c() {
225 v.back() = 0;
226 }
227 explicit Engine(ukey_type& uk) : key(uk), c() {
228 v.back() = 0;
229 }
230 void seed(ukey_type const& uk) {
231 *this = Engine(uk);
232 }
233 void seed(ukey_type& uk) {
234 *this = Engine(uk);
235 }
236
237#if R123_USE_CXX11_TYPE_TRAITS
238 template<typename DUMMY = void>
239 explicit Engine(key_type const& k, typename std::enable_if<!std::is_same<ukey_type, key_type>::value, DUMMY>::type* = 0)
240 : key(k), c() {
241 v.back() = 0;
242 }
243
244 template<typename DUMMY = void>
245 void seed(key_type const& k, typename std::enable_if<!std::is_same<ukey_type, key_type>::value, DUMMY>::type* = 0) {
246 *this = Engine(k);
247 }
248#endif
249
250 // Forward the e(counter) to the CBRNG we are templated
251 // on, using the current value of the key.
253 return b(c, key);
254 }
255
256 key_type getkey() const {
257 return key;
258 }
259
260 // N.B. setkey(k) is different from seed(k) because seed(k) zeros
261 // the counter (per the C++11 requirements for an Engine), whereas
262 // setkey does not.
263 void setkey(key_type const& k) {
264 key = k;
266 }
267
268 // Maybe the caller want's to know the details of
269 // the internal state, e.g., so it can call a different
270 // bijection with the same counter.
271 std::pair<ctr_type, result_type> getcounter() const {
272 return std::make_pair(c, v.back());
273 }
274
275 // And the inverse.
276 void setcounter(ctr_type const& _c, result_type _elem) {
277 static const size_t nelem = c.size();
278 if(_elem >= nelem)
279 throw std::range_error("Engine::setcounter called with elem out of range");
280 c = _c;
281 v.back() = _elem;
283 }
284
285 void setcounter(std::pair<ctr_type, result_type> const& ce) {
286 setcounter(ce.first, ce.second);
287 }
288};
289} // namespace r123
290
291#endif
#define R123_USE_CXX11_TYPE_TRAITS
Definition: clangfeatures.h:83
#define R123_ULONG_LONG
Definition: array.h:344
static R123_CONSTEXPR result_type max R123_NO_MACRO_SUBST()
Definition: Engine.hpp:186
friend std::ostream & operator<<(std::ostream &os, Engine const &be)
Definition: Engine.hpp:159
void setcounter(std::pair< ctr_type, result_type > const &ce)
Definition: Engine.hpp:285
CBRNG::key_type key_type
Definition: Engine.hpp:71
friend bool operator==(Engine const &lhs, Engine const &rhs)
Definition: Engine.hpp:152
void seed(ukey_type const &uk)
Definition: Engine.hpp:230
void discard(R123_ULONG_LONG skip)
Definition: Engine.hpp:203
CBRNG::ukey_type ukey_type
Definition: Engine.hpp:72
Engine(Engine &e)
Definition: Engine.hpp:112
ctr_type::value_type result_type
Definition: Engine.hpp:73
CBRNG cbrng_type
Definition: Engine.hpp:69
friend std::istream & operator>>(std::istream &is, Engine &be)
Definition: Engine.hpp:163
Engine(ukey_type const &uk)
Definition: Engine.hpp:224
cbrng_type b
Definition: Engine.hpp:76
ctr_type v
Definition: Engine.hpp:79
friend bool operator!=(Engine const &lhs, Engine const &rhs)
Definition: Engine.hpp:155
ctr_type operator()(ctr_type const &c) const
Definition: Engine.hpp:252
void seed(ukey_type &uk)
Definition: Engine.hpp:233
key_type getkey() const
Definition: Engine.hpp:256
std::pair< ctr_type, result_type > getcounter() const
Definition: Engine.hpp:271
void seed(result_type r)
Definition: Engine.hpp:137
Engine(Engine const &e)
Definition: Engine.hpp:116
CBRNG::ctr_type ctr_type
Definition: Engine.hpp:70
static const result_type _Min
Definition: Engine.hpp:180
void fix_invariant()
Definition: Engine.hpp:81
void seed(SeedSeq &s)
Definition: Engine.hpp:141
void setkey(key_type const &k)
Definition: Engine.hpp:263
Engine(SeedSeq &s)
Definition: Engine.hpp:126
result_type operator()()
Definition: Engine.hpp:190
key_type key
Definition: Engine.hpp:77
Engine(result_type r)
Definition: Engine.hpp:95
static const result_type _Max
Definition: Engine.hpp:181
Engine(ukey_type &uk)
Definition: Engine.hpp:227
static R123_CONSTEXPR result_type min R123_NO_MACRO_SUBST()
Definition: Engine.hpp:183
void setcounter(ctr_type const &_c, result_type _elem)
Definition: Engine.hpp:276
ctr_type c
Definition: Engine.hpp:78
void seed()
Definition: Engine.hpp:149