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
18package org.apache.commons.math.optimization.fitting;
19
20import org.apache.commons.math.FunctionEvaluationException;
21import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
22import org.apache.commons.math.optimization.DifferentiableMultivariateVectorialOptimizer;
23import org.apache.commons.math.optimization.OptimizationException;
24
25/** This class implements a curve fitting specialized for polynomials.
26 * <p>Polynomial fitting is a very simple case of curve fitting. The
27 * estimated coefficients are the polynomial coefficients. They are
28 * searched by a least square estimator.</p>
29 * @version $Revision: 1073270 $ $Date: 2011-02-22 10:19:27 +0100 (mar. 22 févr. 2011) $
30 * @since 2.0
31 */
32
33public class PolynomialFitter {
34
35    /** Fitter for the coefficients. */
36    private final CurveFitter fitter;
37
38    /** Polynomial degree. */
39    private final int degree;
40
41    /** Simple constructor.
42     * <p>The polynomial fitter built this way are complete polynomials,
43     * ie. a n-degree polynomial has n+1 coefficients.</p>
44     * @param degree maximal degree of the polynomial
45     * @param optimizer optimizer to use for the fitting
46     */
47    public PolynomialFitter(int degree, final DifferentiableMultivariateVectorialOptimizer optimizer) {
48        this.fitter = new CurveFitter(optimizer);
49        this.degree = degree;
50    }
51
52    /** Add an observed weighted (x,y) point to the sample.
53     * @param weight weight of the observed point in the fit
54     * @param x abscissa of the point
55     * @param y observed value of the point at x, after fitting we should
56     * have P(x) as close as possible to this value
57     */
58    public void addObservedPoint(double weight, double x, double y) {
59        fitter.addObservedPoint(weight, x, y);
60    }
61
62    /**
63     * Remove all observations.
64     * @since 2.2
65     */
66    public void clearObservations() {
67        fitter.clearObservations();
68    }
69
70    /** Get the polynomial fitting the weighted (x, y) points.
71     * @return polynomial function best fitting the observed points
72     * @exception OptimizationException if the algorithm failed to converge
73     */
74    public PolynomialFunction fit() throws OptimizationException {
75        try {
76            return new PolynomialFunction(fitter.fit(new ParametricPolynomial(), new double[degree + 1]));
77        } catch (FunctionEvaluationException fee) {
78            // should never happen
79            throw new RuntimeException(fee);
80        }
81    }
82
83    /** Dedicated parametric polynomial class. */
84    private static class ParametricPolynomial implements ParametricRealFunction {
85
86        /** {@inheritDoc} */
87        public double[] gradient(double x, double[] parameters) {
88            final double[] gradient = new double[parameters.length];
89            double xn = 1.0;
90            for (int i = 0; i < parameters.length; ++i) {
91                gradient[i] = xn;
92                xn *= x;
93            }
94            return gradient;
95        }
96
97        /** {@inheritDoc} */
98        public double value(final double x, final double[] parameters) {
99            double y = 0;
100            for (int i = parameters.length - 1; i >= 0; --i) {
101                y = y * x + parameters[i];
102            }
103            return y;
104        }
105
106    }
107
108}
109