1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * https://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 /* 19 * This is not the original file distributed by the Apache Software Foundation 20 * It has been modified by the Hipparchus project 21 */ 22 package org.hipparchus.fitting; 23 24 import java.util.Collection; 25 26 import org.hipparchus.analysis.polynomials.PolynomialFunction; 27 import org.hipparchus.exception.MathRuntimeException; 28 import org.hipparchus.linear.DiagonalMatrix; 29 import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresBuilder; 30 import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresProblem; 31 32 /** 33 * Fits points to a {@link 34 * org.hipparchus.analysis.polynomials.PolynomialFunction.Parametric polynomial} 35 * function. 36 * <br> 37 * The size of the {@link #withStartPoint(double[]) initial guess} array defines the 38 * degree of the polynomial to be fitted. 39 * They must be sorted in increasing order of the polynomial's degree. 40 * The optimal values of the coefficients will be returned in the same order. 41 * 42 */ 43 public class PolynomialCurveFitter extends AbstractCurveFitter { 44 /** Parametric function to be fitted. */ 45 private static final PolynomialFunction.Parametric FUNCTION = new PolynomialFunction.Parametric(); 46 /** Initial guess. */ 47 private final double[] initialGuess; 48 /** Maximum number of iterations of the optimization algorithm. */ 49 private final int maxIter; 50 51 /** 52 * Constructor used by the factory methods. 53 * 54 * @param initialGuess Initial guess. 55 * @param maxIter Maximum number of iterations of the optimization algorithm. 56 * @throws MathRuntimeException if {@code initialGuess} is {@code null}. 57 */ 58 private PolynomialCurveFitter(double[] initialGuess, int maxIter) { 59 this.initialGuess = initialGuess.clone(); 60 this.maxIter = maxIter; 61 } 62 63 /** 64 * Creates a default curve fitter. 65 * Zero will be used as initial guess for the coefficients, and the maximum 66 * number of iterations of the optimization algorithm is set to 67 * {@link Integer#MAX_VALUE}. 68 * 69 * @param degree Degree of the polynomial to be fitted. 70 * @return a curve fitter. 71 * 72 * @see #withStartPoint(double[]) 73 * @see #withMaxIterations(int) 74 */ 75 public static PolynomialCurveFitter create(int degree) { 76 return new PolynomialCurveFitter(new double[degree + 1], Integer.MAX_VALUE); 77 } 78 79 /** 80 * Configure the start point (initial guess). 81 * @param newStart new start point (initial guess) 82 * @return a new instance. 83 */ 84 public PolynomialCurveFitter withStartPoint(double[] newStart) { 85 return new PolynomialCurveFitter(newStart.clone(), 86 maxIter); 87 } 88 89 /** 90 * Configure the maximum number of iterations. 91 * @param newMaxIter maximum number of iterations 92 * @return a new instance. 93 */ 94 public PolynomialCurveFitter withMaxIterations(int newMaxIter) { 95 return new PolynomialCurveFitter(initialGuess, 96 newMaxIter); 97 } 98 99 /** {@inheritDoc} */ 100 @Override 101 protected LeastSquaresProblem getProblem(Collection<WeightedObservedPoint> observations) { 102 // Prepare least-squares problem. 103 final int len = observations.size(); 104 final double[] target = new double[len]; 105 final double[] weights = new double[len]; 106 107 int i = 0; 108 for (WeightedObservedPoint obs : observations) { 109 target[i] = obs.getY(); 110 weights[i] = obs.getWeight(); 111 ++i; 112 } 113 114 final AbstractCurveFitter.TheoreticalValuesFunction model = 115 new AbstractCurveFitter.TheoreticalValuesFunction(FUNCTION, observations); 116 117 if (initialGuess == null) { 118 throw MathRuntimeException.createInternalError(); 119 } 120 121 // Return a new least squares problem set up to fit a polynomial curve to the 122 // observed points. 123 return new LeastSquaresBuilder(). 124 maxEvaluations(Integer.MAX_VALUE). 125 maxIterations(maxIter). 126 start(initialGuess). 127 target(target). 128 weight(new DiagonalMatrix(weights)). 129 model(model.getModelFunction(), model.getModelFunctionJacobian()). 130 build(); 131 132 } 133 134 }