Math.NET Numerics | Math.NET Project | GitHub


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, 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 ]
val it : float list = [10.0; 12.0; 14.0] 
[ for x in 10.0 .. 2.0 .. 15.0 -> sin x ]
val it : float list = [-0.5440211109; -0.536572918; 0.9906073557] 

In C# you can get the same result with LinearRange:

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.

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
val it : float [] = 
  [|0.0; 0.222520934; 0.4338837391; 0.6234898019; 0.7818314825; 0.9009688679; 
    0.9749279122; 1.0; 0.9749279122; 0.9009688679; 0.7818314825; 0.6234898019; 
    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.

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)
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)
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)
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)

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
val it : float [] = 
  [|100.0; 101.0; 102.0; 103.0; 104.0; 105.0; 106.0; 107.0; 108.0; 109.0; 
    100.0; 101.0; 102.0; 103.0; 104.0|] 

Sinusoidal

Generates a Sine wave array of the given length. This is equivalent to 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)

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.

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.

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.

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
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:

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)
val it : float [] = [|3.0; 3.0; 5.0; 4.0|] 

Typical F# equivalent:

Array.map2 (+) a b
val it : float [] = [|3.0; 3.0; 5.0; 4.0|] 

And in C# with LINQ:

a.Zip(b, (x, y) => x + y).ToArray();
val x : float
val sin : value:'T -> 'T (requires member Sin)
<summary>Sine of the given number</summary>
<param name="value">The input value.</param>
<returns>The sine of the input.</returns>
module Array from Microsoft.FSharp.Collections
<summary>Contains operations for working with arrays.</summary>
<remarks> See also <a href="https://docs.microsoft.com/dotnet/fsharp/language-reference/arrays">F# Language Guide - Arrays</a>. </remarks>
val map : mapping:('T -> 'U) -> array:'T [] -> 'U []
<summary>Builds a new array whose elements are the results of applying the given function to each of the elements of the array.</summary>
<param name="mapping">The function to transform elements of the array.</param>
<param name="array">The input array.</param>
<returns>The array of transformed elements.</returns>
<exception cref="T:System.ArgumentNullException">Thrown when the input array is null.</exception>
val a : float []
val b : float []
val map2 : mapping:('T1 -> 'T2 -> 'U) -> array1:'T1 [] -> array2:'T2 [] -> 'U []
<summary>Builds a new collection whose elements are the results of applying the given function to the corresponding elements of the two collections pairwise. The two input arrays must have the same lengths, otherwise an <c>ArgumentException</c> is raised.</summary>
<param name="mapping">The function to transform the pairs of the input elements.</param>
<param name="array1">The first input array.</param>
<param name="array2">The second input array.</param>
<exception cref="T:System.ArgumentException">Thrown when the input arrays differ in length.</exception>
<exception cref="T:System.ArgumentNullException">Thrown when either of the input arrays is null.</exception>
<returns>The array of transformed elements.</returns>