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."); } }
 
   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);
 
   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();
 
 
  306template<
class T, 
unsigned int N>
 
  307void idol::Model::add_vector(
const Vector<T, N> &t_vector) {
 
  308    if constexpr (N == 1) {
 
  309        for (
const auto& x : t_vector) {
 
  313        for (
const auto& x : t_vector) {
 
  314            add_vector<T, N - 1>(x);
 
  319template<
unsigned int N>
 
  320idol::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) {
 
  321    auto result = 
Var::make_vector(m_env, t_dim, t_lb, t_ub, t_type, t_obj, t_name);
 
  322    add_vector<Var, N>(result);
 
  326template<
unsigned int N>
 
  327idol::Vector<idol::Ctr, N> idol::Model::add_ctrs(Dim<N> t_dim, CtrType t_type, 
double t_rhs, 
const std::string &t_name) {
 
  329    add_vector<Ctr, N>(result);
 
  335    static auto save_primal(
const Model &t_original_model, 
const Model &t_model) {
 
  339        const auto status = t_model.get_status();
 
  340        const auto reason = t_model.get_reason();
 
  342        if (status != Optimal && status != Feasible && status != SubOptimal) {
 
  343            throw Exception(
"Primal values not available.");
 
  346        result.set_status(status);
 
  347        result.set_reason(reason);
 
  349        result.set_objective_value(t_model.get_best_obj());
 
  351        for (
const auto &var: t_original_model.vars()) {
 
  352            const double value = t_model.get_var_primal(var);
 
  353            result.set(var, value);
 
  360    static auto save_primal(
const Model &t_original_model) {
 
  361        return save_primal(t_original_model, t_original_model);
 
  364    static auto save_ray(
const Model &t_original_model, 
const Model &t_model) {
 
  368        const auto status = t_model.get_status();
 
  369        const auto reason = t_model.get_reason();
 
  371        if (status != Unbounded) {
 
  372            throw Exception(
"Ray not available.");
 
  375        result.set_status(status);
 
  376        result.set_reason(reason);
 
  378        result.set_objective_value(-Inf);
 
  380        for (
const auto &var: t_original_model.vars()) {
 
  381            const double value = t_model.get_var_ray(var);
 
  382            result.set(var, value);
 
  389    static auto save_ray(
const Model &t_original_model) {
 
  390        return save_ray(t_original_model, t_original_model);
 
  393    static auto save_dual(
const Model &t_original_model, 
const Model &t_model) {
 
  397        const auto status = t_model.get_status();
 
  398        const auto reason = t_model.get_reason();
 
  400        if (status != Optimal && status != Feasible) {
 
  401            throw Exception(
"Dual values not available.");
 
  404        result.set_status(status);
 
  405        result.set_reason(reason);
 
  407        result.set_objective_value(t_model.get_best_bound());
 
  409        for (
const auto &ctr: t_original_model.ctrs()) {
 
  410            const double value = t_model.get_ctr_dual(ctr);
 
  411            result.set(ctr, value);
 
  418    static auto save_dual(
const Model &t_original_model) {
 
  419        return save_dual(t_original_model, t_original_model);
 
  422    static auto save_farkas(
const Model &t_original_model, 
const Model &t_model) {
 
  426        const auto status = t_model.get_status();
 
  427        const auto reason = t_model.get_reason();
 
  429        if (status != Infeasible) {
 
  430            throw Exception(
"Farkas certificate not available.");
 
  433        result.set_status(status);
 
  434        result.set_reason(reason);
 
  436        result.set_objective_value(+Inf);
 
  438        for (
const auto &ctr: t_original_model.ctrs()) {
 
  439            const double value = t_model.get_ctr_farkas(ctr);
 
  440            result.set(ctr, value);
 
  447    static auto save_farkas(
const Model &t_original_model) {
 
  448        return save_farkas(t_original_model, t_original_model);
 
  451    static auto save_reduced_cost(
const Model &t_original_model, 
const Model &t_model) {
 
  455        const auto status = t_model.get_status();
 
  456        const auto reason = t_model.get_reason();
 
  458        if (status != Optimal && status != Feasible && status != SubOptimal) {
 
  459            throw Exception(
"Reduced costs not available.");
 
  462        result.set_status(status);
 
  463        result.set_reason(reason);
 
  465        result.set_objective_value(t_model.get_best_obj());
 
  467        for (
const auto &var: t_original_model.vars()) {
 
  468            const double value = t_model.get_var_reduced_cost(var);
 
  469            result.set(var, value);
 
  476    static auto save_reduced_cost(
const Model &t_original_model) {
 
  477        return save_reduced_cost(t_original_model, t_original_model);
 
  484    static std::ostream &operator<<(std::ostream &t_os, 
const idol::Model &t_model) {
 
  486        using namespace idol;
 
  488        if (t_model.storage() == Model::Storage::ColumnOriented) {
 
  489            std::cerr << 
"Warning: print a column-oriented model leads to the generation of a minor representation. " 
  490                         "This operation can be slow and memory-consuming." << std::endl;
 
  495        if (t_model.get_obj_sense() == Minimize) {
 
  496            stream << 
"Minimize";
 
  498            stream << 
"Maximize";
 
  501        stream << std::endl << 
"\t" << t_model.get_obj_expr() << std::endl << 
"Subject To" << std::endl;
 
  503        for (
const auto &ctr: t_model.ctrs()) {
 
  505            const auto linear = t_model.get_ctr_row(ctr);
 
  506            const double rhs = t_model.get_ctr_rhs(ctr);
 
  507            const auto type = t_model.get_ctr_type(ctr);
 
  509            stream << 
'\t' << ctr << 
": ";
 
  524                    stream << 
" ?undefined? ";
 
  527            stream << rhs << std::endl;
 
  530        for (
const auto& qctr : t_model.qctrs()) {
 
  531            const auto& expr = t_model.get_qctr_expr(qctr);
 
  532            const auto type = t_model.get_qctr_type(qctr);
 
  534            stream << 
'\t' << qctr << 
": ";
 
  549                    stream << 
" ?undefined? ";
 
  555        std::list<Var> generals, binaries;
 
  557        stream << 
"Bounds\n";
 
  558        for (
const auto &var: t_model.vars()) {
 
  560            const double lb = t_model.get_var_lb(var);
 
  561            const double ub = t_model.get_var_ub(var);
 
  562            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 << 
'\t' << 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 << 
'\t' << 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="")