001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  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
018package org.apache.commons.rng.sampling;
019
020import java.util.List;
021import java.util.Objects;
022import java.util.ArrayList;
023
024import org.apache.commons.rng.UniformRandomProvider;
025import org.apache.commons.rng.sampling.distribution.AliasMethodDiscreteSampler;
026import org.apache.commons.rng.sampling.distribution.ContinuousSampler;
027import org.apache.commons.rng.sampling.distribution.DiscreteSampler;
028import org.apache.commons.rng.sampling.distribution.DiscreteUniformSampler;
029import org.apache.commons.rng.sampling.distribution.GuideTableDiscreteSampler;
030import org.apache.commons.rng.sampling.distribution.LongSampler;
031import org.apache.commons.rng.sampling.distribution.MarsagliaTsangWangDiscreteSampler;
032import org.apache.commons.rng.sampling.distribution.SharedStateContinuousSampler;
033import org.apache.commons.rng.sampling.distribution.SharedStateDiscreteSampler;
034import org.apache.commons.rng.sampling.distribution.SharedStateLongSampler;
035
036/**
037 * Factory class to create a sampler that combines sampling from multiple samplers.
038 *
039 * <p>The composite sampler is constructed using a {@link Builder builder} for the type of samplers
040 * that will form the composite. Each sampler has a weight in the composition.
041 * Samples are returned using a 2 step algorithm:
042 *
043 * <ol>
044 *  <li>Select a sampler based on its weighting</li>
045 *  <li>Return a sample from the selected sampler</li>
046 * </ol>
047 *
048 * <p>The weights used for each sampler create a discrete probability distribution. This is
049 * sampled using a discrete probability distribution sampler. The builder provides methods
050 * to change the default implementation.
051 *
052 * <p>The following example will create a sampler to uniformly sample the border of a triangle
053 * using the line segment lengths as weights:
054 *
055 * <pre>
056 * UniformRandomProvider rng = RandomSource.KISS.create();
057 * double[] a = {1.23, 4.56};
058 * double[] b = {6.78, 9.01};
059 * double[] c = {3.45, 2.34};
060 * ObjectSampler&lt;double[]&gt; sampler =
061 *     CompositeSamplers.&lt;double[]&gt;newObjectSamplerBuilder()
062 *         .add(LineSampler.of(rng, a, b), Math.hypot(a[0] - b[0], a[1] - b[1]))
063 *         .add(LineSampler.of(rng, b, c), Math.hypot(b[0] - c[0], b[1] - c[1]))
064 *         .add(LineSampler.of(rng, c, a), Math.hypot(c[0] - a[0], c[1] - a[1]))
065 *         .build(rng);
066 * </pre>
067 *
068 * @since 1.4
069 */
070public final class CompositeSamplers {
071    /**
072     * A factory for creating a sampler of a user-defined
073     * <a href="https://en.wikipedia.org/wiki/Probability_distribution#Discrete_probability_distribution">
074     * discrete probability distribution</a>.
075     */
076    @FunctionalInterface
077    public interface DiscreteProbabilitySamplerFactory {
078        /**
079         * Creates the sampler.
080         *
081         * @param rng Source of randomness.
082         * @param probabilities Discrete probability distribution.
083         * @return the sampler
084         */
085        DiscreteSampler create(UniformRandomProvider rng,
086                               double[] probabilities);
087    }
088
089    /**
090     * Enumerates implementations that sample from a user-defined
091     * <a href="https://en.wikipedia.org/wiki/Probability_distribution#Discrete_probability_distribution">
092     * discrete probability distribution</a>.
093     *
094     * <p>All implementations support the {@link SharedStateDiscreteSampler} interface.
095     */
096    public enum DiscreteProbabilitySampler implements DiscreteProbabilitySamplerFactory {
097        /** Sample using a guide table (see {@link GuideTableDiscreteSampler}). */
098        GUIDE_TABLE {
099            @Override
100            public SharedStateDiscreteSampler create(UniformRandomProvider rng, double[] probabilities) {
101                return GuideTableDiscreteSampler.of(rng, probabilities);
102            }
103        },
104        /** Sample using the alias method (see {@link AliasMethodDiscreteSampler}). */
105        ALIAS_METHOD {
106            @Override
107            public SharedStateDiscreteSampler create(UniformRandomProvider rng, double[] probabilities) {
108                return AliasMethodDiscreteSampler.of(rng, probabilities);
109            }
110        },
111        /**
112         * Sample using an optimised look-up table (see
113         * {@link org.apache.commons.rng.sampling.distribution.MarsagliaTsangWangDiscreteSampler.Enumerated
114         * MarsagliaTsangWangDiscreteSampler.Enumerated}).
115         */
116        LOOKUP_TABLE {
117            @Override
118            public SharedStateDiscreteSampler create(UniformRandomProvider rng, double[] probabilities) {
119                return MarsagliaTsangWangDiscreteSampler.Enumerated.of(rng, probabilities);
120            }
121        }
122    }
123
124    /**
125     * A class to implement the SharedStateDiscreteSampler interface for a discrete probability
126     * sampler given a factory and the probability distribution. Each new instance will recreate
127     * the distribution sampler using the factory.
128     */
129    private static final class SharedStateDiscreteProbabilitySampler implements SharedStateDiscreteSampler {
130        /** The sampler. */
131        private final DiscreteSampler sampler;
132        /** The factory to create a new discrete sampler. */
133        private final DiscreteProbabilitySamplerFactory factory;
134        /** The probabilities. */
135        private final double[] probabilities;
136
137        /**
138         * @param sampler Sampler of the discrete distribution.
139         * @param factory Factory to create a new discrete sampler.
140         * @param probabilities Probabilities of the discrete distribution.
141         * @throws NullPointerException if the {@code sampler} is null
142         */
143        SharedStateDiscreteProbabilitySampler(DiscreteSampler sampler,
144                                              DiscreteProbabilitySamplerFactory factory,
145                                              double[] probabilities) {
146            this.sampler = Objects.requireNonNull(sampler, "discrete sampler");
147            // Assume the factory and probabilities are not null
148            this.factory = factory;
149            this.probabilities = probabilities;
150        }
151
152        @Override
153        public int sample() {
154            // Delegate
155            return sampler.sample();
156        }
157
158        @Override
159        public SharedStateDiscreteSampler withUniformRandomProvider(UniformRandomProvider rng) {
160            // The factory may destructively modify the probabilities
161            return new SharedStateDiscreteProbabilitySampler(factory.create(rng, probabilities.clone()),
162                                                             factory, probabilities);
163        }
164    }
165
166    /**
167     * Builds a composite sampler.
168     *
169     * <p>A composite sampler is a combination of multiple samplers
170     * that all return the same sample type. Each sampler has a weighting in the composition.
171     * Samples are returned using a 2 step algorithm:
172     *
173     * <ol>
174     *  <li>Select a sampler based on its weighting</li>
175     *  <li>Return a sample from the selected sampler</li>
176     * </ol>
177     *
178     * <p>Step 1 requires a discrete sampler constructed from a discrete probability distribution.
179     * The probability for each sampler is the sampler weight divided by the sum of the weights:
180     * <pre>
181     * p(i) = w(i) / sum(w)
182     * </pre>
183     *
184     * <p>The builder provides a method to set the factory used to generate the discrete sampler.
185     *
186     * @param <S> Type of sampler
187     */
188    public interface Builder<S> {
189        /**
190         * Return the number of samplers in the composite. The size must be non-zero before
191         * the {@link #build(UniformRandomProvider) build} method can create a sampler.
192         *
193         * @return the size
194         */
195        int size();
196
197        /**
198         * Adds the sampler to the composite. A sampler with a zero weight is ignored.
199         *
200         * @param sampler Sampler.
201         * @param weight Weight for the composition.
202         * @return a reference to this builder
203         * @throws IllegalArgumentException if {@code weight} is negative, infinite or {@code NaN}.
204         * @throws NullPointerException if {@code sampler} is null.
205         */
206        Builder<S> add(S sampler, double weight);
207
208        /**
209         * Sets the factory to use to generate the composite's discrete sampler from the sampler
210         * weights.
211         *
212         * <p>Note: If the factory is not explicitly set then a default will be used.
213         *
214         * @param factory Factory.
215         * @return a reference to this builder
216         * @throws NullPointerException if {@code factory} is null.
217         */
218        Builder<S> setFactory(DiscreteProbabilitySamplerFactory factory);
219
220        /**
221         * Builds the composite sampler. The {@code rng} is the source of randomness for selecting
222         * which sampler to use for each sample.
223         *
224         * <p>Note: When the sampler is created the builder is reset to an empty state.
225         * This prevents building multiple composite samplers with the same samplers and
226         * their identical underlying source of randomness.
227         *
228         * @param rng Generator of uniformly distributed random numbers.
229         * @return the sampler
230         * @throws IllegalStateException if no samplers have been added to create a composite.
231         * @see #size()
232         */
233        S build(UniformRandomProvider rng);
234    }
235
236    /**
237     * Builds a composite sampler.
238     *
239     * <p>A single builder can be used to create composites of different implementing classes
240     * which support different sampler interfaces. The type of sampler is generic. The individual
241     * samplers and their weights can be collected by the builder. The build method creates
242     * the discrete probability distribution from the weights. The final composite is created
243     * using a factory to create the class.
244     *
245     * @param <S> Type of sampler
246     */
247    private static final class SamplerBuilder<S> implements Builder<S> {
248        /** The specialisation of the sampler. */
249        private final Specialisation specialisation;
250        /** The weighted samplers. */
251        private final List<WeightedSampler<S>> weightedSamplers;
252        /** The factory to create the discrete probability sampler from the weights. */
253        private DiscreteProbabilitySamplerFactory factory;
254        /** The factory to create the composite sampler. */
255        private final SamplerFactory<S> compositeFactory;
256
257        /**
258         * The specialisation of composite sampler to build.
259         * This is used to determine if specialised interfaces from the sampler
260         * type must be supported, e.g. {@link SharedStateSampler}.
261         */
262        enum Specialisation {
263            /** Instance of {@link SharedStateSampler}. */
264            SHARED_STATE_SAMPLER,
265            /** No specialisation. */
266            NONE
267        }
268
269        /**
270         * A factory for creating composite samplers.
271         *
272         * <p>This interface is used to build concrete implementations
273         * of different sampler interfaces.
274         *
275         * @param <S> Type of sampler
276         */
277        @FunctionalInterface
278        interface SamplerFactory<S> {
279            /**
280             * Creates a new composite sampler.
281             *
282             * <p>If the composite specialisation is a
283             * {@link Specialisation#SHARED_STATE_SAMPLER shared state sampler}
284             * the discrete sampler passed to this method will be an instance of
285             * {@link SharedStateDiscreteSampler}.
286             *
287             * @param discreteSampler Discrete sampler.
288             * @param samplers Samplers.
289             * @return the sampler
290             */
291            S createSampler(DiscreteSampler discreteSampler,
292                            List<S> samplers);
293        }
294
295        /**
296         * Contains a weighted sampler.
297         *
298         * @param <S> Sampler type
299         */
300        private static final class WeightedSampler<S> {
301            /** The weight. */
302            private final double weight;
303            /** The sampler. */
304            private final S sampler;
305
306            /**
307             * @param weight the weight
308             * @param sampler the sampler
309             * @throws IllegalArgumentException if {@code weight} is negative, infinite or {@code NaN}.
310             * @throws NullPointerException if {@code sampler} is null.
311             */
312            WeightedSampler(double weight, S sampler) {
313                this.weight = requirePositiveFinite(weight, "weight");
314                this.sampler = Objects.requireNonNull(sampler, "sampler");
315            }
316
317            /**
318             * Gets the weight.
319             *
320             * @return the weight
321             */
322            double getWeight() {
323                return weight;
324            }
325
326            /**
327             * Gets the sampler.
328             *
329             * @return the sampler
330             */
331            S getSampler() {
332                return sampler;
333            }
334
335            /**
336             * Checks that the specified value is positive finite and throws a customized
337             * {@link IllegalArgumentException} if it is not.
338             *
339             * @param value the value
340             * @param message detail message to be used in the event that a {@code
341             *                IllegalArgumentException} is thrown
342             * @return {@code value} if positive finite
343             * @throws IllegalArgumentException if {@code weight} is negative, infinite or {@code NaN}.
344             */
345            private static double requirePositiveFinite(double value, String message) {
346                // Must be positive finite
347                if (!(value >= 0 && value < Double.POSITIVE_INFINITY)) {
348                    throw new IllegalArgumentException(message + " is not positive finite: " + value);
349                }
350                return value;
351            }
352        }
353
354        /**
355         * @param specialisation Specialisation of the sampler.
356         * @param compositeFactory Factory to create the final composite sampler.
357         */
358        SamplerBuilder(Specialisation specialisation,
359                       SamplerFactory<S> compositeFactory) {
360            this.specialisation = specialisation;
361            this.compositeFactory = compositeFactory;
362            weightedSamplers = new ArrayList<>();
363            factory = DiscreteProbabilitySampler.GUIDE_TABLE;
364        }
365
366        @Override
367        public int size() {
368            return weightedSamplers.size();
369        }
370
371        @Override
372        public Builder<S> add(S sampler, double weight) {
373            // Ignore zero weights. The sampler and weight are validated by the WeightedSampler.
374            if (weight != 0) {
375                weightedSamplers.add(new WeightedSampler<>(weight, sampler));
376            }
377            return this;
378        }
379
380        /**
381         * {@inheritDoc}
382         *
383         * <p>If the weights are uniform the factory is ignored and composite's discrete sampler
384         * is a {@link DiscreteUniformSampler uniform distribution sampler}.
385         */
386        @Override
387        public Builder<S> setFactory(DiscreteProbabilitySamplerFactory samplerFactory) {
388            this.factory = Objects.requireNonNull(samplerFactory, "factory");
389            return this;
390        }
391
392        /**
393         * {@inheritDoc}
394         *
395         * <p>If only one sampler has been added to the builder then the sampler is returned
396         * and the builder is reset.
397         *
398         * @throws IllegalStateException if no samplers have been added to create a composite.
399         */
400        @Override
401        public S build(UniformRandomProvider rng) {
402            final List<WeightedSampler<S>> list = this.weightedSamplers;
403            final int n = list.size();
404            if (n == 0) {
405                throw new IllegalStateException("No samplers to build the composite");
406            }
407            if (n == 1) {
408                // No composite
409                final S sampler = list.get(0).sampler;
410                reset();
411                return sampler;
412            }
413
414            // Extract the weights and samplers.
415            final double[] weights = new double[n];
416            final List<S> samplers = new ArrayList<>(n);
417            for (int i = 0; i < n; i++) {
418                final WeightedSampler<S> weightedItem = list.get(i);
419                weights[i] = weightedItem.getWeight();
420                samplers.add(weightedItem.getSampler());
421            }
422
423            reset();
424
425            final DiscreteSampler discreteSampler = createDiscreteSampler(rng, weights);
426
427            return compositeFactory.createSampler(discreteSampler, samplers);
428        }
429
430        /**
431         * Reset the builder.
432         */
433        private void reset() {
434            weightedSamplers.clear();
435        }
436
437        /**
438         * Creates the discrete sampler of the enumerated probability distribution.
439         *
440         * <p>If the specialisation is a {@link Specialisation#SHARED_STATE_SAMPLER shared state sampler}
441         * the discrete sampler will be an instance of {@link SharedStateDiscreteSampler}.
442         *
443         * @param rng Generator of uniformly distributed random numbers.
444         * @param weights Weight associated to each item.
445         * @return the sampler
446         */
447        private DiscreteSampler createDiscreteSampler(UniformRandomProvider rng,
448                                                      double[] weights) {
449            // Edge case. Detect uniform weights.
450            final int n = weights.length;
451            if (uniform(weights)) {
452                // Uniformly sample from the size.
453                // Note: Upper bound is inclusive.
454                return DiscreteUniformSampler.of(rng, 0, n - 1);
455            }
456
457            // If possible normalise with a simple sum.
458            final double sum = sum(weights);
459            if (sum < Double.POSITIVE_INFINITY) {
460                // Do not use f = 1.0 / sum and multiplication by f.
461                // Use of divide handles a sub-normal sum.
462                for (int i = 0; i < n; i++) {
463                    weights[i] /= sum;
464                }
465            } else {
466                // The sum is not finite. We know the weights are all positive finite.
467                // Compute the mean without overflow and divide by the mean and number of items.
468                final double mean = mean(weights);
469                for (int i = 0; i < n; i++) {
470                    // Two step division avoids using the denominator (mean * n)
471                    weights[i] = weights[i] / mean / n;
472                }
473            }
474
475            // Create the sampler from the factory.
476            // Check if a SharedStateSampler is required.
477            // If a default factory then the result is a SharedStateDiscreteSampler,
478            // otherwise the sampler must be checked.
479            if (specialisation == Specialisation.SHARED_STATE_SAMPLER &&
480                !(factory instanceof DiscreteProbabilitySampler)) {
481                // If the factory was user-defined then clone the weights as they may be required
482                // to create a SharedStateDiscreteProbabilitySampler.
483                final DiscreteSampler sampler = factory.create(rng, weights.clone());
484                return sampler instanceof SharedStateDiscreteSampler ?
485                     sampler :
486                     new SharedStateDiscreteProbabilitySampler(sampler, factory, weights);
487            }
488
489            return factory.create(rng, weights);
490        }
491
492        /**
493         * Check if all the values are the same.
494         *
495         * <p>Warning: This method assumes there are input values. If the length is zero an
496         * {@link ArrayIndexOutOfBoundsException} will be thrown.
497         *
498         * @param values the values
499         * @return true if all values are the same
500         */
501        private static boolean uniform(double[] values) {
502            final double value = values[0];
503            for (int i = 1; i < values.length; i++) {
504                if (value != values[i]) {
505                    return false;
506                }
507            }
508            return true;
509        }
510
511        /**
512         * Compute the sum of the values.
513         *
514         * @param values the values
515         * @return the sum
516         */
517        private static double sum(double[] values) {
518            double sum = 0;
519            for (final double value : values) {
520                sum += value;
521            }
522            return sum;
523        }
524
525        /**
526         * Compute the mean of the values. Uses a rolling algorithm to avoid overflow of a simple sum.
527         * This method can be used to compute the mean of observed counts for normalisation to a
528         * probability:
529         *
530         * <pre>
531         * double[] values = ...;
532         * int n = values.length;
533         * double mean = mean(values);
534         * for (int i = 0; i &lt; n; i++) {
535         *     // Two step division avoids using the denominator (mean * n)
536         *     values[i] = values[i] / mean / n;
537         * }
538         * </pre>
539         *
540         * <p>Warning: This method assumes there are input values. If the length is zero an
541         * {@link ArrayIndexOutOfBoundsException} will be thrown.
542         *
543         * @param values the values
544         * @return the mean
545         */
546        private static double mean(double[] values) {
547            double mean = values[0];
548            int i = 1;
549            while (i < values.length) {
550                // Deviation from the mean
551                final double dev = values[i] - mean;
552                i++;
553                mean += dev / i;
554            }
555            return mean;
556        }
557    }
558
559    /**
560     * A composite sampler.
561     *
562     * <p>The source sampler for each sampler is chosen based on a user-defined continuous
563     * probability distribution.
564     *
565     * @param <S> Type of sampler
566     */
567    private static class CompositeSampler<S> {
568        /** Continuous sampler to choose the individual sampler to sample. */
569        protected final DiscreteSampler discreteSampler;
570        /** Collection of samplers to be sampled from. */
571        protected final List<S> samplers;
572
573        /**
574         * @param discreteSampler Continuous sampler to choose the individual sampler to sample.
575         * @param samplers Collection of samplers to be sampled from.
576         */
577        CompositeSampler(DiscreteSampler discreteSampler,
578                         List<S> samplers) {
579            this.discreteSampler = discreteSampler;
580            this.samplers = samplers;
581        }
582
583        /**
584         * Gets the next sampler to use to create a sample.
585         *
586         * @return the sampler
587         */
588        S nextSampler() {
589            return samplers.get(discreteSampler.sample());
590        }
591    }
592
593    /**
594     * A factory for creating a composite ObjectSampler.
595     *
596     * @param <T> Type of sample
597     */
598    private static final class ObjectSamplerFactory<T> implements
599            SamplerBuilder.SamplerFactory<ObjectSampler<T>> {
600        /** The instance. */
601        @SuppressWarnings("rawtypes")
602        private static final ObjectSamplerFactory INSTANCE = new ObjectSamplerFactory<>();
603
604        /**
605         * Get an instance.
606         *
607         * @param <T> Type of sample
608         * @return the factory
609         */
610        @SuppressWarnings("unchecked")
611        static <T> ObjectSamplerFactory<T> instance() {
612            return (ObjectSamplerFactory<T>) INSTANCE;
613        }
614
615        @Override
616        public ObjectSampler<T> createSampler(DiscreteSampler discreteSampler,
617                                              List<ObjectSampler<T>> samplers) {
618            return new CompositeObjectSampler<>(discreteSampler, samplers);
619        }
620
621        /**
622         * A composite object sampler.
623         *
624         * @param <T> Type of sample
625         */
626        private static final class CompositeObjectSampler<T>
627                extends CompositeSampler<ObjectSampler<T>>
628                implements ObjectSampler<T> {
629            /**
630             * @param discreteSampler Discrete sampler to choose the individual sampler to sample.
631             * @param samplers Collection of samplers to be sampled from.
632             */
633            CompositeObjectSampler(DiscreteSampler discreteSampler,
634                                   List<ObjectSampler<T>> samplers) {
635                super(discreteSampler, samplers);
636            }
637
638            @Override
639            public T sample() {
640                return nextSampler().sample();
641            }
642        }
643    }
644
645    /**
646     * A factory for creating a composite SharedStateObjectSampler.
647     *
648     * @param <T> Type of sample
649     */
650    private static final class SharedStateObjectSamplerFactory<T> implements
651            SamplerBuilder.SamplerFactory<SharedStateObjectSampler<T>> {
652        /** The instance. */
653        @SuppressWarnings("rawtypes")
654        private static final SharedStateObjectSamplerFactory INSTANCE = new SharedStateObjectSamplerFactory<>();
655
656        /**
657         * Get an instance.
658         *
659         * @param <T> Type of sample
660         * @return the factory
661         */
662        @SuppressWarnings("unchecked")
663        static <T> SharedStateObjectSamplerFactory<T> instance() {
664            return (SharedStateObjectSamplerFactory<T>) INSTANCE;
665        }
666
667        @Override
668        public SharedStateObjectSampler<T> createSampler(DiscreteSampler discreteSampler,
669                                                         List<SharedStateObjectSampler<T>> samplers) {
670            // The input discrete sampler is assumed to be a SharedStateDiscreteSampler
671            return new CompositeSharedStateObjectSampler<>(
672                (SharedStateDiscreteSampler) discreteSampler, samplers);
673        }
674
675        /**
676         * A composite object sampler with shared state support.
677         *
678         * <p>The source sampler for each sampler is chosen based on a user-defined
679         * discrete probability distribution.
680         *
681         * @param <T> Type of sample
682         */
683        private static final class CompositeSharedStateObjectSampler<T>
684                extends CompositeSampler<SharedStateObjectSampler<T>>
685                implements SharedStateObjectSampler<T> {
686            /**
687             * @param discreteSampler Discrete sampler to choose the individual sampler to sample.
688             * @param samplers Collection of samplers to be sampled from.
689             */
690            CompositeSharedStateObjectSampler(SharedStateDiscreteSampler discreteSampler,
691                                              List<SharedStateObjectSampler<T>> samplers) {
692                super(discreteSampler, samplers);
693            }
694
695            @Override
696            public T sample() {
697                return nextSampler().sample();
698            }
699
700            @Override
701            public CompositeSharedStateObjectSampler<T> withUniformRandomProvider(UniformRandomProvider rng) {
702                // Duplicate each sampler with the same source of randomness
703                return new CompositeSharedStateObjectSampler<>(
704                    ((SharedStateDiscreteSampler) this.discreteSampler).withUniformRandomProvider(rng),
705                    copy(samplers, rng));
706            }
707        }
708    }
709
710    /**
711     * A factory for creating a composite DiscreteSampler.
712     */
713    private static final class DiscreteSamplerFactory implements
714            SamplerBuilder.SamplerFactory<DiscreteSampler> {
715        /** The instance. */
716        static final DiscreteSamplerFactory INSTANCE = new DiscreteSamplerFactory();
717
718        @Override
719        public DiscreteSampler createSampler(DiscreteSampler discreteSampler,
720                                             List<DiscreteSampler> samplers) {
721            return new CompositeDiscreteSampler(discreteSampler, samplers);
722        }
723
724        /**
725         * A composite discrete sampler.
726         */
727        private static final class CompositeDiscreteSampler
728                extends CompositeSampler<DiscreteSampler>
729                implements DiscreteSampler {
730            /**
731             * @param discreteSampler Discrete sampler to choose the individual sampler to sample.
732             * @param samplers Collection of samplers to be sampled from.
733             */
734            CompositeDiscreteSampler(DiscreteSampler discreteSampler,
735                                     List<DiscreteSampler> samplers) {
736                super(discreteSampler, samplers);
737            }
738
739            @Override
740            public int sample() {
741                return nextSampler().sample();
742            }
743        }
744    }
745
746    /**
747     * A factory for creating a composite SharedStateDiscreteSampler.
748     */
749    private static final class SharedStateDiscreteSamplerFactory implements
750            SamplerBuilder.SamplerFactory<SharedStateDiscreteSampler> {
751        /** The instance. */
752        static final SharedStateDiscreteSamplerFactory INSTANCE = new SharedStateDiscreteSamplerFactory();
753
754        @Override
755        public SharedStateDiscreteSampler createSampler(DiscreteSampler discreteSampler,
756                                                        List<SharedStateDiscreteSampler> samplers) {
757            // The input discrete sampler is assumed to be a SharedStateDiscreteSampler
758            return new CompositeSharedStateDiscreteSampler(
759                (SharedStateDiscreteSampler) discreteSampler, samplers);
760        }
761
762        /**
763         * A composite discrete sampler with shared state support.
764         */
765        private static final class CompositeSharedStateDiscreteSampler
766                extends CompositeSampler<SharedStateDiscreteSampler>
767                implements SharedStateDiscreteSampler {
768            /**
769             * @param discreteSampler Discrete sampler to choose the individual sampler to sample.
770             * @param samplers Collection of samplers to be sampled from.
771             */
772            CompositeSharedStateDiscreteSampler(SharedStateDiscreteSampler discreteSampler,
773                                                List<SharedStateDiscreteSampler> samplers) {
774                super(discreteSampler, samplers);
775            }
776
777            @Override
778            public int sample() {
779                return nextSampler().sample();
780            }
781
782            @Override
783            public CompositeSharedStateDiscreteSampler withUniformRandomProvider(UniformRandomProvider rng) {
784                // Duplicate each sampler with the same source of randomness
785                return new CompositeSharedStateDiscreteSampler(
786                    ((SharedStateDiscreteSampler) this.discreteSampler).withUniformRandomProvider(rng),
787                    copy(samplers, rng));
788            }
789        }
790    }
791
792    /**
793     * A factory for creating a composite ContinuousSampler.
794     */
795    private static final class ContinuousSamplerFactory implements
796            SamplerBuilder.SamplerFactory<ContinuousSampler> {
797        /** The instance. */
798        static final ContinuousSamplerFactory INSTANCE = new ContinuousSamplerFactory();
799
800        @Override
801        public ContinuousSampler createSampler(DiscreteSampler discreteSampler,
802                                               List<ContinuousSampler> samplers) {
803            return new CompositeContinuousSampler(discreteSampler, samplers);
804        }
805
806        /**
807         * A composite continuous sampler.
808         */
809        private static final class CompositeContinuousSampler
810                extends CompositeSampler<ContinuousSampler>
811                implements ContinuousSampler {
812            /**
813             * @param discreteSampler Continuous sampler to choose the individual sampler to sample.
814             * @param samplers Collection of samplers to be sampled from.
815             */
816            CompositeContinuousSampler(DiscreteSampler discreteSampler,
817                                       List<ContinuousSampler> samplers) {
818                super(discreteSampler, samplers);
819            }
820
821            @Override
822            public double sample() {
823                return nextSampler().sample();
824            }
825        }
826    }
827
828    /**
829     * A factory for creating a composite SharedStateContinuousSampler.
830     */
831    private static final class SharedStateContinuousSamplerFactory implements
832            SamplerBuilder.SamplerFactory<SharedStateContinuousSampler> {
833        /** The instance. */
834        static final SharedStateContinuousSamplerFactory INSTANCE = new SharedStateContinuousSamplerFactory();
835
836        @Override
837        public SharedStateContinuousSampler createSampler(DiscreteSampler discreteSampler,
838                                                          List<SharedStateContinuousSampler> samplers) {
839            // The sampler is assumed to be a SharedStateContinuousSampler
840            return new CompositeSharedStateContinuousSampler(
841                (SharedStateDiscreteSampler) discreteSampler, samplers);
842        }
843
844        /**
845         * A composite continuous sampler with shared state support.
846         */
847        private static final class CompositeSharedStateContinuousSampler
848                extends CompositeSampler<SharedStateContinuousSampler>
849                implements SharedStateContinuousSampler {
850            /**
851             * @param discreteSampler Continuous sampler to choose the individual sampler to sample.
852             * @param samplers Collection of samplers to be sampled from.
853             */
854            CompositeSharedStateContinuousSampler(SharedStateDiscreteSampler discreteSampler,
855                                                  List<SharedStateContinuousSampler> samplers) {
856                super(discreteSampler, samplers);
857            }
858
859            @Override
860            public double sample() {
861                return nextSampler().sample();
862            }
863
864            @Override
865            public CompositeSharedStateContinuousSampler withUniformRandomProvider(UniformRandomProvider rng) {
866                // Duplicate each sampler with the same source of randomness
867                return new CompositeSharedStateContinuousSampler(
868                    ((SharedStateDiscreteSampler) this.discreteSampler).withUniformRandomProvider(rng),
869                    copy(samplers, rng));
870            }
871        }
872    }
873
874    /**
875     * A factory for creating a composite LongSampler.
876     */
877    private static final class LongSamplerFactory implements
878            SamplerBuilder.SamplerFactory<LongSampler> {
879        /** The instance. */
880        static final LongSamplerFactory INSTANCE = new LongSamplerFactory();
881
882        @Override
883        public LongSampler createSampler(DiscreteSampler discreteSampler,
884                                         List<LongSampler> samplers) {
885            return new CompositeLongSampler(discreteSampler, samplers);
886        }
887
888        /**
889         * A composite long sampler.
890         */
891        private static final class CompositeLongSampler
892                extends CompositeSampler<LongSampler>
893                implements LongSampler {
894            /**
895             * @param discreteSampler Long sampler to choose the individual sampler to sample.
896             * @param samplers Collection of samplers to be sampled from.
897             */
898            CompositeLongSampler(DiscreteSampler discreteSampler,
899                                 List<LongSampler> samplers) {
900                super(discreteSampler, samplers);
901            }
902
903            @Override
904            public long sample() {
905                return nextSampler().sample();
906            }
907        }
908    }
909
910    /**
911     * A factory for creating a composite SharedStateLongSampler.
912     */
913    private static final class SharedStateLongSamplerFactory implements
914            SamplerBuilder.SamplerFactory<SharedStateLongSampler> {
915        /** The instance. */
916        static final SharedStateLongSamplerFactory INSTANCE = new SharedStateLongSamplerFactory();
917
918        @Override
919        public SharedStateLongSampler createSampler(DiscreteSampler discreteSampler,
920                                                    List<SharedStateLongSampler> samplers) {
921            // The input discrete sampler is assumed to be a SharedStateLongSampler
922            return new CompositeSharedStateLongSampler(
923                (SharedStateDiscreteSampler) discreteSampler, samplers);
924        }
925
926        /**
927         * A composite long sampler with shared state support.
928         */
929        private static final class CompositeSharedStateLongSampler
930                extends CompositeSampler<SharedStateLongSampler>
931                implements SharedStateLongSampler {
932            /**
933             * @param discreteSampler Long sampler to choose the individual sampler to sample.
934             * @param samplers Collection of samplers to be sampled from.
935             */
936            CompositeSharedStateLongSampler(SharedStateDiscreteSampler discreteSampler,
937                                            List<SharedStateLongSampler> samplers) {
938                super(discreteSampler, samplers);
939            }
940
941            @Override
942            public long sample() {
943                return nextSampler().sample();
944            }
945
946            @Override
947            public CompositeSharedStateLongSampler withUniformRandomProvider(UniformRandomProvider rng) {
948                // Duplicate each sampler with the same source of randomness
949                return new CompositeSharedStateLongSampler(
950                    ((SharedStateDiscreteSampler) this.discreteSampler).withUniformRandomProvider(rng),
951                    copy(samplers, rng));
952            }
953        }
954    }
955
956    /** No public instances. */
957    private CompositeSamplers() {}
958
959    /**
960     * Create a new builder for a composite {@link ObjectSampler}.
961     *
962     * <p>Note: If the compiler cannot infer the type parameter of the sampler it can be specified
963     * within the diamond operator {@code <T>} preceding the call to
964     * {@code newObjectSamplerBuilder()}, for example:
965     *
966     * <pre>{@code
967     * CompositeSamplers.<double[]>newObjectSamplerBuilder()
968     * }</pre>
969     *
970     * @param <T> Type of the sample.
971     * @return the builder
972     */
973    public static <T> Builder<ObjectSampler<T>> newObjectSamplerBuilder() {
974        final SamplerBuilder.SamplerFactory<ObjectSampler<T>> factory = ObjectSamplerFactory.instance();
975        return new SamplerBuilder<>(
976            SamplerBuilder.Specialisation.NONE, factory);
977    }
978
979    /**
980     * Create a new builder for a composite {@link SharedStateObjectSampler}.
981     *
982     * <p>Note: If the compiler cannot infer the type parameter of the sampler it can be specified
983     * within the diamond operator {@code <T>} preceding the call to
984     * {@code newSharedStateObjectSamplerBuilder()}, for example:
985     *
986     * <pre>{@code
987     * CompositeSamplers.<double[]>newSharedStateObjectSamplerBuilder()
988     * }</pre>
989     *
990     * @param <T> Type of the sample.
991     * @return the builder
992     */
993    public static <T> Builder<SharedStateObjectSampler<T>> newSharedStateObjectSamplerBuilder() {
994        final SamplerBuilder.SamplerFactory<SharedStateObjectSampler<T>> factory =
995            SharedStateObjectSamplerFactory.instance();
996        return new SamplerBuilder<>(
997            SamplerBuilder.Specialisation.SHARED_STATE_SAMPLER, factory);
998    }
999
1000    /**
1001     * Create a new builder for a composite {@link DiscreteSampler}.
1002     *
1003     * @return the builder
1004     */
1005    public static Builder<DiscreteSampler> newDiscreteSamplerBuilder() {
1006        return new SamplerBuilder<>(
1007            SamplerBuilder.Specialisation.NONE, DiscreteSamplerFactory.INSTANCE);
1008    }
1009
1010    /**
1011     * Create a new builder for a composite {@link SharedStateDiscreteSampler}.
1012     *
1013     * @return the builder
1014     */
1015    public static Builder<SharedStateDiscreteSampler> newSharedStateDiscreteSamplerBuilder() {
1016        return new SamplerBuilder<>(
1017            SamplerBuilder.Specialisation.SHARED_STATE_SAMPLER, SharedStateDiscreteSamplerFactory.INSTANCE);
1018    }
1019
1020    /**
1021     * Create a new builder for a composite {@link ContinuousSampler}.
1022     *
1023     * @return the builder
1024     */
1025    public static Builder<ContinuousSampler> newContinuousSamplerBuilder() {
1026        return new SamplerBuilder<>(
1027            SamplerBuilder.Specialisation.NONE, ContinuousSamplerFactory.INSTANCE);
1028    }
1029
1030    /**
1031     * Create a new builder for a composite {@link SharedStateContinuousSampler}.
1032     *
1033     * @return the builder
1034     */
1035    public static Builder<SharedStateContinuousSampler> newSharedStateContinuousSamplerBuilder() {
1036        return new SamplerBuilder<>(
1037            SamplerBuilder.Specialisation.SHARED_STATE_SAMPLER, SharedStateContinuousSamplerFactory.INSTANCE);
1038    }
1039
1040    /**
1041     * Create a new builder for a composite {@link LongSampler}.
1042     *
1043     * @return the builder
1044     */
1045    public static Builder<LongSampler> newLongSamplerBuilder() {
1046        return new SamplerBuilder<>(
1047            SamplerBuilder.Specialisation.NONE, LongSamplerFactory.INSTANCE);
1048    }
1049
1050    /**
1051     * Create a new builder for a composite {@link SharedStateLongSampler}.
1052     *
1053     * @return the builder
1054     */
1055    public static Builder<SharedStateLongSampler> newSharedStateLongSamplerBuilder() {
1056        return new SamplerBuilder<>(
1057            SamplerBuilder.Specialisation.SHARED_STATE_SAMPLER, SharedStateLongSamplerFactory.INSTANCE);
1058    }
1059
1060    /**
1061     * Create a copy instance of each sampler in the list of samplers using the given
1062     * uniform random provider as the source of randomness.
1063     *
1064     * @param <T> the type of sampler
1065     * @param samplers Source to copy.
1066     * @param rng Generator of uniformly distributed random numbers.
1067     * @return the copy
1068     */
1069    private static <T extends SharedStateSampler<T>> List<T> copy(List<T> samplers,
1070                                                                  UniformRandomProvider rng) {
1071        final List<T> newSamplers = new ArrayList<>(samplers.size());
1072        for (final T s : samplers) {
1073            newSamplers.add(s.withUniformRandomProvider(rng));
1074        }
1075        return newSamplers;
1076    }
1077}