diff --git a/src/FSharp/Distributions.fs b/src/FSharp/Distributions.fs
index ac079b1f..266c7839 100644
--- a/src/FSharp/Distributions.fs
+++ b/src/FSharp/Distributions.fs
@@ -44,117 +44,117 @@ module Sample =
let mapSeq3 f dist1 dist2 dist3 : System.Random -> 'T seq = fun rng -> Seq.zip3 (dist1 rng) (dist2 rng) (dist3 rng) |> Seq.map (fun (d1, d2, d3) -> f d1 d2 d3)
/// Bernoulli with probability (p).
- let bernoulli p rng = Bernoulli.Sample(rng, p)
- let bernoulliSeq p rng = Bernoulli.Samples(rng, p)
+ let bernoulli p (rng:System.Random) = Bernoulli.Sample(rng, p)
+ let bernoulliSeq p (rng:System.Random) = Bernoulli.Samples(rng, p)
/// Beta with α and β shape parameters.
- let beta a b rng = Beta.Sample(rng, a, b)
- let betaSeq a b rng = Beta.Samples(rng, a, b)
+ let beta a b (rng:System.Random) = Beta.Sample(rng, a, b)
+ let betaSeq a b (rng:System.Random) = Beta.Samples(rng, a, b)
/// Binomial with success probability (p) in each trial and number of trials (n).
- let binomial p n rng = Binomial.Sample(rng, p, n)
- let binomialSeq p n rng = Binomial.Samples(rng, p, n)
+ let binomial p n (rng:System.Random) = Binomial.Sample(rng, p, n)
+ let binomialSeq p n (rng:System.Random) = Binomial.Samples(rng, p, n)
/// Categorical with an array of nonnegative ratios defining the relative probability mass (unnormalized).
- let categorical probabilityMass rng = Categorical.Sample(rng, probabilityMass)
- let categoricalSeq probabilityMass rng = Categorical.Samples(rng, probabilityMass)
+ let categorical probabilityMass (rng:System.Random) = Categorical.Sample(rng, probabilityMass)
+ let categoricalSeq probabilityMass (rng:System.Random) = Categorical.Samples(rng, probabilityMass)
/// Cauchy with location (x0) and scale (γ).
- let cauchy location scale rng = Cauchy.Sample(rng, location, scale)
- let cauchySeq location scale rng = Cauchy.Samples(rng, location, scale)
+ let cauchy location scale (rng:System.Random) = Cauchy.Sample(rng, location, scale)
+ let cauchySeq location scale (rng:System.Random) = Cauchy.Samples(rng, location, scale)
/// Chi with degrees of freedom (k).
- let chi freedom rng = Chi.Sample(rng, freedom)
- let chiSeq freedom rng = Chi.Samples(rng, freedom)
+ let chi freedom (rng:System.Random) = Chi.Sample(rng, freedom)
+ let chiSeq freedom (rng:System.Random) = Chi.Samples(rng, freedom)
/// Chi-Squared with degrees of freedom (k).
- let chiSquared freedom rng = ChiSquared.Sample(rng, freedom)
- let chiSquaredSeq freedom rng = ChiSquared.Samples(rng, freedom)
+ let chiSquared freedom (rng:System.Random) = ChiSquared.Sample(rng, freedom)
+ let chiSquaredSeq freedom (rng:System.Random) = ChiSquared.Samples(rng, freedom)
/// Continuous-Uniform with lower and upper bounds.
- let continuousUniform lower upper rng = ContinuousUniform.Sample(rng, lower, upper)
- let continuousUniformSeq lower upper rng = ContinuousUniform.Samples(rng, lower, upper)
+ let continuousUniform lower upper (rng:System.Random) = ContinuousUniform.Sample(rng, lower, upper)
+ let continuousUniformSeq lower upper (rng:System.Random) = ContinuousUniform.Samples(rng, lower, upper)
/// Conway-Maxwell-Poisson with lambda (λ) and rate of decay (ν).
- let conwayMaxwellPoisson lambda nu rng = ConwayMaxwellPoisson.Sample(rng, lambda, nu)
- let conwayMaxwellPoissonSeq lambda nu rng = ConwayMaxwellPoisson.Samples(rng, lambda, nu)
+ let conwayMaxwellPoisson lambda nu (rng:System.Random) = ConwayMaxwellPoisson.Sample(rng, lambda, nu)
+ let conwayMaxwellPoissonSeq lambda nu (rng:System.Random) = ConwayMaxwellPoisson.Samples(rng, lambda, nu)
/// Discrete-Uniform with lower and upper bounds (both inclusive).
- let discreteUniform lower upper rng = DiscreteUniform.Sample(rng, lower, upper)
- let discreteUniformSeq lower upper rng = DiscreteUniform.Samples(rng, lower, upper)
+ let discreteUniform lower upper (rng:System.Random) = DiscreteUniform.Sample(rng, lower, upper)
+ let discreteUniformSeq lower upper (rng:System.Random) = DiscreteUniform.Samples(rng, lower, upper)
/// Erlang with shape (k) and rate or inverse scale (λ).
- let erlang shape rate rng = Erlang.Sample(rng, shape, rate)
- let erlangSeq shape rate rng = Erlang.Samples(rng, shape, rate)
+ let erlang shape rate (rng:System.Random) = Erlang.Sample(rng, shape, rate)
+ let erlangSeq shape rate (rng:System.Random) = Erlang.Samples(rng, shape, rate)
/// Exponential with rate (λ).
- let exponential rate rng = Exponential.Sample(rng, rate)
- let exponentialSeq rate rng = Exponential.Samples(rng, rate)
+ let exponential rate (rng:System.Random) = Exponential.Sample(rng, rate)
+ let exponentialSeq rate (rng:System.Random) = Exponential.Samples(rng, rate)
/// Fisher-Snedecor (F-Distribution) with first (d1) and second (d2) degree of freedom.
- let fisherSnedecor d1 d2 rng = FisherSnedecor.Sample(rng, d1, d2)
- let fisherSnedecorSeq d1 d2 rng = FisherSnedecor.Samples(rng, d1, d2)
+ let fisherSnedecor d1 d2 (rng:System.Random) = FisherSnedecor.Sample(rng, d1, d2)
+ let fisherSnedecorSeq d1 d2 (rng:System.Random) = FisherSnedecor.Samples(rng, d1, d2)
/// Gamma with shape (k, α) and rate or inverse scale (β).
- let gamma shape rate rng = Gamma.Sample(rng, shape, rate)
- let gammaSeq shape rate rng = Gamma.Sample(rng, shape, rate)
+ let gamma shape rate (rng:System.Random) = Gamma.Sample(rng, shape, rate)
+ let gammaSeq shape rate (rng:System.Random) = Gamma.Sample(rng, shape, rate)
/// Geometric with probability (p) of generating one.
- let geometric p rng = Geometric.Sample(rng, p)
- let geometricSeq p rng = Geometric.Samples(rng, p)
+ let geometric p (rng:System.Random) = Geometric.Sample(rng, p)
+ let geometricSeq p (rng:System.Random) = Geometric.Samples(rng, p)
/// Hypergeometric with size of the population (N), number successes within the population (K, M) and number of draws without replacement (n).
- let hypergeometric population success draws rng = Hypergeometric.Sample(rng, population, success, draws)
- let hypergeometricSeq population success draws rng = Hypergeometric.Samples(rng, population, success, draws)
+ let hypergeometric population success draws (rng:System.Random) = Hypergeometric.Sample(rng, population, success, draws)
+ let hypergeometricSeq population success draws (rng:System.Random) = Hypergeometric.Samples(rng, population, success, draws)
/// Inverse-Gamma with shape (α) and scale (β)
- let inverseGamma shape scale rng = InverseGamma.Sample(rng, shape, scale)
- let inverseGammaSeq shape scale rng = InverseGamma.Samples(rng, shape, scale)
+ let inverseGamma shape scale (rng:System.Random) = InverseGamma.Sample(rng, shape, scale)
+ let inverseGammaSeq shape scale (rng:System.Random) = InverseGamma.Samples(rng, shape, scale)
/// Laplace with location (μ) and scale (b).
- let laplace location scale rng = Laplace.Sample(rng, location, scale)
- let laplaceSeq location scale rng = Laplace.Samples(rng, location, scale)
+ let laplace location scale (rng:System.Random) = Laplace.Sample(rng, location, scale)
+ let laplaceSeq location scale (rng:System.Random) = Laplace.Samples(rng, location, scale)
/// Log-Normal with log-scale (μ) and shape (σ).
- let logNormal mu sigma rng = LogNormal.Sample(rng, mu, sigma)
- let logNormalSeq mu sigma rng = LogNormal.Samples(rng, mu, sigma)
+ let logNormal mu sigma (rng:System.Random) = LogNormal.Sample(rng, mu, sigma)
+ let logNormalSeq mu sigma (rng:System.Random) = LogNormal.Samples(rng, mu, sigma)
/// Negative-Binomial with number of failures (r) until the experiment stopped and probability (p) of a trial resulting in success.
- let negativeBinomial r p rng = NegativeBinomial.Sample(rng, r, p)
- let negativeBinomialSeq r p rng = NegativeBinomial.Samples(rng, r, p)
+ let negativeBinomial r p (rng:System.Random) = NegativeBinomial.Sample(rng, r, p)
+ let negativeBinomialSeq r p (rng:System.Random) = NegativeBinomial.Samples(rng, r, p)
/// Normal with mean (μ) and standard deviation (σ).
- let normal mean stddev rng = Normal.Sample(rng, mean, stddev)
- let normalSeq mean stddev rng = Normal.Samples(rng, mean, stddev)
+ let normal mean stddev (rng:System.Random) = Normal.Sample(rng, mean, stddev)
+ let normalSeq mean stddev (rng:System.Random) = Normal.Samples(rng, mean, stddev)
/// Standard Gaussian.
- let standard rng = Normal.Sample(rng, 0.0, 1.0)
- let standardSeq rng = Normal.Samples(rng, 0.0, 1.0)
+ let standard (rng:System.Random) = Normal.Sample(rng, 0.0, 1.0)
+ let standardSeq (rng:System.Random) = Normal.Samples(rng, 0.0, 1.0)
/// Pareto with scale (xm) and shape (α).
- let pareto scale shape rng = Pareto.Sample(rng, scale, shape)
- let paretoSeq scale shape rng = Pareto.Samples(rng, scale, shape)
+ let pareto scale shape (rng:System.Random) = Pareto.Sample(rng, scale, shape)
+ let paretoSeq scale shape (rng:System.Random) = Pareto.Samples(rng, scale, shape)
/// Poisson with lambda (λ).
- let poisson lambda rng = Poisson.Sample(rng, lambda)
- let poissonSeq lambda rng = Poisson.Samples(rng, lambda)
+ let poisson lambda (rng:System.Random) = Poisson.Sample(rng, lambda)
+ let poissonSeq lambda (rng:System.Random) = Poisson.Samples(rng, lambda)
/// Rayleigh with scale (σ).
- let rayleigh scale rng = Rayleigh.Sample(rng, scale)
- let rayleighSeq scale rng = Rayleigh.Sample(rng, scale)
+ let rayleigh scale (rng:System.Random) = Rayleigh.Sample(rng, scale)
+ let rayleighSeq scale (rng:System.Random) = Rayleigh.Sample(rng, scale)
/// Stable with stability (α), skewness (β), scale (c) and location (μ).
- let stable alpha beta scale location rng = Stable.Sample(rng, alpha, beta, scale, location)
- let stableSeq alpha beta scale location rng = Stable.Samples(rng, alpha, beta, scale, location)
+ let stable alpha beta scale location (rng:System.Random) = Stable.Sample(rng, alpha, beta, scale, location)
+ let stableSeq alpha beta scale location (rng:System.Random) = Stable.Samples(rng, alpha, beta, scale, location)
/// Student-T with location (μ), scale (σ) and degrees of freedom (ν).
- let studentT location scale freedom rng = StudentT.Sample(rng, location, scale, freedom)
- let studentTSeq location scale freedom rng = StudentT.Samples(rng, location, scale, freedom)
+ let studentT location scale freedom (rng:System.Random) = StudentT.Sample(rng, location, scale, freedom)
+ let studentTSeq location scale freedom (rng:System.Random) = StudentT.Samples(rng, location, scale, freedom)
/// Weibull with shape (k) and scale (λ).
- let weibull shape scale rng = Weibull.Sample(rng, shape, scale)
- let weibullSeq shape scale rng = Weibull.Samples(rng, shape, scale)
+ let weibull shape scale (rng:System.Random) = Weibull.Sample(rng, shape, scale)
+ let weibullSeq shape scale (rng:System.Random) = Weibull.Samples(rng, shape, scale)
/// Zipf with s and n parameters.
- let zipf s n rng = Zipf.Sample(rng, s, n)
- let zipfSeq s n rng = Zipf.Samples(rng, s, n)
+ let zipf s n (rng:System.Random) = Zipf.Sample(rng, s, n)
+ let zipfSeq s n (rng:System.Random) = Zipf.Samples(rng, s, n)
diff --git a/src/Numerics/Distributions/Cauchy.cs b/src/Numerics/Distributions/Cauchy.cs
index 84060c9d..ed1acaec 100644
--- a/src/Numerics/Distributions/Cauchy.cs
+++ b/src/Numerics/Distributions/Cauchy.cs
@@ -32,6 +32,7 @@ using System;
using System.Collections.Generic;
using MathNet.Numerics.Properties;
using MathNet.Numerics.Random;
+using MathNet.Numerics.Threading;
namespace MathNet.Numerics.Distributions
{
@@ -254,7 +255,7 @@ namespace MathNet.Numerics.Distributions
/// A random number from this distribution.
public double Sample()
{
- return _location + _scale*Math.Tan(Constants.Pi*(_random.NextDouble() - 0.5));
+ return SampleUnchecked(_random, _location, _scale);
}
///
@@ -262,13 +263,35 @@ namespace MathNet.Numerics.Distributions
///
/// a sequence of samples from the distribution.
public IEnumerable Samples()
+ {
+ return SamplesUnchecked(_random, _location, _scale);
+ }
+
+ static double SampleUnchecked(System.Random rnd, double location, double scale)
+ {
+ return location + scale*Math.Tan(Constants.Pi*(rnd.NextDouble() - 0.5));
+ }
+
+ static IEnumerable SamplesUnchecked(System.Random rnd, double location, double scale)
{
while (true)
{
- yield return _location + _scale*Math.Tan(Constants.Pi*(_random.NextDouble() - 0.5));
+ yield return location + scale*Math.Tan(Constants.Pi*(rnd.NextDouble() - 0.5));
}
}
+ static void SamplesUnchecked(System.Random rnd, double[] values, double location, double scale)
+ {
+ rnd.NextDoubles(values);
+ CommonParallel.For(0, values.Length, 4096, (a, b) =>
+ {
+ for (int i = a; i < b; i++)
+ {
+ values[i] = location + scale*Math.Tan(Constants.Pi*(values[i] - 0.5));
+ }
+ });
+ }
+
///
/// Computes the probability density of the distribution (PDF) at x, i.e. ∂P(X ≤ x)/∂x.
///
@@ -342,7 +365,7 @@ namespace MathNet.Numerics.Distributions
{
if (scale <= 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
- return location + scale*Math.Tan(Constants.Pi*(rnd.NextDouble() - 0.5));
+ return SampleUnchecked(SystemRandomSource.Default, location, scale);
}
///
@@ -356,10 +379,21 @@ namespace MathNet.Numerics.Distributions
{
if (scale <= 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
- while (true)
- {
- yield return location + scale*Math.Tan(Constants.Pi*(rnd.NextDouble() - 0.5));
- }
+ return SamplesUnchecked(rnd, location, scale);
+ }
+
+ ///
+ /// Fills an array with samples generated from the distribution.
+ ///
+ /// The random number generator to use.
+ /// The location (x0) of the distribution.
+ /// The scale (γ) of the distribution. Range: γ > 0.
+ /// a sequence of samples from the distribution.
+ public static void Samples(System.Random rnd, double[] values, double location, double scale)
+ {
+ if (scale <= 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ SamplesUnchecked(rnd, values, location, scale);
}
///
@@ -370,7 +404,9 @@ namespace MathNet.Numerics.Distributions
/// a sample from the distribution.
public static double Sample(double location, double scale)
{
- return Sample(SystemRandomSource.Default, location, scale);
+ if (scale <= 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ return SampleUnchecked(SystemRandomSource.Default, location, scale);
}
///
@@ -381,7 +417,23 @@ namespace MathNet.Numerics.Distributions
/// a sequence of samples from the distribution.
public static IEnumerable Samples(double location, double scale)
{
- return Samples(SystemRandomSource.Default, location, scale);
+ if (scale <= 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ return SamplesUnchecked(SystemRandomSource.Default, location, scale);
+ }
+
+ ///
+ /// Fills an array with samples generated from the distribution.
+ ///
+ /// The random number generator to use.
+ /// The location (x0) of the distribution.
+ /// The scale (γ) of the distribution. Range: γ > 0.
+ /// a sequence of samples from the distribution.
+ public static void Samples(double[] values, double location, double scale)
+ {
+ if (scale <= 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ SamplesUnchecked(SystemRandomSource.Default, values, location, scale);
}
}
}
diff --git a/src/Numerics/Distributions/ContinuousUniform.cs b/src/Numerics/Distributions/ContinuousUniform.cs
index f333d242..c8238022 100644
--- a/src/Numerics/Distributions/ContinuousUniform.cs
+++ b/src/Numerics/Distributions/ContinuousUniform.cs
@@ -32,6 +32,7 @@ using System;
using System.Collections.Generic;
using MathNet.Numerics.Properties;
using MathNet.Numerics.Random;
+using MathNet.Numerics.Threading;
namespace MathNet.Numerics.Distributions
{
@@ -258,7 +259,7 @@ namespace MathNet.Numerics.Distributions
/// a sample from the distribution.
public double Sample()
{
- return _lower + _random.NextDouble()*(_upper - _lower);
+ return SampleUnchecked(_random, _lower, _upper);
}
///
@@ -267,12 +268,36 @@ namespace MathNet.Numerics.Distributions
/// a sequence of samples from the distribution.
public IEnumerable Samples()
{
+ return SamplesUnchecked(_random, _lower, _upper);
+ }
+
+ static double SampleUnchecked(System.Random rnd, double lower, double upper)
+ {
+ return lower + rnd.NextDouble()*(upper - lower);
+ }
+
+ static IEnumerable SamplesUnchecked(System.Random rnd, double lower, double upper)
+ {
+ double difference = upper - lower;
while (true)
{
- yield return _lower + _random.NextDouble()*(_upper - _lower);
+ yield return lower + rnd.NextDouble()*difference;
}
}
+ static void SamplesUnchecked(System.Random rnd, double[] values, double lower, double upper)
+ {
+ rnd.NextDoubles(values);
+ var difference = upper - lower;
+ CommonParallel.For(0, values.Length, 4096, (a, b) =>
+ {
+ for (int i = a; i < b; i++)
+ {
+ values[i] = lower + values[i]*difference;
+ }
+ });
+ }
+
///
/// Computes the probability density of the distribution (PDF) at x, i.e. ∂P(X ≤ x)/∂x.
///
@@ -345,7 +370,7 @@ namespace MathNet.Numerics.Distributions
{
if (upper < lower) throw new ArgumentException(Resources.InvalidDistributionParameters);
- return lower + rnd.NextDouble()*(upper - lower);
+ return SampleUnchecked(rnd, lower, upper);
}
///
@@ -359,10 +384,22 @@ namespace MathNet.Numerics.Distributions
{
if (upper < lower) throw new ArgumentException(Resources.InvalidDistributionParameters);
- while (true)
- {
- yield return lower + rnd.NextDouble()*(upper - lower);
- }
+ return SamplesUnchecked(rnd, lower, upper);
+ }
+
+ ///
+ /// Fills an array with samples generated from the distribution.
+ ///
+ /// The random number generator to use.
+ /// The array to fill with the samples.
+ /// Lower bound. Range: lower ≤ upper.
+ /// Upper bound. Range: lower ≤ upper.
+ /// a sequence of samples from the distribution.
+ public static void Samples(System.Random rnd, double[] values, double lower, double upper)
+ {
+ if (upper < lower) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ SamplesUnchecked(rnd, values, lower, upper);
}
///
@@ -373,7 +410,9 @@ namespace MathNet.Numerics.Distributions
/// a uniformly distributed sample.
public static double Sample(double lower, double upper)
{
- return Sample(SystemRandomSource.Default, lower, upper);
+ if (upper < lower) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ return SampleUnchecked(SystemRandomSource.Default, lower, upper);
}
///
@@ -384,7 +423,23 @@ namespace MathNet.Numerics.Distributions
/// a sequence of uniformly distributed samples.
public static IEnumerable Samples(double lower, double upper)
{
- return Samples(SystemRandomSource.Default, lower, upper);
+ if (upper < lower) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ return SamplesUnchecked(SystemRandomSource.Default, lower, upper);
+ }
+
+ ///
+ /// Fills an array with samples generated from the distribution.
+ ///
+ /// The array to fill with the samples.
+ /// Lower bound. Range: lower ≤ upper.
+ /// Upper bound. Range: lower ≤ upper.
+ /// a sequence of samples from the distribution.
+ public static void Samples(double[] values, double lower, double upper)
+ {
+ if (upper < lower) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ SamplesUnchecked(SystemRandomSource.Default, values, lower, upper);
}
}
}
diff --git a/src/Numerics/Distributions/Laplace.cs b/src/Numerics/Distributions/Laplace.cs
index fd8c6327..eafe9c7e 100644
--- a/src/Numerics/Distributions/Laplace.cs
+++ b/src/Numerics/Distributions/Laplace.cs
@@ -255,10 +255,7 @@ namespace MathNet.Numerics.Distributions
/// a sample from the distribution.
public IEnumerable Samples()
{
- while (true)
- {
- yield return SampleUnchecked(_random, _location, _scale);
- }
+ return SamplesUnchecked(_random, _location, _scale);
}
///
@@ -271,7 +268,26 @@ namespace MathNet.Numerics.Distributions
static double SampleUnchecked(System.Random rnd, double location, double scale)
{
var u = rnd.NextDouble() - 0.5;
- return location - (scale * Math.Sign(u) * Math.Log(1.0 - (2.0 * Math.Abs(u))));
+ return location - (scale*Math.Sign(u)*Math.Log(1.0 - (2.0*Math.Abs(u))));
+ }
+
+ static IEnumerable SamplesUnchecked(System.Random rnd, double location, double scale)
+ {
+ while (true)
+ {
+ var u = rnd.NextDouble() - 0.5;
+ yield return location - (scale*Math.Sign(u)*Math.Log(1.0 - (2.0*Math.Abs(u))));
+ }
+ }
+
+ static void SamplesUnchecked(System.Random rnd, double[] values, double location, double scale)
+ {
+ rnd.NextDoubles(values);
+ for (int i = 0; i < values.Length; i++)
+ {
+ var u = values[i] - 0.5;
+ values[i] = location - (scale*Math.Sign(u)*Math.Log(1.0 - (2.0*Math.Abs(u))));
+ }
}
///
@@ -344,10 +360,22 @@ namespace MathNet.Numerics.Distributions
{
if (scale <= 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
- while (true)
- {
- yield return SampleUnchecked(rnd, location, scale);
- }
+ return SamplesUnchecked(rnd, location, scale);
+ }
+
+ ///
+ /// Fills an array with samples generated from the distribution.
+ ///
+ /// The random number generator to use.
+ /// The array to fill with the samples.
+ /// The location (μ) of the distribution.
+ /// The scale (b) of the distribution. Range: b > 0.
+ /// a sequence of samples from the distribution.
+ public static void Samples(System.Random rnd, double[] values, double location, double scale)
+ {
+ if (scale <= 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ SamplesUnchecked(rnd, values, location, scale);
}
///
@@ -358,7 +386,9 @@ namespace MathNet.Numerics.Distributions
/// a sample from the distribution.
public static double Sample(double location, double scale)
{
- return Sample(SystemRandomSource.Default, location, scale);
+ if (scale <= 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ return SampleUnchecked(SystemRandomSource.Default, location, scale);
}
///
@@ -369,7 +399,24 @@ namespace MathNet.Numerics.Distributions
/// a sequence of samples from the distribution.
public static IEnumerable Samples(double location, double scale)
{
- return Samples(SystemRandomSource.Default, location, scale);
+ if (scale <= 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ return SamplesUnchecked(SystemRandomSource.Default, location, scale);
+ }
+
+ ///
+ /// Fills an array with samples generated from the distribution.
+ ///
+ /// The random number generator to use.
+ /// The array to fill with the samples.
+ /// The location (μ) of the distribution.
+ /// The scale (b) of the distribution. Range: b > 0.
+ /// a sequence of samples from the distribution.
+ public static void Samples(double[] values, double location, double scale)
+ {
+ if (scale <= 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ SamplesUnchecked(SystemRandomSource.Default, values, location, scale);
}
}
}
diff --git a/src/Numerics/Distributions/LogNormal.cs b/src/Numerics/Distributions/LogNormal.cs
index 3e9af3a0..73b71cd7 100644
--- a/src/Numerics/Distributions/LogNormal.cs
+++ b/src/Numerics/Distributions/LogNormal.cs
@@ -31,9 +31,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Reflection.Emit;
using MathNet.Numerics.Properties;
using MathNet.Numerics.Random;
using MathNet.Numerics.Statistics;
+using MathNet.Numerics.Threading;
namespace MathNet.Numerics.Distributions
{
@@ -98,7 +100,7 @@ namespace MathNet.Numerics.Distributions
public static LogNormal WithMeanVariance(double mean, double var, System.Random randomSource = null)
{
var sigma2 = Math.Log(var/(mean*mean) + 1.0);
- return new LogNormal(Math.Log(mean) - sigma2 / 2.0, Math.Sqrt(sigma2), randomSource);
+ return new LogNormal(Math.Log(mean) - sigma2/2.0, Math.Sqrt(sigma2), randomSource);
}
///
@@ -264,7 +266,7 @@ namespace MathNet.Numerics.Distributions
return 0.0;
}
- var a = (Math.Log(x) - _mu) / _sigma;
+ var a = (Math.Log(x) - _mu)/_sigma;
return Math.Exp(-0.5*a*a)/(x*_sigma*Constants.Sqrt2Pi);
}
@@ -281,7 +283,7 @@ namespace MathNet.Numerics.Distributions
return Double.NegativeInfinity;
}
- var a = (Math.Log(x) - _mu) / _sigma;
+ var a = (Math.Log(x) - _mu)/_sigma;
return (-0.5*a*a) - Math.Log(x*_sigma) - Constants.LogSqrt2Pi;
}
@@ -316,7 +318,7 @@ namespace MathNet.Numerics.Distributions
/// a sample from the distribution.
public double Sample()
{
- return Math.Exp(Normal.Sample(_random, _mu, _sigma));
+ return SampleUnchecked(_random, _mu, _sigma);
}
///
@@ -325,7 +327,29 @@ namespace MathNet.Numerics.Distributions
/// a sequence of samples from the distribution.
public IEnumerable Samples()
{
- return Normal.Samples(_random, _mu, _sigma).Select(Math.Exp);
+ return SamplesUnchecked(_random, _mu, _sigma);
+ }
+
+ static double SampleUnchecked(System.Random rnd, double mu, double sigma)
+ {
+ return Math.Exp(Normal.SampleUnchecked(rnd, mu, sigma));
+ }
+
+ static IEnumerable SamplesUnchecked(System.Random rnd, double mu, double sigma)
+ {
+ return Normal.SamplesUnchecked(rnd, mu, sigma).Select(Math.Exp);
+ }
+
+ static void SamplesUnchecked(System.Random rnd, double[] values, double mu, double sigma)
+ {
+ Normal.SamplesUnchecked(rnd, values, mu, sigma);
+ CommonParallel.For(0, values.Length, 4096, (a, b) =>
+ {
+ for (int i = a; i < b; i++)
+ {
+ values[i] = Math.Exp(values[i]);
+ }
+ });
}
///
@@ -346,7 +370,7 @@ namespace MathNet.Numerics.Distributions
return 0.0;
}
- var a = (Math.Log(x) - mu) / sigma;
+ var a = (Math.Log(x) - mu)/sigma;
return Math.Exp(-0.5*a*a)/(x*sigma*Constants.Sqrt2Pi);
}
@@ -367,7 +391,7 @@ namespace MathNet.Numerics.Distributions
return Double.NegativeInfinity;
}
- var a = (Math.Log(x) - mu) / sigma;
+ var a = (Math.Log(x) - mu)/sigma;
return (-0.5*a*a) - Math.Log(x*sigma) - Constants.LogSqrt2Pi;
}
@@ -415,7 +439,9 @@ namespace MathNet.Numerics.Distributions
/// a sample from the distribution.
public static double Sample(System.Random rnd, double mu, double sigma)
{
- return Math.Exp(Normal.Sample(rnd, mu, sigma));
+ if (sigma < 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ return SampleUnchecked(rnd, mu, sigma);
}
///
@@ -427,7 +453,24 @@ namespace MathNet.Numerics.Distributions
/// a sequence of samples from the distribution.
public static IEnumerable Samples(System.Random rnd, double mu, double sigma)
{
- return Normal.Samples(rnd, mu, sigma).Select(Math.Exp);
+ if (sigma < 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ return SamplesUnchecked(rnd, mu, sigma);
+ }
+
+ ///
+ /// Fills an array with samples generated from the distribution.
+ ///
+ /// The random number generator to use.
+ /// The array to fill with the samples.
+ /// The log-scale (μ) of the distribution.
+ /// The shape (σ) of the distribution. Range: σ ≥ 0.
+ /// a sequence of samples from the distribution.
+ public static void Samples(System.Random rnd, double[] values, double mu, double sigma)
+ {
+ if (sigma < 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ SamplesUnchecked(rnd, values, mu, sigma);
}
///
@@ -438,7 +481,9 @@ namespace MathNet.Numerics.Distributions
/// a sample from the distribution.
public static double Sample(double mu, double sigma)
{
- return Sample(SystemRandomSource.Default, mu, sigma);
+ if (sigma < 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ return SampleUnchecked(SystemRandomSource.Default, mu, sigma);
}
///
@@ -449,7 +494,23 @@ namespace MathNet.Numerics.Distributions
/// a sequence of samples from the distribution.
public static IEnumerable Samples(double mu, double sigma)
{
- return Samples(SystemRandomSource.Default, mu, sigma);
+ if (sigma < 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ return SamplesUnchecked(SystemRandomSource.Default, mu, sigma);
+ }
+
+ ///
+ /// Fills an array with samples generated from the distribution.
+ ///
+ /// The array to fill with the samples.
+ /// The log-scale (μ) of the distribution.
+ /// The shape (σ) of the distribution. Range: σ ≥ 0.
+ /// a sequence of samples from the distribution.
+ public static void Samples(double[] values, double mu, double sigma)
+ {
+ if (sigma < 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ SamplesUnchecked(SystemRandomSource.Default, values, mu, sigma);
}
}
}
diff --git a/src/Numerics/Distributions/Normal.cs b/src/Numerics/Distributions/Normal.cs
index e7097a9a..a2f436c8 100644
--- a/src/Numerics/Distributions/Normal.cs
+++ b/src/Numerics/Distributions/Normal.cs
@@ -324,7 +324,7 @@ namespace MathNet.Numerics.Distributions
/// a sample from the distribution.
public double Sample()
{
- return _mean + (_stdDev*SampleStandardBoxMuller(_random).Item1);
+ return SampleUnchecked(_random, _mean, _stdDev);
}
///
@@ -333,33 +333,93 @@ namespace MathNet.Numerics.Distributions
/// a sequence of samples from the distribution.
public IEnumerable Samples()
{
+ return SamplesUnchecked(_random, _mean, _stdDev);
+ }
+
+ internal static double SampleUnchecked(System.Random rnd, double mean, double stddev)
+ {
+ double x, y;
+ while (!PolarTransform(rnd.NextDouble(), rnd.NextDouble(), out x, out y))
+ {
+ }
+ return mean + (stddev*x);
+ }
+
+ internal static IEnumerable SamplesUnchecked(System.Random rnd, double mean, double stddev)
+ {
+ double x, y;
while (true)
{
- var sample = SampleStandardBoxMuller(_random);
- yield return _mean + (_stdDev*sample.Item1);
- yield return _mean + (_stdDev*sample.Item2);
+ if (!PolarTransform(rnd.NextDouble(), rnd.NextDouble(), out x, out y))
+ {
+ continue;
+ }
+ yield return mean + (stddev*x);
+ yield return mean + (stddev*y);
}
}
- ///
- /// Samples a pair of standard normal distributed random variables using the Box-Muller algorithm.
- ///
- /// The random number generator to use.
- /// a pair of random numbers from the standard normal distribution.
- static Tuple SampleStandardBoxMuller(System.Random rnd)
+ internal static void SamplesUnchecked(System.Random rnd, double[] values, double mean, double stddev)
{
- var v1 = (2.0 * rnd.NextDouble()) - 1.0;
- var v2 = (2.0 * rnd.NextDouble()) - 1.0;
- var r = (v1 * v1) + (v2 * v2);
- while (r >= 1.0 || r == 0.0)
+ if (values.Length == 0)
+ {
+ return;
+ }
+
+ // Since we only accept points within the unit circle
+ // we need to generate roughly 4/pi=1.27 times the numbers needed.
+ int n = (int)Math.Ceiling(values.Length*4*Constants.InvPi);
+ if (n.IsOdd())
+ {
+ n++;
+ }
+ var uniform = rnd.NextDoubles(n);
+
+ // Polar transform
+ double x, y;
+ int index = 0;
+ for (int i = 0; i < uniform.Length && index < values.Length; i += 2)
{
- v1 = (2.0 * rnd.NextDouble()) - 1.0;
- v2 = (2.0 * rnd.NextDouble()) - 1.0;
- r = (v1 * v1) + (v2 * v2);
+ if (!PolarTransform(uniform[i], uniform[i + 1], out x, out y))
+ {
+ continue;
+ }
+ values[index++] = mean + stddev*x;
+ if (index == values.Length) return;
+ values[index++] = mean + stddev*y;
+ if (index == values.Length) return;
}
- var fac = Math.Sqrt(-2.0 * Math.Log(r) / r);
- return new Tuple(v1 * fac, v2 * fac);
+ // remaining, if any
+ while (index < values.Length)
+ {
+ if (!PolarTransform(rnd.NextDouble(), rnd.NextDouble(), out x, out y))
+ {
+ continue;
+ }
+ values[index++] = mean + stddev*x;
+ if (index == values.Length) return;
+ values[index++] = mean + stddev*y;
+ if (index == values.Length) return;
+ }
+ }
+
+ static bool PolarTransform(double a, double b, out double x, out double y)
+ {
+ var v1 = (2.0*a) - 1.0;
+ var v2 = (2.0*b) - 1.0;
+ var r = (v1*v1) + (v2*v2);
+ if (r >= 1.0 || r == 0.0)
+ {
+ x = 0;
+ y = 0;
+ return false;
+ }
+
+ var fac = Math.Sqrt(-2.0*Math.Log(r)/r);
+ x = v1*fac;
+ y = v2*fac;
+ return true;
}
///
@@ -439,7 +499,7 @@ namespace MathNet.Numerics.Distributions
{
if (stddev < 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
- return mean + (stddev*SampleStandardBoxMuller(rnd).Item1);
+ return SampleUnchecked(rnd, mean, stddev);
}
///
@@ -453,12 +513,22 @@ namespace MathNet.Numerics.Distributions
{
if (stddev < 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
- while (true)
- {
- var sample = SampleStandardBoxMuller(rnd);
- yield return mean + (stddev*sample.Item1);
- yield return mean + (stddev*sample.Item2);
- }
+ return SamplesUnchecked(rnd, mean, stddev);
+ }
+
+ ///
+ /// Fills an array with samples generated from the distribution.
+ ///
+ /// The random number generator to use.
+ /// The array to fill with the samples.
+ /// The mean (μ) of the normal distribution.
+ /// The standard deviation (σ) of the normal distribution. Range: σ ≥ 0.
+ /// a sequence of samples from the distribution.
+ public static void Samples(System.Random rnd, double[] values, double mean, double stddev)
+ {
+ if (stddev < 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ SamplesUnchecked(rnd, values, mean, stddev);
}
///
@@ -469,7 +539,9 @@ namespace MathNet.Numerics.Distributions
/// a sample from the distribution.
public static double Sample(double mean, double stddev)
{
- return Sample(SystemRandomSource.Default, mean, stddev);
+ if (stddev < 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ return SampleUnchecked(SystemRandomSource.Default, mean, stddev);
}
///
@@ -480,7 +552,23 @@ namespace MathNet.Numerics.Distributions
/// a sequence of samples from the distribution.
public static IEnumerable Samples(double mean, double stddev)
{
- return Samples(SystemRandomSource.Default, mean, stddev);
+ if (stddev < 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ return SamplesUnchecked(SystemRandomSource.Default, mean, stddev);
+ }
+
+ ///
+ /// Fills an array with samples generated from the distribution.
+ ///
+ /// The array to fill with the samples.
+ /// The mean (μ) of the normal distribution.
+ /// The standard deviation (σ) of the normal distribution. Range: σ ≥ 0.
+ /// a sequence of samples from the distribution.
+ public static void Samples(double[] values, double mean, double stddev)
+ {
+ if (stddev < 0.0) throw new ArgumentException(Resources.InvalidDistributionParameters);
+
+ SamplesUnchecked(SystemRandomSource.Default, values, mean, stddev);
}
}
}
diff --git a/src/Numerics/Distributions/Rayleigh.cs b/src/Numerics/Distributions/Rayleigh.cs
index c1e2648a..e254eb80 100644
--- a/src/Numerics/Distributions/Rayleigh.cs
+++ b/src/Numerics/Distributions/Rayleigh.cs
@@ -32,6 +32,7 @@ using System;
using System.Collections.Generic;
using MathNet.Numerics.Properties;
using MathNet.Numerics.Random;
+using MathNet.Numerics.Threading;
namespace MathNet.Numerics.Distributions
{
@@ -252,6 +253,18 @@ namespace MathNet.Numerics.Distributions
}
}
+ static void SampleUnchecked(System.Random rnd, double[] values, double scale)
+ {
+ rnd.NextDoubles(values);
+ CommonParallel.For(0, values.Length, 4096, (a, b) =>
+ {
+ for (int i = a; i < b; i++)
+ {
+ values[i] = scale*Math.Sqrt(-2.0*Math.Log(values[i]));
+ }
+ });
+ }
+
///
/// Computes the probability density of the distribution (PDF) at x, i.e. ∂P(X ≤ x)/∂x.
///
diff --git a/src/Numerics/Distributions/Triangular.cs b/src/Numerics/Distributions/Triangular.cs
index ac0f690d..991ea0d4 100644
--- a/src/Numerics/Distributions/Triangular.cs
+++ b/src/Numerics/Distributions/Triangular.cs
@@ -32,6 +32,7 @@ using System;
using System.Collections.Generic;
using MathNet.Numerics.Properties;
using MathNet.Numerics.Random;
+using MathNet.Numerics.Threading;
namespace MathNet.Numerics.Distributions
{
@@ -295,6 +296,23 @@ namespace MathNet.Numerics.Distributions
return Samples(_random, _lower, _upper, _mode);
}
+ static void SampleUnchecked(System.Random rnd, double[] values, double lower, double upper, double mode)
+ {
+ double ml = mode - lower;
+ double ul = upper - lower;
+ double um = upper - mode;
+ rnd.NextDoubles(values);
+ CommonParallel.For(0, values.Length, 4096, (a, b) =>
+ {
+ for (int i = a; i < b; i++)
+ {
+ values[i] = values[i] < ml/ul
+ ? lower + Math.Sqrt(values[i]*ul*ml)
+ : upper - Math.Sqrt((1 - values[i])*ul*um);
+ }
+ });
+ }
+
///
/// Computes the probability density of the distribution (PDF) at x, i.e. ∂P(X ≤ x)/∂x.
///
diff --git a/src/Numerics/Distributions/Weibull.cs b/src/Numerics/Distributions/Weibull.cs
index 88fa065b..9330789c 100644
--- a/src/Numerics/Distributions/Weibull.cs
+++ b/src/Numerics/Distributions/Weibull.cs
@@ -32,6 +32,7 @@ using System;
using System.Collections.Generic;
using MathNet.Numerics.Properties;
using MathNet.Numerics.Random;
+using MathNet.Numerics.Threading;
namespace MathNet.Numerics.Distributions
{
@@ -289,6 +290,18 @@ namespace MathNet.Numerics.Distributions
return scale*Math.Pow(-Math.Log(x), 1.0/shape);
}
+ static void SampleUnchecked(System.Random rnd, double[] values, double shape, double scale)
+ {
+ rnd.NextDoubles(values);
+ CommonParallel.For(0, values.Length, 4096, (a, b) =>
+ {
+ for (int i = a; i < b; i++)
+ {
+ values[i] = scale*Math.Pow(-Math.Log(values[i]), 1.0/shape);
+ }
+ });
+ }
+
///
/// Generates a sample from the Weibull distribution.
///
diff --git a/src/Numerics/Random/RandomExtensions.cs b/src/Numerics/Random/RandomExtensions.cs
index 45398c01..50aa5e73 100644
--- a/src/Numerics/Random/RandomExtensions.cs
+++ b/src/Numerics/Random/RandomExtensions.cs
@@ -46,7 +46,7 @@ namespace MathNet.Numerics.Random
/// The array to fill with random values.
///
/// This extension is thread-safe if and only if called on an random number
- /// generator provided by Math.NET Nummerics or derived from the RandomSource class.
+ /// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static void NextDoubles(this System.Random rnd, double[] values)
{
@@ -70,7 +70,7 @@ namespace MathNet.Numerics.Random
/// The size of the array to fill.
///
/// This extension is thread-safe if and only if called on an random number
- /// generator provided by Math.NET Nummerics or derived from the RandomSource class.
+ /// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static double[] NextDoubles(this System.Random rnd, int count)
{
@@ -84,7 +84,7 @@ namespace MathNet.Numerics.Random
///
///
/// This extension is thread-safe if and only if called on an random number
- /// generator provided by Math.NET Nummerics or derived from the RandomSource class.
+ /// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static IEnumerable NextDoubleSequence(this System.Random rnd)
{
@@ -112,7 +112,7 @@ namespace MathNet.Numerics.Random
/// The size of the array to fill.
///
/// This extension is thread-safe if and only if called on an random number
- /// generator provided by Math.NET Nummerics or derived from the RandomSource class.
+ /// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static byte[] NextBytes(this System.Random rnd, int count)
{
@@ -132,7 +132,7 @@ namespace MathNet.Numerics.Random
///
///
/// This extension is thread-safe if and only if called on an random number
- /// generator provided by Math.NET Nummerics or derived from the RandomSource class.
+ /// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static long NextInt64(this System.Random rnd)
{
@@ -160,7 +160,7 @@ namespace MathNet.Numerics.Random
///
///
/// This extension is thread-safe if and only if called on an random number
- /// generator provided by Math.NET Nummerics or derived from the RandomSource class.
+ /// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static int NextFullRangeInt32(this System.Random rnd)
{
@@ -180,7 +180,7 @@ namespace MathNet.Numerics.Random
///
///
/// This extension is thread-safe if and only if called on an random number
- /// generator provided by Math.NET Nummerics or derived from the RandomSource class.
+ /// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static long NextFullRangeInt64(this System.Random rnd)
{
@@ -199,7 +199,7 @@ namespace MathNet.Numerics.Random
///
///
/// This extension is thread-safe if and only if called on an random number
- /// generator provided by Math.NET Nummerics or derived from the RandomSource class.
+ /// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static decimal NextDecimal(this System.Random rnd)
{