到目前为止,我直接在 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++程序打印出optimization failed,意思是没有找到解决方案。
有人看到我犯的错误吗?
有趣 - 我在 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 进行进一步调查。