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     */
017    
018    package org.apache.commons.math3.optimization.direct;
019    
020    import org.apache.commons.math3.util.Incrementor;
021    import org.apache.commons.math3.exception.MaxCountExceededException;
022    import org.apache.commons.math3.exception.TooManyEvaluationsException;
023    import org.apache.commons.math3.exception.DimensionMismatchException;
024    import org.apache.commons.math3.exception.NullArgumentException;
025    import org.apache.commons.math3.analysis.MultivariateVectorFunction;
026    import org.apache.commons.math3.optimization.OptimizationData;
027    import org.apache.commons.math3.optimization.InitialGuess;
028    import org.apache.commons.math3.optimization.Target;
029    import org.apache.commons.math3.optimization.Weight;
030    import org.apache.commons.math3.optimization.BaseMultivariateVectorOptimizer;
031    import org.apache.commons.math3.optimization.ConvergenceChecker;
032    import org.apache.commons.math3.optimization.PointVectorValuePair;
033    import org.apache.commons.math3.optimization.SimpleVectorValueChecker;
034    import org.apache.commons.math3.linear.RealMatrix;
035    
036    /**
037     * Base class for implementing optimizers for multivariate scalar functions.
038     * This base class handles the boiler-plate methods associated to thresholds
039     * settings, iterations and evaluations counting.
040     *
041     * @param <FUNC> the type of the objective function to be optimized
042     *
043     * @version $Id: BaseAbstractMultivariateVectorOptimizer.java 1422230 2012-12-15 12:11:13Z erans $
044     * @deprecated As of 3.1 (to be removed in 4.0).
045     * @since 3.0
046     */
047    @Deprecated
048    public abstract class BaseAbstractMultivariateVectorOptimizer<FUNC extends MultivariateVectorFunction>
049        implements BaseMultivariateVectorOptimizer<FUNC> {
050        /** Evaluations counter. */
051        protected final Incrementor evaluations = new Incrementor();
052        /** Convergence checker. */
053        private ConvergenceChecker<PointVectorValuePair> checker;
054        /** Target value for the objective functions at optimum. */
055        private double[] target;
056        /** Weight matrix. */
057        private RealMatrix weightMatrix;
058        /** Weight for the least squares cost computation.
059         * @deprecated
060         */
061        private double[] weight;
062        /** Initial guess. */
063        private double[] start;
064        /** Objective function. */
065        private FUNC function;
066    
067        /**
068         * Simple constructor with default settings.
069         * The convergence check is set to a {@link SimpleVectorValueChecker}.
070         * @deprecated See {@link SimpleVectorValueChecker#SimpleVectorValueChecker()}
071         */
072        @Deprecated
073        protected BaseAbstractMultivariateVectorOptimizer() {
074            this(new SimpleVectorValueChecker());
075        }
076        /**
077         * @param checker Convergence checker.
078         */
079        protected BaseAbstractMultivariateVectorOptimizer(ConvergenceChecker<PointVectorValuePair> checker) {
080            this.checker = checker;
081        }
082    
083        /** {@inheritDoc} */
084        public int getMaxEvaluations() {
085            return evaluations.getMaximalCount();
086        }
087    
088        /** {@inheritDoc} */
089        public int getEvaluations() {
090            return evaluations.getCount();
091        }
092    
093        /** {@inheritDoc} */
094        public ConvergenceChecker<PointVectorValuePair> getConvergenceChecker() {
095            return checker;
096        }
097    
098        /**
099         * 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         */
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
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         */
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
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         */
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         */
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         */
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         */
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         */
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         */
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
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
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         */
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         */
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         */
364        private void checkParameters() {
365            if (target.length != weightMatrix.getColumnDimension()) {
366                throw new DimensionMismatchException(target.length,
367                                                     weightMatrix.getColumnDimension());
368            }
369        }
370    }