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
308template<class T, unsigned int N>
309void idol::Model::add_vector(const Vector<T, N> &t_vector) {
310 if constexpr (N == 1) {
311 for (const auto& x : t_vector) {
312 add(x);
313 }
314 } else {
315 for (const auto& x : t_vector) {
316 add_vector<T, N - 1>(x);
317 }
318 }
319}
320
321template<unsigned int N>
322idol::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) {
323 auto result = Var::make_vector(m_env, t_dim, t_lb, t_ub, t_type, t_obj, t_name);
324 add_vector<Var, N>(result);
325 return result;
326}
327
328template<unsigned int N>
329idol::Vector<idol::Ctr, N> idol::Model::add_ctrs(Dim<N> t_dim, CtrType t_type, double t_rhs, const std::string &t_name) {
330 auto result = Ctr::make_vector(m_env, t_dim, t_type, t_rhs, t_name);
331 add_vector<Ctr, N>(result);
332 return result;
333}
334
335namespace idol {
336
337 static auto save_primal(const Model &t_original_model, const Model &t_model) {
338
339 PrimalPoint result;
340
341 const auto status = t_model.get_status();
342 const auto reason = t_model.get_reason();
343
344 if (status != Optimal && status != Feasible && status != SubOptimal) {
345 throw Exception("Primal values not available.");
346 }
347
348 result.set_status(status);
349 result.set_reason(reason);
350
351 result.set_objective_value(t_model.get_best_obj());
352
353 for (const auto &var: t_original_model.vars()) {
354 const double value = t_model.get_var_primal(var);
355 result.set(var, value);
356 }
357
358 return result;
359
360 }
361
362 static auto save_primal(const Model &t_original_model) {
363 return save_primal(t_original_model, t_original_model);
364 }
365
366 static auto save_ray(const Model &t_original_model, const Model &t_model) {
367
368 PrimalPoint result;
369
370 const auto status = t_model.get_status();
371 const auto reason = t_model.get_reason();
372
373 if (status != Unbounded) {
374 throw Exception("Ray not available.");
375 }
376
377 result.set_status(status);
378 result.set_reason(reason);
379
380 result.set_objective_value(-Inf);
381
382 for (const auto &var: t_original_model.vars()) {
383 const double value = t_model.get_var_ray(var);
384 result.set(var, value);
385 }
386
387 return result;
388
389 }
390
391 static auto save_ray(const Model &t_original_model) {
392 return save_ray(t_original_model, t_original_model);
393 }
394
395 static auto save_dual(const Model &t_original_model, const Model &t_model) {
396
397 DualPoint result;
398
399 const auto status = t_model.get_status();
400 const auto reason = t_model.get_reason();
401
402 if (status != Optimal && status != Feasible) {
403 throw Exception("Dual values not available.");
404 }
405
406 result.set_status(status);
407 result.set_reason(reason);
408
409 result.set_objective_value(t_model.get_best_bound());
410
411 for (const auto &ctr: t_original_model.ctrs()) {
412 const double value = t_model.get_ctr_dual(ctr);
413 result.set(ctr, value);
414 }
415
416 return result;
417
418 }
419
420 static auto save_dual(const Model &t_original_model) {
421 return save_dual(t_original_model, t_original_model);
422 }
423
424 static auto save_farkas(const Model &t_original_model, const Model &t_model) {
425
426 DualPoint result;
427
428 const auto status = t_model.get_status();
429 const auto reason = t_model.get_reason();
430
431 if (status != Infeasible) {
432 throw Exception("Farkas certificate not available.");
433 }
434
435 result.set_status(status);
436 result.set_reason(reason);
437
438 result.set_objective_value(+Inf);
439
440 for (const auto &ctr: t_original_model.ctrs()) {
441 const double value = t_model.get_ctr_farkas(ctr);
442 result.set(ctr, value);
443 }
444
445 return result;
446
447 }
448
449 static auto save_farkas(const Model &t_original_model) {
450 return save_farkas(t_original_model, t_original_model);
451 }
452
453 static auto save_reduced_cost(const Model &t_original_model, const Model &t_model) {
454
455 PrimalPoint result;
456
457 const auto status = t_model.get_status();
458 const auto reason = t_model.get_reason();
459
460 if (status != Optimal && status != Feasible && status != SubOptimal) {
461 throw Exception("Reduced costs not available.");
462 }
463
464 result.set_status(status);
465 result.set_reason(reason);
466
467 result.set_objective_value(t_model.get_best_obj());
468
469 for (const auto &var: t_original_model.vars()) {
470 const double value = t_model.get_var_reduced_cost(var);
471 result.set(var, value);
472 }
473
474 return result;
475
476 }
477
478 static auto save_reduced_cost(const Model &t_original_model) {
479 return save_reduced_cost(t_original_model, t_original_model);
480 }
481
482}
483
484namespace idol {
485
486 static std::ostream &operator<<(std::ostream &t_os, const idol::Model &t_model) {
487
488 using namespace idol;
489
490 if (t_model.storage() == Model::Storage::ColumnOriented) {
491 std::cerr << "Warning: print a column-oriented model leads to the generation of a minor representation. "
492 "This operation can be slow and memory-consuming." << std::endl;
493 }
494
495 LimitedWidthStream stream(t_os, 120);
496
497 if (t_model.get_obj_sense() == Minimize) {
498 stream << "Minimize";
499 } else {
500 stream << "Maximize";
501 }
502
503 stream << std::endl << t_model.get_obj_expr() << std::endl << "Subject To" << std::endl;
504
505 for (const auto &ctr: t_model.ctrs()) {
506
507 const auto linear = t_model.get_ctr_row(ctr);
508 const double rhs = t_model.get_ctr_rhs(ctr);
509 const auto type = t_model.get_ctr_type(ctr);
510
511 stream << ctr << ": ";
512
513 stream << linear;
514
515 switch (type) {
516 case LessOrEqual:
517 stream << " <= ";
518 break;
519 case Equal:
520 stream << " = ";
521 break;
522 case GreaterOrEqual:
523 stream << " >= ";
524 break;
525 default:
526 stream << " ?undefined? ";
527 }
528
529 stream << rhs << std::endl;
530 }
531
532 for (const auto& qctr : t_model.qctrs()) {
533 const auto& expr = t_model.get_qctr_expr(qctr);
534 const auto type = t_model.get_qctr_type(qctr);
535
536 stream << qctr << ": ";
537
538 stream << expr;
539
540 switch (type) {
541 case LessOrEqual:
542 stream << " <= 0";
543 break;
544 case Equal:
545 stream << " = 0";
546 break;
547 case GreaterOrEqual:
548 stream << " >= 0";
549 break;
550 default:
551 stream << " ?undefined? ";
552 }
553
554 stream << std::endl;
555 }
556
557 std::list<Var> generals, binaries;
558
559 stream << "Bounds\n";
560 for (const auto &var: t_model.vars()) {
561
562 const double lb = t_model.get_var_lb(var);
563 const double ub = t_model.get_var_ub(var);
564 const int type = t_model.get_var_type(var);
565
566 if (!is_neg_inf(lb) && !is_pos_inf(ub)) {
567 stream << lb << " <= " << var << " <= " << ub;
568 } else if (!is_pos_inf(ub)) {
569 stream << var << " <= " << ub;
570 } else if (!is_neg_inf(lb)) {
571 stream << var << " >= " << lb;
572 } else {
573 stream << var;
574 }
575
576 if (type == Binary) {
577 binaries.emplace_back(var);
578 } else if (type == Integer) {
579 generals.emplace_back(var);
580 }
581
582 stream << std::endl;
583 }
584
585 if (!generals.empty()) {
586 stream << "Generals\n";
587 for (const auto& var : generals) {
588 stream << var.name() << std::endl;
589 }
590 }
591
592 if (!binaries.empty()) {
593 stream << "Binaries\n";
594 for (const auto& var : binaries) {
595 stream << '\t' << var.name() << std::endl;
596 }
597 }
598
599 if (t_model.sosctrs().size() > 0) {
600 stream << "SOS\n";
601 for (const auto& sos : t_model.sosctrs()) {
602 stream << sos << ": ";
603 const auto& vars = t_model.get_sosctr_vars(sos);
604 const auto& weights = t_model.get_sosctr_weights(sos);
605 for (unsigned int i = 0; i < vars.size(); ++i) {
606 stream << vars[i] << " " << weights[i] << " ";
607 }
608 stream << std::endl;
609 }
610 }
611
612 return t_os;
613 }
614
615}
616
617#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