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