Hi I have to solve a problem which contains a two-index node-based problem with pickup and delivery. This is my work in cplex but i am not really satisfied with the final result even though it works. Are there any suggestions on how to improve the structure of my code? Especially regarding the union of all the sets and the simplicity of the overall code. I only used arrays and sets and therefore the programm is not really nested/complex.
.mod: Sets:
{string} depot = ...;
{string} satellites = ...;
{string} customers = ...;
{string} Knoten = depot union satellites union customers;
{string} Knoten1 = depot union satellites;
{string} Knoten2 = satellites union customers;
Parameters:
float distance[Knoten][Knoten] = ...; // complete distance matrix with high costs for connection between depot and customers
float ddC[customers] = ...; // delivery demand of each customer
float pdC[customers] = ...; // pickup demand of each customer
float capSat[satellites] = ...; // capacity of each satellite
float capVBig = ...; // capacity of vehicles in the first echelon
float capVSmall = ...; // capacity of vehicles in the second echelon
decision variables:
dvar boolean x[Knoten1][Knoten1]; // binary variable for first echelon arc
dvar boolean y[Knoten2][Knoten2]; // binary variable for second echelon arc
dvar boolean z[customers][satellites]; // binary variable for customer assignment to satellite
dvar float+ ddS[satellites]; // delivery demand of each satellite
dvar float+ pdS[satellites]; // pickup demand of each satellite
dvar float+ uC[customers]; // delivery load on vehicle just before having serviced customer
dvar float+ vC[customers]; // pickup load on vehicle just after having serviced customer
dvar float+ uS[satellites]; // delivery load on vehicle just before having serviced satellite
dvar float+ vS[satellites]; // pickup load on vehicle just after having serviced satellite
Objec function:
// Minimize the total transportation cost (1)
minimize sum(i,j in Knoten1) distance[i][j] * x[i][j] + sum(l,m in Knoten2) distance[l][m] * y[l][m];
constraints:
subject to {
// Each satellite must be visited exactly once (2)
forall(i in satellites){
sum(j in Knoten1: j != i) x[i][j] == 1;
}
// Number of entering and leaving arcs to each node are equal to each other (3)
forall(i in Knoten1){
sum(j in Knoten1) x[i][j] == sum(j in Knoten1) x[j][i];
}
// Elimination of sub tours for delivery tours in the first echelon (4)
forall(i,j in satellites){
uS[j] - uS[i] + capVBig * x[i][j] <= capVBig - ddS[i];
}
// Lower and upper bounds of the additional variable u(i) (5)
forall(i in satellites){
ddS[i] <= uS[i] && uS[i] <= capVBig;
}
// Elimination of sub tours for pickup tours in the first echelon (6)
forall(i,j in satellites){
vS[i] - vS[j] + capVBig * x[i][j] <= capVBig - pdS[j];
}
// Lower and upper bounds of the additional variable v(i) (7)
forall(i in satellites){
pdS[i] <= vS[i] && vS[i] <= capVBig;
}
// Load transported on route is smaller than capacity of vehicle in first echelon (8)
forall(i in satellites){
uS[i] + vS[i] - ddS[i] <= capVBig;
}
// Total pickup and delivery demands of each satellite are equal or lower than the capacity of the satellite (9)
forall(i in satellites){
ddS[i] + pdS[i] <= capSat[i];
}
// Sum of the pickup demands of the customers assigned to each satellite must be equal to the pickup demands of the corresponding satellite (10)
forall(i in satellites){
sum(l in customers) z[l][i] * pdC[l] == pdS[i];
}
// Sum of the delivery demands of the customers assigned to each satellite must be equal to the delivery demands of the corresponding satellite (11)
forall(i in satellites){
sum(l in customers) z[l][i] * ddC[l] == ddS[i];
}
// Each customer must be visited exactly once (12)
forall(l in customers){
sum(m in Knoten2: m != l) y[l][m] == 1;
}
// Entering and leaving arcs to each node are equal (13)
forall(l in Knoten2){
sum(m in Knoten2) y[l][m] == sum(m in Knoten2) y[m][l];
}
// Each customer must be assigned to only one satellite (14)
forall(l in customers){
sum(i in satellites) z[l][i] == 1;
}
// Prevention of illegal routes:
// Vehicle can only travel from customer to satellite, if customer is assigned to this specific satellite (15)
forall(i in satellites){
forall(l in customers){
y[l][i] <= z[l][i];
}
}
// Vehicle can only travel from satellite to customer, if customer is assigned to this specific satellite (16)
forall(i in satellites){
forall(l in customers){
y[i][l] <= z[l][i];
}
}
// Vehicle has to start and end the route at the same satellite (17)
forall(l,m in customers: l != m){
forall(i in satellites){
y[l][m] + z[l][i] + sum(s in satellites: s != i) z[m][s] <= 2;
}
}
// Elimination of sub tours for delivery tours in the second echelon (18)
forall(l,m in customers){
uC[m] - uC[l] + capVSmall * y[l][m] + (capVSmall - ddC[l] - ddC[m]) * y[m][l] <= capVSmall - ddC[l];
}
// Lower bound for the additional variable u(l) (19)
forall(l in customers){
sum(m in customers) y[l][m] * ddC[m] + ddC[l] <= uC[l];
}
// Upper bound for the additional variable u(l) (20)
forall(i in satellites){
forall(l in customers){
uC[l] <= capVSmall - (capVSmall - ddC[l]) * y[l][i];
}
}
// Elimination of sub tours for pickup tours in the second echelon (21)
forall(l,m in customers){
vC[l] - vC[m] + capVSmall * y[l][m] + (capVSmall - pdC[l] - pdC[m]) * y[m][l] <= capVSmall - pdC[m];
}
// Lower bound for the additional variable v(l) (22)
forall(l in customers){
sum(m in customers) y[m][l] * pdC[m] + pdC[l] <= vC[l];
}
// Upper bound for the additional variable v(l) (23)
forall(i in satellites){
forall(l in customers){
vC[l] <= capVSmall - (capVSmall - pdC[l]) * y[i][l];
}
}
// Load transported on route is smaller than capacity of vehicle in the second echelon (24)
forall(l in customers){
uC[l] + vC[l] - ddC[l] <= capVSmall;
}
}