From 44ea89a983505f58caff0370300b34619523a489 Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Sat, 21 Mar 2015 21:01:44 +0100 Subject: [PATCH] Generate: Unfold, Fibonacci --- src/Numerics/Generate.cs | 86 ++++++++++++++++++++++++++++++++++ src/UnitTests/GenerateTests.cs | 29 ++++++++++++ 2 files changed, 115 insertions(+) diff --git a/src/Numerics/Generate.cs b/src/Numerics/Generate.cs index bf5b04c7..3520913e 100644 --- a/src/Numerics/Generate.cs +++ b/src/Numerics/Generate.cs @@ -717,6 +717,90 @@ namespace MathNet.Numerics } } + /// + /// Generate samples generated by the given computation. + /// + public static T[] Unfold(int length, Func> f, TState state) + { + if (length < 0) + { + throw new ArgumentOutOfRangeException("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; + } + } + +#if !NOSYSNUMERICS + + /// + /// Generate a Fibonacci sequence, including zero as first value. + /// + public static BigInteger[] Fibonacci(int length) + { + if (length < 0) + { + throw new ArgumentOutOfRangeException("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; + } + } + +#endif + /// /// Create random samples, uniform between 0 and 1. /// Faster than other methods but with reduced guarantees on randomness. @@ -1016,5 +1100,7 @@ namespace MathNet.Numerics { return distribution.Samples().Zip(distribution.Samples(), map); } + + } } diff --git a/src/UnitTests/GenerateTests.cs b/src/UnitTests/GenerateTests.cs index 522a43ef..432075b7 100644 --- a/src/UnitTests/GenerateTests.cs +++ b/src/UnitTests/GenerateTests.cs @@ -30,6 +30,7 @@ using System; using System.Linq; +using System.Numerics; using NUnit.Framework; namespace MathNet.Numerics.UnitTests @@ -217,5 +218,33 @@ namespace MathNet.Numerics.UnitTests Generate.PeriodicImpulseSequence(100, 5, 40).Take(1000).ToArray(), Is.EqualTo(Generate.PeriodicImpulse(1000, 100, 5, 40)).AsCollection); } + + [Test] + public void UnfoldConsistentWithSequence() + { + Assert.That( + Generate.UnfoldSequence((s => Tuple.Create(s + 1, s + 1)), 0).Take(250).ToArray(), + Is.EqualTo(Generate.Unfold(250, (s => Tuple.Create(s + 1, s + 1)), 0)).AsCollection); + } + + [Test] + public void FibonacciConsistentWithSequence() + { + Assert.That( + Generate.FibonacciSequence().Take(250).ToArray(), + Is.EqualTo(Generate.Fibonacci(250)).AsCollection); + } + + [Test] + public void FibonacciConsistentWithUnfold() + { + Assert.That( + Generate.FibonacciSequence().Take(250).ToArray(), + Is.EqualTo(new[] { BigInteger.Zero, BigInteger.One }.Concat(Generate.Unfold(248, (s => + { + var z = s.Item1 + s.Item2; + return Tuple.Create(z, Tuple.Create(s.Item2, z)); + }), Tuple.Create(BigInteger.Zero, BigInteger.One)))).AsCollection); + } } }