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