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* @deprecated As of 3.1 (to be removed in 4.0).53* @since 2.054*/55 56 @Deprecated 57publicclassLeastSquaresConverterimplementsMultivariateFunction { 58 59/** Underlying vectorial function. */60privatefinalMultivariateVectorFunction function; 61 62/** Observations to be compared to objective function to compute residuals. */63privatefinaldouble[] observations; 64 65/** Optional weights for the residuals. */66privatefinaldouble[] weights; 67 68/** Optional scaling matrix (weight and correlations) for the residuals. */69privatefinalRealMatrix scale; 70 71/** Build a simple converter for uncorrelated residuals with the same weight.72* @param function vectorial residuals function to wrap73* @param observations observations to be compared to objective function to compute residuals74*/75publicLeastSquaresConverter(finalMultivariateVectorFunction function, 76finaldouble[] observations) { 77this.function = function; 78this.observations = observations.clone(); 79this.weights =null; 80this.scale =null; 81 } 82 83/** Build a simple converter for uncorrelated residuals with the specific weights.84* <p>85* The scalar objective function value is computed as:86* <pre>87* objective = ∑weight<sub>i</sub>(observation<sub>i</sub>-objective<sub>i</sub>)<sup>2</sup>88* </pre>89* </p>90* <p>91* Weights can be used for example to combine residuals with different standard92* deviations. As an example, consider a residuals array in which even elements93* are angular measurements in degrees with a 0.01° standard deviation and94* odd elements are distance measurements in meters with a 15m standard deviation.95* In this case, the weights array should be initialized with value96* 1.0/(0.01<sup>2</sup>) in the even elements and 1.0/(15.0<sup>2</sup>) in the97* odd elements (i.e. reciprocals of variances).98* </p>99* <p>100* The array computed by the objective function, the observations array and the101* weights array must have consistent sizes or a {@link DimensionMismatchException}102* will be triggered while computing the scalar objective.103* </p>104* @param function vectorial residuals function to wrap105* @param observations observations to be compared to objective function to compute residuals106* @param weights weights to apply to the residuals107* @exception DimensionMismatchException if the observations vector and the weights108* vector dimensions do not match (objective function dimension is checked only when109* the {@link #value(double[])} method is called)110*/111publicLeastSquaresConverter(finalMultivariateVectorFunction function, 112finaldouble[] observations,finaldouble[] weights) { 113if(observations.length != weights.length) { 114thrownewDimensionMismatchException(observations.length, weights.length); 115 } 116this.function = function; 117this.observations = observations.clone(); 118this.weights = weights.clone(); 119this.scale =null; 120 } 121 122/** Build a simple converter for correlated residuals with the specific weights.123* <p>124* The scalar objective function value is computed as:125* <pre>126* objective = y<sup>T</sup>y with y = scale×(observation-objective)127* </pre>128* </p>129* <p>130* The array computed by the objective function, the observations array and the131* the scaling matrix must have consistent sizes or a {@link DimensionMismatchException}132* will be triggered while computing the scalar objective.133* </p>134* @param function vectorial residuals function to wrap135* @param observations observations to be compared to objective function to compute residuals136* @param scale scaling matrix137* @throws DimensionMismatchException if the observations vector and the scale138* matrix dimensions do not match (objective function dimension is checked only when139* the {@link #value(double[])} method is called)140*/141publicLeastSquaresConverter(finalMultivariateVectorFunction function, 142finaldouble[] observations,finalRealMatrix scale) { 143if(observations.length != scale.getColumnDimension()) { 144thrownewDimensionMismatchException(observations.length, scale.getColumnDimension()); 145 } 146this.function = function; 147this.observations = observations.clone(); 148this.weights =null; 149this.scale = scale.copy(); 150 } 151 152/** {@inheritDoc} */153publicdoublevalue(finaldouble[] point) { 154// compute residuals155finaldouble[] residuals = function.value(point); 156if(residuals.length != observations.length) { 157thrownewDimensionMismatchException(residuals.length, observations.length); 158 } 159for(inti = 0; i < residuals.length; ++i) { 160 residuals[i] -= observations[i]; 161 } 162 163// compute sum of squares164doublesumSquares = 0; 165if(weights !=null) { 166for(inti = 0; i < residuals.length; ++i) { 167finaldoubleri = residuals[i]; 168 sumSquares += weights[i] * ri * ri; 169 } 170 }elseif(scale !=null) { 171for(finaldoubleyi : scale.operate(residuals)) { 172 sumSquares += yi * yi; 173 } 174 }else{ 175for(finaldoubleri : residuals) { 176 sumSquares += ri * ri; 177 } 178 } 179 180returnsumSquares; 181 } 182 }