001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.math3.fitting; 018 019import java.util.Collection; 020 021import org.apache.commons.math3.analysis.polynomials.PolynomialFunction; 022import org.apache.commons.math3.exception.MathInternalError; 023import org.apache.commons.math3.fitting.leastsquares.LeastSquaresBuilder; 024import org.apache.commons.math3.fitting.leastsquares.LeastSquaresProblem; 025import org.apache.commons.math3.linear.DiagonalMatrix; 026 027/** 028 * Fits points to a {@link 029 * org.apache.commons.math3.analysis.polynomials.PolynomialFunction.Parametric polynomial} 030 * function. 031 * <br/> 032 * The size of the {@link #withStartPoint(double[]) initial guess} array defines the 033 * degree of the polynomial to be fitted. 034 * They must be sorted in increasing order of the polynomial's degree. 035 * The optimal values of the coefficients will be returned in the same order. 036 * 037 * @since 3.3 038 */ 039public class PolynomialCurveFitter extends AbstractCurveFitter { 040 /** Parametric function to be fitted. */ 041 private static final PolynomialFunction.Parametric FUNCTION = new PolynomialFunction.Parametric(); 042 /** Initial guess. */ 043 private final double[] initialGuess; 044 /** Maximum number of iterations of the optimization algorithm. */ 045 private final int maxIter; 046 047 /** 048 * Contructor used by the factory methods. 049 * 050 * @param initialGuess Initial guess. 051 * @param maxIter Maximum number of iterations of the optimization algorithm. 052 * @throws MathInternalError if {@code initialGuess} is {@code null}. 053 */ 054 private PolynomialCurveFitter(double[] initialGuess, 055 int maxIter) { 056 this.initialGuess = initialGuess; 057 this.maxIter = maxIter; 058 } 059 060 /** 061 * Creates a default curve fitter. 062 * Zero will be used as initial guess for the coefficients, and the maximum 063 * number of iterations of the optimization algorithm is set to 064 * {@link Integer#MAX_VALUE}. 065 * 066 * @param degree Degree of the polynomial to be fitted. 067 * @return a curve fitter. 068 * 069 * @see #withStartPoint(double[]) 070 * @see #withMaxIterations(int) 071 */ 072 public static PolynomialCurveFitter create(int degree) { 073 return new PolynomialCurveFitter(new double[degree + 1], Integer.MAX_VALUE); 074 } 075 076 /** 077 * Configure the start point (initial guess). 078 * @param newStart new start point (initial guess) 079 * @return a new instance. 080 */ 081 public PolynomialCurveFitter withStartPoint(double[] newStart) { 082 return new PolynomialCurveFitter(newStart.clone(), 083 maxIter); 084 } 085 086 /** 087 * Configure the maximum number of iterations. 088 * @param newMaxIter maximum number of iterations 089 * @return a new instance. 090 */ 091 public PolynomialCurveFitter withMaxIterations(int newMaxIter) { 092 return new PolynomialCurveFitter(initialGuess, 093 newMaxIter); 094 } 095 096 /** {@inheritDoc} */ 097 @Override 098 protected LeastSquaresProblem getProblem(Collection<WeightedObservedPoint> observations) { 099 // Prepare least-squares problem. 100 final int len = observations.size(); 101 final double[] target = new double[len]; 102 final double[] weights = new double[len]; 103 104 int i = 0; 105 for (WeightedObservedPoint obs : observations) { 106 target[i] = obs.getY(); 107 weights[i] = obs.getWeight(); 108 ++i; 109 } 110 111 final AbstractCurveFitter.TheoreticalValuesFunction model = 112 new AbstractCurveFitter.TheoreticalValuesFunction(FUNCTION, observations); 113 114 if (initialGuess == null) { 115 throw new MathInternalError(); 116 } 117 118 // Return a new least squares problem set up to fit a polynomial curve to the 119 // observed points. 120 return new LeastSquaresBuilder(). 121 maxEvaluations(Integer.MAX_VALUE). 122 maxIterations(maxIter). 123 start(initialGuess). 124 target(target). 125 weight(new DiagonalMatrix(weights)). 126 model(model.getModelFunction(), model.getModelFunctionJacobian()). 127 build(); 128 129 } 130 131}