From de9e8d101d9a73eb5f809a556c7bcb9eee8b54ed Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Fri, 28 Oct 2016 11:01:39 +0200 Subject: [PATCH] FFT: real-complex, packed --- src/Numerics/IntegralTransforms/Fourier.cs | 112 ++++++++++++++---- src/Numerics/Properties/Resources.Designer.cs | 2 +- src/Numerics/Properties/Resources.resx | 2 +- .../IFourierTransformProvider.cs | 12 +- .../ManagedFourierTransformProvider.cs | 34 +++--- .../Mkl/MklFourierTransformProvider.cs | 66 ++++++----- .../MatchingNaiveTransformTest.cs | 15 ++- .../FourierTransformProviderTests.cs | 4 +- 8 files changed, 160 insertions(+), 87 deletions(-) diff --git a/src/Numerics/IntegralTransforms/Fourier.cs b/src/Numerics/IntegralTransforms/Fourier.cs index 5e7f383f..2364f9ba 100644 --- a/src/Numerics/IntegralTransforms/Fourier.cs +++ b/src/Numerics/IntegralTransforms/Fourier.cs @@ -50,7 +50,7 @@ namespace MathNet.Numerics.IntegralTransforms /// Sample vector, where the FFT is evaluated in place. public static void Forward(Complex[] samples) { - Control.FourierTransformProvider.ForwardInplace(samples, FourierTransformScaling.SymmetricScaling); + Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.SymmetricScaling); } /// @@ -64,17 +64,17 @@ namespace MathNet.Numerics.IntegralTransforms { case FourierOptions.NoScaling: case FourierOptions.AsymmetricScaling: - Control.FourierTransformProvider.ForwardInplace(samples, FourierTransformScaling.NoScaling); + Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.NoScaling); break; case FourierOptions.InverseExponent: - Control.FourierTransformProvider.BackwardInplace(samples, FourierTransformScaling.SymmetricScaling); + Control.FourierTransformProvider.Backward(samples, FourierTransformScaling.SymmetricScaling); break; case FourierOptions.InverseExponent | FourierOptions.NoScaling: case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling: - Control.FourierTransformProvider.BackwardInplace(samples, FourierTransformScaling.NoScaling); + Control.FourierTransformProvider.Backward(samples, FourierTransformScaling.NoScaling); break; default: - Control.FourierTransformProvider.ForwardInplace(samples, FourierTransformScaling.SymmetricScaling); + Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.SymmetricScaling); break; } } @@ -110,14 +110,38 @@ namespace MathNet.Numerics.IntegralTransforms } } - public static void ForwardReal(double[] samples, FourierOptions options = FourierOptions.Default) + /// + /// Packed Real-Complex forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors. + /// Since for real-valued time samples the complex spectrum is conjugate-even (symmetry), + /// the spectrum can be fully reconstructed form the positive frequencies only (first half). + /// The data array needs to be N+2 (if N is even) or N+1 (if N is odd) long in order to support such a packed spectrum. + /// + /// Data array of length N+2 (if N is even) or N+1 (if N is odd). + /// The number of samples. + /// Fourier Transform Convention Options. + public static void ForwardReal(double[] data, int n, FourierOptions options = FourierOptions.Default) { - if (real.Length != imaginary.Length) + int length = n.IsEven() ? n + 2 : n + 1; + if (data.Length < length) { - throw new ArgumentException(Resources.ArgumentArraysSameLength); + throw new ArgumentException(string.Format(Resources.ArrayTooSmall, length)); } - int length = real.Length/2; + if ((options & FourierOptions.InverseExponent) == FourierOptions.InverseExponent) + { + throw new NotSupportedException(); + } + + switch (options) + { + case FourierOptions.NoScaling: + case FourierOptions.AsymmetricScaling: + Control.FourierTransformProvider.ForwardReal(data, n, FourierTransformScaling.NoScaling); + break; + default: + Control.FourierTransformProvider.ForwardReal(data, n, FourierTransformScaling.SymmetricScaling); + break; + } } /// @@ -135,17 +159,17 @@ namespace MathNet.Numerics.IntegralTransforms { case FourierOptions.NoScaling: case FourierOptions.AsymmetricScaling: - Control.FourierTransformProvider.ForwardInplaceMultidim(samples, dimensions, FourierTransformScaling.NoScaling); + Control.FourierTransformProvider.ForwardMultidim(samples, dimensions, FourierTransformScaling.NoScaling); break; case FourierOptions.InverseExponent: - Control.FourierTransformProvider.BackwardInplaceMultidim(samples, dimensions, FourierTransformScaling.SymmetricScaling); + Control.FourierTransformProvider.BackwardMultidim(samples, dimensions, FourierTransformScaling.SymmetricScaling); break; case FourierOptions.InverseExponent | FourierOptions.NoScaling: case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling: - Control.FourierTransformProvider.BackwardInplaceMultidim(samples, dimensions, FourierTransformScaling.NoScaling); + Control.FourierTransformProvider.BackwardMultidim(samples, dimensions, FourierTransformScaling.NoScaling); break; default: - Control.FourierTransformProvider.ForwardInplaceMultidim(samples, dimensions, FourierTransformScaling.SymmetricScaling); + Control.FourierTransformProvider.ForwardMultidim(samples, dimensions, FourierTransformScaling.SymmetricScaling); break; } } @@ -191,7 +215,7 @@ namespace MathNet.Numerics.IntegralTransforms /// Spectrum data, where the iFFT is evaluated in place. public static void Inverse(Complex[] spectrum) { - Control.FourierTransformProvider.BackwardInplace(spectrum, FourierTransformScaling.SymmetricScaling); + Control.FourierTransformProvider.Backward(spectrum, FourierTransformScaling.SymmetricScaling); } /// @@ -204,22 +228,22 @@ namespace MathNet.Numerics.IntegralTransforms switch (options) { case FourierOptions.NoScaling: - Control.FourierTransformProvider.BackwardInplace(spectrum, FourierTransformScaling.NoScaling); + Control.FourierTransformProvider.Backward(spectrum, FourierTransformScaling.NoScaling); break; case FourierOptions.AsymmetricScaling: - Control.FourierTransformProvider.BackwardInplace(spectrum, FourierTransformScaling.BackwardScaling); + Control.FourierTransformProvider.Backward(spectrum, FourierTransformScaling.BackwardScaling); break; case FourierOptions.InverseExponent: - Control.FourierTransformProvider.ForwardInplace(spectrum, FourierTransformScaling.SymmetricScaling); + Control.FourierTransformProvider.Forward(spectrum, FourierTransformScaling.SymmetricScaling); break; case FourierOptions.InverseExponent | FourierOptions.NoScaling: - Control.FourierTransformProvider.ForwardInplace(spectrum, FourierTransformScaling.NoScaling); + Control.FourierTransformProvider.Forward(spectrum, FourierTransformScaling.NoScaling); break; case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling: - Control.FourierTransformProvider.ForwardInplace(spectrum, FourierTransformScaling.ForwardScaling); + Control.FourierTransformProvider.Forward(spectrum, FourierTransformScaling.ForwardScaling); break; default: - Control.FourierTransformProvider.BackwardInplace(spectrum, FourierTransformScaling.SymmetricScaling); + Control.FourierTransformProvider.Backward(spectrum, FourierTransformScaling.SymmetricScaling); break; } } @@ -255,6 +279,42 @@ namespace MathNet.Numerics.IntegralTransforms } } + /// + /// Packed Real-Complex inverse Fast Fourier Transform (iFFT) to arbitrary-length sample vectors. + /// Since for real-valued time samples the complex spectrum is conjugate-even (symmetry), + /// the spectrum can be fully reconstructed form the positive frequencies only (first half). + /// The data array needs to be N+2 (if N is even) or N+1 (if N is odd) long in order to support such a packed spectrum. + /// + /// Data array of length N+2 (if N is even) or N+1 (if N is odd). + /// The number of samples. + /// Fourier Transform Convention Options. + public static void InverseReal(double[] data, int n, FourierOptions options = FourierOptions.Default) + { + int length = n.IsEven() ? n + 2 : n + 1; + if (data.Length < length) + { + throw new ArgumentException(string.Format(Resources.ArrayTooSmall, length)); + } + + if ((options & FourierOptions.InverseExponent) == FourierOptions.InverseExponent) + { + throw new NotSupportedException(); + } + + switch (options) + { + case FourierOptions.NoScaling: + Control.FourierTransformProvider.BackwardReal(data, n, FourierTransformScaling.NoScaling); + break; + case FourierOptions.AsymmetricScaling: + Control.FourierTransformProvider.BackwardReal(data, n, FourierTransformScaling.BackwardScaling); + break; + default: + Control.FourierTransformProvider.BackwardReal(data, n, FourierTransformScaling.SymmetricScaling); + break; + } + } + /// /// Applies the inverse Fast Fourier Transform (iFFT) to multiple dimensional sample data. /// @@ -269,22 +329,22 @@ namespace MathNet.Numerics.IntegralTransforms switch (options) { case FourierOptions.NoScaling: - Control.FourierTransformProvider.BackwardInplaceMultidim(spectrum, dimensions, FourierTransformScaling.NoScaling); + Control.FourierTransformProvider.BackwardMultidim(spectrum, dimensions, FourierTransformScaling.NoScaling); break; case FourierOptions.AsymmetricScaling: - Control.FourierTransformProvider.BackwardInplaceMultidim(spectrum, dimensions, FourierTransformScaling.BackwardScaling); + Control.FourierTransformProvider.BackwardMultidim(spectrum, dimensions, FourierTransformScaling.BackwardScaling); break; case FourierOptions.InverseExponent: - Control.FourierTransformProvider.ForwardInplaceMultidim(spectrum, dimensions, FourierTransformScaling.SymmetricScaling); + Control.FourierTransformProvider.ForwardMultidim(spectrum, dimensions, FourierTransformScaling.SymmetricScaling); break; case FourierOptions.InverseExponent | FourierOptions.NoScaling: - Control.FourierTransformProvider.ForwardInplaceMultidim(spectrum, dimensions, FourierTransformScaling.NoScaling); + Control.FourierTransformProvider.ForwardMultidim(spectrum, dimensions, FourierTransformScaling.NoScaling); break; case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling: - Control.FourierTransformProvider.ForwardInplaceMultidim(spectrum, dimensions, FourierTransformScaling.ForwardScaling); + Control.FourierTransformProvider.ForwardMultidim(spectrum, dimensions, FourierTransformScaling.ForwardScaling); break; default: - Control.FourierTransformProvider.BackwardInplaceMultidim(spectrum, dimensions, FourierTransformScaling.SymmetricScaling); + Control.FourierTransformProvider.BackwardMultidim(spectrum, dimensions, FourierTransformScaling.SymmetricScaling); break; } } diff --git a/src/Numerics/Properties/Resources.Designer.cs b/src/Numerics/Properties/Resources.Designer.cs index ca56ef13..d35d15d6 100644 --- a/src/Numerics/Properties/Resources.Designer.cs +++ b/src/Numerics/Properties/Resources.Designer.cs @@ -90,7 +90,7 @@ namespace MathNet.Numerics.Properties { } /// - /// Looks up a localized string similar to The given array is the wrong length. Should be {0}.. + /// Looks up a localized string similar to The given array has the wrong length. Should be {0}.. /// public static string ArgumentArrayWrongLength { get { diff --git a/src/Numerics/Properties/Resources.resx b/src/Numerics/Properties/Resources.resx index 13cc7a6e..fe831bfe 100644 --- a/src/Numerics/Properties/Resources.resx +++ b/src/Numerics/Properties/Resources.resx @@ -370,7 +370,7 @@ The given array is too small. It must be at least {0} long. - The given array is the wrong length. Should be {0}. + The given array has the wrong length. Should be {0}. The number of rows must greater than or equal to the number of columns. diff --git a/src/Numerics/Providers/FourierTransform/IFourierTransformProvider.cs b/src/Numerics/Providers/FourierTransform/IFourierTransformProvider.cs index 1e3e5187..4809a664 100644 --- a/src/Numerics/Providers/FourierTransform/IFourierTransformProvider.cs +++ b/src/Numerics/Providers/FourierTransform/IFourierTransformProvider.cs @@ -55,13 +55,13 @@ namespace MathNet.Numerics.Providers.FourierTransform /// void InitializeVerify(); - void ForwardInplace(Complex[] complex, FourierTransformScaling scaling); - void BackwardInplace(Complex[] complex, FourierTransformScaling scaling); + void Forward(Complex[] samples, FourierTransformScaling scaling); + void Backward(Complex[] spectrum, FourierTransformScaling scaling); - Complex[] Forward(Complex[] complexTimeSpace, FourierTransformScaling scaling); - Complex[] Backward(Complex[] complexFrequenceSpace, FourierTransformScaling scaling); + void ForwardReal(double[] samples, int n, FourierTransformScaling scaling); + void BackwardReal(double[] spectrum, int n, FourierTransformScaling scaling); - void ForwardInplaceMultidim(Complex[] complex, int[] dimensions, FourierTransformScaling scaling); - void BackwardInplaceMultidim(Complex[] complex, int[] dimensions, FourierTransformScaling scaling); + void ForwardMultidim(Complex[] samples, int[] dimensions, FourierTransformScaling scaling); + void BackwardMultidim(Complex[] spectrum, int[] dimensions, FourierTransformScaling scaling); } } diff --git a/src/Numerics/Providers/FourierTransform/ManagedFourierTransformProvider.cs b/src/Numerics/Providers/FourierTransform/ManagedFourierTransformProvider.cs index ce3f69dc..13cc5799 100644 --- a/src/Numerics/Providers/FourierTransform/ManagedFourierTransformProvider.cs +++ b/src/Numerics/Providers/FourierTransform/ManagedFourierTransformProvider.cs @@ -58,61 +58,55 @@ namespace MathNet.Numerics.Providers.FourierTransform return "Managed"; } - public void ForwardInplace(Complex[] complex, FourierTransformScaling scaling) + public void Forward(Complex[] samples, FourierTransformScaling scaling) { switch (scaling) { case FourierTransformScaling.SymmetricScaling: - Fourier.BluesteinForward(complex, FourierOptions.Default); + Fourier.BluesteinForward(samples, FourierOptions.Default); break; case FourierTransformScaling.ForwardScaling: // Only backward scaling can be expressed with options, hence the double-inverse - Fourier.BluesteinInverse(complex, FourierOptions.AsymmetricScaling | FourierOptions.InverseExponent); + Fourier.BluesteinInverse(samples, FourierOptions.AsymmetricScaling | FourierOptions.InverseExponent); break; default: - Fourier.BluesteinForward(complex, FourierOptions.NoScaling); + Fourier.BluesteinForward(samples, FourierOptions.NoScaling); break; } } - public void BackwardInplace(Complex[] complex, FourierTransformScaling scaling) + public void Backward(Complex[] spectrum, FourierTransformScaling scaling) { switch (scaling) { case FourierTransformScaling.SymmetricScaling: - Fourier.BluesteinInverse(complex, FourierOptions.Default); + Fourier.BluesteinInverse(spectrum, FourierOptions.Default); break; case FourierTransformScaling.BackwardScaling: - Fourier.BluesteinInverse(complex, FourierOptions.AsymmetricScaling); + Fourier.BluesteinInverse(spectrum, FourierOptions.AsymmetricScaling); break; default: - Fourier.BluesteinInverse(complex, FourierOptions.NoScaling); + Fourier.BluesteinInverse(spectrum, FourierOptions.NoScaling); break; } } - public Complex[] Forward(Complex[] complexTimeSpace, FourierTransformScaling scaling) + public void ForwardReal(double[] samples, int n, FourierTransformScaling scaling) { - Complex[] work = new Complex[complexTimeSpace.Length]; - complexTimeSpace.Copy(work); - ForwardInplace(work, scaling); - return work; + throw new NotImplementedException(); } - public Complex[] Backward(Complex[] complexFrequenceSpace, FourierTransformScaling scaling) + public void BackwardReal(double[] spectrum, int n, FourierTransformScaling scaling) { - Complex[] work = new Complex[complexFrequenceSpace.Length]; - complexFrequenceSpace.Copy(work); - BackwardInplace(work, scaling); - return work; + throw new NotImplementedException(); } - public void ForwardInplaceMultidim(Complex[] complex, int[] dimensions, FourierTransformScaling scaling) + public void ForwardMultidim(Complex[] samples, int[] dimensions, FourierTransformScaling scaling) { throw new NotImplementedException(); } - public void BackwardInplaceMultidim(Complex[] complex, int[] dimensions, FourierTransformScaling scaling) + public void BackwardMultidim(Complex[] spectrum, int[] dimensions, FourierTransformScaling scaling) { throw new NotImplementedException(); } diff --git a/src/Numerics/Providers/FourierTransform/Mkl/MklFourierTransformProvider.cs b/src/Numerics/Providers/FourierTransform/Mkl/MklFourierTransformProvider.cs index 01fe4844..60d0e285 100644 --- a/src/Numerics/Providers/FourierTransform/Mkl/MklFourierTransformProvider.cs +++ b/src/Numerics/Providers/FourierTransform/Mkl/MklFourierTransformProvider.cs @@ -42,6 +42,7 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl public IntPtr Handle; public int[] Dimensions; public FourierTransformScaling Scaling; + public bool Real; } Kernel _kernel; @@ -142,7 +143,7 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl return MklProvider.Describe(); } - Kernel Configure(int length, FourierTransformScaling scaling) + Kernel Configure(int length, FourierTransformScaling scaling, bool real) { Kernel kernel = Interlocked.Exchange(ref _kernel, null); @@ -151,20 +152,26 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl kernel = new Kernel { Dimensions = new[] {length}, - Scaling = scaling + Scaling = scaling, + Real = real }; - SafeNativeMethods.z_fft_create(out kernel.Handle, length, ForwardScaling(scaling, length), BackwardScaling(scaling, length)); + if (real) SafeNativeMethods.d_fft_create(out kernel.Handle, length, ForwardScaling(scaling, length), BackwardScaling(scaling, length)); + else SafeNativeMethods.z_fft_create(out kernel.Handle, length, ForwardScaling(scaling, length), BackwardScaling(scaling, length)); return kernel; } - if (kernel.Dimensions.Length != 1 || kernel.Dimensions[0] != length || kernel.Scaling != scaling) + if (kernel.Dimensions.Length != 1 || kernel.Dimensions[0] != length || kernel.Scaling != scaling || kernel.Real != real) { SafeNativeMethods.x_fft_free(ref kernel.Handle); - SafeNativeMethods.z_fft_create(out kernel.Handle, length, ForwardScaling(scaling, length), BackwardScaling(scaling, length)); + + if (real) SafeNativeMethods.d_fft_create(out kernel.Handle, length, ForwardScaling(scaling, length), BackwardScaling(scaling, length)); + else SafeNativeMethods.z_fft_create(out kernel.Handle, length, ForwardScaling(scaling, length), BackwardScaling(scaling, length)); + kernel.Dimensions = new[] {length}; kernel.Scaling = scaling; + kernel.Real = real; return kernel; } @@ -175,7 +182,7 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl { if (dimensions.Length == 1) { - return Configure(dimensions[0], scaling); + return Configure(dimensions[0], scaling, false); } Kernel kernel = Interlocked.Exchange(ref _kernel, null); @@ -185,7 +192,8 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl kernel = new Kernel { Dimensions = dimensions, - Scaling = scaling + Scaling = scaling, + Real = false }; long length = 1; @@ -198,7 +206,7 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl return kernel; } - bool mismatch = kernel.Dimensions.Length != dimensions.Length || kernel.Scaling != scaling; + bool mismatch = kernel.Dimensions.Length != dimensions.Length || kernel.Scaling != scaling || kernel.Real != false; if (!mismatch) { for (int i = 0; i < dimensions.Length; i++) @@ -221,8 +229,10 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl SafeNativeMethods.x_fft_free(ref kernel.Handle); SafeNativeMethods.z_fft_create_multidim(out kernel.Handle, dimensions.Length, dimensions, ForwardScaling(scaling, length), BackwardScaling(scaling, length)); + kernel.Dimensions = dimensions; kernel.Scaling = scaling; + kernel.Real = false; return kernel; } @@ -238,47 +248,47 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl } } - public void ForwardInplace(Complex[] complex, FourierTransformScaling scaling) + public void Forward(Complex[] samples, FourierTransformScaling scaling) { - Kernel kernel = Configure(complex.Length, scaling); - SafeNativeMethods.z_fft_forward(kernel.Handle, complex); + Kernel kernel = Configure(samples.Length, scaling, false); + SafeNativeMethods.z_fft_forward(kernel.Handle, samples); Release(kernel); } - public void BackwardInplace(Complex[] complex, FourierTransformScaling scaling) + public void Backward(Complex[] spectrum, FourierTransformScaling scaling) { - Kernel kernel = Configure(complex.Length, scaling); - SafeNativeMethods.z_fft_backward(kernel.Handle, complex); + Kernel kernel = Configure(spectrum.Length, scaling, false); + SafeNativeMethods.z_fft_backward(kernel.Handle, spectrum); Release(kernel); } - public Complex[] Forward(Complex[] complexTimeSpace, FourierTransformScaling scaling) + public void ForwardReal(double[] samples, int n, FourierTransformScaling scaling) { - Complex[] work = new Complex[complexTimeSpace.Length]; - complexTimeSpace.Copy(work); - ForwardInplace(work, scaling); - return work; + Kernel kernel = Configure(n, scaling, true); + SafeNativeMethods.d_fft_forward(kernel.Handle, samples); + Release(kernel); } - public Complex[] Backward(Complex[] complexFrequenceSpace, FourierTransformScaling scaling) + public void BackwardReal(double[] spectrum, int n, FourierTransformScaling scaling) { - Complex[] work = new Complex[complexFrequenceSpace.Length]; - complexFrequenceSpace.Copy(work); - BackwardInplace(work, scaling); - return work; + Kernel kernel = Configure(n, scaling, true); + SafeNativeMethods.d_fft_backward(kernel.Handle, spectrum); + Release(kernel); + + spectrum[n] = 0d; } - public void ForwardInplaceMultidim(Complex[] complex, int[] dimensions, FourierTransformScaling scaling) + public void ForwardMultidim(Complex[] samples, int[] dimensions, FourierTransformScaling scaling) { Kernel kernel = Configure(dimensions, scaling); - SafeNativeMethods.z_fft_forward(kernel.Handle, complex); + SafeNativeMethods.z_fft_forward(kernel.Handle, samples); Release(kernel); } - public void BackwardInplaceMultidim(Complex[] complex, int[] dimensions, FourierTransformScaling scaling) + public void BackwardMultidim(Complex[] spectrum, int[] dimensions, FourierTransformScaling scaling) { Kernel kernel = Configure(dimensions, scaling); - SafeNativeMethods.z_fft_backward(kernel.Handle, complex); + SafeNativeMethods.z_fft_backward(kernel.Handle, spectrum); Release(kernel); } diff --git a/src/UnitTests/IntegralTransformsTests/MatchingNaiveTransformTest.cs b/src/UnitTests/IntegralTransformsTests/MatchingNaiveTransformTest.cs index 85c75e9b..e40185d5 100644 --- a/src/UnitTests/IntegralTransformsTests/MatchingNaiveTransformTest.cs +++ b/src/UnitTests/IntegralTransformsTests/MatchingNaiveTransformTest.cs @@ -187,7 +187,10 @@ namespace MathNet.Numerics.UnitTests.IntegralTransformsTests // 65536 = 2^16 const FourierOptions options = FourierOptions.NoScaling; var samples = Generate.RandomComplex(65536, GetUniform(1)); - var provider = Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.NoScaling); + + var provider = new Complex[samples.Length]; + samples.Copy(provider); + Control.FourierTransformProvider.Forward(provider, FourierTransformScaling.NoScaling); Verify(samples, 10, options, (a, b) => provider, Fourier.Radix2Forward); Verify(samples, 10, options, (a, b) => provider, Fourier.BluesteinForward); @@ -199,7 +202,10 @@ namespace MathNet.Numerics.UnitTests.IntegralTransformsTests // 30870 = 2*3*3*5*7*7*7 const FourierOptions options = FourierOptions.NoScaling; var samples = Generate.RandomComplex(30870, GetUniform(1)); - var provider = Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.NoScaling); + + var provider = new Complex[samples.Length]; + samples.Copy(provider); + Control.FourierTransformProvider.Forward(provider, FourierTransformScaling.NoScaling); Verify(samples, 10, options, (a, b) => provider, Fourier.BluesteinForward); } @@ -209,7 +215,10 @@ namespace MathNet.Numerics.UnitTests.IntegralTransformsTests { const FourierOptions options = FourierOptions.NoScaling; var samples = Generate.RandomComplex(46500, GetUniform(1)); - var provider = Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.NoScaling); + + var provider = new Complex[samples.Length]; + samples.Copy(provider); + Control.FourierTransformProvider.Forward(provider, FourierTransformScaling.NoScaling); Verify(samples, 10, options, (a, b) => provider, Fourier.BluesteinForward); } diff --git a/src/UnitTests/Providers/FourierTransform/FourierTransformProviderTests.cs b/src/UnitTests/Providers/FourierTransform/FourierTransformProviderTests.cs index 3eac8759..58bf1c2e 100644 --- a/src/UnitTests/Providers/FourierTransform/FourierTransformProviderTests.cs +++ b/src/UnitTests/Providers/FourierTransform/FourierTransformProviderTests.cs @@ -55,7 +55,7 @@ namespace MathNet.Numerics.UnitTests.Providers.FourierTransform // real-odd transforms to imaginary odd samples.Copy(spectrum); - Control.FourierTransformProvider.ForwardInplace(spectrum, FourierTransformScaling.BackwardScaling); + Control.FourierTransformProvider.Forward(spectrum, FourierTransformScaling.BackwardScaling); // all real components must be zero foreach (var c in spectrum) @@ -88,7 +88,7 @@ namespace MathNet.Numerics.UnitTests.Providers.FourierTransform var samples = Generate.RandomComplex(count, GetUniform(1)); var timeSpaceEnergy = Generate.Map(samples, s => s.MagnitudeSquared()).Mean(); - Control.FourierTransformProvider.ForwardInplace(samples, FourierTransformScaling.SymmetricScaling); + Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.SymmetricScaling); var frequencySpaceEnergy = Generate.Map(samples, s => s.MagnitudeSquared()).Mean(); Assert.AreEqual(timeSpaceEnergy, frequencySpaceEnergy, 1e-12);