From 19e351b7dac46ebd492e53eecd9c6f56373019be Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Thu, 13 Aug 2009 04:34:52 +0800 Subject: [PATCH] transforms: reorganized unit tests, now full coverage Signed-off-by: Christoph Ruegg --- .../IntegralTransformsTests/DftTest.cs | 290 ------------------ .../IntegralTransformsTests/FourierTest.cs | 96 ++++++ .../{DhtTest.cs => HartleyTest.cs} | 64 ++-- .../InverseTransformTest.cs | 173 +++++++++++ .../MatchingNaiveTransformTest.cs | 164 ++++++++++ .../ParsevalTheoremTest.cs | 82 +++++ .../IntegralTransformsTests/SampleProvider.cs | 73 +++++ src/UnitTests/UnitTests.csproj | 8 +- 8 files changed, 621 insertions(+), 329 deletions(-) delete mode 100644 src/UnitTests/IntegralTransformsTests/DftTest.cs create mode 100644 src/UnitTests/IntegralTransformsTests/FourierTest.cs rename src/UnitTests/IntegralTransformsTests/{DhtTest.cs => HartleyTest.cs} (60%) create mode 100644 src/UnitTests/IntegralTransformsTests/InverseTransformTest.cs create mode 100644 src/UnitTests/IntegralTransformsTests/MatchingNaiveTransformTest.cs create mode 100644 src/UnitTests/IntegralTransformsTests/ParsevalTheoremTest.cs create mode 100644 src/UnitTests/IntegralTransformsTests/SampleProvider.cs diff --git a/src/UnitTests/IntegralTransformsTests/DftTest.cs b/src/UnitTests/IntegralTransformsTests/DftTest.cs deleted file mode 100644 index be55e3e1..00000000 --- a/src/UnitTests/IntegralTransformsTests/DftTest.cs +++ /dev/null @@ -1,290 +0,0 @@ -// -// Math.NET Numerics, part of the Math.NET Project -// http://mathnet.opensourcedotnet.info -// -// Copyright (c) 2009 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. -// - -namespace MathNet.Numerics.UnitTests.IntegralTransformsTests -{ - using System; - using System.Linq; - using MbUnit.Framework; - using IntegralTransforms; - using IntegralTransforms.Algorithms; - using Statistics; - - [TestFixture] - public class DftTest - { - private static readonly Random _random = new Random(); - - private static Complex[] ProvideSamples(int count) - { - var samples = new Complex[count]; - for (int i = 0; i < samples.Length; i++) - { - samples[i] = Complex.WithRealImaginary( - 1 - (2 * _random.NextDouble()), - 1 - (2 * _random.NextDouble())); - } - - return samples; - } - - [Test] - public void NaiveTransformsRealSineCorrectly() - { - var realSine = new Complex[16]; - for (int i = 0; i < realSine.Length; i++) - { - realSine[i] = Math.Sin(i / 8.0 * Constants.Pi); - } - - // real-odd transforms to imaginary odd - var dft = new DiscreteFourierTransform(); - var spectrum = dft.NaiveForward(realSine, FourierOptions.Matlab); - - // all real components must be zero - foreach (var c in spectrum) - { - Assert.AreApproximatelyEqual(0, c.Real, 1e-12, "real"); - } - - // all imaginary components except second and last musth be zero - for(int i = 0; i dft.Radix2Forward(samples, FourierOptions.Default)); - - Assert.Throws( - typeof(ArgumentException), - () => dft.Radix2Inverse(samples, FourierOptions.Default)); - } - - [Test] - public void BluesteinMatchesNaiveOnRealSine() - { - var realSine = new Complex[14]; - for (int i = 0; i < realSine.Length; i++) - { - realSine[i] = Math.Sin(i / 7.0 * Constants.Pi); - } - - // real-odd transforms to imaginary odd - var dft = new DiscreteFourierTransform(); - var spectrumNaive = dft.NaiveForward(realSine, FourierOptions.Matlab); - - var spectrumBluestein = new Complex[realSine.Length]; - realSine.CopyTo(spectrumBluestein, 0); - dft.BluesteinForward(spectrumBluestein, FourierOptions.Matlab); - - AssertHelpers.AlmostEqualList(spectrumNaive, spectrumBluestein, 1e-12); - } - - [Test] - public void BluesteinMatchesNaiveOnRandomPowerOfTwo() - { - var samples = ProvideSamples(0x80); - var work = new Complex[samples.Length]; - samples.CopyTo(work, 0); - - var dft = new DiscreteFourierTransform(); - var spectrumNaive = dft.NaiveForward(samples, FourierOptions.Matlab); - dft.BluesteinForward(work, FourierOptions.Matlab); - - AssertHelpers.AlmostEqualList(spectrumNaive, work, 1e-12); - } - - [Test] - public void BluesteinMatchesNaiveOnRandomNonPowerOfTwo() - { - var samples = ProvideSamples(0x7F); - var work = new Complex[samples.Length]; - samples.CopyTo(work, 0); - - var dft = new DiscreteFourierTransform(); - var spectrumNaive = dft.NaiveForward(samples, FourierOptions.Matlab); - dft.BluesteinForward(work, FourierOptions.Matlab); - - AssertHelpers.AlmostEqualList(spectrumNaive, work, 1e-12); - } - - [Test] - [Row(FourierOptions.Default)] - [Row(FourierOptions.Matlab)] - public void BluesteinIsReversible(FourierOptions options) - { - var samples = ProvideSamples(0x7FFF); - var work = new Complex[samples.Length]; - samples.CopyTo(work, 0); - - var dft = new DiscreteFourierTransform(); - dft.BluesteinForward(work, options); - - Assert.IsFalse(work.AlmostEqualListWithError(samples, 1e-12)); - - dft.BluesteinInverse(work, options); - - AssertHelpers.AlmostEqualList(samples, work, 1e-12); - } - - [Test] - public void DefaultTransformIsReversible() - { - var samples = ProvideSamples(0x7FFF); - var work = new Complex[samples.Length]; - samples.CopyTo(work, 0); - - Transform.FourierForward(work); - - Assert.IsFalse(work.AlmostEqualListWithError(samples, 1e-12)); - - Transform.FourierInverse(work); - - AssertHelpers.AlmostEqualList(samples, work, 1e-12); - - Transform.FourierInverse(work, FourierOptions.Default); - - Assert.IsFalse(work.AlmostEqualListWithError(samples, 1e-12)); - - Transform.FourierForward(work, FourierOptions.Default); - - AssertHelpers.AlmostEqualList(samples, work, 1e-12); - } - - [Test] - public void TransformSatisfiesParsevalsTheorem() - { - var samples = ProvideSamples(0x1000); - - var timeSpaceEnergy = (from s in samples select s.ModulusSquared).Mean(); - - var work = new Complex[samples.Length]; - samples.CopyTo(work, 0); - - // Only symmetric scaling scaling satisfies the theorem, hence FourierOptions.Default. - Transform.FourierForward(work, FourierOptions.Default); - - var frequencySpaceEnergy = (from s in work select s.ModulusSquared).Mean(); - - Assert.AreApproximatelyEqual(timeSpaceEnergy, frequencySpaceEnergy, 1e-12); - } - } -} diff --git a/src/UnitTests/IntegralTransformsTests/FourierTest.cs b/src/UnitTests/IntegralTransformsTests/FourierTest.cs new file mode 100644 index 00000000..bb5221a4 --- /dev/null +++ b/src/UnitTests/IntegralTransformsTests/FourierTest.cs @@ -0,0 +1,96 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// +// Copyright (c) 2009 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. +// + +namespace MathNet.Numerics.UnitTests.IntegralTransformsTests +{ + using System; + using MbUnit.Framework; + using IntegralTransforms; + using IntegralTransforms.Algorithms; + + [TestFixture] + public class FourierTest + { + [Test] + public void NaiveTransformsRealSineCorrectly() + { + var samples = SampleProvider.ProvideComplexRealSine(16); + + // real-odd transforms to imaginary odd + var dft = new DiscreteFourierTransform(); + var spectrum = dft.NaiveForward(samples, FourierOptions.Matlab); + + // all real components must be zero + foreach (var c in spectrum) + { + Assert.AreApproximatelyEqual(0, c.Real, 1e-12, "real"); + } + + // all imaginary components except second and last musth be zero + for(int i = 0; i dft.Radix2Forward(samples, FourierOptions.Default)); + + Assert.Throws( + typeof(ArgumentException), + () => dft.Radix2Inverse(samples, FourierOptions.Default)); + + Assert.Throws( + typeof (ArgumentException), + () => DiscreteFourierTransform.Radix2(samples, -1)); + + Assert.Throws( + typeof(ArgumentException), + () => DiscreteFourierTransform.Radix2Parallel(samples, -1)); + } + } +} diff --git a/src/UnitTests/IntegralTransformsTests/DhtTest.cs b/src/UnitTests/IntegralTransformsTests/HartleyTest.cs similarity index 60% rename from src/UnitTests/IntegralTransformsTests/DhtTest.cs rename to src/UnitTests/IntegralTransformsTests/HartleyTest.cs index 679cc30b..5e250fb4 100644 --- a/src/UnitTests/IntegralTransformsTests/DhtTest.cs +++ b/src/UnitTests/IntegralTransformsTests/HartleyTest.cs @@ -1,4 +1,4 @@ -// +// // Math.NET Numerics, part of the Math.NET Project // http://mathnet.opensourcedotnet.info // @@ -34,19 +34,22 @@ namespace MathNet.Numerics.UnitTests.IntegralTransformsTests using IntegralTransforms.Algorithms; [TestFixture] - public class DhtTest + public class HartleyTest { - private static readonly Random _random = new Random(); - - private static double[] ProvideSamples(int count) + private static void VerifyMatchesDFT( + double[] samples, + double maximumError, + bool inverse, + Action dft, + Func hartley) { - var samples = new double[count]; - for (int i = 0; i < samples.Length; i++) - { - samples[i] = 1 - (2 * _random.NextDouble()); - } + var hartleyReal = hartley(samples); + + var fourierComplex = Array.ConvertAll(samples, s => new Complex(s, inverse ? -s : s)); + dft(fourierComplex); + var fourierReal = Array.ConvertAll(fourierComplex, s => s.Real); - return samples; + AssertHelpers.AlmostEqualList(fourierReal, hartleyReal, maximumError); } [Test] @@ -55,35 +58,22 @@ namespace MathNet.Numerics.UnitTests.IntegralTransformsTests [Row(HartleyOptions.NoScaling, FourierOptions.NoScaling)] public void NaiveMatchesDFT(HartleyOptions hartleyOptions, FourierOptions fourierOptions) { - var samples = ProvideSamples(0x80); - - var dht = new DiscreteHartleyTransform(); - var hartley = dht.NaiveForward(samples, hartleyOptions); - - var fourierComplex = Array.ConvertAll(samples, s => new Complex(s, s)); - Transform.FourierForward(fourierComplex, fourierOptions); - var fourierReal = Array.ConvertAll(fourierComplex, s => s.Real); - - AssertHelpers.AlmostEqualList(fourierReal, hartley, 1e-10); - } - - [Test] - [Row(HartleyOptions.Default)] - [Row(HartleyOptions.AsymmetricScaling)] - public void NaiveIsReversible(HartleyOptions options) - { - var samples = ProvideSamples(0x80); - var work = new double[samples.Length]; - samples.CopyTo(work, 0); - var dht = new DiscreteHartleyTransform(); - work = dht.NaiveForward(work, options); - - Assert.IsFalse(work.AlmostEqualListWithError(samples, 1e-10)); + var samples = SampleProvider.ProvideRealSamples(0x80); - work = dht.NaiveInverse(work, options); + VerifyMatchesDFT( + samples, + 1e-10, + false, + s => Transform.FourierForward(s, fourierOptions), + s => dht.NaiveForward(s, hartleyOptions)); - AssertHelpers.AlmostEqualList(samples, work, 1e-10); + VerifyMatchesDFT( + samples, + 1e-10, + true, + s => Transform.FourierInverse(s, fourierOptions), + s => dht.NaiveInverse(s, hartleyOptions)); } } } diff --git a/src/UnitTests/IntegralTransformsTests/InverseTransformTest.cs b/src/UnitTests/IntegralTransformsTests/InverseTransformTest.cs new file mode 100644 index 00000000..dc663072 --- /dev/null +++ b/src/UnitTests/IntegralTransformsTests/InverseTransformTest.cs @@ -0,0 +1,173 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// +// Copyright (c) 2009 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. +// + +namespace MathNet.Numerics.UnitTests.IntegralTransformsTests +{ + using System; + using IntegralTransforms; + using IntegralTransforms.Algorithms; + using MbUnit.Framework; + + [TestFixture] + public class InverseTransformTest + { + private static void VerifyIsReversibleComplex( + int count, + double maximumError, + Func forward, + Func inverse) + { + var samples = SampleProvider.ProvideComplexSamples(count); + var work = new Complex[samples.Length]; + samples.CopyTo(work, 0); + + work = forward(work); + + Assert.IsFalse(work.AlmostEqualListWithError(samples, maximumError)); + + work = inverse(work); + + AssertHelpers.AlmostEqualList(samples, work, maximumError); + } + + private static void VerifyIsReversibleReal( + int count, + double maximumError, + Func forward, + Func inverse) + { + var samples = SampleProvider.ProvideRealSamples(count); + var work = new double[samples.Length]; + samples.CopyTo(work, 0); + + work = forward(work); + + Assert.IsFalse(work.AlmostEqualListWithError(samples, maximumError)); + + work = inverse(work); + + AssertHelpers.AlmostEqualList(samples, work, maximumError); + } + + [Test] + [Row(FourierOptions.Default)] + [Row(FourierOptions.Matlab)] + public void FourierNaiveIsReversible(FourierOptions options) + { + var dft = new DiscreteFourierTransform(); + + VerifyIsReversibleComplex( + 0x80, + 1e-12, + s => dft.NaiveForward(s, options), + s => dft.NaiveInverse(s, options)); + } + + [Test] + [Row(FourierOptions.Default)] + [Row(FourierOptions.Matlab)] + public void FourierRadix2IsReversible(FourierOptions options) + { + var dft = new DiscreteFourierTransform(); + + VerifyIsReversibleComplex( + 0x8000, + 1e-12, + s => + { + dft.Radix2Forward(s, options); + return s; + }, + s => + { + dft.Radix2Inverse(s, options); + return s; + }); + } + + [Test] + [Row(FourierOptions.Default)] + [Row(FourierOptions.Matlab)] + public void FourierBluesteinIsReversible(FourierOptions options) + { + var dft = new DiscreteFourierTransform(); + + VerifyIsReversibleComplex( + 0x7FFF, + 1e-12, + s => + { + dft.BluesteinForward(s, options); + return s; + }, + s => + { + dft.BluesteinInverse(s, options); + return s; + }); + } + + [Test] + [Row(HartleyOptions.Default)] + [Row(HartleyOptions.AsymmetricScaling)] + public void HartleyNaiveIsReversible(HartleyOptions options) + { + var dht = new DiscreteHartleyTransform(); + + VerifyIsReversibleReal( + 0x80, + 1e-10, + s => dht.NaiveForward(s, options), + s => dht.NaiveInverse(s, options)); + } + + [Test] + public void FourierDefaultTransformIsReversible() + { + var samples = SampleProvider.ProvideComplexSamples(0x7FFF); + var work = new Complex[samples.Length]; + samples.CopyTo(work, 0); + + Transform.FourierForward(work); + + Assert.IsFalse(work.AlmostEqualListWithError(samples, 1e-12)); + + Transform.FourierInverse(work); + + AssertHelpers.AlmostEqualList(samples, work, 1e-12); + + Transform.FourierInverse(work, FourierOptions.Default); + + Assert.IsFalse(work.AlmostEqualListWithError(samples, 1e-12)); + + Transform.FourierForward(work, FourierOptions.Default); + + AssertHelpers.AlmostEqualList(samples, work, 1e-12); + } + } +} diff --git a/src/UnitTests/IntegralTransformsTests/MatchingNaiveTransformTest.cs b/src/UnitTests/IntegralTransformsTests/MatchingNaiveTransformTest.cs new file mode 100644 index 00000000..259a4fc9 --- /dev/null +++ b/src/UnitTests/IntegralTransformsTests/MatchingNaiveTransformTest.cs @@ -0,0 +1,164 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// +// Copyright (c) 2009 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. +// + +namespace MathNet.Numerics.UnitTests.IntegralTransformsTests +{ + using System; + using IntegralTransforms; + using IntegralTransforms.Algorithms; + using MbUnit.Framework; + + [TestFixture] + public class MatchingNaiveTransformTest + { + private static void VerifyMatchesNaiveComplex( + Complex[] samples, + double maximumError, + Func naive, + Action fast) + { + var spectrumNaive = naive(samples); + + var spectrumFast = new Complex[samples.Length]; + samples.CopyTo(spectrumFast, 0); + fast(spectrumFast); + + AssertHelpers.AlmostEqualList(spectrumNaive, spectrumFast, maximumError); + } + + [Test] + [Row(FourierOptions.Default)] + [Row(FourierOptions.Matlab)] + [Row(FourierOptions.NumericalRecipes)] + public void FourierRadix2MatchesNaiveOnRealSine(FourierOptions options) + { + var dft = new DiscreteFourierTransform(); + var samples = SampleProvider.ProvideComplexRealSine(16); + + VerifyMatchesNaiveComplex( + samples, + 1e-12, + s => dft.NaiveForward(s, options), + s => dft.Radix2Forward(s, options)); + + VerifyMatchesNaiveComplex( + samples, + 1e-12, + s => dft.NaiveInverse(s, options), + s => dft.Radix2Inverse(s, options)); + } + + [Test] + [Row(FourierOptions.Default)] + [Row(FourierOptions.Matlab)] + [Row(FourierOptions.NumericalRecipes)] + public void FourierRadix2MatchesNaiveOnRandom(FourierOptions options) + { + var dft = new DiscreteFourierTransform(); + var samples = SampleProvider.ProvideComplexSamples(0x80); + + VerifyMatchesNaiveComplex( + samples, + 1e-12, + s => dft.NaiveForward(s, options), + s => dft.Radix2Forward(s, options)); + + VerifyMatchesNaiveComplex( + samples, + 1e-12, + s => dft.NaiveInverse(s, options), + s => dft.Radix2Inverse(s, options)); + } + + [Test] + [Row(FourierOptions.Default)] + [Row(FourierOptions.Matlab)] + [Row(FourierOptions.NumericalRecipes)] + public void FourierBluesteinMatchesNaiveOnRealSineNonPowerOfTwo(FourierOptions options) + { + var dft = new DiscreteFourierTransform(); + var samples = SampleProvider.ProvideComplexRealSine(14); + + VerifyMatchesNaiveComplex( + samples, + 1e-12, + s => dft.NaiveForward(s, options), + s => dft.BluesteinForward(s, options)); + + VerifyMatchesNaiveComplex( + samples, + 1e-12, + s => dft.NaiveInverse(s, options), + s => dft.BluesteinInverse(s, options)); + } + + [Test] + [Row(FourierOptions.Default)] + [Row(FourierOptions.Matlab)] + [Row(FourierOptions.NumericalRecipes)] + public void FourierBluesteinMatchesNaiveOnRandomPowerOfTwo(FourierOptions options) + { + var dft = new DiscreteFourierTransform(); + var samples = SampleProvider.ProvideComplexSamples(0x80); + + VerifyMatchesNaiveComplex( + samples, + 1e-12, + s => dft.NaiveForward(s, options), + s => dft.BluesteinForward(s, options)); + + VerifyMatchesNaiveComplex( + samples, + 1e-12, + s => dft.NaiveInverse(s, options), + s => dft.BluesteinInverse(s, options)); + } + + [Test] + [Row(FourierOptions.Default)] + [Row(FourierOptions.Matlab)] + [Row(FourierOptions.NumericalRecipes)] + public void FourierBluesteinMatchesNaiveOnRandomNonPowerOfTwo(FourierOptions options) + { + var dft = new DiscreteFourierTransform(); + var samples = SampleProvider.ProvideComplexSamples(0x7F); + + VerifyMatchesNaiveComplex( + samples, + 1e-12, + s => dft.NaiveForward(s, options), + s => dft.BluesteinForward(s, options)); + + VerifyMatchesNaiveComplex( + samples, + 1e-12, + s => dft.NaiveInverse(s, options), + s => dft.BluesteinInverse(s, options)); + } + } +} diff --git a/src/UnitTests/IntegralTransformsTests/ParsevalTheoremTest.cs b/src/UnitTests/IntegralTransformsTests/ParsevalTheoremTest.cs new file mode 100644 index 00000000..40426719 --- /dev/null +++ b/src/UnitTests/IntegralTransformsTests/ParsevalTheoremTest.cs @@ -0,0 +1,82 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// +// Copyright (c) 2009 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 MathNet.Numerics.IntegralTransforms.Algorithms; + +namespace MathNet.Numerics.UnitTests.IntegralTransformsTests +{ + using System.Linq; + using MbUnit.Framework; + using IntegralTransforms; + using Statistics; + + [TestFixture] + public class ParsevalTheoremTest + { + [Test] + [Row(0x1000)] + [Row(0x7FF)] + public void FourierDefaultTransformSatisfiesParsevalsTheorem(int count) + { + var samples = SampleProvider.ProvideComplexSamples(count); + + var timeSpaceEnergy = (from s in samples select s.ModulusSquared).Mean(); + + var work = new Complex[samples.Length]; + samples.CopyTo(work, 0); + + // Default -> Symmetric Scaling + Transform.FourierForward(work); + + var frequencySpaceEnergy = (from s in work select s.ModulusSquared).Mean(); + + Assert.AreApproximatelyEqual(timeSpaceEnergy, frequencySpaceEnergy, 1e-12); + } + + [Test] + [Row(0x40)] + [Row(0x1F)] + public void HartleyDefaultNaiveSatisfiesParsevalsTheorem(int count) + { + var samples = SampleProvider.ProvideRealSamples(count); + + var timeSpaceEnergy = (from s in samples select s * s).Mean(); + + var work = new double[samples.Length]; + samples.CopyTo(work, 0); + + // Default -> Symmetric Scaling + var dht = new DiscreteHartleyTransform(); + work = dht.NaiveForward(work, HartleyOptions.Default); + + var frequencySpaceEnergy = (from s in work select s * s).Mean(); + + Assert.AreApproximatelyEqual(timeSpaceEnergy, frequencySpaceEnergy, 1e-12); + } + } +} diff --git a/src/UnitTests/IntegralTransformsTests/SampleProvider.cs b/src/UnitTests/IntegralTransformsTests/SampleProvider.cs new file mode 100644 index 00000000..e2ee1cc0 --- /dev/null +++ b/src/UnitTests/IntegralTransformsTests/SampleProvider.cs @@ -0,0 +1,73 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// +// Copyright (c) 2009 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. +// + +namespace MathNet.Numerics.UnitTests.IntegralTransformsTests +{ + using System; + + internal static class SampleProvider + { + private static readonly Random _random = new Random(); + + internal static Complex[] ProvideComplexSamples(int count) + { + var samples = new Complex[count]; + for (int i = 0; i < samples.Length; i++) + { + samples[i] = Complex.WithRealImaginary( + 1 - (2 * _random.NextDouble()), + 1 - (2 * _random.NextDouble())); + } + + return samples; + } + + internal static double[] ProvideRealSamples(int count) + { + var samples = new double[count]; + for (int i = 0; i < samples.Length; i++) + { + samples[i] = 1 - (2 * _random.NextDouble()); + } + + return samples; + } + + internal static Complex[] ProvideComplexRealSine(int count) + { + double halfPeriod = count / 2.0; + var samples = new Complex[count]; + for (int i = 0; i < samples.Length; i++) + { + samples[i] = Math.Sin(i * Constants.Pi / halfPeriod); + } + + return samples; + } + } +} diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj index ca45201b..fe292ad0 100644 --- a/src/UnitTests/UnitTests.csproj +++ b/src/UnitTests/UnitTests.csproj @@ -67,8 +67,12 @@ - - + + + + + +