1/*2* Licensed to the Apache Software Foundation (ASF) under one or more3* contributor license agreements. See the NOTICE file distributed with4* this work for additional information regarding copyright ownership.5* The ASF licenses this file to You under the Apache License, Version 2.06* (the "License"); you may not use this file except in compliance with7* the License. You may obtain a copy of the License at8*9* http://www.apache.org/licenses/LICENSE-2.010*11* Unless required by applicable law or agreed to in writing, software12* 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 and15* limitations under the License.16*/17 18packageorg.apache.commons.math3.optimization; 19 20importorg.apache.commons.math3.analysis.MultivariateFunction; 21importorg.apache.commons.math3.analysis.MultivariateVectorFunction; 22importorg.apache.commons.math3.exception.DimensionMismatchException; 23importorg.apache.commons.math3.linear.RealMatrix; 24 25/** This class converts {@link MultivariateVectorFunction vectorial26* objective functions} to {@link MultivariateFunction scalar objective functions}27* when the goal is to minimize them.28* <p>29* This class is mostly used when the vectorial objective function represents30* a theoretical result computed from a point set applied to a model and31* the models point must be adjusted to fit the theoretical result to some32* reference observations. The observations may be obtained for example from33* physical measurements whether the model is built from theoretical34* considerations.35* </p>36* <p>37* This class computes a possibly weighted squared sum of the residuals, which is38* a scalar value. The residuals are the difference between the theoretical model39* (i.e. the output of the vectorial objective function) and the observations. The40* class implements the {@link MultivariateFunction} interface and can therefore be41* minimized by any optimizer supporting scalar objectives functions.This is one way42* to perform a least square estimation. There are other ways to do this without using43* this converter, as some optimization algorithms directly support vectorial objective44* functions.45* </p>46* <p>47* This class support combination of residuals with or without weights and correlations.48* </p>49*50* @see MultivariateFunction51* @see MultivariateVectorFunction52* @version $Id: LeastSquaresConverter.java 1591835 2014-05-02 09:04:01Z tn $53* @deprecated As of 3.1 (to be removed in 4.0).54* @since 2.055*/56 57 @Deprecated 58publicclassLeastSquaresConverterimplementsMultivariateFunction { 59 60/** Underlying vectorial function. */61privatefinalMultivariateVectorFunction function; 62 63/** Observations to be compared to objective function to compute residuals. */64privatefinaldouble[] observations; 65 66/** Optional weights for the residuals. */67privatefinaldouble[] weights; 68 69/** Optional scaling matrix (weight and correlations) for the residuals. */70privatefinalRealMatrix scale; 71 72/** Build a simple converter for uncorrelated residuals with the same weight.73* @param function vectorial residuals function to wrap74* @param observations observations to be compared to objective function to compute residuals75*/76publicLeastSquaresConverter(finalMultivariateVectorFunction function, 77finaldouble[] observations) { 78this.function = function; 79this.observations = observations.clone(); 80this.weights =null; 81this.scale =null; 82 } 83 84/** Build a simple converter for uncorrelated residuals with the specific weights.85* <p>86* The scalar objective function value is computed as:87* <pre>88* objective = ∑weight<sub>i</sub>(observation<sub>i</sub>-objective<sub>i</sub>)<sup>2</sup>89* </pre>90* </p>91* <p>92* Weights can be used for example to combine residuals with different standard93* deviations. As an example, consider a residuals array in which even elements94* are angular measurements in degrees with a 0.01° standard deviation and95* odd elements are distance measurements in meters with a 15m standard deviation.96* In this case, the weights array should be initialized with value97* 1.0/(0.01<sup>2</sup>) in the even elements and 1.0/(15.0<sup>2</sup>) in the98* odd elements (i.e. reciprocals of variances).99* </p>100* <p>101* The array computed by the objective function, the observations array and the102* weights array must have consistent sizes or a {@link DimensionMismatchException}103* will be triggered while computing the scalar objective.104* </p>105* @param function vectorial residuals function to wrap106* @param observations observations to be compared to objective function to compute residuals107* @param weights weights to apply to the residuals108* @exception DimensionMismatchException if the observations vector and the weights109* vector dimensions do not match (objective function dimension is checked only when110* the {@link #value(double[])} method is called)111*/112publicLeastSquaresConverter(finalMultivariateVectorFunction function, 113finaldouble[] observations,finaldouble[] weights) { 114if(observations.length != weights.length) { 115thrownewDimensionMismatchException(observations.length, weights.length); 116 } 117this.function = function; 118this.observations = observations.clone(); 119this.weights = weights.clone(); 120this.scale =null; 121 } 122 123/** Build a simple converter for correlated residuals with the specific weights.124* <p>125* The scalar objective function value is computed as:126* <pre>127* objective = y<sup>T</sup>y with y = scale×(observation-objective)128* </pre>129* </p>130* <p>131* The array computed by the objective function, the observations array and the132* the scaling matrix must have consistent sizes or a {@link DimensionMismatchException}133* will be triggered while computing the scalar objective.134* </p>135* @param function vectorial residuals function to wrap136* @param observations observations to be compared to objective function to compute residuals137* @param scale scaling matrix138* @throws DimensionMismatchException if the observations vector and the scale139* matrix dimensions do not match (objective function dimension is checked only when140* the {@link #value(double[])} method is called)141*/142publicLeastSquaresConverter(finalMultivariateVectorFunction function, 143finaldouble[] observations,finalRealMatrix scale) { 144if(observations.length != scale.getColumnDimension()) { 145thrownewDimensionMismatchException(observations.length, scale.getColumnDimension()); 146 } 147this.function = function; 148this.observations = observations.clone(); 149this.weights =null; 150this.scale = scale.copy(); 151 } 152 153/** {@inheritDoc} */154publicdoublevalue(finaldouble[] point) { 155// compute residuals156finaldouble[] residuals = function.value(point); 157if(residuals.length != observations.length) { 158thrownewDimensionMismatchException(residuals.length, observations.length); 159 } 160for(inti = 0; i < residuals.length; ++i) { 161 residuals[i] -= observations[i]; 162 } 163 164// compute sum of squares165doublesumSquares = 0; 166if(weights !=null) { 167for(inti = 0; i < residuals.length; ++i) { 168finaldoubleri = residuals[i]; 169 sumSquares += weights[i] * ri * ri; 170 } 171 }elseif(scale !=null) { 172for(finaldoubleyi : scale.operate(residuals)) { 173 sumSquares += yi * yi; 174 } 175 }else{ 176for(finaldoubleri : residuals) { 177 sumSquares += ri * ri; 178 } 179 } 180 181returnsumSquares; 182 } 183 }