BaseOptimizer.java

  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. package org.apache.commons.math3.optim;

  18. import org.apache.commons.math3.util.Incrementor;
  19. import org.apache.commons.math3.exception.TooManyEvaluationsException;
  20. import org.apache.commons.math3.exception.TooManyIterationsException;

  21. /**
  22.  * Base class for implementing optimizers.
  23.  * It contains the boiler-plate code for counting the number of evaluations
  24.  * of the objective function and the number of iterations of the algorithm,
  25.  * and storing the convergence checker.
  26.  * <em>It is not a "user" class.</em>
  27.  *
  28.  * @param <PAIR> Type of the point/value pair returned by the optimization
  29.  * algorithm.
  30.  *
  31.  * @since 3.1
  32.  */
  33. public abstract class BaseOptimizer<PAIR> {
  34.     /** Evaluations counter. */
  35.     protected final Incrementor evaluations;
  36.     /** Iterations counter. */
  37.     protected final Incrementor iterations;
  38.     /** Convergence checker. */
  39.     private final ConvergenceChecker<PAIR> checker;

  40.     /**
  41.      * @param checker Convergence checker.
  42.      */
  43.     protected BaseOptimizer(ConvergenceChecker<PAIR> checker) {
  44.         this(checker, 0, Integer.MAX_VALUE);
  45.     }

  46.     /**
  47.      * @param checker Convergence checker.
  48.      * @param maxEval Maximum number of objective function evaluations.
  49.      * @param maxIter Maximum number of algorithm iterations.
  50.      */
  51.     protected BaseOptimizer(ConvergenceChecker<PAIR> checker,
  52.                             int maxEval,
  53.                             int maxIter) {
  54.         this.checker = checker;

  55.         evaluations = new Incrementor(maxEval, new MaxEvalCallback());
  56.         iterations = new Incrementor(maxIter, new MaxIterCallback());
  57.     }

  58.     /**
  59.      * Gets the maximal number of function evaluations.
  60.      *
  61.      * @return the maximal number of function evaluations.
  62.      */
  63.     public int getMaxEvaluations() {
  64.         return evaluations.getMaximalCount();
  65.     }

  66.     /**
  67.      * Gets the number of evaluations of the objective function.
  68.      * The number of evaluations corresponds to the last call to the
  69.      * {@code optimize} method. It is 0 if the method has not been
  70.      * called yet.
  71.      *
  72.      * @return the number of evaluations of the objective function.
  73.      */
  74.     public int getEvaluations() {
  75.         return evaluations.getCount();
  76.     }

  77.     /**
  78.      * Gets the maximal number of iterations.
  79.      *
  80.      * @return the maximal number of iterations.
  81.      */
  82.     public int getMaxIterations() {
  83.         return iterations.getMaximalCount();
  84.     }

  85.     /**
  86.      * Gets the number of iterations performed by the algorithm.
  87.      * The number iterations corresponds to the last call to the
  88.      * {@code optimize} method. It is 0 if the method has not been
  89.      * called yet.
  90.      *
  91.      * @return the number of evaluations of the objective function.
  92.      */
  93.     public int getIterations() {
  94.         return iterations.getCount();
  95.     }

  96.     /**
  97.      * Gets the convergence checker.
  98.      *
  99.      * @return the object used to check for convergence.
  100.      */
  101.     public ConvergenceChecker<PAIR> getConvergenceChecker() {
  102.         return checker;
  103.     }

  104.     /**
  105.      * Stores data and performs the optimization.
  106.      * <p>
  107.      * The list of parameters is open-ended so that sub-classes can extend it
  108.      * with arguments specific to their concrete implementations.
  109.      * <p>
  110.      * When the method is called multiple times, instance data is overwritten
  111.      * only when actually present in the list of arguments: when not specified,
  112.      * data set in a previous call is retained (and thus is optional in
  113.      * subsequent calls).
  114.      * <p>
  115.      * Important note: Subclasses <em>must</em> override
  116.      * {@link #parseOptimizationData(OptimizationData[])} if they need to register
  117.      * their own options; but then, they <em>must</em> also call
  118.      * {@code super.parseOptimizationData(optData)} within that method.
  119.      *
  120.      * @param optData Optimization data.
  121.      * This method will register the following data:
  122.      * <ul>
  123.      *  <li>{@link MaxEval}</li>
  124.      *  <li>{@link MaxIter}</li>
  125.      * </ul>
  126.      * @return a point/value pair that satisfies the convergence criteria.
  127.      * @throws TooManyEvaluationsException if the maximal number of
  128.      * evaluations is exceeded.
  129.      * @throws TooManyIterationsException if the maximal number of
  130.      * iterations is exceeded.
  131.      */
  132.     public PAIR optimize(OptimizationData... optData)
  133.         throws TooManyEvaluationsException,
  134.                TooManyIterationsException {
  135.         // Parse options.
  136.         parseOptimizationData(optData);

  137.         // Reset counters.
  138.         evaluations.resetCount();
  139.         iterations.resetCount();
  140.         // Perform optimization.
  141.         return doOptimize();
  142.     }

  143.     /**
  144.      * Performs the optimization.
  145.      *
  146.      * @return a point/value pair that satisfies the convergence criteria.
  147.      * @throws TooManyEvaluationsException if the maximal number of
  148.      * evaluations is exceeded.
  149.      * @throws TooManyIterationsException if the maximal number of
  150.      * iterations is exceeded.
  151.      */
  152.     public PAIR optimize()
  153.         throws TooManyEvaluationsException,
  154.                TooManyIterationsException {
  155.         // Reset counters.
  156.         evaluations.resetCount();
  157.         iterations.resetCount();
  158.         // Perform optimization.
  159.         return doOptimize();
  160.     }

  161.     /**
  162.      * Performs the bulk of the optimization algorithm.
  163.      *
  164.      * @return the point/value pair giving the optimal value of the
  165.      * objective function.
  166.      */
  167.     protected abstract PAIR doOptimize();

  168.     /**
  169.      * Increment the evaluation count.
  170.      *
  171.      * @throws TooManyEvaluationsException if the allowed evaluations
  172.      * have been exhausted.
  173.      */
  174.     protected void incrementEvaluationCount()
  175.         throws TooManyEvaluationsException {
  176.         evaluations.incrementCount();
  177.     }

  178.     /**
  179.      * Increment the iteration count.
  180.      *
  181.      * @throws TooManyIterationsException if the allowed iterations
  182.      * have been exhausted.
  183.      */
  184.     protected void incrementIterationCount()
  185.         throws TooManyIterationsException {
  186.         iterations.incrementCount();
  187.     }

  188.     /**
  189.      * Scans the list of (required and optional) optimization data that
  190.      * characterize the problem.
  191.      *
  192.      * @param optData Optimization data.
  193.      * The following data will be looked for:
  194.      * <ul>
  195.      *  <li>{@link MaxEval}</li>
  196.      *  <li>{@link MaxIter}</li>
  197.      * </ul>
  198.      */
  199.     protected void parseOptimizationData(OptimizationData... optData) {
  200.         // The existing values (as set by the previous call) are reused if
  201.         // not provided in the argument list.
  202.         for (OptimizationData data : optData) {
  203.             if (data instanceof MaxEval) {
  204.                 evaluations.setMaximalCount(((MaxEval) data).getMaxEval());
  205.                 continue;
  206.             }
  207.             if (data instanceof MaxIter) {
  208.                 iterations.setMaximalCount(((MaxIter) data).getMaxIter());
  209.                 continue;
  210.             }
  211.         }
  212.     }

  213.     /**
  214.      * Defines the action to perform when reaching the maximum number
  215.      * of evaluations.
  216.      */
  217.     private static class MaxEvalCallback
  218.         implements  Incrementor.MaxCountExceededCallback {
  219.         /**
  220.          * {@inheritDoc}
  221.          * @throws TooManyEvaluationsException
  222.          */
  223.         public void trigger(int max) {
  224.             throw new TooManyEvaluationsException(max);
  225.         }
  226.     }

  227.     /**
  228.      * Defines the action to perform when reaching the maximum number
  229.      * of evaluations.
  230.      */
  231.     private static class MaxIterCallback
  232.         implements Incrementor.MaxCountExceededCallback {
  233.         /**
  234.          * {@inheritDoc}
  235.          * @throws TooManyIterationsException
  236.          */
  237.         public void trigger(int max) {
  238.             throw new TooManyIterationsException(max);
  239.         }
  240.     }
  241. }