I would like to fit a quadratic function y = a + bx + cx^2 to some data, in such a way that c is always greater than or equal to 0 in the final result. That is, I would like to restrict my search domain over c to a particular range ([0, Double.MAX_VALUE]). Currently, I have the following code snippet:
final CurveFitter<Parametric> fitter = new CurveFitter<Parametric>(new LevenbergMarquardtOptimizer());
fitter.addObservedPoint(0, 0);
fitter.addObservedPoint(1, -1);
fitter.addObservedPoint(-1, -1);
fitter.addObservedPoint(2, -4);
fitter.addObservedPoint(-2, -4);
final double[] init = { 1, 2, 3 };
final double[] best = fitter.fit(new PositivePolynomialFunctionParametric(), init);
final PolynomialFunction fitted = new PolynomialFunction(best);
System.out.println(Arrays.toString(fitted.getCoefficients()));
where:
private static class PositivePolynomialFunctionParametric extends PolynomialFunction.Parametric {
@Override
public double value(double x, double... parameters) {
parameters[parameters.length - 1] = Math.abs(parameters[parameters.length - 1]);
return super.value(x, parameters);
}
@Override
public double[] gradient(double x, double... parameters) {
parameters[parameters.length - 1] = Math.abs(parameters[parameters.length - 1]);
return super.gradient(x, parameters);
}
}
The output makes sense:
[-1.4286835350284688, -8.489786562989103E-17, 1.0300498244514197E-11]
This seems to work in this particular application, but it is not a very elegant solution for the general case of restricting the search domain. Is there a better way to do this?
You should use one of the optimizers that implements/extends the *BoundsOptimizer types, or that supports a SimpleBounds in its OptimizationData. Section 12.4 of the user guide on optimization also mentions a way to adjust the function being optimized, but recommends using one of the bounds-supporting algorithms instead.