    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    }