Skip to content

Commit

Permalink
add Gurobi::read_from_file
Browse files Browse the repository at this point in the history
  • Loading branch information
hlefebvr committed Dec 14, 2023
1 parent 622e90b commit 6cab4f9
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 20 deletions.
23 changes: 3 additions & 20 deletions dev/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,17 @@
#include "idol/problems/knapsack-problem/KP_Instance.h"
#include "idol/modeling/models/dualize.h"
#include "idol/optimizers/wrappers/Gurobi/Gurobi.h"
#include "idol/optimizers/wrappers/Gurobi/Optimizers_Gurobi.h"

using namespace idol;

int main(int t_argc, char** t_argv) {

const auto instance = Problems::KP::read_instance("/home/henri/Research/idol/examples/knapsack.data.txt");

const auto n_items = instance.n_items();

Env env;

auto model = read_mps_file(env, "/home/henri/Downloads/SMALL/knapsack.mps");

model.set_obj_sense(Maximize);

model.use(Gurobi::ContinuousRelaxation());

model.optimize();

std::cout << "Primal: " << model.get_best_obj() << std::endl;

auto dual = dualize(model);

dual.use(Gurobi());

dual.optimize();
auto model = Gurobi::read_from_file(env, "/home/henri/Research/bilevel-ccg/code/cmake-build-debug/instance.lp");

std::cout << "Dual: " << dual.get_best_obj() << std::endl;
std::cout << model << std::endl;

return 0;
}
3 changes: 3 additions & 0 deletions lib/include/idol/optimizers/wrappers/Gurobi/Gurobi.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <memory>
#include "idol/optimizers/callbacks/CallbackFactory.h"
#include "idol/containers/Map.h"
#include "idol/modeling/objects/Env.h"

#ifdef IDOL_USE_GUROBI
#include <gurobi_c++.h>
Expand Down Expand Up @@ -56,6 +57,8 @@ class idol::Gurobi : public OptimizerFactoryWithDefaultParameters<Gurobi> {

Gurobi& with_external_param(GRB_DoubleParam t_param, double t_value);

static Model read_from_file(Env& t_env, const std::string& t_filename);

[[nodiscard]] Gurobi *clone() const override;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ class idol::Optimizers::Gurobi : public OptimizerWithLazyUpdates<GRBVar, std::va
static char gurobi_ctr_type(int t_type);
static char gurobi_obj_sense(int t_sense);
static double gurobi_numeric(double t_value);
static VarType idol_var_type(char t_type);
static CtrType idol_ctr_type(char t_type);
static ObjectiveSense idol_obj_sense(int t_sense);
[[nodiscard]] std::pair<SolutionStatus, SolutionReason> gurobi_status(int t_status) const;
protected:
void hook_build() override;
Expand Down Expand Up @@ -113,6 +116,8 @@ class idol::Optimizers::Gurobi : public OptimizerWithLazyUpdates<GRBVar, std::va
void set_tol_optimality(double t_tol_optimality) override;

void set_tol_integer(double t_tol_integer) override;

static Model read_from_file(Env& t_quad_expr, const std::string& t_filename);
};

#endif
Expand Down
4 changes: 4 additions & 0 deletions lib/src/optimizers/wrappers/gurobi/Gurobi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,7 @@ idol::Gurobi &idol::Gurobi::with_external_param(GRB_DoubleParam t_param, double

return *this;
}

idol::Model idol::Gurobi::read_from_file(idol::Env &t_env, const std::string &t_filename) {
return Optimizers::Gurobi::read_from_file(t_env, t_filename);
}
123 changes: 123 additions & 0 deletions lib/src/optimizers/wrappers/gurobi/Optimizers_Gurobi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#ifdef IDOL_USE_GUROBI

#include "idol/optimizers/wrappers/Gurobi/Optimizers_Gurobi.h"
#include "idol/modeling/expressions/operations/operators.h"

#define GUROBI_CATCH(cmd) \
try { \
Expand Down Expand Up @@ -510,4 +511,126 @@ void idol::Optimizers::Gurobi::set_tol_integer(double t_tol_integer) {
m_model.set(GRB_DoubleParam_IntFeasTol, t_tol_integer);
}

idol::Model idol::Optimizers::Gurobi::read_from_file(idol::Env &t_env, const std::string &t_filename) {

Model result(t_env);

std::unique_ptr<GRBModel> model;
GUROBI_CATCH(model = std::make_unique<GRBModel>(get_global_env(), t_filename);)

const unsigned int n_vars = model->get(GRB_IntAttr_NumVars);
const unsigned int n_ctrs = model->get(GRB_IntAttr_NumConstrs);
const unsigned int n_quad_ctrs = model->get(GRB_IntAttr_NumQConstrs);

for (unsigned int j = 0 ; j < n_vars ; ++j) {

const auto& var = model->getVar(j);
const double lb = var.get(GRB_DoubleAttr_LB);
const double ub = var.get(GRB_DoubleAttr_UB);
VarType type = idol_var_type(var.get(GRB_CharAttr_VType));

result.add_var(lb, ub, type, var.get(GRB_StringAttr_VarName));
}

const auto parse_linear = [&](const GRBLinExpr& t_lin_expr) {
Expr result_ = t_lin_expr.getConstant();

for (unsigned int j = 0, n = t_lin_expr.size() ; j < n ; ++j) {
auto var = t_lin_expr.getVar(j);
result_ += t_lin_expr.getCoeff(j) * result.get_var_by_index(var.index());
}

return result_;
};

const auto parse_quadratic = [&](const GRBQuadExpr& t_quad_expr) {
Expr result_ = parse_linear(t_quad_expr.getLinExpr());

for (unsigned int j = 0, n = t_quad_expr.size() ; j < n ; ++j) {
auto var1 = t_quad_expr.getVar1(j);
auto var2 = t_quad_expr.getVar2(j);
result_ += t_quad_expr.getCoeff(j) * result.get_var_by_index(var1.index()) * result.get_var_by_index(var2.index());
}

return result_;
};

const auto add_ctr = [&](const auto& t_lhs, const auto& t_rhs, char t_type) {

switch (t_type) {
case LessOrEqual: result.add_ctr(t_lhs <= t_rhs); break;
case GreaterOrEqual: result.add_ctr(t_lhs >= t_rhs); break;
case Equal: result.add_ctr(t_lhs == t_rhs); break;
default: throw Exception("Enum out of bounds.");
}

};

for (unsigned int i = 0 ; i < n_ctrs ; ++i) {

const auto& ctr = model->getConstr(i);
const auto& expr = model->getRow(ctr);
const double rhs = ctr.get(GRB_DoubleAttr_RHS);
const auto type = idol_ctr_type(ctr.get(GRB_CharAttr_Sense));

Expr lhs = parse_linear(expr);
add_ctr(lhs, rhs, type);
}

for (unsigned int i = 0 ; i < n_quad_ctrs ; ++i) {

const auto& ctr = model->getQConstrs()[i];
const auto& expr = model->getQCRow(ctr);
const double rhs = ctr.get(GRB_DoubleAttr_QCRHS);
const auto type = idol_ctr_type(ctr.get(GRB_CharAttr_QCSense));

Expr lhs = parse_quadratic(expr);
add_ctr(lhs, rhs, type);

}

const auto sense = model->get(GRB_IntAttr_ModelSense);
model->set(GRB_IntAttr_ModelSense, idol_obj_sense(sense));

const auto& objective = model->getObjective();
result.set_obj_expr(parse_quadratic(objective));

return std::move(result);
}

idol::VarType idol::Optimizers::Gurobi::idol_var_type(char t_type) {

switch (t_type) {
case GRB_INTEGER: return Integer;
case GRB_BINARY: return Binary;
case GRB_CONTINUOUS: return Continuous;
default:;
}

throw Exception("Unexpected variable type.");
}

idol::CtrType idol::Optimizers::Gurobi::idol_ctr_type(char t_type) {

switch (t_type) {
case GRB_LESS_EQUAL: return LessOrEqual;
case GRB_GREATER_EQUAL: return GreaterOrEqual;
case GRB_EQUAL: return Equal;
default:;
}

throw Exception("Unexpected constraint type.");
}

idol::ObjectiveSense idol::Optimizers::Gurobi::idol_obj_sense(int t_sense) {

switch (t_sense) {
case GRB_MINIMIZE: return Minimize;
case GRB_MAXIMIZE: return Maximize;
default:;
}

throw Exception("Unexpected constraint type.");
}

#endif

0 comments on commit 6cab4f9

Please sign in to comment.