-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathqrng.py
More file actions
159 lines (153 loc) · 5.26 KB
/
Copy pathqrng.py
File metadata and controls
159 lines (153 loc) · 5.26 KB
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
""" Interfaces to quasi-random sequences in C"""
import ctypes
import numpy
import os
path = os.path.dirname(os.path.abspath(__file__))+'/src/'
lib = ctypes.CDLL(path+'library.so',mode=ctypes.RTLD_GLOBAL)
# MRG63k3a
mrg63ka_f = lib.MRG63k3a
mrg63ka_f.argtypes = None
mrg63ka_f.restype = ctypes.c_double
# korobov
korobov_f = lib.korobov
korobov_f.argtypes = [
ctypes.c_int, # n
ctypes.c_int, # d
numpy.ctypeslib.ndpointer(ctypes.c_int,flags='C_CONTIGUOUS'), # generator
ctypes.c_int, # randomize
numpy.ctypeslib.ndpointer(ctypes.c_double,flags='C_CONTIGUOUS'), # res
ctypes.c_long] # seed
korobov_f.restype = None
# ghalton
ghalton_f = lib.ghalton
ghalton_f.argtypes = [
ctypes.c_int, # n
ctypes.c_int, # d
ctypes.c_int, # generalized
numpy.ctypeslib.ndpointer(ctypes.c_double,flags='C_CONTIGUOUS'), # res
ctypes.c_long] # seed
ghalton_f.restype = None
# sobol
sobol_f = lib.sobol
sobol_f.argtypes = [
ctypes.c_int, # n
ctypes.c_int, # d
ctypes.c_int, # randomize
numpy.ctypeslib.ndpointer(ctypes.c_double,flags='C_CONTIGUOUS'), # res
ctypes.c_int, # skip
ctypes.c_long] # seed
sobol_f.restype = None
def korobov_qrng(n,d,generator,randomize,seed):
"""
Korobov's sequence
Args:
n (int): number of points (>= 2 as generator has to be in {1,..,n-1}
d (int): dimension
generator (ndarray of ints): generator in {1,..,n-1}
either a vector of length d
or a single number (which is appropriately extended)
randomize (boolean): random shift
seed (int): random number generator seed
Return:
result (ndarray): (n, d)-matrix containing the quasi-random sequence
"""
generator = numpy.array(generator,dtype=numpy.int32)
l = len(generator)
if not (n >= 2 and d >= 1 and (l == 1 or l == d) and \
(generator>=1).all() and (generator<=(n-1)).all()):
raise Exception('korobov_qrng input error')
lim = 2**31-1
if n > lim:
raise Exception('n must be <=2^32-1')
if d > lim:
raise Exception('d must be <=2^31-1')
if l==1:
generator = (generator**numpy.arange(d,dtype=numpy.int32))%n
res = numpy.zeros((d,n),dtype=numpy.double)
korobov_f(n,d,generator,randomize,res,seed)
return res.T
def ghalton_qrng(n,d,generalize,seed):
"""
Generalized Halton sequence
Args:
n (int): number of points
d (int): dimension
generalize (bool): string indicating which sequence is generated
(generalized Halton (1) or (plain) Halton (0))
seed (int): random number generator seed
Return:
res (ndarray): an (n, d)-matrix containing the quasi-random sequence
"""
if not( n >= 1 and d >= 1):
raise Exception('ghalton_qrng input error')
if n > (2**32-1):
raise Exception('n must be <= 2^32-1')
if d > 360:
raise Exception('d must be <= 360')
res = numpy.zeros((d,n),dtype=numpy.double)
ghalton_f(n,d,generalize,res,seed)
return res.T
def sobol_qrng(n,d,scramble,skip,seed):
"""
Sobol sequence
Args:
n (int): number of points
d (int): dimension
randomize (boolean): apply digital shift scramble
skip (int): number of initial points in the sequence to skip.
Return:
res (ndarray): an (n, d)-matrix containing the quasi-random sequence
"""
if not (n >= 1 and d >= 1 and skip >= 0):
raise Exception('sobol_qrng input error')
if n > (2**31-1):
raise Exception('n must be <= 2^32-1')
if d > 16510:
raise Exception('d must be <= 16510')
res = numpy.zeros((d,n),dtype=numpy.double)
sobol_f(n,d,scramble,res,skip,seed)
return res.T
if __name__ == '__main__':
import time
# constants
n = 2**11
d = 2
randomize = True
seed = 7
plot = True
# generate points
# MRG63k3a
t0 = time.perf_counter()
mrg63ka_pts = numpy.array([mrg63ka_f() for i in range(n*d)]).reshape((n,d))
mrg63ka_t = time.perf_counter() - t0
# korobov
t0 = time.perf_counter()
korobov_pts = korobov_qrng(n,d,generator=[2],randomize=randomize,seed=seed)
korobov_t = time.perf_counter() - t0
# ghalton
t0 = time.perf_counter()
ghalton_pts = ghalton_qrng(n,d,generalize=True,seed=seed)
ghalton_t = time.perf_counter() - t0
# sobol
t0 = time.perf_counter()
sobol_pts = sobol_qrng(n,d,scramble=randomize,skip=0,seed=7)
sobol_t = time.perf_counter() - t0
# outputs
from matplotlib import pyplot
fig,ax = pyplot.subplots(nrows=1,ncols=4,figsize=(10,3))
for i,(name,pts,time) in enumerate(zip(
['MRG63k3a', 'Korobov', 'GHalton', 'Sobol'],
[mrg63ka_pts, korobov_pts, ghalton_pts, sobol_pts],
[mrg63ka_t, korobov_t, ghalton_t, sobol_t])):
print('%s Points in %.3f sec'%(name,time))
print('\t'+str(pts).replace('\n','\n\t'))
if plot and d==2:
ax[i].scatter(pts[:,0],pts[:,1],s=.5)
ax[i].set_xlim([0,1])
ax[i].set_ylim([0,1])
ax[i].set_aspect('equal')
ax[i].set_title('%s Points'%name)
if plot and d==2:
fig.suptitle('qrng points with n=%d, d=%d, randomize=%s'%(n,d,randomize))
fig.tight_layout()
pyplot.show()