Loading...
Searching...
No Matches
Model.h
1//
2// Created by henri on 27/01/23.
3//
4
5#ifndef IDOL_MODEL_H
6#define IDOL_MODEL_H
7
8#include <vector>
9#include <string>
10#include <functional>
11
12#include "idol/general/utils/Vector.h"
13
14#include "idol/mixed-integer/modeling/constraints/CtrVersion.h"
15#include "idol/mixed-integer/modeling/variables/VarVersion.h"
16#include "idol/mixed-integer/modeling/expressions/QuadExpr.h"
17#include "idol/general/utils/Point.h"
18
19#include "idol/mixed-integer/modeling/constraints/Ctr.h"
20#include "idol/mixed-integer/modeling/variables/Var.h"
21
22#include "idol/general/optimizers/Optimizer.h"
23#include "idol/general/optimizers/OptimizerFactory.h"
24
25#include "idol/general/optimizers/Timer.h"
26#include "idol/general/utils/LimitedWidthStream.h"
27#include "idol/mixed-integer/modeling/constraints/QCtr.h"
28#include "idol/mixed-integer/modeling/constraints/SOSCtr.h"
29
30namespace idol {
31 static const unsigned int MasterId = std::numeric_limits<unsigned int>::max();
32
33 class Env;
34 class TempCtr;
35
36 class Model;
37
38}
39
44public:
45 enum Storage { ColumnOriented, RowOriented, Both };
46private:
47 Env& m_env;
48 const unsigned int m_id;
49 bool m_has_been_moved = false;
50
51 ObjectiveSense m_sense = Minimize;
52
53 QuadExpr<Var> m_objective;
54 LinExpr<Ctr> m_rhs;
55 std::vector<Var> m_variables;
56 std::vector<Ctr> m_constraints;
57 std::vector<QCtr> m_qconstraints;
58 std::vector<SOSCtr> m_sosconstraints;
59
60 Storage m_storage;
61 mutable bool m_has_minor_representation = false;
62
63 std::unique_ptr<Optimizer> m_optimizer;
64 std::unique_ptr<OptimizerFactory> m_optimizer_factory;
65
66 void throw_if_no_optimizer() const { if (!m_optimizer) { throw Exception("No optimizer was found."); } }
67
68 Model(const Model& t_src);
69
70 template<class T> void throw_if_unknown_object(const LinExpr<T>& t_expr);
71 template<class T> void throw_if_unknown_object(const QuadExpr<T>& t_expr);
72 void add_column_to_rows(const Var& t_var);
73 void add_row_to_columns(const Ctr& t_ctr);
74 void build_row(const Ctr& t_ctr);
75 void build_column(const Var& t_var);
76 void build_rows();
77 void build_columns();
78
79 bool column_storage_matters() const;
80 bool row_storage_matters() const;
81public:
82 explicit Model(Env& t_env, Storage t_storage = Both);
83
84 Model(Model&&) noexcept;
85
86 Model& operator=(const Model&) = delete;
87 Model& operator=(Model&&) noexcept = delete;
88
89 ~Model();
90
91 Var add_var(double t_lb, double t_ub, VarType t_type, double t_obj = 0., std::string t_name = "");
92
93 Var add_var(double t_lb, double t_ub, VarType t_type, double t_obj, LinExpr<Ctr> t_column, std::string t_name = "");
94
95 template<unsigned int N> Vector<Var, N> add_vars(Dim<N> t_dim, double t_lb, double t_ub, VarType t_type, double t_obj = 0., const std::string& t_name = "");
96
97 void add(const Var& t_var);
98
99 void add(const Var& t_var, TempVar t_temp_var);
100
101 [[nodiscard]] bool has(const Var& t_var) const;
102
103 void remove(const Var& t_var);
104
105 [[nodiscard]] ConstIteratorForward<std::vector<Var>> vars() const { return m_variables; }
106
107 Ctr add_ctr(TempCtr t_temp_ctr, std::string t_name = "");
108
109 Ctr add_ctr(LinExpr<Var>&& t_lhs, CtrType t_type, double t_rhs, std::string t_name = "");
110
111 template<unsigned int N> Vector<Ctr, N> add_ctrs(Dim<N> t_dim, CtrType t_type, double t_rhs, const std::string& t_name = "");
112
113 void add(const Ctr& t_ctr);
114
115 void add(const Ctr &t_ctr, TempCtr t_temp_ctr);
116
117 [[nodiscard]] bool has(const Ctr& t_ctr) const;
118
119 void remove(const Ctr& t_ctr);
120
121 [[nodiscard]] ConstIteratorForward<std::vector<Ctr>> ctrs() const { return m_constraints; }
122
123 QCtr add_qctr(TempQCtr t_temp_ctr, std::string t_name = "");
124
125 QCtr add_qctr(QuadExpr<Var>&& t_expr, CtrType t_type, std::string t_name = "");
126
127 template<unsigned int N> Vector<QCtr, N> add_qctrs(Dim<N> t_dim, CtrType t_type, const std::string& t_name = "");
128
129 void add(const QCtr& t_ctr);
130
131 void add(const QCtr &t_ctr, TempQCtr t_temp_ctr);
132
133 [[nodiscard]] bool has(const QCtr& t_ctr) const;
134
135 void remove(const QCtr& t_ctr);
136
137 [[nodiscard]] ConstIteratorForward<std::vector<QCtr>> qctrs() const { return m_qconstraints; }
138
139 SOSCtr add_sosctr(bool t_is_sos1, std::vector<Var> t_vars, std::vector<double> t_weights, std::string t_name = "");
140
141 void add(const SOSCtr& t_ctr, bool t_is_sos1, const std::vector<Var>& t_vars, const std::vector<double>& t_weights);
142
143 void add(const SOSCtr& t_ctr);
144
145 void remove(const SOSCtr& t_ctr);
146
147 [[nodiscard]] ConstIteratorForward<std::vector<SOSCtr>> sosctrs() const { return m_sosconstraints; }
148
149 [[nodiscard]] bool has(const SOSCtr& t_ctr) const;
150
151 [[nodiscard]] unsigned int id() const { return m_id; }
152
153 [[nodiscard]] Model* clone() const;
154
155 [[nodiscard]] Model copy() const;
156
157 void reserve_vars(unsigned int t_size);
158
159 void reserve_ctrs(unsigned int t_size);
160
161 void reserve_qctrs(unsigned int t_size);
162
163 void reserve_sos_ctrs(unsigned int t_size);
164
165 [[nodiscard]] Env& env() const { return const_cast<Model*>(this)->m_env; }
166
167 void use(const OptimizerFactory& t_optimizer_factory);
168
169 [[nodiscard]] bool has_optimizer() const;
170
171 [[nodiscard]] bool has_optimizer_factory() const { return bool(m_optimizer_factory); }
172
173 [[nodiscard]] const OptimizerFactory& optimizer_factory() const { return *m_optimizer_factory; }
174
175 void unuse();
176
177 template<class T, unsigned int N> void add_vector(const Vector<T, N>& t_vector);
178
179 Optimizer& optimizer() { throw_if_no_optimizer(); return *m_optimizer; }
180
181 [[nodiscard]] const Optimizer& optimizer() const { throw_if_no_optimizer(); return *m_optimizer; }
182
183 void optimize();
184
185 void write(const std::string& t_name);
186
187 void update();
188
189 [[nodiscard]] ObjectiveSense get_obj_sense() const;
190
191 [[nodiscard]] const QuadExpr<Var>& get_obj_expr() const;
192
193 [[nodiscard]] const LinExpr<Ctr>& get_rhs_expr() const;
194
195 [[nodiscard]] double get_mat_coeff(const Ctr& t_ctr, const Var& t_var) const;
196
197 [[nodiscard]] SolutionStatus get_status() const;
198
199 [[nodiscard]] SolutionReason get_reason() const;
200
201 [[nodiscard]] double get_best_obj() const;
202
203 [[nodiscard]] double get_best_bound() const;
204
205 void set_obj_sense(ObjectiveSense t_value);
206
207 void set_obj_expr(const QuadExpr<Var>& t_objective);
208
209 void set_obj_expr(QuadExpr<Var>&& t_objective);
210
211 void set_rhs_expr(LinExpr<Ctr>&& t_rhs);
212
213 void set_rhs_expr(const LinExpr<Ctr>& t_rhs);
214
215 void set_obj_const(double t_constant);
216
217 void set_mat_coeff(const Ctr& t_ctr, const Var& t_var, double t_coeff);
218
219 [[nodiscard]] QCtr get_qctr_by_index(unsigned int t_index) const;
220
221 [[nodiscard]] Ctr get_ctr_by_index(unsigned int t_index) const;
222
223 [[nodiscard]] Var get_var_by_index(unsigned int t_index) const;
224
225 [[nodiscard]] SOSCtr get_sosctr_by_index(unsigned int t_index) const;
226
227 [[nodiscard]] unsigned int get_ctr_index(const Ctr& t_ctr) const;
228
229 [[nodiscard]] unsigned int get_qctr_index(const QCtr& tctr) const;
230
231 [[nodiscard]] unsigned int get_sosctr_index(const SOSCtr& t_ctr) const;
232
233 [[nodiscard]] CtrType get_ctr_type(const Ctr& t_ctr) const;
234
235 double get_ctr_rhs(const Ctr& t_ctr) const;
236
237 [[nodiscard]] const LinExpr<Var>& get_ctr_row(const Ctr& t_ctr) const;
238
239 const QuadExpr<Var>& get_qctr_expr(const QCtr& t_ctr) const;
240
241 CtrType get_qctr_type(const QCtr& t_ctr) const;
242
243 [[nodiscard]] double get_ctr_dual(const Ctr& t_ctr) const;
244
245 [[nodiscard]] double get_ctr_farkas(const Ctr& t_ctr) const;
246
247 void set_ctr_rhs(const Ctr& t_ctr, double t_rhs);
248
249 void set_ctr_type(const Ctr& t_ctr, CtrType t_type);
250
251 void set_ctr_row(const Ctr& t_ctr, const LinExpr<Var>& t_row);
252
253 void set_ctr_row(const Ctr& t_ctr, LinExpr<Var>&& t_row);
254
255 [[nodiscard]] unsigned int get_var_index(const Var& t_var) const;
256
257 [[nodiscard]] VarType get_var_type(const Var& t_var) const;
258
259 [[nodiscard]] double get_var_lb(const Var& t_var) const;
260
261 [[nodiscard]] double get_var_ub(const Var& t_var) const;
262
263 [[nodiscard]] double get_var_primal(const Var& t_var) const;
264
265 [[nodiscard]] double get_var_reduced_cost(const Var& t_var) const;
266
267 [[nodiscard]] double get_var_ray(const Var& t_var) const;
268
269 [[nodiscard]] const LinExpr<Ctr>& get_var_column(const Var& t_var) const;
270
271 [[nodiscard]] double get_var_obj(const Var& t_var) const;
272
273 void set_var_type(const Var& t_var, VarType t_type);
274
275 void set_var_lb(const Var& t_var, double t_lb);
276
277 void set_var_ub(const Var& t_var, double t_ub);
278
279 void set_var_obj(const Var& t_var, double t_obj);
280
281 void set_var_column(const Var& t_var, const LinExpr<Ctr>& t_column);
282
283 void set_var_column(const Var& t_var, LinExpr<Ctr>&& t_column);
284
285 const std::vector<Var>& get_sosctr_vars(const SOSCtr& t_ctr) const;
286
287 const std::vector<double>& get_sosctr_weights(const SOSCtr& t_ctr) const;
288
289 [[nodiscard]] bool is_sos1(const SOSCtr& t_ctr) const;
290
291 [[nodiscard]] unsigned int get_n_solutions() const;
292
293 [[nodiscard]] unsigned int get_solution_index() const;
294
295 void set_solution_index(unsigned int t_index);
296
297 void dump(std::ostream& t_os = std::cout) const;
298
299 Storage storage() const { return m_storage; }
300
301 void set_storage(Storage t_storage, bool t_reset_minor_representation = false);
302
303 void reset_minor_representation();
304
305 static Model read_from_file(Env& t_env, const std::string& t_filename);
306
307 void print_statistics(std::ostream& t_os = std::cout) const;
308};
309
310template<class T, unsigned int N>
311void idol::Model::add_vector(const Vector<T, N> &t_vector) {
312 if constexpr (N == 1) {
313 for (const auto& x : t_vector) {
314 add(x);
315 }
316 } else {
317 for (const auto& x : t_vector) {
318 add_vector<T, N - 1>(x);
319 }
320 }
321}
322
323template<unsigned int N>
324idol::Vector<idol::Var, N> idol::Model::add_vars(Dim<N> t_dim, double t_lb, double t_ub, VarType t_type, double t_obj, const std::string& t_name) {
325 auto result = Var::make_vector(m_env, t_dim, t_lb, t_ub, t_type, t_obj, t_name);
326 add_vector<Var, N>(result);
327 return result;
328}
329
330template<unsigned int N>
331idol::Vector<idol::Ctr, N> idol::Model::add_ctrs(Dim<N> t_dim, CtrType t_type, double t_rhs, const std::string &t_name) {
332 auto result = Ctr::make_vector(m_env, t_dim, t_type, t_rhs, t_name);
333 add_vector<Ctr, N>(result);
334 return result;
335}
336
337namespace idol {
338
339 static auto save_primal(const Model &t_original_model, const Model &t_model) {
340
341 PrimalPoint result;
342
343 const auto status = t_model.get_status();
344 const auto reason = t_model.get_reason();
345
346 if (status != Optimal && status != Feasible && status != SubOptimal) {
347 throw Exception("Primal values not available.");
348 }
349
350 result.set_status(status);
351 result.set_reason(reason);
352
353 result.set_objective_value(t_model.get_best_obj());
354
355 for (const auto &var: t_original_model.vars()) {
356 const double value = t_model.get_var_primal(var);
357 result.set(var, value);
358 }
359
360 return result;
361
362 }
363
364 static auto save_primal(const Model &t_original_model) {
365 return save_primal(t_original_model, t_original_model);
366 }
367
368 static auto save_ray(const Model &t_original_model, const Model &t_model) {
369
370 PrimalPoint result;
371
372 const auto status = t_model.get_status();
373 const auto reason = t_model.get_reason();
374
375 if (status != Unbounded) {
376 throw Exception("Ray not available.");
377 }
378
379 result.set_status(status);
380 result.set_reason(reason);
381
382 result.set_objective_value(-Inf);
383
384 for (const auto &var: t_original_model.vars()) {
385 const double value = t_model.get_var_ray(var);
386 result.set(var, value);
387 }
388
389 return result;
390
391 }
392
393 static auto save_ray(const Model &t_original_model) {
394 return save_ray(t_original_model, t_original_model);
395 }
396
397 static auto save_dual(const Model &t_original_model, const Model &t_model) {
398
399 DualPoint result;
400
401 const auto status = t_model.get_status();
402 const auto reason = t_model.get_reason();
403
404 if (status != Optimal && status != Feasible) {
405 throw Exception("Dual values not available.");
406 }
407
408 result.set_status(status);
409 result.set_reason(reason);
410
411 result.set_objective_value(t_model.get_best_bound());
412
413 for (const auto &ctr: t_original_model.ctrs()) {
414 const double value = t_model.get_ctr_dual(ctr);
415 result.set(ctr, value);
416 }
417
418 return result;
419
420 }
421
422 static auto save_dual(const Model &t_original_model) {
423 return save_dual(t_original_model, t_original_model);
424 }
425
426 static auto save_farkas(const Model &t_original_model, const Model &t_model) {
427
428 DualPoint result;
429
430 const auto status = t_model.get_status();
431 const auto reason = t_model.get_reason();
432
433 if (status != Infeasible) {
434 throw Exception("Farkas certificate not available.");
435 }
436
437 result.set_status(status);
438 result.set_reason(reason);
439
440 result.set_objective_value(+Inf);
441
442 for (const auto &ctr: t_original_model.ctrs()) {
443 const double value = t_model.get_ctr_farkas(ctr);
444 result.set(ctr, value);
445 }
446
447 return result;
448
449 }
450
451 static auto save_farkas(const Model &t_original_model) {
452 return save_farkas(t_original_model, t_original_model);
453 }
454
455 static auto save_reduced_cost(const Model &t_original_model, const Model &t_model) {
456
457 PrimalPoint result;
458
459 const auto status = t_model.get_status();
460 const auto reason = t_model.get_reason();
461
462 if (status != Optimal && status != Feasible && status != SubOptimal) {
463 throw Exception("Reduced costs not available.");
464 }
465
466 result.set_status(status);
467 result.set_reason(reason);
468
469 result.set_objective_value(t_model.get_best_obj());
470
471 for (const auto &var: t_original_model.vars()) {
472 const double value = t_model.get_var_reduced_cost(var);
473 result.set(var, value);
474 }
475
476 return result;
477
478 }
479
480 static auto save_reduced_cost(const Model &t_original_model) {
481 return save_reduced_cost(t_original_model, t_original_model);
482 }
483
484}
485
486namespace idol {
487
488 static std::ostream &operator<<(std::ostream &t_os, const idol::Model &t_model) {
489
490 using namespace idol;
491
492 if (t_model.storage() == Model::Storage::ColumnOriented) {
493 std::cerr << "Warning: print a column-oriented model leads to the generation of a minor representation. "
494 "This operation can be slow and memory-consuming." << std::endl;
495 }
496
497 LimitedWidthStream stream(t_os, 120);
498
499 if (t_model.get_obj_sense() == Minimize) {
500 stream << "Minimize";
501 } else {
502 stream << "Maximize";
503 }
504
505 stream << std::endl << t_model.get_obj_expr() << std::endl << "Subject To" << std::endl;
506
507 for (const auto &ctr: t_model.ctrs()) {
508
509 const auto linear = t_model.get_ctr_row(ctr);
510 const double rhs = t_model.get_ctr_rhs(ctr);
511 const auto type = t_model.get_ctr_type(ctr);
512
513 stream << ctr << ": ";
514
515 stream << linear;
516
517 switch (type) {
518 case LessOrEqual:
519 stream << " <= ";
520 break;
521 case Equal:
522 stream << " = ";
523 break;
524 case GreaterOrEqual:
525 stream << " >= ";
526 break;
527 default:
528 stream << " ?undefined? ";
529 }
530
531 stream << rhs << std::endl;
532 }
533
534 for (const auto& qctr : t_model.qctrs()) {
535 const auto& expr = t_model.get_qctr_expr(qctr);
536 const auto type = t_model.get_qctr_type(qctr);
537
538 stream << qctr << ": ";
539
540 stream << expr;
541
542 switch (type) {
543 case LessOrEqual:
544 stream << " <= 0";
545 break;
546 case Equal:
547 stream << " = 0";
548 break;
549 case GreaterOrEqual:
550 stream << " >= 0";
551 break;
552 default:
553 stream << " ?undefined? ";
554 }
555
556 stream << std::endl;
557 }
558
559 std::list<Var> generals, binaries;
560
561 stream << "Bounds\n";
562 for (const auto &var: t_model.vars()) {
563
564 const double lb = t_model.get_var_lb(var);
565 const double ub = t_model.get_var_ub(var);
566 const int type = t_model.get_var_type(var);
567
568 if (!is_neg_inf(lb) && !is_pos_inf(ub)) {
569 stream << lb << " <= " << var << " <= " << ub;
570 } else if (!is_pos_inf(ub)) {
571 stream << var << " <= " << ub;
572 } else if (!is_neg_inf(lb)) {
573 stream << var << " >= " << lb;
574 } else {
575 stream << var;
576 }
577
578 if (type == Binary) {
579 binaries.emplace_back(var);
580 } else if (type == Integer) {
581 generals.emplace_back(var);
582 }
583
584 stream << std::endl;
585 }
586
587 if (!generals.empty()) {
588 stream << "Generals\n";
589 for (const auto& var : generals) {
590 stream << var.name() << std::endl;
591 }
592 }
593
594 if (!binaries.empty()) {
595 stream << "Binaries\n";
596 for (const auto& var : binaries) {
597 stream << '\t' << var.name() << std::endl;
598 }
599 }
600
601 if (t_model.sosctrs().size() > 0) {
602 stream << "SOS\n";
603 for (const auto& sos : t_model.sosctrs()) {
604 stream << sos << ": ";
605 const auto& vars = t_model.get_sosctr_vars(sos);
606 const auto& weights = t_model.get_sosctr_weights(sos);
607 for (unsigned int i = 0; i < vars.size(); ++i) {
608 stream << vars[i] << " " << weights[i] << " ";
609 }
610 stream << std::endl;
611 }
612 }
613
614 return t_os;
615 }
616
617}
618
619#endif //IDOL_MODEL_H
static Vector< Ctr, N - I > make_vector(Env &t_env, const Dim< N > &t_dim, CtrType t_type, double t_constant, const std::string &t_name="")
Definition Ctr.h:92
static Vector< Var, N - I > make_vector(Env &t_env, const Dim< N > &t_dim, double t_lb, double t_ub, VarType t_type, double t_obj, const std::string &t_name="")
Definition Var.h:104