! Job to Machine Assignment and Sequencing. (MachAsgSeq)
A number of jobs (trucks, airplanes, patients, ...)
arrive over time at a facility (terminal, hospital...).
A job cannot be started before its arrival time.
Each job has a due date by which its processing must be finished.
The facility has a number of docks or machines, or operating rooms.
Each machine can handle at most one job at a time.
For each job and machine combination, there is a
value of this assignment, as well as a
processing time of the job on the specific machine.
   We would like to assign jobs to machines, and find
 a sequence of jobs on each machine so that
 at most one job is assigned to a specific machine
 at a specific instance, and
 there is very little delay, and
 the value of the assignments is maximized;
! Examples are: Assigning airplanes to gates at an airport,
assigning trucks to docks at a freight terminal, 
hotel guests to hotel rooms, surgical procedures to operating rooms,
and manufacturing jobs to machines in a factory.
  An extension, not considered here, is to allow a
job to finish after its due date (be tardy), at a penalty;

! Keywords: Assignment, Gate assignment, Dock assignment, 
  Sequencing, Machine Assignment, Task assignment, Scheduling,
  Operating Room Assignment;

SETS:
  JOB: ARVT, DD;
  MACH;
  TSLOT;
  MXJ( MACH, JOB) : PT, VAL;
  MXT( MACH, TSLOT): IDLE;
ENDSETS
! Parameters: ARVT(j) = arrival or available time of job j, the first period in which j can be processed, PT(m,j) = processing time/number periods needed on machine m of job j, VAL(m,j) = value or profit of assigning job j to machine m, DD(j) = due date for job j, e.g., if DD(j) = 10, must finish in 9 or less; ! This formulation assumes ARVT, DD, and PT are integers; ! Variables: Z(m,t,j) = 1 if job j is assigned to machine m starting during time slot t, IDLE(m,t) = 1 if machine m is idle during period t; DATA: TSLOT = 1..40; ! Assume at most 30 minutes in horizon, should be >= max DD; SFWGT = 0.001; ! Weight applied to minimizing sum of completion times; JOB = J1..J20; MACH = A B C D; ! Arrival time or first period in which task can be started; ! 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; ARVT = 2 1 2 1 1 4 7 8 8 11 8 9 21 9 11 3 6 12 17 22; ! Last processing of a job must be in a period < DD(j); DD = 13 15 11 11 15 14 27 20 18 17 19 24 28 31 32 9 14 19 23 35; ! Processing time of tasks on machines; PT = 4 8 5 6 4 3 2 3 5 4 6 5 6 8 6 4 5 6 4 9 ! Mach 1; 5 9 7 7 5 5 1 3 5 5 7 6 7 9 10 5 3 7 6 10 ! Mach 2; 6 9 8 7 5 6 3 3 6 5 7 7 7 9 9 6 7 6 5 11 ! Mach 3; 5 9 8 7 5 5 2 3 4 6 8 8 8 10 5 6 7 7 6 12;! Mach 4; ! Value of doing a specific job on a specific machine; VAL = 5 8 7 7 6 5 2 1 9 6 4 3 4 6 8 9 9 7 5 6! Mach 1; 6 9 7 7 6 5 3 3 9 7 6 6 6 8 9 7 5 8 3 3! Mach 2; 6 9 7 8 7 5 2 4 9 8 7 7 8 8 9 3 4 5 4 7! Mach 3; 1 4 2 5 9 7 4 5 3 8 3 2 5 9 4 3 3 5 8 9;!Mach 4; ENDDATA SETS: ! Key observation: job j can be assigned to/started in time slot t only if ( (ARVT( j) #LE# t) #AND# t + PT(m,j) #LE# DD(j) ) ; MXTXJ( MACH, TSLOT, JOB) | ( ARVT( &3) #LE# &2) #AND# ( &2 + PT(&1,&3) #LE# DD(&3) ) : Z, FLAG; ENDSETS
SUBMODEL ASGSEQ: ! Maximize the value of the assignments; MAX = OBJVALA - SFWGT* SUMFIN; OBJVALA = @SUM( MXTXJ(m,t,j) : VAL(m,j)*Z(m,t,j)); ! Compute sum of finish times; SUMFIN = @SUM( MXTXJ(m,t,j): (t+PT(m,j))*Z(m,t,j)); ! Each job must be assigned to at most one machine; @FOR( JOB( j): [CANDO] @SUM( MXTXJ(m,t,j): Z(m,t,j)) <= 1; ); ! At most one job can be active on machine m at timeslot t, for t not in an obviously idle period; ! Every machine starts idle before 1st period and remains idle or gets some work; @FOR( MACH( m): [JUST1] 1 = IDLE(m,TSTRT) + @SUM( MXTXJ(m,t,j) | t #EQ# TSTRT: Z(m,t,j)) ; ); ! For subsequent periods, in period t-1 (the LHS), if the machine is either: a)idle, or b)not idle but some job finishes, then in period t (the RHS) the machine will be either: a) idle, or b) starts a new task; @FOR( TSLOT(t) | t #GT# TSTRT #AND# t #LE# TENDT : @FOR( MACH( m): [JUSTN] IDLE(m,t-1) + @SUM( JOB(j) | (ARVT(j) #LE# t-PT(m,j)) #AND# t #LE# DD(j): Z(m,t-PT(m,j),j)) = IDLE(m,t) + @SUM( JOB(j) | ( ARVT( j) #LE# t) #AND# ( t + PT(m,j) #LE# DD(j)) : Z(m,t,j)); ); !@FOR( MACH; ); ! @FOR(TSLOT; ! The 0/1 variables; @FOR( MXTXJ(m,t,j): @BIN( Z(m,t,j)); ); ENDSUBMODEL
CALC: ! @SET( "TERSEO", 2); ! Get the start and end of the interesting periods; TSTRT = @MIN( JOB(j): ARVT(j)); TENDT = @MAX( JOB(j): DD(j)); TSTART = @TIME(); @SOLVE( ASGSEQ); ! Solve assignment and sequencing problem; TEND = @TIME(); ! Display a short report; ! Sort the report by MACH, Start time; ! Set FLAG(m,t,j) = 1 for items still needed to print; @WRITE(' Number jobs assigned= ',@SUM(MXTXJ(m,t,j) | Z(m,t,j) #GT# 0.5: 1), ', out of ',@SIZE(JOB), @NEWLINE(1)); @FOR( MXTXJ(m,t,j): @IFC( Z(m,t,j) #GT# 0.5: FLAG(m,t,j) = 1; @ELSE FLAG(m,t,j) = 0; ); ); @WRITE('Value of job assignments= ', OBJVALA, @NEWLINE(1)); @WRITE('Sum of finish times= ', SUMFIN, @NEWLINE(2)); @WRITE(' Mach- Ready Start Finish Due',@NEWLINE(1)); @WRITE(' ine Job time time time time', @NEWLINE(1)); MORE = 1; ! = 0 when no more lines to print; @WHILE( MORE: ! Find the lexico smallest (machine, Start time) remaining to print; ms = 1 + @SIZE( JOB); ts = 1 + @SIZE(TSLOT); MORE = 0; @FOR( MXTXJ(m,t,j) | FLAG(m,t,j): @IFC( m #EQ# ms #AND# t #LT# ts: ts = t; ! New smaller start time, same machine; js = j; MORE = 1; ); @IFC( m #LT# ms: ms = m; ! New smaller machine; ts = t; js = j; MORE = 1; ); ); @IFC( MORE: ! Did we find another line to print?; @WRITE( ' ', @FORMAT( MACH(ms), '5s')); @WRITE( ' ',@FORMAT( JOB(js), '5s'),' ', @FORMAT(ARVT(js),'4.0F'), ' ', @FORMAT(ts,'4.0f'), ' ', @FORMAT(ts+PT(ms,js),'4.0F'), ' ', @FORMAT(DD(js),'4.0F'), @NEWLINE(1)); FLAG( ms, ts, js) = 0; ! This line is done; ); ); @WRITE(@NEWLINE(1), ' Total solve time= ', @FORMAT(TEND-TSTART,'10.2f'),' seconds.',@NEWLINE(1)); ENDCALC