1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.math4.legacy.random;
18
19 import java.io.BufferedReader;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.InputStreamReader;
23 import java.nio.charset.Charset;
24 import java.util.Arrays;
25 import java.util.NoSuchElementException;
26 import java.util.StringTokenizer;
27 import java.util.function.Supplier;
28
29 import org.apache.commons.math4.legacy.exception.MathInternalError;
30 import org.apache.commons.math4.legacy.exception.MathParseException;
31 import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException;
32 import org.apache.commons.math4.legacy.exception.OutOfRangeException;
33 import org.apache.commons.math4.core.jdkmath.JdkMath;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 public class SobolSequenceGenerator implements Supplier<double[]> {
57
58 private static final int BITS = 52;
59
60
61 private static final double SCALE = JdkMath.pow(2, BITS);
62
63
64 private static final int MAX_DIMENSION = 21201;
65
66
67 private static final String RESOURCE_NAME = "/assets/org/apache/commons/math4/legacy/random/new-joe-kuo-6.21201";
68
69
70 private static final String FILE_CHARSET = "US-ASCII";
71
72
73 private final int dimension;
74
75
76 private int count;
77
78
79 private final long[][] direction;
80
81
82 private final long[] x;
83
84
85
86
87
88
89
90 public SobolSequenceGenerator(final int dimension) {
91 if (dimension < 1 || dimension > MAX_DIMENSION) {
92 throw new OutOfRangeException(dimension, 1, MAX_DIMENSION);
93 }
94
95
96 final InputStream is = getClass().getResourceAsStream(RESOURCE_NAME);
97 if (is == null) {
98 throw new MathInternalError();
99 }
100
101 this.dimension = dimension;
102
103
104 direction = new long[dimension][BITS + 1];
105 x = new long[dimension];
106
107 try {
108 initFromStream(is);
109 } catch (IOException e) {
110
111 throw new MathInternalError();
112 } catch (MathParseException e) {
113
114 throw new MathInternalError();
115 } finally {
116 try {
117 is.close();
118 } catch (IOException e) {
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 public SobolSequenceGenerator(final int dimension, final InputStream is)
156 throws IOException {
157 if (dimension < 1) {
158 throw new NotStrictlyPositiveException(dimension);
159 }
160
161 this.dimension = dimension;
162
163
164 direction = new long[dimension][BITS + 1];
165 x = new long[dimension];
166
167
168 int lastDimension = initFromStream(is);
169 if (lastDimension < dimension) {
170 throw new OutOfRangeException(dimension, 1, lastDimension);
171 }
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185 private int initFromStream(final InputStream is) throws IOException {
186
187 for (int i = 1; i <= BITS; i++) {
188 direction[0][i] = 1L << (BITS - i);
189 }
190
191 final Charset charset = Charset.forName(FILE_CHARSET);
192 final BufferedReader reader = new BufferedReader(new InputStreamReader(is, charset));
193 int dim = -1;
194
195 try {
196
197 reader.readLine();
198
199 int lineNumber = 2;
200 int index = 1;
201 String line = null;
202 while ( (line = reader.readLine()) != null) {
203 StringTokenizer st = new StringTokenizer(line, " ");
204 try {
205 dim = Integer.parseInt(st.nextToken());
206 if (dim >= 2 && dim <= dimension) {
207 final int s = Integer.parseInt(st.nextToken());
208 final int a = Integer.parseInt(st.nextToken());
209 final int[] m = new int[s + 1];
210 for (int i = 1; i <= s; i++) {
211 m[i] = Integer.parseInt(st.nextToken());
212 }
213 initDirectionVector(index++, a, m);
214 }
215
216 if (dim > dimension) {
217 return dim;
218 }
219 } catch (NoSuchElementException e) {
220 throw new MathParseException(line, lineNumber);
221 } catch (NumberFormatException e) {
222 throw new MathParseException(line, lineNumber);
223 }
224 lineNumber++;
225 }
226 } finally {
227 reader.close();
228 }
229
230 return dim;
231 }
232
233
234
235
236
237
238
239
240 private void initDirectionVector(final int d, final int a, final int[] m) {
241 final int s = m.length - 1;
242 for (int i = 1; i <= s; i++) {
243 direction[d][i] = ((long) m[i]) << (BITS - i);
244 }
245 for (int i = s + 1; i <= BITS; i++) {
246 direction[d][i] = direction[d][i - s] ^ (direction[d][i - s] >> s);
247 for (int k = 1; k <= s - 1; k++) {
248 direction[d][i] ^= ((a >> (s - 1 - k)) & 1) * direction[d][i - k];
249 }
250 }
251 }
252
253
254 @Override
255 public double[] get() {
256 final double[] v = new double[dimension];
257 if (count == 0) {
258 count++;
259 return v;
260 }
261
262
263 int c = 1;
264 int value = count - 1;
265 while ((value & 1) == 1) {
266 value >>= 1;
267 c++;
268 }
269
270 for (int i = 0; i < dimension; i++) {
271 x[i] ^= direction[i][c];
272 v[i] = (double) x[i] / SCALE;
273 }
274 count++;
275 return v;
276 }
277
278
279
280
281
282
283
284
285
286
287 public double[] skipTo(final int index) {
288 if (index == 0) {
289
290 Arrays.fill(x, 0);
291 } else {
292 final int i = index - 1;
293 final long grayCode = i ^ (i >> 1);
294 for (int j = 0; j < dimension; j++) {
295 long result = 0;
296 for (int k = 1; k <= BITS; k++) {
297 final long shift = grayCode >> (k - 1);
298 if (shift == 0) {
299
300 break;
301 }
302
303 final long ik = shift & 1;
304 result ^= ik * direction[j][k];
305 }
306 x[j] = result;
307 }
308 }
309 count = index;
310 return get();
311 }
312
313
314
315
316
317
318
319 public int getNextIndex() {
320 return count;
321 }
322 }