Укажите смысл ограничения в CPLEX - PullRequest
4 голосов
/ 26 сентября 2019

Я пишу небольшую оболочку вокруг 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
}

И у меня возникают проблемы с выяснением, как передать коэффициент для переменной в цели.Я хотел бы иметь возможность сделать это при создании переменной (или, по крайней мере, сразу после создания переменной), чтобы у меня была функциональность, аналогичная 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
  }

1 Ответ

2 голосов
/ 26 сентября 2019

Для вашего 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);

Я не очень знаком с API Gurobi, но для вашего метода addVar похоже, что вы захотите изменить его на вызов GRBModel::setObjective() отдельно (после созданияпеременные).С помощью CPLEX C ++ API вы создаете цель отдельно, аналогичным образом.Например, использование IloMinimize , например так:

model.add(IloMinimize(env, objexpr));

ПРИМЕЧАНИЕ : CPLEX C API (Callable Library), возможно, больше соответствует духу вашего исходного кода,Таким образом, вы можете установить смысл ограничения с помощью аргумента char, и вы можете установить объективное значение переменной при ее создании.Возможно, вам захочется проделать дополнительную работу, но вы можете рассмотреть возможность создания настраиваемой облегченной объектно-ориентированной оболочки вокруг API-интерфейса CPLEX C, отвечающей вашим потребностям.

...