Description
Create a composite sampler that combines 2 or more samplers, each with its own weight. The weights can be used to create a discrete probability distribution.
The composite sampler for example can be used to combine sampling from different shapes to generate a sample from inside a more complex volume, such as combining 6 triangles to create a hexagon.
We have 3 samplers that can sample efficiently from a weighted distribution:
- GuideTableDiscreteSampler
- AliasMethodDiscreteSampler
- MarsagliaTsangWangDiscreteSampler.Enumerated
So a composite sampler must accept a set of weighted samplers (of the same type) and create a discrete sampler to select which one to sample. This is facilitated using a builder API:
S is the type of sampler
public interface Builder<S> { int size(); Builder<S> add(S sampler, double weight); Builder<S> setFactory(DiscreteProbabilitySamplerFactory factory); // Only works if size > 0 S build(UniformRandomProvider rng); }
The factory specifies a mechanism to create the users choice of discrete sampler:
public interface DiscreteProbabilitySamplerFactory { DiscreteSampler create(UniformRandomProvider rng, double[] probabilities); }
It is not required to be set as a default will exist. The choice for the DiscreteProbabilityCollectionSampler was the GuideTableDiscreteSampler due to its low construction overhead (see RNG-109).
A static class provides a mechanism to create composite samplers via builders typed to the final sample type:
public final class CompositeSamplers { public static <T> Builder<ObjectSampler<T>> newObjectSamplerBuilder(); public static <T> Builder<SharedStateObjectSampler<T>> newSharedStateObjectSamplerBuilder(); public static Builder<DiscreteSampler> newDiscreteSamplerBuilder(); public static Builder<SharedStateDiscreteSampler> newSharedStateDiscreteSamplerBuilder(); public static Builder<ContinuousSampler> newContinuousSamplerBuilder(); public static Builder<SharedStateContinuousSampler> newSharedStateContinuousSamplerBuilder(); }
An example of usage would be:
UniformRandomProvider rng = ...; // Diamond vertices double[] a = {0, 0}; double[] b = {1, 1}; double[] c = {2, 0}; double[] d = {1, -1}; // Note: The sample type (double[]) must be specified if the builder is not assigned ObjectSampler<double[]> diamond = CompositeSamplers.<double[]>newObjectSamplerBuilder() .add(TriangleSampler.of(a, b, c, rng), 1) // Upper .add(TriangleSampler.of(a, d, c, rng), 1) // Lower .build(rng); double[] coord = diamond.sample(); // Note: Type is inferred if the builder is assigned and then used: Builder<ObjectSampler<double[]>> builder = CompositeSamplers.newObjectSamplerBuilder(); ObjectSampler<double[]> diamond = builder .add(TriangleSampler.of(a, b, c, rng), 1) // Upper .add(TriangleSampler.of(a, d, c, rng), 1) // Lower .build(rng);
Attachments
Issue Links
- relates to
-
RNG-132 Package rng.sampling.shape for sampling coordinates from shapes
- Closed