numerical-collection-cpp 0.10.0
A collection of algorithms in numerical analysis implemented in C++
Loading...
Searching...
No Matches
gaussian_process_optimizer.h
Go to the documentation of this file.
1/*
2 * Copyright 2024 MusicScience37 (Kenta Kabashima)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
20#pragma once
21
22#include <algorithm>
23#include <cmath>
24#include <cstdlib>
25#include <limits>
26#include <vector>
27
28#include <Eigen/Core>
29
35#include "num_collect/constants/pi.h" // IWYU pragma: keep
45#include "num_collect/util/is_eigen_vector.h" // IWYU pragma: keep
46
47namespace num_collect::opt {
48
51 logging::log_tag_view("num_collect::opt::gaussian_process_optimizer");
52
59template <concepts::objective_function ObjectiveFunction>
61 : public optimizer_base<gaussian_process_optimizer<ObjectiveFunction>> {
62public:
65
67 using objective_function_type = ObjectiveFunction;
68
70 using variable_type = typename objective_function_type::variable_type;
71
73 using value_type = typename objective_function_type::value_type;
74
91
98 obj_fun_ = obj_fun;
99 }
100
107 void init(const variable_type& lower, const variable_type& upper) {
108 if constexpr (is_eigen_vector_v<variable_type>) {
109 NUM_COLLECT_PRECONDITION(lower.size() == upper.size(),
110 this->logger(),
111 "Lower and upper limits must have the same size.");
112 }
113 lower_ = lower;
114 upper_ = upper;
116
117 // First sample.
118 obj_fun_.evaluate_on(upper_);
121 variables_.resize(1);
122 values_.resize(1);
124 values_[0] = opt_value_;
125
126 iterations_ = 0;
127 evaluations_ = 1;
128
129 // Second sample.
131 }
132
136 void iterate() {
139 variables_.size() == static_cast<std::size_t>(values_.size()));
140
141 interpolator_.optimize_length_parameter_scale(variables_, values_);
143
145
146 ++iterations_;
147 }
148
152 [[nodiscard]] auto is_stop_criteria_satisfied() const -> bool {
153 return evaluations() >= max_evaluations_;
154 }
155
161 const {
162 iteration_logger.template append<index_type>(
163 "Iter.", &this_type::iterations);
164 iteration_logger.template append<index_type>(
165 "Eval.", &this_type::evaluations);
166 iteration_logger.template append<value_type>(
167 "Value", &this_type::opt_value);
168 }
169
173 [[nodiscard]] auto opt_variable() const -> const variable_type& {
174 return opt_variable_;
175 }
176
180 [[nodiscard]] auto opt_value() const -> const value_type& {
181 return opt_value_;
182 }
183
187 [[nodiscard]] auto iterations() const noexcept -> index_type {
188 return iterations_;
189 }
190
194 [[nodiscard]] auto evaluations() const noexcept -> index_type {
195 return evaluations_;
196 }
197
205 NUM_COLLECT_PRECONDITION(value > 0, this->logger(),
206 "Maximum number of function evaluations must be a positive "
207 "integer.");
208 max_evaluations_ = value;
209 return *this;
210 }
211
220 NUM_COLLECT_PRECONDITION(value > 0, this->logger(),
221 "Maximum number of evaluations of lower bounds must be a positive "
222 "integer.");
223 lower_bound_optimizer_.max_evaluations(value);
224 return *this;
225 }
226
227private:
233
239 void evaluate_on(const variable_type& variable) {
240 obj_fun_.evaluate_on(variable);
241 const value_type value = correct_value_if_needed(obj_fun_.value());
242 if (value < opt_value_) {
243 opt_variable_ = variable;
244 opt_value_ = value;
245 }
246 variables_.push_back(variable);
247 values_.conservativeResize(values_.size() + 1);
248 values_(values_.size() - 1) = value;
249 ++evaluations_;
250 }
251
258 [[nodiscard]] static auto correct_value_if_needed(value_type value) noexcept
259 -> value_type {
260 constexpr auto safe_limit =
261 std::numeric_limits<value_type>::max() * 1e-2;
262 if (!isfinite(value) || value > safe_limit) {
263 return safe_limit;
264 }
265 return value;
266 }
267
274 [[nodiscard]] auto try_find_and_evaluate_using_lower_bound() -> bool {
275 const auto lower_bound_function =
276 [this](const variable_type& variable) -> value_type {
277 using std::log;
278 using std::sqrt;
279 using std::max;
280 using std::pow;
281
282 const auto [mean, variance] =
283 interpolator_.evaluate_mean_and_variance_on(variable);
284 const auto variance_coeff = static_cast<value_type>(2) *
285 log(pow(static_cast<value_type>(evaluations_),
286 static_cast<value_type>(0.5) *
287 static_cast<value_type>(dim_) +
288 static_cast<value_type>(2)) *
290 static_cast<value_type>(0.3));
291 return mean -
292 sqrt(
293 max(variance_coeff * variance, static_cast<value_type>(0)));
294 };
295 lower_bound_optimizer_.change_objective_function(lower_bound_function);
296
299
300 evaluate_on(lower_bound_optimizer_.opt_variable());
301
302 return true;
303 }
304
308
311
314
316 std::vector<variable_type> variables_{};
317
319 Eigen::VectorX<value_type> values_{};
320
323
326
329
332
335
338
341
343 static constexpr index_type default_max_evaluations = 20;
344
347
350};
351
352} // namespace num_collect::opt
Definition of any_objective_function class.
Definition of assertion macros.
#define NUM_COLLECT_ASSERT(CONDITION)
Macro to check whether a condition is satisfied.
Definition assert.h:66
Class of tags of logs without memory management.
void configure_child_algorithm_logger_if_exists(Child &child)
Configure a logger of a child algorithm if exists.
auto logger() const noexcept -> const num_collect::logging::logger &
Access to the logger.
Class to store any type of objects of objective functions.
Class of dividing rectangles (DIRECT) method jones1993 for optimization.
static constexpr index_type default_max_lower_bound_evaluations
Default value of the maximum number of evaluations of lower bounds.
index_type max_evaluations_
Maximum number of function evaluations.
auto evaluations() const noexcept -> index_type
Get the number of function evaluations.
void evaluate_on(const variable_type &variable)
Evaluate function value.
rbf::gaussian_process_interpolator< value_type(variable_type)> interpolator_type
Type of interpolator.
void configure_iteration_logger(logging::iterations::iteration_logger< this_type > &iteration_logger) const
Configure an iteration logger.
auto max_lower_bound_evaluations(index_type value) -> gaussian_process_optimizer &
Set the maximum number of evaluations of lower bounds.
auto opt_variable() const -> const variable_type &
Get current optimal variable.
Eigen::VectorX< value_type > values_
Function values of sample points.
auto is_stop_criteria_satisfied() const -> bool
Determine if stopping criteria of the algorithm are satisfied.
index_type evaluations_
Number of function evaluations.
void change_objective_function(const objective_function_type &obj_fun)
Change the objective function.
typename objective_function_type::value_type value_type
Type of function values.
typename objective_function_type::variable_type variable_type
Type of variables.
gaussian_process_optimizer(const objective_function_type &obj_fun=objective_function_type())
Constructor.
ObjectiveFunction objective_function_type
Type of the objective function.
void init(const variable_type &lower, const variable_type &upper)
Initialize the algorithm.
variable_type opt_variable_
Current optimal variable.
auto iterations() const noexcept -> index_type
Get the number of iterations.
gaussian_process_optimizer< ObjectiveFunction > this_type
This class.
static constexpr index_type default_max_evaluations
Default value of the maximum number of function evaluations.
variable_type upper_
Element-wise upper limit.
variable_type lower_
Element-wise lower limit.
auto try_find_and_evaluate_using_lower_bound() -> bool
Try to find a sample point using lower bounds and evaluate a function value for the sample point.
auto opt_value() const -> const value_type &
Get current optimal value.
auto max_evaluations(index_type value) -> gaussian_process_optimizer &
Set the maximum number of function evaluations.
static auto correct_value_if_needed(value_type value) noexcept -> value_type
Correct function values if needed.
objective_function_type obj_fun_
Objective function.
std::vector< variable_type > variables_
Variables of sample points.
dividing_rectangles< any_objective_function< value_type(variable_type)> > lower_bound_optimizer_
Optimizer of lower bounds.
Class to interpolate using Gaussian process.
Definition of dividing_rectangles class.
Definition of exceptions.
Definition of gaussian_process_interpolator class.
Definition of get_size class.
Definition of index_type type.
Definition of is_eigen_vector class.
Definition of isfinite function.
Definition of iteration_logger class.
Definition of log_tag_view class.
Definition of macros for logging.
std::ptrdiff_t index_type
Type of indices in this library.
Definition index_type.h:33
auto get_size(const Matrix &matrix) -> index_type
Get the size.
Definition get_size.h:39
auto isfinite(const T &val) -> bool
Check whether a number is finite.
Definition isfinite.h:39
constexpr T pi
Value of pi, .
Definition pi.h:40
Namespace of optimization algorithms.
constexpr auto gaussian_process_optimizer_tag
Tag of gaussian_process_optimizer.
constexpr bool is_eigen_vector_v
Get whether a type is a Eigen's vector.
Definition of objective_function concept.
Definition of optimizer_base class.
Definition of pi.
Definition of NUM_COLLECT_PRECONDITION macro.
#define NUM_COLLECT_PRECONDITION(CONDITION,...)
Check whether a precondition is satisfied and throw an exception if not.