在 CPLEX 中指定约束的含义
Specify the sense of a constraint in CPLEX
我正在围绕 Gurobi 和 Cplex 编写一个小型包装器,以便我编写的模型独立于求解器。我对 Gurobi 非常熟悉,但我对 Cplex 很陌生,而且我在复制我经常使用的某些 api 调用时遇到了麻烦。
具体来说,我无法弄清楚如何将感觉传递给 Cplex API:
std::shared_ptr<Constraint> Model::addConstr(const std::vector<std::shared_ptr<Variable>>& vars,
const std::vector<double>& coeffs, char sense,
double rhs, const std::string& name)
#ifdef GUROBI
GRBLinExpr expr;
std::vector<GRBVar> grb_vars;
for(auto var : vars) {
grb_vars.push_back(*(var->getGRBVar()));
}
expr.addTerms(&coeffs[0], &grb_vars[0], (int) vars.size());
GRBConstr constraint = _grb_model->addConstr(expr, sense, rhs, name);
std::shared_ptr<GRBConstr> grb_constr_shared = std::make_shared<GRBConstr>(constraint);
return std::make_shared<Constraint>(grb_constr_shared);
#elif defined CPLEX
// do exactly the same process for cplex
IloExpr expr(_cplex_env);
for(int i = 0; i < vars.size(); ++i) {
expr += coeffs[i] * vars[i];
}
// this line below doesn't work -- I don't know how to pass the sense of
// the constraint. I'd like to avoid using a switch statement if possible..
IloConstraint constraint = _cplex_model.add(expr, sense, rhs);
#endif
}
而且我无法弄清楚如何为 objective 中的变量传递系数。我希望能够在创建变量时(或至少在创建变量后立即)执行此操作,以便我可以具有与 gurobi 类似的功能。
std::shared_ptr<Variable> Model::addVar(double lb, double ub, double obj,
char var_type, std::string name) {
#ifdef GUROBI
GRBVar grb_var = _grb_model->addVar(lb, ub, obj, var_type, std::move(name));
std::shared_ptr<GRBVar> grb_var_shared = std::make_shared<GRBVar>(grb_var);
return std::make_shared<Variable>(grb_var_shared);
#elif defined CPLEX
// do the same process for CPLEX and return std::make_shared<Variable>(cplex_var_shared);
// this line defines the variable but doesn't set its coeff in the
// objective function -- how do I set the variable's objective coefficient?
IloNumVar var(*_cplex_env, lb, ub, IloNumVar::Int, name.c_str());
#endif
}
对于您的 addConstr
方法,您将不得不使用 switch 语句(不幸的是,正如您希望避免的那样)。使用 CPLEX C++ API,使用重载的 <=
、==
和 >=
运算符或使用 IloRange 构造函数之一构建约束。例如:
IloRange constraint;
switch (sense) {
case 'L':
constraint = (expr <= rhs);
// Equivalent to:
// constraint = IloRange(env, 0.0, expr, rhs);
break;
case 'G':
constraint = (expr >= rhs);
// Equivalent to:
// constraint = IloRange(env, rhs, expr, IloInfinity);
break;
case 'E':
constraint = (expr == rhs);
// Equivalent to:
// constraint = IloRange(env, rhs, expr, rhs);
break;
default:
// This should not happen.
abort();
}
_cplex_model.add(constraint);
我对 Gurobi API 不是很熟悉,但是对于您的 addVar
方法,您似乎需要重构它以单独调用 GRBModel::setObjective()
(在创建变量)。使用 CPLEX C++ API,您可以用类似的方式单独创建 objective。例如,使用 IloMinimize,像这样:
model.add(IloMinimize(env, objexpr));
注意:CPLEX C API(又名可调用库)可能更符合您的原始代码。也就是说,您可以使用 char
参数设置约束的含义,并且可以在创建变量时设置变量的 objective 值。您可能想要承担更多工作,但您可以考虑围绕 CPLEX C API 创建自定义轻量级面向对象包装器以满足您的需求。
我正在围绕 Gurobi 和 Cplex 编写一个小型包装器,以便我编写的模型独立于求解器。我对 Gurobi 非常熟悉,但我对 Cplex 很陌生,而且我在复制我经常使用的某些 api 调用时遇到了麻烦。
具体来说,我无法弄清楚如何将感觉传递给 Cplex API:
std::shared_ptr<Constraint> Model::addConstr(const std::vector<std::shared_ptr<Variable>>& vars,
const std::vector<double>& coeffs, char sense,
double rhs, const std::string& name)
#ifdef GUROBI
GRBLinExpr expr;
std::vector<GRBVar> grb_vars;
for(auto var : vars) {
grb_vars.push_back(*(var->getGRBVar()));
}
expr.addTerms(&coeffs[0], &grb_vars[0], (int) vars.size());
GRBConstr constraint = _grb_model->addConstr(expr, sense, rhs, name);
std::shared_ptr<GRBConstr> grb_constr_shared = std::make_shared<GRBConstr>(constraint);
return std::make_shared<Constraint>(grb_constr_shared);
#elif defined CPLEX
// do exactly the same process for cplex
IloExpr expr(_cplex_env);
for(int i = 0; i < vars.size(); ++i) {
expr += coeffs[i] * vars[i];
}
// this line below doesn't work -- I don't know how to pass the sense of
// the constraint. I'd like to avoid using a switch statement if possible..
IloConstraint constraint = _cplex_model.add(expr, sense, rhs);
#endif
}
而且我无法弄清楚如何为 objective 中的变量传递系数。我希望能够在创建变量时(或至少在创建变量后立即)执行此操作,以便我可以具有与 gurobi 类似的功能。
std::shared_ptr<Variable> Model::addVar(double lb, double ub, double obj,
char var_type, std::string name) {
#ifdef GUROBI
GRBVar grb_var = _grb_model->addVar(lb, ub, obj, var_type, std::move(name));
std::shared_ptr<GRBVar> grb_var_shared = std::make_shared<GRBVar>(grb_var);
return std::make_shared<Variable>(grb_var_shared);
#elif defined CPLEX
// do the same process for CPLEX and return std::make_shared<Variable>(cplex_var_shared);
// this line defines the variable but doesn't set its coeff in the
// objective function -- how do I set the variable's objective coefficient?
IloNumVar var(*_cplex_env, lb, ub, IloNumVar::Int, name.c_str());
#endif
}
对于您的 addConstr
方法,您将不得不使用 switch 语句(不幸的是,正如您希望避免的那样)。使用 CPLEX C++ API,使用重载的 <=
、==
和 >=
运算符或使用 IloRange 构造函数之一构建约束。例如:
IloRange constraint;
switch (sense) {
case 'L':
constraint = (expr <= rhs);
// Equivalent to:
// constraint = IloRange(env, 0.0, expr, rhs);
break;
case 'G':
constraint = (expr >= rhs);
// Equivalent to:
// constraint = IloRange(env, rhs, expr, IloInfinity);
break;
case 'E':
constraint = (expr == rhs);
// Equivalent to:
// constraint = IloRange(env, rhs, expr, rhs);
break;
default:
// This should not happen.
abort();
}
_cplex_model.add(constraint);
我对 Gurobi API 不是很熟悉,但是对于您的 addVar
方法,您似乎需要重构它以单独调用 GRBModel::setObjective()
(在创建变量)。使用 CPLEX C++ API,您可以用类似的方式单独创建 objective。例如,使用 IloMinimize,像这样:
model.add(IloMinimize(env, objexpr));
注意:CPLEX C API(又名可调用库)可能更符合您的原始代码。也就是说,您可以使用 char
参数设置约束的含义,并且可以在创建变量时设置变量的 objective 值。您可能想要承担更多工作,但您可以考虑围绕 CPLEX C API 创建自定义轻量级面向对象包装器以满足您的需求。