using CP;
tuple Node {
key string nodeID;
int x;
int y;
}
{Node} nodes = ...;
tuple Visit {
key int visitID;
string nodeID;
int quantity;
int minTime;
int maxTime;
int dropTime;
};
{Visit} clientVisits = ...;
tuple Vehicle {
key string vehicleID;
string firstVisitID;
string lastVisitID;
int capacity;
int start;
int end;
}
{Vehicle} vehicles = ...;
int numTrucks = card(vehicles);
dvar interval itvs_vehicle[v in vehicles] in v.start..v.end size v.end-v.start;
execute
{
itvs_vehicle;
}
int firstDepotVisitID = min(v in clientVisits) v.visitID - 1;
int lastDepotVisitID = max(v in clientVisits) v.visitID + 1;
Visit firstDepotVisit = <firstDepotVisitID,"depot",0,0,230,0>;
Visit lastDepotVisit = <lastDepotVisitID,"depot",0,0,230,0>;
{Visit} allVisits = clientVisits union
// Needs to be generalized for multiple depots
{firstDepotVisit, lastDepotVisit };
int horizon = max (v in allVisits) v.maxTime;
// Create transition distance
tuple triplet { int c1; int c2; int d; };
{triplet} Dist = {
// <v1.visitID, v2.visitID,
<ord(allVisits,v1), ord(allVisits,v2),
ftoi(round(sqrt(pow(n2.x-n1.x,2)+pow(n2.y-n1.y,2))))>
| v1,v2 in allVisits, n1, n2 in nodes : v1.nodeID == n1.nodeID && v2.nodeID == n2.nodeID };
dvar interval visitInterval[v in clientVisits] in v.minTime..(v.maxTime+v.dropTime) size v.dropTime;
dvar interval wtvisitInterval [v in clientVisits] size v.dropTime..horizon;
dvar interval tvisitInterval [v in allVisits][veh in vehicles]
optional(v.visitID!=firstDepotVisitID && v.visitID!=lastDepotVisitID);
dvar sequence route[veh in vehicles] in all(v in allVisits) tvisitInterval[v][veh]
types all(v in allVisits) /*v.visitID;*/ ord(allVisits,v);
dvar interval truck [veh in vehicles] optional;
execute {
cp.param.NoOverlapInferenceLevel = "Medium";
cp.param.TemporalRelaxation = "Off";
cp.param.TimeLimit = 10
}
dexpr int nonTravelTime = sum(v in clientVisits) sizeOf(wtvisitInterval[v]);
dexpr float travelTime = sum(veh in vehicles) endOf(tvisitInterval[lastDepotVisit][veh]) - nonTravelTime;
dexpr int nbUsed = sum(veh in vehicles) presenceOf(truck[veh]);
dexpr int load[veh in vehicles] = sum(v in clientVisits) presenceOf(tvisitInterval[v][veh])*v.quantity;
minimize staticLex(nbUsed,travelTime);
subject to {
forall(v in clientVisits ) {
endAtEnd(wtvisitInterval[v], visitInterval[v]);
startBeforeStart(wtvisitInterval[v], visitInterval[v]);
}
forall(veh in vehicles) {
span (truck[veh], all(v in clientVisits) tvisitInterval[v][veh]);
noOverlap(route[veh], Dist); // Travel time
startOf(tvisitInterval[firstDepotVisit][veh])==0; // Truck t starts at time 0 from depot
last (route[veh],tvisitInterval[lastDepotVisit] [veh]); // Truck t returns at depot
load[veh] <= veh.capacity; // Truck capacity
}
forall(v in clientVisits)
alternative(wtvisitInterval[v], all(t in vehicles) tvisitInterval[v][t]); // Truck selection
}
execute {
writeln(nbUsed + " vehicles are used");
writeln("Total travelled distance is " + travelTime);
}
range rr=1..4;
execute {
for(var veh in vehicles)
{
var seq=route[veh];
writeln("loop");
var s=seq.first();
for(var i in rr)
{
writeln(s);
var ty=Opl.typeOfNext(seq,s,0);
if (ty==0) break;
writeln("type = ",ty);
s=seq.next(s) ;
}
writeln(s);
}
}