View Javadoc
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 }