目前我正在尝试使用MTZ子巡回消除约束来实现非对称容量车辆路径问题的CPLEX精确解。
当我尝试实现Lazy Constraint Callbacks时出现问题。更具体地说,我得到一个空指针异常。几乎没有实现回调的教程,所以非常感谢您的帮助。
这是我的代码:
CVRP类
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import ilog.concert.*;
import ilog.cplex.*;
public class ACVRP {
// euclidean distance method
public static double distance(int x1, int y1, int x2, int y2) {
return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
}
public static void solveModel() {
int n = 32; // number of customers
int k = 5; // number of vehicles
int c = 100; // capacity of vehicles
int datacoords[][] = new int[n][2];
double[][] node = new double[n][n]; // dissimilarity matrix
int[] demand = new int[n]; // demand of every customer
try {
// load matrixes
FileReader frd = new FileReader("demands.txt");
FileReader frcoords = new FileReader("coords.txt");
BufferedReader brd = new BufferedReader(frd);
BufferedReader brcoords = new BufferedReader(frcoords);
String str;
int counter = 0;
while ((str = brd.readLine()) != null) {
String[] splitStr = str.trim().split("\\s+");
demand[counter] = Integer.parseInt(splitStr[1]);
counter++;
}
counter = 0;
while ((str = brcoords.readLine()) != null) {
String[] splitStr = str.trim().split("\\s+");
datacoords[counter][0] = Integer.parseInt(splitStr[1]);
datacoords[counter][1] = Integer.parseInt(splitStr[2]);
counter++;
}
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
node[i][j] = distance(datacoords[i][0],datacoords[i][1],datacoords[j][0],datacoords[j][1]);
// if (i == j ){
// node[i][j] = 99999999;
// }
}
}
brd.close();
brcoords.close();
IloCplex cplex = new IloCplex();
// variables
IloIntVar[][] x = new IloIntVar[n][];
for (int i = 0; i < n; i++) {
x[i] = cplex.boolVarArray(n);
for (int j = 0; j < n; j++) {
x[i][j].setName("x." + i + "." + j );
}
}
// mtz variables
IloNumVar[] u = cplex.numVarArray(n, 0, Double.MAX_VALUE);
for (int j = 0; j < n; j++) {
u[j].setName("u." + j);
}
//objective
IloLinearNumExpr conObj = cplex.linearNumExpr();
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if ( i != j ){
conObj.addTerm(node[i][j], x[i][j]) ;
}
}
}
cplex.addMinimize(conObj);
// constraints
for (int i = 1; i < n; i++) {
IloLinearNumExpr equation1 = cplex.linearNumExpr();
for (int j = 0; j < n; j++) {
if (i!=j) {
equation1.addTerm(1.0, x[i][j]);
}
}
cplex.addEq(equation1, 1.0);
}
for (int j = 1; j < n; j++) {
IloLinearNumExpr equation2 = cplex.linearNumExpr();
for (int i = 0; i < n; i++) {
if (i!=j) {
equation2.addTerm(1.0, x[i][j]);
}
}
cplex.addEq(equation2, 1.0);
}
IloLinearNumExpr equation3 = cplex.linearNumExpr();
for (int i = 1; i < n; i++) {
equation3.addTerm(1.0, x[i][0]);
}
cplex.addEq(equation3, k);
IloLinearNumExpr equation4 = cplex.linearNumExpr();
for (int j = 1; j < n; j++) {
equation4.addTerm(1.0, x[0][j]);
}
cplex.addEq(equation4, k);
cplex.use(new LazyContstraintMTZ(n, c, demand, x, u, cplex));
//parameters
//cplex.setParam(IloCplex.Param.TimeLimit,50);
//cplex.setParam(IloCplex.Param.Preprocessing.Reduce, 0);
// cplex.setParam(IloCplex.Param.RootAlgorithm, IloCplex.Algorithm.Primal);
// solve model
cplex.solve();
cplex.exportModel("model.lp");
System.out.println(cplex.getBestObjValue());
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i != j) {
if (cplex.getValue(x[i][j]) != 0) {
System.out.println("name: " + x[i][j].getName() + " value: " + cplex.getValue(x[i][j]));
}
}
}
}
// end
cplex.end();
} catch (IloException | NumberFormatException | IOException exc) {
exc.printStackTrace();
}
}
}
延迟约束的类:
import ilog.concert.*;
import ilog.cplex.*;
public class LazyContstraintMTZ extends IloCplex.LazyConstraintCallback {
int n; // number of customers
int c; // capacity of vehicles
int[] demand; // demand of every customer
IloIntVar[][] x;
IloNumVar[] u;
IloCplex cplex;
IloRange[] rng;
//constructor
LazyContstraintMTZ(int n, int c, int[] demand, IloIntVar[][] x, IloNumVar[] u, IloCplex cplex){
this.n = n;
this.c = c;
this.demand = demand;
this.x = x;
this.u = u;
this.cplex = cplex;
}
protected void main() throws IloException {
// Get the current x solution
// double[][] sol = new double[n][n];
// for (int i = 0; i < n; i++) {
// for (int j = 0; j < n; j++) {
// sol[i][j] = cplex.getValue(x[i][j]);
// }
// }
for (int i = 1; i < n; i++) {
for (int j = 1; j < n; j++) {
if (i!=j && demand[i]+demand[j]<=c){
IloLinearNumExpr equation5 = cplex.linearNumExpr();
equation5.addTerm(1.0, u[i]);
equation5.addTerm(-1.0, u[j]);
equation5.addTerm(c, x[i][j]);
rng[i].setExpr(equation5);
rng[i].setBounds(Double.MIN_VALUE, c-demand[j]);
cplex.addLazyConstraint(rng[i]);
}
}
}
for (int i = 1; i < n; i++) {
IloLinearNumExpr equation6 = cplex.linearNumExpr();
equation6.addTerm(1.0, u[i]);
rng[i].setExpr(equation6);
rng[i].setBounds(demand[i], c);
cplex.addLazyConstraint(rng[i]);
}
}
}
答案 0 :(得分:0)
据我所知,rng
从未在您的回调类中初始化。因此,它始终是null
,一旦您尝试在其中设置元素,就会得到NullPointerException。
请注意,您甚至不需要该数组。代替
rng[i].setExpr(equation5);
rng[i].setBounds(Double.MIN_VALUE, c-demand[j]);
cplex.addLazyConstraint(rng[i]);
你可以写
IloRange rng = cplex.range(Double.MIN_VALUE, equation5, c - demand[j]);
cplex.addLazyConstraint(rng);
(对于equation6
也是如此)。
还请注意,Double.MIN_VALUE
可能不是您想要的。这给出了大于0的最小可表示数字。我想您想要的是Double.NEGATIVE_INFINITY
,以指定一个没有下限的范围。在这种情况下,您也可以写
IloRange rng = cplex.le(equation5, c - demand[j]);