com.opengamma.strata.math.impl.interpolation.HermiteCoefficientsProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of strata-math Show documentation
Show all versions of strata-math Show documentation
Mathematic support for Strata
/*
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.math.impl.interpolation;
import java.util.Arrays;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.collect.array.DoubleMatrix;
/**
* Hermite interpolation is determined if one specifies first derivatives for a cubic
* interpolant and first and second derivatives for a quintic interpolant.
*/
public class HermiteCoefficientsProvider {
/**
* @param values (yValues_i)
* @param intervals (xValues_{i+1} - xValues_{i})
* @param slopes (yValues_{i+1} - yValues_{i})/(xValues_{i+1} - xValues_{i})
* @param first First derivatives at xValues_i
* @return Coefficient matrix whose i-th row vector is { a_n, a_{n-1}, ...} for the i-th interval,
* where a_n, a_{n-1},... are coefficients of f(x) = a_n (x-x_i)^n + a_{n-1} (x-x_i)^{n-1} + .... with n=3
*/
public double[][] solve(double[] values, double[] intervals, double[] slopes, double[] first) {
int nInt = intervals.length;
double[][] res = new double[nInt][4];
for (int i = 0; i < nInt; ++i) {
Arrays.fill(res[i], 0.);
}
for (int i = 0; i < nInt; ++i) {
res[i][3] = values[i];
res[i][2] = first[i];
res[i][1] = (3. * slopes[i] - first[i + 1] - 2. * first[i]) / intervals[i];
res[i][0] = -(2. * slopes[i] - first[i + 1] - first[i]) / intervals[i] / intervals[i];
}
return res;
}
/**
* @param values Y values of data
* @param intervals (xValues_{i+1} - xValues_{i})
* @param slopes (yValues_{i+1} - yValues_{i})/(xValues_{i+1} - xValues_{i})
* @param slopeSensitivity Derivative values of slope with respect to yValues
* @param firstWithSensitivity First derivative values at xValues_i and their yValues dependencies
* @return Coefficient matrix and its node dependencies
*/
public DoubleMatrix[] solveWithSensitivity(
double[] values,
double[] intervals,
double[] slopes,
double[][] slopeSensitivity,
DoubleArray[] firstWithSensitivity) {
int nData = values.length;
double[] first = firstWithSensitivity[0].toArray();
DoubleMatrix[] res = new DoubleMatrix[nData];
double[][] coef = solve(values, intervals, slopes, first);
res[0] = DoubleMatrix.copyOf(coef);
for (int i = 0; i < nData - 1; ++i) {
double[][] coefSense = new double[4][nData];
Arrays.fill(coefSense[3], 0.);
coefSense[3][i] = 1.;
for (int k = 0; k < nData; ++k) {
coefSense[0][k] =
-(2. * slopeSensitivity[i][k] - firstWithSensitivity[i + 2].get(k) - firstWithSensitivity[i + 1].get(k)) /
intervals[i] / intervals[i];
coefSense[1][k] =
(3. * slopeSensitivity[i][k] - firstWithSensitivity[i + 2].get(k) - 2. * firstWithSensitivity[i + 1].get(k)) /
intervals[i];
coefSense[2][k] = firstWithSensitivity[i + 1].get(k);
}
res[i + 1] = DoubleMatrix.copyOf(coefSense);
}
return res;
}
/**
* @param values (yValues_i)
* @param intervals (xValues_{i+1} - xValues_{i})
* @param slopes (yValues_{i+1} - yValues_{i})/(xValues_{i+1} - xValues_{i})
* @param first First derivatives at xValues_i
* @param second Second derivatives at xValues_i
* @return Coefficient matrix whose i-th row vector is { a_n, a_{n-1}, ...} for the i-th interval,
* where a_n, a_{n-1},... are coefficients of f(x) = a_n (x-x_i)^n + a_{n-1} (x-x_i)^{n-1} + .... with n=5
*/
public double[][] solve(double[] values, double[] intervals, double[] slopes, double[] first, double[] second) {
int nInt = intervals.length;
double[][] res = new double[nInt][6];
for (int i = 0; i < nInt; ++i) {
Arrays.fill(res[i], 0.);
}
for (int i = 0; i < nInt; ++i) {
res[i][5] = values[i];
res[i][4] = first[i];
res[i][3] = 0.5 * second[i];
res[i][2] = 0.5 * (second[i + 1] - 3. * second[i]) / intervals[i] +
2. * (5. * slopes[i] - 3. * first[i] - 2. * first[i + 1]) / intervals[i] / intervals[i];
res[i][1] = 0.5 * (3. * second[i] - 2. * second[i + 1]) / intervals[i] / intervals[i] +
(8. * first[i] + 7. * first[i + 1] - 15. * slopes[i]) / intervals[i] / intervals[i] / intervals[i];
res[i][0] = 0.5 * (second[i + 1] - second[i]) / intervals[i] / intervals[i] / intervals[i] +
3. * (2. * slopes[i] - first[i + 1] - first[i]) / intervals[i] / intervals[i] / intervals[i] / intervals[i];
}
return res;
}
/**
*
* @param values (yValues_i)
* @param intervals (xValues_{i+1} - xValues_{i})
* @param slopes (yValues_{i+1} - yValues_{i})/(xValues_{i+1} - xValues_{i})
* @param slopeSensitivity Derivative values of slope with respect to yValues
* @param firstWithSensitivity First derivative values at xValues_i and their yValues dependencies
* @param secondWithSensitivity Second derivative values at xValues_i and their yValues dependencies
* @return Coefficient matrix and its node dependencies
*/
public DoubleMatrix[] solveWithSensitivity(
double[] values,
double[] intervals,
double[] slopes,
double[][] slopeSensitivity,
DoubleArray[] firstWithSensitivity,
DoubleArray[] secondWithSensitivity) {
int nData = values.length;
double[] first = firstWithSensitivity[0].toArray();
double[] second = secondWithSensitivity[0].toArray();
DoubleMatrix[] res = new DoubleMatrix[nData];
double[][] coef = solve(values, intervals, slopes, first, second);
res[0] = DoubleMatrix.copyOf(coef);
for (int i = 0; i < nData - 1; ++i) {
double interval = intervals[i];
double[][] coefSense = new double[6][nData];
Arrays.fill(coefSense[5], 0.);
coefSense[5][i] = 1.;
for (int k = 0; k < nData; ++k) {
double cs0b = 2d * slopeSensitivity[i][k] - firstWithSensitivity[i + 2].get(k) - firstWithSensitivity[i + 1].get(k);
double cs0a = secondWithSensitivity[i + 2].get(k) - secondWithSensitivity[i + 1].get(k);
coefSense[0][k] = 0.5 * cs0a / interval / interval / interval + 3d * cs0b / interval / interval / interval / interval;
double cs1a = 3d * secondWithSensitivity[i + 1].get(k) - 2d * secondWithSensitivity[i + 2].get(k);
double cs1b =
8d * firstWithSensitivity[i + 1].get(k) + 7d * firstWithSensitivity[i + 2].get(k) - 15d * slopeSensitivity[i][k];
coefSense[1][k] = 0.5 * cs1a / interval / interval + cs1b / interval / interval / interval;
double cs2a = secondWithSensitivity[i + 2].get(k) - 3d * secondWithSensitivity[i + 1].get(k);
double cs2b = 5d * slopeSensitivity[i][k] - 3d * firstWithSensitivity[i + 1].get(k) - 2d * firstWithSensitivity[i + 2].get(k);
coefSense[2][k] = 0.5 * cs2a / interval + 2. * cs2b / interval / interval;
coefSense[3][k] = 0.5 * secondWithSensitivity[i + 1].get(k);
coefSense[4][k] = firstWithSensitivity[i + 1].get(k);
}
res[i + 1] = DoubleMatrix.copyOf(coefSense);
}
return res;
}
/**
* @param xValues The x values
* @return Intervals of xValues, ( xValues_{i+1} - xValues_i )
*/
public double[] intervalsCalculator(double[] xValues) {
int nDataPts = xValues.length;
double[] intervals = new double[nDataPts - 1];
for (int i = 0; i < nDataPts - 1; ++i) {
intervals[i] = xValues[i + 1] - xValues[i];
}
return intervals;
}
/**
* @param yValues Y values of data
* @param intervals Intervals of x data
* @return ( yValues_{i+1} - yValues_i )/( xValues_{i+1} - xValues_i )
*/
public double[] slopesCalculator(double[] yValues, double[] intervals) {
int nDataPts = yValues.length;
double[] slopes = new double[nDataPts - 1];
for (int i = 0; i < nDataPts - 1; ++i) {
slopes[i] = (yValues[i + 1] - yValues[i]) / intervals[i];
}
return slopes;
}
/**
* Derivative values of slopes_i with respect to yValues_j, s_{ij}.
* @param intervals Intervals of x data
* @return The matrix s_{ij}
*/
public double[][] slopeSensitivityCalculator(double[] intervals) {
int nDataPts = intervals.length + 1;
double[][] res = new double[nDataPts - 1][nDataPts];
for (int i = 0; i < nDataPts - 1; ++i) {
Arrays.fill(res[i], 0.);
res[i][i] = -1. / intervals[i];
res[i][i + 1] = 1. / intervals[i];
}
return res;
}
/**
* @param ints1 The first interval
* @param ints2 The second interval
* @param slope1 The first gradient
* @param slope2 The second gradient
* @return Value of derivative at each endpoint
*/
public double endpointDerivatives(double ints1, double ints2, double slope1, double slope2) {
double val = (2. * ints1 + ints2) * slope1 / (ints1 + ints2) - ints1 * slope2 / (ints1 + ints2);
if (Math.signum(val) != Math.signum(slope1)) {
return 0.;
}
if (Math.signum(slope1) != Math.signum(slope2) && Math.abs(val) > 3. * Math.abs(slope1)) {
return 3. * slope1;
}
return val;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy