1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
|
/*
Copyright 2010-2011, D. E. Shaw Research.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions, and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of D. E. Shaw Research nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// TODO - really do a thorough and complete set of tests.
#ifdef _MSC_FULL_VER
// Engines have multiple copy constructors, quite legal C++, disable MSVC complaint
#pragma warning (disable : 4521)
#endif
#include <Random123/philox.h>
#include <Random123/aes.h>
#include <Random123/threefry.h>
#include <Random123/ars.h>
#include <Random123/conventional/Engine.hpp>
#include <Random123/ReinterpretCtr.hpp>
#if R123_USE_CXX11_RANDOM
#include <random>
#endif
#include <cassert>
#include <iostream>
#include <sstream>
#include "util_demangle.hpp"
using namespace std;
using namespace r123;
template <typename EType>
typename EType::result_type kat1000(){
// A zero return says that no KAT is known. This makes
// sense for the ReniterpretCtr-based engines which are
// expected to produce endian-specific results, so we
// don't have known answers for them.
return 0;
}
#if R123_USE_PHILOX_64BIT
template <> uint64_t kat1000<Engine<Philox2x64 > >(){ return R123_64BIT(10575809911605703474); }
#endif
template <> uint32_t kat1000<Engine<Philox4x32 > >(){ return 1721865298; }
template <> uint64_t kat1000<Engine<Threefry2x64 > >(){ return R123_64BIT(17578122881062615727); }
template <> uint32_t kat1000<Engine<Threefry4x32 > >(){ return 874101813; }
#if R123_USE_AES_OPENSSL
template <> uint8_t kat1000<Engine<AESOpenSSL16x8> >(){ return 0237; }
#endif
#define ASSERTEQ(A, B) assert(A==B); assert(A()==B()); assert(A()==B()); assert(A()==B())
struct DummySeedSeq{
template <typename ITER>
void generate(ITER b, ITER e){
std::fill(b, e, 1);
}
};
template <typename EType>
void doit(){
EType e;
cout << "doit<" << demangle(e) << ">";
typedef typename EType::cbrng_type BType;
typedef typename EType::result_type rtype;
typedef typename BType::ctr_type ctype;
typedef typename BType::key_type ktype;
DummySeedSeq dummyss;
EType ess(dummyss);
assert(ess != e);
rtype r1 = e();
rtype r2 = e(); assert( r1 != r2 );
rtype r3 = e(); assert( r3 != r2 && r3 != r1 );
// We've elsewhere confirmed that the underlying bijections actually "work",
// e.g., that they pass the Known Answer Test for some set of test vectors.
// Here, we simply check that the output of the Engine corresponds, in the expected
// way to the output of the underlying bijection.
// Check that the first few values out of the engine correspond
// to output from the underlying bijection.
BType b;
ctype c1 = {{}};
ktype k = e.getseed();
e.seed();
for(int i=0; i<100; ++i){
c1[0]++;
ctype rb = b(c1, k);
for(typename ctype::reverse_iterator p=rb.rbegin(); p!=rb.rend(); ++p){
rtype re = e();
assert( *p == re );
}
}
// Check that discard work as expected, i.e., we can keep two
// engines "in sync" by discarding from one and stepping the other.
EType e2;
assert(e2 != e);
e2.discard(100*c1.size());
ASSERTEQ(e2, e);
for(int disc=1; disc<50; ++disc){
e.discard(disc);
assert( e != e2 );
for(int j=0; j<disc; ++j) e2();
ASSERTEQ(e2, e);
}
// Check that saving and restoring state and the copy constructor
// works as expected.
ostringstream oss;
oss << e2;
string s2 = oss.str();
int fiftyfive = 55;
#if R123_USE_CXX11_TYPE_TRAITS
// With CXX11, the library has type_traits to prevent
// undesirable type resolution against the templated SeedSeq constructor
EType e3(fiftyfive);
#else
// Without CXX11, we have to be careful to pass in
// a bona fide rtype, and not just something that will promote
// to an rtype, if we want the rtype constructor.
EType e3((rtype(fiftyfive)));
#endif
EType esave(e);
assert(e3 != e2);
{
istringstream iss(s2);
iss >> e3;
}
ASSERTEQ(e3, e2);
assert(e3 != esave );
{
istringstream iss(s2);
iss >> e3;
}
ASSERTEQ(e3, esave);
// Check that the constructor-from-rvalue works.
EType e4((rtype)99);
EType e5;
assert(e4 != e5);
assert(e4 != e3);
e5.seed((rtype)99);
ASSERTEQ(e4, e5);
#if R123_USE_STD_RANDOM
// Check that we can use an EType with a std::distribution.
// Obviously, this requires <random>
uniform_int_distribution<int> dieroller(1, 6);
vector<int> hist(7);
int NROLL = 10000;
for(int i=0; i<NROLL; ++i){
int roll = dieroller(e5);
hist[roll]++;
}
double chisq = 0.;
double expected = NROLL/6.;
double var = NROLL*5./36.;
for(int pips=1; pips<=6; ++pips){
double delta = hist[pips] - expected;
chisq += delta*delta/var;
}
// The critical value of chisq with 6 degrees of freedom
// for P=0.01 is 16.81. For P=0.05, it is 12.59
const double chicrit = 12.59;
if( chisq > chicrit ){
printf("std::uniform_int_distribution doesn't look random. Chisq = %g. Does this look like the result of a fair set of dice rolls to you?\n", chisq);
for(int pips=1; pips<=6; ++pips){
printf("%d pips %d times\n", pips, hist[pips]);
}
abort(); // a bit harsh, no? It might just be a rare event at the 5% level...
}
#endif
// Finally do a kat test.
EType ekat;
ekat.discard(1000);
typename EType::result_type r = ekat();
typename EType::result_type knownanswer = kat1000<EType>();
if( knownanswer != 0 && r != knownanswer )
cerr << "KAT mismatch. The 1000th random from " << demangle(ekat) << " is " << r << " it should be " << knownanswer << "\n";
assert( knownanswer==0 || r == knownanswer );
cout << " OK" << endl;
}
int main(int, char **){
#if R123_USE_PHILOX_64BIT
doit<Engine<Philox2x64 > >();
doit<Engine<ReinterpretCtr<r123array4x32, Philox2x64 > > >();
#endif
doit<Engine<Philox4x32 > >();
doit<Engine<Threefry2x64 > >();
doit<Engine<Threefry4x32 > >();
doit<Engine<ReinterpretCtr<r123array4x32, Threefry2x64 > > >();
doit<Engine<ReinterpretCtr<r123array2x64, Threefry4x32 > > >();
#if R123_USE_AES_NI
if( haveAESNI() ){
doit<Engine<ARS4x32> >();
doit<Engine<ReinterpretCtr<r123array2x64, ARS4x32> > >();
doit<Engine<AESNI4x32> >();
}else{
cout << "AES is compiled into the binary, but is not available on this hardware\n";
}
#endif
#if R123_USE_AES_OPENSSL
doit<Engine<AESOpenSSL16x8> >();
#endif
cout << "ut_Engine: all OK" << endl;
return 0;
}
|