! Given a set of desired flights, figure out how to
route planes to cover these flights.
Repositioning flights are allowed at a cost.
This model illustrate two features:
1) Calendar routines for coordinating the times of
flights involving different locations and time zones,
2) The @INSERT( ) function for creating a derived set
according to fairly arbitrary rules;
! This version considers only flights with aircraft type or fleet
within specified range [ALO, AHI]. Thus, one can show the
economies of scale of combining fleets;
! Keywords:
Airline Routing, Fleet Routing, FTL routing,
Vehicle routing, Airline Scheduling, Fleet Scheduling;
SETS:
CITY: INITA, GMTOFF;
LEG;
CXC( CITY, CITY): TRVTIM;
LODPAIR( LEG, CITY, CITY): Year, Month, Day, Hour, Minute, AType,
DLTIME, Y, PLFLAG;
RLEG;
RPAIR( RLEG, CITY, CITY): DRTIME, U;
DOW /SUN..SAT/;
ENDSETS DATA:
City, GMTOFF = ! Cities and their offset in hours from GMT;
Chicago -6 ! Chicago is 6 hours behind Greenwich Mean Time;
Salt_Lake_City -7
Los_Angeles -8
Phoenix -7
Las_Vegas -8
Tucson -7;
LEG = 1..7;
! Get data of each loaded candidate Origin-Destination (OD) pair;
LODPAIR, Year, Month, Day, Hour, Minute, AType =
! Origin Destination Departure time Aircraft
LEG City City Year Month Day Hour Minute Type;
1 Los_Angeles Salt_Lake_City 2012 10 20 11 0 3
2 Salt_Lake_City Phoenix 2012 10 24 16 20 2
3 Salt_Lake_City Los_Angeles 2012 10 25 16 0 1
4 Salt_Lake_City Las_Vegas 2012 10 26 16 0 5
5 Las_Vegas Salt_Lake_City 2012 10 28 12 0 5
6 Tucson Salt_Lake_City 2012 10 28 13 0 2
7 Chicago Las_Vegas 2012 10 22 10 30 1
;
! Get travel time matrix in minutes;
TRVTIM =
0 190 240 205 215 195 ! Chicago;
190 0 110 100 85 120 ! Salt_Lake_City;
240 110 0 120 120 120 ! Los_Angeles;
205 100 120 0 85 60 ! Phoenix;
215 85 120 85 0 95 ! Las_Vegas;
195 120 120 60 95 0 ;! Tucson;
RLEG = 1..1000; ! Possible number of repositioning legs;
VL = 1; ! Relative value of covering a loaded flight;
RP = .01; ! Relative cost of a repositioning flight;
RA = .95; ! Relative cost of an aircraft;
ALO = 1; ! Lower limit on aircraft type considered;
AHI = 5; ! Upper limit on aircraft type considered;
ENDDATA
! Variables:
Y(n,d,a) = 1 if load carrying flight n is flown from d to a,
U(n,d,a) = 1 if repositioning flight n is flown from d to a;
SUBMODEL ROUTEM:
! Maximize number of requested flights flown(covered)
- cost of repositioning flights
- cost of aircraft;
MAX = VL*@SUM( LODPAIR( n, d, a) |(ALO #LE# ATYPE(n,d,a)
#AND# ATYPE(n,d,a) #LE# AHI) : Y(n,d,a)) ! Loaded flights;
- RP*@SUM( RPAIR( n, d, a): U(n,d,a)) ! Repositions;
- RA*@SUM( CITY(i): INITA(i)); ! Initial AC at city i;
! You either fly it or you do not;
@FOR( LODPAIR( n, d, a): @BIN(Y(n,d,a)));
@FOR( RPAIR( n, d, a): @BIN(U(n,d,a)));
! For every departing loaded flight from d to a at time DLTIME,
the number of earlier arrivals - earlier departures must be >= Y(n,d,a);
@FOR( LODPAIR( n, d, a) |(ALO #LE# ATYPE(n,d,a) #AND# ATYPE(n,d,a) #LE# AHI) :
[LFLO] INITA(d)
+ @SUM( LODPAIR( n1, d1, d) | DLTIME(n1,d1,d) + TRVTIM(d1,d)/60 #LE# DLTIME(n,d,a)
#AND# (ALO #LE# ATYPE(n1,d1,d) #AND# ATYPE(n1,d1,d) #LE# AHI):
Y(n1,d1,d)) ! Loaded flights arriving earlier;
+ @SUM( RPAIR( n1, d1, d) | DRTIME(n1,d1,d) + TRVTIM(D1,d)/60 #LE# DLTIME(n,d,a):
U(n1,d1,d)) ! Repositioning flights arriving earlier;
- @SUM(LODPAIR(n1,d,a1) | DLTIME(n1,d,a1) #LT# DLTIME(n,d,a)
#AND# (ALO #LE# ATYPE(n1,d,a1) #AND# ATYPE(n1,d,a1) #LE# AHI):
Y(n1,d,a1)) ! Loaded flights departing earlier;
- @SUM( RPAIR(n1,d,a1) | DRTIME(n1,d,a1) #LE# DLTIME(n,d,a):
U(n1,d,a1)) ! Repositioning flights departing earlier;
>= Y(n,d,a); ! Loaded flight departing at time DLTIME(n,d,a);
);
! For every departing repositioning flight from d to a at time DRTIME,
the number of earlier arrivals - earlier departures must be >= U(n,d,a);
@FOR( RPAIR( n, d, a):
[RFLO] INITA(d)
+ @SUM( LODPAIR( n1, d1, d) | DLTIME(n1,d1,d) + TRVTIM(d1,d)/60 #LE# DRTIME(n,d,a)
#AND# (ALO #LE# ATYPE(n1,d1,d) #AND# ATYPE(n1,d1,d) #LE# AHI) :
Y(n1,d1,d)) ! Loaded flights arriving earlier;
+ @SUM( RPAIR( n1, d1, d) | DRTIME(n1,d1,d) + TRVTIM(d1,d)/60 #LE# DRTIME(n,d,a):
U(n1,d1,d)) ! Repositioning flights arriving earlier;
- @SUM(LODPAIR(n1,d,a1) | DLTIME(n1,d,a1) #LE# DRTIME(n,d,a)
#AND# (ALO #LE# ATYPE(n1,d,a1) #AND# ATYPE(n1,d,a1) #LE# AHI) :
Y(n1,d,a1)) ! Loaded flights departing earlier;
- @SUM( RPAIR(n1,d,a1) | a1 #NE# a #AND# (DRTIME(n1,d,a1) #LE# DRTIME(n,d,a)):
U(n1,d,a1)) ! Repositioning flights departing earlier;
>= U(n,d,a); ! Repositioning flight departing at time DRTIME(n,d,a);
);
ENDSUBMODEL
CALC:
! Convert Year, Month, Day, Hour, Minute, Second(n,d,a) to a scalar DLTIME(n,d,a)
in hours so we can do simple comparisons and arithmetic;
! Compute departure time in scalar GMT time for each loaded flight;
@FOR( LODPAIR( n, d, a):
DLTIME(n,d,a) = @YMD2STM( Year(n,d,a), Month(n,d,a), Day(n,d,a) , Hour(n,d,a), Minute(n,d,a), 0)
- GMTOFF(d); ! Take into account local time;
);
! Construct the set of candidate repositioning legs. For each departing
flight from city j, we add a candidate repositioning leg from every
other city j, j #NE# i, at TRVTIM(i,j) minutes earlier ;
k = 0;
@FOR( LODPAIR( n, j, a) |(ALO #LE# ATYPE(n,j,a) #AND# ATYPE(n,j,a) #LE# AHI) :
@FOR( CITY(i) | i #NE# j:
k = k+1;
@INSERT( RPAIR, k, i, j);
! Note, travel times are in minutes, scalar time in hours;
DRTIME(k,i,j) = DLTIME(n,j,a) - TRVTIM(i,j)/60;
);
);
! @GEN( ROUTEM); @SOLVE( ROUTEM);
@WRITE(' Value/flight covered= ',VL,@NEWLINE(1),
' Relative cost/repositioning= ',RP,@NEWLINE(1),' Relative cost/aircraft= ',RA,@NEWLINE(1));
@WRITE(@NEWLINE(1),' Number flights covered= ',
@SUM(LODPAIR(n,d,a)| Y(n,d,a) #GT# 0.5 #AND# (ALO #LE# ATYPE(n,d,a) #AND# ATYPE(n,d,a) #LE# AHI) :1),
' (of ',
@SUM(LODPAIR(n,d,a) |(ALO #LE# ATYPE(n,d,a) #AND# ATYPE(n,d,a) #LE# AHI) :1),')',@NEWLINE(1));
@WRITE(' Number aircraft used= ',@SUM(CITY(i):INITA(I)),@NEWLINE(1));
@WRITE(' Fleets used: ',ALO,' to ',AHI,@NEWLINE(1));
@WRITE(@NEWLINE(1),' Initial Aircraft Positions:',@NEWLINE(1),
' # Aircraft City', @NEWLINE(1));
@FOR( CITY(i)| INITA(i) #GT# 0.5:
@WRITE(' ', @FORMAT(INITA(i),'3.0f'), ' ', CITY(i),@NEWLINE(1));
);
@WRITE(@NEWLINE(1),' Load carrying flights: Depart at (local time)',@NEWLINE(1));
@WRITE(' Origin Destination yyyy mm dd hh mm dwk',@NEWLINE(1));
! A while loop to print the legs used, sorted by DLTIME;
@FOR( LODPAIR( n, d, a): PLFLAG(n,d,a) = 1); ! PLFLAG = 0 if already printed;
MORE = 1;
@WHILE(MORE:
MORE = 0;
CTIME = 9999999999;
@FOR( LODPAIR( n, d, a) | PLFLAG(n,d,a) #AND# (Y(n,d,a) #GT# 0.5)
#AND# (ALO #LE# ATYPE(n,d,a) #AND# ATYPE(n,d,a) #LE# AHI) :
CTEMP = DLTIME(n,d,a);
@IFC( CTEMP #LT# CTIME:
MORE = 1;
CTIME = CTEMP;
nsv=n; dsv=d; asv=a;
);
);
@IFC( MORE:
PLFLAG(nsv,dsv,asv) = 0;!
Begin code to ... Convert DLTIME(n,d,a) back to year, month, day, hour, minute;
CTIME = CTIME + GMTOFF(dsv); ! Take into account local time;
IYR = @STM2YR( CTIME); ! Get the year;
IMON = @STM2MON( CTIME); ! Get the month of the year;
IDAY = @STM2DAY( CTIME); ! Get day of month;
IHR = @STM2HR( CTIME); ! Get the hour of the day;
IMIN = @STM2MIN( CTIME); ! Get the minute of the hour;
IWKD = @STM2DWK( CTIME); ! Get the day of the week;
! End of code to convert to year, month,...;
@WRITE( @FORMAT(CITY(dsv),'18s'),' ',@FORMAT(CITY(asv),'18s'),' ',IYR,' ',
IMON,' ',@FORMAT(IDAY,'2.0F'),' ',@FORMAT(IHR,'2.0F'),' ',@FORMAT(IMIN,'2.0F'),' ',DOW(IWKD),@NEWLINE(1));
);
);
@WRITE(@NEWLINE(1),' Repositioning Flights:',@NEWLINE(1));
@FOR( RPAIR( n, d, a) | U(n,d,a) #GT# 0.5:
! Begin code to ... ;
! Convert DRTIME(n,d,a) back to year month, day, hour, minute;
CTIME = DRTIME(n,d,a)+ GMTOFF(d); ! Take into account local time;
IYR = @STM2YR( CTIME); ! Get the year;
IMON = @STM2MON( CTIME); ! Get the month of the year;
IDAY = @STM2DAY( CTIME); ! Get day of month;
IHR = @STM2HR( CTIME); ! Get the hour of the day;
IMIN = @STM2MIN( CTIME); ! Get the minute of the hour;
IWKD = @STM2DWK( CTIME); ! Get the day of the week;
! End of convert code;
@WRITE( @FORMAT(CITY(d),'18s'),' ',@FORMAT(CITY(a),'18s'),' ',IYR,' ',
IMON,' ',@FORMAT(IDAY,'2.0F'),' ',@FORMAT(IHR,'2.0F'),' ',@FORMAT(IMIN,'2.0F'),' ',DOW(IWKD),@NEWLINE(1));
);
ENDCALC
|