// // Math.NET Numerics, part of the Math.NET Project // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // // Copyright (c) 2009-2016 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections.Generic; using System.Linq; using IStation.Numerics.Distributions; using IStation.Numerics.Random; using IStation.Numerics.Threading; using BigInteger = System.Numerics.BigInteger; using Complex = System.Numerics.Complex; namespace IStation.Numerics { public static class Generate { /// /// Generate samples by sampling a function at the provided points. /// public static T[] Map(TA[] points, Func map) { var res = new T[points.Length]; for (int i = 0; i < points.Length; i++) { res[i] = map(points[i]); } return res; } /// /// Generate a sample sequence by sampling a function at the provided point sequence. /// public static IEnumerable MapSequence(IEnumerable points, Func map) { return points.Select(map); } /// /// Generate samples by sampling a function at the provided points. /// public static T[] Map2(TA[] pointsA, TB[] pointsB, Func map) { if (pointsA.Length != pointsB.Length) { throw new ArgumentException("The array arguments must have the same length.", nameof(pointsB)); } var res = new T[pointsA.Length]; for (int i = 0; i < res.Length; i++) { res[i] = map(pointsA[i], pointsB[i]); } return res; } /// /// Generate a sample sequence by sampling a function at the provided point sequence. /// public static IEnumerable Map2Sequence(IEnumerable pointsA, IEnumerable pointsB, Func map) { return pointsA.Zip(pointsB, map); } /// /// Generate a linearly spaced sample vector of the given length between the specified values (inclusive). /// Equivalent to MATLAB linspace but with the length as first instead of last argument. /// public static double[] LinearSpaced(int length, double start, double stop) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } if (length == 0) return new double[0]; if (length == 1) return new[] { stop }; double step = (stop - start)/(length - 1); var data = new double[length]; for (int i = 0; i < data.Length; i++) { data[i] = start + i*step; } data[data.Length - 1] = stop; return data; } /// /// Generate samples by sampling a function at linearly spaced points between the specified values (inclusive). /// public static T[] LinearSpacedMap(int length, double start, double stop, Func map) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } if (length == 0) return new T[0]; if (length == 1) return new[] { map(stop) }; double step = (stop - start)/(length - 1); var data = new T[length]; for (int i = 0; i < data.Length; i++) { data[i] = map(start + i*step); } data[data.Length - 1] = map(stop); return data; } /// /// Generate a base 10 logarithmically spaced sample vector of the given length between the specified decade exponents (inclusive). /// Equivalent to MATLAB logspace but with the length as first instead of last argument. /// public static double[] LogSpaced(int length, double startExponent, double stopExponent) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } if (length == 0) return new double[0]; if (length == 1) return new[] { Math.Pow(10, stopExponent) }; double step = (stopExponent - startExponent)/(length - 1); var data = new double[length]; for (int i = 0; i < data.Length; i++) { data[i] = Math.Pow(10, startExponent + i*step); } data[data.Length - 1] = Math.Pow(10, stopExponent); return data; } /// /// Generate samples by sampling a function at base 10 logarithmically spaced points between the specified decade exponents (inclusive). /// public static T[] LogSpacedMap(int length, double startExponent, double stopExponent, Func map) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } if (length == 0) return new T[0]; if (length == 1) return new[] { map(Math.Pow(10, stopExponent)) }; double step = (stopExponent - startExponent)/(length - 1); var data = new T[length]; for (int i = 0; i < data.Length; i++) { data[i] = map(Math.Pow(10, startExponent + i*step)); } data[data.Length - 1] = map(Math.Pow(10, stopExponent)); return data; } /// /// Generate a linearly spaced sample vector within the inclusive interval (start, stop) and step 1. /// Equivalent to MATLAB colon operator (:). /// public static double[] LinearRange(int start, int stop) { if (start == stop) return new double[] { start }; if (start < stop) { var data = new double[stop - start + 1]; for (int i = 0; i < data.Length; i++) { data[i] = start + i; } return data; } else { var data = new double[start - stop + 1]; for (int i = 0; i < data.Length; i++) { data[i] = start - i; } return data; } } /// /// Generate a linearly spaced sample vector within the inclusive interval (start, stop) and step 1. /// Equivalent to MATLAB colon operator (:). /// public static int[] LinearRangeInt32(int start, int stop) { if (start == stop) return new int[] { start }; if (start < stop) { var data = new int[stop - start + 1]; for (int i = 0; i < data.Length; i++) { data[i] = start + i; } return data; } else { var data = new int[start - stop + 1]; for (int i = 0; i < data.Length; i++) { data[i] = start - i; } return data; } } /// /// 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 (::). /// public static double[] LinearRange(int start, int step, int stop) { if (start == stop) return new double[] { start }; if (start < stop && step < 0 || start > stop && step > 0 || step == 0d) { return new double[0]; } var data = new double[(stop - start)/step + 1]; for (int i = 0; i < data.Length; i++) { data[i] = start + i*step; } return data; } /// /// 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 (::). /// public static int[] LinearRangeInt32(int start, int step, int stop) { if (start == stop) return new int[] { start }; if (start < stop && step < 0 || start > stop && step > 0 || step == 0d) { return new int[0]; } var data = new int[(stop - start) / step + 1]; for (int i = 0; i < data.Length; i++) { data[i] = start + i * step; } return data; } /// /// Generate a linearly spaced sample vector within the inclusive interval (start, stop) and the provide 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 (::). /// public static double[] LinearRange(double start, double step, double stop) { if (start == stop) return new[] { start }; if (start < stop && step < 0 || start > stop && step > 0 || step == 0d) { return new double[0]; } var data = new double[(int)Math.Floor((stop - start)/step + 1d)]; for (int i = 0; i < data.Length; i++) { data[i] = start + i*step; } return data; } /// /// Generate samples by sampling a function at linearly spaced points within the inclusive interval (start, stop) and the provide step. /// The start value is aways included as first value, but stop is only included if it stop-start is a multiple of step. /// public static T[] LinearRangeMap(double start, double step, double stop, Func map) { if (start == stop) return new[] { map(start) }; if (start < stop && step < 0 || start > stop && step > 0 || step == 0d) { return new T[0]; } var data = new T[(int)Math.Floor((stop - start)/step + 1d)]; for (int i = 0; i < data.Length; i++) { data[i] = map(start + i*step); } return data; } /// /// Create a periodic wave. /// /// The number of samples to generate. /// Samples per time unit (Hz). Must be larger than twice the frequency to satisfy the Nyquist criterion. /// Frequency in periods per time unit (Hz). /// The length of the period when sampled at one sample per time unit. This is the interval of the periodic domain, a typical value is 1.0, or 2*Pi for angular functions. /// Optional phase offset. /// Optional delay, relative to the phase. public static double[] Periodic(int length, double samplingRate, double frequency, double amplitude = 1.0, double phase = 0.0, int delay = 0) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } double step = frequency/samplingRate*amplitude; phase = Euclid.Modulus(phase - delay*step, amplitude); var data = new double[length]; for (int i = 0, k = 0; i < data.Length; i++, k++) { var x = phase + k*step; if (x >= amplitude) { x %= amplitude; phase = x; k = 0; } data[i] = x; } return data; } /// /// Create a periodic wave. /// /// The number of samples to generate. /// The function to apply to each of the values and evaluate the resulting sample. /// Samples per time unit (Hz). Must be larger than twice the frequency to satisfy the Nyquist criterion. /// Frequency in periods per time unit (Hz). /// The length of the period when sampled at one sample per time unit. This is the interval of the periodic domain, a typical value is 1.0, or 2*Pi for angular functions. /// Optional phase offset. /// Optional delay, relative to the phase. public static T[] PeriodicMap(int length, Func map, double samplingRate, double frequency, double amplitude = 1.0, double phase = 0.0, int delay = 0) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } double step = frequency/samplingRate*amplitude; phase = Euclid.Modulus(phase - delay*step, amplitude); var data = new T[length]; for (int i = 0, k = 0; i < data.Length; i++, k++) { var x = phase + k*step; if (x >= amplitude) { x %= amplitude; phase = x; k = 0; } data[i] = map(x); } return data; } /// /// Create an infinite periodic wave sequence. /// /// Samples per time unit (Hz). Must be larger than twice the frequency to satisfy the Nyquist criterion. /// Frequency in periods per time unit (Hz). /// The length of the period when sampled at one sample per time unit. This is the interval of the periodic domain, a typical value is 1.0, or 2*Pi for angular functions. /// Optional phase offset. /// Optional delay, relative to the phase. public static IEnumerable PeriodicSequence(double samplingRate, double frequency, double amplitude = 1.0, double phase = 0.0, int delay = 0) { double step = frequency/samplingRate*amplitude; phase = Euclid.Modulus(phase - delay*step, amplitude); int k = 0; while (true) { var x = phase + (k++)*step; if (x >= amplitude) { x %= amplitude; phase = x; k = 1; } yield return x; } } /// /// Create an infinite periodic wave sequence. /// /// The function to apply to each of the values and evaluate the resulting sample. /// Samples per time unit (Hz). Must be larger than twice the frequency to satisfy the Nyquist criterion. /// Frequency in periods per time unit (Hz). /// The length of the period when sampled at one sample per time unit. This is the interval of the periodic domain, a typical value is 1.0, or 2*Pi for angular functions. /// Optional phase offset. /// Optional delay, relative to the phase. public static IEnumerable PeriodicMapSequence(Func map, double samplingRate, double frequency, double amplitude = 1.0, double phase = 0.0, int delay = 0) { double step = frequency/samplingRate*amplitude; phase = Euclid.Modulus(phase - delay*step, amplitude); int k = 0; while (true) { var x = phase + (k++)*step; if (x >= amplitude) { x %= amplitude; phase = x; k = 1; } yield return map(x); } } /// /// Create a Sine wave. /// /// The number of samples to generate. /// Samples per time unit (Hz). Must be larger than twice the frequency to satisfy the Nyquist criterion. /// Frequency in periods per time unit (Hz). /// The maximal reached peak. /// The mean, or DC part, of the signal. /// Optional phase offset. /// Optional delay, relative to the phase. public static double[] Sinusoidal(int length, double samplingRate, double frequency, double amplitude, double mean = 0.0, double phase = 0.0, int delay = 0) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } double step = frequency/samplingRate*Constants.Pi2; phase = (phase - delay*step)%Constants.Pi2; var data = new double[length]; for (int i = 0; i < data.Length; i++) { data[i] = mean + amplitude*Math.Sin(phase + i*step); } return data; } /// /// Create an infinite Sine wave sequence. /// /// Samples per unit. /// Frequency in samples per unit. /// The maximal reached peak. /// The mean, or DC part, of the signal. /// Optional phase offset. /// Optional delay, relative to the phase. public static IEnumerable SinusoidalSequence(double samplingRate, double frequency, double amplitude, double mean = 0.0, double phase = 0.0, int delay = 0) { double step = frequency/samplingRate*Constants.Pi2; phase = (phase - delay*step)%Constants.Pi2; while (true) { for (int i = 0; i < 1000; i++) { yield return mean + amplitude*Math.Sin(phase + i*step); } phase = (phase + 1000*step)%Constants.Pi2; } } /// /// Create a periodic square wave, starting with the high phase. /// /// The number of samples to generate. /// Number of samples of the high phase. /// Number of samples of the low phase. /// Sample value to be emitted during the low phase. /// Sample value to be emitted during the high phase. /// Optional delay. public static double[] Square(int length, int highDuration, int lowDuration, double lowValue, double highValue, int delay = 0) { var duration = highDuration + lowDuration; return PeriodicMap(length, x => x < highDuration ? highValue : lowValue, 1.0, 1.0/duration, duration, 0.0, delay); } /// /// Create an infinite periodic square wave sequence, starting with the high phase. /// /// Number of samples of the high phase. /// Number of samples of the low phase. /// Sample value to be emitted during the low phase. /// Sample value to be emitted during the high phase. /// Optional delay. public static IEnumerable SquareSequence(int highDuration, int lowDuration, double lowValue, double highValue, int delay = 0) { var duration = highDuration + lowDuration; return PeriodicMapSequence(x => x < highDuration ? highValue : lowValue, 1.0, 1.0/duration, duration, 0.0, delay); } /// /// Create a periodic triangle wave, starting with the raise phase from the lowest sample. /// /// The number of samples to generate. /// Number of samples of the raise phase. /// Number of samples of the fall phase. /// Lowest sample value. /// Highest sample value. /// Optional delay. public static double[] Triangle(int length, int raiseDuration, int fallDuration, double lowValue, double highValue, int delay = 0) { var duration = raiseDuration + fallDuration; var height = highValue - lowValue; var raise = height / raiseDuration; var fall = height / fallDuration; return PeriodicMap(length, x => x < raiseDuration ? lowValue + x*raise : highValue - (x-raiseDuration)*fall, 1.0, 1.0/duration, duration, 0.0, delay); } /// /// Create an infinite periodic triangle wave sequence, starting with the raise phase from the lowest sample. /// /// Number of samples of the raise phase. /// Number of samples of the fall phase. /// Lowest sample value. /// Highest sample value. /// Optional delay. public static IEnumerable TriangleSequence(int raiseDuration, int fallDuration, double lowValue, double highValue, int delay = 0) { var duration = raiseDuration + fallDuration; var height = highValue - lowValue; var raise = height / raiseDuration; var fall = height / fallDuration; return PeriodicMapSequence(x => x < raiseDuration ? lowValue + x*raise : highValue - (x-raiseDuration)*fall, 1.0, 1.0/duration, duration, 0.0, delay); } /// /// Create a periodic sawtooth wave, starting with the lowest sample. /// /// The number of samples to generate. /// Number of samples a full sawtooth period. /// Lowest sample value. /// Highest sample value. /// Optional delay. public static double[] Sawtooth(int length, int period, double lowValue, double highValue, int delay = 0) { var height = highValue - lowValue; return PeriodicMap(length, x => x + lowValue, 1.0, 1.0/period, height*period/(period-1), 0.0, delay); } /// /// Create an infinite periodic sawtooth wave sequence, starting with the lowest sample. /// /// Number of samples a full sawtooth period. /// Lowest sample value. /// Highest sample value. /// Optional delay. public static IEnumerable SawtoothSequence(int period, double lowValue, double highValue, int delay = 0) { var height = highValue - lowValue; return PeriodicMapSequence(x => x + lowValue, 1.0, 1.0/period, height*period/(period-1), 0.0, delay); } /// /// Create an array with each field set to the same value. /// /// The number of samples to generate. /// The value that each field should be set to. public static T[] Repeat(int length, T value) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } var data = new T[length]; CommonParallel.For(0, data.Length, 4096, (a, b) => { for (int i = a; i < b; i++) { data[i] = value; } }); return data; } /// /// Create an infinite sequence where each element has the same value. /// /// The value that each element should be set to. public static IEnumerable RepeatSequence(T value) { while (true) { yield return value; } } /// /// Create a Heaviside Step sample vector. /// /// The number of samples to generate. /// The maximal reached peak. /// Offset to the time axis. public static double[] Step(int length, double amplitude, int delay) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } var data = new double[length]; for (int i = Math.Max(0, delay); i < data.Length; i++) { data[i] = amplitude; } return data; } /// /// Create an infinite Heaviside Step sample sequence. /// /// The maximal reached peak. /// Offset to the time axis. public static IEnumerable StepSequence(double amplitude, int delay) { for (int i = 0; i < delay; i++) { yield return 0d; } while (true) { yield return amplitude; } } /// /// Create a Kronecker Delta impulse sample vector. /// /// The number of samples to generate. /// The maximal reached peak. /// Offset to the time axis. Zero or positive. public static double[] Impulse(int length, double amplitude, int delay) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } var data = new double[length]; if (delay >= 0 && delay < length) { data[delay] = amplitude; } return data; } /// /// Create a Kronecker Delta impulse sample vector. /// /// The maximal reached peak. /// Offset to the time axis, hence the sample index of the impulse. public static IEnumerable ImpulseSequence(double amplitude, int delay) { if (delay >= 0) { for (int i = 0; i < delay; i++) { yield return 0d; } yield return amplitude; } while (true) { yield return 0d; } } /// /// Create a periodic Kronecker Delta impulse sample vector. /// /// The number of samples to generate. /// impulse sequence period. /// The maximal reached peak. /// Offset to the time axis. Zero or positive. public static double[] PeriodicImpulse(int length, int period, double amplitude, int delay) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } var data = new double[length]; delay = Euclid.Modulus(delay, period); while (delay < length) { data[delay] = amplitude; delay += period; } return data; } /// /// Create a Kronecker Delta impulse sample vector. /// /// impulse sequence period. /// The maximal reached peak. /// Offset to the time axis. Zero or positive. public static IEnumerable PeriodicImpulseSequence(int period, double amplitude, int delay) { delay = Euclid.Modulus(delay, period); for (int i = 0; i < delay; i++) { yield return 0d; } while (true) { yield return amplitude; for (int i = 1; i < period; i++) { yield return 0d; } } } /// /// Generate samples generated by the given computation. /// public static T[] Unfold(int length, Func> f, TState state) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } var data = new T[length]; for (int i = 0; i < data.Length; i++) { Tuple next = f(state); data[i] = next.Item1; state = next.Item2; } return data; } /// /// Generate an infinite sequence generated by the given computation. /// public static IEnumerable UnfoldSequence(Func> f, TState state) { while (true) { Tuple next = f(state); state = next.Item2; yield return next.Item1; } } /// /// Generate a Fibonacci sequence, including zero as first value. /// public static BigInteger[] Fibonacci(int length) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } var data = new BigInteger[length]; if (data.Length > 0) { data[0] = BigInteger.Zero; } if (data.Length > 1) { data[1] = BigInteger.One; } for (int i = 2; i < data.Length; i++) { data[i] = data[i - 1] + data[i - 2]; } return data; } /// /// Generate an infinite Fibonacci sequence, including zero as first value. /// public static IEnumerable FibonacciSequence() { BigInteger a = BigInteger.Zero; yield return a; BigInteger b = BigInteger.One; yield return b; while (true) { a = a + b; yield return a; b = a + b; yield return b; } } /// /// Create random samples, uniform between 0 and 1. /// Faster than other methods but with reduced guarantees on randomness. /// public static double[] Uniform(int length) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } return SystemRandomSource.FastDoubles(length); } /// /// Create an infinite random sample sequence, uniform between 0 and 1. /// Faster than other methods but with reduced guarantees on randomness. /// public static IEnumerable UniformSequence() { return SystemRandomSource.DoubleSequence(); } /// /// 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. /// public static T[] UniformMap(int length, Func map) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } var samples = SystemRandomSource.FastDoubles(length); return Map(samples, map); } /// /// 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. /// public static IEnumerable UniformMapSequence(Func map) { return SystemRandomSource.DoubleSequence().Select(map); } /// /// 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. /// public static T[] UniformMap2(int length, Func map) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } var samples1 = SystemRandomSource.FastDoubles(length); var samples2 = SystemRandomSource.FastDoubles(length); return Map2(samples1, samples2, map); } /// /// 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. /// public static IEnumerable UniformMap2Sequence(Func 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()); } } /// /// Create samples with independent amplitudes of standard distribution. /// public static double[] Standard(int length) { return Normal(length, 0.0, 1.0); } /// /// Create an infinite sample sequence with independent amplitudes of standard distribution. /// public static IEnumerable StandardSequence() { return NormalSequence(0.0, 1.0); } /// /// Create samples with independent amplitudes of normal distribution and a flat spectral density. /// public static double[] Normal(int length, double mean, double standardDeviation) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } var samples = new double[length]; Distributions.Normal.Samples(SystemRandomSource.Default, samples, mean, standardDeviation); return samples; } /// /// Create an infinite sample sequence with independent amplitudes of normal distribution and a flat spectral density. /// public static IEnumerable NormalSequence(double mean, double standardDeviation) { return Distributions.Normal.Samples(SystemRandomSource.Default, mean, standardDeviation); } /// /// Create random samples. /// public static double[] Random(int length, IContinuousDistribution distribution) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } var samples = new double[length]; distribution.Samples(samples); return samples; } /// /// Create an infinite random sample sequence. /// public static IEnumerable Random(IContinuousDistribution distribution) { return distribution.Samples(); } /// /// Create random samples. /// public static float[] RandomSingle(int length, IContinuousDistribution distribution) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } var samples = new double[length]; distribution.Samples(samples); return Map(samples, v => (float)v); } /// /// Create an infinite random sample sequence. /// public static IEnumerable RandomSingle(IContinuousDistribution distribution) { return distribution.Samples().Select(v => (float)v); } /// /// Create random samples. /// public static Complex[] RandomComplex(int length, IContinuousDistribution distribution) { return RandomMap2(length, distribution, (r, i) => new Complex(r, i)); } /// /// Create an infinite random sample sequence. /// public static IEnumerable RandomComplex(IContinuousDistribution distribution) { return RandomMap2Sequence(distribution, (r, i) => new Complex(r, i)); } /// /// Create random samples. /// public static Complex32[] RandomComplex32(int length, IContinuousDistribution distribution) { return RandomMap2(length, distribution, (r, i) => new Complex32((float)r, (float)i)); } /// /// Create an infinite random sample sequence. /// public static IEnumerable RandomComplex32(IContinuousDistribution distribution) { return RandomMap2Sequence(distribution, (r, i) => new Complex32((float)r, (float)i)); } /// /// Generate samples by sampling a function at samples from a probability distribution. /// public static T[] RandomMap(int length, IContinuousDistribution distribution, Func map) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } var samples = new double[length]; distribution.Samples(samples); return Map(samples, map); } /// /// Generate a sample sequence by sampling a function at samples from a probability distribution. /// public static IEnumerable RandomMapSequence(IContinuousDistribution distribution, Func map) { return distribution.Samples().Select(map); } /// /// Generate samples by sampling a function at sample pairs from a probability distribution. /// public static T[] RandomMap2(int length, IContinuousDistribution distribution, Func map) { if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } var samples1 = new double[length]; var samples2 = new double[length]; distribution.Samples(samples1); distribution.Samples(samples2); return Map2(samples1, samples2, map); } /// /// Generate a sample sequence by sampling a function at sample pairs from a probability distribution. /// public static IEnumerable RandomMap2Sequence(IContinuousDistribution distribution, Func map) { return distribution.Samples().Zip(distribution.Samples(), map); } } }