Skip to content

Instantly share code, notes, and snippets.

@c3c
Created March 27, 2013 17:02
Show Gist options
  • Save c3c/5256039 to your computer and use it in GitHub Desktop.
Save c3c/5256039 to your computer and use it in GitHub Desktop.
c+vrp+tw working for depot too
/*********************************************
* OPL 12.5 Model
* Author: crash
* Creation Date: Mar 6, 2013 at 3:33:35 PM
*********************************************/
using CP;
// Nodes
tuple node { string name; float lat; float lon; int x; int y; int tmin; int tmax; }
{node} AllNodes = ...;
int N = card(AllNodes);
range nodes = 0..N-1;
// Edges
tuple edge {int i; int j;}
setof(edge) AllEdges = { <i,j> | i,j in nodes : i != j }; // not filtered!
setof(edge) OrderedEdges = { <i,j> | ordered i,j in nodes};
int Dist[OrderedEdges] = ...;
// Deliveries
tuple delivery {int destination; int from; int numpalettes;}
{delivery} Deliveries = ...;
// Remove superfluous thingies
sorted {int} clients = { d.from | d in Deliveries : d.numpalettes > 0 } union { d.destination | d in Deliveries : d.numpalettes > 0 } diff {0};
sorted {int} cities = {0} union clients;
int numCities = card(cities);
int demand[t in cities] = sum (d in Deliveries : d.destination == t) d.numpalettes;
//int outgoing[t in cities] = sum (d in Deliveries : d.from == t) d.numpalettes;
//int orders[from in cities, dest in cities] = sum (d in Deliveries : d.from == from && d.destination == dest) d.numpalettes;
int tmin[t in cities] = item(AllNodes, t).tmin;
int tmax[t in cities] = item(AllNodes, t).tmax;
setof(edge) Edges = { <i,j> | i,j in cities : i != j }; // filtered! :)
// Camions
tuple camion {key int id;int capacity; int maxweight; int maxtime;}
{camion} Camions = ...;
// Travel time
int vitesse = 65; // km/h
int tempstrajet[<i,j> in OrderedEdges] = ftoi(round(Dist[<i,j>]/vitesse*60));
int tempsservice = 30;
// Decision variables
dvar boolean x[Edges,Camions]; // est-ce que le camion fait le trajet entre i et j
dvar boolean y[Camions,cities]; // est-ce que le camion va visiter le noeud
dvar int+ z[Deliveries][Camions]; // combien de palettes d'un livraison est-ce que le camion va prendre
dvar boolean takenby[Deliveries][Camions];
dvar int+ arrival[Camions][cities] in 1..numCities;
dvar int+ tarrival[Camions][cities];// in 0..1440; // range important? interval gebruiken?
dexpr int charge[w in cities][k in Camions] = (sum (d in Deliveries : d.from == 0) z[d][k]) + y[k][w] * sum (i in cities, d in Deliveries) ((y[k][i]+(arrival[k][i]<arrival[k][w]) == 2) * (z[d][k]*((d.from==i && i != 0)-(d.destination==i))));
dexpr int treated[k in Camions][i in clients] = sum(d in Deliveries : d.destination == i || d.from == i) z[d][k]; // # paletten behandeld at node
execute {
cp.param.TimeMode = "ElapsedTime";
cp.param.TimeLimit = 600;
};
minimize sum (<i,j> in Edges, m in Camions) Dist[<minl(i,j), maxl(i,j)>]*x[<i,j>,m];
subject to {
forall (k in Camions, d in Deliveries) // fill up dvar takenby
(z[d][k]>=1) == takenby[d][k];
forall (k in Camions, j in cities)
(sum(i in cities : j!=i) x[<i,j>][k]) == y[k][j];
forall (k in Camions, j in cities)
(sum(i in cities : j!=i) x[<j,i>][k]) == y[k][j];
forall (d in Deliveries)
sum (k in Camions) takenby[d][k] >= 1;
forall (d in Deliveries, k in Camions)
(takenby[d][k] == 1) => (y[k][d.from] == 1 && y[k][d.destination] == 1);
// continuité
forall (p in cities, k in Camions)
((sum(i in cities : i!=p) x[<i,p>][k]) - (sum(j in cities : j!=p) x[<p,j>][k])) == 0;
//
forall (k in Camions, <i,j> in Edges : i!=0) // pick a number please :]
(x[<i,j>][k] == 1) => (arrival[k][i] + 1 == arrival[k][j]);
// For each client, the aggregated quantity of all trucks must match the demand
forall (d in Deliveries)
sum(k in Camions) z[d][k] == d.numpalettes;
forall (i in cities)
sum(k in Camions, d in Deliveries : d.destination == i) z[d][k] == demand[i];
// The amount of palettes the truck is going to deliver must be inferior|equal to his capacity
forall (k in Camions, i in cities)
(y[k][i] == 1) => (charge[i][k] <= k.capacity);
// respect timewindows
forall(j in clients, k in Camions)
(x[<0,j>][k] == 1) => (tarrival[k][j] >= (tempstrajet[<0,j>] + tmin[0]));
forall (<i,j> in Edges : i!=0, k in Camions)
(x[<i,j>][k] == 1) => ((tarrival[k][i] + tempstrajet[<minl(i,j), maxl(i,j)>] + 15+(3 * treated[k][i])) <= tarrival[k][j]);
// min max timeframe for entry at client
forall(i in cities, k in Camions)
(y[k][i] ==1) => ((tmin[i] <= tarrival[k][i]) && (tarrival[k][i] <= tmax[i]));
// truck can't be longer than e.g. 12h on route
forall (m in Camions)
m.maxtime >= ((sum (<i,j> in Edges) x[<i,j>,m]*(tempstrajet[<minl(i,j),maxl(i,j)>]+tempsservice))-tempsservice);
// pickup is before delivery, by same truck
forall (d in Deliveries : d.from != 0, m in Camions)
(takenby[d][m] == 1) => (arrival[m][d.from] <= arrival[m][d.destination]);
};
// POST-processing
edge E = <0,1>; // intermediary object
execute {
writeln(charge);
var unused = "We didn't use the following trucks: ";
var nUnused = 0;
for (var k in arrival) {
var num = 0;
var last = 0;
var timetotal = 0;
var str = "- Camion "+k.id+": 0 -> ";
for (var f = 1; f <= numCities-1; f++) {
for (var i in y[k]) {
if (y[k][i] == 1 && arrival[k][i] == f) {
if (!(last == 0 && i == 0)) {
E.i = Math.min(last, i);
E.j = Math.max(i, last);
timetotal += tempstrajet[E] + tempsservice;
last = i;
if (i!=0) {
str += i+" -> ";
}
}
num++;
}
}
}
timetotal -= tempsservice;
if (num > 0) {
writeln(str + "0 (total time: "+timetotal+")");
} else {
nUnused++;
unused += "c"+k.id + " ";
}
}
if (nUnused > 0) {
writeln(unused);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment