PolynomialCurveFitter.java

  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.  *      http://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. package org.apache.commons.math3.fitting;

  18. import java.util.Collection;

  19. import org.apache.commons.math3.analysis.polynomials.PolynomialFunction;
  20. import org.apache.commons.math3.exception.MathInternalError;
  21. import org.apache.commons.math3.fitting.leastsquares.LeastSquaresBuilder;
  22. import org.apache.commons.math3.fitting.leastsquares.LeastSquaresProblem;
  23. import org.apache.commons.math3.linear.DiagonalMatrix;

  24. /**
  25.  * Fits points to a {@link
  26.  * org.apache.commons.math3.analysis.polynomials.PolynomialFunction.Parametric polynomial}
  27.  * function.
  28.  * <br/>
  29.  * The size of the {@link #withStartPoint(double[]) initial guess} array defines the
  30.  * degree of the polynomial to be fitted.
  31.  * They must be sorted in increasing order of the polynomial's degree.
  32.  * The optimal values of the coefficients will be returned in the same order.
  33.  *
  34.  * @since 3.3
  35.  */
  36. public class PolynomialCurveFitter extends AbstractCurveFitter {
  37.     /** Parametric function to be fitted. */
  38.     private static final PolynomialFunction.Parametric FUNCTION = new PolynomialFunction.Parametric();
  39.     /** Initial guess. */
  40.     private final double[] initialGuess;
  41.     /** Maximum number of iterations of the optimization algorithm. */
  42.     private final int maxIter;

  43.     /**
  44.      * Contructor used by the factory methods.
  45.      *
  46.      * @param initialGuess Initial guess.
  47.      * @param maxIter Maximum number of iterations of the optimization algorithm.
  48.      * @throws MathInternalError if {@code initialGuess} is {@code null}.
  49.      */
  50.     private PolynomialCurveFitter(double[] initialGuess,
  51.                                   int maxIter) {
  52.         this.initialGuess = initialGuess;
  53.         this.maxIter = maxIter;
  54.     }

  55.     /**
  56.      * Creates a default curve fitter.
  57.      * Zero will be used as initial guess for the coefficients, and the maximum
  58.      * number of iterations of the optimization algorithm is set to
  59.      * {@link Integer#MAX_VALUE}.
  60.      *
  61.      * @param degree Degree of the polynomial to be fitted.
  62.      * @return a curve fitter.
  63.      *
  64.      * @see #withStartPoint(double[])
  65.      * @see #withMaxIterations(int)
  66.      */
  67.     public static PolynomialCurveFitter create(int degree) {
  68.         return new PolynomialCurveFitter(new double[degree + 1], Integer.MAX_VALUE);
  69.     }

  70.     /**
  71.      * Configure the start point (initial guess).
  72.      * @param newStart new start point (initial guess)
  73.      * @return a new instance.
  74.      */
  75.     public PolynomialCurveFitter withStartPoint(double[] newStart) {
  76.         return new PolynomialCurveFitter(newStart.clone(),
  77.                                          maxIter);
  78.     }

  79.     /**
  80.      * Configure the maximum number of iterations.
  81.      * @param newMaxIter maximum number of iterations
  82.      * @return a new instance.
  83.      */
  84.     public PolynomialCurveFitter withMaxIterations(int newMaxIter) {
  85.         return new PolynomialCurveFitter(initialGuess,
  86.                                          newMaxIter);
  87.     }

  88.     /** {@inheritDoc} */
  89.     @Override
  90.     protected LeastSquaresProblem getProblem(Collection<WeightedObservedPoint> observations) {
  91.         // Prepare least-squares problem.
  92.         final int len = observations.size();
  93.         final double[] target  = new double[len];
  94.         final double[] weights = new double[len];

  95.         int i = 0;
  96.         for (WeightedObservedPoint obs : observations) {
  97.             target[i]  = obs.getY();
  98.             weights[i] = obs.getWeight();
  99.             ++i;
  100.         }

  101.         final AbstractCurveFitter.TheoreticalValuesFunction model =
  102.                 new AbstractCurveFitter.TheoreticalValuesFunction(FUNCTION, observations);

  103.         if (initialGuess == null) {
  104.             throw new MathInternalError();
  105.         }

  106.         // Return a new least squares problem set up to fit a polynomial curve to the
  107.         // observed points.
  108.         return new LeastSquaresBuilder().
  109.                 maxEvaluations(Integer.MAX_VALUE).
  110.                 maxIterations(maxIter).
  111.                 start(initialGuess).
  112.                 target(target).
  113.                 weight(new DiagonalMatrix(weights)).
  114.                 model(model.getModelFunction(), model.getModelFunctionJacobian()).
  115.                 build();

  116.     }

  117. }