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 
18 package org.apache.commons.math3.optimization.direct;
19 
20 import org.apache.commons.math3.util.Incrementor;
21 import org.apache.commons.math3.exception.MaxCountExceededException;
22 import org.apache.commons.math3.exception.TooManyEvaluationsException;
23 import org.apache.commons.math3.exception.DimensionMismatchException;
24 import org.apache.commons.math3.exception.NullArgumentException;
25 import org.apache.commons.math3.analysis.MultivariateVectorFunction;
26 import org.apache.commons.math3.optimization.OptimizationData;
27 import org.apache.commons.math3.optimization.InitialGuess;
28 import org.apache.commons.math3.optimization.Target;
29 import org.apache.commons.math3.optimization.Weight;
30 import org.apache.commons.math3.optimization.BaseMultivariateVectorOptimizer;
31 import org.apache.commons.math3.optimization.ConvergenceChecker;
32 import org.apache.commons.math3.optimization.PointVectorValuePair;
33 import org.apache.commons.math3.optimization.SimpleVectorValueChecker;
34 import org.apache.commons.math3.linear.RealMatrix;
35 
36 /**
37  * Base class for implementing optimizers for multivariate scalar functions.
38  * This base class handles the boiler-plate methods associated to thresholds
39  * settings, iterations and evaluations counting.
40  *
41  * @param <FUNC> the type of the objective function to be optimized
42  *
43  * @deprecated As of 3.1 (to be removed in 4.0).
44  * @since 3.0
45  */
46 @Deprecated
47 public abstract class BaseAbstractMultivariateVectorOptimizer<FUNC extends MultivariateVectorFunction>
48     implements BaseMultivariateVectorOptimizer<FUNC> {
49     /** Evaluations counter. */
50     protected final Incrementor evaluations = new Incrementor();
51     /** Convergence checker. */
52     private ConvergenceChecker<PointVectorValuePair> checker;
53     /** Target value for the objective functions at optimum. */
54     private double[] target;
55     /** Weight matrix. */
56     private RealMatrix weightMatrix;
57     /** Weight for the least squares cost computation.
58      * @deprecated
59      */
60     @Deprecated
61     private double[] weight;
62     /** Initial guess. */
63     private double[] start;
64     /** Objective function. */
65     private FUNC function;
66 
67     /**
68      * Simple constructor with default settings.
69      * The convergence check is set to a {@link SimpleVectorValueChecker}.
70      * @deprecated See {@link SimpleVectorValueChecker#SimpleVectorValueChecker()}
71      */
72     @Deprecated
BaseAbstractMultivariateVectorOptimizer()73     protected BaseAbstractMultivariateVectorOptimizer() {
74         this(new SimpleVectorValueChecker());
75     }
76     /**
77      * @param checker Convergence checker.
78      */
BaseAbstractMultivariateVectorOptimizer(ConvergenceChecker<PointVectorValuePair> checker)79     protected BaseAbstractMultivariateVectorOptimizer(ConvergenceChecker<PointVectorValuePair> checker) {
80         this.checker = checker;
81     }
82 
83     /** {@inheritDoc} */
getMaxEvaluations()84     public int getMaxEvaluations() {
85         return evaluations.getMaximalCount();
86     }
87 
88     /** {@inheritDoc} */
getEvaluations()89     public int getEvaluations() {
90         return evaluations.getCount();
91     }
92 
93     /** {@inheritDoc} */
getConvergenceChecker()94     public ConvergenceChecker<PointVectorValuePair> getConvergenceChecker() {
95         return checker;
96     }
97 
98     /**
99      * Compute the objective function value.
100      *
101      * @param point Point at which the objective function must be evaluated.
102      * @return the objective function value at the specified point.
103      * @throws TooManyEvaluationsException if the maximal number of evaluations is
104      * exceeded.
105      */
computeObjectiveValue(double[] point)106     protected double[] computeObjectiveValue(double[] point) {
107         try {
108             evaluations.incrementCount();
109         } catch (MaxCountExceededException e) {
110             throw new TooManyEvaluationsException(e.getMax());
111         }
112         return function.value(point);
113     }
114 
115     /** {@inheritDoc}
116      *
117      * @deprecated As of 3.1. Please use
118      * {@link #optimize(int,MultivariateVectorFunction,OptimizationData[])}
119      * instead.
120      */
121     @Deprecated
optimize(int maxEval, FUNC f, double[] t, double[] w, double[] startPoint)122     public PointVectorValuePair optimize(int maxEval, FUNC f, double[] t, double[] w,
123                                          double[] startPoint) {
124         return optimizeInternal(maxEval, f, t, w, startPoint);
125     }
126 
127     /**
128      * Optimize an objective function.
129      *
130      * @param maxEval Allowed number of evaluations of the objective function.
131      * @param f Objective function.
132      * @param optData Optimization data. The following data will be looked for:
133      * <ul>
134      *  <li>{@link Target}</li>
135      *  <li>{@link Weight}</li>
136      *  <li>{@link InitialGuess}</li>
137      * </ul>
138      * @return the point/value pair giving the optimal value of the objective
139      * function.
140      * @throws TooManyEvaluationsException if the maximal number of
141      * evaluations is exceeded.
142      * @throws DimensionMismatchException if the initial guess, target, and weight
143      * arguments have inconsistent dimensions.
144      *
145      * @since 3.1
146      */
optimize(int maxEval, FUNC f, OptimizationData... optData)147     protected PointVectorValuePair optimize(int maxEval,
148                                             FUNC f,
149                                             OptimizationData... optData)
150         throws TooManyEvaluationsException,
151                DimensionMismatchException {
152         return optimizeInternal(maxEval, f, optData);
153     }
154 
155     /**
156      * Optimize an objective function.
157      * Optimization is considered to be a weighted least-squares minimization.
158      * The cost function to be minimized is
159      * <code>&sum;weight<sub>i</sub>(objective<sub>i</sub> - target<sub>i</sub>)<sup>2</sup></code>
160      *
161      * @param f Objective function.
162      * @param t Target value for the objective functions at optimum.
163      * @param w Weights for the least squares cost computation.
164      * @param startPoint Start point for optimization.
165      * @return the point/value pair giving the optimal value for objective
166      * function.
167      * @param maxEval Maximum number of function evaluations.
168      * @throws org.apache.commons.math3.exception.DimensionMismatchException
169      * if the start point dimension is wrong.
170      * @throws org.apache.commons.math3.exception.TooManyEvaluationsException
171      * if the maximal number of evaluations is exceeded.
172      * @throws org.apache.commons.math3.exception.NullArgumentException if
173      * any argument is {@code null}.
174      * @deprecated As of 3.1. Please use
175      * {@link #optimizeInternal(int,MultivariateVectorFunction,OptimizationData[])}
176      * instead.
177      */
178     @Deprecated
optimizeInternal(final int maxEval, final FUNC f, final double[] t, final double[] w, final double[] startPoint)179     protected PointVectorValuePair optimizeInternal(final int maxEval, final FUNC f,
180                                                     final double[] t, final double[] w,
181                                                     final double[] startPoint) {
182         // Checks.
183         if (f == null) {
184             throw new NullArgumentException();
185         }
186         if (t == null) {
187             throw new NullArgumentException();
188         }
189         if (w == null) {
190             throw new NullArgumentException();
191         }
192         if (startPoint == null) {
193             throw new NullArgumentException();
194         }
195         if (t.length != w.length) {
196             throw new DimensionMismatchException(t.length, w.length);
197         }
198 
199         return optimizeInternal(maxEval, f,
200                                 new Target(t),
201                                 new Weight(w),
202                                 new InitialGuess(startPoint));
203     }
204 
205     /**
206      * Optimize an objective function.
207      *
208      * @param maxEval Allowed number of evaluations of the objective function.
209      * @param f Objective function.
210      * @param optData Optimization data. The following data will be looked for:
211      * <ul>
212      *  <li>{@link Target}</li>
213      *  <li>{@link Weight}</li>
214      *  <li>{@link InitialGuess}</li>
215      * </ul>
216      * @return the point/value pair giving the optimal value of the objective
217      * function.
218      * @throws TooManyEvaluationsException if the maximal number of
219      * evaluations is exceeded.
220      * @throws DimensionMismatchException if the initial guess, target, and weight
221      * arguments have inconsistent dimensions.
222      *
223      * @since 3.1
224      */
optimizeInternal(int maxEval, FUNC f, OptimizationData... optData)225     protected PointVectorValuePair optimizeInternal(int maxEval,
226                                                     FUNC f,
227                                                     OptimizationData... optData)
228         throws TooManyEvaluationsException,
229                DimensionMismatchException {
230         // Set internal state.
231         evaluations.setMaximalCount(maxEval);
232         evaluations.resetCount();
233         function = f;
234         // Retrieve other settings.
235         parseOptimizationData(optData);
236         // Check input consistency.
237         checkParameters();
238         // Allow subclasses to reset their own internal state.
239         setUp();
240         // Perform computation.
241         return doOptimize();
242     }
243 
244     /**
245      * Gets the initial values of the optimized parameters.
246      *
247      * @return the initial guess.
248      */
getStartPoint()249     public double[] getStartPoint() {
250         return start.clone();
251     }
252 
253     /**
254      * Gets the weight matrix of the observations.
255      *
256      * @return the weight matrix.
257      * @since 3.1
258      */
getWeight()259     public RealMatrix getWeight() {
260         return weightMatrix.copy();
261     }
262     /**
263      * Gets the observed values to be matched by the objective vector
264      * function.
265      *
266      * @return the target values.
267      * @since 3.1
268      */
getTarget()269     public double[] getTarget() {
270         return target.clone();
271     }
272 
273     /**
274      * Gets the objective vector function.
275      * Note that this access bypasses the evaluation counter.
276      *
277      * @return the objective vector function.
278      * @since 3.1
279      */
getObjectiveFunction()280     protected FUNC getObjectiveFunction() {
281         return function;
282     }
283 
284     /**
285      * Perform the bulk of the optimization algorithm.
286      *
287      * @return the point/value pair giving the optimal value for the
288      * objective function.
289      */
doOptimize()290     protected abstract PointVectorValuePair doOptimize();
291 
292     /**
293      * @return a reference to the {@link #target array}.
294      * @deprecated As of 3.1.
295      */
296     @Deprecated
getTargetRef()297     protected double[] getTargetRef() {
298         return target;
299     }
300     /**
301      * @return a reference to the {@link #weight array}.
302      * @deprecated As of 3.1.
303      */
304     @Deprecated
getWeightRef()305     protected double[] getWeightRef() {
306         return weight;
307     }
308 
309     /**
310      * Method which a subclass <em>must</em> override whenever its internal
311      * state depend on the {@link OptimizationData input} parsed by this base
312      * class.
313      * It will be called after the parsing step performed in the
314      * {@link #optimize(int,MultivariateVectorFunction,OptimizationData[])
315      * optimize} method and just before {@link #doOptimize()}.
316      *
317      * @since 3.1
318      */
setUp()319     protected void setUp() {
320         // XXX Temporary code until the new internal data is used everywhere.
321         final int dim = target.length;
322         weight = new double[dim];
323         for (int i = 0; i < dim; i++) {
324             weight[i] = weightMatrix.getEntry(i, i);
325         }
326     }
327 
328     /**
329      * Scans the list of (required and optional) optimization data that
330      * characterize the problem.
331      *
332      * @param optData Optimization data. The following data will be looked for:
333      * <ul>
334      *  <li>{@link Target}</li>
335      *  <li>{@link Weight}</li>
336      *  <li>{@link InitialGuess}</li>
337      * </ul>
338      */
parseOptimizationData(OptimizationData... optData)339     private void parseOptimizationData(OptimizationData... optData) {
340         // The existing values (as set by the previous call) are reused if
341         // not provided in the argument list.
342         for (OptimizationData data : optData) {
343             if (data instanceof Target) {
344                 target = ((Target) data).getTarget();
345                 continue;
346             }
347             if (data instanceof Weight) {
348                 weightMatrix = ((Weight) data).getWeight();
349                 continue;
350             }
351             if (data instanceof InitialGuess) {
352                 start = ((InitialGuess) data).getInitialGuess();
353                 continue;
354             }
355         }
356     }
357 
358     /**
359      * Check parameters consistency.
360      *
361      * @throws DimensionMismatchException if {@link #target} and
362      * {@link #weightMatrix} have inconsistent dimensions.
363      */
checkParameters()364     private void checkParameters() {
365         if (target.length != weightMatrix.getColumnDimension()) {
366             throw new DimensionMismatchException(target.length,
367                                                  weightMatrix.getColumnDimension());
368         }
369     }
370 }
371