All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.rng.sampling.CompositeSamplers Maven / Gradle / Ivy

Go to download

The Apache Commons RNG Sampling module provides samplers for various distributions.

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

package org.apache.commons.rng.sampling;

import java.util.List;
import java.util.Objects;
import java.util.ArrayList;

import org.apache.commons.rng.UniformRandomProvider;
import org.apache.commons.rng.sampling.distribution.AliasMethodDiscreteSampler;
import org.apache.commons.rng.sampling.distribution.ContinuousSampler;
import org.apache.commons.rng.sampling.distribution.DiscreteSampler;
import org.apache.commons.rng.sampling.distribution.DiscreteUniformSampler;
import org.apache.commons.rng.sampling.distribution.GuideTableDiscreteSampler;
import org.apache.commons.rng.sampling.distribution.LongSampler;
import org.apache.commons.rng.sampling.distribution.MarsagliaTsangWangDiscreteSampler;
import org.apache.commons.rng.sampling.distribution.SharedStateContinuousSampler;
import org.apache.commons.rng.sampling.distribution.SharedStateDiscreteSampler;
import org.apache.commons.rng.sampling.distribution.SharedStateLongSampler;

/**
 * Factory class to create a sampler that combines sampling from multiple samplers.
 *
 * 

The composite sampler is constructed using a {@link Builder builder} for the type of samplers * that will form the composite. Each sampler has a weight in the composition. * Samples are returned using a 2 step algorithm: * *

    *
  1. Select a sampler based on its weighting *
  2. Return a sample from the selected sampler *
* *

The weights used for each sampler create a discrete probability distribution. This is * sampled using a discrete probability distribution sampler. The builder provides methods * to change the default implementation. * *

The following example will create a sampler to uniformly sample the border of a triangle * using the line segment lengths as weights: * *

 * UniformRandomProvider rng = RandomSource.KISS.create();
 * double[] a = {1.23, 4.56};
 * double[] b = {6.78, 9.01};
 * double[] c = {3.45, 2.34};
 * ObjectSampler<double[]> sampler =
 *     CompositeSamplers.<double[]>newObjectSamplerBuilder()
 *         .add(LineSampler.of(rng, a, b), Math.hypot(a[0] - b[0], a[1] - b[1]))
 *         .add(LineSampler.of(rng, b, c), Math.hypot(b[0] - c[0], b[1] - c[1]))
 *         .add(LineSampler.of(rng, c, a), Math.hypot(c[0] - a[0], c[1] - a[1]))
 *         .build(rng);
 * 
* * @since 1.4 */ public final class CompositeSamplers { /** * A factory for creating a sampler of a user-defined * * discrete probability distribution. */ public interface DiscreteProbabilitySamplerFactory { /** * Creates the sampler. * * @param rng Source of randomness. * @param probabilities Discrete probability distribution. * @return the sampler */ DiscreteSampler create(UniformRandomProvider rng, double[] probabilities); } /** * The DiscreteProbabilitySampler class defines implementations that sample from a user-defined * * discrete probability distribution. * *

All implementations support the {@link SharedStateDiscreteSampler} interface. */ public enum DiscreteProbabilitySampler implements DiscreteProbabilitySamplerFactory { /** Sample using a guide table (see {@link GuideTableDiscreteSampler}). */ GUIDE_TABLE { @Override public SharedStateDiscreteSampler create(UniformRandomProvider rng, double[] probabilities) { return GuideTableDiscreteSampler.of(rng, probabilities); } }, /** Sample using the alias method (see {@link AliasMethodDiscreteSampler}). */ ALIAS_METHOD { @Override public SharedStateDiscreteSampler create(UniformRandomProvider rng, double[] probabilities) { return AliasMethodDiscreteSampler.of(rng, probabilities); } }, /** * Sample using an optimised look-up table (see * {@link org.apache.commons.rng.sampling.distribution.MarsagliaTsangWangDiscreteSampler.Enumerated * MarsagliaTsangWangDiscreteSampler.Enumerated}). */ LOOKUP_TABLE { @Override public SharedStateDiscreteSampler create(UniformRandomProvider rng, double[] probabilities) { return MarsagliaTsangWangDiscreteSampler.Enumerated.of(rng, probabilities); } } } /** * A class to implement the SharedStateDiscreteSampler interface for a discrete probability * sampler given a factory and the probability distribution. Each new instance will recreate * the distribution sampler using the factory. */ private static class SharedStateDiscreteProbabilitySampler implements SharedStateDiscreteSampler { /** The sampler. */ private final DiscreteSampler sampler; /** The factory to create a new discrete sampler. */ private final DiscreteProbabilitySamplerFactory factory; /** The probabilities. */ private final double[] probabilities; /** * @param sampler Sampler of the discrete distribution. * @param factory Factory to create a new discrete sampler. * @param probabilities Probabilities of the discrete distribution. * @throws NullPointerException if the {@code sampler} is null */ SharedStateDiscreteProbabilitySampler(DiscreteSampler sampler, DiscreteProbabilitySamplerFactory factory, double[] probabilities) { this.sampler = Objects.requireNonNull(sampler, "discrete sampler"); // Assume the factory and probabilities are not null this.factory = factory; this.probabilities = probabilities; } @Override public int sample() { // Delegate return sampler.sample(); } @Override public SharedStateDiscreteSampler withUniformRandomProvider(UniformRandomProvider rng) { // The factory may destructively modify the probabilities return new SharedStateDiscreteProbabilitySampler(factory.create(rng, probabilities.clone()), factory, probabilities); } } /** * Builds a composite sampler. * *

A composite sampler is a combination of multiple samplers * that all return the same sample type. Each sampler has a weighting in the composition. * Samples are returned using a 2 step algorithm: * *

    *
  1. Select a sampler based on its weighting *
  2. Return a sample from the selected sampler *
* *

Step 1 requires a discrete sampler constructed from a discrete probability distribution. * The probability for each sampler is the sampler weight divided by the sum of the weights: *

     * p(i) = w(i) / sum(w)
     * 
* *

The builder provides a method to set the factory used to generate the discrete sampler. * * @param Type of sampler */ public interface Builder { /** * Return the number of samplers in the composite. The size must be non-zero before * the {@link #build(UniformRandomProvider) build} method can create a sampler. * * @return the size */ int size(); /** * Adds the sampler to the composite. A sampler with a zero weight is ignored. * * @param sampler Sampler. * @param weight Weight for the composition. * @return a reference to this builder * @throws IllegalArgumentException if {@code weight} is negative, infinite or {@code NaN}. * @throws NullPointerException if {@code sampler} is null. */ Builder add(S sampler, double weight); /** * Sets the factory to use to generate the composite's discrete sampler from the sampler * weights. * *

Note: If the factory is not explicitly set then a default will be used. * * @param factory Factory. * @return a reference to this builder * @throws NullPointerException if {@code factory} is null. */ Builder setFactory(DiscreteProbabilitySamplerFactory factory); /** * Builds the composite sampler. The {@code rng} is the source of randomness for selecting * which sampler to use for each sample. * *

Note: When the sampler is created the builder is reset to an empty state. * This prevents building multiple composite samplers with the same samplers and * their identical underlying source of randomness. * * @param rng Generator of uniformly distributed random numbers. * @return the sampler * @throws IllegalStateException if no samplers have been added to create a composite. * @see #size() */ S build(UniformRandomProvider rng); } /** * Builds a composite sampler. * *

A single builder can be used to create composites of different implementing classes * which support different sampler interfaces. The type of sampler is generic. The individual * samplers and their weights can be collected by the builder. The build method creates * the discrete probability distribution from the weights. The final composite is created * using a factory to create the class. * * @param Type of sampler */ private static class SamplerBuilder implements Builder { /** The specialisation of the sampler. */ private final Specialisation specialisation; /** The weighted samplers. */ private final List> weightedSamplers; /** The factory to create the discrete probability sampler from the weights. */ private DiscreteProbabilitySamplerFactory factory; /** The factory to create the composite sampler. */ private final SamplerFactory compositeFactory; /** * The specialisation of composite sampler to build. * This is used to determine if specialised interfaces from the sampler * type must be supported, e.g. {@link SharedStateSampler}. */ enum Specialisation { /** Instance of {@link SharedStateSampler}. */ SHARED_STATE_SAMPLER, /** No specialisation. */ NONE } /** * A factory for creating composite samplers. * *

This interface is used to build concrete implementations * of different sampler interfaces. * * @param Type of sampler */ interface SamplerFactory { /** * Creates a new composite sampler. * *

If the composite specialisation is a * {@link Specialisation#SHARED_STATE_SAMPLER shared state sampler} * the discrete sampler passed to this method will be an instance of * {@link SharedStateDiscreteSampler}. * * @param discreteSampler Discrete sampler. * @param samplers Samplers. * @return the sampler */ S createSampler(DiscreteSampler discreteSampler, List samplers); } /** * Contains a weighted sampler. * * @param Sampler type */ private static class WeightedSampler { /** The weight. */ private final double weight; /** The sampler. */ private final S sampler; /** * @param weight the weight * @param sampler the sampler * @throws IllegalArgumentException if {@code weight} is negative, infinite or {@code NaN}. * @throws NullPointerException if {@code sampler} is null. */ WeightedSampler(double weight, S sampler) { this.weight = requirePositiveFinite(weight, "weight"); this.sampler = Objects.requireNonNull(sampler, "sampler"); } /** * Gets the weight. * * @return the weight */ double getWeight() { return weight; } /** * Gets the sampler. * * @return the sampler */ S getSampler() { return sampler; } /** * Checks that the specified value is positive finite and throws a customized * {@link IllegalArgumentException} if it is not. * * @param value the value * @param message detail message to be used in the event that a {@code * IllegalArgumentException} is thrown * @return {@code value} if positive finite * @throws IllegalArgumentException if {@code weight} is negative, infinite or {@code NaN}. */ private static double requirePositiveFinite(double value, String message) { // Must be positive finite if (!(value >= 0 && value < Double.POSITIVE_INFINITY)) { throw new IllegalArgumentException(message + " is not positive finite: " + value); } return value; } } /** * @param specialisation Specialisation of the sampler. * @param compositeFactory Factory to create the final composite sampler. */ SamplerBuilder(Specialisation specialisation, SamplerFactory compositeFactory) { this.specialisation = specialisation; this.compositeFactory = compositeFactory; weightedSamplers = new ArrayList<>(); factory = DiscreteProbabilitySampler.GUIDE_TABLE; } @Override public int size() { return weightedSamplers.size(); } @Override public Builder add(S sampler, double weight) { // Ignore zero weights. The sampler and weight are validated by the WeightedSampler. if (weight != 0) { weightedSamplers.add(new WeightedSampler<>(weight, sampler)); } return this; } /** * {@inheritDoc} * *

If the weights are uniform the factory is ignored and composite's discrete sampler * is a {@link DiscreteUniformSampler uniform distribution sampler}. */ @Override public Builder setFactory(DiscreteProbabilitySamplerFactory samplerFactory) { this.factory = Objects.requireNonNull(samplerFactory, "factory"); return this; } /** * {@inheritDoc} * *

If only one sampler has been added to the builder then the sampler is returned * and the builder is reset. * * @throws IllegalStateException if no samplers have been added to create a composite. */ @Override public S build(UniformRandomProvider rng) { final List> list = this.weightedSamplers; final int n = list.size(); if (n == 0) { throw new IllegalStateException("No samplers to build the composite"); } if (n == 1) { // No composite final S sampler = list.get(0).sampler; reset(); return sampler; } // Extract the weights and samplers. final double[] weights = new double[n]; final ArrayList samplers = new ArrayList<>(n); for (int i = 0; i < n; i++) { final WeightedSampler weightedItem = list.get(i); weights[i] = weightedItem.getWeight(); samplers.add(weightedItem.getSampler()); } reset(); final DiscreteSampler discreteSampler = createDiscreteSampler(rng, weights); return compositeFactory.createSampler(discreteSampler, samplers); } /** * Reset the builder. */ private void reset() { weightedSamplers.clear(); } /** * Creates the discrete sampler of the enumerated probability distribution. * *

If the specialisation is a {@link Specialisation#SHARED_STATE_SAMPLER shared state sampler} * the discrete sampler will be an instance of {@link SharedStateDiscreteSampler}. * * @param rng Generator of uniformly distributed random numbers. * @param weights Weight associated to each item. * @return the sampler */ private DiscreteSampler createDiscreteSampler(UniformRandomProvider rng, double[] weights) { // Edge case. Detect uniform weights. final int n = weights.length; if (uniform(weights)) { // Uniformly sample from the size. // Note: Upper bound is inclusive. return DiscreteUniformSampler.of(rng, 0, n - 1); } // If possible normalise with a simple sum. final double sum = sum(weights); if (sum < Double.POSITIVE_INFINITY) { // Do not use f = 1.0 / sum and multiplication by f. // Use of divide handles a sub-normal sum. for (int i = 0; i < n; i++) { weights[i] /= sum; } } else { // The sum is not finite. We know the weights are all positive finite. // Compute the mean without overflow and divide by the mean and number of items. final double mean = mean(weights); for (int i = 0; i < n; i++) { // Two step division avoids using the denominator (mean * n) weights[i] = weights[i] / mean / n; } } // Create the sampler from the factory. // Check if a SharedStateSampler is required. // If a default factory then the result is a SharedStateDiscreteSampler, // otherwise the sampler must be checked. if (specialisation == Specialisation.SHARED_STATE_SAMPLER && !(factory instanceof DiscreteProbabilitySampler)) { // If the factory was user defined then clone the weights as they may be required // to create a SharedStateDiscreteProbabilitySampler. final DiscreteSampler sampler = factory.create(rng, weights.clone()); return sampler instanceof SharedStateDiscreteSampler ? sampler : new SharedStateDiscreteProbabilitySampler(sampler, factory, weights); } return factory.create(rng, weights); } /** * Check if all the values are the same. * *

Warning: This method assumes there are input values. If the length is zero an * {@link ArrayIndexOutOfBoundsException} will be thrown. * * @param values the values * @return true if all values are the same */ private static boolean uniform(double[] values) { final double value = values[0]; for (int i = 1; i < values.length; i++) { if (value != values[i]) { return false; } } return true; } /** * Compute the sum of the values. * * @param values the values * @return the sum */ private static double sum(double[] values) { double sum = 0; for (final double value : values) { sum += value; } return sum; } /** * Compute the mean of the values. Uses a rolling algorithm to avoid overflow of a simple sum. * This method can be used to compute the mean of observed counts for normalisation to a * probability: * *

         * double[] values = ...;
         * int n = values.length;
         * double mean = mean(values);
         * for (int i = 0; i < n; i++) {
         *     // Two step division avoids using the denominator (mean * n)
         *     values[i] = values[i] / mean / n;
         * }
         * 
* *

Warning: This method assumes there are input values. If the length is zero an * {@link ArrayIndexOutOfBoundsException} will be thrown. * * @param values the values * @return the mean */ private static double mean(double[] values) { double mean = values[0]; int i = 1; while (i < values.length) { // Deviation from the mean final double dev = values[i] - mean; i++; mean += dev / i; } return mean; } } /** * A composite sampler. * *

The source sampler for each sampler is chosen based on a user-defined continuous * probability distribution. * * @param Type of sampler */ private static class CompositeSampler { /** Continuous sampler to choose the individual sampler to sample. */ protected final DiscreteSampler discreteSampler; /** Collection of samplers to be sampled from. */ protected final List samplers; /** * @param discreteSampler Continuous sampler to choose the individual sampler to sample. * @param samplers Collection of samplers to be sampled from. */ CompositeSampler(DiscreteSampler discreteSampler, List samplers) { this.discreteSampler = discreteSampler; this.samplers = samplers; } /** * Gets the next sampler to use to create a sample. * * @return the sampler */ S nextSampler() { return samplers.get(discreteSampler.sample()); } } /** * A factory for creating a composite ObjectSampler. * * @param Type of sample */ private static class ObjectSamplerFactory implements SamplerBuilder.SamplerFactory> { /** The instance. */ @SuppressWarnings("rawtypes") private static final ObjectSamplerFactory INSTANCE = new ObjectSamplerFactory(); /** * Get an instance. * * @param Type of sample * @return the factory */ @SuppressWarnings("unchecked") static ObjectSamplerFactory instance() { return (ObjectSamplerFactory) INSTANCE; } @Override public ObjectSampler createSampler(DiscreteSampler discreteSampler, List> samplers) { return new CompositeObjectSampler<>(discreteSampler, samplers); } /** * A composite object sampler. * * @param Type of sample */ private static class CompositeObjectSampler extends CompositeSampler> implements ObjectSampler { /** * @param discreteSampler Discrete sampler to choose the individual sampler to sample. * @param samplers Collection of samplers to be sampled from. */ CompositeObjectSampler(DiscreteSampler discreteSampler, List> samplers) { super(discreteSampler, samplers); } @Override public T sample() { return nextSampler().sample(); } } } /** * A factory for creating a composite SharedStateObjectSampler. * * @param Type of sample */ private static class SharedStateObjectSamplerFactory implements SamplerBuilder.SamplerFactory> { /** The instance. */ @SuppressWarnings("rawtypes") private static final SharedStateObjectSamplerFactory INSTANCE = new SharedStateObjectSamplerFactory(); /** * Get an instance. * * @param Type of sample * @return the factory */ @SuppressWarnings("unchecked") static SharedStateObjectSamplerFactory instance() { return (SharedStateObjectSamplerFactory) INSTANCE; } @Override public SharedStateObjectSampler createSampler(DiscreteSampler discreteSampler, List> samplers) { // The input discrete sampler is assumed to be a SharedStateDiscreteSampler return new CompositeSharedStateObjectSampler<>( (SharedStateDiscreteSampler) discreteSampler, samplers); } /** * A composite object sampler with shared state support. * *

The source sampler for each sampler is chosen based on a user-defined * discrete probability distribution. * * @param Type of sample */ private static class CompositeSharedStateObjectSampler extends CompositeSampler> implements SharedStateObjectSampler { /** * @param discreteSampler Discrete sampler to choose the individual sampler to sample. * @param samplers Collection of samplers to be sampled from. */ CompositeSharedStateObjectSampler(SharedStateDiscreteSampler discreteSampler, List> samplers) { super(discreteSampler, samplers); } @Override public T sample() { return nextSampler().sample(); } @Override public CompositeSharedStateObjectSampler withUniformRandomProvider(UniformRandomProvider rng) { // Duplicate each sampler with the same source of randomness return new CompositeSharedStateObjectSampler<>( ((SharedStateDiscreteSampler) this.discreteSampler).withUniformRandomProvider(rng), copy(samplers, rng)); } } } /** * A factory for creating a composite DiscreteSampler. */ private static class DiscreteSamplerFactory implements SamplerBuilder.SamplerFactory { /** The instance. */ static final DiscreteSamplerFactory INSTANCE = new DiscreteSamplerFactory(); @Override public DiscreteSampler createSampler(DiscreteSampler discreteSampler, List samplers) { return new CompositeDiscreteSampler(discreteSampler, samplers); } /** * A composite discrete sampler. */ private static class CompositeDiscreteSampler extends CompositeSampler implements DiscreteSampler { /** * @param discreteSampler Discrete sampler to choose the individual sampler to sample. * @param samplers Collection of samplers to be sampled from. */ CompositeDiscreteSampler(DiscreteSampler discreteSampler, List samplers) { super(discreteSampler, samplers); } @Override public int sample() { return nextSampler().sample(); } } } /** * A factory for creating a composite SharedStateDiscreteSampler. */ private static class SharedStateDiscreteSamplerFactory implements SamplerBuilder.SamplerFactory { /** The instance. */ static final SharedStateDiscreteSamplerFactory INSTANCE = new SharedStateDiscreteSamplerFactory(); @Override public SharedStateDiscreteSampler createSampler(DiscreteSampler discreteSampler, List samplers) { // The input discrete sampler is assumed to be a SharedStateDiscreteSampler return new CompositeSharedStateDiscreteSampler( (SharedStateDiscreteSampler) discreteSampler, samplers); } /** * A composite discrete sampler with shared state support. */ private static class CompositeSharedStateDiscreteSampler extends CompositeSampler implements SharedStateDiscreteSampler { /** * @param discreteSampler Discrete sampler to choose the individual sampler to sample. * @param samplers Collection of samplers to be sampled from. */ CompositeSharedStateDiscreteSampler(SharedStateDiscreteSampler discreteSampler, List samplers) { super(discreteSampler, samplers); } @Override public int sample() { return nextSampler().sample(); } @Override public CompositeSharedStateDiscreteSampler withUniformRandomProvider(UniformRandomProvider rng) { // Duplicate each sampler with the same source of randomness return new CompositeSharedStateDiscreteSampler( ((SharedStateDiscreteSampler) this.discreteSampler).withUniformRandomProvider(rng), copy(samplers, rng)); } } } /** * A factory for creating a composite ContinuousSampler. */ private static class ContinuousSamplerFactory implements SamplerBuilder.SamplerFactory { /** The instance. */ static final ContinuousSamplerFactory INSTANCE = new ContinuousSamplerFactory(); @Override public ContinuousSampler createSampler(DiscreteSampler discreteSampler, List samplers) { return new CompositeContinuousSampler(discreteSampler, samplers); } /** * A composite continuous sampler. */ private static class CompositeContinuousSampler extends CompositeSampler implements ContinuousSampler { /** * @param discreteSampler Continuous sampler to choose the individual sampler to sample. * @param samplers Collection of samplers to be sampled from. */ CompositeContinuousSampler(DiscreteSampler discreteSampler, List samplers) { super(discreteSampler, samplers); } @Override public double sample() { return nextSampler().sample(); } } } /** * A factory for creating a composite SharedStateContinuousSampler. */ private static class SharedStateContinuousSamplerFactory implements SamplerBuilder.SamplerFactory { /** The instance. */ static final SharedStateContinuousSamplerFactory INSTANCE = new SharedStateContinuousSamplerFactory(); @Override public SharedStateContinuousSampler createSampler(DiscreteSampler discreteSampler, List samplers) { // The sampler is assumed to be a SharedStateContinuousSampler return new CompositeSharedStateContinuousSampler( (SharedStateDiscreteSampler) discreteSampler, samplers); } /** * A composite continuous sampler with shared state support. */ private static class CompositeSharedStateContinuousSampler extends CompositeSampler implements SharedStateContinuousSampler { /** * @param discreteSampler Continuous sampler to choose the individual sampler to sample. * @param samplers Collection of samplers to be sampled from. */ CompositeSharedStateContinuousSampler(SharedStateDiscreteSampler discreteSampler, List samplers) { super(discreteSampler, samplers); } @Override public double sample() { return nextSampler().sample(); } @Override public CompositeSharedStateContinuousSampler withUniformRandomProvider(UniformRandomProvider rng) { // Duplicate each sampler with the same source of randomness return new CompositeSharedStateContinuousSampler( ((SharedStateDiscreteSampler) this.discreteSampler).withUniformRandomProvider(rng), copy(samplers, rng)); } } } /** * A factory for creating a composite LongSampler. */ private static class LongSamplerFactory implements SamplerBuilder.SamplerFactory { /** The instance. */ static final LongSamplerFactory INSTANCE = new LongSamplerFactory(); @Override public LongSampler createSampler(DiscreteSampler discreteSampler, List samplers) { return new CompositeLongSampler(discreteSampler, samplers); } /** * A composite long sampler. */ private static class CompositeLongSampler extends CompositeSampler implements LongSampler { /** * @param discreteSampler Long sampler to choose the individual sampler to sample. * @param samplers Collection of samplers to be sampled from. */ CompositeLongSampler(DiscreteSampler discreteSampler, List samplers) { super(discreteSampler, samplers); } @Override public long sample() { return nextSampler().sample(); } } } /** * A factory for creating a composite SharedStateLongSampler. */ private static class SharedStateLongSamplerFactory implements SamplerBuilder.SamplerFactory { /** The instance. */ static final SharedStateLongSamplerFactory INSTANCE = new SharedStateLongSamplerFactory(); @Override public SharedStateLongSampler createSampler(DiscreteSampler discreteSampler, List samplers) { // The input discrete sampler is assumed to be a SharedStateLongSampler return new CompositeSharedStateLongSampler( (SharedStateDiscreteSampler) discreteSampler, samplers); } /** * A composite long sampler with shared state support. */ private static class CompositeSharedStateLongSampler extends CompositeSampler implements SharedStateLongSampler { /** * @param discreteSampler Long sampler to choose the individual sampler to sample. * @param samplers Collection of samplers to be sampled from. */ CompositeSharedStateLongSampler(SharedStateDiscreteSampler discreteSampler, List samplers) { super(discreteSampler, samplers); } @Override public long sample() { return nextSampler().sample(); } @Override public CompositeSharedStateLongSampler withUniformRandomProvider(UniformRandomProvider rng) { // Duplicate each sampler with the same source of randomness return new CompositeSharedStateLongSampler( ((SharedStateDiscreteSampler) this.discreteSampler).withUniformRandomProvider(rng), copy(samplers, rng)); } } } /** No public instances. */ private CompositeSamplers() {} /** * Create a new builder for a composite {@link ObjectSampler}. * *

Note: If the compiler cannot infer the type parameter of the sampler it can be specified * within the diamond operator {@code } preceding the call to * {@code newObjectSamplerBuilder()}, for example: * *

{@code
     * CompositeSamplers.newObjectSamplerBuilder()
     * }
* * @param Type of the sample. * @return the builder */ public static Builder> newObjectSamplerBuilder() { final SamplerBuilder.SamplerFactory> factory = ObjectSamplerFactory.instance(); return new SamplerBuilder<>( SamplerBuilder.Specialisation.NONE, factory); } /** * Create a new builder for a composite {@link SharedStateObjectSampler}. * *

Note: If the compiler cannot infer the type parameter of the sampler it can be specified * within the diamond operator {@code } preceding the call to * {@code newSharedStateObjectSamplerBuilder()}, for example: * *

{@code
     * CompositeSamplers.newSharedStateObjectSamplerBuilder()
     * }
* * @param Type of the sample. * @return the builder */ public static Builder> newSharedStateObjectSamplerBuilder() { final SamplerBuilder.SamplerFactory> factory = SharedStateObjectSamplerFactory.instance(); return new SamplerBuilder<>( SamplerBuilder.Specialisation.SHARED_STATE_SAMPLER, factory); } /** * Create a new builder for a composite {@link DiscreteSampler}. * * @return the builder */ public static Builder newDiscreteSamplerBuilder() { return new SamplerBuilder<>( SamplerBuilder.Specialisation.NONE, DiscreteSamplerFactory.INSTANCE); } /** * Create a new builder for a composite {@link SharedStateDiscreteSampler}. * * @return the builder */ public static Builder newSharedStateDiscreteSamplerBuilder() { return new SamplerBuilder<>( SamplerBuilder.Specialisation.SHARED_STATE_SAMPLER, SharedStateDiscreteSamplerFactory.INSTANCE); } /** * Create a new builder for a composite {@link ContinuousSampler}. * * @return the builder */ public static Builder newContinuousSamplerBuilder() { return new SamplerBuilder<>( SamplerBuilder.Specialisation.NONE, ContinuousSamplerFactory.INSTANCE); } /** * Create a new builder for a composite {@link SharedStateContinuousSampler}. * * @return the builder */ public static Builder newSharedStateContinuousSamplerBuilder() { return new SamplerBuilder<>( SamplerBuilder.Specialisation.SHARED_STATE_SAMPLER, SharedStateContinuousSamplerFactory.INSTANCE); } /** * Create a new builder for a composite {@link LongSampler}. * * @return the builder */ public static Builder newLongSamplerBuilder() { return new SamplerBuilder<>( SamplerBuilder.Specialisation.NONE, LongSamplerFactory.INSTANCE); } /** * Create a new builder for a composite {@link SharedStateLongSampler}. * * @return the builder */ public static Builder newSharedStateLongSamplerBuilder() { return new SamplerBuilder<>( SamplerBuilder.Specialisation.SHARED_STATE_SAMPLER, SharedStateLongSamplerFactory.INSTANCE); } /** * Create a copy instance of each sampler in the list of samplers using the given * uniform random provider as the source of randomness. * * @param the type of sampler * @param samplers Source to copy. * @param rng Generator of uniformly distributed random numbers. * @return the copy */ private static > List copy(List samplers, UniformRandomProvider rng) { final ArrayList newSamplers = new ArrayList<>(samplers.size()); for (final T s : samplers) { newSamplers.add(s.withUniformRandomProvider(rng)); } return newSamplers; } }