177 lines
7.2 KiB
MiniZinc
177 lines
7.2 KiB
MiniZinc
%----------------------------------------------------------------------------%
|
|
%----------------------------------------------------------------------------%
|
|
%
|
|
% We have n trains moving along a single track with m stations. There is a
|
|
% non-zero constant flow of passengers arriving at all but the first and last
|
|
% station who wish to travel to the final station. Trains are originally
|
|
% scheduled so that they collect the passengers and drop them at the final
|
|
% station. To this original schedule a disruption is introduced whereby a train
|
|
% is delayed. Each of the trains (at the time of the delay) has knowledge of the
|
|
% duration of the delay. The objective is to reschedule the trains to minimize
|
|
% the average travel time of the passengers. Trains are not able to overtake
|
|
% preceding trains, however they do have the option to
|
|
% skip a station and wait longer at a station to collect more passengers.
|
|
|
|
%----------------------------------------------------------------------------%
|
|
%----------------------------------------------------------------------------%
|
|
|
|
%include "globals.mzn";
|
|
|
|
int : n;
|
|
int : m;
|
|
|
|
int : maxTime;
|
|
|
|
0..maxTime : delayTime;
|
|
1..n : delayTrain;
|
|
0..maxTime : delayDuration;
|
|
|
|
array [1..m-1] of 0..maxTime : distance;
|
|
|
|
array [1..n, 1..m] of 0..maxTime : scheduledArrival;
|
|
array [1..n, 1..m] of 0..maxTime : scheduledDeparture;
|
|
|
|
array [1..m] of 0..maxTime : passengerStart;
|
|
array [1..m] of 0..maxTime : passengerStop = [scheduledDeparture[n,j] | j in 1..m];
|
|
array [1..m] of int : passengerFlow;
|
|
|
|
array [1..n, 1..m] of var 0..maxTime : departure;
|
|
array [1..n, 1..m] of var 0..maxTime : arrival;
|
|
|
|
array [1..n] of var 0..maxTime : finalArrival = [ arrival[i,m] | i in 1..n ];
|
|
|
|
array [1..n, 1..m] of var 0..maxTime : sigmaLower;
|
|
array [1..n, 1..m] of var 0..maxTime : sigmaUpper;
|
|
|
|
int : capacity;
|
|
|
|
array [1..n, 1..m] of var 0..capacity : collect;
|
|
array [1..n, 1..m] of var 0..capacity : load;
|
|
|
|
% All trains "arrive" at the first station at time 0.
|
|
constraint forall (i in 1..n)
|
|
(arrival[i,1] = 0);
|
|
% ... and "depart" from the last station as soon as they arrive there.
|
|
constraint forall (i in 1..n)
|
|
(departure[i,m] = arrival[i,m]);
|
|
|
|
% Before the delay, everything runs to schedule.
|
|
constraint forall (i in 1..n, j in 1..m-1)
|
|
(if scheduledDeparture[i,j] <= delayTime
|
|
then departure[i,j] = scheduledDeparture[i,j]
|
|
else true
|
|
endif);
|
|
|
|
% If the train is in motion, then the arrival of the
|
|
% delayed train is at least the departure time at the previous station
|
|
% plus the ordinary travel time plus the duration of the delay.
|
|
int : destinationWhenDelayed = min([j | j in 1..m where scheduledDeparture[delayTrain,j] > delayTime]);
|
|
constraint if destinationWhenDelayed > 1
|
|
then if delayTime < scheduledDeparture[delayTrain,destinationWhenDelayed-1] + distance[destinationWhenDelayed-1]
|
|
then arrival[delayTrain,destinationWhenDelayed] >=
|
|
departure[delayTrain,destinationWhenDelayed-1] + delayDuration + distance[destinationWhenDelayed-1]
|
|
else true
|
|
endif
|
|
else true
|
|
endif;
|
|
% The train's next departure is at least the delay time plus the delay
|
|
% duration.
|
|
constraint departure[delayTrain, destinationWhenDelayed] >= delayTime + delayDuration;
|
|
|
|
% Trains depart after they arrive.
|
|
constraint forall (i in 1..n, j in 1..m)
|
|
(departure[i,j] >= arrival[i,j]);
|
|
|
|
% Trains never leave earlier than scheduled.
|
|
constraint forall (i in 1..n, j in 1..m-1)
|
|
(departure[i,j] >= scheduledDeparture[i,j]);
|
|
|
|
% There is a minimum travel time between stations.
|
|
constraint forall (i in 1..n, j in 1..m-1)
|
|
(arrival[i,j+1] >= departure[i,j] + distance[j]);
|
|
|
|
% At station 1, trains leave in order.
|
|
constraint forall (i in 1..n-1)
|
|
(departure[i,1] < departure[i+1,1]);
|
|
% At most one train dwelling at a station at a given time.
|
|
constraint forall (i in 1..n-1, j in 2..m-1)
|
|
(departure[i,j] <= arrival[i+1,j]-2);
|
|
|
|
% The sigma values partition time at each station.
|
|
constraint forall (i in 1..n, j in 1..m)
|
|
(sigmaLower[i,j] <= sigmaUpper[i,j]);
|
|
|
|
% For the first and last trains, the sigma values are equal to the
|
|
% extreme times of passenger arrivals.
|
|
constraint forall (j in 2..m-1)
|
|
((sigmaLower[1,j] = passengerStart[j])
|
|
/\ (sigmaUpper[n,j] = scheduledDeparture[n,j]));
|
|
% The sigma values join together.
|
|
constraint forall (i in 1..n-1, j in 1..m)
|
|
(sigmaUpper[i,j] = sigmaLower[i+1,j]);
|
|
|
|
% You can't pick up people after you leave.
|
|
constraint forall (i in 1..n-1, j in 1..m-1)
|
|
(sigmaUpper[i,j] <= departure[i,j]);
|
|
constraint forall (j in 1..m-1)
|
|
(sigmaUpper[n,j] <= departure[n,j]);
|
|
|
|
% Defines collect and load variables.
|
|
constraint forall (i in 1..n, j in 1..m)
|
|
(collect[i,j] = (sigmaUpper[i,j]-sigmaLower[i,j])*passengerFlow[j]);
|
|
|
|
constraint forall (i in 1..n) (load[i,1] = collect[i,1]);
|
|
constraint forall (i in 1..n, j in 2..m)
|
|
(load[i,j] = load[i,j-1] + collect[i,j]);
|
|
|
|
% If a train picks anyone up, then it must pick
|
|
% everyone up (until it gets full).
|
|
constraint forall (i in 1..n, j in 1..m-1)
|
|
(sigmaUpper[i,j] > sigmaLower[i,j] ->
|
|
((sigmaUpper[i,j] = departure[i,j]) \/
|
|
(sigmaUpper[i,j] = scheduledDeparture[n,j]) \/
|
|
(load[i,j] + bool2int(sigmaUpper[i,j] < scheduledDeparture[n,j])*passengerFlow[j] > capacity)));
|
|
|
|
% Boarding time.
|
|
constraint forall (i in 1..n, j in 2..m)
|
|
(((capacity-load[i,j-1] < 100) -> (collect[i,j] <= dwell[i,j]*20)) /\
|
|
((capacity-load[i,j-1] >= 100) -> (collect[i,j] <= dwell[i,j]*50)));
|
|
% (Redundant for j>=2 (but necessary for j=1))
|
|
constraint forall (i in 1..n, j in 1..m)
|
|
(collect[i,j] <= (departure[i,j]-arrival[i,j])*50);
|
|
|
|
array [1..n, 1..m] of var 0..maxTime : dwell;
|
|
constraint forall (i in 1..n, j in 1..m) (dwell[i,j] = departure[i,j] - arrival[i,j]);
|
|
|
|
int: objective_min = lb(sum(i in 1..n)(load[i,m]*arrival[i,m]));
|
|
int: objective_max = ub(sum(i in 1..n)(load[i,m]*arrival[i,m]));
|
|
var objective_min..objective_max: objective = sum(i in 1..n)(load[i,m]*arrival[i,m]);
|
|
|
|
solve
|
|
:: seq_search([
|
|
int_search(
|
|
[arrival[i,m-j+1] | j in 1..m, i in 1..n] ++
|
|
[departure[i,m-j+1] | j in 1..m, i in 1..n] ++
|
|
[sigmaUpper[i,m-j+1] | j in 1..m, i in 1..n] ++
|
|
[sigmaLower[i,m-j+1] | j in 1..m, i in 1..n],
|
|
input_order, indomain_min, complete
|
|
),
|
|
int_search(
|
|
array1d(1..n*m, collect) ++ array1d(1..n*m, load) ++ array1d(1..n*m, dwell),
|
|
first_fail, indomain_min, complete
|
|
)
|
|
])
|
|
minimize objective;
|
|
|
|
output [
|
|
"arrival = array2d(1..", show(n), ", 1..", show(m), ", ", show(arrival), ");\n",
|
|
"departure = array2d(1..", show(n), ", 1..", show(m), ", ", show(departure), ");\n",
|
|
"sigmaLower = array2d(1..", show(n), ", 1..", show(m), ", ", show(sigmaLower), ");\n",
|
|
"sigmaUpper = array2d(1..", show(n), ", 1..", show(m), ", ", show(sigmaUpper), ");\n",
|
|
"collect = array2d(1..", show(n), ", 1..", show(m), ", ", show(collect), ");\n",
|
|
"load = array2d(1..", show(n), ", 1..", show(m), ", ", show(load), ");\n",
|
|
"dwell = array2d(1..", show(n), ", 1..", show(m), ", ", show(dwell), ");\n",
|
|
"constraint objective = ", show(objective), ";\n"
|
|
];
|
|
|