diff --git a/src/Managed.UnitTests/InterpolationTests/InterpolationContract.cs b/src/Managed.UnitTests/InterpolationTests/InterpolationContract.cs index ae63a0d9..c2877369 100644 --- a/src/Managed.UnitTests/InterpolationTests/InterpolationContract.cs +++ b/src/Managed.UnitTests/InterpolationTests/InterpolationContract.cs @@ -40,6 +40,7 @@ namespace MathNet.Numerics.UnitTests.InterpolationTests { public Func, IList, IInterpolation> Factory { get; set; } public int[] Order { get; set; } + public bool LinearBehavior { get; set; } public bool PolynomialBehavior { get; set; } public bool RationalBehavior { get; set; } @@ -56,7 +57,11 @@ namespace MathNet.Numerics.UnitTests.InterpolationTests yield return CreateConstructorInitShortcutTest("ConstructorInitShortcut"); yield return CreateConsistentCapabilityBehaviorTest("ConsistentCapabilityBehavior"); yield return CreateInterpolationMatchesNodePointsTest("InterpolationMatchesNodePoints"); - yield return CreateLinearBehaviorTest("LinearBehavior"); + + if (LinearBehavior) + { + yield return CreateLinearBehaviorTest("LinearBehavior"); + } if (PolynomialBehavior) { diff --git a/src/Managed.UnitTests/InterpolationTests/InterpolationTest.cs b/src/Managed.UnitTests/InterpolationTests/InterpolationTest.cs index 62f14632..bdf355be 100644 --- a/src/Managed.UnitTests/InterpolationTests/InterpolationTest.cs +++ b/src/Managed.UnitTests/InterpolationTests/InterpolationTest.cs @@ -42,6 +42,7 @@ namespace MathNet.Numerics.UnitTests.InterpolationTests { Factory = Interpolate.LinearBetweenPoints, Order = new[] { 2, 3, 6 }, + LinearBehavior = true, PolynomialBehavior = false, RationalBehavior = false }; @@ -51,6 +52,7 @@ namespace MathNet.Numerics.UnitTests.InterpolationTests { Factory = Interpolate.RationalWithoutPoles, Order = new[] { 1, 2, 6 }, + LinearBehavior = true, PolynomialBehavior = true, RationalBehavior = true }; @@ -60,8 +62,19 @@ namespace MathNet.Numerics.UnitTests.InterpolationTests { Factory = (t, x) => new NevillePolynomialInterpolation(t, x), Order = new[] { 1, 2, 6 }, + LinearBehavior = true, PolynomialBehavior = true, RationalBehavior = false }; + + [VerifyContract] + public readonly IContract BulirschStoerRationalContractTests = new InterpolationContract() + { + Factory = Interpolate.RationalWithPoles, + Order = new[] { 1, 2, 6 }, + LinearBehavior = false, + PolynomialBehavior = true, + RationalBehavior = true + }; } } diff --git a/src/Managed/Interpolation/Algorithms/BulirschStoerRationalInterpolation.cs b/src/Managed/Interpolation/Algorithms/BulirschStoerRationalInterpolation.cs new file mode 100644 index 00000000..719ce499 --- /dev/null +++ b/src/Managed/Interpolation/Algorithms/BulirschStoerRationalInterpolation.cs @@ -0,0 +1,222 @@ +// +// 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.Interpolation.Algorithms +{ + using System; + using System.Collections.Generic; + + /// + /// Rational Interpolation (with poles) using Roland Bulirsch and Josef Stoer's Algorithm. + /// + /// + /// + /// This algorithm supports neither differentiation nor integration. + /// + /// + public class BulirschStoerRationalInterpolation : IInterpolation + { + /// + /// Sample Points t. + /// + private IList _points; + + /// + /// Spline Values x(t). + /// + private IList _values; + + /// + /// Initializes a new instance of the BulirschStoerRationalInterpolation class. + /// + public BulirschStoerRationalInterpolation() + { + } + + /// + /// Initializes a new instance of the BulirschStoerRationalInterpolation class. + /// + /// Sample Points t + /// Sample Values x(t) + public BulirschStoerRationalInterpolation( + IList samplePoints, + IList sampleValues) + { + Initialize(samplePoints, sampleValues); + } + + /// + /// Gets a value indicating whether the algorithm supports differentiation (interpolated derivative). + /// + /// + /// + bool IInterpolation.SupportsDifferentiation + { + get { return false; } + } + + /// + /// Gets a value indicating whether the algorithm supports integration (interpolated quadrature). + /// + /// + bool IInterpolation.SupportsIntegration + { + get { return false; } + } + + /// + /// Initialize the interpolation method with the given sample pairs. + /// + /// Sample Points t + /// Sample Values x(t) + public void Initialize( + IList samplePoints, + IList sampleValues) + { + if (null == samplePoints) + { + throw new ArgumentNullException("samplePoints"); + } + + if (null == sampleValues) + { + throw new ArgumentNullException("sampleValues"); + } + + if (samplePoints.Count != sampleValues.Count) + { + throw new ArgumentException(Properties.Resources.ArgumentVectorsSameLengths); + } + + _points = samplePoints; + _values = sampleValues; + } + + /// + /// Interpolate at point t. + /// + /// Point t to interpolate at. + /// Interpolated value x(t). + public double Interpolate(double t) + { + const double Tiny = 1.0e-25; + int n = _points.Count; + + double[] c = new double[n]; + double[] d = new double[n]; + + int nearestIndex = 0; + double nearestDistance = Math.Abs(t - _points[0]); + + for (int i = 0; i < n; i++) + { + double distance = Math.Abs(t - _points[i]); + if (distance.AlmostZero()) + { + return _values[i]; + } + + if (distance < nearestDistance) + { + nearestIndex = i; + nearestDistance = distance; + } + + c[i] = _values[i]; + d[i] = _values[i] + Tiny; + } + + double x = _values[nearestIndex]; + + for (int level = 1; level < n; level++) + { + for (int i = 0; i < n - level; i++) + { + double hp = _points[i + level] - t; + double ho = (_points[i] - t) * d[i] / hp; + + double den = ho - c[i + 1]; + if (den.AlmostZero()) + { + return double.NaN; // zero-div, singularity + } + + den = (c[i + 1] - d[i]) / den; + d[i] = c[i + 1] * den; + c[i] = ho * den; + } + + x += (2 * nearestIndex) < (n - level) + ? c[nearestIndex] + : d[--nearestIndex]; + } + + return x; + } + + /// + /// Differentiate at point t. + /// + /// Point t to interpolate at. + /// Interpolated first derivative at point t. + /// + /// + double IInterpolation.Differentiate(double t) + { + throw new NotSupportedException(); + } + + /// + /// Differentiate at point t. + /// + /// Point t to interpolate at. + /// Interpolated value x(t) + /// Interpolated second derivative at point t. + /// Interpolated first derivative at point t. + /// + /// + double IInterpolation.Differentiate( + double t, + out double interpolatedValue, + out double secondDerivative) + { + throw new NotSupportedException(); + } + + /// + /// Integrate up to point t. + /// + /// Right bound of the integration interval [a,t]. + /// Interpolated definite integral over the interval [a,t]. + /// + double IInterpolation.Integrate(double t) + { + throw new NotSupportedException(); + } + } +} \ No newline at end of file diff --git a/src/Managed/Interpolation/Algorithms/FloaterHormannRationalInterpolation.cs b/src/Managed/Interpolation/Algorithms/FloaterHormannRationalInterpolation.cs index 777ad64b..0a7d652a 100644 --- a/src/Managed/Interpolation/Algorithms/FloaterHormannRationalInterpolation.cs +++ b/src/Managed/Interpolation/Algorithms/FloaterHormannRationalInterpolation.cs @@ -32,7 +32,7 @@ namespace MathNet.Numerics.Interpolation.Algorithms using System.Collections.Generic; /// - /// Barycentric Rational Interpolation without poles, using Floater and Hormann's Algorithm. + /// Barycentric Rational Interpolation without poles, using Mike Floater and Kai Hormann's Algorithm. /// /// /// This algorithm neither supports differentiation nor integration. diff --git a/src/Managed/Interpolation/Algorithms/NevillePolynomialInterpolation.cs b/src/Managed/Interpolation/Algorithms/NevillePolynomialInterpolation.cs index 20cbc92e..bcb4f00e 100644 --- a/src/Managed/Interpolation/Algorithms/NevillePolynomialInterpolation.cs +++ b/src/Managed/Interpolation/Algorithms/NevillePolynomialInterpolation.cs @@ -95,7 +95,7 @@ namespace MathNet.Numerics.Interpolation.Algorithms } /// - /// Initialize the interpolation method with the given spline coefficients. + /// Initialize the interpolation method with the given sample pairs. /// /// Sample Points t /// Sample Values x(t) diff --git a/src/Managed/Interpolation/Interpolate.cs b/src/Managed/Interpolation/Interpolate.cs index 75da3c7c..b99fa2d2 100644 --- a/src/Managed/Interpolation/Interpolate.cs +++ b/src/Managed/Interpolation/Interpolate.cs @@ -90,5 +90,24 @@ namespace MathNet.Numerics.Interpolation method.Initialize(points, values); return method; } + + /// + /// Create a burlish stoer rational interpolation based on arbitrary points. + /// + /// The sample points t. Supports both lists and arrays. + /// The sample point values x(t). Supports both lists and arrays. + /// + /// An interpolation scheme optimized for the given sample points and values, + /// which can then be used to compute interpolations and extrapolations + /// on arbitrary points. + /// + public static IInterpolation RationalWithPoles( + IList points, + IList values) + { + BulirschStoerRationalInterpolation method = new BulirschStoerRationalInterpolation(); + method.Initialize(points, values); + return method; + } } } \ No newline at end of file diff --git a/src/Managed/Managed.csproj b/src/Managed/Managed.csproj index ff36bae7..66ca14aa 100644 --- a/src/Managed/Managed.csproj +++ b/src/Managed/Managed.csproj @@ -55,6 +55,7 @@ + diff --git a/src/Native/Native.csproj b/src/Native/Native.csproj index 2c1393ed..af0990e7 100644 --- a/src/Native/Native.csproj +++ b/src/Native/Native.csproj @@ -74,6 +74,9 @@ Interpolation\Algorithms\BarycentricInterpolation.cs + + Interpolation\Algorithms\BulirschStoerRationalInterpolation.cs + Interpolation\Algorithms\FloaterHormannRationalInterpolation.cs