Hello. Le jeu. 20 janv. 2022 à 15:06, qiqi tang <tangonepiece...@gmail.com> a écrit : > > Dear Sir/Madam, > I recently used the CurveFitter tool inside the commons package and > I found a problem that I couldn't constrain the relevant parameters.
A possible approach is to transform the relevant parameters so that whatever value is tried by the optimizer, it always maps to a value within the allowed range (see below). > The specific relevant codes are as follows: import org.apache.commons.math4.legacy.analysis.function.Logit; import org.apache.commons.math4.legacy.analysis.function.Sigmoid; > public class MyFuncFitter extends AbstractCurveFitter { private Sigmoid constrainedM; private Logit unconstrainedK; private Sigmoid constrainedK; private Logit unconstrainedK public MyFuncFitter(minM, maxM, minK, maxK) { constrainedM = new Sigmoid(minM, maxM); unconstrainedM = new Logit(minM, maxM); constrainedK = new Sigmoid(minK, maxK); unconstrainedK = new Logit(minK, maxK); } > @Override > protected LeastSquaresProblem > getProblem(Collection<WeightedObservedPoint> points) { > final int len = points.size(); > final double[] target = new double[len]; > final double[] weights = new double[len]; > final double[] initialGuess = { unconstrainedM.value(50), unconstrainedK.value(1.0), 1.0 }; > > int i = 0; > for (WeightedObservedPoint point : points) { > target[i] = point.getY(); > weights[i] = point.getWeight(); > i += 1; > } > > final AbstractCurveFitter.TheoreticalValuesFunction model = > new AbstractCurveFitter.TheoreticalValuesFunction(new MyFunc(), > points); > > return new LeastSquaresBuilder(). > maxEvaluations(Integer.MAX_VALUE). > maxIterations(Integer.MAX_VALUE). > start(initialGuess). > target(target). > weight(new DiagonalMatrix(weights)). > model(model.getModelFunction(), > model.getModelFunctionJacobian()).build(); > }} > > public class MyFunc implements ParametricUnivariateFunction { > @Override > public double value(double x, double... parameters) { final double m = constrainedM.value(parameters[0]); final double k = constrainedK.value(parameters[1]); final double b = parameters[2]; > return m * k * b * Math.exp(-k * x) * Math.pow(1 - Math.exp(-k > * x), b - 1); > } > > @Override > public double[] gradient(double x, double... parameters) { final double m = constrainedM.value(parameters[0]); final double k = constrainedK.value(parameters[1]); final double b = parameters[2]; > return new double[]{ > b * k * Math.exp(-k * x) * Math.pow(1 - Math.exp(-k * > x), b - 1), > (b - 1) * b * k * m * x * Math.exp(-2 * k * x) * > Math.pow(1 - Math.exp(-k * x), b - 2) + b * m * Math.exp(-k * x) * > Math.pow(1 - Math.exp(-k * x), b - 1) - b * k * m * x * Math.exp(-k * > x) * Math.pow(1 - Math.exp(-k * x), b - 1), > k * m * Math.exp(-k * x) * Math.pow(1 - Math.exp(-k * > x), b - 1) + b * k * m * Math.exp(-k * x) * Math.pow(1 - Math.exp(-k * > x), b - 1) * Math.log(1 - Math.exp(-k * x)) > }; @Override public double[] fit(Collection<WeightedObservedPoint> points) { final double[] p = super.fit(points); return new double[] { constrainedM.value(p[0]), constrainedK.value(p[1]), p[2] }; } > } > > public static void main(String[] args) { > MyFuncFitter fitter = new MyFuncFitter(); > ArrayList<WeightedObservedPoint> points = new ArrayList<>(); > points.add(new WeightedObservedPoint(1.0, 0.25, 3.801713179)); > points.add(new WeightedObservedPoint(1.0, 4, 10.46561902)); > final double coeffs[] = fitter.fit(points); > System.out.println(Arrays.toString(coeffs)); > }} > > Then, What should I do to limit the parameters 'm' to 1 to 100 and 'k' > to 100 to 10,000,It would be nice if the code dome was available. I don't understand what "code dome" means. > Please help me thank you very much! Let us know how the above suggestion (untested code) went. Best regards, Gilles --------------------------------------------------------------------- To unsubscribe, e-mail: user-unsubscr...@commons.apache.org For additional commands, e-mail: user-h...@commons.apache.org