提问人:Arctic_Skill 提问时间:8/11/2023 更新时间:8/15/2023 访问量:77
C++ 中的优化问题不会产生与 CPLEX 中相同的结果
Optimization problem in C++ does not yield the same result as in CPLEX
问:
到目前为止,我直接在 IBM ILOG CPLEX Optimization Studio 中对优化问题进行了建模。
现在,我想尝试在使用 CPLEX API 的同时使用 C++ 来表述模型。
为此,我从一个非常简单的问题开始,只是为了学习 C++ 并感受如何使用 CPLEX API。
问题在 CPLEX 中如下所示:
range j = 1..3;
dvar int+ x[i];
dvar float+ y[j];
maximize -3*x[1] - 2*x[2] + 4*x[3] + y[1] - 3*y[2] - 2*y[3];
subject to {
c1: -2*x[1] + 4*x[2] - x[3] + 3*y[1] - 2*y[2] + 3*y[3] <= -4;
c2: -x[1] - 2*x[2] + 4*x[3] + 2*y[1] + 4*y[2] - 5*y[3] <= 2;
c3: forall(i in i) x[i] <= 6;
}
现在,我只想用 C++ 编写相同的模型。这是我当前的代码:
#include <iostream>
#include "ilcplex//ilocplex.h";
using namespace std;
int main() {
IloEnv env;
IloModel Model(env);
IloIntVar x1(env, 0, IloInfinity, "x1");
IloIntVar x2(env, 0, IloInfinity, "x2");
IloIntVar x3(env, 0, IloInfinity, "x3");
IloNumVar y1(env, 0, IloInfinity, ILOFLOAT, "y1");
IloNumVar y2(env, 0, IloInfinity, ILOFLOAT, "y2");
IloNumVar y3(env, 0, IloInfinity, ILOFLOAT, "y3");
Model.add(IloMaximize(env, -3 * x1 - 2 * x2 + 4 * x3 + y1 - 3 * y2 - 2 * y3));
Model.add((-2 * x1 + 4 * x2 - x3 + 3 * y1 - 2 * y2 + 3 * y3) <= -4);
Model.add((-x1 - 2 * x2 + 4 * x3 + 2 * y1 + 4 * y2 - 5 * y3) <= 2);
Model.add(x1 <= 6);
Model.add(x2 <= 6);
Model.add(x3 <= 6);
IloCplex cplex(Model);
if (!cplex.solve()) {
env.error() << "Optimization failed" << endl;
throw(-1);
}
double obj = cplex.getObjValue();
cout << "\n\n\t objective value: " << obj << endl;
cout << "x1 = " << cplex.getValue(x1) << endl;
cout << "x2 = " << cplex.getValue(x2) << endl;
cout << "x3 = " << cplex.getValue(x3) << endl;
cout << "y1 = " << cplex.getValue(y1) << endl;
cout << "y2 = " << cplex.getValue(y2) << endl;
cout << "y3 = " << cplex.getValue(y3) << endl;
}
老实说,我已经看了一段时间了,我无法弄清楚为什么这两个程序不能产生相同的解决方案。
CPLEX 程序的目标值为 2.429,这是正确的解决方案。 C++ 程序打印出优化失败,这意味着它没有找到解决方案。
有人看到我犯的错误吗?
答:
有趣 - 我在 Windows 上使用 CPLEX 20.1 和 VS2022 尝试过这个,因为我无论如何都需要刷新我的 C++ CPLEX 内容。我同意您的上述代码被报告为不可行,但是下面的小改动似乎可以解决:
IloIntVar x1(env, 0, 6, "x1");
IloIntVar x2(env, 0, 6, "x2");
IloIntVar x3(env, 0, 6, "x3");
IloNumVar y1(env, 0, IloInfinity, ILOFLOAT, "y1");
IloNumVar y2(env, 0, IloInfinity, ILOFLOAT, "y2");
IloNumVar y3(env, 0, IloInfinity, ILOFLOAT, "y3");
Model.add(IloMaximize(env, -3 * x1 - 2 * x2 + 4 * x3 + y1 - 3 * y2 - 2 * y3));
Model.add((-2 * x1 + 4 * x2 - x3 + 3 * y1 - 2 * y2 + 3 * y3) <= -4);
Model.add((-x1 - 2 * x2 + 4 * x3 + 2 * y1 + 4 * y2 - 5 * y3) <= 2);
//Model.add(x1 <= 6);
//Model.add(x2 <= 6);
//Model.add(x3 <= 6);
即更改是在声明这些 x 变量时将它们的边界设置为 6,而不是通过约束单独设置。以下是修改后的模型的输出日志:
Version identifier: 20.1.0.0 | 2020-11-10 | 9bedb6d68
Found incumbent of value -6.000000 after 0.00 sec. (0.00 ticks)
Tried aggregator 1 time.
Reduced MIP has 2 rows, 6 columns, and 12 nonzeros.
Reduced MIP has 0 binaries, 3 generals, 0 SOSs, and 0 indicators.
Presolve time = 0.00 sec. (0.00 ticks)
Tried aggregator 1 time.
Reduced MIP has 2 rows, 6 columns, and 12 nonzeros.
Reduced MIP has 0 binaries, 3 generals, 0 SOSs, and 0 indicators.
Presolve time = 0.00 sec. (0.00 ticks)
MIP emphasis: balance optimality and feasibility.
MIP search method: dynamic search.
Parallel mode: deterministic, using up to 16 threads.
Root relaxation solution time = 0.00 sec. (0.00 ticks)
Nodes Cuts/
Node Left Objective IInf Best Integer Best Bound ItCnt Gap
* 0+ 0 -6.0000 0.00%
* 0+ 0 -1.9524 0.00%
0 0 4.0000 1 -1.9524 4.0000 3 304.88%
* 0+ 0 1.9231 4.0000 108.00%
* 0+ 0 2.2857 4.0000 75.00%
0 0 2.5000 2 2.2857 MIRcuts: 1 5 9.37%
* 0+ 0 2.4286 2.5000 2.94%
0 0 cutoff 2.4286 5 ---
Elapsed time = 0.05 sec. (0.05 ticks, tree = 0.01 MB, solutions = 5)
Mixed integer rounding cuts applied: 1
Root node processing (before b&c):
Real time = 0.05 sec. (0.05 ticks)
Parallel b&c, 16 threads:
Real time = 0.00 sec. (0.00 ticks)
Sync time (average) = 0.00 sec.
Wait time (average) = 0.00 sec.
------------
Total (root+branch&cut) = 0.05 sec. (0.05 ticks)
objective value: 2.42857
x1 = 4
x2 = -0
x3 = 5
y1 = 0.142857
y2 = 0
y3 = 2.85714
我原以为这应该在 CPLEX 的预解析之后生成一个非常相似的模型并给出相同的结果,但它显然做了一些不同的事情。我会将此报告给 IBM 进行进一步调查。
编辑:更多挖掘。看起来它不喜欢用 IloInfinity 的上限声明 IloIntVars。如果我将模型导出为 LP 文件,我会在这些变量上获得意想不到的边界,将它们全部设置为零:
\ENCODING=ISO-8859-1
\Problem name: IloCplex
Maximize
obj1: - 3 x1 - 2 x2 + 4 x3 + y1 - 3 y2 - 2 y3
Subject To
c1: - 2 x1 + 4 x2 - x3 + 3 y1 - 2 y2 + 3 y3 <= -4
c2: - x1 - 2 x2 + 4 x3 + 2 y1 + 4 y2 - 5 y3 <= 2
c3: x1 <= 6
c4: x2 <= 6
c5: x3 <= 6
Bounds
x1 = 0
x2 = 0
x3 = 0
Generals
x1 x2 x3
End
如果我将声明更改为以下内容,它似乎可以正常工作:
IloNumVar x1(env, 0, IloInfinity, ILOINT, "x1");
IloNumVar x2(env, 0, IloInfinity, ILOINT, "x2");
IloNumVar x3(env, 0, IloInfinity, ILOINT, "x3");
评论
使用 IloIntVar 时,应使用 IloIntMax 作为上限,而不是 IloInfinity
评论
CPLEX