    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    package org.apache.commons.math3.optim;
    018
    019    import org.apache.commons.math3.exception.DimensionMismatchException;
    020    import org.apache.commons.math3.exception.NumberIsTooSmallException;
    021    import org.apache.commons.math3.exception.NumberIsTooLargeException;
    022
    023    /**
    024     * Base class for implementing optimizers for multivariate functions.
    025     * It contains the boiler-plate code for initial guess and bounds
    026     * specifications.
    027     * <em>It is not a "user" class.</em>
    028     *
    029     * @param <PAIR> Type of the point/value pair returned by the optimization
    030     * algorithm.
    031     *
    032     * @version $Id$
    033     * @since 3.1
    034     */
    035    public abstract class BaseMultivariateOptimizer<PAIR>
    036        extends BaseOptimizer<PAIR> {
    037        /** Initial guess. */
    038        private double[] start;
    039        /** Lower bounds. */
    040        private double[] lowerBound;
    041        /** Upper bounds. */
    042        private double[] upperBound;
    043
    044        /**
    045         * @param checker Convergence checker.
    046         */
    047        protected BaseMultivariateOptimizer(ConvergenceChecker<PAIR> checker) {
    048            super(checker);
    049        }
    050
    051        /**
    052         * {@inheritDoc}
    053         *
    054         * @param optData Optimization data.
    055         * The following data will be looked for:
    056         * <ul>
    057         *  <li>{@link MaxEval}</li>
    058         *  <li>{@link InitialGuess}</li>
    059         *  <li>{@link SimpleBounds}</li>
    060         * </ul>
    061         * @return {@inheritDoc}
    062         */
    063        @Override
    064        public PAIR optimize(OptimizationData... optData) {
    065            // Retrieve settings.
    066            parseOptimizationData(optData);
    067            // Check input consistency.
    068            checkParameters();
    069            // Perform optimization.
    070            return super.optimize(optData);
    071        }
    072
    073        /**
    074         * Scans the list of (required and optional) optimization data that
    075         * characterize the problem.
    076         *
    077         * @param optData Optimization data. The following data will be looked for:
    078         * <ul>
    079         *  <li>{@link InitialGuess}</li>
    080         *  <li>{@link SimpleBounds}</li>
    081         * </ul>
    082         */
    083        private void parseOptimizationData(OptimizationData... optData) {
    084            // The existing values (as set by the previous call) are reused if
    085            // not provided in the argument list.
    086            for (OptimizationData data : optData) {
    087                if (data instanceof InitialGuess) {
    088                    start = ((InitialGuess) data).getInitialGuess();
    089                    continue;
    090                }
    091                if (data instanceof SimpleBounds) {
    092                    final SimpleBounds bounds = (SimpleBounds) data;
    093                    lowerBound = bounds.getLower();
    094                    upperBound = bounds.getUpper();
    095                    continue;
    096                }
    097            }
    098        }
    099
    100        /**
    101         * Gets the initial guess.
    102         *
    103         * @return the initial guess, or {@code null} if not set.
    104         */
    105        public double[] getStartPoint() {
    106            return start == null ? null : start.clone();
    107        }
    108        /**
    109         * @return the lower bounds, or {@code null} if not set.
    110         */
    111        public double[] getLowerBound() {
    112            return lowerBound == null ? null : lowerBound.clone();
    113        }
    114        /**
    115         * @return the upper bounds, or {@code null} if not set.
    116         */
    117        public double[] getUpperBound() {
    118            return upperBound == null ? null : upperBound.clone();
    119        }
    120
    121        /**
    122         * Check parameters consistency.
    123         */
    124        private void checkParameters() {
    125            if (start != null) {
    126                final int dim = start.length;
    127                if (lowerBound != null) {
    128                    if (lowerBound.length != dim) {
    129                        throw new DimensionMismatchException(lowerBound.length, dim);
    130                    }
    131                    for (int i = 0; i < dim; i++) {
    132                        final double v = start[i];
    133                        final double lo = lowerBound[i];
    134                        if (v < lo) {
    135                            throw new NumberIsTooSmallException(v, lo, true);
    136                        }
    137                    }
    138                }
    139                if (upperBound != null) {
    140                    if (upperBound.length != dim) {
    141                        throw new DimensionMismatchException(upperBound.length, dim);
    142                    }
    143                    for (int i = 0; i < dim; i++) {
    144                        final double v = start[i];
    145                        final double hi = upperBound[i];
    146                        if (v > hi) {
    147                            throw new NumberIsTooLargeException(v, hi, true);
    148                        }
    149                    }
    150                }
    151            }
    152        }
    153    }