ScalarFieldFirstOrderDifferentiator implements Differentiator<DoubleMatrix1D, Double, DoubleMatrix1D> { @Override public Function1D<DoubleMatrix1D, DoubleMatrix1D> differentiate(final Function1D<DoubleMatrix1D, Double> function) { Validate.notNull(function); switch (_differenceType) { case FORWARD: return new Function1D<DoubleMatrix1D, DoubleMatrix1D>() { @SuppressWarnings("synthetic-access") @Override public DoubleMatrix1D evaluate(final DoubleMatrix1D x) { Validate.notNull(x, "x"); final int n = x.getNumberOfElements(); final double y = function.evaluate(x); final double[] xData = x.getData(); double oldValue; final double[] res = new double[n]; for (int i = 0; i < n; i++) { oldValue = xData[i]; xData[i] += _eps; res[i] = (function.evaluate(x) - y) / _eps; xData[i] = oldValue; } return new DoubleMatrix1D(res); } }; case CENTRAL: return new Function1D<DoubleMatrix1D, DoubleMatrix1D>() { @SuppressWarnings("synthetic-access") @Override public DoubleMatrix1D evaluate(final DoubleMatrix1D x) { Validate.notNull(x, "x"); final int n = x.getNumberOfElements(); final double[] xData = x.getData(); double oldValue; double up, down; final double[] res = new double[n]; for (int i = 0; i < n; i++) { oldValue = xData[i]; xData[i] += _eps; up = function.evaluate(x); xData[i] -= _twoEps; down = function.evaluate(x); res[i] = (up - down) / _twoEps; xData[i] = oldValue; } return new DoubleMatrix1D(res); } }; case BACKWARD: return new Function1D<DoubleMatrix1D, DoubleMatrix1D>() { @SuppressWarnings("synthetic-access") @Override public DoubleMatrix1D evaluate(final DoubleMatrix1D x) { Validate.notNull(x, "x"); final double y = function.evaluate(x); final int n = x.getNumberOfElements(); final double[] xData = x.getData(); double oldValue; final double[] res = new double[n]; for (int i = 0; i < n; i++) { oldValue = xData[i]; xData[i] -= _eps; res[i] = (y - function.evaluate(x)) / _eps; xData[i] = oldValue; } return new DoubleMatrix1D(res); } }; default: throw new IllegalArgumentException("Can only handle forward, backward and central differencing"); } } ScalarFieldFirstOrderDifferentiator();  ScalarFieldFirstOrderDifferentiator(final FiniteDifferenceType differenceType, final double eps); @Override Function1D<DoubleMatrix1D, DoubleMatrix1D> differentiate(final Function1D<DoubleMatrix1D, Double> function); @Override Function1D<DoubleMatrix1D, DoubleMatrix1D> differentiate(final Function1D<DoubleMatrix1D, Double> function, final Function1D<DoubleMatrix1D, Boolean> domain);  }
@Test(expectedExceptions = IllegalArgumentException.class) public void testNullFunction() { CENTRAL.differentiate((Function1D<DoubleMatrix1D, Double>) null); }
@Test public void test() { final DoubleMatrix1D x = new DoubleMatrix1D(.2245, -1.2344); final DoubleMatrix1D anGrad = G.evaluate(x); final DoubleMatrix1D fdFwdGrad = FORWARD.differentiate(F).evaluate(x); final DoubleMatrix1D fdCentGrad = CENTRAL.differentiate(F).evaluate(x); final DoubleMatrix1D fdBackGrad = BACKWARD.differentiate(F).evaluate(x); for (int i = 0; i < 2; i++) { assertEquals(fdFwdGrad.getEntry(i), anGrad.getEntry(i), 10 * EPS); assertEquals(fdCentGrad.getEntry(i), anGrad.getEntry(i), EPS * EPS); assertEquals(fdBackGrad.getEntry(i), anGrad.getEntry(i), 10 * EPS); } }
@Test public void domainTest() { final DoubleMatrix1D[] x = new DoubleMatrix1D[3]; x[0] = new DoubleMatrix1D(0.2245, -1.2344); x[1] = new DoubleMatrix1D(0.0, 12.6); x[2] = new DoubleMatrix1D(Math.PI, 0.0); final Function1D<DoubleMatrix1D, DoubleMatrix1D> fdGradFunc = CENTRAL.differentiate(F, DOMAIN); for (int k = 0; k < 3; k++) { final DoubleMatrix1D fdRes = fdGradFunc.evaluate(x[k]); final DoubleMatrix1D alRes = G.evaluate(x[k]); for (int i = 0; i < 2; i++) { assertEquals(fdRes.getEntry(i), alRes.getEntry(i), 1e-7); } } }