From d5c9182f1e16a780e998008d78fdb8626602bef2 Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Fri, 14 Aug 2009 04:38:19 +0800 Subject: [PATCH] interpolation: refactored unit tests Signed-off-by: Christoph Ruegg --- .../Algorithms/SplineInterpolation.cs | 2 +- .../InterpolationTests/FunctionalHelpers.cs | 104 +++++ .../InterpolationContract.cs | 378 ------------------ .../InterpolationFunctionalContract.cs | 201 ++++++++++ .../InterpolationFunctionalTest.cs | 122 ++++++ .../InterpolationInfrastructureContract.cs | 265 ++++++++++++ .../InterpolationInfrastuctureTest.cs | 343 ++++++++++++++++ .../InterpolationTests/InterpolationTest.cs | 130 ------ .../InterpolationTests/SampleProvider.cs | 81 ++++ src/UnitTests/UnitTests.csproj | 8 +- 10 files changed, 1123 insertions(+), 511 deletions(-) create mode 100644 src/UnitTests/InterpolationTests/FunctionalHelpers.cs delete mode 100644 src/UnitTests/InterpolationTests/InterpolationContract.cs create mode 100644 src/UnitTests/InterpolationTests/InterpolationFunctionalContract.cs create mode 100644 src/UnitTests/InterpolationTests/InterpolationFunctionalTest.cs create mode 100644 src/UnitTests/InterpolationTests/InterpolationInfrastructureContract.cs create mode 100644 src/UnitTests/InterpolationTests/InterpolationInfrastuctureTest.cs delete mode 100644 src/UnitTests/InterpolationTests/InterpolationTest.cs create mode 100644 src/UnitTests/InterpolationTests/SampleProvider.cs diff --git a/src/Numerics/Interpolation/Algorithms/SplineInterpolation.cs b/src/Numerics/Interpolation/Algorithms/SplineInterpolation.cs index 6b28cfcc..0d9084ee 100644 --- a/src/Numerics/Interpolation/Algorithms/SplineInterpolation.cs +++ b/src/Numerics/Interpolation/Algorithms/SplineInterpolation.cs @@ -111,7 +111,7 @@ namespace MathNet.Numerics.Interpolation.Algorithms throw new ArgumentNullException("splineCoefficients"); } - if (samplePoints.Count < 1) + if (samplePoints.Count < 2) { throw new ArgumentOutOfRangeException("samplePoints"); } diff --git a/src/UnitTests/InterpolationTests/FunctionalHelpers.cs b/src/UnitTests/InterpolationTests/FunctionalHelpers.cs new file mode 100644 index 00000000..e2d91552 --- /dev/null +++ b/src/UnitTests/InterpolationTests/FunctionalHelpers.cs @@ -0,0 +1,104 @@ +// +// 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; +using System.Linq.Expressions; +using MathNet.Numerics.Interpolation; + +namespace MathNet.Numerics.UnitTests.InterpolationTests +{ + using System; + + internal static class FunctionalHelpers + { + internal static Expression[] ApplySingleMap( + IList list, + int index, + Func replace) + { + var newList = new Expression[list.Count]; + for (int i = 0; i < list.Count; i++) + { + newList[i] = (i == index) ? replace(list[i]) : list[i]; + } + + return newList; + } + + internal static IEnumerable>> ApplySingleMapEachArgument( + this LambdaExpression lambda, + Func predicate, + Func replace) + { + var body = lambda.Body; + var arguments = + body is NewExpression + ? ((NewExpression)body).Arguments + : ((MethodCallExpression)body).Arguments; + + for (int i = 0; i < arguments.Count; i++) + { + if (!predicate(arguments[i].Type)) + { + continue; + } + + var mappedArguments = ApplySingleMap(arguments, i, replace); + + yield return Expression.Lambda>( + body is NewExpression + ? (Expression)Expression.New( + ((NewExpression)body).Constructor, + mappedArguments) + : (Expression)Expression.Call( + ((MethodCallExpression)body).Method, + mappedArguments)); + } + } + + internal static T ApplyReduceArgument( + this LambdaExpression lambda, + Func reduce, + T init) + { + var body = lambda.Body; + var arguments = + body is NewExpression + ? ((NewExpression)body).Arguments + : ((MethodCallExpression)body).Arguments; + + T value = init; + foreach (var argument in arguments) + { + value = reduce(argument, value); + } + + return value; + } + } +} diff --git a/src/UnitTests/InterpolationTests/InterpolationContract.cs b/src/UnitTests/InterpolationTests/InterpolationContract.cs deleted file mode 100644 index 4dc559d2..00000000 --- a/src/UnitTests/InterpolationTests/InterpolationContract.cs +++ /dev/null @@ -1,378 +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.InterpolationTests -{ - using System; - using System.Collections.Generic; - using Gallio.Framework.Assertions; - using Interpolation; - using MbUnit.Framework; - using MbUnit.Framework.ContractVerifiers; - - internal class InterpolationContract : AbstractContract - where TInterpolation : IInterpolation - { - public Func, IList, IInterpolation> Factory { get; set; } - public int MinimumSampleCount { get; set; } - public bool NonStandardParameters { get; set; } - public bool LinearBehavior { get; set; } - public bool PolynomialBehavior { get; set; } - public bool RationalBehavior { get; set; } - - protected override IEnumerable GetContractVerificationTests() - { - // Infrastructure Tests - - yield return CreateFactoryReturnsCorrectTypeTest("FactoryReturnsCorrectType"); - yield return CreateConsistentCapabilityBehaviorTest("ConsistentCapabilityBehavior"); - - yield return CreateInitChecksForNullTest("InitChecksForNull"); - yield return CreateInitChecksForMatchingCountTest("InitChecksForMatchingCount"); - yield return CreateInitChecksForMinimumCountTest("InitChecksForMinimumCount"); - - if (!NonStandardParameters) - { - yield return CreateConstructorInitShortcutTest("ConstructorInitShortcut"); - } - - // Numerics Behavior Tests - - yield return CreateInterpolationMatchesNodePointsTest("InterpolationMatchesNodePoints"); - - if (LinearBehavior && !NonStandardParameters) - { - yield return CreateLinearBehaviorTest("LinearBehavior"); - } - - if (PolynomialBehavior && !NonStandardParameters) - { - yield return CreatePolynomialBehaviorTest("PolynomialBehavior"); - } - - if (RationalBehavior && !NonStandardParameters) - { - yield return CreateRationalBehaviorTest("RationalBehavior"); - } - } - - private Test CreateFactoryReturnsCorrectTypeTest(string name) - { - return new TestCase(name, () => - { - double[] points, values; - SampleFunctionEquidistant(t => 5 + 10 * t, -2.0, 8.0, MinimumSampleCount, out points, out values); - - var interpolation = Factory(points, values); - - AssertionHelper.Verify(() => - { - // verify returned interpolation has the expected type - if (interpolation.GetType() == typeof(TInterpolation)) - { - return null; - } - - return new AssertionFailureBuilder( - "Expected the factory to return the correct type.") - .AddRawLabeledValue("Interpolation Type", typeof(TInterpolation)) - .SetStackTrace(Context.GetStackTraceData()) - .ToAssertionFailure(); - }); - }); - } - - private Test CreateInitChecksForNullTest(string name) - { - return new TestCase(name, () => - { - var points = new List { 1, 2, 3, 4, 5 }; - var values = new List { 10, 20, 30, 40, 50 }; - - Assert.DoesNotThrow(() => Factory(points, values)); - - Assert.Throws(typeof(ArgumentNullException), () => Factory(points, null)); - Assert.Throws(typeof(ArgumentNullException), () => Factory(null, values)); - Assert.Throws(typeof(ArgumentNullException), () => Factory(null, null)); - }); - } - - private Test CreateInitChecksForMatchingCountTest(string name) - { - return new TestCase(name, () => - { - var points = new List { 1, 2, 3, 4, 5 }; - var valuesOk = new List { 10, 20, 30, 40, 50 }; - var valuesFail1 = new List { 10, 20, 30, 40 }; - var valuesFail2 = new List { 10, 20, 30, 40, 50, 60 }; - - Assert.DoesNotThrow(() => Factory(points, valuesOk)); - - Assert.Throws(typeof(ArgumentException), () => Factory(points, valuesFail1)); - Assert.Throws(typeof(ArgumentException), () => Factory(points, valuesFail2)); - }); - } - - private Test CreateInitChecksForMinimumCountTest(string name) - { - return new TestCase(name, () => - { - double[] pointsOk, valuesOk; - SampleFunctionEquidistant(t => 5 + 10 * t, -2.0, 8.0, MinimumSampleCount, out pointsOk, out valuesOk); - - Assert.DoesNotThrow(() => Factory(pointsOk, valuesOk)); - - double[] pointsFail, valuesFail; - SampleFunctionEquidistant(t => 5 + 10 * t, -2.0, 8.0, MinimumSampleCount - 1, out pointsFail, out valuesFail); - - Assert.Throws(typeof(ArgumentOutOfRangeException), () => Factory(pointsFail, valuesFail)); - }); - } - - private Test CreateConstructorInitShortcutTest(string name) - { - return new TestCase(name, () => - { - var points = new List { 1, 2, 3, 4, 5 }; - var values = new List { 10, 20, 30, 40, 50 }; - - var ctor = typeof(TInterpolation).GetConstructor( - new[] { typeof (IList), typeof (IList) } - ); - - var interpolation = (IInterpolation)ctor.Invoke( - new[] { points, values } - ); - - Assert.AreApproximatelyEqual(20, interpolation.Interpolate(2), 1e-12); - }); - } - - private Test CreateConsistentCapabilityBehaviorTest(string name) - { - return new TestCase(name, () => - { - double[] points, values; - SampleFunctionEquidistant(t => 5 + 10 * t, -2.0, 8.0, MinimumSampleCount, out points, out values); - - var interpolation = Factory(points, values); - - // verify consistent differentiation capability - if (interpolation.SupportsDifferentiation) - { - double a, b; - Assert.DoesNotThrow(() => interpolation.Differentiate(1.2)); - Assert.DoesNotThrow(() => interpolation.Differentiate(1.2, out a, out b)); - } - else - { - double a, b; - - Assert.Throws( - typeof(NotSupportedException), - () => interpolation.Differentiate(1.2)); - - Assert.Throws( - typeof(NotSupportedException), - () => interpolation.Differentiate(1.2, out a, out b)); - } - - // verify consistent integration capability - if (interpolation.SupportsIntegration) - { - Assert.DoesNotThrow(() => interpolation.Integrate(1.2)); - } - else - { - Assert.Throws( - typeof(NotSupportedException), - () => interpolation.Integrate(1.2)); - } - }); - } - - private Test CreateInterpolationMatchesNodePointsTest(string name) - { - return new TestCase(name, () => - { - var points = new List { 1, 2, 2.3, 3, 8 }; - var values = new List { 50, 20, 30, 10, -20 }; - var interpolation = Factory(points, values); - - for (int i = 0; i < points.Count; i++) - { - Assert.AreApproximatelyEqual( - values[i], - interpolation.Interpolate(points[i]), - 1e-12); - } - }); - } - - private Test CreateLinearBehaviorTest(string name) - { - return new TestCase(name, () => - { - const double yOffset = 2.0; - const double xOffset = 4.0; - Random random = new Random(); - - int[] orders = { MinimumSampleCount, MinimumSampleCount + 1, MinimumSampleCount + 5 }; - - for (int k = 0; k < orders.Length; k++) - { - int order = orders[k]; - - // build linear samples - double[] points = new double[order]; - double[] values = new double[order]; - for (int i = 0; i < points.Length; i++) - { - points[i] = xOffset + i; - values[i] = yOffset + i; - } - - var interpolation = Factory(points, values); - - // build linear test vectors randomly between the sample points - double[] testPoints = new double[order + 1]; - double[] testValues = new double[order + 1]; - if (order == 1) - { - testPoints[0] = xOffset - random.NextDouble(); - testPoints[1] = xOffset + random.NextDouble(); - testValues[0] = testValues[1] = yOffset; - } - else - { - for (int i = 0; i < testPoints.Length; i++) - { - double z = (i - 1) + random.NextDouble(); - testPoints[i] = xOffset + z; - testValues[i] = yOffset + z; - } - } - - // verify interpolation with test samples - for (int i = 0; i < testPoints.Length; i++) - { - Assert.AreApproximatelyEqual( - testValues[i], - interpolation.Interpolate(testPoints[i]), - 1e-12); - } - } - }); - } - - private Test CreatePolynomialBehaviorTest(string name) - { - return new TestCase(name, () => - { - var points = new List { -2.0, -1.0, 0.0, 1.0, 2.0 }; - var values = new List { 1.0, 2.0, -1.0, 0.0, 1.0 }; - var interpolation = Factory(points, values); - - // Maple: "with(CurveFitting);" - // Maple: "PolynomialInterpolation([[-2,1],[-1,2],[0,-1],[1,0],[2,1]], x);" - Assert.AreApproximatelyEqual(-4.5968, interpolation.Interpolate(-2.4), 1e-6, "A -2.4"); - Assert.AreApproximatelyEqual(1.65395, interpolation.Interpolate(-0.9), 1e-6, "A -0.9"); - Assert.AreApproximatelyEqual(0.21875, interpolation.Interpolate(-0.5), 1e-6, "A -0.5"); - Assert.AreApproximatelyEqual(-0.84205, interpolation.Interpolate(-0.1), 1e-6, "A -0.1"); - Assert.AreApproximatelyEqual(-1.10805, interpolation.Interpolate(0.1), 1e-6, "A 0.1"); - Assert.AreApproximatelyEqual(-1.1248, interpolation.Interpolate(0.4), 1e-6, "A 0.4"); - Assert.AreApproximatelyEqual(0.5392, interpolation.Interpolate(1.2), 1e-6, "A 1.2"); - Assert.AreApproximatelyEqual(-4431.0, interpolation.Interpolate(10.0), 1e-6, "A 10.0"); - Assert.AreApproximatelyEqual(-5071.0, interpolation.Interpolate(-10.0), 1e-6, "A -10.0"); - }); - } - - private Test CreateRationalBehaviorTest(string name) - { - return new TestCase(name, () => - { - double[] points, values; - SampleFunctionEquidistant(t => 1 / (1 + (t * t)), -5.0, 5.0, 41, out points, out values); - var interpolation = Factory(points, values); - - for (int i = 0; i < points.Length; i++) - { - Assert.AreApproximatelyEqual( - values[i], - interpolation.Interpolate(points[i]), - 1e-12, - "Match on knots"); - } - - double[] testPoints, testValues; - SampleFunctionEquidistant(t => 1 / (1 + (t * t)), -5.0, 5.0, 81, out testPoints, out testValues); - - for (int i = 0; i < testPoints.Length; i++) - { - Assert.AreApproximatelyEqual( - testValues[i], - interpolation.Interpolate(testPoints[i]), - 1e-5, - "Match between knots"); - } - }); - } - - private static void SampleFunctionEquidistant( - Func f, - double start, - double stop, - int samples, - out double[] points, - out double[] values) - { - points = new double[samples]; - values = new double[samples]; - - if(samples == 0) - { - return; - } - - if(samples == 1) - { - double t = points[0] = 0.5 * (start + stop); - values[0] = f(t); - return; - } - - double step = (stop - start) / (samples - 1); - for (int i = 0; i < points.Length; i++) - { - double t = start + (i * step); - points[i] = t; - values[i] = f(t); - } - } - } -} diff --git a/src/UnitTests/InterpolationTests/InterpolationFunctionalContract.cs b/src/UnitTests/InterpolationTests/InterpolationFunctionalContract.cs new file mode 100644 index 00000000..8f5a4e66 --- /dev/null +++ b/src/UnitTests/InterpolationTests/InterpolationFunctionalContract.cs @@ -0,0 +1,201 @@ +// +// 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.InterpolationTests +{ + using System; + using System.Collections.Generic; + using Interpolation; + using MbUnit.Framework; + using MbUnit.Framework.ContractVerifiers; + + internal class InterpolationFunctionalContract : AbstractContract + where TInterpolation : IInterpolation + { + public Func, IList, IInterpolation> Factory { get; set; } + public int MinimumSampleCount { get; set; } + public bool LinearBehavior { get; set; } + public bool PolynomialBehavior { get; set; } + public bool RationalBehavior { get; set; } + + protected override IEnumerable GetContractVerificationTests() + { + yield return CreateInterpolationMatchesNodePointsTest(); + + if (LinearBehavior) + { + yield return CreateLinearBehaviorTest(); + } + + if (PolynomialBehavior) + { + yield return CreatePolynomialBehaviorTest(); + } + + if (RationalBehavior) + { + yield return CreateRationalBehaviorTest(); + } + } + + private Test CreateInterpolationMatchesNodePointsTest() + { + return new TestCase( + "InterpolationMatchesNodePoints", + () => + { + var points = new List { 1, 2, 2.3, 3, 8 }; + var values = new List { 50, 20, 30, 10, -20 }; + var interpolation = Factory(points, values); + + for (int i = 0; i < points.Count; i++) + { + Assert.AreApproximatelyEqual( + values[i], + interpolation.Interpolate(points[i]), + 1e-12); + } + }); + } + + private Test CreateLinearBehaviorTest() + { + return new TestCase( + "LinearBehavior", + () => + { + const double yOffset = 2.0; + const double xOffset = 4.0; + var random = new Random(); + + int[] orders = { MinimumSampleCount, MinimumSampleCount + 1, MinimumSampleCount + 5 }; + + for (int k = 0; k < orders.Length; k++) + { + int order = orders[k]; + + // build linear samples + var points = new double[order]; + var values = new double[order]; + for (int i = 0; i < points.Length; i++) + { + points[i] = xOffset + i; + values[i] = yOffset + i; + } + + var interpolation = Factory(points, values); + + // build linear test vectors randomly between the sample points + var testPoints = new double[order + 1]; + var testValues = new double[order + 1]; + if (order == 1) + { + testPoints[0] = xOffset - random.NextDouble(); + testPoints[1] = xOffset + random.NextDouble(); + testValues[0] = testValues[1] = yOffset; + } + else + { + for (int i = 0; i < testPoints.Length; i++) + { + double z = (i - 1) + random.NextDouble(); + testPoints[i] = xOffset + z; + testValues[i] = yOffset + z; + } + } + + // verify interpolation with test samples + for (int i = 0; i < testPoints.Length; i++) + { + Assert.AreApproximatelyEqual( + testValues[i], + interpolation.Interpolate(testPoints[i]), + 1e-12); + } + } + }); + } + + private Test CreatePolynomialBehaviorTest() + { + return new TestCase( + "PolynomialBehavior", + () => + { + var points = new List { -2.0, -1.0, 0.0, 1.0, 2.0 }; + var values = new List { 1.0, 2.0, -1.0, 0.0, 1.0 }; + var interpolation = Factory(points, values); + + // Maple: "with(CurveFitting);" + // Maple: "PolynomialInterpolation([[-2,1],[-1,2],[0,-1],[1,0],[2,1]], x);" + Assert.AreApproximatelyEqual(-4.5968, interpolation.Interpolate(-2.4), 1e-6, "A -2.4"); + Assert.AreApproximatelyEqual(1.65395, interpolation.Interpolate(-0.9), 1e-6, "A -0.9"); + Assert.AreApproximatelyEqual(0.21875, interpolation.Interpolate(-0.5), 1e-6, "A -0.5"); + Assert.AreApproximatelyEqual(-0.84205, interpolation.Interpolate(-0.1), 1e-6, "A -0.1"); + Assert.AreApproximatelyEqual(-1.10805, interpolation.Interpolate(0.1), 1e-6, "A 0.1"); + Assert.AreApproximatelyEqual(-1.1248, interpolation.Interpolate(0.4), 1e-6, "A 0.4"); + Assert.AreApproximatelyEqual(0.5392, interpolation.Interpolate(1.2), 1e-6, "A 1.2"); + Assert.AreApproximatelyEqual(-4431.0, interpolation.Interpolate(10.0), 1e-6, "A 10.0"); + Assert.AreApproximatelyEqual(-5071.0, interpolation.Interpolate(-10.0), 1e-6, "A -10.0"); + }); + } + + private Test CreateRationalBehaviorTest() + { + return new TestCase( + "RationalBehavior", + () => + { + double[] points, values; + SampleProvider.Equidistant(t => 1 / (1 + (t * t)), -5.0, 5.0, 41, out points, out values); + var interpolation = Factory(points, values); + + for (int i = 0; i < points.Length; i++) + { + Assert.AreApproximatelyEqual( + values[i], + interpolation.Interpolate(points[i]), + 1e-12, + "Match on knots"); + } + + double[] testPoints, testValues; + SampleProvider.Equidistant(t => 1 / (1 + (t * t)), -5.0, 5.0, 81, out testPoints, out testValues); + + for (int i = 0; i < testPoints.Length; i++) + { + Assert.AreApproximatelyEqual( + testValues[i], + interpolation.Interpolate(testPoints[i]), + 1e-5, + "Match between knots"); + } + }); + } + } +} diff --git a/src/UnitTests/InterpolationTests/InterpolationFunctionalTest.cs b/src/UnitTests/InterpolationTests/InterpolationFunctionalTest.cs new file mode 100644 index 00000000..ea36be81 --- /dev/null +++ b/src/UnitTests/InterpolationTests/InterpolationFunctionalTest.cs @@ -0,0 +1,122 @@ +// +// 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.InterpolationTests +{ + using Interpolation; + using Interpolation.Algorithms; + using MbUnit.Framework; + using MbUnit.Framework.ContractVerifiers; + + [TestFixture] + public class InterpolationFunctionalTest + { + /**** Direct Algorithms (without precomputations) ****/ + + [VerifyContract] + public readonly IContract NevillePolynomialFunctionalTests = + new InterpolationFunctionalContract + { + Factory = (t, x) => new NevillePolynomialInterpolation(t, x), + MinimumSampleCount = 1, + LinearBehavior = true, + PolynomialBehavior = true, + RationalBehavior = false + }; + + [VerifyContract] + public readonly IContract BulirschStoerRationalFunctionalTests = + new InterpolationFunctionalContract + { + Factory = Interpolate.RationalWithPoles, + MinimumSampleCount = 1, + LinearBehavior = false, + PolynomialBehavior = true, + RationalBehavior = true + }; + + /**** Barycentric Algorithms ****/ + + [VerifyContract] + public readonly IContract FloaterHormannRationalFunctionalTests = + new InterpolationFunctionalContract + { + Factory = Interpolate.RationalWithoutPoles, + MinimumSampleCount = 1, + LinearBehavior = true, + PolynomialBehavior = true, + RationalBehavior = true + }; + + [VerifyContract] + public readonly IContract EquidistantPolynomialFunctionalTests = + new InterpolationFunctionalContract + { + Factory = (t, x) => new EquidistantPolynomialInterpolation(t, x), + MinimumSampleCount = 1, + LinearBehavior = true, + PolynomialBehavior = true, + RationalBehavior = false + }; + + /**** Spline Algorithms ****/ + + [VerifyContract] + public readonly IContract LinearSplineFunctionalTests = + new InterpolationFunctionalContract + { + Factory = Interpolate.LinearBetweenPoints, + MinimumSampleCount = 2, + LinearBehavior = true, + PolynomialBehavior = false, + RationalBehavior = false + }; + + [VerifyContract] + public readonly IContract CubicSplineFunctionalTests = + new InterpolationFunctionalContract + { + Factory = (t, x) => new CubicSplineInterpolation(t, x), + MinimumSampleCount = 2, + LinearBehavior = true, + PolynomialBehavior = false, + RationalBehavior = false + }; + + [VerifyContract] + public readonly IContract AkimaSplineFunctionalTests = + new InterpolationFunctionalContract + { + Factory = (t, x) => new AkimaSplineInterpolation(t, x), + MinimumSampleCount = 5, + LinearBehavior = true, + PolynomialBehavior = false, + RationalBehavior = false + }; + } +} diff --git a/src/UnitTests/InterpolationTests/InterpolationInfrastructureContract.cs b/src/UnitTests/InterpolationTests/InterpolationInfrastructureContract.cs new file mode 100644 index 00000000..45c08c28 --- /dev/null +++ b/src/UnitTests/InterpolationTests/InterpolationInfrastructureContract.cs @@ -0,0 +1,265 @@ +// +// 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.InterpolationTests +{ + using System; + using System.Collections.Generic; + using System.Linq.Expressions; + using Interpolation; + using MbUnit.Framework; + using MbUnit.Framework.ContractVerifiers; + + internal class InterpolationInfrastructureContract : AbstractContract + where TInterpolation : IInterpolation + { + public Func[] UninitializedFactories { get; set; } + public Expression>[] InitializedFactories { get; set; } + + public int MinimumSampleCount { get; set; } + + protected override IEnumerable GetContractVerificationTests() + { + yield return CreateLoadUninitializedFactoryTest(); + yield return CreateLoadInitializedFactoryTest(); + + yield return CreateInitializedFactoryChecksForNullTest(); + yield return CreateInitializedFactoryChecksForToFewSamplesTest(); + yield return CreateInitializedFactoryChecksForCountMismatchTest(); + + yield return CreateConsistentCapabilityBehaviorTest(); + } + + private Test CreateLoadUninitializedFactoryTest() + { + return new TestCase( + "LoadUninitializedFactory", + () => + { + Assert.IsNotNull(UninitializedFactories); + Assert.LessThan(0, UninitializedFactories.Length); + + foreach (var factory in UninitializedFactories) + { + var interpolation = factory(); + + Assert.IsNotNull(interpolation); + Assert.IsInstanceOfType(typeof(TInterpolation), interpolation); + } + }); + } + + private Test CreateLoadInitializedFactoryTest() + { + return new TestCase( + "LoadInitializedFactory", + () => + { + Assert.IsNotNull(InitializedFactories); + Assert.LessThan(0, InitializedFactories.Length); + + foreach (var factory in InitializedFactories) + { + var interpolation = factory.Compile()(); + + Assert.IsNotNull(interpolation); + Assert.IsInstanceOfType(typeof(TInterpolation), interpolation); + Assert.DoesNotThrow(() => interpolation.Interpolate(0.0)); + } + }); + } + + private Test CreateInitializedFactoryChecksForNullTest() + { + return new TestCase( + "InitializedFactoryChecksForNull", + () => + { + foreach (var factory in InitializedFactories) + { + // we only support method calls and constructors for now. + if (factory.Body.NodeType != ExpressionType.New + && factory.Body.NodeType != ExpressionType.Call) + { + Assert.Fail( + "Factory '{0}' is neither a constructor or a method call.", + factory.ToString()); + continue; + } + + var modifiedFactories = factory.ApplySingleMapEachArgument( + t => !t.IsValueType, + e => Expression.Constant(null, e.Type)); + + foreach (var modifiedFactory in modifiedFactories) + { + var closureFactoryReference = modifiedFactory; + + Assert.Throws( + typeof(ArgumentNullException), + () => closureFactoryReference.Compile()(), + "Factory must check for null arguments ({0})", + closureFactoryReference.ToString()); + } + } + }); + } + + private Test CreateInitializedFactoryChecksForToFewSamplesTest() + { + return new TestCase( + "InitializedFactoryChecksForToFewSamples", + () => + { + foreach (var factory in InitializedFactories) + { + // we only support method calls and constructors for now. + if (factory.Body.NodeType != ExpressionType.New + && factory.Body.NodeType != ExpressionType.Call) + { + Assert.Fail( + "Factory '{0}' is neither a constructor or a method call.", + factory.ToString()); + continue; + } + + var modifiedFactories = factory.ApplySingleMapEachArgument( + t => !t.IsValueType, + e => Expression.Constant(new double[MinimumSampleCount - 1], typeof(double[]))); + + foreach (var modifiedFactory in modifiedFactories) + { + var closureFactoryReference = modifiedFactory; + + Assert.Throws( + typeof(ArgumentException), + () => closureFactoryReference.Compile()(), + "Factory must check to ensure there are enough samples ({0})", + closureFactoryReference.ToString()); + } + } + }); + } + + private Test CreateInitializedFactoryChecksForCountMismatchTest() + { + return new TestCase( + "InitializedFactoryChecksForCountMismatch", + () => + { + foreach (var factory in InitializedFactories) + { + // we only support method calls and constructors for now. + if (factory.Body.NodeType != ExpressionType.New + && factory.Body.NodeType != ExpressionType.Call) + { + Assert.Fail( + "Factory '{0}' is neither a constructor or a method call.", + factory.ToString()); + continue; + } + + // mismatch doesn't make sense when there are less than two list arguments. + int listCount = factory.ApplyReduceArgument( + (e, count) => typeof(IList).IsAssignableFrom(e.Type) ? count + 1 : count, + 0); + + if (listCount < 2) + { + continue; + } + + var modifiedFactories = factory.ApplySingleMapEachArgument( + t => !t.IsValueType, + e => + { + // add a single entry to the end of the list + var originalList = Expression.Lambda>(e).Compile()(); + var newList = new double[originalList.Length + 1]; + originalList.CopyTo(newList, 0); + newList[newList.Length - 1] = -1; + return Expression.Constant(newList, e.Type); + }); + + foreach (var modifiedFactory in modifiedFactories) + { + var closureFactoryReference = modifiedFactory; + + Assert.Throws( + typeof(ArgumentException), + () => closureFactoryReference.Compile()(), + "Factory must check for matching sample lengths ({0})", + closureFactoryReference.ToString()); + } + } + }); + } + + private Test CreateConsistentCapabilityBehaviorTest() + { + return new TestCase( + "ConsistentCapabilityBehavior", + () => + { + var interpolation = InitializedFactories[0].Compile()(); + + // verify consistent differentiation capability + if (interpolation.SupportsDifferentiation) + { + double a, b; + Assert.DoesNotThrow(() => interpolation.Differentiate(1.2)); + Assert.DoesNotThrow(() => interpolation.Differentiate(1.2, out a, out b)); + } + else + { + double a, b; + + Assert.Throws( + typeof(NotSupportedException), + () => interpolation.Differentiate(1.2)); + + Assert.Throws( + typeof(NotSupportedException), + () => interpolation.Differentiate(1.2, out a, out b)); + } + + // verify consistent integration capability + if (interpolation.SupportsIntegration) + { + Assert.DoesNotThrow(() => interpolation.Integrate(1.2)); + } + else + { + Assert.Throws( + typeof(NotSupportedException), + () => interpolation.Integrate(1.2)); + } + }); + } + } +} diff --git a/src/UnitTests/InterpolationTests/InterpolationInfrastuctureTest.cs b/src/UnitTests/InterpolationTests/InterpolationInfrastuctureTest.cs new file mode 100644 index 00000000..31b0722c --- /dev/null +++ b/src/UnitTests/InterpolationTests/InterpolationInfrastuctureTest.cs @@ -0,0 +1,343 @@ +// +// 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.InterpolationTests +{ + using System; + using System.Linq.Expressions; + using Interpolation; + using Interpolation.Algorithms; + using MbUnit.Framework; + using MbUnit.Framework.ContractVerifiers; + + [TestFixture] + public class InterpolationInfrastuctureTest + { + /**** Direct Algorithms (without precomputations) ****/ + + [VerifyContract] + public readonly IContract NevillePolynomialInfrastructureTests = + new InterpolationInfrastructureContract + { + MinimumSampleCount = 1, + UninitializedFactories = + new Func[] + { + () => new NevillePolynomialInterpolation() + }, + InitializedFactories = + new Expression>[] + { + () => new NevillePolynomialInterpolation( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5)) + } + }; + + [VerifyContract] + public readonly IContract BulirschStoerRationalInfrastructureTests = + new InterpolationInfrastructureContract + { + MinimumSampleCount = 1, + UninitializedFactories = + new Func[] + { + () => new BulirschStoerRationalInterpolation() + }, + InitializedFactories = + new Expression>[] + { + () => new BulirschStoerRationalInterpolation( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5)), + () => Interpolate.RationalWithPoles( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5)) + } + }; + + /**** Barycentric Algorithms ****/ + + [VerifyContract] + public readonly IContract BarycentricInfrastructureTests = + new InterpolationInfrastructureContract + { + MinimumSampleCount = 3, + UninitializedFactories = + new Func[] + { + () => new BarycentricInterpolation() + }, + InitializedFactories = + new Expression>[] + { + () => new BarycentricInterpolation( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5), + SampleProvider.LinearEquidistant(10, 1, 0.1)), + () => new BarycentricInterpolation( + SampleProvider.LinearEquidistant(10, 5, -1), + SampleProvider.LinearEquidistant(10, -2, 0.5), + SampleProvider.LinearEquidistant(10, 1, 0.1)) + } + }; + + [VerifyContract] + public readonly IContract FloaterHormannRationalInfrastructureTests = + new InterpolationInfrastructureContract + { + MinimumSampleCount = 1, + UninitializedFactories = + new Func[] + { + () => new FloaterHormannRationalInterpolation() + }, + InitializedFactories = + new Expression>[] + { + () => new FloaterHormannRationalInterpolation( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5)), + () => new FloaterHormannRationalInterpolation( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5), + 5), + () => Interpolate.RationalWithoutPoles( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5)), + () => Interpolate.Common( + SampleProvider.LinearEquidistant(10, 5, -1), + SampleProvider.LinearEquidistant(10, -2, 0.5)) + } + }; + + [VerifyContract] + public readonly IContract EquidistantPolynomialInfrastructureTests = + new InterpolationInfrastructureContract + { + MinimumSampleCount = 1, + UninitializedFactories = + new Func[] + { + () => new EquidistantPolynomialInterpolation() + }, + InitializedFactories = + new Expression>[] + { + () => new EquidistantPolynomialInterpolation( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5)), + () => new EquidistantPolynomialInterpolation( + SampleProvider.LinearEquidistant(10, 5, -1), + SampleProvider.LinearEquidistant(10, -2, 0.5)), + () => new EquidistantPolynomialInterpolation( + -5, + 4, + SampleProvider.LinearEquidistant(10, -2, 0.5)) + } + }; + + /**** Spline Algorithms ****/ + + [VerifyContract] + public readonly IContract SplineInfrastructureTests = + new InterpolationInfrastructureContract + { + MinimumSampleCount = 2, + UninitializedFactories = + new Func[] + { + () => new SplineInterpolation() + }, + InitializedFactories = + new Expression>[] + { + () => new SplineInterpolation( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(4 * (10 - 1), -2, 0.5)), + () => new SplineInterpolation( + SampleProvider.LinearEquidistant(10, -5, 1), + AkimaSplineInterpolation.EvaluateSplineCoefficients( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5))), + () => new SplineInterpolation( + SampleProvider.LinearEquidistant(10, -5, 1), + CubicSplineInterpolation.EvaluateSplineCoefficients( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5), + SplineBoundaryCondition.Natural, + 1.0, + SplineBoundaryCondition.Natural, + -1.0)) + } + }; + + [VerifyContract] + public readonly IContract CubicHermiteSplineInfrastructureTests = + new InterpolationInfrastructureContract + { + MinimumSampleCount = 2, + UninitializedFactories = + new Func[] + { + () => new CubicHermiteSplineInterpolation() + }, + InitializedFactories = + new Expression>[] + { + () => new CubicHermiteSplineInterpolation( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5), + SampleProvider.LinearEquidistant(10, 1, 0.1)) + } + }; + + [VerifyContract] + public readonly IContract LinearSplineInfrastructureTests = + new InterpolationInfrastructureContract + { + MinimumSampleCount = 2, + UninitializedFactories = + new Func[] + { + () => new LinearSplineInterpolation() + }, + InitializedFactories = + new Expression>[] + { + () => new LinearSplineInterpolation( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5)), + () => Interpolate.LinearBetweenPoints( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5)) + } + }; + + [VerifyContract] + public readonly IContract CubicSplineInfrastructureTests = + new InterpolationInfrastructureContract + { + MinimumSampleCount = 2, + UninitializedFactories = + new Func[] + { + () => new CubicSplineInterpolation() + }, + InitializedFactories = + new Expression>[] + { + () => new CubicSplineInterpolation( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5)), + () => new CubicSplineInterpolation( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5), + SplineBoundaryCondition.FirstDerivative, + 1.0, + SplineBoundaryCondition.FirstDerivative, + -1.0), + () => new CubicSplineInterpolation( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5), + SplineBoundaryCondition.Natural, + 1.0, + SplineBoundaryCondition.Natural, + -1.0), + () => new CubicSplineInterpolation( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5), + SplineBoundaryCondition.ParabolicallyTerminated, + 1.0, + SplineBoundaryCondition.ParabolicallyTerminated, + -1.0), + () => new CubicSplineInterpolation( + SampleProvider.LinearEquidistant(2, -5, 1), + SampleProvider.LinearEquidistant(2, -2, 0.5), + SplineBoundaryCondition.ParabolicallyTerminated, + 1.0, + SplineBoundaryCondition.ParabolicallyTerminated, + -1.0) + } + }; + + [VerifyContract] + public readonly IContract AkimaSplineInfrastructureTests = + new InterpolationInfrastructureContract + { + MinimumSampleCount = 5, + UninitializedFactories = + new Func[] + { + () => new AkimaSplineInterpolation() + }, + InitializedFactories = + new Expression>[] + { + () => new AkimaSplineInterpolation( + SampleProvider.LinearEquidistant(10, -5, 1), + SampleProvider.LinearEquidistant(10, -2, 0.5)) + } + }; + + [Test] + public void FloaterHormannRationalThrowsOnBadOrder() + { + Assert.Throws( + typeof(ArgumentOutOfRangeException), + () => new FloaterHormannRationalInterpolation( + new double[5], + new double[5], + 10)); + } + + [Test] + public void CubicSplineThrowsOnBadBoundaryCondition() + { + Assert.Throws( + typeof(NotSupportedException), + () => new CubicSplineInterpolation( + new double[5], + new double[5], + (SplineBoundaryCondition)(-1), + 0, + SplineBoundaryCondition.Natural, + 0)); + + Assert.Throws( + typeof(NotSupportedException), + () => new CubicSplineInterpolation( + new double[5], + new double[5], + SplineBoundaryCondition.Natural, + 0, + (SplineBoundaryCondition)(-1), + 0)); + } + } +} diff --git a/src/UnitTests/InterpolationTests/InterpolationTest.cs b/src/UnitTests/InterpolationTests/InterpolationTest.cs deleted file mode 100644 index 1c733696..00000000 --- a/src/UnitTests/InterpolationTests/InterpolationTest.cs +++ /dev/null @@ -1,130 +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.InterpolationTests -{ - using System; - using Interpolation; - using Interpolation.Algorithms; - using MbUnit.Framework; - using MbUnit.Framework.ContractVerifiers; - - [TestFixture] - public class InterpolationTest - { - // Direct Algorithms (without precomputations) - - [VerifyContract] - public readonly IContract NevillePolynomialContractTests = new InterpolationContract() - { - Factory = (t, x) => new NevillePolynomialInterpolation(t, x), - MinimumSampleCount = 1, - LinearBehavior = true, - PolynomialBehavior = true, - RationalBehavior = false - }; - - [VerifyContract] - public readonly IContract BulirschStoerRationalContractTests = new InterpolationContract() - { - Factory = Interpolate.RationalWithPoles, - MinimumSampleCount = 1, - LinearBehavior = false, - PolynomialBehavior = true, - RationalBehavior = true - }; - - // Barycentric Algorithms - - [VerifyContract] - public readonly IContract BarycentricContractTests = new InterpolationContract() - { - Factory = (t, x) => new BarycentricInterpolation(t, x, FloaterHormannRationalInterpolation.EvaluateBarycentricWeights(t, x, 2)), - MinimumSampleCount = 3, - NonStandardParameters = true, - }; - - [VerifyContract] - public readonly IContract FloaterHormannRationalContractTests = new InterpolationContract() - { - Factory = Interpolate.RationalWithoutPoles, - MinimumSampleCount = 1, - LinearBehavior = true, - PolynomialBehavior = true, - RationalBehavior = true - }; - - // Spline Algorithms - - [VerifyContract] - public readonly IContract SplineContractTests = new InterpolationContract() - { - Factory = (t, x) => new SplineInterpolation(t, LinearSplineInterpolation.EvaluateSplineCoefficients(t, x)), - MinimumSampleCount = 2, - NonStandardParameters = true, - }; - - [VerifyContract] - public readonly IContract CubicHermiteSplineContractTests = new InterpolationContract() - { - Factory = (t, x) => new CubicHermiteSplineInterpolation(t, x, CubicSplineInterpolation.EvaluateSplineDerivatives(t, x, SplineBoundaryCondition.Natural, 0.0, SplineBoundaryCondition.Natural, 0.0)), - MinimumSampleCount = 2, - NonStandardParameters = true, - }; - - [VerifyContract] - public readonly IContract LinearSplineContractTests = new InterpolationContract() - { - Factory = Interpolate.LinearBetweenPoints, - MinimumSampleCount = 2, - LinearBehavior = true, - PolynomialBehavior = false, - RationalBehavior = false - }; - - [VerifyContract] - public readonly IContract CubicSplineContractTests = new InterpolationContract() - { - Factory = (t, x) => new CubicSplineInterpolation(t, x), - MinimumSampleCount = 2, - LinearBehavior = true, - PolynomialBehavior = false, - RationalBehavior = false - }; - - [VerifyContract] - public readonly IContract AkimaSplineContractTests = new InterpolationContract() - { - Factory = (t, x) => new AkimaSplineInterpolation(t, x), - MinimumSampleCount = 5, - LinearBehavior = true, - PolynomialBehavior = false, - RationalBehavior = false - }; - } -} diff --git a/src/UnitTests/InterpolationTests/SampleProvider.cs b/src/UnitTests/InterpolationTests/SampleProvider.cs new file mode 100644 index 00000000..abd8903d --- /dev/null +++ b/src/UnitTests/InterpolationTests/SampleProvider.cs @@ -0,0 +1,81 @@ +// +// 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.InterpolationTests +{ + using System; + + internal static class SampleProvider + { + internal static double[] LinearEquidistant(int count, double start, double step) + { + var samples = new double[count]; + var nextValue = start; + + for (int i = 0; i < samples.Length; i++) + { + samples[i] = nextValue; + nextValue += step; + } + + return samples; + } + + internal static void Equidistant( + Func f, + double start, + double stop, + int samples, + out double[] points, + out double[] values) + { + points = new double[samples]; + values = new double[samples]; + + if (samples == 0) + { + return; + } + + if (samples == 1) + { + double t = points[0] = 0.5 * (start + stop); + values[0] = f(t); + return; + } + + double step = (stop - start) / (samples - 1); + for (int i = 0; i < points.Length; i++) + { + double t = start + (i * step); + points[i] = t; + values[i] = f(t); + } + } + } +} diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj index fe292ad0..74f53267 100644 --- a/src/UnitTests/UnitTests.csproj +++ b/src/UnitTests/UnitTests.csproj @@ -74,8 +74,12 @@ - - + + + + + +