/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.hawaii.jmotif.sampler;
/**
*
* @author ytoh
*/
public class CentralDifferenceHessian implements NumericalHessian {
public Hessian hessianAt(ObjectiveFunction function, Point point) {
int dimension = function.getDimension();
double[][] hessian = new double[dimension][dimension];
double[] h = new double[dimension];
double[] fplus = new double[dimension];
double[] fminus = new double[dimension];
double tolerance = Math.pow(MachineAccuracy.EPSILON, 0.25);//TODO revise maybe 1/3
double[] p = point.toArray();
double valueAtPoint = function.valueAt(point);
double xh, oldx, oldy, fxx, tH;
for (int i = 0; i < dimension; i++) {
h[i] = tolerance * (Math.abs(p[i]) + MachineAccuracy.EPSILON);
xh = p[i] + h[i];
h[i] = xh - p[i];
oldx = p[i];
p[i] = oldx + h[i];
fplus[i] = function.valueAt(Point.at(p));
p[i] = oldx - h[i];
fminus[i] = function.valueAt(Point.at(p));
p[i] = oldx;
}
for (int i = 0; i < dimension; i++) {
hessian[i][i] = h[i] * h[i];
for (int j = 0; j < dimension; j++) {
tH = h[i] * h[j];
hessian[i][j] = tH;
hessian[j][i] = tH;
}
}
for (int i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
if (i == j) {
hessian[i][j] = (fplus[i] + fminus[j] - 2 * valueAtPoint) / hessian[i][j];
} else {
oldx = p[i];
oldy = p[j];
p[i] = oldx + h[i];
p[j] = oldy - h[j];
fxx = function.valueAt(Point.at(p));
p[i] = oldx;
p[j] = oldy;
hessian[i][j] = (fplus[i] + fminus[j] - valueAtPoint - fxx) / hessian[i][j];
}
}
}
// H=(H+H')/2
for (int i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
tH = (hessian[i][j] + hessian[j][i]) / 2.0;
hessian[i][j] = tH;
hessian[j][i] = tH;
}
}
return Hessian.valueOf(hessian);
}
}