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] =
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.
Class of Gaussian process optimization srinivas2010, brochu2010.
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.
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.
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.
Base class of implementations of optimization algorithms.
auto evaluate_mean_and_variance_on(const variable_type &variable) const -> std::pair< function_value_type, function_value_type >
Evaluate mean and variance in the gaussian process for a variable.
void compute(const std::vector< variable_type > &variables, const function_value_vector_type &function_values)
Compute parameters for interpolation.
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.