diff --git a/src/Numerics/Interpolation/Barycentric.cs b/src/Numerics/Interpolation/Barycentric.cs index 495e4d50..c32476c5 100644 --- a/src/Numerics/Interpolation/Barycentric.cs +++ b/src/Numerics/Interpolation/Barycentric.cs @@ -57,7 +57,7 @@ namespace MathNet.Numerics.Interpolation if (x.Length < 1) { - throw new ArgumentOutOfRangeException("x"); + throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 1), "x"); } _x = x; @@ -77,7 +77,7 @@ namespace MathNet.Numerics.Interpolation if (x.Length < 1) { - throw new ArgumentOutOfRangeException("x"); + throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 1), "x"); } var weights = new double[x.Length]; @@ -101,11 +101,6 @@ namespace MathNet.Numerics.Interpolation throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - if (x.Length < 1) - { - throw new ArgumentOutOfRangeException("x"); - } - Sorting.Sort(x, y); return InterpolatePolynomialEquidistantSorted(x, y); } @@ -141,28 +136,28 @@ namespace MathNet.Numerics.Interpolation /// public static Barycentric InterpolateRationalFloaterHormannSorted(double[] x, double[] y, int order) { - var xx = (x as double[]) ?? x.ToArray(); - var yy = (y as double[]) ?? y.ToArray(); - - if (xx.Length != yy.Length) + if (x.Length != y.Length) { throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - if (0 > order || xx.Length <= order) + if (x.Length < 1) { - throw new ArgumentOutOfRangeException("order"); + throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 1), "x"); } - Sorting.Sort(xx, yy); + if (0 > order || x.Length <= order) + { + throw new ArgumentOutOfRangeException("order"); + } - var weights = new double[xx.Length]; + var weights = new double[x.Length]; // order: odd -> negative, even -> positive double sign = ((order & 0x1) == 0x1) ? -1.0 : 1.0; // compute barycentric weights - for (int k = 0; k < xx.Length; k++) + for (int k = 0; k < x.Length; k++) { double s = 0; for (int i = Math.Max(k - order, 0); i <= Math.Min(k, weights.Length - 1 - order); i++) @@ -172,7 +167,7 @@ namespace MathNet.Numerics.Interpolation { if (j != k) { - v = v/Math.Abs(xx[k] - xx[j]); + v = v/Math.Abs(x[k] - x[j]); } } @@ -183,7 +178,7 @@ namespace MathNet.Numerics.Interpolation sign = -sign; } - return new Barycentric(xx, yy, weights); + return new Barycentric(x, y, weights); } /// @@ -203,11 +198,6 @@ namespace MathNet.Numerics.Interpolation throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - if (0 > order || x.Length <= order) - { - throw new ArgumentOutOfRangeException("order"); - } - Sorting.Sort(x, y); return InterpolateRationalFloaterHormannSorted(x, y, order); } diff --git a/src/Numerics/Interpolation/BulirschStoerRationalInterpolation.cs b/src/Numerics/Interpolation/BulirschStoerRationalInterpolation.cs index bc4495d6..80a3583c 100644 --- a/src/Numerics/Interpolation/BulirschStoerRationalInterpolation.cs +++ b/src/Numerics/Interpolation/BulirschStoerRationalInterpolation.cs @@ -59,7 +59,7 @@ namespace MathNet.Numerics.Interpolation if (x.Length < 1) { - throw new ArgumentOutOfRangeException("x"); + throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 1), "x"); } _x = x; diff --git a/src/Numerics/Interpolation/CubicSpline.cs b/src/Numerics/Interpolation/CubicSpline.cs index 6367269f..f31268c3 100644 --- a/src/Numerics/Interpolation/CubicSpline.cs +++ b/src/Numerics/Interpolation/CubicSpline.cs @@ -60,6 +60,11 @@ namespace MathNet.Numerics.Interpolation throw new ArgumentException(Resources.ArgumentVectorsSameLength); } + if (x.Length < 2) + { + throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 2), "x"); + } + _x = x; _c0 = c0; _c1 = c1; @@ -80,7 +85,7 @@ namespace MathNet.Numerics.Interpolation if (x.Length < 2) { - throw new ArgumentOutOfRangeException("x"); + throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 2), "x"); } var c0 = new double[x.Length - 1]; @@ -113,7 +118,7 @@ namespace MathNet.Numerics.Interpolation if (x.Length < 2) { - throw new ArgumentOutOfRangeException("x"); + throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 2), "x"); } Sorting.Sort(x, y, firstDerivatives); @@ -142,7 +147,7 @@ namespace MathNet.Numerics.Interpolation if (x.Length < 5) { - throw new ArgumentOutOfRangeException("x"); + throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 5), "x"); } /* Prepare divided differences (diff) and weights (w) */ @@ -193,11 +198,6 @@ namespace MathNet.Numerics.Interpolation throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - if (x.Length < 5) - { - throw new ArgumentOutOfRangeException("x"); - } - Sorting.Sort(x, y); return InterpolateAkimaSorted(x, y); } @@ -227,7 +227,7 @@ namespace MathNet.Numerics.Interpolation if (x.Length < 2) { - throw new ArgumentOutOfRangeException("x"); + throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 2), "x"); } int n = x.Length; @@ -337,11 +337,6 @@ namespace MathNet.Numerics.Interpolation throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - if (x.Length < 2) - { - throw new ArgumentOutOfRangeException("x"); - } - Sorting.Sort(x, y); return InterpolateBoundariesSorted(x, y, leftBoundaryCondition, leftBoundary, rightBoundaryCondition, rightBoundary); } @@ -460,7 +455,7 @@ namespace MathNet.Numerics.Interpolation /// Interpolated value x(t). public double Interpolate(double t) { - int k = LeftBracketIndex(t); + int k = LeftSegmentIndex(t); var x = t - _x[k]; return _c0[k] + x*(_c1[k] + x*(_c2[k] + x*_c3[k])); } @@ -472,7 +467,7 @@ namespace MathNet.Numerics.Interpolation /// Interpolated first derivative at point t. public double Differentiate(double t) { - int k = LeftBracketIndex(t); + int k = LeftSegmentIndex(t); var x = t - _x[k]; return _c1[k] + x*(2*_c2[k] + x*3*_c3[k]); } @@ -484,7 +479,7 @@ namespace MathNet.Numerics.Interpolation /// Interpolated second derivative at point t. public double Differentiate2(double t) { - int k = LeftBracketIndex(t); + int k = LeftSegmentIndex(t); var x = t - _x[k]; return 2*_c2[k] + x*6*_c3[k]; } @@ -495,7 +490,7 @@ namespace MathNet.Numerics.Interpolation /// Point t to integrate at. public double Integrate(double t) { - int k = LeftBracketIndex(t); + int k = LeftSegmentIndex(t); var x = t - _x[k]; return _indefiniteIntegral.Value[k] + x*(_c0[k] + x*(_c1[k]/2 + x*(_c2[k]/3 + x*_c3[k]/4))); } @@ -523,11 +518,11 @@ namespace MathNet.Numerics.Interpolation } /// - /// Find the index of the greatest sample point smaller than t. + /// Find the index of the greatest sample point smaller than t, + /// or the left index of the closest segment for extrapolation. /// - int LeftBracketIndex(double t) + int LeftSegmentIndex(double t) { - // Binary search in the [ t[0], ..., t[n-2] ] (t[n-1] is not included) int low = 0; int high = _x.Length - 1; while (low != high - 1) diff --git a/src/Numerics/Interpolation/LinearSpline.cs b/src/Numerics/Interpolation/LinearSpline.cs index be7a387e..20d0fb8c 100644 --- a/src/Numerics/Interpolation/LinearSpline.cs +++ b/src/Numerics/Interpolation/LinearSpline.cs @@ -56,6 +56,11 @@ namespace MathNet.Numerics.Interpolation throw new ArgumentException(Resources.ArgumentVectorsSameLength); } + if (x.Length < 2) + { + throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 2), "x"); + } + _x = x; _c0 = c0; _c1 = c1; @@ -72,6 +77,11 @@ namespace MathNet.Numerics.Interpolation throw new ArgumentException(Resources.ArgumentVectorsSameLength); } + if (x.Length < 2) + { + throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 2), "x"); + } + var c1 = new double[x.Length - 1]; for (int i = 0; i < c1.Length; i++) { @@ -128,7 +138,7 @@ namespace MathNet.Numerics.Interpolation /// Interpolated value x(t). public double Interpolate(double t) { - int k = LeftBracketIndex(t); + int k = LeftSegmentIndex(t); return _c0[k] + (t - _x[k])*_c1[k]; } @@ -139,7 +149,7 @@ namespace MathNet.Numerics.Interpolation /// Interpolated first derivative at point t. public double Differentiate(double t) { - int k = LeftBracketIndex(t); + int k = LeftSegmentIndex(t); return _c1[k]; } @@ -159,7 +169,7 @@ namespace MathNet.Numerics.Interpolation /// Point t to integrate at. public double Integrate(double t) { - int k = LeftBracketIndex(t); + int k = LeftSegmentIndex(t); var x = t - _x[k]; return _indefiniteIntegral.Value[k] + x*(_c0[k] + x*_c1[k]/2); } @@ -187,11 +197,11 @@ namespace MathNet.Numerics.Interpolation } /// - /// Find the index of the greatest sample point smaller than t. + /// Find the index of the greatest sample point smaller than t, + /// or the left index of the closest segment for extrapolation. /// - int LeftBracketIndex(double t) + int LeftSegmentIndex(double t) { - // Binary search in the [ t[0], ..., t[n-2] ] (t[n-1] is not included) int low = 0; int high = _x.Length - 1; while (low != high - 1) diff --git a/src/Numerics/Interpolation/NevillePolynomialInterpolation.cs b/src/Numerics/Interpolation/NevillePolynomialInterpolation.cs index 9f2ad234..8c74b21d 100644 --- a/src/Numerics/Interpolation/NevillePolynomialInterpolation.cs +++ b/src/Numerics/Interpolation/NevillePolynomialInterpolation.cs @@ -64,7 +64,7 @@ namespace MathNet.Numerics.Interpolation if (x.Length < 1) { - throw new ArgumentOutOfRangeException("x"); + throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 1), "x"); } for (var i = 1; i < x.Length; ++i) diff --git a/src/Numerics/Interpolation/QuadraticSpline.cs b/src/Numerics/Interpolation/QuadraticSpline.cs index 866fd000..2edb7867 100644 --- a/src/Numerics/Interpolation/QuadraticSpline.cs +++ b/src/Numerics/Interpolation/QuadraticSpline.cs @@ -56,6 +56,11 @@ namespace MathNet.Numerics.Interpolation throw new ArgumentException(Resources.ArgumentVectorsSameLength); } + if (x.Length < 2) + { + throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 2), "x"); + } + _x = x; _c0 = c0; _c1 = c1; @@ -86,7 +91,7 @@ namespace MathNet.Numerics.Interpolation /// Interpolated value x(t). public double Interpolate(double t) { - int k = LeftBracketIndex(t); + int k = LeftSegmentIndex(t); var x = t - _x[k]; return _c0[k] + x*(_c1[k] + x*_c2[k]); } @@ -98,7 +103,7 @@ namespace MathNet.Numerics.Interpolation /// Interpolated first derivative at point t. public double Differentiate(double t) { - int k = LeftBracketIndex(t); + int k = LeftSegmentIndex(t); return _c1[k] + (t - _x[k])*2*_c2[k]; } @@ -109,7 +114,7 @@ namespace MathNet.Numerics.Interpolation /// Interpolated second derivative at point t. public double Differentiate2(double t) { - int k = LeftBracketIndex(t); + int k = LeftSegmentIndex(t); return 2*_c2[k]; } @@ -119,7 +124,7 @@ namespace MathNet.Numerics.Interpolation /// Point t to integrate at. public double Integrate(double t) { - int k = LeftBracketIndex(t); + int k = LeftSegmentIndex(t); var x = t - _x[k]; return _indefiniteIntegral.Value[k] + x*(_c0[k] + x*(_c1[k]/2 + x*_c2[k]/3)); } @@ -147,11 +152,11 @@ namespace MathNet.Numerics.Interpolation } /// - /// Find the index of the greatest sample point smaller than t. + /// Find the index of the greatest sample point smaller than t, + /// or the left index of the closest segment for extrapolation. /// - int LeftBracketIndex(double t) + int LeftSegmentIndex(double t) { - // Binary search in the [ t[0], ..., t[n-2] ] (t[n-1] is not included) int low = 0; int high = _x.Length - 1; while (low != high - 1) diff --git a/src/Numerics/Interpolation/StepInterpolation.cs b/src/Numerics/Interpolation/StepInterpolation.cs index 532f92da..03c29291 100644 --- a/src/Numerics/Interpolation/StepInterpolation.cs +++ b/src/Numerics/Interpolation/StepInterpolation.cs @@ -56,6 +56,11 @@ namespace MathNet.Numerics.Interpolation throw new ArgumentException(Resources.ArgumentVectorsSameLength); } + if (x.Length < 1) + { + throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 1), "x"); + } + _x = x; _y = sy; _indefiniteIntegral = new Lazy(ComputeIndefiniteIntegral); diff --git a/src/UnitTests/InterpolationTests/AkimaSplineTest.cs b/src/UnitTests/InterpolationTests/AkimaSplineTest.cs index c092232f..e8d937b8 100644 --- a/src/UnitTests/InterpolationTests/AkimaSplineTest.cs +++ b/src/UnitTests/InterpolationTests/AkimaSplineTest.cs @@ -92,5 +92,13 @@ namespace MathNet.Numerics.UnitTests.InterpolationTests Assert.AreEqual(ytest[i], it.Interpolate(xtest[i]), 1e-15, "Linear with {0} samples, sample {1}", samples, i); } } + + [Test] + public void FewSamples() + { + Assert.That(() => CubicSpline.InterpolateAkima(new double[0], new double[0]), Throws.ArgumentException); + Assert.That(() => CubicSpline.InterpolateAkima(new double[4], new double[4]), Throws.ArgumentException); + Assert.That(CubicSpline.InterpolateAkima(new[] { 1.0, 2.0, 3.0, 4.0, 5.0 }, new[] { 2.0, 2.0, 2.0, 2.0, 2.0 }).Interpolate(1.0), Is.EqualTo(2.0)); + } } } diff --git a/src/UnitTests/InterpolationTests/BulirschStoerRationalTest.cs b/src/UnitTests/InterpolationTests/BulirschStoerRationalTest.cs index 2370a46e..fdae0563 100644 --- a/src/UnitTests/InterpolationTests/BulirschStoerRationalTest.cs +++ b/src/UnitTests/InterpolationTests/BulirschStoerRationalTest.cs @@ -92,6 +92,13 @@ namespace MathNet.Numerics.UnitTests.InterpolationTests Assert.AreEqual(x, interpolation.Interpolate(t), maxAbsoluteError, "Interpolation at {0}", t); } + [Test] + public void FewSamples() + { + Assert.That(() => BulirschStoerRationalInterpolation.Interpolate(new double[0], new double[0]), Throws.ArgumentException); + Assert.That(BulirschStoerRationalInterpolation.Interpolate(new[] { 1.0 }, new[] { 2.0 }).Interpolate(1.0), Is.EqualTo(2.0)); + } + // NOTE: No test for the linear case because this algorithms is incredibly bad at this. } } diff --git a/src/UnitTests/InterpolationTests/CubicSplineTest.cs b/src/UnitTests/InterpolationTests/CubicSplineTest.cs index b0364afe..106c6f71 100644 --- a/src/UnitTests/InterpolationTests/CubicSplineTest.cs +++ b/src/UnitTests/InterpolationTests/CubicSplineTest.cs @@ -176,6 +176,14 @@ namespace MathNet.Numerics.UnitTests.InterpolationTests } } + [Test] + public void FewSamples() + { + Assert.That(() => CubicSpline.InterpolateNatural(new double[0], new double[0]), Throws.ArgumentException); + Assert.That(() => CubicSpline.InterpolateNatural(new double[1], new double[1]), Throws.ArgumentException); + Assert.That(CubicSpline.InterpolateNatural(new[] { 1.0, 2.0 }, new[] { 2.0, 2.0 }).Interpolate(1.0), Is.EqualTo(2.0)); + } + #if !NET35 && !PORTABLE [Test] public void InterpolateAkimaSorted_MustBeThreadSafe_GitHub219([Values(8, 32, 256, 1024)] int samples) diff --git a/src/UnitTests/InterpolationTests/EquidistantPolynomialTest.cs b/src/UnitTests/InterpolationTests/EquidistantPolynomialTest.cs index c1ef7f0e..fbfc426a 100644 --- a/src/UnitTests/InterpolationTests/EquidistantPolynomialTest.cs +++ b/src/UnitTests/InterpolationTests/EquidistantPolynomialTest.cs @@ -94,5 +94,12 @@ namespace MathNet.Numerics.UnitTests.InterpolationTests Assert.AreEqual(ytest[i], it.Interpolate(xtest[i]), 1e-12, "Linear with {0} samples, sample {1}", samples, i); } } + + [Test] + public void FewSamples() + { + Assert.That(() => Barycentric.InterpolatePolynomialEquidistant(new double[0], new double[0]), Throws.ArgumentException); + Assert.That(Barycentric.InterpolatePolynomialEquidistant(new[] { 1.0 }, new[] { 2.0 }).Interpolate(1.0), Is.EqualTo(2.0)); + } } } diff --git a/src/UnitTests/InterpolationTests/FloaterHormannRationalTest.cs b/src/UnitTests/InterpolationTests/FloaterHormannRationalTest.cs index 1aa9380c..8c444b9a 100644 --- a/src/UnitTests/InterpolationTests/FloaterHormannRationalTest.cs +++ b/src/UnitTests/InterpolationTests/FloaterHormannRationalTest.cs @@ -119,5 +119,12 @@ namespace MathNet.Numerics.UnitTests.InterpolationTests Assert.AreEqual(ytest[i], it.Interpolate(xtest[i]), 1e-14, "Linear with {0} samples, sample {1}", samples, i); } } + + [Test] + public void FewSamples() + { + Assert.That(() => Barycentric.InterpolateRationalFloaterHormann(new double[0], new double[0]), Throws.ArgumentException); + Assert.That(Barycentric.InterpolateRationalFloaterHormann(new[] { 1.0 }, new[] { 2.0 }).Interpolate(1.0), Is.EqualTo(2.0)); + } } } diff --git a/src/UnitTests/InterpolationTests/LinearSplineTest.cs b/src/UnitTests/InterpolationTests/LinearSplineTest.cs index 44e07b20..c14dc2bc 100644 --- a/src/UnitTests/InterpolationTests/LinearSplineTest.cs +++ b/src/UnitTests/InterpolationTests/LinearSplineTest.cs @@ -131,5 +131,13 @@ namespace MathNet.Numerics.UnitTests.InterpolationTests Assert.AreEqual(ytest[i], ip.Interpolate(xtest[i]), 1e-15, "Linear with {0} samples, sample {1}", samples, i); } } + + [Test] + public void FewSamples() + { + Assert.That(() => LinearSpline.Interpolate(new double[0], new double[0]), Throws.ArgumentException); + Assert.That(() => LinearSpline.Interpolate(new double[1], new double[1]), Throws.ArgumentException); + Assert.That(LinearSpline.Interpolate(new[] { 1.0, 2.0 }, new[] { 2.0, 2.0 }).Interpolate(1.0), Is.EqualTo(2.0)); + } } } diff --git a/src/UnitTests/InterpolationTests/NevillePolynomialTest.cs b/src/UnitTests/InterpolationTests/NevillePolynomialTest.cs index e1544277..a568034a 100644 --- a/src/UnitTests/InterpolationTests/NevillePolynomialTest.cs +++ b/src/UnitTests/InterpolationTests/NevillePolynomialTest.cs @@ -146,5 +146,12 @@ namespace MathNet.Numerics.UnitTests.InterpolationTests var actual = interpolation.Interpolate(Math.Log(value)); Assert.That(actual, Is.Not.NaN); } + + [Test] + public void FewSamples() + { + Assert.That(() => NevillePolynomialInterpolation.Interpolate(new double[0], new double[0]), Throws.ArgumentException); + Assert.That(NevillePolynomialInterpolation.Interpolate(new[] { 1.0 }, new[] { 2.0 }).Interpolate(1.0), Is.EqualTo(2.0)); + } } } diff --git a/src/UnitTests/InterpolationTests/StepInterpolationTest.cs b/src/UnitTests/InterpolationTests/StepInterpolationTest.cs index 15a4c930..fa85c938 100644 --- a/src/UnitTests/InterpolationTests/StepInterpolationTest.cs +++ b/src/UnitTests/InterpolationTests/StepInterpolationTest.cs @@ -28,6 +28,7 @@ // OTHER DEALINGS IN THE SOFTWARE. // +using System; using MathNet.Numerics.Interpolation; using NUnit.Framework; @@ -87,5 +88,12 @@ namespace MathNet.Numerics.UnitTests.InterpolationTests Assert.AreEqual(_y[i], ip.Interpolate(_t[i]), "A Exact Point " + i); } } + + [Test] + public void FewSamples() + { + Assert.That(() => StepInterpolation.Interpolate(new double[0], new double[0]), Throws.ArgumentException); + Assert.That(StepInterpolation.Interpolate(new[] { 1.0 }, new[] { 2.0 }).Interpolate(1.0), Is.EqualTo(2.0)); + } } }