diff --git a/src/Numerics/Interpolation/CubicSpline.cs b/src/Numerics/Interpolation/CubicSpline.cs
index f2284506..5da1a2e6 100644
--- a/src/Numerics/Interpolation/CubicSpline.cs
+++ b/src/Numerics/Interpolation/CubicSpline.cs
@@ -210,6 +210,85 @@ namespace MathNet.Numerics.Interpolation
return InterpolateAkimaInplace(x.ToArray(), y.ToArray());
}
+ ///
+ /// Create a piecewise cubic Hermite interpolating polynomial from an unsorted set of (x,y) value pairs.
+ ///
+ public static CubicSpline InterpolatePchipSorted(double[] x, double[] y)
+ {
+ if (x.Length != y.Length)
+ {
+ throw new ArgumentException("All vectors must have the same dimensionality.");
+ }
+ // TODO: minsize?
+ if (x.Length < 5)
+ {
+ throw new ArgumentException("The given array is too small. It must be at least 5 long.", nameof(x));
+ }
+
+ var h = new double[x.Length - 1];
+ // The slopes between each x.
+ var m = new double[x.Length - 1];
+ // The slope of the interpolant at each x.
+ var d = new double[x.Length];
+
+ for (var k = 0; k < x.Length - 1; ++k)
+ {
+ h[k] = x[k + 1] - x[k];
+ m[k] = (y[k + 1] - y[k]) / h[k];
+ if (k == 0)
+ continue;
+ if (m[k].AlmostEqual(0.0) || m[k - 1].AlmostEqual(0.0) || Math.Sign(m[k]) != Math.Sign(m[k-1]))
+ d[k] = 0;
+ else
+ {
+ // Weighted harmonic mean of each slope.
+ var w1 = 2 * h[k] + h[k - 1];
+ var w2 = h[k] + 2 * h[k - 1];
+ d[k] = (w1 + w2) / (w1 / m[k - 1] + w2 / m[k]);
+ }
+ }
+
+ // Special case end-points.
+ d[0] = PchipEndPoints(h[0], h[1], m[0], m[1]);
+ d[d.Length - 1] = PchipEndPoints(h[h.Length - 1], h[h.Length - 2], m[m.Length - 1], m[m.Length - 2]);
+
+ return InterpolateHermiteSorted(x, y, d);
+ }
+
+ private static double PchipEndPoints(double h0, double h1, double m0, double m1)
+ {
+ var d = ((2 * h0 + h1) * m0 - h0 * m1) / (h0 + h1);
+ if (Math.Sign(d) != Math.Sign(m0))
+ return 0.0;
+ if (Math.Sign(m0) != Math.Sign(m1) && (Math.Abs(d) > 3 * Math.Abs(m0)))
+ return 3 * m0;
+ return d;
+ }
+
+ ///
+ /// Create a piecewise cubic Hermite interpolating polynomial from an unsorted set of (x,y) value pairs.
+ /// WARNING: Works in-place and can thus causes the data array to be reordered.
+ ///
+ public static CubicSpline InterpolatePchipInplace(double[] x, double[] y)
+ {
+ if (x.Length != y.Length)
+ {
+ throw new ArgumentException("All vectors must have the same dimensionality.");
+ }
+
+ Sorting.Sort(x, y);
+ return InterpolatePchipSorted(x, y);
+ }
+
+ ///
+ /// Create a piecewise cubic Hermite interpolating polynomial from an unsorted set of (x,y) value pairs.
+ ///
+ public static CubicSpline InterpolatePchip(IEnumerable x, IEnumerable y)
+ {
+ // note: we must make a copy, even if the input was arrays already
+ return InterpolatePchipInplace(x.ToArray(), y.ToArray());
+ }
+
///
/// Create a cubic spline interpolation from a set of (x,y) value pairs, sorted ascendingly by x,
/// and custom boundary/termination conditions.