Browse Source

Generate: clarifications and simplifications, F# module, docs

pull/197/head
Christoph Ruegg 13 years ago
parent
commit
dfa9483c3b
  1. 1
      MathNet.Numerics.sln
  2. 252
      docs/content/Generate.fsx
  3. 18
      docs/content/index.fsx
  4. 2
      docs/tools/templates/template.cshtml
  5. 8
      src/FSharp/Generate.fs
  6. 244
      src/Numerics/Generate.cs
  7. 8
      src/UnitTests/GenerateTests.cs

1
MathNet.Numerics.sln

@ -43,6 +43,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{039229DA-A
docs\content\DescriptiveStatistics.fsx = docs\content\DescriptiveStatistics.fsx
docs\content\Distance.fsx = docs\content\Distance.fsx
docs\content\Functions.fsx = docs\content\Functions.fsx
docs\content\Generate.fsx = docs\content\Generate.fsx
docs\content\index.fsx = docs\content\index.fsx
docs\content\IntegralTransforms.fsx = docs\content\IntegralTransforms.fsx
docs\content\Integration.fsx = docs\content\Integration.fsx

252
docs/content/Generate.fsx

@ -0,0 +1,252 @@
(*** hide ***)
#I "../../out/lib/net40"
#r "MathNet.Numerics.dll"
#r "MathNet.Numerics.FSharp.dll"
open System
open MathNet.Numerics
let a = [| 2.0; 4.0; 3.0; 6.0 |]
(**
Generating Data
===============
Numerics is all about analyzing and manipulating numeric data. But unless you can read in data from an external
file, source or e.g. with the excellent [F# Type Providers](http://fsharp.github.io/FSharp.Data/),
you may need to generate synthetic or random data locally, or transform existing data into a new form.
The `Generate` class can help you in all these scenarios with a set of static functions generating either
an array or an IEnumerable sequence.
There is some overlap with LINQ, in case of F# also with some integrated language features and its fundamental types.
This is intended for simplicity and consistency between array and sequence operations, as LINQ only supports sequences.
Linear Range
------------
Generates a linearly spaced array within the inclusive interval between start and stop,
and either a provided step or a step of 1.0. Linear range is equivalent to the
single colon `:` and double colon `::` operators in MATLAB.
F# has built in linear range support in array comprehensions with the colon operator:
*)
[ 10.0 .. 2.0 .. 15.0 ]
// [fsi:val it : float list = [10.0; 12.0; 14.0] ]
[ for x in 10.0 .. 2.0 .. 15.0 -> sin x ]
// [fsi:val it : float list = [-0.5440211109; -0.536572918; 0.9906073557] ]
(**
In C# you can get the same result with `LinearRange`:
[lang=csharp]
Generate.LinearRange(10, 2, 15); // returns array { 10.0, 12.0, 14.0 }
Generate.LinearRangeMap(10, 2, 15, Math.Sin); // applies sin(x) to each value
Most of the routines in the `Generate` class have variants with a `Map` suffix.
Instead of returning an array with the generated numbers, these routines instead
apply the generated numbers to a custom function and return an array with the results.
Similarly, some routines have variants with a `Sequence` suffix that return
lazy enumerable sequences instead of arrays.
Linear-Spaced and Log-Spaced
----------------------------
Generates a linearly or log-spaced array within an interval, but other than linear range
where the step is provided, here we instead provide the number of values we want.
This is equivalent to the linspace and logspace operators in MATLAB.
[lang=csharp]
Generate.LinearSpaced(11, 0.0, 1.0); // returns array { 0.0, 0.1, 0.2, .., 1.0 }
Generate.LinearSpacedMap(15, 0.0, Math.Pi, Math.Sin); // applies sin(x) to each value
In F# you can also use:
*)
Generate.linearSpacedMap 15 0.0 Math.PI sin
// [fsi:val it : float [] = ]
// [fsi: [|0.0; 0.222520934; 0.4338837391; 0.6234898019; 0.7818314825; 0.9009688679; ]
// [fsi: 0.9749279122; 1.0; 0.9749279122; 0.9009688679; 0.7818314825; 0.6234898019; ]
// [fsi: 0.4338837391; 0.222520934; 1.224606354e-16|] ]
(**
`LogSpaced` works the same way but instead of the values $10^x$ it spaces the decade exponents $x$ linearly
between the provided two exponents.
[lang=csharp]
Generate.LogSpaced(4,0,3); // returns array { 1, 10, 100, 1000 }
Kronecker Delta Impulse
-----------------------
The Kronecker delta $\delta[n]$ is a fundamental signal in time-discrete signal processing,
often referred to as *unit impulse*. When applied to a system, the resulting output is the system's *impulse response*.
It is closely related to the Dirac delta impulse function $\delta(x)$ in continuous signal processing.
$$$
\delta[n] = \begin{cases} 0 &\mbox{if } n \ne 0 \\ 1 & \mbox{if } n = 0\end{cases}
The `Impulse` routine generates a Kronecker delta impulse, but also accepts a sample delay
parameter $d$ and amplitude $A$ such that the resulting generated signal is
$$$
s[n] = A\cdot\delta[n-d] = \begin{cases} 0 &\mbox{if } n \ne d \\ A & \mbox{if } n = d\end{cases}
There is also a periodic version in `PeriodicImpulse` which accepts an additional `period` parameter.
*)
Generate.Impulse(8, 2.0, 3)
// [fsi:val it : float [] = [|0.0; 0.0; 0.0; 2.0; 0.0; 0.0; 0.0; 0.0|] ]
Generate.PeriodicImpulse(8, 3, 10.0, 1)
// [fsi:val it : float [] = [|0.0; 10.0; 0.0; 0.0; 10.0; 0.0; 0.0; 10.0|] ]
(**
Heaviside Step
--------------
Another fundamental signal in signal processing, the Heaviside step function $H[n]$
is the integral of the Dirac delta impulse and represents a signal that switches on
at a specified time and then stays on indefinitely. In discrete time:
$$$
H[n] = \begin{cases} 0 &\mbox{if } n < 0 \\ 1 & \mbox{if } n \ge 0\end{cases}
The `Step` routines generates a Heaviside step, but just like the Kronecker Delta impulse
also accepts a sample delay parameter $d$ and amplitude $A$ such that the resulting generated signal is
$$$
s[n] = A\cdot H[n-d] = \begin{cases} 0 &\mbox{if } n < d \\ A & \mbox{if } n \ge d\end{cases}
*)
Generate.Step(8, 2.0, 3)
// [fsi:val it : float [] = [|0.0; 0.0; 0.0; 2.0; 2.0; 2.0; 2.0; 2.0|] ]
(**
Periodic Sawtooth
-----------------
Generates an array of the given length with a periodic upper forward sawtooth signal,
i.e. a line starting at zero up to some amplitude $A$, then drop back to zero instantly and start afresh.
The sawtooth can be used to turn any arbitrary function defined over the interval $[0,A)$ into a
periodic function by repeating it continuously.
Mathematically, the sawtooth can be described using the fractional part function
$\mathrm{frac}(x) \equiv x - \lfloor x \rfloor$, frequency $\nu$ and phase $\theta$ as
$$$
s(x) = A\cdot\mathrm{frac}\left(x\nu+\frac{\theta}{A}\right)
In a trigonometric interpretation the signal represents the angular position $\alpha$ of a point moving endlessly
around a circle with radius $\frac{A}{2\pi}$ (and thus circumference $A$) in constant speed,
normalized to strictly $0\le\alpha < A$.
`Generate.Periodic(length,samplingRate,frequency,amplitude,phase,delay)`
* **Sampling Rate**: Number of samples $r$ per time unit. If the time unit is 1s, the sampling rate has unit Hz.
* **Frequency**: Frequency $\nu$ of the signal, in sawtooth-periods per time unit. If the time unit is 1s, the frequency has unit Hz.
For a desired number of samples $n$ per sawtooth-period and sampling rate $r$ choose $\nu=\frac{r}{n}$.
* **Amplitude**: The theoretical maximum value $A$, which is never reached and logically equivalent to zero.
The circumference of the circle. Typically $1$ or $2\pi$.
* **Phase**: Optional initial value or phase offset. Contributes to $\theta$.
* **Delay**: Optional initial delay, in samples. Contributes to $\theta$.
The equivalent map function accepts a custom map lambda as second argument after the length:
*)
Generate.periodicMap 15 ((+) 100.0) 1000.0 100.0 10.0 0.0 0
// [fsi:val it : float [] = ]
// [fsi: [|100.0; 101.0; 102.0; 103.0; 104.0; 105.0; 106.0; 107.0; 108.0; 109.0; ]
// [fsi: 100.0; 101.0; 102.0; 103.0; 104.0|] ]
(**
Sinusoidal
----------
Generates a Sine wave array of the given length. This is equivalent of applying a scaled trigonometric Sine function
to a periodic sawtooth of amplitude $2\pi$.
$$$
s(x) = A\cdot\sin(2\pi\nu x + \theta)
`Generate.Sinusoidal(length,samplingRate,frequency,amplitude,mean,phase,delay)`
[lang=csharp]
Generate.Sinusoidal(15, 1000.0, 100.0, 10.0);
// returns array { 0, 5.9, 9.5, 9.5, 5.9, 0, -5.9, ... }
Random
------
Generate random sequences by sampling from a random distribution.
#### Uniform Distribution
Generate sample sequences distributed uniformly between 0 and 1.
[lang=csharp]
Generate.Uniform(100); // e.g. 0.867421787170424, 0.236744313145403, ...
Uniform supports mapping to functions with not only one but also two uniform variables
as arguments, with `UniformMap` and `UniformMap2`. As usual, lazy sequences can be
generated using the variants with the `Sequence` suffix, e.g. `UniformMap2Sequence`.
#### Non-Uniform Distributions
Instead of uniform we can also sample from other distributions.
* `Gaussian` - sample an array or sequence form a normal or standard distribution
* `Stable` - sample from a Levy alpha-stable distribution.
In addition, the `Random` functions accept a custom distribution instance to sample
from. See the section about random numbers and probability distributions for details.
Map
---
Generates a new array or sequence where each new values is the result of applying the provided function
the the corresponding value in the input data.
[lang=csharp]
var a = new double[] { 2.0, 4.0, 3.0, 6.0 };
Generate.Map(a, x => x + 1.0); // returns array { 3.0, 5.0, 4.0, 7.0 }
In F# you'd typically use the Array module to the same effect (and should continue to do so):
*)
Array.map ((+) 1.0) a
// [fsi:val it : float [] = [|3.0; 5.0; 4.0; 7.0|] ]
(**
...but no equivalent operation is available in the .NET base class libraries (BCL) for C#.
You can use LINQ, but that operates on sequences instead of arrays:
[lang=csharp]
a.Select(x => x + 1.0).ToArray();
Similarly, with `Map2` you can also map a function accepting two inputs to two input arrays:
*)
let b = [| 1.0; -1.0; 2.0; -2.0 |]
Generate.Map2(a, b, fun x y -> x + y)
// [fsi:val it : float [] = [|3.0; 3.0; 5.0; 4.0|] ]
(**
Typical F# equivalent:
*)
Array.map2 (+) a b
// [fsi:val it : float [] = [|3.0; 3.0; 5.0; 4.0|] ]
(**
And in C# with LINQ:
[lang=csharp]
a.Zip(b, (x, y) => x + y).ToArray();
*)

18
docs/content/index.fsx

@ -12,14 +12,14 @@ Installation Instructions
The recommended way to get Math.NET Numerics is to use NuGet. The following packages are provided and maintained in the public [NuGet Gallery](https://nuget.org/profiles/mathnet/):
- `MathNet.Numerics` - core package, including .Net 4, .Net 3.5 and portable/PCL builds
- `MathNet.Numerics.FSharp` - optional extensions for a better F# experience
- `MathNet.Numerics.Data.Text` - optional extensions for text-based matrix input/output
- `MathNet.Numerics.Data.Matlab` - optional extensions for MATLAB matrix file input/output
- `MathNet.Numerics.MKL.Win-x86` - optional Linear Algebra MKL native provider
- `MathNet.Numerics.MKL.Win-x64` - optional Linear Algebra MKL native provider
- `MathNet.Numerics.Signed` - strong-named version of the core package *(not recommended)*
- `MathNet.Numerics.FSharp.Signed` - strong-named version of the F# package *(not recommended)*
- `MathNet.Numerics` - core package, including .Net 4, .Net 3.5 and portable/PCL builds.
- `MathNet.Numerics.FSharp` - optional extensions for a better F# experience. BigRational.
- `MathNet.Numerics.Data.Text` - optional extensions for text-based matrix input/output.
- `MathNet.Numerics.Data.Matlab` - optional extensions for MATLAB matrix file input/output.
- `MathNet.Numerics.MKL.Win-x86` - optional Linear Algebra MKL native provider.
- `MathNet.Numerics.MKL.Win-x64` - optional Linear Algebra MKL native provider.
- `MathNet.Numerics.Signed` - strong-named version of the core package *(not recommended)*.
- `MathNet.Numerics.FSharp.Signed` - strong-named version of the F# package *(not recommended)*.
Alternatively you can also download the binaries in Zip packages, available on [CodePlex](http://mathnetnumerics.codeplex.com/releases):
@ -30,7 +30,7 @@ Supported Platforms:
- .Net 4.0, .Net 3.5 and Mono: Windows, Linux and Mac.
- PCL Portable Profiles 47 and 136: Silverlight 5, Windows Phone 8, .NET for Windows Store apps (Metro).
- PCL/Xamarin: Android, iOS
- PCL/Xamarin: Android, iOS *(not verified due to lack of license and devices)*
Building Math.NET Numerics
--------------------------

2
docs/tools/templates/template.cshtml

@ -58,7 +58,7 @@
<li>Complex Numbers</li>
<li>Euclid & Number Theory</li>
<li>Combinatorics</li>
<li>Generating Data</li>
<li><a href="@Root/Generate.html">Generating Data</a></li>
<li><a href="@Root/RandomAndDistributions.html">Random Numbers</a></li>
<li>Probability Distributions</li>
<li><a href="@Root/Distance.html">Distance Metrics</a></li>

8
src/FSharp/Generate.fs

@ -58,7 +58,7 @@ module Generate =
let inline randomMap2 length distribution map = Generate.RandomMap2(length, distribution, tobcl2 map)
let inline randomMap2Seq distribution map = Generate.RandomMap2Sequence(distribution, tobcl2 map)
let inline randomUniformMap length map = Generate.RandomUniformMap(length, tobcl map)
let inline randomUniformMapSeq map = Generate.RandomUniformMapSequence(tobcl map)
let inline randomUniformMap2 length map = Generate.RandomUniformMap2(length, tobcl2 map)
let inline randomUniformMap2Seq map = Generate.RandomUniformMap2Sequence(tobcl2 map)
let inline uniformMap length map = Generate.UniformMap(length, tobcl map)
let inline uniformMapSeq map = Generate.UniformMapSequence(tobcl map)
let inline uniformMap2 length map = Generate.UniformMap2(length, tobcl2 map)
let inline uniformMap2Seq map = Generate.UniformMap2Sequence(tobcl2 map)

244
src/Numerics/Generate.cs

@ -196,7 +196,7 @@ namespace MathNet.Numerics
}
/// <summary>
/// Generate a linearly spaced sample vector within the inclusive interval (start, stop) and the provide step.
/// Generate a linearly spaced sample vector within the inclusive interval (start, stop) and the provided step.
/// The start value is aways included as first value, but stop is only included if it stop-start is a multiple of step.
/// Equivalent to MATLAB double colon operator (::).
/// </summary>
@ -457,44 +457,29 @@ namespace MathNet.Numerics
}
/// <summary>
/// Create a Dirac Delta Impulse sample vector.
/// Create a Kronecker Delta impulse sample vector.
/// </summary>
/// <param name="length">The number of samples to generate.</param>
/// <param name="period">impulse sequence period. -1 for single impulse only.</param>
/// <param name="amplitude">The maximal reached peak.</param>
/// <param name="delay">Offset to the time axis. Zero or positive.</param>
public static double[] Impulse(int length, int period, double amplitude, int delay)
public static double[] Impulse(int length, double amplitude, int delay)
{
var data = new double[length];
if (period <= 0)
{
if (delay >= 0 && delay < length)
{
data[delay] = amplitude;
}
}
else
if (delay >= 0 && delay < length)
{
delay = ((delay%period) + period)%period;
while (delay < length)
{
data[delay] = amplitude;
delay += period;
}
data[delay] = amplitude;
}
return data;
}
/// <summary>
/// Create a Dirac Delta Impulse sample vector.
/// Create a Kronecker Delta impulse sample vector.
/// </summary>
/// <param name="period">impulse sequence period. -1 for single impulse only.</param>
/// <param name="amplitude">The maximal reached peak.</param>
/// <param name="delay">Offset to the time axis. Zero or positive.</param>
public static IEnumerable<double> ImpulseSequence(int period, double amplitude, int delay)
/// <param name="delay">Offset to the time axis, hence the sample index of the impulse.</param>
public static IEnumerable<double> ImpulseSequence(double amplitude, int delay)
{
if (period <= 0)
if (delay >= 0)
{
for (int i = 0; i < delay; i++)
{
@ -502,87 +487,141 @@ namespace MathNet.Numerics
}
yield return amplitude;
}
while (true)
{
yield return 0d;
}
while (true)
{
yield return 0d;
}
else
}
/// <summary>
/// Create a periodic Kronecker Delta impulse sample vector.
/// </summary>
/// <param name="length">The number of samples to generate.</param>
/// <param name="period">impulse sequence period.</param>
/// <param name="amplitude">The maximal reached peak.</param>
/// <param name="delay">Offset to the time axis. Zero or positive.</param>
public static double[] PeriodicImpulse(int length, int period, double amplitude, int delay)
{
var data = new double[length];
delay = Euclid.Modulus(delay, period);
while (delay < length)
{
delay = ((delay%period) + period)%period;
data[delay] = amplitude;
delay += period;
}
return data;
}
for (int i = 0; i < delay; i++)
{
yield return 0d;
}
/// <summary>
/// Create a Kronecker Delta impulse sample vector.
/// </summary>
/// <param name="period">impulse sequence period.</param>
/// <param name="amplitude">The maximal reached peak.</param>
/// <param name="delay">Offset to the time axis. Zero or positive.</param>
public static IEnumerable<double> PeriodicImpulseSequence(int period, double amplitude, int delay)
{
delay = Euclid.Modulus(delay, period);
while (true)
{
yield return amplitude;
for (int i = 0; i < delay; i++)
{
yield return 0d;
}
for (int i = 1; i < period; i++)
{
yield return 0d;
}
while (true)
{
yield return amplitude;
for (int i = 1; i < period; i++)
{
yield return 0d;
}
}
}
/// <summary>
/// Create random samples.
/// Create random samples, uniform between 0 and 1.
/// Faster than other methods but with reduced guarantees on randomness.
/// </summary>
public static double[] Random(int length, IContinuousDistribution distribution)
public static double[] Uniform(int length)
{
return distribution.Samples().Take(length).ToArray();
return SystemRandomSource.Doubles(length);
}
/// <summary>
/// Create an infinite random sample sequence.
/// Create an infinite random sample sequence, uniform between 0 and 1.
/// Faster than other methods but with reduced guarantees on randomness.
/// </summary>
public static IEnumerable<double> Random(IContinuousDistribution distribution)
public static IEnumerable<double> UniformSequence()
{
return distribution.Samples();
return SystemRandomSource.DoubleSequence();
}
/// <summary>
/// Create random samples, uniform between 0 and 1.
/// Generate samples by sampling a function at samples from a probability distribution, uniform between 0 and 1.
/// Faster than other methods but with reduced guarantees on randomness.
/// </summary>
public static double[] RandomUniform(int length)
public static T[] UniformMap<T>(int length, Func<double, T> map)
{
return SystemRandomSource.Doubles(length);
var samples = SystemRandomSource.Doubles(length);
var data = new T[length];
for (int i = 0; i < data.Length; i++)
{
data[i] = map(samples[i]);
}
return data;
}
/// <summary>
/// Create an infinite random sample sequence, uniform between 0 and 1.
/// Generate a sample sequence by sampling a function at samples from a probability distribution, uniform between 0 and 1.
/// Faster than other methods but with reduced guarantees on randomness.
/// </summary>
public static IEnumerable<double> RandomUniform()
public static IEnumerable<T> UniformMapSequence<T>(Func<double, T> map)
{
return SystemRandomSource.DoubleSequence();
return SystemRandomSource.DoubleSequence().Select(map);
}
/// <summary>
/// Create random samples.
/// Generate samples by sampling a function at sample pairs from a probability distribution, uniform between 0 and 1.
/// Faster than other methods but with reduced guarantees on randomness.
/// </summary>
public static Complex[] RandomComplex(int length, IContinuousDistribution distribution)
public static T[] UniformMap2<T>(int length, Func<double, double, T> map)
{
return RandomMap2(length, distribution, (r, i) => new Complex(r, i));
var samples1 = SystemRandomSource.Doubles(length);
var samples2 = SystemRandomSource.Doubles(length);
var data = new T[length];
for (int i = 0; i < data.Length; i++)
{
data[i] = map(samples1[i], samples2[i]);
}
return data;
}
/// <summary>
/// Create an infinite random sample sequence.
/// Generate a sample sequence by sampling a function at sample pairs from a probability distribution, uniform between 0 and 1.
/// Faster than other methods but with reduced guarantees on randomness.
/// </summary>
public static IEnumerable<Complex> RandomComplex(IContinuousDistribution distribution)
public static IEnumerable<T> UniformMap2Sequence<T>(Func<double, double, T> map)
{
return RandomMap2Sequence(distribution, (r, i) => new Complex(r, i));
var rnd1 = SystemRandomSource.Default;
for (int i = 0; i < 128; i++)
{
yield return map(rnd1.NextDouble(), rnd1.NextDouble());
}
var rnd2 = new System.Random(RandomSeed.Robust());
while (true)
{
yield return map(rnd2.NextDouble(), rnd2.NextDouble());
}
}
/// <summary>
/// Create samples with independent amplitudes of normal distribution and a flat spectral density.
/// </summary>
public static double[] WhiteGaussianNoise(int length, double mean, double standardDeviation)
public static double[] Gaussian(int length, double mean, double standardDeviation)
{
return Normal.Samples(SystemRandomSource.Default, mean, standardDeviation).Take(length).ToArray();
}
@ -590,7 +629,7 @@ namespace MathNet.Numerics
/// <summary>
/// Create an infinite sample sequence with independent amplitudes of normal distribution and a flat spectral density.
/// </summary>
public static IEnumerable<double> WhiteGaussianNoiseSequence(double mean, double standardDeviation)
public static IEnumerable<double> GaussianSequence(double mean, double standardDeviation)
{
return Normal.Samples(SystemRandomSource.Default, mean, standardDeviation);
}
@ -603,9 +642,9 @@ namespace MathNet.Numerics
/// <param name="beta">Skewness beta-parameter of the stable distribution</param>
/// <param name="scale">Scale c-parameter of the stable distribution</param>
/// <param name="location">Location mu-parameter of the stable distribution</param>
public static double[] StableNoise(int length, double alpha, double beta, double scale, double location)
public static double[] Stable(int length, double alpha, double beta, double scale, double location)
{
return Stable.Samples(SystemRandomSource.Default, alpha, beta, scale, location).Take(length).ToArray();
return Distributions.Stable.Samples(SystemRandomSource.Default, alpha, beta, scale, location).Take(length).ToArray();
}
/// <summary>
@ -615,110 +654,83 @@ namespace MathNet.Numerics
/// <param name="beta">Skewness beta-parameter of the stable distribution</param>
/// <param name="scale">Scale c-parameter of the stable distribution</param>
/// <param name="location">Location mu-parameter of the stable distribution</param>
public static IEnumerable<double> StableNoiseSequence(double alpha, double beta, double scale, double location)
public static IEnumerable<double> StableSequence(double alpha, double beta, double scale, double location)
{
return Stable.Samples(SystemRandomSource.Default, alpha, beta, scale, location);
return Distributions.Stable.Samples(SystemRandomSource.Default, alpha, beta, scale, location);
}
/// <summary>
/// Generate samples by sampling a function at samples from a probability distribution.
/// Create random samples.
/// </summary>
public static T[] RandomMap<T>(int length, IContinuousDistribution distribution, Func<double, T> map)
public static double[] Random(int length, IContinuousDistribution distribution)
{
var data = new T[length];
for (int i = 0; i < data.Length; i++)
{
data[i] = map(distribution.Sample());
}
return data;
return distribution.Samples().Take(length).ToArray();
}
/// <summary>
/// Generate a sample sequence by sampling a function at samples from a probability distribution.
/// Create an infinite random sample sequence.
/// </summary>
public static IEnumerable<T> RandomMapSequence<T>(IContinuousDistribution distribution, Func<double, T> map)
public static IEnumerable<double> Random(IContinuousDistribution distribution)
{
return distribution.Samples().Select(map);
return distribution.Samples();
}
/// <summary>
/// Generate samples by sampling a function at sample pairs from a probability distribution.
/// Create random samples.
/// </summary>
public static T[] RandomMap2<T>(int length, IContinuousDistribution distribution, Func<double, double, T> map)
public static Complex[] RandomComplex(int length, IContinuousDistribution distribution)
{
var data = new T[length];
for (int i = 0; i < data.Length; i++)
{
data[i] = map(distribution.Sample(), distribution.Sample());
}
return data;
return RandomMap2(length, distribution, (r, i) => new Complex(r, i));
}
/// <summary>
/// Generate a sample sequence by sampling a function at sample pairs from a probability distribution.
/// Create an infinite random sample sequence.
/// </summary>
public static IEnumerable<T> RandomMap2Sequence<T>(IContinuousDistribution distribution, Func<double, double, T> map)
public static IEnumerable<Complex> RandomComplex(IContinuousDistribution distribution)
{
return distribution.Samples().Zip(distribution.Samples(), map);
return RandomMap2Sequence(distribution, (r, i) => new Complex(r, i));
}
/// <summary>
/// Generate samples by sampling a function at samples from a probability distribution, uniform between 0 and 1.
/// Faster than other methods but with reduced guarantees on randomness.
/// Generate samples by sampling a function at samples from a probability distribution.
/// </summary>
public static T[] RandomUniformMap<T>(int length, Func<double, T> map)
public static T[] RandomMap<T>(int length, IContinuousDistribution distribution, Func<double, T> map)
{
var samples = SystemRandomSource.Doubles(length);
var data = new T[length];
for (int i = 0; i < data.Length; i++)
{
data[i] = map(samples[i]);
data[i] = map(distribution.Sample());
}
return data;
}
/// <summary>
/// Generate a sample sequence by sampling a function at samples from a probability distribution, uniform between 0 and 1.
/// Faster than other methods but with reduced guarantees on randomness.
/// Generate a sample sequence by sampling a function at samples from a probability distribution.
/// </summary>
public static IEnumerable<T> RandomUniformMapSequence<T>(Func<double, T> map)
public static IEnumerable<T> RandomMapSequence<T>(IContinuousDistribution distribution, Func<double, T> map)
{
return SystemRandomSource.DoubleSequence().Select(map);
return distribution.Samples().Select(map);
}
/// <summary>
/// Generate samples by sampling a function at sample pairs from a probability distribution, uniform between 0 and 1.
/// Faster than other methods but with reduced guarantees on randomness.
/// Generate samples by sampling a function at sample pairs from a probability distribution.
/// </summary>
public static T[] RandomUniformMap2<T>(int length, Func<double, double, T> map)
public static T[] RandomMap2<T>(int length, IContinuousDistribution distribution, Func<double, double, T> map)
{
var samples1 = SystemRandomSource.Doubles(length);
var samples2 = SystemRandomSource.Doubles(length);
var data = new T[length];
for (int i = 0; i < data.Length; i++)
{
data[i] = map(samples1[i], samples2[i]);
data[i] = map(distribution.Sample(), distribution.Sample());
}
return data;
}
/// <summary>
/// Generate a sample sequence by sampling a function at sample pairs from a probability distribution, uniform between 0 and 1.
/// Faster than other methods but with reduced guarantees on randomness.
/// Generate a sample sequence by sampling a function at sample pairs from a probability distribution.
/// </summary>
public static IEnumerable<T> RandomUniformMap2Sequence<T>(Func<double, double, T> map)
public static IEnumerable<T> RandomMap2Sequence<T>(IContinuousDistribution distribution, Func<double, double, T> map)
{
var rnd1 = SystemRandomSource.Default;
for (int i = 0; i < 128; i++)
{
yield return map(rnd1.NextDouble(), rnd1.NextDouble());
}
var rnd2 = new System.Random(RandomSeed.Robust());
while (true)
{
yield return map(rnd2.NextDouble(), rnd2.NextDouble());
}
return distribution.Samples().Zip(distribution.Samples(), map);
}
}
}

8
src/UnitTests/GenerateTests.cs

@ -188,12 +188,12 @@ namespace MathNet.Numerics.UnitTests
public void ImpulseConsistentWithSequence()
{
Assert.That(
Generate.ImpulseSequence(0, 5, 40).Take(1000).ToArray(),
Is.EqualTo(Generate.Impulse(1000, 0, 5, 40)).AsCollection);
Generate.PeriodicImpulseSequence(0, 5, 40).Take(1000).ToArray(),
Is.EqualTo(Generate.PeriodicImpulse(1000, 0, 5, 40)).AsCollection);
Assert.That(
Generate.ImpulseSequence(100, 5, 40).Take(1000).ToArray(),
Is.EqualTo(Generate.Impulse(1000, 100, 5, 40)).AsCollection);
Generate.PeriodicImpulseSequence(100, 5, 40).Take(1000).ToArray(),
Is.EqualTo(Generate.PeriodicImpulse(1000, 100, 5, 40)).AsCollection);
}
}
}

Loading…
Cancel
Save