1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.rng.examples.jmh.sampling.shape;
19
20 import org.apache.commons.rng.UniformRandomProvider;
21 import org.apache.commons.rng.sampling.ObjectSampler;
22 import org.apache.commons.rng.sampling.UnitSphereSampler;
23 import org.apache.commons.rng.simple.RandomSource;
24 import org.openjdk.jmh.annotations.Benchmark;
25 import org.openjdk.jmh.annotations.BenchmarkMode;
26 import org.openjdk.jmh.annotations.Fork;
27 import org.openjdk.jmh.annotations.Level;
28 import org.openjdk.jmh.annotations.Measurement;
29 import org.openjdk.jmh.annotations.Mode;
30 import org.openjdk.jmh.annotations.OutputTimeUnit;
31 import org.openjdk.jmh.annotations.Param;
32 import org.openjdk.jmh.annotations.Scope;
33 import org.openjdk.jmh.annotations.Setup;
34 import org.openjdk.jmh.annotations.State;
35 import org.openjdk.jmh.annotations.Warmup;
36 import org.openjdk.jmh.infra.Blackhole;
37 import java.util.concurrent.TimeUnit;
38
39
40
41
42 @BenchmarkMode(Mode.AverageTime)
43 @OutputTimeUnit(TimeUnit.NANOSECONDS)
44 @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
45 @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
46 @State(Scope.Benchmark)
47 @Fork(value = 1, jvmArgs = { "-server", "-Xms512M", "-Xmx512M" })
48 public class TetrahedronSamplerBenchmark {
49
50 private static final String BASELINE = "Baseline";
51
52 private static final String ARRAY = "Array";
53
54 private static final String NON_ARRAY = "NonArray";
55
56 private static final String ARRAY_INLINE = "ArrayInline";
57
58 private static final String NON_ARRAY_INLINE = "NonArrayInline";
59
60 private static final String UNKNOWN_SAMPLER = "Unknown sampler type: ";
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 private abstract static class TetrahedronSampler implements ObjectSampler<double[]> {
80
81 private final UniformRandomProvider rng;
82
83
84
85
86 TetrahedronSampler(UniformRandomProvider rng) {
87 this.rng = rng;
88 }
89
90 @Override
91 public double[] sample() {
92 double s = rng.nextDouble();
93 double t = rng.nextDouble();
94 final double u = rng.nextDouble();
95
96
97
98
99
100
101
102
103
104 if (s + t > 1) {
105
106 s = 1 - s;
107 t = 1 - t;
108 }
109
110
111 final double tpu = t + u;
112 final double sptpu = s + tpu;
113 if (sptpu > 1) {
114 if (tpu > 1) {
115
116
117 return createSample(u - 1 + t, s, 1 - u, 1 - s - t);
118 }
119
120
121 return createSample(1 - s - t, 1 - tpu, t, s - 1 + tpu);
122 }
123 return createSample(1 - sptpu, s, t, u);
124 }
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141 protected abstract double[] createSample(double p1msmtmu, double s, double t, double u);
142 }
143
144
145
146
147 private static class ArrayTetrahedronSampler extends TetrahedronSampler {
148
149 private final double[] a;
150 private final double[] b;
151 private final double[] c;
152 private final double[] d;
153
154
155
156
157
158
159
160
161
162 ArrayTetrahedronSampler(UniformRandomProvider rng,
163 double[] a, double[] b, double[] c, double[] d) {
164 super(rng);
165 this.a = a.clone();
166 this.b = b.clone();
167 this.c = c.clone();
168 this.d = d.clone();
169 }
170
171 @Override
172 protected double[] createSample(double p1msmtmu, double s, double t, double u) {
173 return new double[] {p1msmtmu * a[0] + s * b[0] + t * c[0] + u * d[0],
174 p1msmtmu * a[1] + s * b[1] + t * c[1] + u * d[1],
175 p1msmtmu * a[2] + s * b[2] + t * c[2] + u * d[2]};
176 }
177 }
178
179
180
181
182 private static class NonArrayTetrahedronSampler extends TetrahedronSampler {
183
184 private final double ax;
185 private final double bx;
186 private final double cx;
187 private final double dx;
188 private final double ay;
189 private final double by;
190 private final double cy;
191 private final double dy;
192 private final double az;
193 private final double bz;
194 private final double cz;
195 private final double dz;
196
197
198
199
200
201
202
203
204
205 NonArrayTetrahedronSampler(UniformRandomProvider rng,
206 double[] a, double[] b, double[] c, double[] d) {
207 super(rng);
208 ax = a[0];
209 ay = a[1];
210 az = a[2];
211 bx = b[0];
212 by = b[1];
213 bz = b[2];
214 cx = c[0];
215 cy = c[1];
216 cz = c[2];
217 dx = d[0];
218 dy = d[1];
219 dz = d[2];
220 }
221
222 @Override
223 protected double[] createSample(double p1msmtmu, double s, double t, double u) {
224 return new double[] {p1msmtmu * ax + s * bx + t * cx + u * dx,
225 p1msmtmu * ay + s * by + t * cy + u * dy,
226 p1msmtmu * az + s * bz + t * cz + u * dz};
227 }
228 }
229
230
231
232
233
234 private static class ArrayInlineTetrahedronSampler implements ObjectSampler<double[]> {
235
236 private final double[] a;
237 private final double[] b;
238 private final double[] c;
239 private final double[] d;
240 private final UniformRandomProvider rng;
241
242
243
244
245
246
247
248
249
250 ArrayInlineTetrahedronSampler(UniformRandomProvider rng,
251 double[] a, double[] b, double[] c, double[] d) {
252 this.a = a.clone();
253 this.b = b.clone();
254 this.c = c.clone();
255 this.d = d.clone();
256 this.rng = rng;
257 }
258
259 @Override
260 public double[] sample() {
261 double s = rng.nextDouble();
262 double t = rng.nextDouble();
263 double u = rng.nextDouble();
264
265 if (s + t > 1) {
266
267 s = 1 - s;
268 t = 1 - t;
269 }
270
271 double p1msmtmu;
272 final double tpu = t + u;
273 final double sptpu = s + tpu;
274 if (sptpu > 1) {
275 if (tpu > 1) {
276
277 final double tt = t;
278 p1msmtmu = u - 1 + t;
279 t = 1 - u;
280 u = 1 - s - tt;
281 } else {
282
283 final double ss = s;
284 p1msmtmu = 1 - s - t;
285 s = 1 - tpu;
286 u = ss - 1 + tpu;
287 }
288 } else {
289 p1msmtmu = 1 - sptpu;
290 }
291
292 return new double[] {p1msmtmu * a[0] + s * b[0] + t * c[0] + u * d[0],
293 p1msmtmu * a[1] + s * b[1] + t * c[1] + u * d[1],
294 p1msmtmu * a[2] + s * b[2] + t * c[2] + u * d[2]};
295 }
296 }
297
298
299
300
301
302 private static class NonArrayInlineTetrahedronSampler implements ObjectSampler<double[]> {
303
304 private final double ax;
305 private final double bx;
306 private final double cx;
307 private final double dx;
308 private final double ay;
309 private final double by;
310 private final double cy;
311 private final double dy;
312 private final double az;
313 private final double bz;
314 private final double cz;
315 private final double dz;
316 private final UniformRandomProvider rng;
317
318
319
320
321
322
323
324
325
326 NonArrayInlineTetrahedronSampler(UniformRandomProvider rng,
327 double[] a, double[] b, double[] c, double[] d) {
328 ax = a[0];
329 ay = a[1];
330 az = a[2];
331 bx = b[0];
332 by = b[1];
333 bz = b[2];
334 cx = c[0];
335 cy = c[1];
336 cz = c[2];
337 dx = d[0];
338 dy = d[1];
339 dz = d[2];
340 this.rng = rng;
341 }
342
343 @Override
344 public double[] sample() {
345 double s = rng.nextDouble();
346 double t = rng.nextDouble();
347 double u = rng.nextDouble();
348
349 if (s + t > 1) {
350
351 s = 1 - s;
352 t = 1 - t;
353 }
354
355 double p1msmtmu;
356 final double tpu = t + u;
357 final double sptpu = s + tpu;
358 if (sptpu > 1) {
359 if (tpu > 1) {
360
361 final double tt = t;
362 p1msmtmu = u - 1 + t;
363 t = 1 - u;
364 u = 1 - s - tt;
365 } else {
366
367 final double ss = s;
368 p1msmtmu = 1 - s - t;
369 s = 1 - tpu;
370 u = ss - 1 + tpu;
371 }
372 } else {
373 p1msmtmu = 1 - sptpu;
374 }
375
376 return new double[] {p1msmtmu * ax + s * bx + t * cx + u * dx,
377 p1msmtmu * ay + s * by + t * cy + u * dy,
378 p1msmtmu * az + s * bz + t * cz + u * dz};
379 }
380 }
381
382
383
384
385 @State(Scope.Benchmark)
386 public static class SamplerData {
387
388 private ObjectSampler<double[]> sampler;
389
390
391 @Param({"1", "10", "100", "1000", "10000"})
392 private int size;
393
394
395 @Param({BASELINE, ARRAY, NON_ARRAY, ARRAY_INLINE, NON_ARRAY_INLINE})
396 private String type;
397
398
399
400
401
402
403 public int getSize() {
404 return size;
405 }
406
407
408
409
410
411
412 public ObjectSampler<double[]> getSampler() {
413 return sampler;
414 }
415
416
417
418
419 @Setup(Level.Iteration)
420 public void setup() {
421
422 final UniformRandomProvider rng = RandomSource.XO_SHI_RO_256_PP.create();
423 final UnitSphereSampler s = UnitSphereSampler.of(rng, 3);
424 final double[] a = s.sample();
425 final double[] b = s.sample();
426 final double[] c = s.sample();
427 final double[] d = s.sample();
428 sampler = createSampler(rng, a, b, c, d);
429 }
430
431
432
433
434
435
436
437
438
439
440
441 private ObjectSampler<double[]> createSampler(final UniformRandomProvider rng,
442 double[] a, double[] b, double[] c, double[] d) {
443 if (BASELINE.equals(type)) {
444 return () -> {
445 final double s = rng.nextDouble();
446 final double t = rng.nextDouble();
447 final double u = rng.nextDouble();
448 return new double[] {s, t, u};
449 };
450 } else if (ARRAY.equals(type)) {
451 return new ArrayTetrahedronSampler(rng, a, b, c, d);
452 } else if (NON_ARRAY.equals(type)) {
453 return new NonArrayTetrahedronSampler(rng, a, b, c, d);
454 } else if (ARRAY_INLINE.equals(type)) {
455 return new ArrayInlineTetrahedronSampler(rng, a, b, c, d);
456 } else if (NON_ARRAY_INLINE.equals(type)) {
457 return new NonArrayInlineTetrahedronSampler(rng, a, b, c, d);
458 }
459 throw new IllegalStateException(UNKNOWN_SAMPLER + type);
460 }
461 }
462
463
464
465
466
467
468
469 @Benchmark
470 public void sample(Blackhole bh, SamplerData data) {
471 final ObjectSampler<double[]> sampler = data.getSampler();
472 for (int i = data.getSize() - 1; i >= 0; i--) {
473 bh.consume(sampler.sample());
474 }
475 }
476 }