001/*
002 * Java Genetic Algorithm Library (jenetics-7.1.0).
003 * Copyright (c) 2007-2022 Franz Wilhelmstötter
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 * Author:
018 *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019 */
020package io.jenetics.util;
021
022import static java.util.Objects.requireNonNull;
023
024import java.util.Random;
025import java.util.function.Consumer;
026import java.util.function.Function;
027import java.util.function.Supplier;
028import java.util.random.RandomGenerator;
029import java.util.random.RandomGeneratorFactory;
030
031/**
032 * This class holds the {@link RandomGenerator} engine used for the GA. The
033 * {@code RandomRegistry} is thread safe and is initialized with the
034 * {@link RandomGeneratorFactory#getDefault()} PRNG.
035 *
036 * <h2>Setup the PRNG used for the evolution process</h2>
037 * There are several ways on how to set the {@link RandomGenerator} used during
038 * the evolution process.
039 * <p>
040 *
041 * <b>Using a {@link RandomGeneratorFactory}</b><br>
042 * The following example registers the <em>L128X1024MixRandom</em> random
043 * generator. By using a factory, each threads gets its own generator instance,
044 * which ensures thread-safety without the necessity of the created random
045 * generator to be thread-safe.
046 * <pre>{@code
047 * // This is the default setup.
048 * RandomRegistry.random(RandomGeneratorFactory.getDefault());
049 *
050 * // Using the "L128X1024MixRandom" random generator for the evolution.
051 * RandomRegistry.random(RandomGeneratorFactory.of("L128X1024MixRandom"));
052 * }</pre>
053 * <br>
054 *
055 * <b>Using a {@link RandomGenerator} {@link Supplier}</b><br>
056 * If you have a random engine, which is not available as
057 * {@link RandomGeneratorFactory}, it is also possible to register a
058 * {@link Supplier} of the desired random generator. This method has the same
059 * thread-safety property as the method above.
060 * <pre>{@code
061 * RandomRegistry.random(() -> new MySpecialRandomGenerator());
062 * }</pre>
063 *
064 * Register a random generator supplier is also more flexible. It allows to
065 * use the streaming and splitting capabilities of the random generators
066 * implemented in the Java library.
067 * <pre>{@code
068 * final Iterator<RandomGenerator> randoms =
069 *     StreamableGenerator.of("L128X1024MixRandom")
070 *         .rngs()
071 *         .iterator();
072 *
073 * RandomRegistry.random(randoms::next);
074 * }</pre>
075 * <br>
076 *
077 * <b>Using a {@link RandomGenerator} instance</b><br>
078 * It is also possible to set a single random generator instance for the whole
079 * evolution process. When using this setup, the used random generator must be
080 * thread safe.
081 * <pre>{@code
082 * RandomRegistry.random(new Random(123456));
083 * }</pre>
084 * <p>
085 *
086 * The following code snippet shows an almost complete example of a typical
087 * random generator setup.
088 * <pre>{@code
089 * public class GA {
090 *     public static void main(final String[] args) {
091 *         // Initialize the registry with the factory of the PRGN.
092 *         final var factory = RandomGeneratorFactory.of("L128X1024MixRandom");
093 *         RandomRegistry.random(factory);
094 *
095 *         final Engine<DoubleGene, Double> engine = ...;
096 *         final EvolutionResult<DoubleGene, Double> result = engine.stream()
097 *             .limit(100)
098 *             .collect(toBestEvolutionResult());
099 *     }
100 * }
101 * }</pre>
102 *
103 * <h2>Setup of a <i>local</i> PRNG</h2>
104 *
105 * You can temporarily (and locally) change the implementation of the PRNG. E.g.
106 * for initialize the engine stream with the same initial population.
107 *
108 * <pre>{@code
109 * public class GA {
110 *     public static void main(final String[] args) {
111 *         // Create a reproducible list of genotypes.
112 *         final var factory = RandomGeneratorFactory.of("L128X1024MixRandom");
113 *         final List<Genotype<DoubleGene>> genotypes =
114 *             with(factory.create(123), r ->
115 *                 Genotype.of(DoubleChromosome.of(0, 10)).instances()
116 *                     .limit(50)
117 *                     .collect(toList())
118 *             );
119 *
120 *         final Engine<DoubleGene, Double> engine = ...;
121 *         final EvolutionResult<DoubleGene, Double> result = engine
122 *              // Initialize the evolution stream with the given genotypes.
123 *             .stream(genotypes)
124 *             .limit(100)
125 *             .collect(toBestEvolutionResult());
126 *     }
127 * }
128 * }</pre>
129 *
130 * @see RandomGenerator
131 * @see RandomGeneratorFactory
132 *
133 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
134 * @since 1.0
135 * @version 7.0
136 */
137public final class RandomRegistry {
138        private RandomRegistry() {}
139
140        /**
141         * Thread local wrapper for a random generator supplier (factory).
142         *
143         * @param <R> the type of the random generator
144         */
145        private static final class TLR<R extends RandomGenerator>
146                extends ThreadLocal<R>
147                implements Supplier<R>
148        {
149                private final Supplier<? extends R> _factory;
150
151                TLR(final Supplier<? extends R> factory) {
152                        _factory = requireNonNull(factory);
153                }
154
155                @Override
156                protected synchronized R initialValue() {
157                        return _factory.get();
158                }
159        }
160
161        private static final TLR<RandomGenerator> DEFAULT_RANDOM_FACTORY =
162                new TLR<>(RandomGeneratorFactory.of("L64X256MixRandom")::create);
163
164        private static final Context<Supplier<? extends RandomGenerator>> CONTEXT =
165                new Context<>(DEFAULT_RANDOM_FACTORY);
166
167        /**
168         * Return the {@link RandomGenerator} of the current scope.
169         *
170         * @return the {@link RandomGenerator} of the current scope
171         */
172        public static RandomGenerator random() {
173                return CONTEXT.get().get();
174        }
175
176        /**
177         * Set a new {@link RandomGenerator} for the <em>global</em> scope. The given
178         * {@link RandomGenerator} <b>must</b> be thread safe, which is the case for
179         * the Java {@link Random} class.
180         *
181         * @see #random(RandomGeneratorFactory)
182         *
183         * @param random the new {@link RandomGenerator} for the <em>global</em>
184         *        scope
185         * @throws NullPointerException if the {@code random} object is {@code null}
186         */
187        public static void random(final RandomGenerator random) {
188                requireNonNull(random);
189                CONTEXT.set(() -> random);
190        }
191
192        /**
193         * Set a new {@link RandomGeneratorFactory} for the <em>global</em> scope.
194         *
195         * @param factory the random generator factory
196         * @throws NullPointerException if the {@code factory} object is {@code null}.
197         */
198        public static <R extends RandomGenerator> void
199        random(final RandomGeneratorFactory<? extends R> factory) {
200                requireNonNull(factory);
201                CONTEXT.set(new TLR<>(factory::create));
202        }
203
204        /**
205         * Set a new {@link Supplier} of {@link RandomGenerator} for the
206         * <em>global</em> scope.
207         *
208         * @param supplier the random generator supplier
209         * @throws NullPointerException if the {@code supplier} object is {@code null}.
210         */
211        public static <R extends RandomGenerator> void
212        random(final Supplier<? extends R> supplier) {
213                requireNonNull(supplier);
214                CONTEXT.set(new TLR<>(supplier));
215        }
216
217        /**
218         * Set the random object to its default value.
219         */
220        public static void reset() {
221                CONTEXT.reset();
222        }
223
224        /**
225         * Executes the consumer code using the given {@code random} generator.
226         *
227         * <pre>{@code
228         * final MSeq<Integer> seq = ...
229         * using(new Random(123), r -> {
230         *     seq.shuffle();
231         * });
232         * }</pre>
233         *
234         * The example above shuffles the given integer {@code seq} <i>using</i> the
235         * given {@code Random(123)} engine.
236         *
237         * @since 3.0
238         *
239         * @param random the PRNG used within the consumer
240         * @param consumer the consumer which is executed with the <i>scope</i> of
241         *        the given {@code random} engine.
242         * @param <R> the type of the random engine
243         * @throws NullPointerException if one of the arguments is {@code null}
244         */
245        public static <R extends RandomGenerator> void using(
246                final R random,
247                final Consumer<? super R> consumer
248        ) {
249                CONTEXT.with(
250                        () -> random,
251                        r -> { consumer.accept(random); return null; }
252                );
253        }
254
255        /**
256         * Executes the consumer code using the given {@code random} generator.
257         *
258         * <pre>{@code
259         * final MSeq<Integer> seq = ...
260         * using(RandomGeneratorFactory.getDefault(), r -> {
261         *     seq.shuffle();
262         * });
263         * }</pre>
264         *
265         * The example above shuffles the given integer {@code seq} <i>using</i> the
266         * given {@link RandomGeneratorFactory#getDefault()} factory.
267         *
268         * @since 7.0
269         *
270         * @param factory the random generator factory used within the consumer
271         * @param consumer the consumer which is executed within the <i>scope</i> of
272         *        the given random generator.
273         * @param <R> the type of the random engine
274         * @throws NullPointerException if one of the arguments is {@code null}
275         */
276        public static <R extends RandomGenerator> void using(
277                final RandomGeneratorFactory<? extends R> factory,
278                final Consumer<? super R> consumer
279        ) {
280                CONTEXT.with(
281                        new TLR<>(factory::create),
282                        r -> { consumer.accept(r.get()); return null; }
283                );
284        }
285
286        /**
287         * Executes the consumer code using the given {@code random} generator
288         * supplier.
289         *
290         * <pre>{@code
291         * final MSeq<Integer> seq = ...
292         * using(() -> new MyRandomGenerator(), r -> {
293         *     seq.shuffle();
294         * });
295         * }</pre>
296         *
297         * @since 7.0
298         *
299         * @param supplier the random generator supplier used within the consumer
300         * @param consumer the consumer which is executed within the <i>scope</i> of
301         *        the given random generator.
302         * @param <R> the type of the random engine
303         * @throws NullPointerException if one of the arguments is {@code null}
304         */
305        public static <R extends RandomGenerator> void using(
306                final Supplier<? extends R> supplier,
307                final Consumer<? super R> consumer
308        ) {
309                CONTEXT.with(
310                        new TLR<>(supplier),
311                        r -> { consumer.accept(r.get()); return null; }
312                );
313        }
314
315        /**
316         * Opens a new <em>scope</em> with the given random generator and executes
317         * the given function within it. The following example shows how to create a
318         * reproducible list of genotypes:
319         * <pre>{@code
320         * final List<Genotype<DoubleGene>> genotypes =
321         *     with(new LCG64ShiftRandom(123), r ->
322         *         Genotype.of(DoubleChromosome.of(0, 10)).instances()
323         *            .limit(50)
324         *            .collect(toList())
325         *     );
326         * }</pre>
327         *
328         * @since 3.0
329         *
330         * @param <R> the type of the random engine
331         * @param <T> the function return type
332         * @param random the PRNG used for the opened scope
333         * @param function the function to apply within the random scope
334         * @return the object returned by the given function
335         * @throws NullPointerException if one of the arguments is {@code null}
336         */
337        public static <R extends RandomGenerator, T> T with(
338                final R random,
339                final Function<? super R, ? extends T> function
340        ) {
341                return CONTEXT.with(
342                        () -> random,
343                        s -> function.apply(random)
344                );
345        }
346
347        /**
348         * Opens a new <em>scope</em> with the given random generator factory and
349         * executes the given function within it.
350         * <pre>{@code
351         * final List<Genotype<DoubleGene>> genotypes =
352         *     with(RandomGeneratorFactory.getDefault(), random ->
353         *         Genotype.of(DoubleChromosome.of(0, 10)).instances()
354         *            .limit(50)
355         *            .collect(toList())
356         *     );
357         * }</pre>
358         *
359         * @since 3.0
360         *
361         * @param <R> the type of the random engine
362         * @param <T> the function return type
363         * @param factory the PRNG used for the opened scope
364         * @param function the function to apply within the random scope
365         * @return the object returned by the given function
366         * @throws NullPointerException if one of the arguments is {@code null}.
367         */
368        public static <R extends RandomGenerator, T> T with(
369                final RandomGeneratorFactory<? extends R> factory,
370                final Function<? super R, ? extends T> function
371        ) {
372                return CONTEXT.with(
373                        new TLR<>(factory::create),
374                        r -> function.apply(r.get())
375                );
376        }
377        /**
378         * Opens a new <em>scope</em> with the given random generator supplier and
379         * executes the given function within it.
380         * <pre>{@code
381         * final List<Genotype<DoubleGene>> genotypes =
382         *     with(() -> new MyRandomGenerator(), random ->
383         *         Genotype.of(DoubleChromosome.of(0, 10)).instances()
384         *            .limit(50)
385         *            .collect(toList())
386         *     );
387         * }</pre>
388         *
389         * @since 3.0
390         *
391         * @param <R> the type of the random engine
392         * @param <T> the function return type
393         * @param supplier the PRNG used for the opened scope
394         * @param function the function to apply within the random scope
395         * @return the object returned by the given function
396         * @throws NullPointerException if one of the arguments is {@code null}.
397         */
398
399        public static <R extends RandomGenerator, T> T with(
400                final Supplier<? extends R> supplier,
401                final Function<? super R, ? extends T> function
402        ) {
403                return CONTEXT.with(
404                        new TLR<>(supplier),
405                        r -> function.apply(r.get())
406                );
407        }
408
409}