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 }