Loading...
Searching...
No Matches
OptimizerFactory.h
1//
2// Created by henri on 21/03/23.
3//
4
5#ifndef IDOL_OPTIMIZERFACTORY_H
6#define IDOL_OPTIMIZERFACTORY_H
7
8#include "Optimizer.h"
9
10#include <optional>
11#include <functional>
12
13namespace idol {
14 class Model;
15 class Env;
16 class OptimizerFactory;
17 template<class CRTP>
19}
20
22protected:
23 std::optional<bool> m_logs;
24 std::optional<double> m_time_limit;
25 std::optional<unsigned int> m_thread_limit;
26 std::optional<unsigned int> m_iteration_count_limit;
27 std::optional<double> m_best_bound_stop;
28 std::optional<double> m_best_obj_stop;
29 std::optional<bool> m_presolve;
30 std::optional<bool> m_infeasible_or_unbounded_info;
31
32 std::optional<double> m_tol_mip_relative_gap;
33 std::optional<double> m_tol_mip_absolute_gap;
34 std::optional<double> m_tol_integer;
35 std::optional<double> m_tol_feasibility;
36 std::optional<double> m_tol_optimality;
37
38 [[nodiscard]] virtual Optimizer* create(const Model& t_model) const = 0;
39public:
40 virtual ~OptimizerFactory() = default;
41
42 virtual Optimizer* operator()(const Model& t_model) const;
43
44 [[nodiscard]] virtual OptimizerFactory* clone() const = 0;
45
46 template<class T> T& as() {
47 auto* result = dynamic_cast<T*>(this);
48 if (!result) {
49 throw Exception("Optimizer factory could not be cast to desired type.");
50 }
51 return *result;
52 }
53
54 template<class T> const T& as() const {
55 auto* result = dynamic_cast<const T*>(this);
56 if (!result) {
57 throw Exception("Optimizer factory could not be cast to desired type.");
58 }
59 return *result;
60 }
61
62 template<class T> [[nodiscard]] bool is() const {
63 return dynamic_cast<const T*>(this);
64 }
65};
66
67template<class CRTP>
69protected:
70 CRTP& crtp() { return static_cast<CRTP&>(*this); }
71 const CRTP& crtp() const { return static_cast<const CRTP&>(*this); }
72public:
73 CRTP& with_logs(bool t_value);
74 CRTP& with_time_limit(double t_time_limit);
75 CRTP& with_thread_limit(unsigned int t_max_n_threads);
76 CRTP& with_iteration_limit(unsigned int t_iteration_count_limit);
77 CRTP& with_best_bound_stop(double t_best_bound_stop);
78 CRTP& with_best_obj_stop(double t_user_best_obj);
79 CRTP& with_presolve(bool t_value);
80 CRTP& with_infeasible_or_unbounded_info(bool t_value);
81
82 CRTP& with_tol_mip_relative_gap(double t_tol_mip_relative_gap);
83 CRTP& with_tol_mip_absolute_gap(double t_tol_mip_absolute_gap);
84 CRTP& with_tol_integer(double t_tol_integer);
85 CRTP& with_tol_feasibility(double t_tol_feasibility);
86 CRTP& with_tol_optimality(double t_tol_optimality);
87
88 CRTP& conditional(bool t_conditional_value, const std::function<void(CRTP&)>& t_if);
89 CRTP& conditional(bool t_conditional_value, const std::function<void(CRTP&)>& t_if, const std::function<void(CRTP&)>& t_else);
90
91};
92
93template<class CRTP>
94CRTP &
95idol::OptimizerFactoryWithDefaultParameters<CRTP>::conditional(bool t_conditional_value, const std::function<void(CRTP&)>& t_if, const std::function<void(CRTP&)>& t_else) {
96 t_conditional_value ? t_if(crtp()) : t_else(crtp());
97 return crtp();
98}
99
100template<class CRTP>
101CRTP &
102idol::OptimizerFactoryWithDefaultParameters<CRTP>::conditional(bool t_conditional_value, const std::function<void(CRTP&)>& t_if) {
103 return conditional(t_conditional_value, t_if, [](CRTP&){});
104}
105
106template<class CRTP>
107CRTP &idol::OptimizerFactoryWithDefaultParameters<CRTP>::with_infeasible_or_unbounded_info(bool t_value) {
108
109 if (m_infeasible_or_unbounded_info.has_value()) {
110 throw Exception("An infeasible-or-unbounded-info instruction has already been given.");
111 }
112
113 m_infeasible_or_unbounded_info = t_value;
114
115 return crtp();
116}
117
118template<class CRTP>
119CRTP &idol::OptimizerFactoryWithDefaultParameters<CRTP>::with_presolve(bool t_value) {
120
121 if (m_presolve.has_value()) {
122 throw Exception("A get_param_presolve instruction has already been given.");
123 }
124
125 m_presolve = t_value;
126
127 return crtp();
128}
129
130template<class CRTP>
131CRTP &idol::OptimizerFactoryWithDefaultParameters<CRTP>::with_tol_mip_absolute_gap(double t_tol_mip_absolute_gap) {
132
133 if (m_tol_mip_absolute_gap.has_value()) {
134 throw Exception("An absolute gap tolerance count limit has already been given.");
135 }
136
137 m_tol_mip_absolute_gap = t_tol_mip_absolute_gap;
138
139 return crtp();
140}
141
142template <class CRTP>
143CRTP& idol::OptimizerFactoryWithDefaultParameters<CRTP>::with_tol_integer(double t_tol_integer) {
144 if (m_tol_mip_absolute_gap.has_value()) {
145 throw Exception("A tolerance for integrality has already been given.");
146 }
147 m_tol_integer = t_tol_integer;
148 return crtp();
149}
150
151template <class CRTP>
152CRTP& idol::OptimizerFactoryWithDefaultParameters<CRTP>::with_tol_feasibility(double t_tol_feasibility) {
153 if (m_tol_feasibility.has_value()) {
154 throw Exception("A tolerance for feasibility has already been given.");
155 }
156 m_tol_feasibility = t_tol_feasibility;
157 return crtp();
158}
159
160template <class CRTP>
161CRTP& idol::OptimizerFactoryWithDefaultParameters<CRTP>::with_tol_optimality(double t_tol_optimality) {
162
163 if (m_tol_optimality.has_value()) {
164 throw Exception("An optimality tolerance has already been given.");
165 }
166
167 m_tol_optimality = t_tol_optimality;
168
169 return crtp();
170}
171
172template<class CRTP>
173CRTP &idol::OptimizerFactoryWithDefaultParameters<CRTP>::with_tol_mip_relative_gap(double t_tol_mip_relative_gap) {
174
175 if (m_tol_mip_relative_gap.has_value()) {
176 throw Exception("A relative gap tolerance count limit has already been given.");
177 }
178
179 m_tol_mip_relative_gap = t_tol_mip_relative_gap;
180
181 return crtp();
182}
183
184template<class CRTP>
185CRTP &idol::OptimizerFactoryWithDefaultParameters<CRTP>::with_best_obj_stop(double t_user_best_obj) {
186
187 if (m_best_obj_stop.has_value()) {
188 throw Exception("A user best obj count limit has already been given.");
189 }
190
191 m_best_obj_stop = t_user_best_obj;
192
193 return crtp();
194}
195
196template<class CRTP>
197CRTP &idol::OptimizerFactoryWithDefaultParameters<CRTP>::with_best_bound_stop(double t_best_bound_stop) {
198
199 if (m_best_bound_stop.has_value()) {
200 throw Exception("A user best bound limit has already been given.");
201 }
202
203 m_best_bound_stop = t_best_bound_stop;
204
205 return crtp();
206}
207
208template<class CRTP>
209CRTP &idol::OptimizerFactoryWithDefaultParameters<CRTP>::with_iteration_limit(unsigned int t_iteration_count_limit) {
210
211 if (m_iteration_count_limit.has_value()) {
212 throw Exception("An iteration count limit has already been given.");
213 }
214
215 m_iteration_count_limit = t_iteration_count_limit;
216
217 return crtp();
218}
219
220template<class CRTP>
221CRTP &idol::OptimizerFactoryWithDefaultParameters<CRTP>::with_thread_limit(unsigned int t_max_n_threads) {
222
223 if (m_thread_limit.has_value()) {
224 throw Exception("A thread limit has already been given.");
225 }
226
227 m_thread_limit = t_max_n_threads;
228
229 return crtp();
230}
231
232template<class CRTP>
233CRTP &idol::OptimizerFactoryWithDefaultParameters<CRTP>::with_time_limit(double t_time_limit) {
234
235 if (m_time_limit.has_value()) {
236 throw Exception("A time limit has already been given.");
237 }
238
239 m_time_limit = t_time_limit;
240
241 return crtp();
242}
243
244template<class CRTP>
245CRTP &idol::OptimizerFactoryWithDefaultParameters<CRTP>::with_logs(bool t_value) {
246
247 if (m_logs.has_value()) {
248 throw Exception("Logging settings have already been given.");
249 }
250
251 m_logs = t_value;
252
253 return crtp();
254}
255
256#endif //IDOL_OPTIMIZERFACTORY_H