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 */
017package org.apache.commons.rng.sampling.distribution;
018
019import org.apache.commons.rng.UniformRandomProvider;
020
021/**
022 * Sampling from a Gaussian distribution with given mean and
023 * standard deviation.
024 *
025 * <h2>Note</h2>
026 *
027 * <p>The mean and standard deviation are validated to ensure they are finite. This prevents
028 * generation of NaN samples by avoiding invalid arithmetic (inf * 0 or inf - inf).
029 * However use of an extremely large standard deviation and/or mean may result in samples that are
030 * infinite; that is the parameters are not validated to prevent truncation of the output
031 * distribution.
032 *
033 * @since 1.1
034 */
035public class GaussianSampler implements SharedStateContinuousSampler {
036    /** Mean. */
037    private final double mean;
038    /** standardDeviation. */
039    private final double standardDeviation;
040    /** Normalized Gaussian sampler. */
041    private final NormalizedGaussianSampler normalized;
042
043    /**
044     * Create an instance.
045     *
046     * @param normalized Generator of N(0,1) Gaussian distributed random numbers.
047     * @param mean Mean of the Gaussian distribution.
048     * @param standardDeviation Standard deviation of the Gaussian distribution.
049     * @throws IllegalArgumentException if {@code standardDeviation <= 0} or is infinite;
050     * or {@code mean} is infinite
051     */
052    public GaussianSampler(NormalizedGaussianSampler normalized,
053                           double mean,
054                           double standardDeviation) {
055        // Validation before java.lang.Object constructor exits prevents partially initialized object
056        this(InternalUtils.requireFinite(mean, "mean"),
057             InternalUtils.requireStrictlyPositiveFinite(standardDeviation, "standardDeviation"),
058             normalized);
059    }
060
061    /**
062     * @param mean Mean of the Gaussian distribution.
063     * @param standardDeviation Standard deviation of the Gaussian distribution.
064     * @param normalized Generator of N(0,1) Gaussian distributed random numbers.
065     */
066    private GaussianSampler(double mean,
067                            double standardDeviation,
068                            NormalizedGaussianSampler normalized) {
069        this.normalized = normalized;
070        this.mean = mean;
071        this.standardDeviation = standardDeviation;
072    }
073
074    /** {@inheritDoc} */
075    @Override
076    public double sample() {
077        return standardDeviation * normalized.sample() + mean;
078    }
079
080    /** {@inheritDoc} */
081    @Override
082    public String toString() {
083        return "Gaussian deviate [" + normalized.toString() + "]";
084    }
085
086    /**
087     * {@inheritDoc}
088     *
089     * <p>Note: This function is available if the underlying {@link NormalizedGaussianSampler}
090     * is a {@link org.apache.commons.rng.sampling.SharedStateSampler SharedStateSampler}.
091     * Otherwise a run-time exception is thrown.</p>
092     *
093     * @throws UnsupportedOperationException if the underlying sampler is not a
094     * {@link org.apache.commons.rng.sampling.SharedStateSampler SharedStateSampler} or
095     * does not return a {@link NormalizedGaussianSampler} when sharing state.
096     *
097     * @since 1.3
098     */
099    @Override
100    public SharedStateContinuousSampler withUniformRandomProvider(UniformRandomProvider rng) {
101        return new GaussianSampler(mean, standardDeviation,
102            InternalUtils.newNormalizedGaussianSampler(normalized, rng));
103    }
104
105    /**
106     * Create a new normalised Gaussian sampler.
107     *
108     * <p>Note: The shared-state functionality is available if the {@link NormalizedGaussianSampler}
109     * is a {@link org.apache.commons.rng.sampling.SharedStateSampler SharedStateSampler}.
110     * Otherwise a run-time exception will be thrown when the sampler is used to share state.</p>
111     *
112     * @param normalized Generator of N(0,1) Gaussian distributed random numbers.
113     * @param mean Mean of the Gaussian distribution.
114     * @param standardDeviation Standard deviation of the Gaussian distribution.
115     * @return the sampler
116     * @throws IllegalArgumentException if {@code standardDeviation <= 0} or is infinite;
117     * or {@code mean} is infinite
118     * @see #withUniformRandomProvider(UniformRandomProvider)
119     * @since 1.3
120     */
121    public static SharedStateContinuousSampler of(NormalizedGaussianSampler normalized,
122                                                  double mean,
123                                                  double standardDeviation) {
124        return new GaussianSampler(normalized, mean, standardDeviation);
125    }
126}