CPLEX -切换到Gurobi
建筑模型
任何使用优化的程序都必须首先建立一个优化模型。虽然模型如何构建的确切细节取决于编程语言,但在我们所支持的所有语言中,一般概念是相似的。我们将关注概念,并在适当时提供细节。在CPLEX和Gurobi中,描述优化问题的前两个步骤是创建一个环境和一个模型.这些是我们的面向对象接口中的对象,分别使用GRBEnv和GRBModel构造函数创建。它们是C接口中的指针,由GRBloadenv()和GRBnewmodel()例程返回。下一步通常是列出决策变量。这是通过C语言中的grbadvar()例程和面向对象接口中的addVar()方法完成的。您可以一次添加一个变量,也可以添加多个变量(使用grbadvars()或addVars())。我们通常发现一次添加一个变量更方便,而且这样做不会造成性能损失,但是如果CPLEX程序已经这样做了,您可能想要添加多个变量。
Gurobi和CPLEX的一个区别是我们使用“懒更新”的方法。在对模型进行更改之后,您需要调用grbupdatmodel /GRBModel。更新以使这些更改可见。更具体地说,你需要打电话“更新”在向模型中添加变量之后,为了在约束中使用这些变量。我们的延迟更新方法使构建或修改模型变得更容易、更有效,因为您可以完全控制实际更改何时发生。然而,我们的接口和CPLEX接口之间的区别是您需要记住的。决策变量有许多属性,包括变量类型(连续、二进制等)、下界、上界等。你有两个选择来指定这些。第一个是在创建变量时输入所需的属性值(例如,作为addVar()的参数)。第二种方法是在将变量添加到模型之后,使用各种Gurobi之一修改属性集例程(例如,C中的GRBsetintattr(), c++中的GRBVar.set())。属性是Gurobi接口中的一个重要概念。与在CPLEX中为访问和修改模型的各种属性提供几十个不同的例程不同,我们通过一个接口来处理它们。下面是一个例子,在一系列语言中显示的命令,您可以使用它来更改变量的上限x1.0:
语言 | 命令 |
---|---|
C | grbsetdbltreelement (model, GRB_DBL_ATTR_UB, x_index, 1.0); |
c++ | x.set (GRB_DoubleAttr_UB, 1.0); |
c# | x.Set (GRB.DoubleAttr。乌兰巴托,1.0); |
Java | x.set (GRB.DoubleAttr。乌兰巴托,1.0); |
Python | x.ub = 1.0 |
类似地,要改变下界:
语言 | 命令 |
---|---|
C | grbsetdbltrelement (model, GRB_DBL_ATTR_LB, x_index, 1.0); |
c++ | x.set (GRB_DoubleAttr_LB, 1.0); |
c# | x.Set (GRB.DoubleAttr。磅,1.0); |
Java | x.set (GRB.DoubleAttr。磅,1.0); |
Python | x.lb = 1.0 |
这个属性接口用于统一和简化各种Gurobi接口。通常,如果您正在搜索一个与CPLEX get/set例程匹配的例程,那么您很可能会在我们的属性接口中找到该功能。
构建优化模型的下一步通常是描述决策变量的线性约束。根据您使用的界面,您可以使用单个约束矩阵来描述这些约束,可以添加约束组,也可以一次添加一个约束。同样,我们发现一次添加一个约束更方便,但我们理解,如果模拟现有的CPLEX方法,可能会简化迁移。如果您使用Gurobi C接口,那么您通常只会使用一个约束矩阵来指定约束。您可以使用GRBloadmodel()例程来实现这一点。这个例程的参数与CPLEX的参数非常相似CPXcopylp ()例行公事。注意,您还可以使用grbadconstr()在C接口中单独添加约束。在我们的面向对象接口中,您可以使用addConstr()方法添加单个线性约束。细节取决于你使用的语言。我们的c++, .NET和Python接口允许操作符重载,所以你可以添加一个线性约束,如下所示:
语言 | 命令 |
---|---|
C | Int ind[] = {1, 3, 4};Double val[] = {1.0, 2.0, 1.0};错误= GRBaddconstr(model, 3, ind, val, GRB_EQUAL, 1.0, "New"); |
c++ | 模型。addConstr(x + y + 2*z <= 2); |
c# | 模型。AddConstr(x + y + 2*z <= 2); |
Python | 模型。addConstr(x + y + 2*z <= 2) |
您还可以构建线性表达式(GRBExpr)对象,向这些表达式添加线性项(expr.addTerm()),然后使用这些表达式添加约束。在Java中:
GRBLinExpr expr = new GRBLinExpr();
expr.addTerm (1.0 x);expr.addTerm (1.0, y);expr.addTerm (2.0, z);
模型。addConstr (expr伽马线暴。LESS_EQUAL, 2.0);
您的模型可能包含其他约束类型,包括特殊有序集(SOS)约束或二次约束。Gurobi接口包含的例程与CPLEX接口中的例程非常相似。我们鼓励您浏览我们的示例以获得详细信息。
设置求解参数手机万博登录
在将优化模型从CPLEX迁移到Gurobi时,您可能需要设置某些Gurobi参数,以匹配您在CPLEX中修改过的参数。我们想要强调的一个重要一点是,您不应该假设需要为您更改的每个CPLEX参数找到一个匹配的Gurobi参数。Gurobi和CPLEX使用不同的策略和算法。Gurobi策略调优可能与您所做的CPLEX调优有所不同,而且通常可能根本就没有必要进行调优。我们建议您从默认设置开始,并且只在您观察到想要修改的特定行为时更改参数。下表给出了最常用CPLEX参数的高级映射:
CPLEX参数(C API) | Gurobi参数 |
---|---|
CPX_PARAM_BARALG | BarHomogeneous |
CPX_PARAM_BARCROSSALG | 交叉 |
CPX_PARAM_BAREPCOMP | BarConvTol |
CPX_PARAM_BARQCPEPCOMP | BarQCPConvTol |
CPX_PARAM_BRDIR | BranchDir |
CPX_PARAM_CLIQUES | CliqueCuts |
CPX_PARAM_COVERS | CoverCuts |
CPX_PARAM_CUTPASS | CutPasses |
CPX_PARAM_EPGAP | MIPGap |
CPX_PARAM_EPAGAP | MIPGapAbs |
CPX_PARAM_EPINT | IntFeasTol |
CPX_PARAM_EPOPT | OptimalityTol |
CPX_PARAM_FLOWCOVERS | FlowCoverCuts |
CPX_PARAM_FPHEUR | PumpPasses |
CPX_PARAM_FRACPASS | GomoryPasses |
CPX_PARAM_GUBCOVERS | GUBCoverCuts |
CPX_PARAM_HEURFREQ | 启发式 |
CPX_PARAM_INTSOLLIM | SolutionLimit |
CPX_PARAM_LPMETHOD | 方法 |
CPX_PARAM_MIPEMPHASIS | MIPFocus |
CPX_PARAM_MIRCUTS | MIRCuts |
CPX_PARAM_NODEFILEIND | NodeFileStart |
CPX_PARAM_POLISHAFTEREPGAP | ImproveStartGap * |
CPX_PARAM_POLISHAFTERTIME | ImproveStartTime * |
CPX_PARAM_PREDUAL | 预对偶 |
CPX_PARAM_PREIND | Presolve |
CPX_PARAM_RINSHEUR | rin |
CPX_PARAM_STARTALG | 方法 |
CPX_PARAM_SUBALG | NodeMethod |
CPX_PARAM_THREADS | 线程 |
CPX_PARAM_TIMELIMIT | 期限 |
CPX_PARAM_VARSEL | VarBranch |
CPX_PARAM_ZEROHALFCUTS | ZeroHalfCuts |
* Gurobi使用了不同的算法,但得到了相似的结果。同样,这只是您在CPLEX中可能使用的参数的部分列表。如果您正在修改不在此列表中的参数,我们鼓励您浏览参考手册中的Gurobi参数列表
一旦知道想要更改哪些参数,更改它们所需的代码就很简单了。在C语言中,调用grbsettparam /GRBsetdblparam/GRBsetstringparam。在我们的面向对象接口中,您调用GRBEnv对象的set()方法。当从CPLEX迁移到Gurobi时,有时会让人们感到困惑的一点是,Gurobi为每个模型提供了自己的Gurobi环境的副本,因此允许每个模型拥有自己的参数设置。在CPLEX中,所有模型使用相同的参数值。最简单的管理方法是为模型设置如下参数:
语言 | 命令 |
---|---|
C | 错误= GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_SOLUTIONLIMIT, 1); |
c++ | model.getEnv()。集(GRB_IntParam_SolutionLimit, 1); |
c# | model.GetEnv()这里(GRB.IntParam。SolutionLimit, 1); |
Java | model.getEnv()这里(GRB.IntParam。SolutionLimit, 1); |
Python | model.params.solutionLimit = 1 |
计算并提取解
一旦您制定了您的优化模型和设置求解器参数,最后一步是计算一个解。手机万博登录你可以通过在C中调用GRBoptimize()或在面向对象的接口中调用GRBModel.optimize()来实现。当您要求的终止条件之一(优化差距、时间限制、解限制等)得到满足时,优化将完成。一旦优化完成,您应该始终检查它的状态。同样,我们不是提供几十个get/set例程,而是将状态作为模型的一个属性返回。您可以使用适当的属性查询它得到例行公事。例如:
语言 | 命令 |
---|---|
C | error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &status); / /获取状态if (status == GRB_OPTIMAL)… |
c++ | if (model.get(GRB_IntAttr_Status) == GRB_OPTIMAL)… |
c# | if (model.Get(GRB.IntAttr.Status) == GRB.OPTIMAL)… |
Java | if (model.get(GRB.IntAttr.Status) == GRB.OPTIMAL)… |
Python | 如果模型。状态= =伽马线暴。优:… |
决策变量的计算值也是属性:
语言 | 命令 |
---|---|
C | error = grbgetdblattreelement (model, GRB_DBL_ATTR_X, x_index, &xvalue); / /将数据复制printf("变量x的值是%g\n", xvalue); |
c++ | cout << "Value for variable x is: " << x.get(GRB_DoubleAttr_X) << endl; |
c# | 控制台。WriteLine("变量x的值是:" + x. get (grb . doubleattrx)); |
Java | system . out。println("变量x的值是:" + x.get(grb . doubleattrn . x)); |
Python | print('变量x的值是:',x.x) |
您还可以使用属性接口检索其他解决方案信息,包括客观值、约束松弛和双变量(可用时)。让我们重申一下,如果您希望将CPLEX get/set函数映射到Gurobi,那么您可能会在我们的属性接口中找到它的等效物。当然,找到一个经过验证的最佳解决方案并不是唯一可能的结果。例如,您可能会发现您的模型是不可行的。如果您正在使用CPLEX冲突细化器来帮助诊断不可行性,Gurobi通过我们的不可约不一致子系统(IIS)例程(C语言中的GRBcomputeIIS();model.computeIIS()在面向对象接口中)。如果您正在使用CPLEX feasopt特性来寻找模型中约束的最小成本松弛,那么您可以使用Gurobi feasRelax特性(C语言中的GRBfeasrelax();模型。面向对象接口中的feasRelax)。