Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/scipy/optimize/_shgo_lib/sobol_seq.py : 7%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2 Licensing:
3 This code is distributed under the MIT license.
6 Authors:
7 Original FORTRAN77 version of i4_sobol by Bennett Fox.
8 MATLAB version by John Burkardt.
9 PYTHON version by Corrado Chisari
11 Original Python version of is_prime by Corrado Chisari
13 Original MATLAB versions of other functions by John Burkardt.
14 PYTHON versions by Corrado Chisari
16 Original code is available from
17 http://people.sc.fsu.edu/~jburkardt/py_src/sobol/sobol.html
19 Modifications:
20 Wrapped into Python class [30.10.2017]
21"""
22import numpy as np
24__all__ = ['Sobol']
27class Sobol:
28 def __init__(self):
29 # Init class variables
30 self.atmost = None
31 self.dim_max = None
32 self.dim_num_save = None
33 self.initialized = None
34 self.lastq = None
35 self.log_max = None
36 self.maxcol = None
37 self.poly = None
38 self.recipd = None
39 self.seed_save = None
40 self.v = None
42 def i4_sobol_generate(self, dim_num, n, skip=1):
43 """
44 i4_sobol_generate generates a Sobol dataset.
46 Parameters:
47 Input, integer dim_num, the spatial dimension.
48 Input, integer N, the number of points to generate.
49 Input, integer SKIP, the number of initial points to skip.
51 Output, real R(M,N), the points.
52 """
53 r = np.full((n, dim_num), np.nan)
54 for j in range(n):
55 seed = j + skip
56 r[j, 0:dim_num], next_seed = self.i4_sobol(dim_num, seed)
58 return r
60 def i4_bit_hi1(self, n):
61 """
62 i4_bit_hi1 returns the position of the high 1 bit base 2 in an integer.
64 Example:
65 +------+-------------+-----
66 | N | Binary | BIT
67 +------|-------------+-----
68 | 0 | 0 | 0
69 | 1 | 1 | 1
70 | 2 | 10 | 2
71 | 3 | 11 | 2
72 | 4 | 100 | 3
73 | 5 | 101 | 3
74 | 6 | 110 | 3
75 | 7 | 111 | 3
76 | 8 | 1000 | 4
77 | 9 | 1001 | 4
78 | 10 | 1010 | 4
79 | 11 | 1011 | 4
80 | 12 | 1100 | 4
81 | 13 | 1101 | 4
82 | 14 | 1110 | 4
83 | 15 | 1111 | 4
84 | 16 | 10000 | 5
85 | 17 | 10001 | 5
86 | 1023 | 1111111111 | 10
87 | 1024 | 10000000000 | 11
88 | 1025 | 10000000001 | 11
90 Parameters:
91 Input, integer N, the integer to be measured.
92 N should be nonnegative. If N is nonpositive,
93 the value will always be 0.
95 Output, integer BIT, the number of bits base 2.
96 """
97 i = np.floor(n)
98 bit = 0
99 while i > 0:
100 bit += 1
101 i //= 2
102 return bit
104 def i4_bit_lo0(self, n):
105 """
106 I4_BIT_LO0 returns the position of the low 0 bit base 2 in an integer.
108 Example:
109 +------+------------+----
110 | N | Binary | BIT
111 +------+------------+----
112 | 0 | 0 | 1
113 | 1 | 1 | 2
114 | 2 | 10 | 1
115 | 3 | 11 | 3
116 | 4 | 100 | 1
117 | 5 | 101 | 2
118 | 6 | 110 | 1
119 | 7 | 111 | 4
120 | 8 | 1000 | 1
121 | 9 | 1001 | 2
122 | 10 | 1010 | 1
123 | 11 | 1011 | 3
124 | 12 | 1100 | 1
125 | 13 | 1101 | 2
126 | 14 | 1110 | 1
127 | 15 | 1111 | 5
128 | 16 | 10000 | 1
129 | 17 | 10001 | 2
130 | 1023 | 1111111111 | 1
131 | 1024 | 0000000000 | 1
132 | 1025 | 0000000001 | 1
134 Parameters:
135 Input, integer N, the integer to be measured.
136 N should be nonnegative.
138 Output, integer BIT, the position of the low 1 bit.
139 """
140 bit = 1
141 i = np.floor(n)
142 while i != 2 * (i // 2):
143 bit += 1
144 i //= 2
145 return bit
147 def i4_sobol(self, dim_num, seed):
148 """
149 i4_sobol generates a new quasirandom Sobol vector with each call.
151 Discussion:
152 The routine adapts the ideas of Antonov and Saleev.
154 Reference:
155 Antonov, Saleev,
156 USSR Computational Mathematics and Mathematical Physics,
157 Volume 19, 1980, pages 252 - 256.
159 Paul Bratley, Bennett Fox,
160 Algorithm 659:
161 Implementing Sobol's Quasirandom Sequence Generator,
162 ACM Transactions on Mathematical Software,
163 Volume 14, Number 1, pp. 88-100, 1988.
165 Bennett Fox,
166 Algorithm 647:
167 Implementation and Relative Efficiency of Quasirandom
168 Sequence Generators,
169 ACM Transactions on Mathematical Software,
170 Volume 12, Number 4, pp. 362-376, 1986.
172 Ilya Sobol,
173 USSR Computational Mathematics and Mathematical Physics,
174 Volume 16, pp. 236-242, 1977.
176 Ilya Sobol, Levitan,
177 The Production of Points Uniformly Distributed in a Multidimensional
178 Cube (in Russian),
179 Preprint IPM Akad. Nauk SSSR,
180 Number 40, Moscow 1976.
182 Parameters:
183 Input, integer DIM_NUM, the number of spatial dimensions.
184 DIM_NUM must satisfy 1 <= DIM_NUM <= 40.
186 Input/output, integer SEED, the "seed" for the sequence.
187 This is essentially the index in the sequence of the quasirandom
188 value to be generated. On output, SEED has been set to the
189 appropriate next value, usually simply SEED+1.
190 If SEED is less than 0 on input, it is treated as though it were 0.
191 An input value of 0 requests the first (0th) element of the sequence.
193 Output, real QUASI(DIM_NUM), the next quasirandom vector.
194 """
196 # if 'self.initialized' not in list(globals().keys()):
197 if self.initialized is None:
198 self.initialized = 0
199 self.dim_num_save = -1
201 if not self.initialized or dim_num != self.dim_num_save:
202 self.initialized = 1
203 self.dim_max = 40
204 self.dim_num_save = -1
205 self.log_max = 30
206 self.seed_save = -1
208 # Initialize (part of) V.
209 self.v = np.zeros((self.dim_max, self.log_max))
210 self.v[0:40, 0] = np.transpose([
211 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
212 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
213 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
214 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
216 self.v[2:40, 1] = np.transpose([
217 1, 3, 1, 3, 1, 3, 3, 1,
218 3, 1, 3, 1, 3, 1, 1, 3, 1, 3,
219 1, 3, 1, 3, 3, 1, 3, 1, 3, 1,
220 3, 1, 1, 3, 1, 3, 1, 3, 1, 3])
222 self.v[3:40, 2] = np.transpose([
223 7, 5, 1, 3, 3, 7, 5,
224 5, 7, 7, 1, 3, 3, 7, 5, 1, 1,
225 5, 3, 3, 1, 7, 5, 1, 3, 3, 7,
226 5, 1, 1, 5, 7, 7, 5, 1, 3, 3])
228 self.v[5:40, 3] = np.transpose([
229 1, 7, 9, 13, 11,
230 1, 3, 7, 9, 5, 13, 13, 11, 3, 15,
231 5, 3, 15, 7, 9, 13, 9, 1, 11, 7,
232 5, 15, 1, 15, 11, 5, 3, 1, 7, 9])
234 self.v[7:40, 4] = np.transpose([
235 9, 3, 27,
236 15, 29, 21, 23, 19, 11, 25, 7, 13, 17,
237 1, 25, 29, 3, 31, 11, 5, 23, 27, 19,
238 21, 5, 1, 17, 13, 7, 15, 9, 31, 9])
240 self.v[13:40, 5] = np.transpose([
241 37, 33, 7, 5, 11, 39, 63,
242 27, 17, 15, 23, 29, 3, 21, 13, 31, 25,
243 9, 49, 33, 19, 29, 11, 19, 27, 15, 25])
245 self.v[19:40, 6] = np.transpose([
246 13,
247 33, 115, 41, 79, 17, 29, 119, 75, 73, 105,
248 7, 59, 65, 21, 3, 113, 61, 89, 45, 107])
250 self.v[37:40, 7] = np.transpose([
251 7, 23, 39])
253 # Set POLY.
254 self.poly = [
255 1, 3, 7, 11, 13, 19, 25, 37, 59, 47,
256 61, 55, 41, 67, 97, 91, 109, 103, 115, 131,
257 193, 137, 145, 143, 241, 157, 185, 167, 229, 171,
258 213, 191, 253, 203, 211, 239, 247, 285, 369, 299]
260 self.atmost = 2 ** self.log_max - 1
262 # Find the number of bits in ATMOST.
263 self.maxcol = self.i4_bit_hi1(self.atmost)
265 # Initialize row 1 of V.
266 self.v[0, 0:self.maxcol] = 1
268 # Things to do only if the dimension changed.
269 if dim_num != self.dim_num_save:
270 self.dim_num_save = dim_num
272 # Initialize the remaining rows of V.
273 for i in range(2, dim_num + 1):
275 # The bits of the integer POLY(I) gives the form of
276 # self.polynomial I.
277 # Find the degree of self.polynomial I from binary encoding.
278 j = self.poly[i - 1]
279 m = 0
280 j //= 2
281 while j > 0:
282 j //= 2
283 m += 1
285 # Expand this bit pattern to separate
286 # components of the logical array INCLUD.
287 j = self.poly[i - 1]
288 includ = np.zeros(m)
289 for k in range(m, 0, -1):
290 j2 = j // 2
291 includ[k - 1] = (j != 2 * j2)
292 j = j2
294 # Calculate the remaining elements of row I as explained
295 # in Bratley and Fox, section 2.
296 for j in range(m + 1, self.maxcol + 1):
297 newv = self.v[i - 1, j - m - 1]
298 lseed = 1
299 for k in range(1, m + 1):
300 lseed *= 2
301 if includ[k - 1]:
302 newv = np.bitwise_xor(
303 int(newv),
304 int(lseed * self.v[i - 1, j - k - 1]))
305 self.v[i - 1, j - 1] = newv
307 # Multiply columns of V by appropriate power of 2.
308 lseed = 1
309 for j in range(self.maxcol - 1, 0, -1):
310 lseed *= 2
311 self.v[0:dim_num, j - 1] = self.v[0:dim_num, j - 1] * lseed
313 # RECIPD is 1/(common denominator of the elements in V).
314 self.recipd = 1.0 / (2 * lseed)
315 self.lastq = np.zeros(dim_num)
317 seed = int(np.floor(seed))
319 if seed < 0:
320 seed = 0
322 lseed = 1
323 if seed == 0:
324 self.lastq = np.zeros(dim_num)
326 elif seed == self.seed_save + 1:
328 # Find the position of the right-hand zero in SEED.
329 lseed = self.i4_bit_lo0(seed)
331 elif seed <= self.seed_save:
333 self.seed_save = 0
334 self.lastq = np.zeros(dim_num)
336 for seed_temp in range(int(self.seed_save), int(seed)):
337 lseed = self.i4_bit_lo0(seed_temp)
338 for i in range(1, dim_num + 1):
339 self.lastq[i - 1] = np.bitwise_xor(
340 int(self.lastq[i - 1]), int(self.v[i - 1, lseed - 1]))
342 lseed = self.i4_bit_lo0(seed)
344 elif self.seed_save + 1 < seed:
346 for seed_temp in range(int(self.seed_save + 1), int(seed)):
347 lseed = self.i4_bit_lo0(seed_temp)
348 for i in range(1, dim_num + 1):
349 self.lastq[i - 1] = np.bitwise_xor(
350 int(self.lastq[i - 1]), int(self.v[i - 1, lseed - 1]))
352 lseed = self.i4_bit_lo0(seed)
354 # Check that the user is not calling too many times!
355 if self.maxcol < lseed:
356 print('I4_SOBOL - Fatal error!')
357 print(' Too many calls!')
358 print(' MAXCOL = %d\n' % self.maxcol)
359 print(' L = %d\n' % lseed)
360 return
362 # Calculate the new components of QUASI.
363 quasi = np.zeros(dim_num)
364 for i in range(1, dim_num + 1):
365 quasi[i - 1] = self.lastq[i - 1] * self.recipd
366 self.lastq[i - 1] = np.bitwise_xor(
367 int(self.lastq[i - 1]), int(self.v[i - 1, lseed - 1]))
369 self.seed_save = seed
370 seed += 1
372 return [quasi, seed]