From 215f910a2c9ccab79caecb8e898686be421f74fe Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Wed, 12 Aug 2009 02:07:04 +0800 Subject: [PATCH] transforms: hartley - naive Signed-off-by: Christoph Ruegg --- .../IntegralTransformsTests/DhtTest.cs | 93 ++++++++++++++++++ .../Managed.UnitTests.csproj | 1 + .../DiscreteHartleyTransform.Naive.cs | 94 +++++++++++++++++++ .../DiscreteHartleyTransform.Options.cs | 82 ++++++++++++++++ .../IntegralTransforms/HartleyOptions.cs | 58 ++++++++++++ src/Managed/Managed.csproj | 3 + src/Native.UnitTests/Native.UnitTests.csproj | 3 + src/Native/Native.csproj | 9 ++ 8 files changed, 343 insertions(+) create mode 100644 src/Managed.UnitTests/IntegralTransformsTests/DhtTest.cs create mode 100644 src/Managed/IntegralTransforms/Algorithms/DiscreteHartleyTransform.Naive.cs create mode 100644 src/Managed/IntegralTransforms/Algorithms/DiscreteHartleyTransform.Options.cs create mode 100644 src/Managed/IntegralTransforms/HartleyOptions.cs diff --git a/src/Managed.UnitTests/IntegralTransformsTests/DhtTest.cs b/src/Managed.UnitTests/IntegralTransformsTests/DhtTest.cs new file mode 100644 index 00000000..a0614695 --- /dev/null +++ b/src/Managed.UnitTests/IntegralTransformsTests/DhtTest.cs @@ -0,0 +1,93 @@ +// +// 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 System.Collections.Generic; + +namespace MathNet.Numerics.UnitTests.IntegralTransformsTests +{ + using System; + using System.Linq; + using MbUnit.Framework; + using IntegralTransforms; + using IntegralTransforms.Algorithms; + using Statistics; + + [TestFixture] + public class DhtTest + { + private static Random _random = new Random(); + + private static double[] ProvideSamples(int count) + { + var samples = new double[count]; + for (int i = 0; i < samples.Length; i++) + { + samples[i] = 1 - (2 * _random.NextDouble()); + } + + return samples; + } + + [Test] + [Row(HartleyOptions.Default, FourierOptions.Default)] + [Row(HartleyOptions.AsymmetricScaling, FourierOptions.AsymmetricScaling)] + [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)); + + work = dht.NaiveInverse(work, options); + + AssertHelpers.AlmostEqualList(samples, work, 1e-10); + } + } +} diff --git a/src/Managed.UnitTests/Managed.UnitTests.csproj b/src/Managed.UnitTests/Managed.UnitTests.csproj index 589a731c..7d796f70 100644 --- a/src/Managed.UnitTests/Managed.UnitTests.csproj +++ b/src/Managed.UnitTests/Managed.UnitTests.csproj @@ -67,6 +67,7 @@ + diff --git a/src/Managed/IntegralTransforms/Algorithms/DiscreteHartleyTransform.Naive.cs b/src/Managed/IntegralTransforms/Algorithms/DiscreteHartleyTransform.Naive.cs new file mode 100644 index 00000000..c2e693cd --- /dev/null +++ b/src/Managed/IntegralTransforms/Algorithms/DiscreteHartleyTransform.Naive.cs @@ -0,0 +1,94 @@ +// +// 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.IntegralTransforms.Algorithms +{ + using System; + using Threading; + + /// + /// Fast (FHT) Implementation of the Discrete Hartley Transform (DHT). + /// + public partial class DiscreteHartleyTransform + { + /// + /// Naive generic DHT, useful e.g. to verify faster algorithms. + /// + /// Time-space sample vector. + /// Corresponding frequency-space vector. + internal static double[] Naive(double[] samples) + { + double w0 = 2 * Constants.Pi / samples.Length; + var spectrum = new double[samples.Length]; + + Parallel.For( + 0, + samples.Length, + k => + { + double wk = w0 * k; + double sum = 0.0; + for (int n = 0; n < samples.Length; n++) + { + double w = n * wk; + sum += samples[n] * Constants.Sqrt2 * Math.Cos(w - Constants.PiOver4); + } + + spectrum[k] = sum; + }); + + return spectrum; + } + + /// + /// Naive forward DHT, useful e.g. to verify faster algorithms. + /// + /// Time-space sample vector. + /// Hartley Transform Convention Options. + /// Corresponding frequency-space vector. + public double[] NaiveForward(double[] timeSpace, HartleyOptions options) + { + var frequencySpace = Naive(timeSpace); + ForwardScaleByOptions(options, frequencySpace); + return frequencySpace; + } + + /// + /// Naive inverse DHT, useful e.g. to verify faster algorithms. + /// + /// Frequency-space sample vector. + /// Hartley Transform Convention Options. + /// Corresponding time-space vector. + public double[] NaiveInverse(double[] frequencySpace, HartleyOptions options) + { + var timeSpace = Naive(frequencySpace); + InverseScaleByOptions(options, timeSpace); + return timeSpace; + } + } +} diff --git a/src/Managed/IntegralTransforms/Algorithms/DiscreteHartleyTransform.Options.cs b/src/Managed/IntegralTransforms/Algorithms/DiscreteHartleyTransform.Options.cs new file mode 100644 index 00000000..ddf94166 --- /dev/null +++ b/src/Managed/IntegralTransforms/Algorithms/DiscreteHartleyTransform.Options.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. +// + +namespace MathNet.Numerics.IntegralTransforms.Algorithms +{ + using System; + + /// + /// Fast (FHT) Implementation of the Discrete Hartley Transform (DHT). + /// + public partial class DiscreteHartleyTransform + { + /// + /// Rescale FFT-the resulting vector according to the provided convention options. + /// + /// Fourier Transform Convention Options. + /// Sample Vector. + private static void ForwardScaleByOptions(HartleyOptions options, double[] samples) + { + if ((options & HartleyOptions.NoScaling) == HartleyOptions.NoScaling || + (options & HartleyOptions.AsymmetricScaling) == HartleyOptions.AsymmetricScaling) + { + return; + } + + var scalingFactor = Math.Sqrt(1.0 / samples.Length); + for (int i = 0; i < samples.Length; i++) + { + samples[i] *= scalingFactor; + } + } + + /// + /// Rescale the iFFT-resulting vector according to the provided convention options. + /// + /// Fourier Transform Convention Options. + /// Sample Vector. + private static void InverseScaleByOptions(HartleyOptions options, double[] samples) + { + if ((options & HartleyOptions.NoScaling) == HartleyOptions.NoScaling) + { + return; + } + + var scalingFactor = 1.0 / samples.Length; + if ((options & HartleyOptions.AsymmetricScaling) != HartleyOptions.AsymmetricScaling) + { + scalingFactor = Math.Sqrt(scalingFactor); + } + + for (int i = 0; i < samples.Length; i++) + { + samples[i] *= scalingFactor; + } + } + } +} diff --git a/src/Managed/IntegralTransforms/HartleyOptions.cs b/src/Managed/IntegralTransforms/HartleyOptions.cs new file mode 100644 index 00000000..fd6f12e0 --- /dev/null +++ b/src/Managed/IntegralTransforms/HartleyOptions.cs @@ -0,0 +1,58 @@ +// +// 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.IntegralTransforms +{ + using System; + + /// + /// Hartley Transform Convention + /// + [Flags] + public enum HartleyOptions + { + // FLAGS: + + /// + /// Only scale by 1/N in the inverse direction; No scaling in forward direction. + /// + AsymmetricScaling = 0x02, + + /// + /// Don't scale at all (neither on forward nor on inverse transformation). + /// + NoScaling = 0x04, + + // USABILITY POINTERS: + + /// + /// Universal; Symmetric scaling. + /// + Default = 0, + } +} diff --git a/src/Managed/Managed.csproj b/src/Managed/Managed.csproj index 069bd8f8..053c9833 100644 --- a/src/Managed/Managed.csproj +++ b/src/Managed/Managed.csproj @@ -56,6 +56,9 @@ + + + diff --git a/src/Native.UnitTests/Native.UnitTests.csproj b/src/Native.UnitTests/Native.UnitTests.csproj index 1d0c56ae..9c4f56bf 100644 --- a/src/Native.UnitTests/Native.UnitTests.csproj +++ b/src/Native.UnitTests/Native.UnitTests.csproj @@ -83,6 +83,9 @@ IntegralTransformsTests\DftTest.cs + + IntegralTransformsTests\DhtTest.cs + IntegrationTests\IntegrationTest.cs diff --git a/src/Native/Native.csproj b/src/Native/Native.csproj index d8d5ab04..cb10aad0 100644 --- a/src/Native/Native.csproj +++ b/src/Native/Native.csproj @@ -89,9 +89,18 @@ IntegralTransforms\Algorithms\DiscreteFourierTransform.RadixN.cs + + IntegralTransforms\Algorithms\DiscreteHartleyTransform.Naive.cs + + + IntegralTransforms\Algorithms\DiscreteHartleyTransform.Options.cs + IntegralTransforms\FourierOptions.cs + + IntegralTransforms\HartleyOptions.cs + IntegralTransforms\Transform.cs