12#include "idol/general/utils/Vector.h"
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"
19#include "idol/mixed-integer/modeling/constraints/Ctr.h"
20#include "idol/mixed-integer/modeling/variables/Var.h"
22#include "idol/general/optimizers/Optimizer.h"
23#include "idol/general/optimizers/OptimizerFactory.h"
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"
31 static const unsigned int MasterId = std::numeric_limits<unsigned int>::max();
45 enum Storage { ColumnOriented, RowOriented, Both };
48 const unsigned int m_id;
49 bool m_has_been_moved =
false;
51 ObjectiveSense m_sense = Minimize;
55 std::vector<Var> m_variables;
56 std::vector<Ctr> m_constraints;
57 std::vector<QCtr> m_qconstraints;
58 std::vector<SOSCtr> m_sosconstraints;
61 mutable bool m_has_minor_representation =
false;
63 std::unique_ptr<Optimizer> m_optimizer;
64 std::unique_ptr<OptimizerFactory> m_optimizer_factory;
66 void throw_if_no_optimizer()
const {
if (!m_optimizer) {
throw Exception(
"No optimizer was found."); } }
68 Model(
const Model& t_src);
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);
79 bool column_storage_matters()
const;
80 bool row_storage_matters()
const;
82 explicit Model(
Env& t_env, Storage t_storage = Both);
84 Model(Model&&)
noexcept;
86 Model& operator=(
const Model&) =
delete;
87 Model& operator=(Model&&)
noexcept =
delete;
91 Var add_var(
double t_lb,
double t_ub, VarType t_type,
double t_obj = 0., std::string t_name =
"");
93 Var add_var(
double t_lb,
double t_ub, VarType t_type,
double t_obj,
LinExpr<Ctr> t_column, std::string t_name =
"");
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 =
"");
97 void add(
const Var& t_var);
99 void add(
const Var& t_var,
TempVar t_temp_var);
101 [[nodiscard]]
bool has(
const Var& t_var)
const;
103 void remove(
const Var& t_var);
107 Ctr add_ctr(
TempCtr t_temp_ctr, std::string t_name =
"");
109 Ctr add_ctr(
LinExpr<Var>&& t_lhs, CtrType t_type,
double t_rhs, std::string t_name =
"");
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 =
"");
113 void add(
const Ctr& t_ctr);
115 void add(
const Ctr &t_ctr,
TempCtr t_temp_ctr);
117 [[nodiscard]]
bool has(
const Ctr& t_ctr)
const;
119 void remove(
const Ctr& t_ctr);
123 QCtr add_qctr(
TempQCtr t_temp_ctr, std::string t_name =
"");
127 template<
unsigned int N> Vector<QCtr, N> add_qctrs(
Dim<N> t_dim, CtrType t_type,
const std::string& t_name =
"");
129 void add(
const QCtr& t_ctr);
133 [[nodiscard]]
bool has(
const QCtr& t_ctr)
const;
135 void remove(
const QCtr& t_ctr);
139 SOSCtr add_sosctr(
bool t_is_sos1, std::vector<Var> t_vars, std::vector<double> t_weights, std::string t_name =
"");
141 void add(
const SOSCtr& t_ctr,
bool t_is_sos1,
const std::vector<Var>& t_vars,
const std::vector<double>& t_weights);
143 void add(
const SOSCtr& t_ctr);
145 void remove(
const SOSCtr& t_ctr);
149 [[nodiscard]]
bool has(
const SOSCtr& t_ctr)
const;
151 [[nodiscard]]
unsigned int id()
const {
return m_id; }
153 [[nodiscard]] Model* clone()
const;
155 [[nodiscard]] Model copy()
const;
157 void reserve_vars(
unsigned int t_size);
159 void reserve_ctrs(
unsigned int t_size);
161 void reserve_qctrs(
unsigned int t_size);
163 void reserve_sos_ctrs(
unsigned int t_size);
165 [[nodiscard]]
Env& env()
const {
return const_cast<Model*
>(
this)->m_env; }
169 [[nodiscard]]
bool has_optimizer()
const;
171 [[nodiscard]]
bool has_optimizer_factory()
const {
return bool(m_optimizer_factory); }
173 [[nodiscard]]
const OptimizerFactory& optimizer_factory()
const {
return *m_optimizer_factory; }
177 template<
class T,
unsigned int N>
void add_vector(
const Vector<T, N>& t_vector);
179 Optimizer& optimizer() { throw_if_no_optimizer();
return *m_optimizer; }
181 [[nodiscard]]
const Optimizer& optimizer()
const { throw_if_no_optimizer();
return *m_optimizer; }
185 void write(
const std::string& t_name);
189 [[nodiscard]] ObjectiveSense get_obj_sense()
const;
195 [[nodiscard]]
double get_mat_coeff(
const Ctr& t_ctr,
const Var& t_var)
const;
197 [[nodiscard]] SolutionStatus get_status()
const;
199 [[nodiscard]] SolutionReason get_reason()
const;
201 [[nodiscard]]
double get_best_obj()
const;
203 [[nodiscard]]
double get_best_bound()
const;
205 void set_obj_sense(ObjectiveSense t_value);
215 void set_obj_const(
double t_constant);
217 void set_mat_coeff(
const Ctr& t_ctr,
const Var& t_var,
double t_coeff);
219 [[nodiscard]]
QCtr get_qctr_by_index(
unsigned int t_index)
const;
221 [[nodiscard]]
Ctr get_ctr_by_index(
unsigned int t_index)
const;
223 [[nodiscard]]
Var get_var_by_index(
unsigned int t_index)
const;
225 [[nodiscard]]
SOSCtr get_sosctr_by_index(
unsigned int t_index)
const;
227 [[nodiscard]]
unsigned int get_ctr_index(
const Ctr& t_ctr)
const;
229 [[nodiscard]]
unsigned int get_qctr_index(
const QCtr& tctr)
const;
231 [[nodiscard]]
unsigned int get_sosctr_index(
const SOSCtr& t_ctr)
const;
233 [[nodiscard]] CtrType get_ctr_type(
const Ctr& t_ctr)
const;
235 double get_ctr_rhs(
const Ctr& t_ctr)
const;
241 CtrType get_qctr_type(
const QCtr& t_ctr)
const;
243 [[nodiscard]]
double get_ctr_dual(
const Ctr& t_ctr)
const;
245 [[nodiscard]]
double get_ctr_farkas(
const Ctr& t_ctr)
const;
247 void set_ctr_rhs(
const Ctr& t_ctr,
double t_rhs);
249 void set_ctr_type(
const Ctr& t_ctr, CtrType t_type);
255 [[nodiscard]]
unsigned int get_var_index(
const Var& t_var)
const;
257 [[nodiscard]] VarType get_var_type(
const Var& t_var)
const;
259 [[nodiscard]]
double get_var_lb(
const Var& t_var)
const;
261 [[nodiscard]]
double get_var_ub(
const Var& t_var)
const;
263 [[nodiscard]]
double get_var_primal(
const Var& t_var)
const;
265 [[nodiscard]]
double get_var_reduced_cost(
const Var& t_var)
const;
267 [[nodiscard]]
double get_var_ray(
const Var& t_var)
const;
269 [[nodiscard]]
const LinExpr<Ctr>& get_var_column(
const Var& t_var)
const;
271 [[nodiscard]]
double get_var_obj(
const Var& t_var)
const;
273 void set_var_type(
const Var& t_var, VarType t_type);
275 void set_var_lb(
const Var& t_var,
double t_lb);
277 void set_var_ub(
const Var& t_var,
double t_ub);
279 void set_var_obj(
const Var& t_var,
double t_obj);
285 const std::vector<Var>& get_sosctr_vars(
const SOSCtr& t_ctr)
const;
287 const std::vector<double>& get_sosctr_weights(
const SOSCtr& t_ctr)
const;
289 [[nodiscard]]
bool is_sos1(
const SOSCtr& t_ctr)
const;
291 [[nodiscard]]
unsigned int get_n_solutions()
const;
293 [[nodiscard]]
unsigned int get_solution_index()
const;
295 void set_solution_index(
unsigned int t_index);
297 void dump(std::ostream& t_os = std::cout)
const;
299 Storage storage()
const {
return m_storage; }
301 void set_storage(Storage t_storage,
bool t_reset_minor_representation =
false);
303 void reset_minor_representation();
305 static Model read_from_file(
Env& t_env,
const std::string& t_filename);
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) {
315 for (
const auto& x : t_vector) {
316 add_vector<T, N - 1>(x);
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);
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) {
331 add_vector<Ctr, N>(result);
337 static auto save_primal(
const Model &t_original_model,
const Model &t_model) {
341 const auto status = t_model.get_status();
342 const auto reason = t_model.get_reason();
344 if (status != Optimal && status != Feasible && status != SubOptimal) {
345 throw Exception(
"Primal values not available.");
348 result.set_status(status);
349 result.set_reason(reason);
351 result.set_objective_value(t_model.get_best_obj());
353 for (
const auto &var: t_original_model.vars()) {
354 const double value = t_model.get_var_primal(var);
355 result.set(var, value);
362 static auto save_primal(
const Model &t_original_model) {
363 return save_primal(t_original_model, t_original_model);
366 static auto save_ray(
const Model &t_original_model,
const Model &t_model) {
370 const auto status = t_model.get_status();
371 const auto reason = t_model.get_reason();
373 if (status != Unbounded) {
377 result.set_status(status);
378 result.set_reason(reason);
380 result.set_objective_value(-Inf);
382 for (
const auto &var: t_original_model.vars()) {
383 const double value = t_model.get_var_ray(var);
384 result.set(var, value);
391 static auto save_ray(
const Model &t_original_model) {
392 return save_ray(t_original_model, t_original_model);
395 static auto save_dual(
const Model &t_original_model,
const Model &t_model) {
399 const auto status = t_model.get_status();
400 const auto reason = t_model.get_reason();
402 if (status != Optimal && status != Feasible) {
403 throw Exception(
"Dual values not available.");
406 result.set_status(status);
407 result.set_reason(reason);
409 result.set_objective_value(t_model.get_best_bound());
411 for (
const auto &ctr: t_original_model.ctrs()) {
412 const double value = t_model.get_ctr_dual(ctr);
413 result.set(ctr, value);
420 static auto save_dual(
const Model &t_original_model) {
421 return save_dual(t_original_model, t_original_model);
424 static auto save_farkas(
const Model &t_original_model,
const Model &t_model) {
428 const auto status = t_model.get_status();
429 const auto reason = t_model.get_reason();
431 if (status != Infeasible) {
432 throw Exception(
"Farkas certificate not available.");
435 result.set_status(status);
436 result.set_reason(reason);
438 result.set_objective_value(+Inf);
440 for (
const auto &ctr: t_original_model.ctrs()) {
441 const double value = t_model.get_ctr_farkas(ctr);
442 result.set(ctr, value);
449 static auto save_farkas(
const Model &t_original_model) {
450 return save_farkas(t_original_model, t_original_model);
453 static auto save_reduced_cost(
const Model &t_original_model,
const Model &t_model) {
457 const auto status = t_model.get_status();
458 const auto reason = t_model.get_reason();
460 if (status != Optimal && status != Feasible && status != SubOptimal) {
461 throw Exception(
"Reduced costs not available.");
464 result.set_status(status);
465 result.set_reason(reason);
467 result.set_objective_value(t_model.get_best_obj());
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);
478 static auto save_reduced_cost(
const Model &t_original_model) {
479 return save_reduced_cost(t_original_model, t_original_model);
486 static std::ostream &operator<<(std::ostream &t_os,
const idol::Model &t_model) {
488 using namespace idol;
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;
497 if (t_model.get_obj_sense() == Minimize) {
498 stream <<
"Minimize";
500 stream <<
"Maximize";
503 stream << std::endl << t_model.get_obj_expr() << std::endl <<
"Subject To" << std::endl;
505 for (
const auto &ctr: t_model.ctrs()) {
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);
511 stream << ctr <<
": ";
526 stream <<
" ?undefined? ";
529 stream << rhs << std::endl;
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);
536 stream << qctr <<
": ";
551 stream <<
" ?undefined? ";
557 std::list<Var> generals, binaries;
559 stream <<
"Bounds\n";
560 for (
const auto &var: t_model.vars()) {
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);
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;
576 if (type == Binary) {
577 binaries.emplace_back(var);
578 }
else if (type == Integer) {
579 generals.emplace_back(var);
585 if (!generals.empty()) {
586 stream <<
"Generals\n";
587 for (
const auto& var : generals) {
588 stream << var.name() << std::endl;
592 if (!binaries.empty()) {
593 stream <<
"Binaries\n";
594 for (
const auto& var : binaries) {
595 stream <<
'\t' << var.name() << std::endl;
599 if (t_model.sosctrs().size() > 0) {
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] <<
" ";
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="")
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="")