com.opengamma.strata.math.impl.differentiation.VectorFieldSecondOrderDifferentiator 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) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.math.impl.differentiation;
import java.util.function.Function;
import com.opengamma.strata.collect.ArgChecker;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.collect.array.DoubleMatrix;
/**
* The Vector field second order differentiator.
*/
public class VectorFieldSecondOrderDifferentiator implements Differentiator {
private static final double DEFAULT_EPS = 1e-4;
private final double eps;
private final double epsSqr;
private final VectorFieldFirstOrderDifferentiator vectorFieldDiff;
private final MatrixFieldFirstOrderDifferentiator maxtrixFieldDiff;
/**
* Creates an instance using the default values.
*/
public VectorFieldSecondOrderDifferentiator() {
this.eps = DEFAULT_EPS;
this.epsSqr = eps * eps;
this.vectorFieldDiff = new VectorFieldFirstOrderDifferentiator(eps);
this.maxtrixFieldDiff = new MatrixFieldFirstOrderDifferentiator(eps);
}
//-------------------------------------------------------------------------
/**
* This computes the second derivative of a vector field, which is a rank 3 tensor field.
* The tensor is represented as an array of DoubleMatrix, where each matrix is
* a Hessian (for the dependent variable y_i), so the indexing is
* H^i_{j,k} =\partial^2y_i/\partial x_j \partial x_k
*
* @param function the function representing the vector field
* @return a function representing the second derivative of the vector field (i.e. a rank 3 tensor field)
*/
@Override
public Function differentiate(
Function function) {
ArgChecker.notNull(function, "function");
Function jacFunc = vectorFieldDiff.differentiate(function);
Function hFunc = maxtrixFieldDiff.differentiate(jacFunc);
return new Function() {
@SuppressWarnings("synthetic-access")
@Override
public DoubleMatrix[] apply(DoubleArray x) {
DoubleMatrix[] gamma = hFunc.apply(x);
return reshapeTensor(gamma);
}
};
}
//-------------------------------------------------------------------------
@Override
public Function differentiate(
Function function,
Function domain) {
ArgChecker.notNull(function, "function");
Function jacFunc = vectorFieldDiff.differentiate(function, domain);
Function hFunc = maxtrixFieldDiff.differentiate(jacFunc, domain);
return new Function() {
@SuppressWarnings("synthetic-access")
@Override
public DoubleMatrix[] apply(DoubleArray x) {
DoubleMatrix[] gamma = hFunc.apply(x);
return reshapeTensor(gamma);
}
};
}
/**
* Gamma is in the form gamma^i_{j,k} =\partial^2y_j/\partial x_i \partial x_k, where i is the
* index of the matrix in the stack (3rd index of the tensor), and j,k are the individual
* matrix indices. We would like it in the form H^i_{j,k} =\partial^2y_i/\partial x_j \partial x_k,
* so that each matrix is a Hessian (for the dependent variable y_i), hence the reshaping below.
*
* @param gamma the rank 3 tensor
* @return the reshaped rank 3 tensor
*/
private DoubleMatrix[] reshapeTensor(DoubleMatrix[] gamma) {
int m = gamma.length;
int n = gamma[0].rowCount();
ArgChecker.isTrue(gamma[0].columnCount() == m,
"tenor wrong size. Seond index is {}, should be {}", gamma[0].columnCount(), m);
DoubleMatrix[] res = new DoubleMatrix[n];
for (int i = 0; i < n; i++) {
double[][] temp = new double[m][m];
for (int j = 0; j < m; j++) {
DoubleMatrix gammaJ = gamma[j];
for (int k = j; k < m; k++) {
temp[j][k] = gammaJ.get(i, k);
}
}
for (int j = 0; j < m; j++) {
for (int k = 0; k < j; k++) {
temp[j][k] = temp[k][j];
}
}
res[i] = DoubleMatrix.copyOf(temp);
}
return res;
}
//-------------------------------------------------------------------------
/**
* Differentiate.
*
* @param function the function
* @return the result
*/
public Function differentiateFull(
Function function) {
return new Function() {
@SuppressWarnings("synthetic-access")
@Override
public DoubleMatrix[] apply(DoubleArray x) {
ArgChecker.notNull(x, "x");
DoubleArray y = function.apply(x);
int n = x.size();
int m = y.size();
double[][][] res = new double[m][n][n];
for (int j = 0; j < n; j++) {
double xj = x.get(j);
DoubleArray xPlusOneEps = x.with(j, xj + eps);
DoubleArray xMinusOneEps = x.with(j, xj - eps);
DoubleArray up = function.apply(x.with(j, xj + eps));
DoubleArray down = function.apply(xMinusOneEps);
for (int i = 0; i < m; i++) {
res[i][j][j] = (up.get(i) + down.get(i) - 2 * y.get(i)) / epsSqr;
}
for (int k = j + 1; k < n; k++) {
double xk = x.get(k);
DoubleArray downup = function.apply(xMinusOneEps.with(k, xk + eps));
DoubleArray downdown = function.apply(xMinusOneEps.with(k, xk - eps));
DoubleArray updown = function.apply(xPlusOneEps.with(k, xk - eps));
DoubleArray upup = function.apply(xPlusOneEps.with(k, xk + eps));
for (int i = 0; i < m; i++) {
res[i][j][k] = (upup.get(i) + downdown.get(i) - updown.get(i) - downup.get(i)) / 4 / epsSqr;
}
}
}
DoubleMatrix[] mres = new DoubleMatrix[m];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
for (int k = 0; k < j; k++) {
res[i][j][k] = res[i][k][j];
}
}
mres[i] = DoubleMatrix.copyOf(res[i]);
}
return mres;
}
};
}
//-------------------------------------------------------------------------
/**
* Computes the second derivative of a vector field, without cross derivatives.
*
* This creates a function returning a matrix whose {i,j} element is
* $H^i_{j} = \partial^2y_i/\partial x_j \partial x_j$.
*
* @param function the function representing the vector field
* @return a function representing the second derivative of the vector field (i.e. a rank 3 tensor field)
*/
public Function differentiateNoCross(Function function) {
return new Function() {
@SuppressWarnings("synthetic-access")
@Override
public DoubleMatrix apply(DoubleArray x) {
ArgChecker.notNull(x, "x");
DoubleArray y = function.apply(x);
int n = x.size();
int m = y.size();
double[][] res = new double[m][n];
for (int j = 0; j < n; j++) {
double xj = x.get(j);
DoubleArray up = function.apply(x.with(j, xj + eps));
DoubleArray down = function.apply(x.with(j, xj - eps));
for (int i = 0; i < m; i++) {
res[i][j] = (up.get(i) + down.get(i) - 2d * y.get(i)) / epsSqr;
}
}
return DoubleMatrix.copyOf(res);
}
};
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy