00 前言
前面我們已經搭建好cplex的java環境了,相信大家已經躍躍欲試,想動手寫幾個模型了。今天就來拿一個TSP的問題模型來給大家演示一下吧~
CPLEX系列教程可以關注我們的公眾號哦!獲取更多精彩消息!
01 TSP建模
關於TSP建模,就不多解釋了。以及什么是TSP問題,也不要問我了。直接貼一個現成的模型出來吧。
02 程序框架
整個程序框架如圖,app下是調用cplex的主要package。
其中:
- App.java:程序入口,cplex調用建模求解過程。
- ConstraintFactory.java:控制子環約束的。
- FileManager.java:讀取instance數據的。
package graph定義了一些變量,在求解過程中需要用到。input是算例,包含100-9000個城市。
03 求解過程
求解過程可以分為以下幾步進行:
- 定義一個模型
IloCplex model = new IloCplex();
- 定義決策變量,boolVar可以返回一個01的bool類型決策變量。
// define variables
IloIntVar[][] x = new IloIntVar[data.size()][data.size()];
for (int i = 0; i < x.length; i++) {
for (int j = 0; j < x.length; j++) {
x[i][j] = model.boolVar("X[" + i + ", " + j + "]");
}
}
- 添加約束7-1,addTerm將1*x[i][j]添加進表達式r里面,最終r的取值是里面所有的元素之和,也就是\(1*x[i][1]+1*x[i][2]+...+1*x[i][n]\)。
// one has only a city to go, and should
for (int i = 0; i < x.length; i++) {
IloLinearIntExpr r = model.linearIntExpr();
for (int j = 0; j < x.length; j++) {
// if (i == j)
// continue;
r.addTerm(1, x[i][j]);
}
model.addEq(r, 1);
}
- 添加約束7-2,原理同上一條。
// one can only arrive to one city at a time, and should
for (int j = 0; j < x.length; j++) {
IloLinearIntExpr r = model.linearIntExpr();
for (int i = 0; i < x.length; i++) {
// if (i == j)
// continue;
r.addTerm(1, x[i][j]);
}
model.addEq(r, 1);
}
- 添加約束7-3,子環約束處理有點復雜,但這個不是本文重點,讀者自行理解。
// add cycle restrictions
for (Stack<Edge> stack : stacks) {
// stack.forEach((edge) -> System.out.println(edge.getFrom() + "->" + edge.getTo()));
constraintFactory.cycleRestrictions(model, x, stack);
}
- 添加目標函數,z的表達式同上。
// one should complete the tour within the smallest distance possible
IloLinearNumExpr z = model.linearNumExpr();
for (int i = 0; i < x.length; i++) {
for (int j = 0; j < x.length; j++) {
if (i == j)
continue;
z.addTerm(distance[i][j], x[i][j]);
}
}
- 確定目標是最小化目標
model.addMinimize(z);
- 開始求解
if (model.solve()) {
// get tour
for (int i = 0; i < x.length; i++) {
for (int j = 0; j < x.length; j++) {
if (model.getValue(x[i][j]) >= 0.5) {
tour.add(new Edge(i, j));
}
}
}
// repaint tour
} else {
System.err.println("Boi, u sick!");
System.exit(1);
}
注意,一次求解不一定能求得最優解,小編跑了一個早上都跑不出來,還是100個節點的。model.getValue(x[i][j]) >= 0.5這個判斷只是把求解過程中一些較好的邊給添加進去而已。最優解是要滿足所有約束的。
04 運行說明
代碼下載請關注我們的公眾號哦!后台回復【CPTSP】不包括【】即可下載。
代碼來源GitHub,小編去掉了部分代碼。期待后期進一步精簡和修改,大家下載下來后用eclipse導入,設置好cplex環境以后。在App.java里面,右鍵Run As->Run configurations...:
找到App,在Arguments窗口,找到Program arguments:
輸入參數說明:
--instancePath+空格+算例文件的路徑,注意用英文雙引號括起來。
--maximumRead+空格+數字,表示算例大小,也就是多少個城市,文件名可以直接看出。
然后就可以愉快的run了。
附上運行結果:
大家可以在while(count<1)這個條件里面更改迭代次數,以便能獲取更好的解。