Coverage Report

Created: 2025-05-30 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/builds/MusicScience37Projects/numerical-analysis/numerical-collection-cpp/include/num_collect/opt/adaptive_diagonal_curves.h
Line
Count
Source
1
/*
2
 * Copyright 2021 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
 */
16
/*!
17
 * \file
18
 * \brief Definition of dividing_rectangles class.
19
 */
20
#pragma once
21
22
#include <algorithm>
23
#include <cmath>
24
#include <cstddef>
25
#include <cstdint>
26
#include <iterator>
27
#include <limits>
28
#include <string_view>
29
#include <utility>
30
#include <vector>
31
32
#include "num_collect/base/exception.h"
33
#include "num_collect/base/index_type.h"
34
#include "num_collect/base/precondition.h"
35
#include "num_collect/logging/iterations/iteration_logger.h"
36
#include "num_collect/logging/log_tag_view.h"
37
#include "num_collect/logging/logging_macros.h"
38
#include "num_collect/opt/concepts/multi_variate_objective_function.h"
39
#include "num_collect/opt/impl/adc_group.h"
40
#include "num_collect/opt/impl/adc_sample_dict.h"
41
#include "num_collect/opt/optimizer_base.h"
42
#include "num_collect/util/assert.h"
43
#include "num_collect/util/safe_cast.h"
44
45
namespace num_collect::opt {
46
47
//! Tag of adaptive_diagonal_curves.
48
constexpr auto adaptive_diagonal_curves_tag =
49
    logging::log_tag_view("num_collect::opt::adaptive_diagonal_curves");
50
51
/*!
52
 * \brief Class of adaptive diagonal curves (ADC) method \cite Sergeyev2006 for
53
 * optimization.
54
 *
55
 * \tparam ObjectiveFunction Type of the objective function.
56
 * \tparam MaxDigits Maximum number of ternary digits per dimension at compile
57
 * time.
58
 */
59
template <concepts::multi_variate_objective_function ObjectiveFunction,
60
    index_type MaxDigits = 8>  // NOLINT(*-magic-numbers)
61
class adaptive_diagonal_curves
62
    : public optimizer_base<
63
          adaptive_diagonal_curves<ObjectiveFunction, MaxDigits>> {
64
public:
65
    //! This class.
66
    using this_type = adaptive_diagonal_curves<ObjectiveFunction, MaxDigits>;
67
68
    //! Type of the objective function.
69
    using objective_function_type = ObjectiveFunction;
70
71
    //! Type of variables.
72
    using variable_type = typename objective_function_type::variable_type;
73
74
    //! Type of function values.
75
    using value_type = typename objective_function_type::value_type;
76
77
    /*!
78
     * \brief Enumeration of states in ADC method.
79
     */
80
    enum class state_type : std::uint8_t {
81
        none,          //!< No operation.
82
        local,         //!< Local phase (not last iteration).
83
        local_last,    //!< Last iteration in local phase.
84
        global,        //!< Global phase (not last iteration).
85
        global_last,   //!< Last iteration in global phase.
86
        non_dividable  //!< No rectangle can be divided.
87
    };
88
89
    /*!
90
     * \brief Convert a state to string.
91
     *
92
     * \param[in] state State.
93
     * \return Name of state.
94
     */
95
57
    [[nodiscard]] static auto state_name(state_type state) -> std::string_view {
96
57
        switch (state) {
97
3
        case state_type::none:
98
3
            return "none";
99
5
        case state_type::local:
100
5
            return "local";
101
4
        case state_type::local_last:
102
4
            return "local (last)";
103
42
        case state_type::global:
104
42
            return "global";
105
2
        case state_type::global_last:
106
2
            return "global (last)";
107
1
        case state_type::non_dividable:
108
1
            return "non dividable";
109
0
        default:
110
0
            return "invalid process";
111
57
        }
112
57
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE10state_nameENS5_10state_typeE
Line
Count
Source
95
54
    [[nodiscard]] static auto state_name(state_type state) -> std::string_view {
96
54
        switch (state) {
97
2
        case state_type::none:
98
2
            return "none";
99
4
        case state_type::local:
100
4
            return "local";
101
4
        case state_type::local_last:
102
4
            return "local (last)";
103
42
        case state_type::global:
104
42
            return "global";
105
2
        case state_type::global_last:
106
2
            return "global (last)";
107
0
        case state_type::non_dividable:
108
0
            return "non dividable";
109
0
        default:
110
0
            return "invalid process";
111
54
        }
112
54
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE10state_nameENS5_10state_typeE
Line
Count
Source
95
3
    [[nodiscard]] static auto state_name(state_type state) -> std::string_view {
96
3
        switch (state) {
97
1
        case state_type::none:
98
1
            return "none";
99
1
        case state_type::local:
100
1
            return "local";
101
0
        case state_type::local_last:
102
0
            return "local (last)";
103
0
        case state_type::global:
104
0
            return "global";
105
0
        case state_type::global_last:
106
0
            return "global (last)";
107
1
        case state_type::non_dividable:
108
1
            return "non dividable";
109
0
        default:
110
0
            return "invalid process";
111
3
        }
112
3
    }
113
114
    /*!
115
     * \brief Constructor.
116
     *
117
     * \param[in] obj_fun Objective function.
118
     */
119
    explicit adaptive_diagonal_curves(
120
        const objective_function_type& obj_fun = objective_function_type())
121
5
        : optimizer_base<this_type>(adaptive_diagonal_curves_tag),
122
5
          value_dict_(obj_fun) {}
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EEC2ERKS4_
Line
Count
Source
121
4
        : optimizer_base<this_type>(adaptive_diagonal_curves_tag),
122
4
          value_dict_(obj_fun) {}
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EEC2ERKS4_
Line
Count
Source
121
1
        : optimizer_base<this_type>(adaptive_diagonal_curves_tag),
122
1
          value_dict_(obj_fun) {}
123
124
    /*!
125
     * \brief Change the objective function.
126
     *
127
     * \param[in] obj_fun Objective function.
128
     */
129
    void change_objective_function(const objective_function_type& obj_fun) {
130
        value_dict_.change_objective_function(obj_fun);
131
    }
132
133
    /*!
134
     * \brief Initialize the algorithm.
135
     *
136
     * \param[in] lower Lower limit.
137
     * \param[in] upper Upper limit.
138
     */
139
5
    void init(const variable_type& lower, const variable_type& upper) {
140
5
        value_dict_.init(lower, upper);
141
5
        groups_.clear();
142
5
        iterations_ = 0;
143
5
        state_ = state_type::none;
144
145
        // Initialize groups_, optimal_value_, optimal_group_index_.
146
5
        create_first_rectangle();
147
148
        // prec_optimal_value_, prec_optimal_group_index, and
149
        // iterations_in_current_phase_ are initialized in switch_state().
150
151
5
        value_dict_.reserve(max_evaluations_);
152
5
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE4initERKN5Eigen6MatrixIdLin1ELi1ELi0ELin1ELi1EEESA_
Line
Count
Source
139
4
    void init(const variable_type& lower, const variable_type& upper) {
140
4
        value_dict_.init(lower, upper);
141
4
        groups_.clear();
142
4
        iterations_ = 0;
143
4
        state_ = state_type::none;
144
145
        // Initialize groups_, optimal_value_, optimal_group_index_.
146
4
        create_first_rectangle();
147
148
        // prec_optimal_value_, prec_optimal_group_index, and
149
        // iterations_in_current_phase_ are initialized in switch_state().
150
151
4
        value_dict_.reserve(max_evaluations_);
152
4
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE4initERKN5Eigen6MatrixIdLin1ELi1ELi0ELin1ELi1EEESA_
Line
Count
Source
139
1
    void init(const variable_type& lower, const variable_type& upper) {
140
1
        value_dict_.init(lower, upper);
141
1
        groups_.clear();
142
1
        iterations_ = 0;
143
1
        state_ = state_type::none;
144
145
        // Initialize groups_, optimal_value_, optimal_group_index_.
146
1
        create_first_rectangle();
147
148
        // prec_optimal_value_, prec_optimal_group_index, and
149
        // iterations_in_current_phase_ are initialized in switch_state().
150
151
1
        value_dict_.reserve(max_evaluations_);
152
1
    }
153
154
    /*!
155
     * \copydoc num_collect::opt::optimizer_base::iterate
156
     */
157
526
    void iterate() {
158
526
        switch_state();
159
160
526
        switch (state_) {
161
79
        case state_type::local:
162
79
            iterate_locally();
163
79
            break;
164
26
        case state_type::local_last:
165
26
            iterate_locally_last();
166
26
            break;
167
397
        case state_type::global:
168
397
            iterate_globally();
169
397
            break;
170
23
        case state_type::global_last:
171
23
            iterate_globally_last();
172
23
            break;
173
1
        case state_type::non_dividable:
174
            // Nothing can be done.
175
1
            break;
176
0
        default:
177
0
            NUM_COLLECT_LOG_AND_THROW(algorithm_failure,
178
526
                "invalid state (bug in adaptive_diagonal_curve class)");
179
526
        }
180
181
526
        ++iterations_;
182
526
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE7iterateEv
Line
Count
Source
157
511
    void iterate() {
158
511
        switch_state();
159
160
511
        switch (state_) {
161
70
        case state_type::local:
162
70
            iterate_locally();
163
70
            break;
164
23
        case state_type::local_last:
165
23
            iterate_locally_last();
166
23
            break;
167
395
        case state_type::global:
168
395
            iterate_globally();
169
395
            break;
170
23
        case state_type::global_last:
171
23
            iterate_globally_last();
172
23
            break;
173
0
        case state_type::non_dividable:
174
            // Nothing can be done.
175
0
            break;
176
0
        default:
177
0
            NUM_COLLECT_LOG_AND_THROW(algorithm_failure,
178
511
                "invalid state (bug in adaptive_diagonal_curve class)");
179
511
        }
180
181
511
        ++iterations_;
182
511
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE7iterateEv
Line
Count
Source
157
15
    void iterate() {
158
15
        switch_state();
159
160
15
        switch (state_) {
161
9
        case state_type::local:
162
9
            iterate_locally();
163
9
            break;
164
3
        case state_type::local_last:
165
3
            iterate_locally_last();
166
3
            break;
167
2
        case state_type::global:
168
2
            iterate_globally();
169
2
            break;
170
0
        case state_type::global_last:
171
0
            iterate_globally_last();
172
0
            break;
173
1
        case state_type::non_dividable:
174
            // Nothing can be done.
175
1
            break;
176
0
        default:
177
0
            NUM_COLLECT_LOG_AND_THROW(algorithm_failure,
178
15
                "invalid state (bug in adaptive_diagonal_curve class)");
179
15
        }
180
181
15
        ++iterations_;
182
15
    }
183
184
    /*!
185
     * \copydoc num_collect::base::iterative_solver_base::is_stop_criteria_satisfied
186
     */
187
527
    [[nodiscard]] auto is_stop_criteria_satisfied() const -> bool {
188
527
        return evaluations() >= max_evaluations_ ||
189
527
            state_ == state_type::non_dividable;
190
527
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE26is_stop_criteria_satisfiedEv
Line
Count
Source
187
512
    [[nodiscard]] auto is_stop_criteria_satisfied() const -> bool {
188
512
        return evaluations() >= max_evaluations_ ||
189
512
            state_ == state_type::non_dividable;
190
512
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE26is_stop_criteria_satisfiedEv
Line
Count
Source
187
15
    [[nodiscard]] auto is_stop_criteria_satisfied() const -> bool {
188
15
        return evaluations() >= max_evaluations_ ||
189
15
            state_ == state_type::non_dividable;
190
15
    }
191
192
    /*!
193
     * \copydoc num_collect::base::iterative_solver_base::configure_iteration_logger
194
     */
195
    void configure_iteration_logger(
196
        logging::iterations::iteration_logger<this_type>& iteration_logger)
197
3
        const {
198
3
        iteration_logger.template append<index_type>(
199
3
            "Iter.", &this_type::iterations);
200
3
        iteration_logger.template append<index_type>(
201
3
            "Eval.", &this_type::evaluations);
202
3
        iteration_logger.template append<value_type>(
203
3
            "Value", &this_type::opt_value);
204
3
        constexpr index_type state_width = 15;
205
3
        iteration_logger
206
3
            .template append<std::string_view>(
207
3
                "State", &this_type::last_state_name)
208
3
            ->width(state_width);
209
3
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE26configure_iteration_loggerERNS_7logging10iterations16iteration_loggerIS5_EE
Line
Count
Source
197
2
        const {
198
2
        iteration_logger.template append<index_type>(
199
2
            "Iter.", &this_type::iterations);
200
2
        iteration_logger.template append<index_type>(
201
2
            "Eval.", &this_type::evaluations);
202
2
        iteration_logger.template append<value_type>(
203
2
            "Value", &this_type::opt_value);
204
2
        constexpr index_type state_width = 15;
205
2
        iteration_logger
206
2
            .template append<std::string_view>(
207
2
                "State", &this_type::last_state_name)
208
2
            ->width(state_width);
209
2
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE26configure_iteration_loggerERNS_7logging10iterations16iteration_loggerIS5_EE
Line
Count
Source
197
1
        const {
198
1
        iteration_logger.template append<index_type>(
199
1
            "Iter.", &this_type::iterations);
200
1
        iteration_logger.template append<index_type>(
201
1
            "Eval.", &this_type::evaluations);
202
1
        iteration_logger.template append<value_type>(
203
1
            "Value", &this_type::opt_value);
204
1
        constexpr index_type state_width = 15;
205
1
        iteration_logger
206
1
            .template append<std::string_view>(
207
1
                "State", &this_type::last_state_name)
208
1
            ->width(state_width);
209
1
    }
210
211
    /*!
212
     * \copydoc num_collect::opt::optimizer_base::opt_variable
213
     */
214
3
    [[nodiscard]] auto opt_variable() const -> const variable_type& {
215
3
        return value_dict_.opt_variable();
216
3
    }
217
218
    /*!
219
     * \copydoc num_collect::opt::optimizer_base::opt_value
220
     */
221
61
    [[nodiscard]] auto opt_value() const -> const value_type& {
222
61
        return value_dict_.opt_value();
223
61
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE9opt_valueEv
Line
Count
Source
221
58
    [[nodiscard]] auto opt_value() const -> const value_type& {
222
58
        return value_dict_.opt_value();
223
58
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE9opt_valueEv
Line
Count
Source
221
3
    [[nodiscard]] auto opt_value() const -> const value_type& {
222
3
        return value_dict_.opt_value();
223
3
    }
224
225
    /*!
226
     * \copydoc num_collect::opt::optimizer_base::iterations
227
     */
228
59
    [[nodiscard]] auto iterations() const noexcept -> index_type {
229
59
        return iterations_;
230
59
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE10iterationsEv
Line
Count
Source
228
56
    [[nodiscard]] auto iterations() const noexcept -> index_type {
229
56
        return iterations_;
230
56
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE10iterationsEv
Line
Count
Source
228
3
    [[nodiscard]] auto iterations() const noexcept -> index_type {
229
3
        return iterations_;
230
3
    }
231
232
    /*!
233
     * \copydoc num_collect::opt::optimizer_base::evaluations
234
     */
235
586
    [[nodiscard]] auto evaluations() const noexcept -> index_type {
236
586
        return value_dict_.evaluations();
237
586
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE11evaluationsEv
Line
Count
Source
235
568
    [[nodiscard]] auto evaluations() const noexcept -> index_type {
236
568
        return value_dict_.evaluations();
237
568
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE11evaluationsEv
Line
Count
Source
235
18
    [[nodiscard]] auto evaluations() const noexcept -> index_type {
236
18
        return value_dict_.evaluations();
237
18
    }
238
239
    /*!
240
     * \brief Get the last state.
241
     *
242
     * \return Last state.
243
     */
244
59
    [[nodiscard]] auto last_state() const noexcept -> state_type {
245
59
        return state_;
246
59
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE10last_stateEv
Line
Count
Source
244
54
    [[nodiscard]] auto last_state() const noexcept -> state_type {
245
54
        return state_;
246
54
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE10last_stateEv
Line
Count
Source
244
5
    [[nodiscard]] auto last_state() const noexcept -> state_type {
245
5
        return state_;
246
5
    }
247
248
    /*!
249
     * \brief Get the name of the last state.
250
     *
251
     * \return Last state.
252
     */
253
57
    [[nodiscard]] auto last_state_name() const noexcept -> std::string_view {
254
57
        return state_name(last_state());
255
57
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE15last_state_nameEv
Line
Count
Source
253
54
    [[nodiscard]] auto last_state_name() const noexcept -> std::string_view {
254
54
        return state_name(last_state());
255
54
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE15last_state_nameEv
Line
Count
Source
253
3
    [[nodiscard]] auto last_state_name() const noexcept -> std::string_view {
254
3
        return state_name(last_state());
255
3
    }
256
257
    /*!
258
     * \brief Set the maximum number of function evaluations.
259
     *
260
     * \param[in] value Value.
261
     * \return This object.
262
     */
263
3
    auto max_evaluations(index_type value) -> adaptive_diagonal_curves& {
264
3
        NUM_COLLECT_PRECONDITION(value > 0, this->logger(),
265
3
            "Maximum number of function evaluations must be a positive "
266
3
            "integer.");
267
268
3
        max_evaluations_ = value;
269
3
        return *this;
270
3
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE15max_evaluationsEl
Line
Count
Source
263
2
    auto max_evaluations(index_type value) -> adaptive_diagonal_curves& {
264
2
        NUM_COLLECT_PRECONDITION(value > 0, this->logger(),
265
2
            "Maximum number of function evaluations must be a positive "
266
2
            "integer.");
267
268
2
        max_evaluations_ = value;
269
2
        return *this;
270
2
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE15max_evaluationsEl
Line
Count
Source
263
1
    auto max_evaluations(index_type value) -> adaptive_diagonal_curves& {
264
1
        NUM_COLLECT_PRECONDITION(value > 0, this->logger(),
265
1
            "Maximum number of function evaluations must be a positive "
266
1
            "integer.");
267
268
1
        max_evaluations_ = value;
269
1
        return *this;
270
1
    }
271
272
    /*!
273
     * \brief Set the minimum rate of improvement in the function value required
274
     * for potentially optimal rectangles.
275
     *
276
     * \param[in] value Value.
277
     * \return This object.
278
     */
279
    auto min_rate_imp(value_type value) -> adaptive_diagonal_curves& {
280
        NUM_COLLECT_PRECONDITION(value > static_cast<value_type>(0),
281
            this->logger(),
282
            "Minimum rate of improvement in the function value required for "
283
            "potentially optimal rectangles must be a positive value.");
284
        min_rate_imp_ = value;
285
        return *this;
286
    }
287
288
    /*!
289
     * \brief Set the rate of function value used to check whether the function
290
     * value decreased in the current phase.
291
     *
292
     * \param[in] value Value.
293
     * \return This object.
294
     */
295
1
    auto decrease_rate_bound(value_type value) -> adaptive_diagonal_curves& {
296
1
        NUM_COLLECT_PRECONDITION(value > static_cast<value_type>(0),
297
1
            this->logger(),
298
1
            "Rate of function value used to check whether the function value "
299
1
            "decreased in the current phase must be a positive value.");
300
1
        decrease_rate_bound_ = value;
301
1
        return *this;
302
1
    }
303
304
private:
305
    //! Type of dictionaries of sample points.
306
    using dict_type = impl::adc_sample_dict<objective_function_type, MaxDigits>;
307
308
    //! Type of ternary vectors.
309
    using ternary_vector_type = typename dict_type::ternary_vector_type;
310
311
    //! Type of groups of hyper-rectangles.
312
    using group_type = impl::adc_group<value_type, ternary_vector_type>;
313
314
    //! Type of hyper-rectangles.
315
    using rectangle_type = typename group_type::rectangle_type;
316
317
    /*!
318
     * \brief Create the first hyper-rectangle.
319
     */
320
5
    void create_first_rectangle() {
321
5
        const index_type dim = value_dict_.dim();
322
5
        auto point = ternary_vector_type{dim};
323
20
        for (index_type i = 0; i < dim; ++i) {
324
15
            point.push_back(0);
325
15
        }
326
327
5
        const auto [lower_vertex, upper_vertex] =
328
5
            rectangle_type::determine_sample_points(point);
329
5
        const auto lower_vertex_value = value_dict_(lower_vertex);
330
5
        const auto upper_vertex_value = value_dict_(upper_vertex);
331
5
        const auto ave_value = half * (lower_vertex_value + upper_vertex_value);
332
5
        const auto rect = rectangle_type(point, ave_value);
333
334
5
        groups_.emplace_back(rect.dist());
335
5
        groups_.front().push(rect);
336
5
        using std::min;
337
5
        optimal_value_ = min(lower_vertex_value, upper_vertex_value);
338
5
        optimal_group_index_ = 0;
339
5
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE22create_first_rectangleEv
Line
Count
Source
320
4
    void create_first_rectangle() {
321
4
        const index_type dim = value_dict_.dim();
322
4
        auto point = ternary_vector_type{dim};
323
16
        for (index_type i = 0; i < dim; ++i) {
324
12
            point.push_back(0);
325
12
        }
326
327
4
        const auto [lower_vertex, upper_vertex] =
328
4
            rectangle_type::determine_sample_points(point);
329
4
        const auto lower_vertex_value = value_dict_(lower_vertex);
330
4
        const auto upper_vertex_value = value_dict_(upper_vertex);
331
4
        const auto ave_value = half * (lower_vertex_value + upper_vertex_value);
332
4
        const auto rect = rectangle_type(point, ave_value);
333
334
4
        groups_.emplace_back(rect.dist());
335
4
        groups_.front().push(rect);
336
4
        using std::min;
337
4
        optimal_value_ = min(lower_vertex_value, upper_vertex_value);
338
4
        optimal_group_index_ = 0;
339
4
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE22create_first_rectangleEv
Line
Count
Source
320
1
    void create_first_rectangle() {
321
1
        const index_type dim = value_dict_.dim();
322
1
        auto point = ternary_vector_type{dim};
323
4
        for (index_type i = 0; i < dim; ++i) {
324
3
            point.push_back(0);
325
3
        }
326
327
1
        const auto [lower_vertex, upper_vertex] =
328
1
            rectangle_type::determine_sample_points(point);
329
1
        const auto lower_vertex_value = value_dict_(lower_vertex);
330
1
        const auto upper_vertex_value = value_dict_(upper_vertex);
331
1
        const auto ave_value = half * (lower_vertex_value + upper_vertex_value);
332
1
        const auto rect = rectangle_type(point, ave_value);
333
334
1
        groups_.emplace_back(rect.dist());
335
1
        groups_.front().push(rect);
336
1
        using std::min;
337
1
        optimal_value_ = min(lower_vertex_value, upper_vertex_value);
338
1
        optimal_group_index_ = 0;
339
1
    }
340
341
    /*!
342
     * \brief Switch to the next state if necessary.
343
     *
344
     * Step 2.1, 2.4, 3, 4.4, 4.5, 4.7 in \cite Sergeyev2006.
345
     */
346
526
    void switch_state() {
347
526
        using std::abs;
348
526
        switch (state_) {
349
78
        case state_type::local:
350
78
            ++iterations_in_current_phase_;
351
78
            if (iterations_in_current_phase_ > value_dict_.dim()) {
352
26
                state_ = state_type::local_last;
353
26
            }
354
78
            return;
355
26
        case state_type::local_last:
356
26
            switch_state_on_local_last();
357
26
            return;
358
394
        case state_type::global:
359
394
            if (optimal_value_ <= prec_optimal_value_ -
360
394
                    decrease_rate_bound_ * abs(prec_optimal_value_)) {
361
0
                state_ = state_type::local;
362
0
                prec_optimal_value_ = optimal_value_;
363
0
                iterations_in_current_phase_ = 1;
364
0
                prec_optimal_group_index_ = optimal_group_index_;
365
0
                return;
366
0
            }
367
394
            ++iterations_in_current_phase_;
368
394
            if (iterations_in_current_phase_ >
369
394
                util::safe_cast<index_type>((static_cast<std::size_t>(2)
370
394
                    << util::safe_cast<std::size_t>(value_dict_.dim())))) {
371
23
                state_ = state_type::global_last;
372
23
                return;
373
23
            }
374
371
            return;
375
371
        case state_type::global_last:
376
23
            if (optimal_value_ <= prec_optimal_value_ -
377
23
                    decrease_rate_bound_ * abs(prec_optimal_value_)) {
378
0
                state_ = state_type::local;
379
0
                prec_optimal_value_ = optimal_value_;
380
0
                iterations_in_current_phase_ = 1;
381
0
                prec_optimal_group_index_ = optimal_group_index_;
382
0
                return;
383
0
            }
384
23
            state_ = state_type::global;
385
23
            iterations_in_current_phase_ = 1;
386
23
            prec_optimal_group_index_ = optimal_group_index_;
387
23
            return;
388
1
        case state_type::non_dividable:
389
            // Nothing can be done.
390
1
            return;
391
4
        default:
392
4
            state_ = state_type::local;
393
4
            prec_optimal_value_ = optimal_value_;
394
4
            iterations_in_current_phase_ = 1;
395
4
            prec_optimal_group_index_ = optimal_group_index_;
396
526
        }
397
526
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE12switch_stateEv
Line
Count
Source
346
511
    void switch_state() {
347
511
        using std::abs;
348
511
        switch (state_) {
349
69
        case state_type::local:
350
69
            ++iterations_in_current_phase_;
351
69
            if (iterations_in_current_phase_ > value_dict_.dim()) {
352
23
                state_ = state_type::local_last;
353
23
            }
354
69
            return;
355
23
        case state_type::local_last:
356
23
            switch_state_on_local_last();
357
23
            return;
358
393
        case state_type::global:
359
393
            if (optimal_value_ <= prec_optimal_value_ -
360
393
                    decrease_rate_bound_ * abs(prec_optimal_value_)) {
361
0
                state_ = state_type::local;
362
0
                prec_optimal_value_ = optimal_value_;
363
0
                iterations_in_current_phase_ = 1;
364
0
                prec_optimal_group_index_ = optimal_group_index_;
365
0
                return;
366
0
            }
367
393
            ++iterations_in_current_phase_;
368
393
            if (iterations_in_current_phase_ >
369
393
                util::safe_cast<index_type>((static_cast<std::size_t>(2)
370
393
                    << util::safe_cast<std::size_t>(value_dict_.dim())))) {
371
23
                state_ = state_type::global_last;
372
23
                return;
373
23
            }
374
370
            return;
375
370
        case state_type::global_last:
376
23
            if (optimal_value_ <= prec_optimal_value_ -
377
23
                    decrease_rate_bound_ * abs(prec_optimal_value_)) {
378
0
                state_ = state_type::local;
379
0
                prec_optimal_value_ = optimal_value_;
380
0
                iterations_in_current_phase_ = 1;
381
0
                prec_optimal_group_index_ = optimal_group_index_;
382
0
                return;
383
0
            }
384
23
            state_ = state_type::global;
385
23
            iterations_in_current_phase_ = 1;
386
23
            prec_optimal_group_index_ = optimal_group_index_;
387
23
            return;
388
0
        case state_type::non_dividable:
389
            // Nothing can be done.
390
0
            return;
391
3
        default:
392
3
            state_ = state_type::local;
393
3
            prec_optimal_value_ = optimal_value_;
394
3
            iterations_in_current_phase_ = 1;
395
3
            prec_optimal_group_index_ = optimal_group_index_;
396
511
        }
397
511
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE12switch_stateEv
Line
Count
Source
346
15
    void switch_state() {
347
15
        using std::abs;
348
15
        switch (state_) {
349
9
        case state_type::local:
350
9
            ++iterations_in_current_phase_;
351
9
            if (iterations_in_current_phase_ > value_dict_.dim()) {
352
3
                state_ = state_type::local_last;
353
3
            }
354
9
            return;
355
3
        case state_type::local_last:
356
3
            switch_state_on_local_last();
357
3
            return;
358
1
        case state_type::global:
359
1
            if (optimal_value_ <= prec_optimal_value_ -
360
1
                    decrease_rate_bound_ * abs(prec_optimal_value_)) {
361
0
                state_ = state_type::local;
362
0
                prec_optimal_value_ = optimal_value_;
363
0
                iterations_in_current_phase_ = 1;
364
0
                prec_optimal_group_index_ = optimal_group_index_;
365
0
                return;
366
0
            }
367
1
            ++iterations_in_current_phase_;
368
1
            if (iterations_in_current_phase_ >
369
1
                util::safe_cast<index_type>((static_cast<std::size_t>(2)
370
1
                    << util::safe_cast<std::size_t>(value_dict_.dim())))) {
371
0
                state_ = state_type::global_last;
372
0
                return;
373
0
            }
374
1
            return;
375
1
        case state_type::global_last:
376
0
            if (optimal_value_ <= prec_optimal_value_ -
377
0
                    decrease_rate_bound_ * abs(prec_optimal_value_)) {
378
0
                state_ = state_type::local;
379
0
                prec_optimal_value_ = optimal_value_;
380
0
                iterations_in_current_phase_ = 1;
381
0
                prec_optimal_group_index_ = optimal_group_index_;
382
0
                return;
383
0
            }
384
0
            state_ = state_type::global;
385
0
            iterations_in_current_phase_ = 1;
386
0
            prec_optimal_group_index_ = optimal_group_index_;
387
0
            return;
388
1
        case state_type::non_dividable:
389
            // Nothing can be done.
390
1
            return;
391
1
        default:
392
1
            state_ = state_type::local;
393
1
            prec_optimal_value_ = optimal_value_;
394
1
            iterations_in_current_phase_ = 1;
395
1
            prec_optimal_group_index_ = optimal_group_index_;
396
15
        }
397
15
    }
398
399
    /*!
400
     * \brief Switch to the next state if necessary in local_last state.
401
     */
402
26
    void switch_state_on_local_last() {
403
26
        using std::abs;
404
26
        if (optimal_value_ <= prec_optimal_value_ -
405
26
                decrease_rate_bound_ * abs(prec_optimal_value_)) {
406
22
            state_ = state_type::local;
407
22
            prec_optimal_value_ = optimal_value_;
408
22
            iterations_in_current_phase_ = 1;
409
22
            prec_optimal_group_index_ = optimal_group_index_;
410
22
            return;
411
22
        }
412
413
4
        const bool is_optimal_smallest =
414
4
            (optimal_group_index_ == groups_.size() - 1);
415
4
        const bool is_all_smallest =
416
4
            std::all_of(std::begin(groups_), std::end(groups_) - 1,
417
13
                [](const group_type& group) { return group.empty(); });
_ZZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE26switch_state_on_local_lastEvENKUlRKNS0_4impl9adc_groupIdNS6_18adc_ternary_vectorIN5Eigen6MatrixIdLin1ELi1ELi0ELin1ELi1EEELl8EEEEEE_clESF_
Line
Count
Source
417
10
                [](const group_type& group) { return group.empty(); });
_ZZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE26switch_state_on_local_lastEvENKUlRKNS0_4impl9adc_groupIdNS6_18adc_ternary_vectorIN5Eigen6MatrixIdLin1ELi1ELi0ELin1ELi1EEELl2EEEEEE_clESF_
Line
Count
Source
417
3
                [](const group_type& group) { return group.empty(); });
418
4
        if ((!is_optimal_smallest) || is_all_smallest) {
419
1
            state_ = state_type::local;
420
1
            iterations_in_current_phase_ = 1;
421
1
            prec_optimal_group_index_ = optimal_group_index_;
422
1
            return;
423
1
        }
424
425
3
        state_ = state_type::global;
426
3
        prec_optimal_value_ = optimal_value_;
427
3
        iterations_in_current_phase_ = 1;
428
3
        prec_optimal_group_index_ = optimal_group_index_;
429
3
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE26switch_state_on_local_lastEv
Line
Count
Source
402
23
    void switch_state_on_local_last() {
403
23
        using std::abs;
404
23
        if (optimal_value_ <= prec_optimal_value_ -
405
23
                decrease_rate_bound_ * abs(prec_optimal_value_)) {
406
20
            state_ = state_type::local;
407
20
            prec_optimal_value_ = optimal_value_;
408
20
            iterations_in_current_phase_ = 1;
409
20
            prec_optimal_group_index_ = optimal_group_index_;
410
20
            return;
411
20
        }
412
413
3
        const bool is_optimal_smallest =
414
3
            (optimal_group_index_ == groups_.size() - 1);
415
3
        const bool is_all_smallest =
416
3
            std::all_of(std::begin(groups_), std::end(groups_) - 1,
417
3
                [](const group_type& group) { return group.empty(); });
418
3
        if ((!is_optimal_smallest) || is_all_smallest) {
419
1
            state_ = state_type::local;
420
1
            iterations_in_current_phase_ = 1;
421
1
            prec_optimal_group_index_ = optimal_group_index_;
422
1
            return;
423
1
        }
424
425
2
        state_ = state_type::global;
426
2
        prec_optimal_value_ = optimal_value_;
427
2
        iterations_in_current_phase_ = 1;
428
2
        prec_optimal_group_index_ = optimal_group_index_;
429
2
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE26switch_state_on_local_lastEv
Line
Count
Source
402
3
    void switch_state_on_local_last() {
403
3
        using std::abs;
404
3
        if (optimal_value_ <= prec_optimal_value_ -
405
3
                decrease_rate_bound_ * abs(prec_optimal_value_)) {
406
2
            state_ = state_type::local;
407
2
            prec_optimal_value_ = optimal_value_;
408
2
            iterations_in_current_phase_ = 1;
409
2
            prec_optimal_group_index_ = optimal_group_index_;
410
2
            return;
411
2
        }
412
413
1
        const bool is_optimal_smallest =
414
1
            (optimal_group_index_ == groups_.size() - 1);
415
1
        const bool is_all_smallest =
416
1
            std::all_of(std::begin(groups_), std::end(groups_) - 1,
417
1
                [](const group_type& group) { return group.empty(); });
418
1
        if ((!is_optimal_smallest) || is_all_smallest) {
419
0
            state_ = state_type::local;
420
0
            iterations_in_current_phase_ = 1;
421
0
            prec_optimal_group_index_ = optimal_group_index_;
422
0
            return;
423
0
        }
424
425
1
        state_ = state_type::global;
426
1
        prec_optimal_value_ = optimal_value_;
427
1
        iterations_in_current_phase_ = 1;
428
1
        prec_optimal_group_index_ = optimal_group_index_;
429
1
    }
430
431
    /*!
432
     * \brief Iterate once in the local phase (not last iteration).
433
     */
434
79
    void iterate_locally() {
435
79
        const std::size_t max_group_index = std::max<std::size_t>(
436
79
            std::max<std::size_t>(prec_optimal_group_index_, 1) - 1,
437
79
            min_nonempty_group_index());
438
79
        divide_nondominated_rectangles(
439
79
            min_nonempty_group_index(), max_group_index);
440
79
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE15iterate_locallyEv
Line
Count
Source
434
70
    void iterate_locally() {
435
70
        const std::size_t max_group_index = std::max<std::size_t>(
436
70
            std::max<std::size_t>(prec_optimal_group_index_, 1) - 1,
437
70
            min_nonempty_group_index());
438
70
        divide_nondominated_rectangles(
439
70
            min_nonempty_group_index(), max_group_index);
440
70
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE15iterate_locallyEv
Line
Count
Source
434
9
    void iterate_locally() {
435
9
        const std::size_t max_group_index = std::max<std::size_t>(
436
9
            std::max<std::size_t>(prec_optimal_group_index_, 1) - 1,
437
9
            min_nonempty_group_index());
438
9
        divide_nondominated_rectangles(
439
9
            min_nonempty_group_index(), max_group_index);
440
9
    }
441
442
    /*!
443
     * \brief Iterate once at the last of the local phase.
444
     */
445
49
    void iterate_locally_last() {
446
49
        const std::size_t max_group_index = std::max<std::size_t>(
447
49
            prec_optimal_group_index_, min_nonempty_group_index());
448
49
        divide_nondominated_rectangles(
449
49
            min_nonempty_group_index(), max_group_index);
450
49
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE20iterate_locally_lastEv
Line
Count
Source
445
46
    void iterate_locally_last() {
446
46
        const std::size_t max_group_index = std::max<std::size_t>(
447
46
            prec_optimal_group_index_, min_nonempty_group_index());
448
46
        divide_nondominated_rectangles(
449
46
            min_nonempty_group_index(), max_group_index);
450
46
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE20iterate_locally_lastEv
Line
Count
Source
445
3
    void iterate_locally_last() {
446
3
        const std::size_t max_group_index = std::max<std::size_t>(
447
3
            prec_optimal_group_index_, min_nonempty_group_index());
448
3
        divide_nondominated_rectangles(
449
3
            min_nonempty_group_index(), max_group_index);
450
3
    }
451
452
    /*!
453
     * \brief Iterate once in the global phase (not last iteration).
454
     */
455
397
    void iterate_globally() {
456
397
        const std::size_t max_group_index =
457
397
            (std::max<std::size_t>(
458
397
                 prec_optimal_group_index_, min_nonempty_group_index()) +
459
397
                min_nonempty_group_index() + 1) /
460
397
            2;
461
397
        divide_nondominated_rectangles(
462
397
            min_nonempty_group_index(), max_group_index);
463
397
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE16iterate_globallyEv
Line
Count
Source
455
395
    void iterate_globally() {
456
395
        const std::size_t max_group_index =
457
395
            (std::max<std::size_t>(
458
395
                 prec_optimal_group_index_, min_nonempty_group_index()) +
459
395
                min_nonempty_group_index() + 1) /
460
395
            2;
461
395
        divide_nondominated_rectangles(
462
395
            min_nonempty_group_index(), max_group_index);
463
395
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE16iterate_globallyEv
Line
Count
Source
455
2
    void iterate_globally() {
456
2
        const std::size_t max_group_index =
457
2
            (std::max<std::size_t>(
458
2
                 prec_optimal_group_index_, min_nonempty_group_index()) +
459
2
                min_nonempty_group_index() + 1) /
460
2
            2;
461
2
        divide_nondominated_rectangles(
462
2
            min_nonempty_group_index(), max_group_index);
463
2
    }
464
465
    /*!
466
     * \brief Iterate once at teh last of the global phase.
467
     */
468
23
    void iterate_globally_last() { iterate_locally_last(); }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE21iterate_globally_lastEv
Line
Count
Source
468
23
    void iterate_globally_last() { iterate_locally_last(); }
Unexecuted instantiation: _ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE21iterate_globally_lastEv
469
470
    /*!
471
     * \brief Get the minimum index of non-empty groups.
472
     *
473
     * \return Minimum index of groups.
474
     */
475
1.44k
    [[nodiscard]] auto min_nonempty_group_index() const -> std::size_t {
476
7.94k
        for (std::size_t i = 0; i < groups_.size(); ++i) {
477
7.94k
            if (!groups_[i].empty()) {
478
1.44k
                return i;
479
1.44k
            }
480
7.94k
        }
481
0
        NUM_COLLECT_LOG_AND_THROW(precondition_not_satisfied,
482
0
            "adaptive_diagonal_curves::init is not called.");
483
0
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE24min_nonempty_group_indexEv
Line
Count
Source
475
1.41k
    [[nodiscard]] auto min_nonempty_group_index() const -> std::size_t {
476
7.85k
        for (std::size_t i = 0; i < groups_.size(); ++i) {
477
7.85k
            if (!groups_[i].empty()) {
478
1.41k
                return i;
479
1.41k
            }
480
7.85k
        }
481
0
        NUM_COLLECT_LOG_AND_THROW(precondition_not_satisfied,
482
0
            "adaptive_diagonal_curves::init is not called.");
483
0
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE24min_nonempty_group_indexEv
Line
Count
Source
475
30
    [[nodiscard]] auto min_nonempty_group_index() const -> std::size_t {
476
83
        for (std::size_t i = 0; i < groups_.size(); ++i) {
477
83
            if (!groups_[i].empty()) {
478
30
                return i;
479
30
            }
480
83
        }
481
0
        NUM_COLLECT_LOG_AND_THROW(precondition_not_satisfied,
482
0
            "adaptive_diagonal_curves::init is not called.");
483
0
    }
484
485
    /*!
486
     * \brief Divide nondominated hyper-rectangles.
487
     *
488
     * \param[in] min_group Minimum index of groups to search in.
489
     * \param[in] max_group Maximum index of groups to search in.
490
     */
491
    void divide_nondominated_rectangles(
492
525
        std::size_t min_group, std::size_t max_group) {
493
525
        const auto search_rect =
494
525
            determine_nondominated_rectangles(min_group, max_group);
495
525
        bool divided_rectangle = false;
496
525
        for (auto iter = std::rbegin(search_rect);
497
3.24k
            iter != std::rend(search_rect); ++iter) {
498
2.71k
            if (divide_rectangle(iter->first)) {
499
2.71k
                divided_rectangle = true;
500
2.71k
            }
501
2.71k
        }
502
525
        if (!divided_rectangle) {
503
1
            state_ = state_type::non_dividable;
504
1
            this->logger().warning()(
505
1
                "No rectangle can be divided. "
506
1
                "Stop the iteration or tune the parameter MaxDigits.");
507
1
        }
508
525
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE30divide_nondominated_rectanglesEmm
Line
Count
Source
492
511
        std::size_t min_group, std::size_t max_group) {
493
511
        const auto search_rect =
494
511
            determine_nondominated_rectangles(min_group, max_group);
495
511
        bool divided_rectangle = false;
496
511
        for (auto iter = std::rbegin(search_rect);
497
3.21k
            iter != std::rend(search_rect); ++iter) {
498
2.70k
            if (divide_rectangle(iter->first)) {
499
2.69k
                divided_rectangle = true;
500
2.69k
            }
501
2.70k
        }
502
511
        if (!divided_rectangle) {
503
0
            state_ = state_type::non_dividable;
504
0
            this->logger().warning()(
505
0
                "No rectangle can be divided. "
506
0
                "Stop the iteration or tune the parameter MaxDigits.");
507
0
        }
508
511
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE30divide_nondominated_rectanglesEmm
Line
Count
Source
492
14
        std::size_t min_group, std::size_t max_group) {
493
14
        const auto search_rect =
494
14
            determine_nondominated_rectangles(min_group, max_group);
495
14
        bool divided_rectangle = false;
496
14
        for (auto iter = std::rbegin(search_rect);
497
30
            iter != std::rend(search_rect); ++iter) {
498
16
            if (divide_rectangle(iter->first)) {
499
13
                divided_rectangle = true;
500
13
            }
501
16
        }
502
14
        if (!divided_rectangle) {
503
1
            state_ = state_type::non_dividable;
504
1
            this->logger().warning()(
505
1
                "No rectangle can be divided. "
506
1
                "Stop the iteration or tune the parameter MaxDigits.");
507
1
        }
508
14
    }
509
510
    /*!
511
     * \brief Determine nondominated hyper-rectangles.
512
     *
513
     * \param[in] min_group Minimum index of groups to search in.
514
     * \param[in] max_group Maximum index of groups to search in.
515
     * \return List of (index of group, slope).
516
     */
517
    [[nodiscard]] auto determine_nondominated_rectangles(
518
        std::size_t min_group, std::size_t max_group) const
519
525
        -> std::vector<std::pair<std::size_t, value_type>> {
520
525
        NUM_COLLECT_DEBUG_ASSERT(min_group <= max_group);
521
525
        NUM_COLLECT_DEBUG_ASSERT(max_group < groups_.size());
522
525
        NUM_COLLECT_DEBUG_ASSERT(!groups_[min_group].empty());
523
524
525
        std::vector<std::pair<std::size_t, value_type>> search_rects;
525
525
        search_rects.emplace_back(
526
525
            min_group, std::numeric_limits<value_type>::max());
527
528
        // convex full scan
529
3.23k
        for (std::size_t i = min_group + 1; i <= max_group; ++i) {
530
2.71k
            if (groups_[i].empty()) {
531
3
                continue;
532
3
            }
533
3.22k
            while (true) {
534
3.22k
                const auto& [last_i, last_slope] = search_rects.back();
535
3.22k
                const auto slope = calculate_slope(last_i, i);
536
3.22k
                if (slope <= last_slope) {
537
2.70k
                    search_rects.emplace_back(i, slope);
538
2.70k
                    break;
539
2.70k
                }
540
515
                search_rects.pop_back();
541
515
            }
542
2.70k
        }
543
544
        // remove rectangles which won't update optimal value
545
525
        using std::abs;
546
525
        const auto value_bound =
547
525
            optimal_value_ - min_rate_imp_ * abs(optimal_value_);
548
3.24k
        for (auto iter = search_rects.begin(); iter != search_rects.end();) {
549
2.71k
            const auto& [ind, slope] = *iter;
550
2.71k
            if (groups_[ind].min_rect().ave_value() -
551
2.71k
                    slope * groups_[ind].dist() <=
552
2.71k
                value_bound) {
553
2.71k
                ++iter;
554
2.71k
            } else {
555
0
                iter = search_rects.erase(iter);
556
0
            }
557
2.71k
        }
558
559
525
        return search_rects;
560
525
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE33determine_nondominated_rectanglesEmm
Line
Count
Source
519
511
        -> std::vector<std::pair<std::size_t, value_type>> {
520
511
        NUM_COLLECT_DEBUG_ASSERT(min_group <= max_group);
521
511
        NUM_COLLECT_DEBUG_ASSERT(max_group < groups_.size());
522
511
        NUM_COLLECT_DEBUG_ASSERT(!groups_[min_group].empty());
523
524
511
        std::vector<std::pair<std::size_t, value_type>> search_rects;
525
511
        search_rects.emplace_back(
526
511
            min_group, std::numeric_limits<value_type>::max());
527
528
        // convex full scan
529
3.22k
        for (std::size_t i = min_group + 1; i <= max_group; ++i) {
530
2.71k
            if (groups_[i].empty()) {
531
3
                continue;
532
3
            }
533
3.22k
            while (true) {
534
3.22k
                const auto& [last_i, last_slope] = search_rects.back();
535
3.22k
                const auto slope = calculate_slope(last_i, i);
536
3.22k
                if (slope <= last_slope) {
537
2.70k
                    search_rects.emplace_back(i, slope);
538
2.70k
                    break;
539
2.70k
                }
540
515
                search_rects.pop_back();
541
515
            }
542
2.70k
        }
543
544
        // remove rectangles which won't update optimal value
545
511
        using std::abs;
546
511
        const auto value_bound =
547
511
            optimal_value_ - min_rate_imp_ * abs(optimal_value_);
548
3.21k
        for (auto iter = search_rects.begin(); iter != search_rects.end();) {
549
2.70k
            const auto& [ind, slope] = *iter;
550
2.70k
            if (groups_[ind].min_rect().ave_value() -
551
2.70k
                    slope * groups_[ind].dist() <=
552
2.70k
                value_bound) {
553
2.70k
                ++iter;
554
2.70k
            } else {
555
0
                iter = search_rects.erase(iter);
556
0
            }
557
2.70k
        }
558
559
511
        return search_rects;
560
511
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE33determine_nondominated_rectanglesEmm
Line
Count
Source
519
14
        -> std::vector<std::pair<std::size_t, value_type>> {
520
14
        NUM_COLLECT_DEBUG_ASSERT(min_group <= max_group);
521
14
        NUM_COLLECT_DEBUG_ASSERT(max_group < groups_.size());
522
14
        NUM_COLLECT_DEBUG_ASSERT(!groups_[min_group].empty());
523
524
14
        std::vector<std::pair<std::size_t, value_type>> search_rects;
525
14
        search_rects.emplace_back(
526
14
            min_group, std::numeric_limits<value_type>::max());
527
528
        // convex full scan
529
16
        for (std::size_t i = min_group + 1; i <= max_group; ++i) {
530
2
            if (groups_[i].empty()) {
531
0
                continue;
532
0
            }
533
2
            while (true) {
534
2
                const auto& [last_i, last_slope] = search_rects.back();
535
2
                const auto slope = calculate_slope(last_i, i);
536
2
                if (slope <= last_slope) {
537
2
                    search_rects.emplace_back(i, slope);
538
2
                    break;
539
2
                }
540
0
                search_rects.pop_back();
541
0
            }
542
2
        }
543
544
        // remove rectangles which won't update optimal value
545
14
        using std::abs;
546
14
        const auto value_bound =
547
14
            optimal_value_ - min_rate_imp_ * abs(optimal_value_);
548
30
        for (auto iter = search_rects.begin(); iter != search_rects.end();) {
549
16
            const auto& [ind, slope] = *iter;
550
16
            if (groups_[ind].min_rect().ave_value() -
551
16
                    slope * groups_[ind].dist() <=
552
16
                value_bound) {
553
16
                ++iter;
554
16
            } else {
555
0
                iter = search_rects.erase(iter);
556
0
            }
557
16
        }
558
559
14
        return search_rects;
560
14
    }
561
562
    /*!
563
     * \brief Calculate slope.
564
     *
565
     * \param[in] group_ind1 Index of group.
566
     * \param[in] group_ind2 Index of group.
567
     * \return Slope.
568
     */
569
    [[nodiscard]] auto calculate_slope(
570
3.22k
        std::size_t group_ind1, std::size_t group_ind2) const -> value_type {
571
3.22k
        return (groups_[group_ind1].min_rect().ave_value() -
572
3.22k
                   groups_[group_ind2].min_rect().ave_value()) /
573
3.22k
            (groups_[group_ind1].dist() - groups_[group_ind2].dist());
574
3.22k
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE15calculate_slopeEmm
Line
Count
Source
570
3.22k
        std::size_t group_ind1, std::size_t group_ind2) const -> value_type {
571
3.22k
        return (groups_[group_ind1].min_rect().ave_value() -
572
3.22k
                   groups_[group_ind2].min_rect().ave_value()) /
573
3.22k
            (groups_[group_ind1].dist() - groups_[group_ind2].dist());
574
3.22k
    }
_ZNK11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE15calculate_slopeEmm
Line
Count
Source
570
2
        std::size_t group_ind1, std::size_t group_ind2) const -> value_type {
571
2
        return (groups_[group_ind1].min_rect().ave_value() -
572
2
                   groups_[group_ind2].min_rect().ave_value()) /
573
2
            (groups_[group_ind1].dist() - groups_[group_ind2].dist());
574
2
    }
575
576
    /*!
577
     * \brief Divide a hyper-rectangle.
578
     *
579
     * \param[in] group_ind Index of group.
580
     * \retval true The hyper-rectangle is divided.
581
     * \retval false The hyper-rectangle is not divided.
582
     */
583
2.71k
    [[nodiscard]] auto divide_rectangle(std::size_t group_ind) -> bool {
584
2.71k
        if (!groups_[group_ind].is_dividable()) {
585
9
            return false;
586
9
        }
587
588
2.71k
        impl::adc_ternary_vector vertex =
589
2.71k
            std::move(groups_[group_ind].pop().vertex());
590
591
2.71k
        const auto [dim, digit] = vertex.push_back(0);
592
2.71k
        const auto rect0 = create_rect(vertex, group_ind + 1);
593
2.71k
        vertex(dim, digit) = 1;
594
2.71k
        const auto rect1 = create_rect(vertex, group_ind + 1);
595
2.71k
        vertex(dim, digit) = 2;
596
2.71k
        const auto rect2 = create_rect(vertex, group_ind + 1);
597
598
2.71k
        if (groups_.size() == group_ind + 1) {
599
46
            groups_.emplace_back(rect0.dist());
600
46
        }
601
2.71k
        groups_[group_ind + 1].push(rect0);
602
2.71k
        groups_[group_ind + 1].push(rect1);
603
2.71k
        groups_[group_ind + 1].push(rect2);
604
605
2.71k
        return true;
606
2.71k
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE16divide_rectangleEm
Line
Count
Source
583
2.70k
    [[nodiscard]] auto divide_rectangle(std::size_t group_ind) -> bool {
584
2.70k
        if (!groups_[group_ind].is_dividable()) {
585
6
            return false;
586
6
        }
587
588
2.69k
        impl::adc_ternary_vector vertex =
589
2.69k
            std::move(groups_[group_ind].pop().vertex());
590
591
2.69k
        const auto [dim, digit] = vertex.push_back(0);
592
2.69k
        const auto rect0 = create_rect(vertex, group_ind + 1);
593
2.69k
        vertex(dim, digit) = 1;
594
2.69k
        const auto rect1 = create_rect(vertex, group_ind + 1);
595
2.69k
        vertex(dim, digit) = 2;
596
2.69k
        const auto rect2 = create_rect(vertex, group_ind + 1);
597
598
2.69k
        if (groups_.size() == group_ind + 1) {
599
43
            groups_.emplace_back(rect0.dist());
600
43
        }
601
2.69k
        groups_[group_ind + 1].push(rect0);
602
2.69k
        groups_[group_ind + 1].push(rect1);
603
2.69k
        groups_[group_ind + 1].push(rect2);
604
605
2.69k
        return true;
606
2.70k
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE16divide_rectangleEm
Line
Count
Source
583
16
    [[nodiscard]] auto divide_rectangle(std::size_t group_ind) -> bool {
584
16
        if (!groups_[group_ind].is_dividable()) {
585
3
            return false;
586
3
        }
587
588
13
        impl::adc_ternary_vector vertex =
589
13
            std::move(groups_[group_ind].pop().vertex());
590
591
13
        const auto [dim, digit] = vertex.push_back(0);
592
13
        const auto rect0 = create_rect(vertex, group_ind + 1);
593
13
        vertex(dim, digit) = 1;
594
13
        const auto rect1 = create_rect(vertex, group_ind + 1);
595
13
        vertex(dim, digit) = 2;
596
13
        const auto rect2 = create_rect(vertex, group_ind + 1);
597
598
13
        if (groups_.size() == group_ind + 1) {
599
3
            groups_.emplace_back(rect0.dist());
600
3
        }
601
13
        groups_[group_ind + 1].push(rect0);
602
13
        groups_[group_ind + 1].push(rect1);
603
13
        groups_[group_ind + 1].push(rect2);
604
605
13
        return true;
606
16
    }
607
608
    /*!
609
     * \brief Create a hyper-rectangle.
610
     *
611
     * \param[in] vertex Vertex with lower first component.
612
     * \param[in] group_ind Group index.
613
     * \return Hyper-rectangle.
614
     */
615
    [[nodiscard]] auto create_rect(const ternary_vector_type& vertex,
616
8.13k
        std::size_t group_ind) -> rectangle_type {
617
8.13k
        const auto [vertex1, vertex2] =
618
8.13k
            rectangle_type::determine_sample_points(vertex);
619
8.13k
        const auto value1 = value_dict_(vertex1);
620
8.13k
        const auto value2 = value_dict_(vertex2);
621
8.13k
        const auto ave_value = half * (value1 + value2);
622
8.13k
        if (value1 < optimal_value_) {
623
38
            optimal_value_ = value1;
624
38
            optimal_group_index_ = group_ind;
625
8.09k
        } else if (value1 <= optimal_value_ &&
626
8.09k
            group_ind > optimal_group_index_) {
627
22
            optimal_group_index_ = group_ind;
628
22
        }
629
8.13k
        if (value2 < optimal_value_) {
630
30
            optimal_value_ = value2;
631
30
            optimal_group_index_ = group_ind;
632
8.10k
        } else if (value2 <= optimal_value_ &&
633
8.10k
            group_ind > optimal_group_index_) {
634
0
            optimal_group_index_ = group_ind;
635
0
        }
636
8.13k
        return rectangle_type(vertex, ave_value);
637
8.13k
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl8EE11create_rectERKNS0_4impl18adc_ternary_vectorIN5Eigen6MatrixIdLin1ELi1ELi0ELin1ELi1EEELl8EEEm
Line
Count
Source
616
8.09k
        std::size_t group_ind) -> rectangle_type {
617
8.09k
        const auto [vertex1, vertex2] =
618
8.09k
            rectangle_type::determine_sample_points(vertex);
619
8.09k
        const auto value1 = value_dict_(vertex1);
620
8.09k
        const auto value2 = value_dict_(vertex2);
621
8.09k
        const auto ave_value = half * (value1 + value2);
622
8.09k
        if (value1 < optimal_value_) {
623
36
            optimal_value_ = value1;
624
36
            optimal_group_index_ = group_ind;
625
8.05k
        } else if (value1 <= optimal_value_ &&
626
8.05k
            group_ind > optimal_group_index_) {
627
19
            optimal_group_index_ = group_ind;
628
19
        }
629
8.09k
        if (value2 < optimal_value_) {
630
27
            optimal_value_ = value2;
631
27
            optimal_group_index_ = group_ind;
632
8.06k
        } else if (value2 <= optimal_value_ &&
633
8.06k
            group_ind > optimal_group_index_) {
634
0
            optimal_group_index_ = group_ind;
635
0
        }
636
8.09k
        return rectangle_type(vertex, ave_value);
637
8.09k
    }
_ZN11num_collect3opt24adaptive_diagonal_curvesIN16num_prob_collect3opt24multi_quadratic_functionELl2EE11create_rectERKNS0_4impl18adc_ternary_vectorIN5Eigen6MatrixIdLin1ELi1ELi0ELin1ELi1EEELl2EEEm
Line
Count
Source
616
39
        std::size_t group_ind) -> rectangle_type {
617
39
        const auto [vertex1, vertex2] =
618
39
            rectangle_type::determine_sample_points(vertex);
619
39
        const auto value1 = value_dict_(vertex1);
620
39
        const auto value2 = value_dict_(vertex2);
621
39
        const auto ave_value = half * (value1 + value2);
622
39
        if (value1 < optimal_value_) {
623
2
            optimal_value_ = value1;
624
2
            optimal_group_index_ = group_ind;
625
37
        } else if (value1 <= optimal_value_ &&
626
37
            group_ind > optimal_group_index_) {
627
3
            optimal_group_index_ = group_ind;
628
3
        }
629
39
        if (value2 < optimal_value_) {
630
3
            optimal_value_ = value2;
631
3
            optimal_group_index_ = group_ind;
632
36
        } else if (value2 <= optimal_value_ &&
633
36
            group_ind > optimal_group_index_) {
634
0
            optimal_group_index_ = group_ind;
635
0
        }
636
39
        return rectangle_type(vertex, ave_value);
637
39
    }
638
639
    //! Half.
640
    static inline const auto half = static_cast<value_type>(0.5);
641
642
    //! Dictionary of sampled points.
643
    dict_type value_dict_;
644
645
    //! Groups of hyper-rectangles.
646
    std::vector<group_type> groups_{};
647
648
    //! Number of iterations.
649
    index_type iterations_{0};
650
651
    //! State.
652
    state_type state_{state_type::none};
653
654
    /*!
655
     * \brief Current optimal value.
656
     *
657
     * This value is used for updating \ref optimal_group_index_.
658
     */
659
    value_type optimal_value_{};
660
661
    //! Index of the group in which the optimal solution exists.
662
    std::size_t optimal_group_index_{0};
663
664
    //! Old optimal value at the start of the current phase.
665
    value_type prec_optimal_value_{};
666
667
    /*!
668
     * \brief Index of the group in which the old optimal solution at the start
669
     * of the current phase exists.
670
     */
671
    std::size_t prec_optimal_group_index_{0};
672
673
    /*!
674
     * \brief Number of iterations in the current phase.
675
     *
676
     * This is initialized at the start of the local or global phases.
677
     */
678
    index_type iterations_in_current_phase_{0};
679
680
    //! Default maximum number of function evaluations.
681
    static constexpr index_type default_max_evaluations = 10000;
682
683
    //! Maximum number of function evaluations.
684
    index_type max_evaluations_{default_max_evaluations};
685
686
    /*!
687
     * \brief Default minimum rate of improvement in the function value required
688
     * for potentially optimal rectangles.
689
     */
690
    static inline const auto default_min_rate_imp =
691
        static_cast<value_type>(1e-4);
692
693
    /*!
694
     * \brief Minimum rate of improvement in the function value required for
695
     * potentially optimal rectangles.
696
     */
697
    value_type min_rate_imp_{default_min_rate_imp};
698
699
    /*!
700
     * \brief Default rate of function value used to check whether the function
701
     * value decreased in the current phase.
702
     */
703
    static inline const auto default_decrease_rate_bound =
704
        static_cast<value_type>(0.01);
705
706
    /*!
707
     * \brief Rate of function value used to check whether the function value
708
     * decreased in the current phase.
709
     */
710
    value_type decrease_rate_bound_{default_decrease_rate_bound};
711
};
712
713
}  // namespace num_collect::opt