! Container routing problem in LINGO;
! We are given a 
  + number of units that must be shipped from i to j each period,
  + the lead time to ship from i to j,
  + the capacity of the containers that carry the units to be shipped.

     The containers must satisfy conservation of flow as they move
  about the system, i.e., they cannot be created or destroyed,
  except in period 1 in which we insert as many containers as
  we wish at each city. A container may physically correspond to 
  whatever the user wishes, e.g., actual containers, trucks, 
  railroad cars, airplanes, etc.
     This is a discrete time model where the unit of time is
  called a "period".  A period could be a hour, a half day,
  a day, etc., whatever the user decides. The model need not 
  know what unit of time the user chose, as long as the user
  is consistent.
     A crucial piece of input data is the travel time matrix.
  It is a matrix of integers specifying how many periods it takes
  a container to be moved from one city to another.
     A variety of objectives are possible. Below we choose
   the objective of minimizing the number of containers needed
   in total;

 ! Keywords: Routing, Container routing, Lead times;
SETS:
  PERIOD;
  CITY: CINIT;
  CXC( CITY, CITY): LT;
  CXCDM( CITY, CITY, PERIOD): DM;
  CXCXP( CITY, CITY, PERIOD): XC;
ENDSETS
DATA: CONCAP = 22; ! Container capacity; PERIOD = 1..6; ! Number of periods we are modeling in this run; CITY = C1 C2 C3 C4; ! Names of the cities; LT = 1 2 2 3 ! Travel time matrix in periods; 2 1 4 2 2 4 1 3 3 2 3 1 ; ! Set of demands to be carried, in the form: From_city, To_city, Period_to_start_Shipment, Units_to_ship; CXCDM DM = C1 C2 1 20 C1 C3 2 31 C1 C4 3 25 C3 C2 1 17 C4 C1 2 18 ; ENDDATA ! Parameters: LT(i,j) = number of periods to move a container from i to j, DM(i,j,t) = number of units of goods that need to be moved from i to j, starting at i in period t, ; ! Variables: XC(i,j,t) = number of containers moved from i to j starting at i in period t, CINIT(i) = number of containers initially at i, ; SUBMODEL MOVEM: ! Minimize the number of containers we need to insert in system at beginning; [OBJ] MIN = @SUM( CITY( i): CINIT(i)); ! Conservation of flow for containers, for every city k in every period t, the number of containers arriving must equal the number of containers departing. Note that the "departure" XC(i,k,t), where k = i, corresponds to the container staying at i in period t; @FOR( CITY(k): ! Period 1 is special; [CONFLO1] CINIT(k) = @SUM( CITY(j): XC(k,j,1)); ! For periods > 1; @FOR( PERIOD(t) | t #GT# 1: ! Incoming containers = outgoing; [CONFLO] @SUM( CXCXP( i, k, t1) | t1 + LT(i,k) #EQ# t: XC(i,k,t1)) = @SUM( CITY(J): XC(k,j,t)); ); ); ! For each shipment we must make, we must assign enough containers, i.e., container_capacity*number_containers >= units_to_be_carried; @FOR( CXCDM( i,j,t): [CAP] CONCAP*XC(i,j,t) >= DM(i,j,t); ); ! Containers moved must be integral; @FOR( CXCXP(i,j,t): @GIN( XC(i,j,t))); ENDSUBMODEL
CALC: @SET( 'TERSEO', 2); ! Set output level to really terse; @SOLVE( MOVEM); ! Solve the submodel; ! Write a little report; @WRITE(' Solution to the container routing problem.', @NEWLINE(1)); @WRITE(' Number containers needed = ', @SUM(CITY(i): CINIT(i)), @NEWLINE(1)); @WRITE(' Initial allocations are: ', @NEWLINE(1)); @FOR( CITY(i) | CINIT(i) #GT# .5: @WRITE(' ',CITY(i),' ', CINIT(i), @NEWLINE(1)); ); @WRITE(@NEWLINE(1),' The container movements are: ', @NEWLINE(1), ' Period From To No. containers', @NEWLINE(1)); @FOR( PERIOD(t): @FOR( CXCXP(i,j,t) | XC(i,j,t) #GT# .5: @WRITE( ' ',@FORMAT(t,'3.0f'),' ', CITY(i),' ', CITY(j),' ', @FORMAT(XC(i,j,t),'4.0f'), @NEWLINE(1)); ); ); ! Optionally, generate an explicit display of the model; ! @WRITE( @NEWLINE(2), ' Here is the explicit model:', @NEWLINE(1)); ! @GEN( MOVEM); ENDCALC