CompositeSamplers.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.rng.sampling;

  18. import java.util.List;
  19. import java.util.Objects;
  20. import java.util.ArrayList;

  21. import org.apache.commons.rng.UniformRandomProvider;
  22. import org.apache.commons.rng.sampling.distribution.AliasMethodDiscreteSampler;
  23. import org.apache.commons.rng.sampling.distribution.ContinuousSampler;
  24. import org.apache.commons.rng.sampling.distribution.DiscreteSampler;
  25. import org.apache.commons.rng.sampling.distribution.DiscreteUniformSampler;
  26. import org.apache.commons.rng.sampling.distribution.GuideTableDiscreteSampler;
  27. import org.apache.commons.rng.sampling.distribution.LongSampler;
  28. import org.apache.commons.rng.sampling.distribution.MarsagliaTsangWangDiscreteSampler;
  29. import org.apache.commons.rng.sampling.distribution.SharedStateContinuousSampler;
  30. import org.apache.commons.rng.sampling.distribution.SharedStateDiscreteSampler;
  31. import org.apache.commons.rng.sampling.distribution.SharedStateLongSampler;

  32. /**
  33.  * Factory class to create a sampler that combines sampling from multiple samplers.
  34.  *
  35.  * <p>The composite sampler is constructed using a {@link Builder builder} for the type of samplers
  36.  * that will form the composite. Each sampler has a weight in the composition.
  37.  * Samples are returned using a 2 step algorithm:
  38.  *
  39.  * <ol>
  40.  *  <li>Select a sampler based on its weighting
  41.  *  <li>Return a sample from the selected sampler
  42.  * </ol>
  43.  *
  44.  * <p>The weights used for each sampler create a discrete probability distribution. This is
  45.  * sampled using a discrete probability distribution sampler. The builder provides methods
  46.  * to change the default implementation.
  47.  *
  48.  * <p>The following example will create a sampler to uniformly sample the border of a triangle
  49.  * using the line segment lengths as weights:
  50.  *
  51.  * <pre>
  52.  * UniformRandomProvider rng = RandomSource.KISS.create();
  53.  * double[] a = {1.23, 4.56};
  54.  * double[] b = {6.78, 9.01};
  55.  * double[] c = {3.45, 2.34};
  56.  * ObjectSampler&lt;double[]&gt; sampler =
  57.  *     CompositeSamplers.&lt;double[]&gt;newObjectSamplerBuilder()
  58.  *         .add(LineSampler.of(rng, a, b), Math.hypot(a[0] - b[0], a[1] - b[1]))
  59.  *         .add(LineSampler.of(rng, b, c), Math.hypot(b[0] - c[0], b[1] - c[1]))
  60.  *         .add(LineSampler.of(rng, c, a), Math.hypot(c[0] - a[0], c[1] - a[1]))
  61.  *         .build(rng);
  62.  * </pre>
  63.  *
  64.  * @since 1.4
  65.  */
  66. public final class CompositeSamplers {
  67.     /**
  68.      * A factory for creating a sampler of a user-defined
  69.      * <a href="http://en.wikipedia.org/wiki/Probability_distribution#Discrete_probability_distribution">
  70.      * discrete probability distribution</a>.
  71.      */
  72.     public interface DiscreteProbabilitySamplerFactory {
  73.         /**
  74.          * Creates the sampler.
  75.          *
  76.          * @param rng Source of randomness.
  77.          * @param probabilities Discrete probability distribution.
  78.          * @return the sampler
  79.          */
  80.         DiscreteSampler create(UniformRandomProvider rng,
  81.                                double[] probabilities);
  82.     }

  83.     /**
  84.      * The DiscreteProbabilitySampler class defines implementations that sample from a user-defined
  85.      * <a href="http://en.wikipedia.org/wiki/Probability_distribution#Discrete_probability_distribution">
  86.      * discrete probability distribution</a>.
  87.      *
  88.      * <p>All implementations support the {@link SharedStateDiscreteSampler} interface.
  89.      */
  90.     public enum DiscreteProbabilitySampler implements DiscreteProbabilitySamplerFactory {
  91.         /** Sample using a guide table (see {@link GuideTableDiscreteSampler}). */
  92.         GUIDE_TABLE {
  93.             @Override
  94.             public SharedStateDiscreteSampler create(UniformRandomProvider rng, double[] probabilities) {
  95.                 return GuideTableDiscreteSampler.of(rng, probabilities);
  96.             }
  97.         },
  98.         /** Sample using the alias method (see {@link AliasMethodDiscreteSampler}). */
  99.         ALIAS_METHOD {
  100.             @Override
  101.             public SharedStateDiscreteSampler create(UniformRandomProvider rng, double[] probabilities) {
  102.                 return AliasMethodDiscreteSampler.of(rng, probabilities);
  103.             }
  104.         },
  105.         /**
  106.          * Sample using an optimised look-up table (see
  107.          * {@link org.apache.commons.rng.sampling.distribution.MarsagliaTsangWangDiscreteSampler.Enumerated
  108.          * MarsagliaTsangWangDiscreteSampler.Enumerated}).
  109.          */
  110.         LOOKUP_TABLE {
  111.             @Override
  112.             public SharedStateDiscreteSampler create(UniformRandomProvider rng, double[] probabilities) {
  113.                 return MarsagliaTsangWangDiscreteSampler.Enumerated.of(rng, probabilities);
  114.             }
  115.         }
  116.     }

  117.     /**
  118.      * A class to implement the SharedStateDiscreteSampler interface for a discrete probability
  119.      * sampler given a factory and the probability distribution. Each new instance will recreate
  120.      * the distribution sampler using the factory.
  121.      */
  122.     private static final class SharedStateDiscreteProbabilitySampler implements SharedStateDiscreteSampler {
  123.         /** The sampler. */
  124.         private final DiscreteSampler sampler;
  125.         /** The factory to create a new discrete sampler. */
  126.         private final DiscreteProbabilitySamplerFactory factory;
  127.         /** The probabilities. */
  128.         private final double[] probabilities;

  129.         /**
  130.          * @param sampler Sampler of the discrete distribution.
  131.          * @param factory Factory to create a new discrete sampler.
  132.          * @param probabilities Probabilities of the discrete distribution.
  133.          * @throws NullPointerException if the {@code sampler} is null
  134.          */
  135.         SharedStateDiscreteProbabilitySampler(DiscreteSampler sampler,
  136.                                               DiscreteProbabilitySamplerFactory factory,
  137.                                               double[] probabilities) {
  138.             this.sampler = Objects.requireNonNull(sampler, "discrete sampler");
  139.             // Assume the factory and probabilities are not null
  140.             this.factory = factory;
  141.             this.probabilities = probabilities;
  142.         }

  143.         @Override
  144.         public int sample() {
  145.             // Delegate
  146.             return sampler.sample();
  147.         }

  148.         @Override
  149.         public SharedStateDiscreteSampler withUniformRandomProvider(UniformRandomProvider rng) {
  150.             // The factory may destructively modify the probabilities
  151.             return new SharedStateDiscreteProbabilitySampler(factory.create(rng, probabilities.clone()),
  152.                                                              factory, probabilities);
  153.         }
  154.     }

  155.     /**
  156.      * Builds a composite sampler.
  157.      *
  158.      * <p>A composite sampler is a combination of multiple samplers
  159.      * that all return the same sample type. Each sampler has a weighting in the composition.
  160.      * Samples are returned using a 2 step algorithm:
  161.      *
  162.      * <ol>
  163.      *  <li>Select a sampler based on its weighting
  164.      *  <li>Return a sample from the selected sampler
  165.      * </ol>
  166.      *
  167.      * <p>Step 1 requires a discrete sampler constructed from a discrete probability distribution.
  168.      * The probability for each sampler is the sampler weight divided by the sum of the weights:
  169.      * <pre>
  170.      * p(i) = w(i) / sum(w)
  171.      * </pre>
  172.      *
  173.      * <p>The builder provides a method to set the factory used to generate the discrete sampler.
  174.      *
  175.      * @param <S> Type of sampler
  176.      */
  177.     public interface Builder<S> {
  178.         /**
  179.          * Return the number of samplers in the composite. The size must be non-zero before
  180.          * the {@link #build(UniformRandomProvider) build} method can create a sampler.
  181.          *
  182.          * @return the size
  183.          */
  184.         int size();

  185.         /**
  186.          * Adds the sampler to the composite. A sampler with a zero weight is ignored.
  187.          *
  188.          * @param sampler Sampler.
  189.          * @param weight Weight for the composition.
  190.          * @return a reference to this builder
  191.          * @throws IllegalArgumentException if {@code weight} is negative, infinite or {@code NaN}.
  192.          * @throws NullPointerException if {@code sampler} is null.
  193.          */
  194.         Builder<S> add(S sampler, double weight);

  195.         /**
  196.          * Sets the factory to use to generate the composite's discrete sampler from the sampler
  197.          * weights.
  198.          *
  199.          * <p>Note: If the factory is not explicitly set then a default will be used.
  200.          *
  201.          * @param factory Factory.
  202.          * @return a reference to this builder
  203.          * @throws NullPointerException if {@code factory} is null.
  204.          */
  205.         Builder<S> setFactory(DiscreteProbabilitySamplerFactory factory);

  206.         /**
  207.          * Builds the composite sampler. The {@code rng} is the source of randomness for selecting
  208.          * which sampler to use for each sample.
  209.          *
  210.          * <p>Note: When the sampler is created the builder is reset to an empty state.
  211.          * This prevents building multiple composite samplers with the same samplers and
  212.          * their identical underlying source of randomness.
  213.          *
  214.          * @param rng Generator of uniformly distributed random numbers.
  215.          * @return the sampler
  216.          * @throws IllegalStateException if no samplers have been added to create a composite.
  217.          * @see #size()
  218.          */
  219.         S build(UniformRandomProvider rng);
  220.     }

  221.     /**
  222.      * Builds a composite sampler.
  223.      *
  224.      * <p>A single builder can be used to create composites of different implementing classes
  225.      * which support different sampler interfaces. The type of sampler is generic. The individual
  226.      * samplers and their weights can be collected by the builder. The build method creates
  227.      * the discrete probability distribution from the weights. The final composite is created
  228.      * using a factory to create the class.
  229.      *
  230.      * @param <S> Type of sampler
  231.      */
  232.     private static final class SamplerBuilder<S> implements Builder<S> {
  233.         /** The specialisation of the sampler. */
  234.         private final Specialisation specialisation;
  235.         /** The weighted samplers. */
  236.         private final List<WeightedSampler<S>> weightedSamplers;
  237.         /** The factory to create the discrete probability sampler from the weights. */
  238.         private DiscreteProbabilitySamplerFactory factory;
  239.         /** The factory to create the composite sampler. */
  240.         private final SamplerFactory<S> compositeFactory;

  241.         /**
  242.          * The specialisation of composite sampler to build.
  243.          * This is used to determine if specialised interfaces from the sampler
  244.          * type must be supported, e.g. {@link SharedStateSampler}.
  245.          */
  246.         enum Specialisation {
  247.             /** Instance of {@link SharedStateSampler}. */
  248.             SHARED_STATE_SAMPLER,
  249.             /** No specialisation. */
  250.             NONE
  251.         }

  252.         /**
  253.          * A factory for creating composite samplers.
  254.          *
  255.          * <p>This interface is used to build concrete implementations
  256.          * of different sampler interfaces.
  257.          *
  258.          * @param <S> Type of sampler
  259.          */
  260.         interface SamplerFactory<S> {
  261.             /**
  262.              * Creates a new composite sampler.
  263.              *
  264.              * <p>If the composite specialisation is a
  265.              * {@link Specialisation#SHARED_STATE_SAMPLER shared state sampler}
  266.              * the discrete sampler passed to this method will be an instance of
  267.              * {@link SharedStateDiscreteSampler}.
  268.              *
  269.              * @param discreteSampler Discrete sampler.
  270.              * @param samplers Samplers.
  271.              * @return the sampler
  272.              */
  273.             S createSampler(DiscreteSampler discreteSampler,
  274.                             List<S> samplers);
  275.         }

  276.         /**
  277.          * Contains a weighted sampler.
  278.          *
  279.          * @param <S> Sampler type
  280.          */
  281.         private static final class WeightedSampler<S> {
  282.             /** The weight. */
  283.             private final double weight;
  284.             /** The sampler. */
  285.             private final S sampler;

  286.             /**
  287.              * @param weight the weight
  288.              * @param sampler the sampler
  289.              * @throws IllegalArgumentException if {@code weight} is negative, infinite or {@code NaN}.
  290.              * @throws NullPointerException if {@code sampler} is null.
  291.              */
  292.             WeightedSampler(double weight, S sampler) {
  293.                 this.weight = requirePositiveFinite(weight, "weight");
  294.                 this.sampler = Objects.requireNonNull(sampler, "sampler");
  295.             }

  296.             /**
  297.              * Gets the weight.
  298.              *
  299.              * @return the weight
  300.              */
  301.             double getWeight() {
  302.                 return weight;
  303.             }

  304.             /**
  305.              * Gets the sampler.
  306.              *
  307.              * @return the sampler
  308.              */
  309.             S getSampler() {
  310.                 return sampler;
  311.             }

  312.             /**
  313.              * Checks that the specified value is positive finite and throws a customized
  314.              * {@link IllegalArgumentException} if it is not.
  315.              *
  316.              * @param value the value
  317.              * @param message detail message to be used in the event that a {@code
  318.              *                IllegalArgumentException} is thrown
  319.              * @return {@code value} if positive finite
  320.              * @throws IllegalArgumentException if {@code weight} is negative, infinite or {@code NaN}.
  321.              */
  322.             private static double requirePositiveFinite(double value, String message) {
  323.                 // Must be positive finite
  324.                 if (!(value >= 0 && value < Double.POSITIVE_INFINITY)) {
  325.                     throw new IllegalArgumentException(message + " is not positive finite: " + value);
  326.                 }
  327.                 return value;
  328.             }
  329.         }

  330.         /**
  331.          * @param specialisation Specialisation of the sampler.
  332.          * @param compositeFactory Factory to create the final composite sampler.
  333.          */
  334.         SamplerBuilder(Specialisation specialisation,
  335.                        SamplerFactory<S> compositeFactory) {
  336.             this.specialisation = specialisation;
  337.             this.compositeFactory = compositeFactory;
  338.             weightedSamplers = new ArrayList<>();
  339.             factory = DiscreteProbabilitySampler.GUIDE_TABLE;
  340.         }

  341.         @Override
  342.         public int size() {
  343.             return weightedSamplers.size();
  344.         }

  345.         @Override
  346.         public Builder<S> add(S sampler, double weight) {
  347.             // Ignore zero weights. The sampler and weight are validated by the WeightedSampler.
  348.             if (weight != 0) {
  349.                 weightedSamplers.add(new WeightedSampler<>(weight, sampler));
  350.             }
  351.             return this;
  352.         }

  353.         /**
  354.          * {@inheritDoc}
  355.          *
  356.          * <p>If the weights are uniform the factory is ignored and composite's discrete sampler
  357.          * is a {@link DiscreteUniformSampler uniform distribution sampler}.
  358.          */
  359.         @Override
  360.         public Builder<S> setFactory(DiscreteProbabilitySamplerFactory samplerFactory) {
  361.             this.factory = Objects.requireNonNull(samplerFactory, "factory");
  362.             return this;
  363.         }

  364.         /**
  365.          * {@inheritDoc}
  366.          *
  367.          * <p>If only one sampler has been added to the builder then the sampler is returned
  368.          * and the builder is reset.
  369.          *
  370.          * @throws IllegalStateException if no samplers have been added to create a composite.
  371.          */
  372.         @Override
  373.         public S build(UniformRandomProvider rng) {
  374.             final List<WeightedSampler<S>> list = this.weightedSamplers;
  375.             final int n = list.size();
  376.             if (n == 0) {
  377.                 throw new IllegalStateException("No samplers to build the composite");
  378.             }
  379.             if (n == 1) {
  380.                 // No composite
  381.                 final S sampler = list.get(0).sampler;
  382.                 reset();
  383.                 return sampler;
  384.             }

  385.             // Extract the weights and samplers.
  386.             final double[] weights = new double[n];
  387.             final List<S> samplers = new ArrayList<>(n);
  388.             for (int i = 0; i < n; i++) {
  389.                 final WeightedSampler<S> weightedItem = list.get(i);
  390.                 weights[i] = weightedItem.getWeight();
  391.                 samplers.add(weightedItem.getSampler());
  392.             }

  393.             reset();

  394.             final DiscreteSampler discreteSampler = createDiscreteSampler(rng, weights);

  395.             return compositeFactory.createSampler(discreteSampler, samplers);
  396.         }

  397.         /**
  398.          * Reset the builder.
  399.          */
  400.         private void reset() {
  401.             weightedSamplers.clear();
  402.         }

  403.         /**
  404.          * Creates the discrete sampler of the enumerated probability distribution.
  405.          *
  406.          * <p>If the specialisation is a {@link Specialisation#SHARED_STATE_SAMPLER shared state sampler}
  407.          * the discrete sampler will be an instance of {@link SharedStateDiscreteSampler}.
  408.          *
  409.          * @param rng Generator of uniformly distributed random numbers.
  410.          * @param weights Weight associated to each item.
  411.          * @return the sampler
  412.          */
  413.         private DiscreteSampler createDiscreteSampler(UniformRandomProvider rng,
  414.                                                       double[] weights) {
  415.             // Edge case. Detect uniform weights.
  416.             final int n = weights.length;
  417.             if (uniform(weights)) {
  418.                 // Uniformly sample from the size.
  419.                 // Note: Upper bound is inclusive.
  420.                 return DiscreteUniformSampler.of(rng, 0, n - 1);
  421.             }

  422.             // If possible normalise with a simple sum.
  423.             final double sum = sum(weights);
  424.             if (sum < Double.POSITIVE_INFINITY) {
  425.                 // Do not use f = 1.0 / sum and multiplication by f.
  426.                 // Use of divide handles a sub-normal sum.
  427.                 for (int i = 0; i < n; i++) {
  428.                     weights[i] /= sum;
  429.                 }
  430.             } else {
  431.                 // The sum is not finite. We know the weights are all positive finite.
  432.                 // Compute the mean without overflow and divide by the mean and number of items.
  433.                 final double mean = mean(weights);
  434.                 for (int i = 0; i < n; i++) {
  435.                     // Two step division avoids using the denominator (mean * n)
  436.                     weights[i] = weights[i] / mean / n;
  437.                 }
  438.             }

  439.             // Create the sampler from the factory.
  440.             // Check if a SharedStateSampler is required.
  441.             // If a default factory then the result is a SharedStateDiscreteSampler,
  442.             // otherwise the sampler must be checked.
  443.             if (specialisation == Specialisation.SHARED_STATE_SAMPLER &&
  444.                 !(factory instanceof DiscreteProbabilitySampler)) {
  445.                 // If the factory was user-defined then clone the weights as they may be required
  446.                 // to create a SharedStateDiscreteProbabilitySampler.
  447.                 final DiscreteSampler sampler = factory.create(rng, weights.clone());
  448.                 return sampler instanceof SharedStateDiscreteSampler ?
  449.                      sampler :
  450.                      new SharedStateDiscreteProbabilitySampler(sampler, factory, weights);
  451.             }

  452.             return factory.create(rng, weights);
  453.         }

  454.         /**
  455.          * Check if all the values are the same.
  456.          *
  457.          * <p>Warning: This method assumes there are input values. If the length is zero an
  458.          * {@link ArrayIndexOutOfBoundsException} will be thrown.
  459.          *
  460.          * @param values the values
  461.          * @return true if all values are the same
  462.          */
  463.         private static boolean uniform(double[] values) {
  464.             final double value = values[0];
  465.             for (int i = 1; i < values.length; i++) {
  466.                 if (value != values[i]) {
  467.                     return false;
  468.                 }
  469.             }
  470.             return true;
  471.         }

  472.         /**
  473.          * Compute the sum of the values.
  474.          *
  475.          * @param values the values
  476.          * @return the sum
  477.          */
  478.         private static double sum(double[] values) {
  479.             double sum = 0;
  480.             for (final double value : values) {
  481.                 sum += value;
  482.             }
  483.             return sum;
  484.         }

  485.         /**
  486.          * Compute the mean of the values. Uses a rolling algorithm to avoid overflow of a simple sum.
  487.          * This method can be used to compute the mean of observed counts for normalisation to a
  488.          * probability:
  489.          *
  490.          * <pre>
  491.          * double[] values = ...;
  492.          * int n = values.length;
  493.          * double mean = mean(values);
  494.          * for (int i = 0; i &lt; n; i++) {
  495.          *     // Two step division avoids using the denominator (mean * n)
  496.          *     values[i] = values[i] / mean / n;
  497.          * }
  498.          * </pre>
  499.          *
  500.          * <p>Warning: This method assumes there are input values. If the length is zero an
  501.          * {@link ArrayIndexOutOfBoundsException} will be thrown.
  502.          *
  503.          * @param values the values
  504.          * @return the mean
  505.          */
  506.         private static double mean(double[] values) {
  507.             double mean = values[0];
  508.             int i = 1;
  509.             while (i < values.length) {
  510.                 // Deviation from the mean
  511.                 final double dev = values[i] - mean;
  512.                 i++;
  513.                 mean += dev / i;
  514.             }
  515.             return mean;
  516.         }
  517.     }

  518.     /**
  519.      * A composite sampler.
  520.      *
  521.      * <p>The source sampler for each sampler is chosen based on a user-defined continuous
  522.      * probability distribution.
  523.      *
  524.      * @param <S> Type of sampler
  525.      */
  526.     private static class CompositeSampler<S> {
  527.         /** Continuous sampler to choose the individual sampler to sample. */
  528.         protected final DiscreteSampler discreteSampler;
  529.         /** Collection of samplers to be sampled from. */
  530.         protected final List<S> samplers;

  531.         /**
  532.          * @param discreteSampler Continuous sampler to choose the individual sampler to sample.
  533.          * @param samplers Collection of samplers to be sampled from.
  534.          */
  535.         CompositeSampler(DiscreteSampler discreteSampler,
  536.                          List<S> samplers) {
  537.             this.discreteSampler = discreteSampler;
  538.             this.samplers = samplers;
  539.         }

  540.         /**
  541.          * Gets the next sampler to use to create a sample.
  542.          *
  543.          * @return the sampler
  544.          */
  545.         S nextSampler() {
  546.             return samplers.get(discreteSampler.sample());
  547.         }
  548.     }

  549.     /**
  550.      * A factory for creating a composite ObjectSampler.
  551.      *
  552.      * @param <T> Type of sample
  553.      */
  554.     private static final class ObjectSamplerFactory<T> implements
  555.             SamplerBuilder.SamplerFactory<ObjectSampler<T>> {
  556.         /** The instance. */
  557.         @SuppressWarnings("rawtypes")
  558.         private static final ObjectSamplerFactory INSTANCE = new ObjectSamplerFactory<>();

  559.         /**
  560.          * Get an instance.
  561.          *
  562.          * @param <T> Type of sample
  563.          * @return the factory
  564.          */
  565.         @SuppressWarnings("unchecked")
  566.         static <T> ObjectSamplerFactory<T> instance() {
  567.             return (ObjectSamplerFactory<T>) INSTANCE;
  568.         }

  569.         @Override
  570.         public ObjectSampler<T> createSampler(DiscreteSampler discreteSampler,
  571.                                               List<ObjectSampler<T>> samplers) {
  572.             return new CompositeObjectSampler<>(discreteSampler, samplers);
  573.         }

  574.         /**
  575.          * A composite object sampler.
  576.          *
  577.          * @param <T> Type of sample
  578.          */
  579.         private static final class CompositeObjectSampler<T>
  580.                 extends CompositeSampler<ObjectSampler<T>>
  581.                 implements ObjectSampler<T> {
  582.             /**
  583.              * @param discreteSampler Discrete sampler to choose the individual sampler to sample.
  584.              * @param samplers Collection of samplers to be sampled from.
  585.              */
  586.             CompositeObjectSampler(DiscreteSampler discreteSampler,
  587.                                    List<ObjectSampler<T>> samplers) {
  588.                 super(discreteSampler, samplers);
  589.             }

  590.             @Override
  591.             public T sample() {
  592.                 return nextSampler().sample();
  593.             }
  594.         }
  595.     }

  596.     /**
  597.      * A factory for creating a composite SharedStateObjectSampler.
  598.      *
  599.      * @param <T> Type of sample
  600.      */
  601.     private static final class SharedStateObjectSamplerFactory<T> implements
  602.             SamplerBuilder.SamplerFactory<SharedStateObjectSampler<T>> {
  603.         /** The instance. */
  604.         @SuppressWarnings("rawtypes")
  605.         private static final SharedStateObjectSamplerFactory INSTANCE = new SharedStateObjectSamplerFactory<>();

  606.         /**
  607.          * Get an instance.
  608.          *
  609.          * @param <T> Type of sample
  610.          * @return the factory
  611.          */
  612.         @SuppressWarnings("unchecked")
  613.         static <T> SharedStateObjectSamplerFactory<T> instance() {
  614.             return (SharedStateObjectSamplerFactory<T>) INSTANCE;
  615.         }

  616.         @Override
  617.         public SharedStateObjectSampler<T> createSampler(DiscreteSampler discreteSampler,
  618.                                                          List<SharedStateObjectSampler<T>> samplers) {
  619.             // The input discrete sampler is assumed to be a SharedStateDiscreteSampler
  620.             return new CompositeSharedStateObjectSampler<>(
  621.                 (SharedStateDiscreteSampler) discreteSampler, samplers);
  622.         }

  623.         /**
  624.          * A composite object sampler with shared state support.
  625.          *
  626.          * <p>The source sampler for each sampler is chosen based on a user-defined
  627.          * discrete probability distribution.
  628.          *
  629.          * @param <T> Type of sample
  630.          */
  631.         private static final class CompositeSharedStateObjectSampler<T>
  632.                 extends CompositeSampler<SharedStateObjectSampler<T>>
  633.                 implements SharedStateObjectSampler<T> {
  634.             /**
  635.              * @param discreteSampler Discrete sampler to choose the individual sampler to sample.
  636.              * @param samplers Collection of samplers to be sampled from.
  637.              */
  638.             CompositeSharedStateObjectSampler(SharedStateDiscreteSampler discreteSampler,
  639.                                               List<SharedStateObjectSampler<T>> samplers) {
  640.                 super(discreteSampler, samplers);
  641.             }

  642.             @Override
  643.             public T sample() {
  644.                 return nextSampler().sample();
  645.             }

  646.             @Override
  647.             public CompositeSharedStateObjectSampler<T> withUniformRandomProvider(UniformRandomProvider rng) {
  648.                 // Duplicate each sampler with the same source of randomness
  649.                 return new CompositeSharedStateObjectSampler<>(
  650.                     ((SharedStateDiscreteSampler) this.discreteSampler).withUniformRandomProvider(rng),
  651.                     copy(samplers, rng));
  652.             }
  653.         }
  654.     }

  655.     /**
  656.      * A factory for creating a composite DiscreteSampler.
  657.      */
  658.     private static final class DiscreteSamplerFactory implements
  659.             SamplerBuilder.SamplerFactory<DiscreteSampler> {
  660.         /** The instance. */
  661.         static final DiscreteSamplerFactory INSTANCE = new DiscreteSamplerFactory();

  662.         @Override
  663.         public DiscreteSampler createSampler(DiscreteSampler discreteSampler,
  664.                                              List<DiscreteSampler> samplers) {
  665.             return new CompositeDiscreteSampler(discreteSampler, samplers);
  666.         }

  667.         /**
  668.          * A composite discrete sampler.
  669.          */
  670.         private static final class CompositeDiscreteSampler
  671.                 extends CompositeSampler<DiscreteSampler>
  672.                 implements DiscreteSampler {
  673.             /**
  674.              * @param discreteSampler Discrete sampler to choose the individual sampler to sample.
  675.              * @param samplers Collection of samplers to be sampled from.
  676.              */
  677.             CompositeDiscreteSampler(DiscreteSampler discreteSampler,
  678.                                      List<DiscreteSampler> samplers) {
  679.                 super(discreteSampler, samplers);
  680.             }

  681.             @Override
  682.             public int sample() {
  683.                 return nextSampler().sample();
  684.             }
  685.         }
  686.     }

  687.     /**
  688.      * A factory for creating a composite SharedStateDiscreteSampler.
  689.      */
  690.     private static final class SharedStateDiscreteSamplerFactory implements
  691.             SamplerBuilder.SamplerFactory<SharedStateDiscreteSampler> {
  692.         /** The instance. */
  693.         static final SharedStateDiscreteSamplerFactory INSTANCE = new SharedStateDiscreteSamplerFactory();

  694.         @Override
  695.         public SharedStateDiscreteSampler createSampler(DiscreteSampler discreteSampler,
  696.                                                         List<SharedStateDiscreteSampler> samplers) {
  697.             // The input discrete sampler is assumed to be a SharedStateDiscreteSampler
  698.             return new CompositeSharedStateDiscreteSampler(
  699.                 (SharedStateDiscreteSampler) discreteSampler, samplers);
  700.         }

  701.         /**
  702.          * A composite discrete sampler with shared state support.
  703.          */
  704.         private static final class CompositeSharedStateDiscreteSampler
  705.                 extends CompositeSampler<SharedStateDiscreteSampler>
  706.                 implements SharedStateDiscreteSampler {
  707.             /**
  708.              * @param discreteSampler Discrete sampler to choose the individual sampler to sample.
  709.              * @param samplers Collection of samplers to be sampled from.
  710.              */
  711.             CompositeSharedStateDiscreteSampler(SharedStateDiscreteSampler discreteSampler,
  712.                                                 List<SharedStateDiscreteSampler> samplers) {
  713.                 super(discreteSampler, samplers);
  714.             }

  715.             @Override
  716.             public int sample() {
  717.                 return nextSampler().sample();
  718.             }

  719.             @Override
  720.             public CompositeSharedStateDiscreteSampler withUniformRandomProvider(UniformRandomProvider rng) {
  721.                 // Duplicate each sampler with the same source of randomness
  722.                 return new CompositeSharedStateDiscreteSampler(
  723.                     ((SharedStateDiscreteSampler) this.discreteSampler).withUniformRandomProvider(rng),
  724.                     copy(samplers, rng));
  725.             }
  726.         }
  727.     }

  728.     /**
  729.      * A factory for creating a composite ContinuousSampler.
  730.      */
  731.     private static final class ContinuousSamplerFactory implements
  732.             SamplerBuilder.SamplerFactory<ContinuousSampler> {
  733.         /** The instance. */
  734.         static final ContinuousSamplerFactory INSTANCE = new ContinuousSamplerFactory();

  735.         @Override
  736.         public ContinuousSampler createSampler(DiscreteSampler discreteSampler,
  737.                                                List<ContinuousSampler> samplers) {
  738.             return new CompositeContinuousSampler(discreteSampler, samplers);
  739.         }

  740.         /**
  741.          * A composite continuous sampler.
  742.          */
  743.         private static final class CompositeContinuousSampler
  744.                 extends CompositeSampler<ContinuousSampler>
  745.                 implements ContinuousSampler {
  746.             /**
  747.              * @param discreteSampler Continuous sampler to choose the individual sampler to sample.
  748.              * @param samplers Collection of samplers to be sampled from.
  749.              */
  750.             CompositeContinuousSampler(DiscreteSampler discreteSampler,
  751.                                        List<ContinuousSampler> samplers) {
  752.                 super(discreteSampler, samplers);
  753.             }

  754.             @Override
  755.             public double sample() {
  756.                 return nextSampler().sample();
  757.             }
  758.         }
  759.     }

  760.     /**
  761.      * A factory for creating a composite SharedStateContinuousSampler.
  762.      */
  763.     private static final class SharedStateContinuousSamplerFactory implements
  764.             SamplerBuilder.SamplerFactory<SharedStateContinuousSampler> {
  765.         /** The instance. */
  766.         static final SharedStateContinuousSamplerFactory INSTANCE = new SharedStateContinuousSamplerFactory();

  767.         @Override
  768.         public SharedStateContinuousSampler createSampler(DiscreteSampler discreteSampler,
  769.                                                           List<SharedStateContinuousSampler> samplers) {
  770.             // The sampler is assumed to be a SharedStateContinuousSampler
  771.             return new CompositeSharedStateContinuousSampler(
  772.                 (SharedStateDiscreteSampler) discreteSampler, samplers);
  773.         }

  774.         /**
  775.          * A composite continuous sampler with shared state support.
  776.          */
  777.         private static final class CompositeSharedStateContinuousSampler
  778.                 extends CompositeSampler<SharedStateContinuousSampler>
  779.                 implements SharedStateContinuousSampler {
  780.             /**
  781.              * @param discreteSampler Continuous sampler to choose the individual sampler to sample.
  782.              * @param samplers Collection of samplers to be sampled from.
  783.              */
  784.             CompositeSharedStateContinuousSampler(SharedStateDiscreteSampler discreteSampler,
  785.                                                   List<SharedStateContinuousSampler> samplers) {
  786.                 super(discreteSampler, samplers);
  787.             }

  788.             @Override
  789.             public double sample() {
  790.                 return nextSampler().sample();
  791.             }

  792.             @Override
  793.             public CompositeSharedStateContinuousSampler withUniformRandomProvider(UniformRandomProvider rng) {
  794.                 // Duplicate each sampler with the same source of randomness
  795.                 return new CompositeSharedStateContinuousSampler(
  796.                     ((SharedStateDiscreteSampler) this.discreteSampler).withUniformRandomProvider(rng),
  797.                     copy(samplers, rng));
  798.             }
  799.         }
  800.     }

  801.     /**
  802.      * A factory for creating a composite LongSampler.
  803.      */
  804.     private static final class LongSamplerFactory implements
  805.             SamplerBuilder.SamplerFactory<LongSampler> {
  806.         /** The instance. */
  807.         static final LongSamplerFactory INSTANCE = new LongSamplerFactory();

  808.         @Override
  809.         public LongSampler createSampler(DiscreteSampler discreteSampler,
  810.                                          List<LongSampler> samplers) {
  811.             return new CompositeLongSampler(discreteSampler, samplers);
  812.         }

  813.         /**
  814.          * A composite long sampler.
  815.          */
  816.         private static final class CompositeLongSampler
  817.                 extends CompositeSampler<LongSampler>
  818.                 implements LongSampler {
  819.             /**
  820.              * @param discreteSampler Long sampler to choose the individual sampler to sample.
  821.              * @param samplers Collection of samplers to be sampled from.
  822.              */
  823.             CompositeLongSampler(DiscreteSampler discreteSampler,
  824.                                  List<LongSampler> samplers) {
  825.                 super(discreteSampler, samplers);
  826.             }

  827.             @Override
  828.             public long sample() {
  829.                 return nextSampler().sample();
  830.             }
  831.         }
  832.     }

  833.     /**
  834.      * A factory for creating a composite SharedStateLongSampler.
  835.      */
  836.     private static final class SharedStateLongSamplerFactory implements
  837.             SamplerBuilder.SamplerFactory<SharedStateLongSampler> {
  838.         /** The instance. */
  839.         static final SharedStateLongSamplerFactory INSTANCE = new SharedStateLongSamplerFactory();

  840.         @Override
  841.         public SharedStateLongSampler createSampler(DiscreteSampler discreteSampler,
  842.                                                     List<SharedStateLongSampler> samplers) {
  843.             // The input discrete sampler is assumed to be a SharedStateLongSampler
  844.             return new CompositeSharedStateLongSampler(
  845.                 (SharedStateDiscreteSampler) discreteSampler, samplers);
  846.         }

  847.         /**
  848.          * A composite long sampler with shared state support.
  849.          */
  850.         private static final class CompositeSharedStateLongSampler
  851.                 extends CompositeSampler<SharedStateLongSampler>
  852.                 implements SharedStateLongSampler {
  853.             /**
  854.              * @param discreteSampler Long sampler to choose the individual sampler to sample.
  855.              * @param samplers Collection of samplers to be sampled from.
  856.              */
  857.             CompositeSharedStateLongSampler(SharedStateDiscreteSampler discreteSampler,
  858.                                             List<SharedStateLongSampler> samplers) {
  859.                 super(discreteSampler, samplers);
  860.             }

  861.             @Override
  862.             public long sample() {
  863.                 return nextSampler().sample();
  864.             }

  865.             @Override
  866.             public CompositeSharedStateLongSampler withUniformRandomProvider(UniformRandomProvider rng) {
  867.                 // Duplicate each sampler with the same source of randomness
  868.                 return new CompositeSharedStateLongSampler(
  869.                     ((SharedStateDiscreteSampler) this.discreteSampler).withUniformRandomProvider(rng),
  870.                     copy(samplers, rng));
  871.             }
  872.         }
  873.     }

  874.     /** No public instances. */
  875.     private CompositeSamplers() {}

  876.     /**
  877.      * Create a new builder for a composite {@link ObjectSampler}.
  878.      *
  879.      * <p>Note: If the compiler cannot infer the type parameter of the sampler it can be specified
  880.      * within the diamond operator {@code <T>} preceding the call to
  881.      * {@code newObjectSamplerBuilder()}, for example:
  882.      *
  883.      * <pre>{@code
  884.      * CompositeSamplers.<double[]>newObjectSamplerBuilder()
  885.      * }</pre>
  886.      *
  887.      * @param <T> Type of the sample.
  888.      * @return the builder
  889.      */
  890.     public static <T> Builder<ObjectSampler<T>> newObjectSamplerBuilder() {
  891.         final SamplerBuilder.SamplerFactory<ObjectSampler<T>> factory = ObjectSamplerFactory.instance();
  892.         return new SamplerBuilder<>(
  893.             SamplerBuilder.Specialisation.NONE, factory);
  894.     }

  895.     /**
  896.      * Create a new builder for a composite {@link SharedStateObjectSampler}.
  897.      *
  898.      * <p>Note: If the compiler cannot infer the type parameter of the sampler it can be specified
  899.      * within the diamond operator {@code <T>} preceding the call to
  900.      * {@code newSharedStateObjectSamplerBuilder()}, for example:
  901.      *
  902.      * <pre>{@code
  903.      * CompositeSamplers.<double[]>newSharedStateObjectSamplerBuilder()
  904.      * }</pre>
  905.      *
  906.      * @param <T> Type of the sample.
  907.      * @return the builder
  908.      */
  909.     public static <T> Builder<SharedStateObjectSampler<T>> newSharedStateObjectSamplerBuilder() {
  910.         final SamplerBuilder.SamplerFactory<SharedStateObjectSampler<T>> factory =
  911.             SharedStateObjectSamplerFactory.instance();
  912.         return new SamplerBuilder<>(
  913.             SamplerBuilder.Specialisation.SHARED_STATE_SAMPLER, factory);
  914.     }

  915.     /**
  916.      * Create a new builder for a composite {@link DiscreteSampler}.
  917.      *
  918.      * @return the builder
  919.      */
  920.     public static Builder<DiscreteSampler> newDiscreteSamplerBuilder() {
  921.         return new SamplerBuilder<>(
  922.             SamplerBuilder.Specialisation.NONE, DiscreteSamplerFactory.INSTANCE);
  923.     }

  924.     /**
  925.      * Create a new builder for a composite {@link SharedStateDiscreteSampler}.
  926.      *
  927.      * @return the builder
  928.      */
  929.     public static Builder<SharedStateDiscreteSampler> newSharedStateDiscreteSamplerBuilder() {
  930.         return new SamplerBuilder<>(
  931.             SamplerBuilder.Specialisation.SHARED_STATE_SAMPLER, SharedStateDiscreteSamplerFactory.INSTANCE);
  932.     }

  933.     /**
  934.      * Create a new builder for a composite {@link ContinuousSampler}.
  935.      *
  936.      * @return the builder
  937.      */
  938.     public static Builder<ContinuousSampler> newContinuousSamplerBuilder() {
  939.         return new SamplerBuilder<>(
  940.             SamplerBuilder.Specialisation.NONE, ContinuousSamplerFactory.INSTANCE);
  941.     }

  942.     /**
  943.      * Create a new builder for a composite {@link SharedStateContinuousSampler}.
  944.      *
  945.      * @return the builder
  946.      */
  947.     public static Builder<SharedStateContinuousSampler> newSharedStateContinuousSamplerBuilder() {
  948.         return new SamplerBuilder<>(
  949.             SamplerBuilder.Specialisation.SHARED_STATE_SAMPLER, SharedStateContinuousSamplerFactory.INSTANCE);
  950.     }

  951.     /**
  952.      * Create a new builder for a composite {@link LongSampler}.
  953.      *
  954.      * @return the builder
  955.      */
  956.     public static Builder<LongSampler> newLongSamplerBuilder() {
  957.         return new SamplerBuilder<>(
  958.             SamplerBuilder.Specialisation.NONE, LongSamplerFactory.INSTANCE);
  959.     }

  960.     /**
  961.      * Create a new builder for a composite {@link SharedStateLongSampler}.
  962.      *
  963.      * @return the builder
  964.      */
  965.     public static Builder<SharedStateLongSampler> newSharedStateLongSamplerBuilder() {
  966.         return new SamplerBuilder<>(
  967.             SamplerBuilder.Specialisation.SHARED_STATE_SAMPLER, SharedStateLongSamplerFactory.INSTANCE);
  968.     }

  969.     /**
  970.      * Create a copy instance of each sampler in the list of samplers using the given
  971.      * uniform random provider as the source of randomness.
  972.      *
  973.      * @param <T> the type of sampler
  974.      * @param samplers Source to copy.
  975.      * @param rng Generator of uniformly distributed random numbers.
  976.      * @return the copy
  977.      */
  978.     private static <T extends SharedStateSampler<T>> List<T> copy(List<T> samplers,
  979.                                                                   UniformRandomProvider rng) {
  980.         final List<T> newSamplers = new ArrayList<>(samplers.size());
  981.         for (final T s : samplers) {
  982.             newSamplers.add(s.withUniformRandomProvider(rng));
  983.         }
  984.         return newSamplers;
  985.     }
  986. }