1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.rng.sampling.shape;
18
19 import java.util.Arrays;
20 import org.apache.commons.math3.stat.inference.ChiSquareTest;
21 import org.apache.commons.rng.UniformRandomProvider;
22 import org.apache.commons.rng.sampling.RandomAssert;
23 import org.apache.commons.rng.sampling.UnitSphereSampler;
24 import org.junit.jupiter.api.Assertions;
25 import org.junit.jupiter.api.Test;
26
27
28
29
30 class LineSamplerTest {
31
32
33
34 @Test
35 void testInvalidDimensionThrows() {
36 final UniformRandomProvider rng = RandomAssert.seededRNG();
37 Assertions.assertThrows(IllegalArgumentException.class,
38 () -> LineSampler.of(rng, new double[0], new double[0]));
39 }
40
41
42
43
44 @Test
45 void testDimensionMismatchThrows() {
46 final UniformRandomProvider rng = RandomAssert.seededRNG();
47 final double[] c2 = new double[2];
48 final double[] c3 = new double[3];
49 for (double[][] c : new double[][][] {
50 {c2, c3},
51 {c3, c2},
52 }) {
53 Assertions.assertThrows(IllegalArgumentException.class,
54 () -> LineSampler.of(rng, c[0], c[1]),
55 () -> String.format("Did not detect dimension mismatch: %d,%d",
56 c[0].length, c[1].length));
57 }
58 }
59
60
61
62
63 @Test
64 void testNonFiniteVertexCoordinates() {
65 final UniformRandomProvider rng = RandomAssert.seededRNG();
66
67 final double[][] c = new double[][] {
68 {0, 1, 2}, {-1, 2, 3}
69 };
70 Assertions.assertNotNull(LineSampler.of(rng, c[0], c[1]));
71 final double[] bad = {Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NaN};
72 for (int i = 0; i < c.length; i++) {
73 final int ii = i;
74 for (int j = 0; j < c[0].length; j++) {
75 final int jj = j;
76 for (final double d : bad) {
77 final double value = c[i][j];
78 c[i][j] = d;
79 Assertions.assertThrows(IllegalArgumentException.class,
80 () -> LineSampler.of(rng, c[0], c[1]),
81 () -> String.format("Did not detect non-finite coordinate: %d,%d = %s",
82 ii, jj, d));
83 c[i][j] = value;
84 }
85 }
86 }
87 }
88
89
90
91
92
93 @Test
94 void testExtremeValueCoordinates1D() {
95 testExtremeValueCoordinates(1);
96 }
97
98
99
100
101
102 @Test
103 void testExtremeValueCoordinates2D() {
104 testExtremeValueCoordinates(2);
105 }
106
107
108
109
110
111 @Test
112 void testExtremeValueCoordinates3D() {
113 testExtremeValueCoordinates(3);
114 }
115
116
117
118
119
120 @Test
121 void testExtremeValueCoordinates4D() {
122 testExtremeValueCoordinates(4);
123 }
124
125
126
127
128
129
130
131 private static void testExtremeValueCoordinates(int dimension) {
132 final double[][] c1 = new double[2][dimension];
133 final double[][] c2 = new double[2][dimension];
134
135 Arrays.fill(c1[0], -1);
136 Arrays.fill(c1[1], 1);
137
138 final double scale = 0x1.0p1023;
139 for (int i = 0; i < c1.length; i++) {
140
141 for (int j = 0; j < dimension; j++) {
142 c2[i][j] = c1[i][j] * scale;
143 }
144 }
145
146 Assertions.assertEquals(Double.POSITIVE_INFINITY, c2[1][0] - c2[0][0],
147 "Expect vector b - a to be infinite in the x dimension");
148
149 final LineSampler sampler1 = LineSampler.of(
150 RandomAssert.seededRNG(), c1[0], c1[1]);
151 final LineSampler sampler2 = LineSampler.of(
152 RandomAssert.seededRNG(), c2[0], c2[1]);
153
154 for (int n = 0; n < 10; n++) {
155 final double[] a = sampler1.sample();
156 final double[] b = sampler2.sample();
157 for (int i = 0; i < a.length; i++) {
158 a[i] *= scale;
159 }
160 Assertions.assertArrayEquals(a, b);
161 }
162 }
163
164
165
166
167 @Test
168 void testDistribution1D() {
169 testDistributionND(1);
170 }
171
172
173
174
175 @Test
176 void testDistribution2D() {
177 testDistributionND(2);
178 }
179
180
181
182
183 @Test
184 void testDistribution3D() {
185 testDistributionND(3);
186 }
187
188
189
190
191 @Test
192 void testDistribution4D() {
193 testDistributionND(4);
194 }
195
196
197
198
199
200
201
202 private static void testDistributionND(int dimension) {
203 final UniformRandomProvider rng = RandomAssert.createRNG();
204
205 double[] a;
206 double[] b;
207 if (dimension == 1) {
208 a = new double[] {rng.nextDouble()};
209 b = new double[] {-rng.nextDouble()};
210 } else {
211 final UnitSphereSampler sphere = UnitSphereSampler.of(rng, dimension);
212 a = sphere.sample();
213 b = sphere.sample();
214 }
215
216
217
218
219
220
221
222
223 final double[] scale = new double[dimension];
224 for (int i = 0; i < dimension; i++) {
225 scale[i] = 1.0 / (b[i] - a[i]);
226 }
227
228
229 final int bins = 100;
230 final int samplesPerBin = 20;
231
232
233 final double[] expected = new double[bins];
234 Arrays.fill(expected, 1.0 / bins);
235
236
237 final LineSampler sampler = LineSampler.of(rng, a, b);
238 final int samples = expected.length * samplesPerBin;
239 for (int n = 0; n < 1; n++) {
240
241 final long[] observed = new long[expected.length];
242 for (int i = 0; i < samples; i++) {
243 final double[] x = sampler.sample();
244 Assertions.assertEquals(dimension, x.length);
245 final double c = (x[0] - a[0]) * scale[0];
246 Assertions.assertTrue(c >= 0.0 && c <= 1.0, "Not uniformly distributed");
247 for (int j = 1; j < dimension; j++) {
248 Assertions.assertEquals(c, (x[j] - a[j]) * scale[j], 1e-14, "Not on the line");
249 }
250
251 observed[(int) (c * bins)]++;
252 }
253 final double p = new ChiSquareTest().chiSquareTest(expected, observed);
254 Assertions.assertFalse(p < 0.001, () -> "p-value too small: " + p);
255 }
256 }
257
258
259
260
261 @Test
262 void testSharedStateSampler1D() {
263 testSharedStateSampler(1);
264 }
265
266
267
268
269 @Test
270 void testSharedStateSampler2D() {
271 testSharedStateSampler(2);
272 }
273
274
275
276
277 @Test
278 void testSharedStateSampler3D() {
279 testSharedStateSampler(3);
280 }
281
282
283
284
285 @Test
286 void testSharedStateSampler4D() {
287 testSharedStateSampler(4);
288 }
289
290
291
292
293 private static void testSharedStateSampler(int dimension) {
294 final UniformRandomProvider rng1 = RandomAssert.seededRNG();
295 final UniformRandomProvider rng2 = RandomAssert.seededRNG();
296 final double[] c1 = createCoordinate(1, dimension);
297 final double[] c2 = createCoordinate(2, dimension);
298 final LineSampler sampler1 = LineSampler.of(rng1, c1, c2);
299 final LineSampler sampler2 = sampler1.withUniformRandomProvider(rng2);
300 RandomAssert.assertProduceSameSequence(sampler1, sampler2);
301 }
302
303
304
305
306 @Test
307 void testChangedInputCoordinates1D() {
308 testChangedInputCoordinates(1);
309 }
310
311
312
313
314 @Test
315 void testChangedInputCoordinates2D() {
316 testChangedInputCoordinates(2);
317 }
318
319
320
321
322 @Test
323 void testChangedInputCoordinates3D() {
324 testChangedInputCoordinates(3);
325 }
326
327
328
329
330 @Test
331 void testChangedInputCoordinates4D() {
332 testChangedInputCoordinates(4);
333 }
334
335
336
337
338
339
340
341 private static void testChangedInputCoordinates(int dimension) {
342 final UniformRandomProvider rng1 = RandomAssert.seededRNG();
343 final UniformRandomProvider rng2 = RandomAssert.seededRNG();
344 final double[] c1 = createCoordinate(1, dimension);
345 final double[] c2 = createCoordinate(2, dimension);
346 final LineSampler sampler1 = LineSampler.of(rng1, c1, c2);
347
348
349
350 final double offset = 10;
351 for (int i = 0; i < dimension; i++) {
352 c1[i] += offset;
353 c2[i] += offset;
354 }
355 final LineSampler sampler2 = LineSampler.of(rng2, c1, c2);
356 for (int n = 0; n < 3; n++) {
357 final double[] s1 = sampler1.sample();
358 final double[] s2 = sampler2.sample();
359 Assertions.assertEquals(s1.length, s2.length);
360 Assertions.assertFalse(Arrays.equals(s1, s2),
361 "First sampler has used the vertices by reference");
362 for (int i = 0; i < dimension; i++) {
363 Assertions.assertEquals(s1[i] + offset, s2[i], 1e-10);
364 }
365 }
366 }
367
368
369
370
371
372
373
374
375
376 private static double[] createCoordinate(double x, int dimension) {
377 final double[] coord = new double[dimension];
378 for (int i = 0; i < dimension; i++) {
379 coord[0] = x + i;
380 }
381 return coord;
382 }
383 }