1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.

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"
];