package com.imsl.test.example.math; import com.imsl.math.*; import java.text.*; /** *

* Approximates the gradient with a combination of * numerical derivatives and analytic derivatives.

* * This example uses the same data as in {@link NumericalDerivativesEx2}. An * examination of the function * $$f(y_1 ,y_2 ) = a\exp (by_1 ) + cy_1 y_2^2$$ * shows that the first term on the right-hand side does not depend on * the second variable, and therefore can be left out of the evaluation of the * first partial of \( f \) with respect to \( y_2 \), potentially avoiding * cancellation errors. Also, \( cy_2^2 \) appears as an additive term when * computing the partial with respect to \(y_1\). This examples shows how different * terms in a derivative can be used explicitly and then added to approximated * terms. * The input values of array * options allow NumericalDerivatives to use these * facts and obtain greater accuracy using fewer evaluations of * the exponential function. * * @see Code * @see Output */ public class NumericalDerivativesEx3 { static private int m = 1, n = 2; static private double a, b, c, f2 = 0.0; public static void main(String args[]) { int[] options = new int[n]; double u; double[] y = new double[n]; double[] valueF = new double[m]; double[] scale = new double[n]; double[][] actual = new double[m][n]; double[] re = new double[2]; // Define data and point of evaluation: a = 2.5e6; b = 3.4e0; c = 4.5e0; y[0] = 2.1e0; y[1] = 3.2e0; // Precision, for measuring errors u = Math.sqrt(2.220446049250313e-016); // Set scaling: scale[0] = 1.e0; // Increase scale to account for large value of a. scale[1] = 8.e3; // Compute true values of partials. actual[0][0] = a * b * Math.exp(b * y[0]) + c * y[1] * y[1]; actual[0][1] = 2 * c * y[0] * y[1]; options[0] = NumericalDerivatives.ACCUMULATE; options[1] = NumericalDerivatives.ONE_SIDED; valueF[0] = a * Math.exp(b * y[0]); scale[1] = 1.e0; NumericalDerivatives.Jacobian fcn = new NumericalDerivatives.Jacobian() { @Override public double[] f(int varIndex, double[] y) { double[] tmp = new double[m]; if (varIndex != 2) { tmp[0] = a * Math.exp(b * y[0]); } else { // This is the function value for the partial wrt y_2. tmp[0] = c * y[0] * y[1] * y[1]; } return tmp; } @Override public double[][] jacobian(double[] y) { double[][] tmp = new double[m][n]; // Start with part of the derivative that is known. tmp[0][0] = c * y[1] * y[1]; return tmp; } }; NumericalDerivatives derv = new NumericalDerivatives(fcn); derv.setDifferencingMethods(options); derv.setScalingFactors(scale); derv.setInitialF(valueF); double[][] jacobian = derv.evaluateJ(y); NumberFormat nf = NumberFormat.getInstance(); nf.setMaximumFractionDigits(2); nf.setMinimumFractionDigits(2); PrintMatrixFormat pmf = new PrintMatrixFormat(); pmf.setNumberFormat(nf); new PrintMatrix("Numerical gradient:").print(pmf, jacobian); new PrintMatrix("Analytic gradient:").print(pmf, actual); jacobian[0][0] = (jacobian[0][0] - actual[0][0]) / actual[0][0]; jacobian[0][1] = (jacobian[0][1] - actual[0][1]) / actual[0][1]; re[0] = jacobian[0][0]; re[1] = jacobian[0][1]; System.out.println("Relative accuracy:"); System.out.println("df/dy_1 df/dy_2"); System.out.printf(" %.2fu %.2fu\n", re[0] / u, re[1] / u); System.out.printf("(%.3e) (%.3e)\n", re[0], re[1]); } }