RAS2012 / dispatching.mod

# models of RAS 2012 problem

param M := 1440;
param L := 1000;
# define a graph
param N;    # number of nodes
set V := 0..N-1;
set E within {r in V, s in V: r < s};
set W := {r in V, s in V: (s,r) in E};
set A := E union W;
# MOW window
set F within E;
param mowstart {F};
param mowend {F};
# train parameters
set T;  # set of trains
param trainname {T} symbolic;
param traintype {T} symbolic;
param entrytime {T};
param orig {T};
param dest {T};
param traindir {T} symbolic;
param speedmult {T};
param trainleng {T};
param tonage {T};
param hazard {T};
param initdelay {T};
param termtime {T};
param twtstart {i in T} := termtime[i] - 60;
param twtend {i in T} := termtime[i] + 180;
param schedtime {T,V};
set I := {i in T: traindir[i] == "EASTBOUND"};
set J := {i in T: traindir[i] == "WESTBOUND"};
# track parameters
param maxspeedeast;
param maxspeedwest;
param maxspeedsl;
param maxspeedsw;
param tracktype {(r,s) in E} symbolic;
param trackleng {(r,s) in E};
param trainspeed {i in T, (r,s) in E} :=
     if tracktype[r,s] == "0"  then 1/60 * speedmult[i] * maxspeedeast
else if tracktype[r,s] == "S"  then 1/60 * speedmult[i] * maxspeedsl
else if tracktype[r,s] == "SW" then 1/60 * speedmult[i] * maxspeedsw;

# if i immediately precedes j on track (r,s)
var x {i in T, j in T, (r,s) in E: i <> j} binary;
# if i travel from r to s on track (r,s)
var f {i in T, (r,s) in A: i in I and (r,s) in E or i in J and (r,s) in W} binary;
# if i uses track (r,s) in E
var y {i in T, (r,s) in E} binary;
# if i go through track (r,s) before MOW
var g {i in T, (r,s) in F} binary;
# the arrival time on track (r,s)
var a {i in T, (r,s) in E} >= 0;
# the departure time on track (r,s)
var d {i in T, (r,s) in E} >= 0;
# the waiting time on track (r,s)
var b {i in T, (r,s) in E} >= 0;

# terminal want time deviance
set LAST := {i in T, (r,s) in E: dest[i] == s and i in I or dest[i] == r and i in J};
var early {LAST} >= 0;
var late  {LAST} >= 0;

# objective
minimize total_cost:
    # universal delay cost
    sum {i in T, (r,s) in E} b[i,r,s] + 
    # terminal want time deviance
    sum {(i,r,s) in LAST} 75/60 * (early[i,r,s] + late[i,r,s]);

# flow conservation constraints
s.t. flow_cons_east {i in I, n in V: n <> orig[i] and n <> dest[i]}: 
    sum {(r,s) in E: s == n} f[i,r,s] = sum {(u,v) in E: u == n} f[i,u,v];
s.t. flow_orig_east {i in I}: sum {(r,s) in E: r == orig[i]} f[i,r,s] = 1;
s.t. flow_dest_east {i in I}: sum {(r,s) in E: s == dest[i]} f[i,r,s] = 1;
s.t. flow_cons_west {j in J, n in V: n <> orig[j] and n <> dest[j]}: 
    sum {(r,s) in W: s == n} f[j,r,s] = sum {(u,v) in W: u == n} f[j,u,v];
s.t. flow_orig_west {j in J}: sum {(r,s) in W: r == orig[j]} f[j,r,s] = 1;
s.t. flow_dest_west {j in J}: sum {(r,s) in W: s == dest[j]} f[j,r,s] = 1;
# toal track flow
s.t. flow_total_east {i in I, (r,s) in E}: y[i,r,s] = f[i,r,s];
s.t. flow_total_west {i in J, (r,s) in E}: y[i,r,s] = f[i,s,r];
# traffic flow and order
s.t. flow_row {j in T, (r,s) in E}: sum {i in T: i <> j} x[i,j,r,s] <= y[j,r,s];
s.t. flow_col {j in T, (r,s) in E}: sum {k in T: k <> j} x[j,k,r,s] <= y[j,r,s];
s.t. flow_sum {(r,s) in E}: 
    sum {i in T, j in T: i <> j} x[i,j,r,s] = sum {k in T} y[k,r,s] - 1;
# kinetic equations
s.t. link_latency {i in T, (r,s) in E}: 
    d[i,r,s] - a[i,r,s] = trackleng[r,s]/trainspeed[i,r,s];
s.t. node_latency {i in T, (r,s) in E, (u,v) in E: u == s}: 
    a[i,u,v] - d[i,r,s] - (y[i,r,s] + y[i,u,v] - 2) * M >= 0;
s.t. wait_lower {i in T, (r,s) in E, (u,v) in E: u == s}: 
    a[i,u,v] - d[i,r,s] + (y[i,r,s] + y[i,u,v] - 2) * M <= b[i,r,s];
s.t. wait_upper {i in T, (r,s) in E, (u,v) in E: u == s}: 
    a[i,u,v] - d[i,r,s] - (y[i,r,s] + y[i,u,v] - 2) * M >= b[i,r,s];
# block signal sections
# var mileage {I,A};
# s.t. train_mileage {i in I, (s,t) in A, r in V: (r,s) in A}: 
#     mileage[i,s,t] = mileage[i,r,s] + trackleng[s,t] * y[i,s,t];
# mileage[i,v] > mileage[i,s]
# mileage[i,v] < mileage[i,s] + trainleng[i]
s.t. train_control {i in T, j in T, (r,s) in E: i <> j}: 
    d[i,r,s] + trainleng[i] / trainspeed[i,r,s] <= a[j,r,s] + (1 - x[i,j,r,s]) * M;
# Maintenance of Way (MOW) track window
s.t. mow_early {i in T, (r,s) in F}: d[i,r,s] <= mowstart[r,s] + (1 - g[i,r,s]) * M;
s.t. mow_later {i in T, (r,s) in F}: a[i,r,s] >= mowend[r,s] - g[i,r,s] * M;
# Terminal Want Time (TWT) deviance
s.t. terminal_early {(i,r,s) in LAST}: early[i,r,s] >= twtstart[i] - a[i,r,s] - (1 - y[i,r,s]) * M;
s.t. terminal_late  {(i,r,s) in LAST}: late[i,r,s]  >= a[i,r,s] - twtend[i] - (1 - y[i,r,s]) * M;
# entry time
s.t. entry_time_east {i in I, (r,s) in E: r == orig[i]}: a[i,r,s] >= entrytime[i];
s.t. entry_time_west {i in J, (r,s) in W: r == orig[i]}: a[i,s,r] >= entrytime[i];
# long train and sliding track
s.t. long_train {i in I, (r,s) in E: tracktype[r,s] == "S"}: 
    trackleng[r,s] >= trainleng[i] - (1 - y[i,r,s]) * L;