/perf/kseta

To get this branch, use:
bzr branch http://darksoft.org/webbzr/perf/kseta

« back to all changes in this revision

Viewing changes to tutorials/4_pi/random123/conventional/Engine.hpp

  • Committer: Suren A. Chilingaryan
  • Date: 2013-10-08 23:53:50 UTC
  • Revision ID: csa@dside.dyndns.org-20131008235350-hsu8oukzkh05gtcm
Add tutorials

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright 2010-2011, D. E. Shaw Research.
 
3
All rights reserved.
 
4
 
 
5
Redistribution and use in source and binary forms, with or without
 
6
modification, are permitted provided that the following conditions are
 
7
met:
 
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
 
 
20
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
21
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
22
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
23
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
24
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
25
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
26
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
27
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
28
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
29
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
30
OF 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
 
 
46
namespace r123{
 
47
/**
 
48
  If G satisfies the requirements of a CBRNG, and has a ctr_type whose
 
49
  value_type is an unsigned integral type, then Engine<G> satisfies
 
50
  the requirements of a C++0x "Uniform Random Number Engine" and can
 
51
  be used in any context where such an object is expected.
 
52
 
 
53
  Note that wrapping a counter based RNG with a traditional API in
 
54
  this way obscures much of the power of counter based PRNGs.
 
55
  Nevertheless, it may be of value in applications that are already
 
56
  coded to work with the C++0x random number engines.
 
57
 
 
58
  The MicroURNG template in MicroURNG.hpp
 
59
  provides the more limited functionality of a C++0x "Uniform
 
60
  Random Number Generator", but leaves the application in control
 
61
  of counters and keys and hence may be preferable to the Engine template.
 
62
  For example, a MicroURNG allows one to use C++0x "Random Number
 
63
  Distributions"  without giving up control over the counters
 
64
  and keys.
 
65
*/ 
 
66
 
 
67
template<typename CBRNG>
 
68
struct 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
    typedef size_t elem_type;
 
75
 
 
76
protected:
 
77
    cbrng_type b;
 
78
    key_type key;
 
79
    ukey_type ukey;
 
80
    ctr_type c;
 
81
    elem_type elem;
 
82
    ctr_type v;
 
83
 
 
84
    void fix_invariant(){
 
85
        if( elem != 0 ) {
 
86
            v = b(c, key);
 
87
        }
 
88
    }        
 
89
public:
 
90
    explicit Engine() : b(), c(), elem() {
 
91
        ukey_type x = {{}};
 
92
        ukey = x;
 
93
        key = ukey;
 
94
    }
 
95
    explicit Engine(result_type r) : b(), c(), elem() {
 
96
        ukey_type x = {{typename ukey_type::value_type(r)}};
 
97
        ukey = x;
 
98
        key = ukey;
 
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++0x
 
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), ukey(e.ukey), c(e.c), elem(e.elem){
 
113
        key = ukey;
 
114
        fix_invariant();
 
115
    }
 
116
    Engine(const Engine& e) : b(e.b), ukey(e.ukey), c(e.c), elem(e.elem){
 
117
        key = ukey;
 
118
        fix_invariant();
 
119
    }
 
120
 
 
121
    template <typename SeedSeq>
 
122
    explicit Engine(SeedSeq &s
 
123
#if R123_USE_CXX11_TYPE_TRAITS
 
124
                    , typename std::enable_if<!std::is_convertible<SeedSeq, result_type>::value>::type* =0
 
125
#endif
 
126
                    )
 
127
        : b(), c(), elem() {
 
128
        ukey = ukey_type::seed(s);
 
129
        key = ukey;
 
130
    }
 
131
    void seed(result_type r){
 
132
        *this = Engine(r);
 
133
    }
 
134
    template <typename SeedSeq>
 
135
    void seed(SeedSeq &s
 
136
#if R123_USE_CXX11_TYPE_TRAITS
 
137
                    , typename std::enable_if<!std::is_convertible<SeedSeq, result_type>::value>::type* =0
 
138
#endif
 
139
              ){ 
 
140
        *this = Engine(s);
 
141
    }
 
142
    void seed(){
 
143
        *this = Engine();
 
144
    }
 
145
    friend bool operator==(const Engine& lhs, const Engine& rhs){
 
146
        return lhs.c==rhs.c && lhs.elem == rhs.elem && lhs.ukey == rhs.ukey;
 
147
    }
 
148
    friend bool operator!=(const Engine& lhs, const Engine& rhs){
 
149
        return lhs.c!=rhs.c || lhs.elem != rhs.elem || lhs.ukey!=rhs.ukey;
 
150
    }
 
151
 
 
152
    friend std::ostream& operator<<(std::ostream& os, const Engine& be){
 
153
        return os << be.c << " " << be.ukey << " " << be.elem;
 
154
    }
 
155
 
 
156
    friend std::istream& operator>>(std::istream& is, Engine& be){
 
157
        is >> be.c >> be.ukey >> be.elem;
 
158
        be.key = be.ukey;
 
159
        be.fix_invariant();
 
160
        return is;
 
161
    }
 
162
 
 
163
    // The <random> shipped with MacOS Xcode 4.5.2 imposes a
 
164
    // non-standard requirement that URNGs also have static data
 
165
    // members: _Min and _Max.  Later versions of libc++ impose the
 
166
    // requirement only when constexpr isn't supported.  Although the
 
167
    // Xcode 4.5.2 requirement is clearly non-standard, it is unlikely
 
168
    // to be fixed and it is very easy work around.  We certainly
 
169
    // don't want to go to great lengths to accommodate every buggy
 
170
    // library we come across, but in this particular case, the effort
 
171
    // is low and the benefit is high, so it's worth doing.  Thanks to
 
172
    // Yan Zhou for pointing this out to us.  See similar code in
 
173
    // ../MicroURNG.hpp
 
174
    const static result_type _Min = 0;
 
175
    const static result_type _Max = ~((result_type)0);
 
176
 
 
177
    static R123_CONSTEXPR result_type min R123_NO_MACRO_SUBST () { return _Min; }
 
178
    static R123_CONSTEXPR result_type max R123_NO_MACRO_SUBST () { return _Max; }
 
179
 
 
180
    result_type operator()(){
 
181
        if( c.size() == 1 )     // short-circuit the scalar case.  Compilers aren't mind-readers.
 
182
            return b(c.incr(), key)[0];
 
183
        if( elem == 0 ){
 
184
            v = b(c.incr(), key);
 
185
            elem = c.size();
 
186
        }
 
187
        return v[--elem];
 
188
    }
 
189
 
 
190
    void discard(R123_ULONG_LONG skip){
 
191
        // don't forget:  elem counts down
 
192
        size_t nelem = c.size();
 
193
        size_t sub = skip % nelem;
 
194
        skip /= nelem;
 
195
        if (elem < sub) {
 
196
            elem += nelem;
 
197
            skip++;
 
198
        }
 
199
        elem -= sub;
 
200
        c.incr(skip);
 
201
        fix_invariant();
 
202
    }
 
203
         
 
204
    //--------------------------
 
205
    // Some bonus methods, not required for a Random Number
 
206
    // Engine
 
207
 
 
208
    // Constructors and seed() method for ukey_type seem useful
 
209
    // We need const and non-const to supersede the SeedSeq template.
 
210
    explicit Engine(const ukey_type &uk) : key(uk), ukey(uk), c(), elem(){}
 
211
    explicit Engine(ukey_type &uk) : key(uk), ukey(uk), c(), elem(){}
 
212
    void seed(const ukey_type& uk){
 
213
        *this = Engine(uk);
 
214
    }        
 
215
    void seed(ukey_type& uk){
 
216
        *this = Engine(uk);
 
217
    }        
 
218
 
 
219
    // Forward the e(counter) to the CBRNG we are templated
 
220
    // on, using the current value of the key.
 
221
    ctr_type operator()(const ctr_type& c) const{
 
222
        return b(c, key);
 
223
    }
 
224
 
 
225
    // Since you can seed *this with a ukey_type, it seems reasonable
 
226
    // to allow the caller to know what seed/ukey *this is using.
 
227
    ukey_type getseed() const{
 
228
        return ukey;
 
229
    }
 
230
 
 
231
    // Maybe the caller want's to know the details of
 
232
    // the internal state, e.g., so it can call a different
 
233
    // bijection with the same counter.
 
234
    std::pair<ctr_type, elem_type> getcounter() const {
 
235
        return make_pair(c,  elem);
 
236
    }
 
237
 
 
238
    // And the inverse.
 
239
    void setcounter(const ctr_type& _c, elem_type _elem){
 
240
        static const size_t nelem = c.size();
 
241
        if( elem > nelem )
 
242
            throw std::range_error("Engine::setcounter called  with elem out of range");
 
243
        c = _c;
 
244
        elem = _elem;
 
245
        fix_invariant();
 
246
    }
 
247
};
 
248
} // namespace r123
 
249
 
 
250
#endif