### Question:
ScalarFieldFirstOrderDifferentiator implements Differentiator<DoubleArray, Double, DoubleArray> { @Override public Function<DoubleArray, DoubleArray> differentiate( Function<DoubleArray, Double> function) { ArgChecker.notNull(function, "function"); switch (differenceType) { case FORWARD: return new Function<DoubleArray, DoubleArray>() { @SuppressWarnings("synthetic-access") @Override public DoubleArray apply(DoubleArray x) { ArgChecker.notNull(x, "x"); double y = function.apply(x); return DoubleArray.of(x.size(), i -> { double up = function.apply(x.with(i, x.get(i) + eps)); return (up - y) / eps; }); } }; case CENTRAL: return new Function<DoubleArray, DoubleArray>() { @SuppressWarnings("synthetic-access") @Override public DoubleArray apply(DoubleArray x) { ArgChecker.notNull(x, "x"); return DoubleArray.of(x.size(), i -> { double up = function.apply(x.with(i, x.get(i) + eps)); double down = function.apply(x.with(i, x.get(i) - eps)); return (up - down) / twoEps; }); } }; case BACKWARD: return new Function<DoubleArray, DoubleArray>() { @SuppressWarnings("synthetic-access") @Override public DoubleArray apply(DoubleArray x) { ArgChecker.notNull(x, "x"); double y = function.apply(x); return DoubleArray.of(x.size(), i -> { double down = function.apply(x.with(i, x.get(i) - eps)); return (y - down) / eps; }); } }; default: throw new IllegalArgumentException("Can only handle forward, backward and central differencing"); } } ScalarFieldFirstOrderDifferentiator();  ScalarFieldFirstOrderDifferentiator(FiniteDifferenceType differenceType, double eps); @Override Function<DoubleArray, DoubleArray> differentiate(
      Function<DoubleArray, Double> function); @Override Function<DoubleArray, DoubleArray> differentiate(
      Function<DoubleArray, Double> function,
      Function<DoubleArray, Boolean> domain);  }### Answer:
@Test public void testNullFunction() { assertThatIllegalArgumentException() .isThrownBy(() -> CENTRAL.differentiate((Function<DoubleArray, Double>) null)); }
@Test public void test() { final DoubleArray x = DoubleArray.of(.2245, -1.2344); final DoubleArray anGrad = G.apply(x); final DoubleArray fdFwdGrad = FORWARD.differentiate(F).apply(x); final DoubleArray fdCentGrad = CENTRAL.differentiate(F).apply(x); final DoubleArray fdBackGrad = BACKWARD.differentiate(F).apply(x); for (int i = 0; i < 2; i++) { assertThat(fdFwdGrad.get(i)).isCloseTo(anGrad.get(i), offset(10 * EPS)); assertThat(fdCentGrad.get(i)).isCloseTo(anGrad.get(i), offset(EPS * EPS)); assertThat(fdBackGrad.get(i)).isCloseTo(anGrad.get(i), offset(10 * EPS)); } }
@Test public void domainTest() { final DoubleArray[] x = new DoubleArray[3]; x[0] = DoubleArray.of(0.2245, -1.2344); x[1] = DoubleArray.of(0.0, 12.6); x[2] = DoubleArray.of(Math.PI, 0.0); final Function<DoubleArray, DoubleArray> fdGradFunc = CENTRAL.differentiate(F, DOMAIN); for (int k = 0; k < 3; k++) { final DoubleArray fdRes = fdGradFunc.apply(x[k]); final DoubleArray alRes = G.apply(x[k]); for (int i = 0; i < 2; i++) { assertThat(fdRes.get(i)).isCloseTo(alRes.get(i), offset(1e-7)); } } }