idol
A C++ Framework for Optimization
Loading...
Searching...
No Matches
OptimizerWithLazyUpdates.h
1//
2// Created by henri on 31/01/23.
3//
4
5#ifndef IDOL_OPTIMIZERWITHLAZYUPDATES_H
6#define IDOL_OPTIMIZERWITHLAZYUPDATES_H
7
8#include "idol/general/optimizers/Optimizer.h"
9
10#include "idol/mixed-integer/modeling/models/Model.h"
11
12#include <vector>
13#include <list>
14#include <optional>
15
16namespace idol {
17 template<class T, class ImplT>
18 class Lazy;
19
20 template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
21 class OptimizerWithLazyUpdates;
22}
23
24template<class T, class ImplT>
26 T m_object;
27 std::optional<ImplT> m_impl;
28 std::optional<std::list<unsigned int>::iterator> m_to_be_updated_flag;
29public:
30 Lazy(const T& t_object, std::list<unsigned int>::iterator t_to_be_updated_flag)
31 : m_object(t_object), m_to_be_updated_flag(t_to_be_updated_flag) {}
32
33 [[nodiscard]] bool has_impl() const { return m_impl.has_value(); }
34
35 ImplT& impl() { return m_impl.value(); }
36
37 const ImplT& impl() const { return m_impl.value(); }
38
39 [[nodiscard]] bool is_to_be_updated() const { return m_to_be_updated_flag.has_value(); }
40
41 void set_as_to_be_updated(std::list<unsigned int>::iterator t_flag) { m_to_be_updated_flag = t_flag; }
42
43 void set_as_updated() { return m_to_be_updated_flag.reset(); }
44
45 [[nodiscard]] std::list<unsigned int>::iterator to_be_updated_flag() const { return m_to_be_updated_flag.value(); }
46
47 void set_impl(ImplT&& t_impl) { m_impl = std::move(t_impl); }
48
49 const T& object() const { return m_object; }
50};
51
52template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
54 std::vector<Lazy<Var, VarImplT>> m_variables;
55 std::list<unsigned int> m_variables_to_update;
56
57 std::vector<Lazy<Ctr, CtrImplT>> m_constraints;
58 std::list<unsigned int> m_constraints_to_update;
59
60 std::vector<Lazy<QCtr, QCtrImplT>> m_qconstraints;
61 std::list<unsigned int> m_qconstraints_to_update;
62
63 std::vector<Lazy<SOSCtr, SOSCtrImplT>> m_sosconstraints;
64 std::list<unsigned int> m_sosconstraints_to_update;
65
66 bool m_is_initialized = false;
67 bool m_is_objective_to_be_updated = true;
68 bool m_is_rhs_to_be_updated = true;
69
70 void update_vars();
71 void update_ctrs();
72 void update_qctrs();
73 void update_sosctrs();
74
75 void lazy_update_objective_sense();
76 void lazy_update_matrix(const Ctr& t_ctr, const Var &t_var, double t_constant);
77 void lazy_update(const Var& t_var);
78 void lazy_update(const Ctr& t_ctr);
79 void lazy_update_objective();
80 void lazy_update_rhs();
81protected:
82 explicit OptimizerWithLazyUpdates(const Model& t_parent);
83
84 void build() final;
85 virtual void hook_build() = 0;
86
87 void write(const std::string &t_name) final;
88 virtual void hook_write(const std::string& t_name) = 0;
89
90 void add(const Var &t_var) final;
91 virtual VarImplT hook_add(const Var& t_var, bool t_add_column) = 0;
92
93 void add(const Ctr &t_ctr) final;
94 virtual CtrImplT hook_add(const Ctr& t_ctr) = 0;
95
96 void add(const QCtr& t_ctr) final;
97 virtual QCtrImplT hook_add(const QCtr& t_ctr) = 0;
98
99 void add(const SOSCtr& t_ctr) final;
100 virtual SOSCtrImplT hook_add(const SOSCtr& t_ctr) = 0;
101
102 virtual void hook_update_objective_sense() = 0;
103 virtual void hook_update_matrix(const Ctr &t_ctr, const Var &t_var, double t_constant) = 0;
104
105 void update() final;
106 virtual void hook_update() = 0;
107 virtual void hook_update(const Var& t_var) = 0;
108 virtual void hook_update(const Ctr& t_ctr) = 0;
109
110 virtual void hook_update_objective() = 0;
111
112 virtual void hook_update_rhs() = 0;
113
114 void remove(const Var& t_var) final;
115 virtual void hook_remove(const Var& t_var) = 0;
116
117 void remove(const Ctr& t_ctr) final;
118 virtual void hook_remove(const Ctr& t_ctr) = 0;
119
120 void remove(const QCtr& t_ctr) final;
121 virtual void hook_remove(const QCtr& t_ctr) = 0;
122
123 void remove(const SOSCtr& t_ctr) final;
124 virtual void hook_remove(const SOSCtr& t_ctr) = 0;
125
126 [[nodiscard]] bool has_lazy(const Var& t_var) const {
127 const unsigned int index = parent().get_var_index(t_var);
128 return index < m_variables.size() && m_variables[index].object().id() == t_var.id();
129 }
130
131 [[nodiscard]] bool has_lazy(const Ctr& t_ctr) const {
132 const unsigned int index = parent().get_ctr_index(t_ctr);
133 return index < m_constraints.size() && m_constraints[index].object().id() == t_ctr.id();
134 }
135
136 [[nodiscard]] bool has_lazy(const QCtr& t_qctr) const {
137 const unsigned int index = parent().get_qctr_index(t_qctr);
138 return index < m_qconstraints.size() && m_qconstraints[index].object().id() == t_qctr.id();
139 }
140
141 auto& lazy(const Var& t_var) { return m_variables[parent().get_var_index(t_var)]; }
142 const auto& lazy(const Var& t_var) const { return m_variables[parent().get_var_index(t_var)]; }
143
144 auto& lazy(const Ctr& t_ctr) { return m_constraints[parent().get_ctr_index(t_ctr)]; }
145 const auto& lazy(const Ctr& t_ctr) const { return m_constraints[parent().get_ctr_index(t_ctr)]; }
146
147 auto& lazy(const QCtr& t_ctr) { return m_qconstraints[parent().get_qctr_index(t_ctr)]; }
148 const auto& lazy(const QCtr& t_ctr) const { return m_qconstraints[parent().get_qctr_index(t_ctr)]; }
149
150 auto& lazy(const SOSCtr& t_ctr) { return m_sosconstraints[parent().get_sosctr_index(t_ctr)]; }
151 const auto& lazy(const SOSCtr& t_ctr) const { return m_sosconstraints[parent().get_sosctr_index(t_ctr)]; }
152
153 auto& lazy_vars() { return m_variables; }
154 const auto& lazy_vars() const { return m_variables; }
155
156 auto& lazy_ctrs() { return m_constraints; }
157 const auto& lazy_ctrs() const { return m_constraints; }
158
159 auto& lazy_qctrs() { return m_qconstraints; }
160 const auto& lazy_qctrs() const { return m_qconstraints; }
161
162 auto& lazy_sosctrs() { return m_sosconstraints; }
163 const auto& lazy_sosctrs() const { return m_sosconstraints; }
164
165 void set_objective_to_be_updated() { m_is_objective_to_be_updated = true; }
166 [[nodiscard]] bool is_objective_to_be_updated() const { return m_is_objective_to_be_updated; }
167 void set_objective_as_updated() { m_is_objective_to_be_updated = false; }
168
169 void set_rhs_to_be_updated() { m_is_rhs_to_be_updated = true; }
170 [[nodiscard]] bool is_rhs_to_be_updated() const { return m_is_rhs_to_be_updated; }
171 void set_rhs_as_updated() { m_is_rhs_to_be_updated = false; }
172
173 void update_obj_sense() override;
174 void update_obj() override;
175 void update_rhs() override;
176 void update_obj_constant() override;
177 void update_mat_coeff(const Ctr &t_ctr, const Var &t_var) override;
178 void update_ctr_type(const Ctr &t_ctr) override;
179 void update_ctr_rhs(const Ctr &t_ctr) override;
180 void update_var_type(const Var &t_var) override;
181 void update_var_lb(const Var &t_var) override;
182 void update_var_ub(const Var &t_var) override;
183 void update_var_obj(const Var &t_var) override;
184public:
185 VarImplT& operator[](const Var& t_var) { return lazy(t_var).impl(); }
186 const VarImplT& operator[](const Var& t_var) const { return lazy(t_var).impl(); }
187
188 CtrImplT& operator[](const Ctr& t_ctr) { return lazy(t_ctr).impl(); }
189 const CtrImplT& operator[](const Ctr& t_ctr) const { return lazy(t_ctr).impl(); }
190};
191
192template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
194 lazy_update(t_var);
195}
196
197template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
199 lazy_update(t_var);
200}
201
202template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
204 lazy_update(t_var);
205}
206
207template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
209 lazy_update(t_var);
210}
211
212template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
214 lazy_update(t_ctr);
215}
216
217template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
219 lazy_update(t_ctr);
220}
221
222template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
224 lazy_update_matrix(t_ctr, t_var, parent().get_mat_coeff(t_ctr, t_var));
225}
226
227template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
229 lazy_update_objective();
230}
231
232template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
234 lazy_update_objective();
235}
236
237template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
239 lazy_update_objective_sense();
240}
241
242
243template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
245 lazy_update_rhs();
246}
247
248template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
250
251}
252
253template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
255
256 const auto& parent = this->parent();
257
258 m_variables.reserve(parent.vars().size());
259 for (const auto& var : parent.vars()) {
260 add(var);
261 }
262
263 m_constraints.reserve(parent.ctrs().size());
264 for (const auto& ctr : parent.ctrs()) {
265 add(ctr);
266 }
267
268 m_qconstraints.reserve(parent.qctrs().size());
269 for (const auto& qctr : parent.qctrs()) {
270 add(qctr);
271 }
272
273 m_sosconstraints.reserve(parent.sosctrs().size());
274 for (const auto& sosctr : parent.sosctrs()) {
275 add(sosctr);
276 }
277
278 set_objective_to_be_updated();
279 set_rhs_to_be_updated();
280
281 hook_build();
282}
283
284template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
286 update();
287 hook_write(t_name);
288}
289
290template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
292
293 update_vars();
294
295 update_ctrs();
296
297 update_qctrs();
298
299 update_sosctrs();
300
301 if (is_objective_to_be_updated()) {
302 hook_update_objective();
303 set_objective_as_updated();
304 }
305
306 if (is_rhs_to_be_updated()) {
307 hook_update_rhs();
308 set_rhs_as_updated();
309 }
310
311 hook_update();
312
313 m_is_initialized = true;
314}
315
316template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
318
319 for (const unsigned int index : m_variables_to_update) {
320
321 if (m_variables[index].has_impl()) {
322 hook_update(m_variables[index].object());
323 } else {
324 auto impl = hook_add(m_variables[index].object(), m_is_initialized);
325 m_variables[index].set_impl(std::move(impl));
326 }
327
328 m_variables[index].set_as_updated();
329 }
330
331 m_variables_to_update.clear();
332
333}
334
335template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
337
338 for (const unsigned int index : m_constraints_to_update) {
339
340 if (m_constraints[index].has_impl()) {
341 hook_update(m_constraints[index].object());
342 } else {
343 auto impl = hook_add(m_constraints[index].object());
344 m_constraints[index].set_impl(std::move(impl));
345 }
346
347 m_constraints[index].set_as_updated();
348
349 }
350
351 m_constraints_to_update.clear();
352
353}
354
355template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
357
358 for (const unsigned int index : m_qconstraints_to_update) {
359
360 if (m_qconstraints[index].has_impl()) {
361 throw Exception("Updating quadratic constraints is not supported.");
362 //hook_update(m_qconstraints[index].object());
363 } else {
364 auto impl = hook_add(m_qconstraints[index].object());
365 m_qconstraints[index].set_impl(std::move(impl));
366 }
367
368 m_qconstraints[index].set_as_updated();
369
370 }
371
372 m_qconstraints_to_update.clear();
373
374}
375
376template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
378
379 for (const unsigned int index : m_sosconstraints_to_update) {
380
381 if (m_sosconstraints[index].has_impl()) {
382 throw Exception("Updating SOS constraints is not supported.");
383 } else {
384 auto impl = hook_add(m_sosconstraints[index].object());
385 m_sosconstraints[index].set_impl(std::move(impl));
386 }
387
388 m_sosconstraints[index].set_as_updated();
389
390 }
391
392 m_sosconstraints_to_update.clear();
393
394}
395
396template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
398 set_rhs_to_be_updated();
399}
400
401template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
403 set_objective_to_be_updated();
404}
405
406template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
408 hook_update_objective_sense();
409}
410
411template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
413 const unsigned int index = parent().get_var_index(t_var);
414 m_variables_to_update.emplace_back(index);
415 m_variables[index].set_as_to_be_updated(m_variables_to_update.begin());
416}
417
418template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
420 const unsigned int index = parent().get_ctr_index(t_ctr);
421 m_constraints_to_update.emplace_back(index);
422 m_constraints[index].set_as_to_be_updated(m_constraints_to_update.begin());
423}
424
425template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
426void idol::OptimizerWithLazyUpdates<VarImplT, CtrImplT, QCtrImplT, SOSCtrImplT>::lazy_update_matrix(const Ctr &t_ctr, const Var &t_var, double t_constant) {
427 hook_update_matrix(t_ctr, t_var, t_constant);
428}
429
430template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
432
433 if (m_is_initialized) {
434 update_vars();
435 }
436
437 const unsigned int index = parent().get_ctr_index(t_ctr);
438 m_constraints_to_update.emplace_back(index);
439 m_constraints.emplace_back(t_ctr, m_constraints_to_update.begin());
440}
441
442template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
444
445 if (m_is_initialized) {
446 update_vars();
447 }
448
449 const unsigned int index = parent().get_qctr_index(t_ctr);
450 m_qconstraints_to_update.emplace_back(index);
451 m_qconstraints.emplace_back(t_ctr, m_qconstraints_to_update.begin());
452
453}
454
455template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
457
458 if (m_is_initialized) {
459 update_vars();
460 }
461
462 const unsigned int index = parent().get_sosctr_index(t_ctr);
463 m_sosconstraints_to_update.emplace_back(index);
464 m_sosconstraints.emplace_back(t_ctr, m_sosconstraints_to_update.begin());
465
466}
467
468template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
470
471 if (m_is_initialized) {
472 update_ctrs();
473 }
474
475 const unsigned int index = parent().get_var_index(t_var);
476 m_variables_to_update.emplace_back(index);
477 m_variables.emplace_back(t_var, m_variables_to_update.begin());
478}
479
480template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
482
483 update();
484
485 const unsigned index = parent().get_var_index(t_var);
486
487 if (m_variables[index].has_impl()) {
488 hook_remove(m_variables[index].object());
489 }
490
491 m_variables[index] = std::move(m_variables.back());
492 m_variables.pop_back();
493}
494
495template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
497
498 update();
499
500 const unsigned index = parent().get_ctr_index(t_ctr);
501
502 if (m_constraints[index].has_impl()) {
503 hook_remove(m_constraints[index].object());
504 }
505
506 m_constraints[index] = std::move(m_constraints.back());
507 m_constraints.pop_back();
508}
509
510template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
512
513 update();
514
515 const unsigned index = parent().get_qctr_index(t_ctr);
516
517 if (m_qconstraints[index].has_impl()) {
518 hook_remove(m_qconstraints[index].object());
519 }
520
521 m_qconstraints[index] = std::move(m_qconstraints.back());
522 m_qconstraints.pop_back();
523}
524
525template<class VarImplT, class CtrImplT, class QCtrImplT, class SOSCtrImplT>
527
528 update();
529
530 const unsigned index = parent().get_sosctr_index(t_ctr);
531
532 if (m_sosconstraints[index].has_impl()) {
533 hook_remove(m_sosconstraints[index].object());
534 }
535
536 m_sosconstraints[index] = std::move(m_sosconstraints.back());
537 m_sosconstraints.pop_back();
538}
539
540#endif //IDOL_OPTIMIZERWITHLAZYUPDATES_H
unsigned int id() const
Definition Object.h:60