View Javadoc
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    *      https://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  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.optim;
23  
24  import org.hipparchus.exception.MathIllegalStateException;
25  import org.hipparchus.util.Incrementor;
26  
27  /**
28   * Base class for implementing optimizers.
29   * It contains the boiler-plate code for counting the number of evaluations
30   * of the objective function and the number of iterations of the algorithm,
31   * and storing the convergence checker.
32   * <em>It is not a "user" class.</em>
33   *
34   * @param <P> Type of the point/value pair returned by the optimization
35   * algorithm.
36   *
37   */
38  public abstract class BaseOptimizer<P> {
39      /** Evaluations counter. */
40      protected Incrementor evaluations;
41      /** Iterations counter. */
42      protected Incrementor iterations;
43      /** Convergence checker. */
44      private final ConvergenceChecker<P> checker;
45  
46      /** Simple constructor.
47       * @param checker Convergence checker.
48       */
49      protected BaseOptimizer(ConvergenceChecker<P> checker) {
50          this(checker, 0, Integer.MAX_VALUE);
51      }
52  
53      /** Simple constructor.
54       * @param checker Convergence checker.
55       * @param maxEval Maximum number of objective function evaluations.
56       * @param maxIter Maximum number of algorithm iterations.
57       */
58      protected BaseOptimizer(ConvergenceChecker<P> checker,
59                              int maxEval,
60                              int maxIter) {
61          this.checker = checker;
62  
63          evaluations = new Incrementor(maxEval);
64          iterations  = new Incrementor(maxIter);
65      }
66  
67      /**
68       * Gets the maximal number of function evaluations.
69       *
70       * @return the maximal number of function evaluations.
71       */
72      public int getMaxEvaluations() {
73          return evaluations.getMaximalCount();
74      }
75  
76      /**
77       * Gets the number of evaluations of the objective function.
78       * The number of evaluations corresponds to the last call to the
79       * {@code optimize} method. It is 0 if the method has not been
80       * called yet.
81       *
82       * @return the number of evaluations of the objective function.
83       */
84      public int getEvaluations() {
85          return evaluations.getCount();
86      }
87  
88      /**
89       * Gets the maximal number of iterations.
90       *
91       * @return the maximal number of iterations.
92       */
93      public int getMaxIterations() {
94          return iterations.getMaximalCount();
95      }
96  
97      /**
98       * Gets the number of iterations performed by the algorithm.
99       * The number iterations corresponds to the last call to the
100      * {@code optimize} method. It is 0 if the method has not been
101      * called yet.
102      *
103      * @return the number of evaluations of the objective function.
104      */
105     public int getIterations() {
106         return iterations.getCount();
107     }
108 
109     /**
110      * Gets the convergence checker.
111      *
112      * @return the object used to check for convergence.
113      */
114     public ConvergenceChecker<P> getConvergenceChecker() {
115         return checker;
116     }
117 
118     /**
119      * Stores data and performs the optimization.
120      * <p>
121      * The list of parameters is open-ended so that sub-classes can extend it
122      * with arguments specific to their concrete implementations.
123      * <p>
124      * When the method is called multiple times, instance data is overwritten
125      * only when actually present in the list of arguments: when not specified,
126      * data set in a previous call is retained (and thus is optional in
127      * subsequent calls).
128      * <p>
129      * Important note: Subclasses <em>must</em> override
130      * {@link #parseOptimizationData(OptimizationData[])} if they need to register
131      * their own options; but then, they <em>must</em> also call
132      * {@code super.parseOptimizationData(optData)} within that method.
133      *
134      * @param optData Optimization data.
135      * This method will register the following data:
136      * <ul>
137      *  <li>{@link MaxEval}</li>
138      *  <li>{@link MaxIter}</li>
139      * </ul>
140      * @return a point/value pair that satisfies the convergence criteria.
141      * @throws MathIllegalStateException if the maximal number of
142      * evaluations is exceeded.
143      * @throws MathIllegalStateException if the maximal number of
144      * iterations is exceeded.
145      */
146     public P optimize(OptimizationData... optData)
147         throws MathIllegalStateException {
148         // Parse options.
149         parseOptimizationData(optData);
150 
151         // Reset counters.
152         evaluations.reset();
153         iterations.reset();
154         // Perform optimization.
155         return doOptimize();
156     }
157 
158     /**
159      * Performs the optimization.
160      *
161      * @return a point/value pair that satisfies the convergence criteria.
162      * @throws MathIllegalStateException if the maximal number of
163      * evaluations is exceeded.
164      * @throws MathIllegalStateException if the maximal number of
165      * iterations is exceeded.
166      */
167     public P optimize()
168         throws MathIllegalStateException {
169         // Reset counters.
170         evaluations.reset();
171         iterations.reset();
172         // Perform optimization.
173         return doOptimize();
174     }
175 
176     /**
177      * Performs the bulk of the optimization algorithm.
178      *
179      * @return the point/value pair giving the optimal value of the
180      * objective function.
181      */
182     protected abstract P doOptimize();
183 
184     /**
185      * Increment the evaluation count.
186      *
187      * @throws MathIllegalStateException if the allowed evaluations
188      * have been exhausted.
189      */
190     protected void incrementEvaluationCount()
191         throws MathIllegalStateException {
192         evaluations.increment();
193     }
194 
195     /**
196      * Increment the iteration count.
197      *
198      * @throws MathIllegalStateException if the allowed iterations
199      * have been exhausted.
200      */
201     protected void incrementIterationCount()
202         throws MathIllegalStateException {
203         iterations.increment();
204     }
205 
206     /**
207      * Scans the list of (required and optional) optimization data that
208      * characterize the problem.
209      *
210      * @param optData Optimization data.
211      * The following data will be looked for:
212      * <ul>
213      *  <li>{@link MaxEval}</li>
214      *  <li>{@link MaxIter}</li>
215      * </ul>
216      */
217     protected void parseOptimizationData(OptimizationData... optData) {
218         // The existing values (as set by the previous call) are reused if
219         // not provided in the argument list.
220         for (OptimizationData data : optData) {
221             if (data instanceof MaxEval) {
222                 evaluations = evaluations.withMaximalCount(((MaxEval) data).getMaxEval());
223                 continue;
224             }
225             if (data instanceof MaxIter) {
226                 iterations = iterations.withMaximalCount(((MaxIter) data).getMaxIter());
227                 continue;
228             }
229         }
230     }
231 }