Reputation: 11
I'm writing an extension of the Vehicle Routing Problem (VRP) in JAVA by using Gurobi. The problem that I have, is that when I run my code, JAVA says that it is optimal with an objective value of zero. Which should not be te case, since:
A VRP works with arcs and nodes. Whether an arc is used is indicated by the Xijk variable (whether you travel from node i to node j by vehicle k). In the VRP one constraints inter alia that each customer needs to be visited exactly once. Meaning that at least one Xijk for customer j needs to be one. Which vehicle k is used and what the previous visited node i was, is something you ask Gurobi to find out.
So only when there are Xijk variables that have a zero cost-factor in the objective function, it seems logic that the objective value equals to zero. However, for me that is not the case, since I (re)write the objective function at the end of my code and use the distance between node i to j as the cost-factor. Even when I look into the model formulation which is retrieved by "model.write("constraintOutput.lp")", I see an objective function that contains Xijk variables with a cost-factor of >0.
So, I have searched around for a solution and people have mentioned that the problem could be:
a. When initializing the variables, the third parameter should not be zero since it says what the "cost-factor" of the variable should be in the objective function. Since I write my constraint at the last part of my code before optimizing my model, this should not matter, I believe. Though I have changed this parameter from zero to one when initializing Xijk variables, but the problem still remains.
b. I should update my model after initializing my variables and constraints. I have done this, but again the problem still remains.
I have even reduced my model by removing some constraints, but this does not help.
Does anybody have an idea of how to solve this problem?
My code:
import java.util.ArrayList;
import gurobi.GRB;
import gurobi.GRBEnv;
import gurobi.GRBException;
import gurobi.GRBLinExpr;
import gurobi.GRBModel;
import gurobi.GRBVar;
public class VRP {
public int M; //big number
public int speed; //speed km/h
public int nDepots; //number of depots
public int nCustomers; //number of customers to be visited
public ArrayList<Node> allLocations; //All locations
public ArrayList<Vehicle> vehicleList; //Vehicles
public double [][] dm; //distance matrix
public VRP(ArrayList<Node> n, ArrayList<Node> d, ArrayList<Node> dummyd, ArrayList<Vehicle> v, double [][] distanceMatrix) throws Exception {
this.M = 1000;
this.speed = 60000;
this.vehicleList = v;
this.allLocations = new ArrayList<Node>();
this.allLocations.addAll(d);
this.allLocations.addAll(n);
this.nDepots = d.size();
this.nCustomers = n.size();
this.dm = distanceMatrix;
}
public void solution() throws Exception{
Functions f = new Functions();
// 1. DEFINE MODEL -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
try{
GRBEnv env = new GRBEnv ();
env.set(GRB.IntParam.OutputFlag, 0); //set to 1 to get constraint overview
GRBModel model = new GRBModel(env);
model.set ( GRB.StringAttr.ModelName, "VRP" );
// 2. DEFINE VARIABLES -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//Xijqk
GRBVar[][][] x = new GRBVar[this.allLocations.size()][this.allLocations.size()][this.vehicleList.size()];
for (int i = 0; i<this.allLocations.size(); i++){
for (int j = 0; j < this.allLocations.size(); j++){
for (int k = 0; k < this.vehicleList.size(); k++){
double dij = f.getDistance(dm, this.allLocations.get(i).nodeID, this.allLocations.get(j).nodeID);
//get.Distance retrieves the distance between two nodes that are indicated by their IDs
x[i][j][k] = model.addVar(0.0, 1.0, dij, GRB.BINARY, "X" + i + j + k); //arc between node i and j used by vehicle k or not
}//k
}//j
}//i
//aik: arival time at customer i by vehicle k
GRBVar[][] a = new GRBVar[this.allLocations.size()][this.vehicleList.size()];
for (int i = 0; i<this.allLocations.size(); i++){
for (int k = 0; k < this.vehicleList.size(); k++){
a[i][k] = model.addVar(0.0, GRB.INFINITY, 0.0, GRB.CONTINUOUS, "a" + i + k); //arival time at node i by vehicle k
}//k
}//i
//dep: departure time from customer i by vehicle k
GRBVar[][] dep = new GRBVar[nDepots][this.vehicleList.size()];
for (int i = 0; i < nDepots; i++){
for (int k = 0; k < this.vehicleList.size(); k++){
dep[i][k] = model.addVar(0.0, GRB.INFINITY, 0.0, GRB.CONTINUOUS, "dep" + i + k); //departure time from depot i by vehicle k
}//k
}//i
model.update();
//3. DEFINE CONSTRAINTS
//Constraint 1
for (int j = nDepots; j < this.allLocations.size(); j++){
GRBLinExpr lhs = new GRBLinExpr();
for(int i = 0; i < this.allLocations.size(); i++){
for (int k = 0; k < this.vehicleList.size(); k++){
lhs.addTerm(1, x[i][j][k]);
}//k
}//i
GRBLinExpr rhs = new GRBLinExpr();
rhs.addConstant(1);
model.addConstr(lhs, GRB.EQUAL, rhs, "Constraint 1");
}//j
//Constraint 2
for (int i = nDepots; i < this.allLocations.size(); i++){
GRBLinExpr lhs = new GRBLinExpr();
for(int j = 0; j < this.allLocations.size(); j++){
for (int k = 0; k < this.vehicleList.size(); k++){
lhs.addTerm(1, x[i][j][k]);
}//k
}//i
GRBLinExpr rhs = new GRBLinExpr();
rhs.addConstant(1);
model.addConstr(lhs, GRB.EQUAL, rhs, "Constraint 2:");
}//j
//Constraint 3
for (int s = nDepots; s < this.allLocations.size(); s++){
for (int k = 0; k < this.vehicleList.size(); k++){
GRBLinExpr lhs = new GRBLinExpr();
for (int i = 0; i < this.allLocations.size(); i++){
lhs.addTerm(1, x[i][s][k]);
}//i
GRBLinExpr rhs = new GRBLinExpr();
rhs.addConstant(1);
model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 3");
}//k
}//s
//Constraint 4
for (int s = nDepots; s < this.allLocations.size(); s++){
for (int k = 0; k < this.vehicleList.size(); k++){
GRBLinExpr lhs = new GRBLinExpr();
for (int j = 0; j < this.allLocations.size(); j++){
lhs.addTerm(1, x[s][j][k]);
}//j
GRBLinExpr rhs = new GRBLinExpr();
rhs.addConstant(1);
model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 4");
}//k
}//s
//Constraint 5
for (int k = 0; k < this.vehicleList.size(); k++){
GRBLinExpr lhs = new GRBLinExpr();
for (int i = 0; i < nDepots; i++){
for (int j = nDepots; j < this.allLocations.size(); j++){
lhs.addTerm(1, x[i][j][k]);
}//j
}//i
GRBLinExpr rhs = new GRBLinExpr();
rhs.addConstant(1);
model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 5:");
}//k
//Constraint 6
for (int k = 0; k < this.vehicleList.size(); k++){
GRBLinExpr lhs = new GRBLinExpr();
for (int i = nDepots; i < this.allLocations.size(); i++){
for (int j = 0; j < nDepots; j++){
lhs.addTerm(1, x[i][j][k]);
}//j
}//i
GRBLinExpr rhs = new GRBLinExpr();
rhs.addConstant(1);
model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 6:");
}//k
//Constraint 7: Capacity constraints of vehicles
for (int k = 0; k < this.vehicleList.size(); k++){
GRBLinExpr lhs = new GRBLinExpr();
for (int i =0; i < this.allLocations.size(); i++){
for (int j = 0; j < this.allLocations.size(); j++){
lhs.addTerm(2, x[i][j][k]);
}//j
}//i
GRBLinExpr rhs = new GRBLinExpr();
rhs.addConstant(20);
model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 7: Capacity");
}//k
//Constraint 8: #vehicles entering depot cannot exceed depot capacity
for (int j=0; j < nDepots; j++){
GRBLinExpr lhs = new GRBLinExpr();
for (int i = nDepots; i < this.allLocations.size(); i++){
for (int k=0; k < this.vehicleList.size(); k++){
lhs.addTerm(1, x[i][j][k]);
}//for k
}// for i
GRBLinExpr rhs = new GRBLinExpr();
int pj = this.allLocations.get(j).vehicleCapacity;
rhs.addConstant(pj);
model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 8");
}//i
//Constraint 9: TimeWindow
for (int i = nDepots; i < this.allLocations.size(); i++){
for (int k = 0; k < this.vehicleList.size(); k++){
GRBLinExpr lhs = new GRBLinExpr();
lhs.addTerm(1, a[i][k]);
GRBLinExpr rhs = new GRBLinExpr();
double stwi = this.allLocations.get(i).startTime;
rhs.addConstant(stwi);
model.addConstr(lhs, GRB.GREATER_EQUAL, rhs, "Constraint 9: ");
}//k
}//i
//Constraint 10: TimeWindow
for (int i = nDepots; i < this.allLocations.size(); i++){
for (int k = 0; k < this.vehicleList.size(); k++){
GRBLinExpr lhs = new GRBLinExpr();
lhs.addTerm(1, a[i][k]);
GRBLinExpr rhs = new GRBLinExpr();
double etw = this.allLocations.get(i).endTime;
rhs.addConstant(etw);
model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 10:");
}//for k
}//i
//Constraint 11: determine departure vehicle from depot
for (int i = 0; i < nDepots; i++){
for (int k = 0; k < this.vehicleList.size(); k++){
GRBLinExpr lhs = new GRBLinExpr();
double eid = this.allLocations.get(i).startTime;
lhs.addConstant(eid);
GRBLinExpr rhs = new GRBLinExpr();
rhs.addTerm(1, dep[i][k]);
model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 11:" );
}//k
}//i
//Constraint 12: determine returning time to depot
for (int i = 0; i < nDepots; i++){
for (int k = 0; k < this.vehicleList.size(); k++){
GRBLinExpr lhs = new GRBLinExpr();
lhs.addTerm(1, a[i][k]);
GRBLinExpr rhs = new GRBLinExpr();
double lid = this.allLocations.get(i).returningTime;
rhs.addConstant(lid);
model.addConstr(lhs, GRB.LESS_EQUAL, rhs, "Constraint 12: " );
}//k
}//i
//Constraint 13: precedence constraint 1
for (int i = nDepots; i < this.allLocations.size(); i++){
for (int j = 0; j < this.allLocations.size(); j++){
if (i != j){
for (int k = 0; k < this.vehicleList.size(); k++){
GRBLinExpr lhs = new GRBLinExpr();
lhs.addTerm(1, a[j][k]);
GRBLinExpr rhs = new GRBLinExpr();
rhs.addTerm(1, a[i][k]);
double si = this.allLocations.get(i).serviceTime;
rhs.addConstant(si);
double dtij = (this.allLocations.get(i).distance + f.getDistance(dm, this.allLocations.get(i).nodeID, this.allLocations.get(j).nodeID))/speed;
rhs.addConstant(dtij);
rhs.addConstant(-M);
rhs.addTerm(M, x[i][j][k]);
model.addConstr(lhs, GRB.GREATER_EQUAL, rhs, "Constraint 13: ");
}//k
}//if
}//j
}//i
//Constraint 14: precedence constraint 2 - if previous node was depot
for (int i = 0; i < nDepots; i++){
for (int j = nDepots; j < this.allLocations.size(); j++){
for (int k = 0; k < this.vehicleList.size(); k++){
GRBLinExpr lhs = new GRBLinExpr();
lhs.addTerm(1, a[j][k]);
GRBLinExpr rhs = new GRBLinExpr();
rhs.addTerm(1, dep[i][k]);
double dtij = (this.allLocations.get(i).distance + f.getDistance(dm, this.allLocations.get(i).nodeID, this.allLocations.get(j).nodeID))/speed;
rhs.addConstant(dtij);
rhs.addConstant(-M);
rhs.addTerm(M, x[i][j][k]);
model.addConstr(lhs, GRB.GREATER_EQUAL, rhs, "Constraint 14: ");
}//for k
}//for j
}//for i
model.update();
//4. SET OBJECTIVE ---------------------------------------------------------------------------------------------------------------------------------------
GRBLinExpr expr = new GRBLinExpr();
for (int i = 0; i < this.allLocations.size(); i++){
for (int j = 0; j < this.allLocations.size(); j++){
if (i != j){
for (int k = 0; k < this.vehicleList.size(); k++){
double dtij = (this.allLocations.get(i).distance + f.getDistance(dm, this.allLocations.get(i).nodeID, this.allLocations.get(j).nodeID))/speed;
expr.addTerm(dtij, x[i][j][k]);
}//k
}//if
}//j
}//i
model.setObjective(expr, GRB.MINIMIZE);
model.update();
model.optimize();
System.out.println("is the solution feasible? " + model.get(GRB.IntAttr.Status));
model.write("constraintOutput.lp");
//5. CONSTRUCT SOLUTION ---------------------------------------------------------------------------------------------------------------------------------------------
double obj = model.get(GRB.DoubleAttr.ObjVal);
for (int i = 0; i < this.allLocations.size(); i++){
for (int j = 0; j < this.allLocations.size(); j++){
if (i != j){
for (int k = 0; k < this.vehicleList.size(); k++){
if (x[i][j][k].get(GRB.DoubleAttr.X) > 0){
System.out.println(x[i][j][k].get(GRB.StringAttr.VarName) + " " + x[i][j][k].get(GRB.DoubleAttr.X));
System.out.println("Node: " + (i+1) + " goes to node: " + (j+1) + " by vehicle: " + (k+1));
}//if
}//k
}//if
}//j
}//i
System.out.println("The objective value is: " + obj);
//6. DISPOSE OF MODEL AND ENVIRONMENT
model.dispose();
env.dispose();
}catch (GRBException e ){
e.printStackTrace();
}//catch
}//solution
}//public main problem
Upvotes: 1
Views: 596
Reputation: 11
So I found the solution:
//Constraint 1
for (int j = nDepots; j < this.allLocations.size(); j++){
GRBLinExpr lhs = new GRBLinExpr();
for(int i = 0; i < this.allLocations.size(); i++){
if(i != j) {
for (int k = 0; k < this.vehicleList.size(); k++){
lhs.addTerm(1, x[i][j][k]);
}//k
}
}//i
GRBLinExpr rhs = new GRBLinExpr();
rhs.addConstant(1);
model.addConstr(lhs, GRB.EQUAL, rhs, "C1 - j"+j);
}//j
I have not included Xijk variables in my objective function where i = j. Since I know beforehand that such variables are invalid answers. However, I forgot to do the same for the constraints. Meaning, I have to add an if loop with (i!=j) as shown in the above example. Now my code is working!
Upvotes: 0
Reputation: 146
what is the value of arc (depot,j), j costumer ? I have an observation : the definition of var x[i][j][k], when you define binary, put (0 and 1), not (0.0 and 1.0) like this:
x[i][j][k] = model.addVar(0, 1, dij, GRB.BINARY, "X" + i + j + k)
Upvotes: 0