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 * @since 1.1
026 */
027public class GaussianSampler implements SharedStateContinuousSampler {
028    /** Mean. */
029    private final double mean;
030    /** standardDeviation. */
031    private final double standardDeviation;
032    /** Normalized Gaussian sampler. */
033    private final NormalizedGaussianSampler normalized;
034
035    /**
036     * @param normalized Generator of N(0,1) Gaussian distributed random numbers.
037     * @param mean Mean of the Gaussian distribution.
038     * @param standardDeviation Standard deviation of the Gaussian distribution.
039     * @throws IllegalArgumentException if {@code standardDeviation <= 0}
040     */
041    public GaussianSampler(NormalizedGaussianSampler normalized,
042                           double mean,
043                           double standardDeviation) {
044        if (standardDeviation <= 0) {
045            throw new IllegalArgumentException(
046                "standard deviation is not strictly positive: " + standardDeviation);
047        }
048        this.normalized = normalized;
049        this.mean = mean;
050        this.standardDeviation = standardDeviation;
051    }
052
053    /**
054     * @param rng Generator of uniformly distributed random numbers.
055     * @param source Source to copy.
056     */
057    private GaussianSampler(UniformRandomProvider rng,
058                            GaussianSampler source) {
059        this.mean = source.mean;
060        this.standardDeviation = source.standardDeviation;
061        this.normalized = InternalUtils.newNormalizedGaussianSampler(source.normalized, rng);
062    }
063
064    /** {@inheritDoc} */
065    @Override
066    public double sample() {
067        return standardDeviation * normalized.sample() + mean;
068    }
069
070    /** {@inheritDoc} */
071    @Override
072    public String toString() {
073        return "Gaussian deviate [" + normalized.toString() + "]";
074    }
075
076    /**
077     * {@inheritDoc}
078     *
079     * <p>Note: This function is available if the underlying {@link NormalizedGaussianSampler}
080     * is a {@link org.apache.commons.rng.sampling.SharedStateSampler SharedStateSampler}.
081     * Otherwise a run-time exception is thrown.</p>
082     *
083     * @throws UnsupportedOperationException if the underlying sampler is not a
084     * {@link org.apache.commons.rng.sampling.SharedStateSampler SharedStateSampler} or
085     * does not return a {@link NormalizedGaussianSampler} when sharing state.
086     *
087     * @since 1.3
088     */
089    @Override
090    public SharedStateContinuousSampler withUniformRandomProvider(UniformRandomProvider rng) {
091        return new GaussianSampler(rng, this);
092    }
093
094    /**
095     * Create a new normalised Gaussian sampler.
096     *
097     * <p>Note: The shared-state functionality is available if the {@link NormalizedGaussianSampler}
098     * is a {@link org.apache.commons.rng.sampling.SharedStateSampler SharedStateSampler}.
099     * Otherwise a run-time exception will be thrown when the sampler is used to share state.</p>
100     *
101     * @param normalized Generator of N(0,1) Gaussian distributed random numbers.
102     * @param mean Mean of the Gaussian distribution.
103     * @param standardDeviation Standard deviation of the Gaussian distribution.
104     * @return the sampler
105     * @throws IllegalArgumentException if {@code standardDeviation <= 0}
106     * @see #withUniformRandomProvider(UniformRandomProvider)
107     * @since 1.3
108     */
109    public static SharedStateContinuousSampler of(NormalizedGaussianSampler normalized,
110                                                  double mean,
111                                                  double standardDeviation) {
112        return new GaussianSampler(normalized, mean, standardDeviation);
113    }
114}