@Test
public void testFindSingleLocalMinimum() {

    final int numDimension = 10;
    GradientDescent.LossDefinition<Void> lossDefinition = new GradientDescent.LossDefinition<Void>() {
        @Override
        public double calculateLoss(VectorModel model, Collection<Observation<Void>> observations) {
            double loss = 0d;
            double[] parameters = model.getParameters();
            for (int i = 0; i < parameters.length; i++) {
                double v = parameters[i];
                loss += v * v;
            }
            return loss;
        }
        @Override
        public double[] calculateGradient(VectorModel model, Collection<Observation<Void>> observations) {
            double[] gradient = new double[numDimension];
            double[] parameters = model.getParameters();
            for (int i = 0; i < parameters.length; i++) {
                double v = parameters[i];
                gradient[i] = 2 * v; // (x^2 + k)' = 2x
            }
            return gradient;
        }
    };
    Collection<Observation<Void>> observations = Collections.emptyList();
    VectorModel model = GradientDescent.minimize(lossDefinition, observations, numDimension, 0.1, 1, 0.0001);
    double loss = lossDefinition.calculateLoss(model, observations);
    double[] parameters = model.getParameters();
    Assert.assertEquals(numDimension, parameters.length);
    Assert.assertEquals(0, loss, 0.01);
    for (int i = 0; i < parameters.length; i++) {
        double v = parameters[i];
        Assert.assertEquals(0d, v, 0.01);
    }
}