/// <summary> /// Create a cubic spline interpolation from an unsorted set of (x,y) value pairs and custom boundary/termination conditions. /// </summary> public static CubicSpline InterpolateBoundaries(IEnumerable <double> x, IEnumerable <double> y, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { // note: we must make a copy, even if the input was arrays already return(InterpolateBoundariesInplace(x.ToArray(), y.ToArray(), leftBoundaryCondition, leftBoundary, rightBoundaryCondition, rightBoundary)); }
/// <summary> /// Initialize the interpolation method with the given spline coefficients (sorted by the sample points t). /// </summary> /// <param name="samplePoints">Sample Points t, sorted ascending.</param> /// <param name="sampleValues">Sample Values x(t)</param> /// <param name="leftBoundaryCondition">Condition of the left boundary.</param> /// <param name="leftBoundary">Left boundary value. Ignored in the parabolic case.</param> /// <param name="rightBoundaryCondition">Condition of the right boundary.</param> /// <param name="rightBoundary">Right boundary value. Ignored in the parabolic case.</param> public void Initialize( IList <double> samplePoints, IList <double> sampleValues, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { double[] derivatives = EvaluateSplineDerivatives( samplePoints, sampleValues, leftBoundaryCondition, leftBoundary, rightBoundaryCondition, rightBoundary); _spline.Initialize(samplePoints, sampleValues, derivatives); }
/// <summary> /// Evaluate the spline coefficients as used /// internally by this interpolation algorithm. /// </summary> /// <param name="samplePoints">Sample Points t, sorted ascending.</param> /// <param name="sampleValues">Sample Values x(t)</param> /// <param name="leftBoundaryCondition">Condition of the left boundary.</param> /// <param name="leftBoundary">Left boundary value. Ignored in the parabolic case.</param> /// <param name="rightBoundaryCondition">Condition of the right boundary.</param> /// <param name="rightBoundary">Right boundary value. Ignored in the parabolic case.</param> /// <returns>Spline Coefficient Vector</returns> public static double[] EvaluateSplineCoefficients( IList <double> samplePoints, IList <double> sampleValues, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { double[] derivatives = EvaluateSplineDerivatives( samplePoints, sampleValues, leftBoundaryCondition, leftBoundary, rightBoundaryCondition, rightBoundary); return(CubicHermiteSplineInterpolation.EvaluateSplineCoefficients(samplePoints, sampleValues, derivatives)); }
/// <summary> /// Create a cubic spline interpolation from an unsorted set of (x,y) value pairs and custom boundary/termination conditions. /// WARNING: Works in-place and can thus causes the data array to be reordered. /// </summary> public static CubicSpline InterpolateBoundariesInplace(double[] x, double[] y, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { if (x.Length != y.Length) { throw new ArgumentException(Resources.ArgumentVectorsSameLength); } Sorting.Sort(x, y); return(InterpolateBoundariesSorted(x, y, leftBoundaryCondition, leftBoundary, rightBoundaryCondition, rightBoundary)); }
/// <summary> /// Initializes a new instance of the CubicSplineInterpolation class. /// </summary> /// <param name="samplePoints">Sample Points t, sorted ascending.</param> /// <param name="sampleValues">Sample Values x(t)</param> /// <param name="leftBoundaryCondition">Condition of the left boundary.</param> /// <param name="leftBoundary">Left boundary value. Ignored in the parabolic case.</param> /// <param name="rightBoundaryCondition">Condition of the right boundary.</param> /// <param name="rightBoundary">Right boundary value. Ignored in the parabolic case.</param> public CubicSplineInterpolation( IList <double> samplePoints, IList <double> sampleValues, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { _spline = new CubicHermiteSplineInterpolation(); Initialize( samplePoints, sampleValues, leftBoundaryCondition, leftBoundary, rightBoundaryCondition, rightBoundary); }
/// <summary> /// Create a cubic spline interpolation from an unsorted set of (x,y) value pairs and custom boundary/termination conditions. /// WARNING: Works in-place and can thus causes the data array to be reordered. /// </summary> public static CubicSpline InterpolateBoundariesInplace(double[] x, double[] y, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { if (x.Length != y.Length) { throw new ArgumentException("All vectors must have the same dimensionality."); } Sorting.Sort(x, y); return(InterpolateBoundariesSorted(x, y, leftBoundaryCondition, leftBoundary, rightBoundaryCondition, rightBoundary)); }
/// <summary> /// Initializes a new instance of the CubicSplineInterpolation class. /// </summary> /// <param name="samplePoints">Sample Points t, sorted ascending.</param> /// <param name="sampleValues">Sample Values x(t)</param> /// <param name="leftBoundaryCondition">Condition of the left boundary.</param> /// <param name="leftBoundary">Left boundary value. Ignored in the parabolic case.</param> /// <param name="rightBoundaryCondition">Condition of the right boundary.</param> /// <param name="rightBoundary">Right boundary value. Ignored in the parabolic case.</param> public CubicSplineInterpolation( IList<double> samplePoints, IList<double> sampleValues, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { _spline = new CubicHermiteSplineInterpolation(); Initialize( samplePoints, sampleValues, leftBoundaryCondition, leftBoundary, rightBoundaryCondition, rightBoundary); }
CreateCubicSpline( IList <double> points, IList <double> values, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { CubicSplineInterpolation method = new CubicSplineInterpolation(); method.Init( points, values, leftBoundaryCondition, leftBoundary, rightBoundaryCondition, rightBoundary); return(method); }
/// <summary> /// Create a cubic spline interpolation from an unsorted set of (x,y) value pairs and custom boundary/termination conditions. /// </summary> public static CubicSpline InterpolateBoundaries(IEnumerable<double> x, IEnumerable<double> y, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { // note: we must make a copy, even if the input was arrays already return InterpolateBoundariesInplace(x.ToArray(), y.ToArray(), leftBoundaryCondition, leftBoundary, rightBoundaryCondition, rightBoundary); }
/// <summary> /// Create a cubic spline interpolation from an unsorted set of (x,y) value pairs and custom boundary/termination conditions. /// WARNING: Works in-place and can thus causes the data array to be reordered. /// </summary> public static CubicSpline InterpolateBoundariesInplace(double[] x, double[] y, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { if (x.Length != y.Length) { throw new ArgumentException(Resources.ArgumentVectorsSameLength); } Sorting.Sort(x, y); return InterpolateBoundariesSorted(x, y, leftBoundaryCondition, leftBoundary, rightBoundaryCondition, rightBoundary); }
/// <summary> /// Create a cubic spline interpolation from a set of (x,y) value pairs, sorted ascendingly by x, /// and custom boundary/termination conditions. /// </summary> public static CubicSpline InterpolateBoundariesSorted(double[] x, double[] y, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { if (x.Length != y.Length) { throw new ArgumentException(Resources.ArgumentVectorsSameLength); } if (x.Length < 2) { throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 2), "x"); } int n = x.Length; // normalize special cases if ((n == 2) && (leftBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated) && (rightBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated)) { leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative; leftBoundary = 0d; rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative; rightBoundary = 0d; } if (leftBoundaryCondition == SplineBoundaryCondition.Natural) { leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative; leftBoundary = 0d; } if (rightBoundaryCondition == SplineBoundaryCondition.Natural) { rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative; rightBoundary = 0d; } var a1 = new double[n]; var a2 = new double[n]; var a3 = new double[n]; var b = new double[n]; // Left Boundary switch (leftBoundaryCondition) { case SplineBoundaryCondition.ParabolicallyTerminated: a1[0] = 0; a2[0] = 1; a3[0] = 1; b[0] = 2*(y[1] - y[0])/(x[1] - x[0]); break; case SplineBoundaryCondition.FirstDerivative: a1[0] = 0; a2[0] = 1; a3[0] = 0; b[0] = leftBoundary; break; case SplineBoundaryCondition.SecondDerivative: a1[0] = 0; a2[0] = 2; a3[0] = 1; b[0] = (3*((y[1] - y[0])/(x[1] - x[0]))) - (0.5*leftBoundary*(x[1] - x[0])); break; default: throw new NotSupportedException(Resources.InvalidLeftBoundaryCondition); } // Central Conditions for (int i = 1; i < x.Length - 1; i++) { a1[i] = x[i + 1] - x[i]; a2[i] = 2*(x[i + 1] - x[i - 1]); a3[i] = x[i] - x[i - 1]; b[i] = (3*(y[i] - y[i - 1])/(x[i] - x[i - 1])*(x[i + 1] - x[i])) + (3*(y[i + 1] - y[i])/(x[i + 1] - x[i])*(x[i] - x[i - 1])); } // Right Boundary switch (rightBoundaryCondition) { case SplineBoundaryCondition.ParabolicallyTerminated: a1[n - 1] = 1; a2[n - 1] = 1; a3[n - 1] = 0; b[n - 1] = 2*(y[n - 1] - y[n - 2])/(x[n - 1] - x[n - 2]); break; case SplineBoundaryCondition.FirstDerivative: a1[n - 1] = 0; a2[n - 1] = 1; a3[n - 1] = 0; b[n - 1] = rightBoundary; break; case SplineBoundaryCondition.SecondDerivative: a1[n - 1] = 1; a2[n - 1] = 2; a3[n - 1] = 0; b[n - 1] = (3*(y[n - 1] - y[n - 2])/(x[n - 1] - x[n - 2])) + (0.5*rightBoundary*(x[n - 1] - x[n - 2])); break; default: throw new NotSupportedException(Resources.InvalidRightBoundaryCondition); } // Build Spline double[] dd = SolveTridiagonal(a1, a2, a3, b); return InterpolateHermiteSorted(x, y, dd); }
/// <summary> /// Evaluate the spline derivatives as used /// internally by this interpolation algorithm. /// </summary> /// <param name="samplePoints">Sample Points t, sorted ascending.</param> /// <param name="sampleValues">Sample Values x(t)</param> /// <param name="leftBoundaryCondition">Condition of the left boundary.</param> /// <param name="leftBoundary">Left boundary value. Ignored in the parabolic case.</param> /// <param name="rightBoundaryCondition">Condition of the right boundary.</param> /// <param name="rightBoundary">Right boundary value. Ignored in the parabolic case.</param> /// <returns>Spline Derivative Vector</returns> public static double[] EvaluateSplineDerivatives( IList<double> samplePoints, IList<double> sampleValues, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { if (null == samplePoints) { throw new ArgumentNullException("samplePoints"); } if (null == sampleValues) { throw new ArgumentNullException("sampleValues"); } if (samplePoints.Count < 2) { throw new ArgumentOutOfRangeException("samplePoints"); } if (samplePoints.Count != sampleValues.Count) { throw new ArgumentException(Resources.ArgumentVectorsSameLength); } int n = samplePoints.Count; // normalize special cases if ((n == 2) && (leftBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated) && (rightBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated)) { leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative; leftBoundary = 0d; rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative; rightBoundary = 0d; } if (leftBoundaryCondition == SplineBoundaryCondition.Natural) { leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative; leftBoundary = 0d; } if (rightBoundaryCondition == SplineBoundaryCondition.Natural) { rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative; rightBoundary = 0d; } double[] a1 = new double[n]; double[] a2 = new double[n]; double[] a3 = new double[n]; double[] b = new double[n]; // Left Boundary switch (leftBoundaryCondition) { case SplineBoundaryCondition.ParabolicallyTerminated: a1[0] = 0; a2[0] = 1; a3[0] = 1; b[0] = 2 * (sampleValues[1] - sampleValues[0]) / (samplePoints[1] - samplePoints[0]); break; case SplineBoundaryCondition.FirstDerivative: a1[0] = 0; a2[0] = 1; a3[0] = 0; b[0] = leftBoundary; break; case SplineBoundaryCondition.SecondDerivative: a1[0] = 0; a2[0] = 2; a3[0] = 1; b[0] = (3 * ((sampleValues[1] - sampleValues[0]) / (samplePoints[1] - samplePoints[0]))) - (0.5 * leftBoundary * (samplePoints[1] - samplePoints[0])); break; default: throw new NotSupportedException(Resources.InvalidLeftBoundaryCondition); } // Central Conditions for (int i = 1; i < samplePoints.Count - 1; i++) { a1[i] = samplePoints[i + 1] - samplePoints[i]; a2[i] = 2 * (samplePoints[i + 1] - samplePoints[i - 1]); a3[i] = samplePoints[i] - samplePoints[i - 1]; b[i] = (3 * (sampleValues[i] - sampleValues[i - 1]) / (samplePoints[i] - samplePoints[i - 1]) * (samplePoints[i + 1] - samplePoints[i])) + (3 * (sampleValues[i + 1] - sampleValues[i]) / (samplePoints[i + 1] - samplePoints[i]) * (samplePoints[i] - samplePoints[i - 1])); } // Right Boundary switch (rightBoundaryCondition) { case SplineBoundaryCondition.ParabolicallyTerminated: a1[n - 1] = 1; a2[n - 1] = 1; a3[n - 1] = 0; b[n - 1] = 2 * (sampleValues[n - 1] - sampleValues[n - 2]) / (samplePoints[n - 1] - samplePoints[n - 2]); break; case SplineBoundaryCondition.FirstDerivative: a1[n - 1] = 0; a2[n - 1] = 1; a3[n - 1] = 0; b[n - 1] = rightBoundary; break; case SplineBoundaryCondition.SecondDerivative: a1[n - 1] = 1; a2[n - 1] = 2; a3[n - 1] = 0; b[n - 1] = (3 * (sampleValues[n - 1] - sampleValues[n - 2]) / (samplePoints[n - 1] - samplePoints[n - 2])) + (0.5 * rightBoundary * (samplePoints[n - 1] - samplePoints[n - 2])); break; default: throw new NotSupportedException(Resources.InvalidRightBoundaryCondition); } // Build Spline return SolveTridiagonal(a1, a2, a3, b); }
/// <summary> /// Initialize the interpolation method with the given samples. /// </summary> /// <param name="t">Points t</param> /// <param name="x">Values x(t)</param> /// <param name="leftBoundaryCondition">Condition of the left boundary.</param> /// <param name="leftBoundary">Left boundary value. Ignored in the parabolic case.</param> /// <param name="rightBoundaryCondition">Condition of the right boundary.</param> /// <param name="rightBoundary">Right boundary value. Ignored in the parabolic case.</param> public void Init( IList<double> t, IList<double> x, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary ) { if(null == t) { throw new ArgumentNullException("t"); } if(null == x) { throw new ArgumentNullException("x"); } if(t.Count < 2) { throw new ArgumentOutOfRangeException("t"); } if(t.Count != x.Count) { throw new ArgumentException(Properties.Resources.ArgumentVectorsSameLengths, "x"); } int n = t.Count; double[] tt = new double[n]; t.CopyTo(tt, 0); double[] xx = new double[n]; x.CopyTo(xx, 0); Sorting.Sort(tt, xx); // normalize special cases if((n == 2) && (leftBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated) && (rightBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated)) { leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative; leftBoundary = 0d; rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative; rightBoundary = 0d; } if(leftBoundaryCondition == SplineBoundaryCondition.Natural) { leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative; leftBoundary = 0d; } if(rightBoundaryCondition == SplineBoundaryCondition.Natural) { rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative; rightBoundary = 0d; } double[] a1 = new double[n]; double[] a2 = new double[n]; double[] a3 = new double[n]; double[] b = new double[n]; // Left Boundary switch(leftBoundaryCondition) { case SplineBoundaryCondition.ParabolicallyTerminated: a1[0] = 0; a2[0] = 1; a3[0] = 1; b[0] = 2 * (xx[1] - xx[0]) / (tt[1] - tt[0]); break; case SplineBoundaryCondition.FirstDerivative: a1[0] = 0; a2[0] = 1; a3[0] = 0; b[0] = leftBoundary; break; case SplineBoundaryCondition.SecondDerivative: a1[0] = 0; a2[0] = 2; a3[0] = 1; b[0] = 3 * (xx[1] - xx[0]) / (tt[1] - tt[0]) - 0.5 * leftBoundary * (tt[1] - tt[0]); break; default: throw new NotSupportedException(Properties.Resources.InvalidLeftBoundaryCondition); } // Central Conditions for(int i = 1; i < tt.Length - 1; i++) { a1[i] = tt[i + 1] - tt[i]; a2[i] = 2 * (tt[i + 1] - tt[i - 1]); a3[i] = tt[i] - tt[i - 1]; b[i] = 3 * (xx[i] - xx[i - 1]) / (tt[i] - tt[i - 1]) * (tt[i + 1] - tt[i]) + 3 * (xx[i + 1] - xx[i]) / (tt[i + 1] - tt[i]) * (tt[i] - tt[i - 1]); } // Right Boundary switch(rightBoundaryCondition) { case SplineBoundaryCondition.ParabolicallyTerminated: a1[n - 1] = 1; a2[n - 1] = 1; a3[n - 1] = 0; b[n - 1] = 2 * (xx[n - 1] - xx[n - 2]) / (tt[n - 1] - tt[n - 2]); break; case SplineBoundaryCondition.FirstDerivative: a1[n - 1] = 0; a2[n - 1] = 1; a3[n - 1] = 0; b[n - 1] = rightBoundary; break; case SplineBoundaryCondition.SecondDerivative: a1[n - 1] = 1; a2[n - 1] = 2; a3[n - 1] = 0; b[n - 1] = 3 * (xx[n - 1] - xx[n - 2]) / (tt[n - 1] - tt[n - 2]) + 0.5 * rightBoundary * (tt[n - 1] - tt[n - 2]); break; default: throw new NotSupportedException(Properties.Resources.InvalidRightBoundaryCondition); } // Build Spline double[] dd = SolveTridiagonal(a1, a2, a3, b); _hermiteSpline.InitInternal(tt, xx, dd); }
/// <summary> /// Create a cubic spline interpolation from a set of (x,y) value pairs and custom boundary/termination conditions. /// </summary> /// <remarks> /// The value pairs do not have to be sorted, but if they are not sorted ascendingly /// and the passed x and y arguments are arrays, they will be sorted inplace and thus modified. /// </remarks> public static CubicSpline InterpolateBoundaries(IEnumerable <double> x, IEnumerable <double> y, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { var xx = (x as double[]) ?? x.ToArray(); var yy = (y as double[]) ?? y.ToArray(); if (xx.Length != yy.Length) { throw new ArgumentException(Resources.ArgumentVectorsSameLength); } if (xx.Length < 2) { throw new ArgumentOutOfRangeException("x"); } Sorting.Sort(xx, yy); int n = xx.Length; // normalize special cases if ((n == 2) && (leftBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated) && (rightBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated)) { leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative; leftBoundary = 0d; rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative; rightBoundary = 0d; } if (leftBoundaryCondition == SplineBoundaryCondition.Natural) { leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative; leftBoundary = 0d; } if (rightBoundaryCondition == SplineBoundaryCondition.Natural) { rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative; rightBoundary = 0d; } var a1 = new double[n]; var a2 = new double[n]; var a3 = new double[n]; var b = new double[n]; // Left Boundary switch (leftBoundaryCondition) { case SplineBoundaryCondition.ParabolicallyTerminated: a1[0] = 0; a2[0] = 1; a3[0] = 1; b[0] = 2 * (yy[1] - yy[0]) / (xx[1] - xx[0]); break; case SplineBoundaryCondition.FirstDerivative: a1[0] = 0; a2[0] = 1; a3[0] = 0; b[0] = leftBoundary; break; case SplineBoundaryCondition.SecondDerivative: a1[0] = 0; a2[0] = 2; a3[0] = 1; b[0] = (3 * ((yy[1] - yy[0]) / (xx[1] - xx[0]))) - (0.5 * leftBoundary * (xx[1] - xx[0])); break; default: throw new NotSupportedException(Resources.InvalidLeftBoundaryCondition); } // Central Conditions for (int i = 1; i < xx.Length - 1; i++) { a1[i] = xx[i + 1] - xx[i]; a2[i] = 2 * (xx[i + 1] - xx[i - 1]); a3[i] = xx[i] - xx[i - 1]; b[i] = (3 * (yy[i] - yy[i - 1]) / (xx[i] - xx[i - 1]) * (xx[i + 1] - xx[i])) + (3 * (yy[i + 1] - yy[i]) / (xx[i + 1] - xx[i]) * (xx[i] - xx[i - 1])); } // Right Boundary switch (rightBoundaryCondition) { case SplineBoundaryCondition.ParabolicallyTerminated: a1[n - 1] = 1; a2[n - 1] = 1; a3[n - 1] = 0; b[n - 1] = 2 * (yy[n - 1] - yy[n - 2]) / (xx[n - 1] - xx[n - 2]); break; case SplineBoundaryCondition.FirstDerivative: a1[n - 1] = 0; a2[n - 1] = 1; a3[n - 1] = 0; b[n - 1] = rightBoundary; break; case SplineBoundaryCondition.SecondDerivative: a1[n - 1] = 1; a2[n - 1] = 2; a3[n - 1] = 0; b[n - 1] = (3 * (yy[n - 1] - yy[n - 2]) / (xx[n - 1] - xx[n - 2])) + (0.5 * rightBoundary * (xx[n - 1] - xx[n - 2])); break; default: throw new NotSupportedException(Resources.InvalidRightBoundaryCondition); } // Build Spline double[] dd = SolveTridiagonal(a1, a2, a3, b); return(InterpolateHermite(xx, yy, dd)); }
public void Init(IList <double> t, IList <double> x, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { if (null == t) { throw new ArgumentNullException("t"); } if (null == x) { throw new ArgumentNullException("x"); } if (t.Count < 2) { throw new ArgumentOutOfRangeException("t"); } if (t.Count != x.Count) { throw new ArgumentException("x"); } int n = t.Count; double[] tt = new double[n]; t.CopyTo(tt, 0); double[] xx = new double[n]; x.CopyTo(xx, 0); Sorting.Sort(tt, xx); // normalize special cases if ((n == 2) && (leftBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated) && (rightBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated)) { leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative; leftBoundary = 0d; rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative; rightBoundary = 0d; } if (leftBoundaryCondition == SplineBoundaryCondition.Natural) { leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative; leftBoundary = 0d; } if (rightBoundaryCondition == SplineBoundaryCondition.Natural) { rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative; rightBoundary = 0d; } double[] a1 = new double[n]; double[] a2 = new double[n]; double[] a3 = new double[n]; double[] b = new double[n]; // Left Boundary switch (leftBoundaryCondition) { case SplineBoundaryCondition.ParabolicallyTerminated: a1[0] = 0; a2[0] = 1; a3[0] = 1; b[0] = 2 * (xx[1] - xx[0]) / (tt[1] - tt[0]); break; case SplineBoundaryCondition.FirstDerivative: a1[0] = 0; a2[0] = 1; a3[0] = 0; b[0] = leftBoundary; break; case SplineBoundaryCondition.SecondDerivative: a1[0] = 0; a2[0] = 2; a3[0] = 1; b[0] = 3 * (xx[1] - xx[0]) / (tt[1] - tt[0]) - 0.5 * leftBoundary * (tt[1] - tt[0]); break; default: throw new NotSupportedException("BoundaryCondition"); } // Central Conditions for (int i = 1; i < tt.Length - 1; i++) { a1[i] = tt[i + 1] - tt[i]; a2[i] = 2 * (tt[i + 1] - tt[i - 1]); a3[i] = tt[i] - tt[i - 1]; b[i] = 3 * (xx[i] - xx[i - 1]) / (tt[i] - tt[i - 1]) * (tt[i + 1] - tt[i]) + 3 * (xx[i + 1] - xx[i]) / (tt[i + 1] - tt[i]) * (tt[i] - tt[i - 1]); } // Right Boundary switch (rightBoundaryCondition) { case SplineBoundaryCondition.ParabolicallyTerminated: a1[n - 1] = 1; a2[n - 1] = 1; a3[n - 1] = 0; b[n - 1] = 2 * (xx[n - 1] - xx[n - 2]) / (tt[n - 1] - tt[n - 2]); break; case SplineBoundaryCondition.FirstDerivative: a1[n - 1] = 0; a2[n - 1] = 1; a3[n - 1] = 0; b[n - 1] = rightBoundary; break; case SplineBoundaryCondition.SecondDerivative: a1[n - 1] = 1; a2[n - 1] = 2; a3[n - 1] = 0; b[n - 1] = 3 * (xx[n - 1] - xx[n - 2]) / (tt[n - 1] - tt[n - 2]) + 0.5 * rightBoundary * (tt[n - 1] - tt[n - 2]); break; default: throw new NotSupportedException("BoundaryCondition"); } // Build Spline double[] dd = SolveTridiagonal(a1, a2, a3, b); _hermiteSpline.InitInternal(tt, xx, dd); }
/// <summary> /// Create a cubic spline interpolation from a set of (x,y) value pairs, sorted ascendingly by x, /// and custom boundary/termination conditions. /// </summary> public static CubicSpline InterpolateBoundariesSorted(double[] x, double[] y, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { if (x.Length != y.Length) { throw new ArgumentException("All vectors must have the same dimensionality."); } if (x.Length < 2) { throw new ArgumentException("The given array is too small. It must be at least 2 long.", nameof(x)); } int n = x.Length; // normalize special cases if ((n == 2) && (leftBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated) && (rightBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated)) { leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative; leftBoundary = 0d; rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative; rightBoundary = 0d; } if (leftBoundaryCondition == SplineBoundaryCondition.Natural) { leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative; leftBoundary = 0d; } if (rightBoundaryCondition == SplineBoundaryCondition.Natural) { rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative; rightBoundary = 0d; } var a1 = new double[n]; var a2 = new double[n]; var a3 = new double[n]; var b = new double[n]; // Left Boundary switch (leftBoundaryCondition) { case SplineBoundaryCondition.ParabolicallyTerminated: a1[0] = 0; a2[0] = 1; a3[0] = 1; b[0] = 2 * (y[1] - y[0]) / (x[1] - x[0]); break; case SplineBoundaryCondition.FirstDerivative: a1[0] = 0; a2[0] = 1; a3[0] = 0; b[0] = leftBoundary; break; case SplineBoundaryCondition.SecondDerivative: a1[0] = 0; a2[0] = 2; a3[0] = 1; b[0] = (3 * ((y[1] - y[0]) / (x[1] - x[0]))) - (0.5 * leftBoundary * (x[1] - x[0])); break; default: throw new NotSupportedException("Invalid Left Boundary Condition."); } // Central Conditions for (int i = 1; i < x.Length - 1; i++) { a1[i] = x[i + 1] - x[i]; a2[i] = 2 * (x[i + 1] - x[i - 1]); a3[i] = x[i] - x[i - 1]; b[i] = (3 * (y[i] - y[i - 1]) / (x[i] - x[i - 1]) * (x[i + 1] - x[i])) + (3 * (y[i + 1] - y[i]) / (x[i + 1] - x[i]) * (x[i] - x[i - 1])); } // Right Boundary switch (rightBoundaryCondition) { case SplineBoundaryCondition.ParabolicallyTerminated: a1[n - 1] = 1; a2[n - 1] = 1; a3[n - 1] = 0; b[n - 1] = 2 * (y[n - 1] - y[n - 2]) / (x[n - 1] - x[n - 2]); break; case SplineBoundaryCondition.FirstDerivative: a1[n - 1] = 0; a2[n - 1] = 1; a3[n - 1] = 0; b[n - 1] = rightBoundary; break; case SplineBoundaryCondition.SecondDerivative: a1[n - 1] = 1; a2[n - 1] = 2; a3[n - 1] = 0; b[n - 1] = (3 * (y[n - 1] - y[n - 2]) / (x[n - 1] - x[n - 2])) + (0.5 * rightBoundary * (x[n - 1] - x[n - 2])); break; default: throw new NotSupportedException("Invalid Right Boundary Condition."); } // Build Spline double[] dd = SolveTridiagonal(a1, a2, a3, b); return(InterpolateHermiteSorted(x, y, dd)); }
/// <summary> /// Evaluate the spline derivatives as used /// internally by this interpolation algorithm. /// </summary> /// <param name="samplePoints">Sample Points t, sorted ascending.</param> /// <param name="sampleValues">Sample Values x(t)</param> /// <param name="leftBoundaryCondition">Condition of the left boundary.</param> /// <param name="leftBoundary">Left boundary value. Ignored in the parabolic case.</param> /// <param name="rightBoundaryCondition">Condition of the right boundary.</param> /// <param name="rightBoundary">Right boundary value. Ignored in the parabolic case.</param> /// <returns>Spline Derivative Vector</returns> public static double[] EvaluateSplineDerivatives( IList <double> samplePoints, IList <double> sampleValues, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { if (null == samplePoints) { throw new ArgumentNullException("samplePoints"); } if (null == sampleValues) { throw new ArgumentNullException("sampleValues"); } if (samplePoints.Count < 2) { throw new ArgumentOutOfRangeException("samplePoints"); } if (samplePoints.Count != sampleValues.Count) { throw new ArgumentException(Resources.ArgumentVectorsSameLength); } for (var i = 1; i < samplePoints.Count; ++i) { if (samplePoints[i] <= samplePoints[i - 1]) { throw new ArgumentException(Resources.Interpolation_Initialize_SamplePointsNotStrictlyAscendingOrder, "samplePoints"); } } int n = samplePoints.Count; // normalize special cases if ((n == 2) && (leftBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated) && (rightBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated)) { leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative; leftBoundary = 0d; rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative; rightBoundary = 0d; } if (leftBoundaryCondition == SplineBoundaryCondition.Natural) { leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative; leftBoundary = 0d; } if (rightBoundaryCondition == SplineBoundaryCondition.Natural) { rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative; rightBoundary = 0d; } double[] a1 = new double[n]; double[] a2 = new double[n]; double[] a3 = new double[n]; double[] b = new double[n]; // Left Boundary switch (leftBoundaryCondition) { case SplineBoundaryCondition.ParabolicallyTerminated: a1[0] = 0; a2[0] = 1; a3[0] = 1; b[0] = 2 * (sampleValues[1] - sampleValues[0]) / (samplePoints[1] - samplePoints[0]); break; case SplineBoundaryCondition.FirstDerivative: a1[0] = 0; a2[0] = 1; a3[0] = 0; b[0] = leftBoundary; break; case SplineBoundaryCondition.SecondDerivative: a1[0] = 0; a2[0] = 2; a3[0] = 1; b[0] = (3 * ((sampleValues[1] - sampleValues[0]) / (samplePoints[1] - samplePoints[0]))) - (0.5 * leftBoundary * (samplePoints[1] - samplePoints[0])); break; default: throw new NotSupportedException(Resources.InvalidLeftBoundaryCondition); } // Central Conditions for (int i = 1; i < samplePoints.Count - 1; i++) { a1[i] = samplePoints[i + 1] - samplePoints[i]; a2[i] = 2 * (samplePoints[i + 1] - samplePoints[i - 1]); a3[i] = samplePoints[i] - samplePoints[i - 1]; b[i] = (3 * (sampleValues[i] - sampleValues[i - 1]) / (samplePoints[i] - samplePoints[i - 1]) * (samplePoints[i + 1] - samplePoints[i])) + (3 * (sampleValues[i + 1] - sampleValues[i]) / (samplePoints[i + 1] - samplePoints[i]) * (samplePoints[i] - samplePoints[i - 1])); } // Right Boundary switch (rightBoundaryCondition) { case SplineBoundaryCondition.ParabolicallyTerminated: a1[n - 1] = 1; a2[n - 1] = 1; a3[n - 1] = 0; b[n - 1] = 2 * (sampleValues[n - 1] - sampleValues[n - 2]) / (samplePoints[n - 1] - samplePoints[n - 2]); break; case SplineBoundaryCondition.FirstDerivative: a1[n - 1] = 0; a2[n - 1] = 1; a3[n - 1] = 0; b[n - 1] = rightBoundary; break; case SplineBoundaryCondition.SecondDerivative: a1[n - 1] = 1; a2[n - 1] = 2; a3[n - 1] = 0; b[n - 1] = (3 * (sampleValues[n - 1] - sampleValues[n - 2]) / (samplePoints[n - 1] - samplePoints[n - 2])) + (0.5 * rightBoundary * (samplePoints[n - 1] - samplePoints[n - 2])); break; default: throw new NotSupportedException(Resources.InvalidRightBoundaryCondition); } // Build Spline return(SolveTridiagonal(a1, a2, a3, b)); }
/// <summary> /// Create a cubic spline interpolation based on arbitrary points, with specified boundary conditions. /// </summary> /// <param name="points">The sample points t. Supports both lists and arrays.</param> /// <param name="values">The sample point values x(t). Supports both lists and arrays.</param> /// <param name="leftBoundaryCondition">Condition of the left boundary.</param> /// <param name="leftBoundary">Left boundary value. Ignored in the parabolic case.</param> /// <param name="rightBoundaryCondition">Condition of the right boundary.</param> /// <param name="rightBoundary">Right boundary value. Ignored in the parabolic case.</param> /// <returns> /// An interpolation scheme optimized for the given sample points and values, /// which can then be used to compute interpolations and extrapolations /// on arbitrary points. /// </returns> public static IInterpolationMethod CreateCubicSpline( IList<double> points, IList<double> values, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary ) { CubicSplineInterpolation method = new CubicSplineInterpolation(); method.Init( points, values, leftBoundaryCondition, leftBoundary, rightBoundaryCondition, rightBoundary ); return method; }
/// <summary> /// Evaluate the spline coefficients as used /// internally by this interpolation algorithm. /// </summary> /// <param name="samplePoints">Sample Points t, sorted ascending.</param> /// <param name="sampleValues">Sample Values x(t)</param> /// <param name="leftBoundaryCondition">Condition of the left boundary.</param> /// <param name="leftBoundary">Left boundary value. Ignored in the parabolic case.</param> /// <param name="rightBoundaryCondition">Condition of the right boundary.</param> /// <param name="rightBoundary">Right boundary value. Ignored in the parabolic case.</param> /// <returns>Spline Coefficient Vector</returns> public static double[] EvaluateSplineCoefficients( IList<double> samplePoints, IList<double> sampleValues, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { double[] derivatives = EvaluateSplineDerivatives( samplePoints, sampleValues, leftBoundaryCondition, leftBoundary, rightBoundaryCondition, rightBoundary); return CubicHermiteSplineInterpolation.EvaluateSplineCoefficients( samplePoints, sampleValues, derivatives); }
/// <summary> /// Create a cubic spline interpolation from a set of (x,y) value pairs and custom boundary/termination conditions. /// </summary> /// <remarks> /// The value pairs do not have to be sorted, but if they are not sorted ascendingly /// and the passed x and y arguments are arrays, they will be sorted inplace and thus modified. /// </remarks> public static CubicSpline InterpolateBoundaries(IEnumerable<double> x, IEnumerable<double> y, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { var xx = (x as double[]) ?? x.ToArray(); var yy = (y as double[]) ?? y.ToArray(); if (xx.Length != yy.Length) { throw new ArgumentException(Resources.ArgumentVectorsSameLength); } if (xx.Length < 2) { throw new ArgumentOutOfRangeException("x"); } Sorting.Sort(xx, yy); int n = xx.Length; // normalize special cases if ((n == 2) && (leftBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated) && (rightBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated)) { leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative; leftBoundary = 0d; rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative; rightBoundary = 0d; } if (leftBoundaryCondition == SplineBoundaryCondition.Natural) { leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative; leftBoundary = 0d; } if (rightBoundaryCondition == SplineBoundaryCondition.Natural) { rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative; rightBoundary = 0d; } var a1 = new double[n]; var a2 = new double[n]; var a3 = new double[n]; var b = new double[n]; // Left Boundary switch (leftBoundaryCondition) { case SplineBoundaryCondition.ParabolicallyTerminated: a1[0] = 0; a2[0] = 1; a3[0] = 1; b[0] = 2*(yy[1] - yy[0])/(xx[1] - xx[0]); break; case SplineBoundaryCondition.FirstDerivative: a1[0] = 0; a2[0] = 1; a3[0] = 0; b[0] = leftBoundary; break; case SplineBoundaryCondition.SecondDerivative: a1[0] = 0; a2[0] = 2; a3[0] = 1; b[0] = (3*((yy[1] - yy[0])/(xx[1] - xx[0]))) - (0.5*leftBoundary*(xx[1] - xx[0])); break; default: throw new NotSupportedException(Resources.InvalidLeftBoundaryCondition); } // Central Conditions for (int i = 1; i < xx.Length - 1; i++) { a1[i] = xx[i + 1] - xx[i]; a2[i] = 2*(xx[i + 1] - xx[i - 1]); a3[i] = xx[i] - xx[i - 1]; b[i] = (3*(yy[i] - yy[i - 1])/(xx[i] - xx[i - 1])*(xx[i + 1] - xx[i])) + (3*(yy[i + 1] - yy[i])/(xx[i + 1] - xx[i])*(xx[i] - xx[i - 1])); } // Right Boundary switch (rightBoundaryCondition) { case SplineBoundaryCondition.ParabolicallyTerminated: a1[n - 1] = 1; a2[n - 1] = 1; a3[n - 1] = 0; b[n - 1] = 2*(yy[n - 1] - yy[n - 2])/(xx[n - 1] - xx[n - 2]); break; case SplineBoundaryCondition.FirstDerivative: a1[n - 1] = 0; a2[n - 1] = 1; a3[n - 1] = 0; b[n - 1] = rightBoundary; break; case SplineBoundaryCondition.SecondDerivative: a1[n - 1] = 1; a2[n - 1] = 2; a3[n - 1] = 0; b[n - 1] = (3*(yy[n - 1] - yy[n - 2])/(xx[n - 1] - xx[n - 2])) + (0.5*rightBoundary*(xx[n - 1] - xx[n - 2])); break; default: throw new NotSupportedException(Resources.InvalidRightBoundaryCondition); } // Build Spline double[] dd = SolveTridiagonal(a1, a2, a3, b); return InterpolateHermite(xx, yy, dd); }
/// <summary> /// Initialize the interpolation method with the given spline coefficients (sorted by the sample points t). /// </summary> /// <param name="samplePoints">Sample Points t, sorted ascending.</param> /// <param name="sampleValues">Sample Values x(t)</param> /// <param name="leftBoundaryCondition">Condition of the left boundary.</param> /// <param name="leftBoundary">Left boundary value. Ignored in the parabolic case.</param> /// <param name="rightBoundaryCondition">Condition of the right boundary.</param> /// <param name="rightBoundary">Right boundary value. Ignored in the parabolic case.</param> public void Initialize( IList<double> samplePoints, IList<double> sampleValues, SplineBoundaryCondition leftBoundaryCondition, double leftBoundary, SplineBoundaryCondition rightBoundaryCondition, double rightBoundary) { double[] derivatives = EvaluateSplineDerivatives( samplePoints, sampleValues, leftBoundaryCondition, leftBoundary, rightBoundaryCondition, rightBoundary); _spline.Initialize(samplePoints, sampleValues, derivatives); }
/// <summary>Creates a <see cref="MklGridPointCurve.Interpolator"/> object that represents the implementation of a specified interpolation approach. /// </summary> /// <param name="splineOrder">The spline order.</param> /// <param name="splineType">The type of the spline.</param> /// <param name="boundaryConditionType">The type of the boundary condition.</param> /// <param name="boundaryCondition">The boundary condition.</param> /// <param name="splineCoefficientHint">The spline coefficient hint.</param> /// <param name="internalConditionType">The internal boundary condition type.</param> /// <param name="internalConditions">The internal boundary condition.</param> /// <returns>A <see cref="MklGridPointCurve.Interpolator"/> object that represents the implementation of the specified interpolation approach.</returns> public MklGridPointCurve.Interpolator Create(SplineOrder splineOrder, SplineType splineType, SplineBoundaryCondition boundaryConditionType, double[] boundaryCondition = null, SplineCoefficientStorageFormat splineCoefficientHint = SplineCoefficientStorageFormat.DF_NO_HINT, SplineInternalConditionType internalConditionType = SplineInternalConditionType.DF_NO_IC, double[] internalConditions = null) { return(new MklDataFitting(splineOrder, splineType, boundaryConditionType, boundaryCondition, splineCoefficientHint, internalConditionType, internalConditions)); }