1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.rng.simple.internal;
18
19 import java.util.Arrays;
20 import java.util.List;
21 import java.util.ArrayList;
22 import java.util.Map;
23 import java.util.concurrent.ConcurrentHashMap;
24 import java.lang.reflect.Constructor;
25 import java.lang.reflect.InvocationTargetException;
26
27 import org.apache.commons.rng.UniformRandomProvider;
28 import org.apache.commons.rng.RestorableUniformRandomProvider;
29 import org.apache.commons.rng.core.source32.JDKRandom;
30 import org.apache.commons.rng.core.source32.Well512a;
31 import org.apache.commons.rng.core.source32.Well1024a;
32 import org.apache.commons.rng.core.source32.Well19937a;
33 import org.apache.commons.rng.core.source32.Well19937c;
34 import org.apache.commons.rng.core.source32.Well44497a;
35 import org.apache.commons.rng.core.source32.Well44497b;
36 import org.apache.commons.rng.core.source32.ISAACRandom;
37 import org.apache.commons.rng.core.source32.MersenneTwister;
38 import org.apache.commons.rng.core.source32.MultiplyWithCarry256;
39 import org.apache.commons.rng.core.source32.KISSRandom;
40 import org.apache.commons.rng.core.source64.SplitMix64;
41 import org.apache.commons.rng.core.source64.XorShift1024Star;
42 import org.apache.commons.rng.core.source64.TwoCmres;
43 import org.apache.commons.rng.core.source64.MersenneTwister64;
44
45
46
47
48
49
50
51
52 public final class ProviderBuilder {
53
54 private static final String INTERNAL_ERROR_MSG = "Internal error: Please file a bug report";
55
56 private static final int RANDOM_SEED_ARRAY_SIZE = 128;
57
58 private static final Long2Int LONG_TO_INT = new Long2Int();
59
60 private static final Int2Long INT_TO_LONG = new Int2Long();
61
62 private static final Long2IntArray LONG_TO_INT_ARRAY = new Long2IntArray(RANDOM_SEED_ARRAY_SIZE);
63
64 private static final Long2LongArray LONG_TO_LONG_ARRAY = new Long2LongArray(RANDOM_SEED_ARRAY_SIZE);
65
66 private static final LongArray2Long LONG_ARRAY_TO_LONG = new LongArray2Long();
67
68 private static final IntArray2Int INT_ARRAY_TO_INT = new IntArray2Int();
69
70 private static final LongArray2IntArray LONG_ARRAY_TO_INT_ARRAY = new LongArray2IntArray();
71
72 private static final IntArray2LongArray INT_ARRAY_TO_LONG_ARRAY = new IntArray2LongArray();
73
74 private static final ByteArray2IntArray BYTE_ARRAY_TO_INT_ARRAY = new ByteArray2IntArray();
75
76 private static final ByteArray2LongArray BYTE_ARRAY_TO_LONG_ARRAY = new ByteArray2LongArray();
77
78 private static final Map<Class<?>, SeedConverter<Integer,?>> CONV_INT =
79 new ConcurrentHashMap<Class<?>, SeedConverter<Integer,?>>();
80
81 private static final Map<Class<?>, SeedConverter<int[],?>> CONV_INT_ARRAY =
82 new ConcurrentHashMap<Class<?>, SeedConverter<int[],?>>();
83
84 private static final Map<Class<?>, SeedConverter<Long,?>> CONV_LONG =
85 new ConcurrentHashMap<Class<?>, SeedConverter<Long,?>>();
86
87 private static final Map<Class<?>, SeedConverter<long[],?>> CONV_LONG_ARRAY =
88 new ConcurrentHashMap<Class<?>, SeedConverter<long[],?>>();
89
90 private static final Map<Class<?>, SeedConverter<byte[],?>> CONV_BYTE_ARRAY =
91 new ConcurrentHashMap<Class<?>, SeedConverter<byte[],?>>();
92
93 static {
94
95
96 CONV_LONG.put(Integer.class, LONG_TO_INT);
97 CONV_LONG.put(Long.class, new NoOpConverter<Long>());
98 CONV_LONG.put(int[].class, LONG_TO_INT_ARRAY);
99 CONV_LONG.put(long[].class, LONG_TO_LONG_ARRAY);
100
101
102
103 CONV_INT.put(Integer.class, new NoOpConverter<Integer>());
104 CONV_INT.put(Long.class, INT_TO_LONG);
105 CONV_INT.put(int[].class, new SeedConverterComposer<Integer,Long,int[]>(INT_TO_LONG, LONG_TO_INT_ARRAY));
106 CONV_INT.put(long[].class, new SeedConverterComposer<Integer,Long,long[]>(INT_TO_LONG, LONG_TO_LONG_ARRAY));
107
108
109
110 CONV_INT_ARRAY.put(Integer.class, INT_ARRAY_TO_INT);
111 CONV_INT_ARRAY.put(Long.class, new SeedConverterComposer<int[],Integer,Long>(INT_ARRAY_TO_INT, INT_TO_LONG));
112 CONV_INT_ARRAY.put(int[].class, new NoOpConverter<int[]>());
113 CONV_INT_ARRAY.put(long[].class, INT_ARRAY_TO_LONG_ARRAY);
114
115
116
117 CONV_LONG_ARRAY.put(Integer.class, new SeedConverterComposer<long[],Long,Integer>(LONG_ARRAY_TO_LONG, LONG_TO_INT));
118 CONV_LONG_ARRAY.put(Long.class, LONG_ARRAY_TO_LONG);
119 CONV_LONG_ARRAY.put(int[].class, LONG_ARRAY_TO_INT_ARRAY);
120 CONV_LONG_ARRAY.put(long[].class, new NoOpConverter<long[]>());
121
122
123
124 CONV_BYTE_ARRAY.put(Integer.class, new SeedConverterComposer<byte[],int[],Integer>(BYTE_ARRAY_TO_INT_ARRAY, INT_ARRAY_TO_INT));
125 CONV_BYTE_ARRAY.put(Long.class, new SeedConverterComposer<byte[],long[],Long>(BYTE_ARRAY_TO_LONG_ARRAY, LONG_ARRAY_TO_LONG));
126 CONV_BYTE_ARRAY.put(int[].class, BYTE_ARRAY_TO_INT_ARRAY);
127 CONV_BYTE_ARRAY.put(long[].class, BYTE_ARRAY_TO_LONG_ARRAY);
128 }
129
130
131
132
133 private ProviderBuilder() {}
134
135
136
137
138
139
140
141
142
143
144
145 public static RestorableUniformRandomProvider create(RandomSourceInternal source,
146 Object seed,
147 Object[] args) {
148
149 final Object nativeSeed = createSeed(source, seed);
150
151
152
153 final List<Object> all = new ArrayList<Object>();
154 all.add(nativeSeed);
155 if (args != null) {
156 all.addAll(Arrays.asList(args));
157 }
158
159
160 return create(createConstructor(source), all.toArray());
161 }
162
163
164
165
166
167
168
169
170
171 private static Object createSeed(RandomSourceInternal source,
172 Object seed) {
173 Object nativeSeed = null;
174
175 if (seed == null) {
176
177
178 if (source.getSeed().equals(Integer.class)) {
179 nativeSeed = SeedFactory.createInt();
180 } else if (source.getSeed().equals(Long.class)) {
181 nativeSeed = SeedFactory.createLong();
182 } else if (source.getSeed().equals(int[].class)) {
183 nativeSeed = SeedFactory.createIntArray(RANDOM_SEED_ARRAY_SIZE);
184 } else if (source.getSeed().equals(long[].class)) {
185 nativeSeed = SeedFactory.createLongArray(RANDOM_SEED_ARRAY_SIZE);
186 } else {
187
188 throw new IllegalStateException(INTERNAL_ERROR_MSG);
189 }
190 } else {
191
192
193 if (seed instanceof Integer) {
194 nativeSeed = CONV_INT.get(source.getSeed()).convert((Integer) seed);
195 } else if (seed instanceof Long) {
196 nativeSeed = CONV_LONG.get(source.getSeed()).convert((Long) seed);
197 } else if (seed instanceof int[]) {
198 nativeSeed = CONV_INT_ARRAY.get(source.getSeed()).convert((int[]) seed);
199 } else if (seed instanceof long[]) {
200 nativeSeed = CONV_LONG_ARRAY.get(source.getSeed()).convert((long[]) seed);
201 } else if (seed instanceof byte[]) {
202 nativeSeed = CONV_BYTE_ARRAY.get(source.getSeed()).convert((byte[]) seed);
203 }
204
205 if (nativeSeed == null) {
206
207
208 throw new UnsupportedOperationException("Unrecognized seed type");
209 }
210
211 if (!source.isNativeSeed(nativeSeed)) {
212
213 throw new IllegalStateException(INTERNAL_ERROR_MSG);
214 }
215 }
216
217 return nativeSeed;
218 }
219
220
221
222
223
224
225
226 private static Constructor<?> createConstructor(RandomSourceInternal source) {
227 try {
228 return source.getRng().getConstructor(source.getArgs());
229 } catch (NoSuchMethodException e) {
230
231
232 throw new IllegalStateException(INTERNAL_ERROR_MSG, e);
233 }
234 }
235
236
237
238
239
240
241
242
243 private static RestorableUniformRandomProvider create(Constructor<?> rng,
244 Object[] args) {
245 try {
246 return (RestorableUniformRandomProvider) rng.newInstance(args);
247 } catch (InvocationTargetException e) {
248 throw new IllegalStateException(INTERNAL_ERROR_MSG, e);
249 } catch (InstantiationException e) {
250 throw new IllegalStateException(INTERNAL_ERROR_MSG, e);
251 } catch (IllegalAccessException e) {
252 throw new IllegalStateException(INTERNAL_ERROR_MSG, e);
253 }
254 }
255
256
257
258
259 public enum RandomSourceInternal {
260
261 JDK(JDKRandom.class,
262 Long.class),
263
264 WELL_512_A(Well512a.class,
265 int[].class),
266
267 WELL_1024_A(Well1024a.class,
268 int[].class),
269
270 WELL_19937_A(Well19937a.class,
271 int[].class),
272
273 WELL_19937_C(Well19937c.class,
274 int[].class),
275
276 WELL_44497_A(Well44497a.class,
277 int[].class),
278
279 WELL_44497_B(Well44497b.class,
280 int[].class),
281
282 MT(MersenneTwister.class,
283 int[].class),
284
285 ISAAC(ISAACRandom.class,
286 int[].class),
287
288 SPLIT_MIX_64(SplitMix64.class,
289 Long.class),
290
291 XOR_SHIFT_1024_S(XorShift1024Star.class,
292 long[].class),
293
294 TWO_CMRES(TwoCmres.class,
295 Integer.class),
296
297
298
299
300 TWO_CMRES_SELECT(TwoCmres.class,
301 Integer.class,
302 Integer.TYPE,
303 Integer.TYPE),
304
305 MT_64(MersenneTwister64.class,
306 long[].class),
307
308 MWC_256(MultiplyWithCarry256.class,
309 int[].class),
310
311 KISS(KISSRandom.class,
312 int[].class);
313
314
315 private final Class<? extends UniformRandomProvider> rng;
316
317 private final Class<?>[] args;
318
319
320
321
322
323
324 RandomSourceInternal(Class<? extends UniformRandomProvider> rng,
325 Class<?> ... args) {
326 this.rng = rng;
327 this.args = Arrays.copyOf(args, args.length);
328 }
329
330
331
332
333 public Class<?> getRng() {
334 return rng;
335 }
336
337
338
339
340 Class<?> getSeed() {
341 return args[0];
342 }
343
344
345
346
347 Class<?>[] getArgs() {
348 return args;
349 }
350
351
352
353
354
355
356
357
358
359
360
361 public <SEED> boolean isNativeSeed(SEED seed) {
362 return seed == null ?
363 false :
364 getSeed().equals(seed.getClass());
365 }
366 }
367 }