from IPython.core.display import HTML HTML(open("styles/custom.css", "r").read()) %%writefile Bottleneck.mod /* Machine Bottleneck Example */ set JOBS; param rel{JOBS} default 0; # Time a job is available to the machine param dur{JOBS}; # Job duration param due{JOBS}; # Job due time /* Data Checks */ check {k in JOBS}: rel[k] + dur[k] <= due[k]; /* The model uses a 'Big M' implementation of disjunctive constraints to avoid conflicts for a single machine. Big M should be larger than the longest time horizon for the completion of all jobs. A bound on the longest horizon is the maximum release plus the sum of durations for all jobs. */ param BigM := (max {k in JOBS} rel[k] ) + sum{k in JOBS} dur[k]; /* Decision variables are the start times for each job, and a disjunctive variable y[j,k] which is 1 if job j precedes job k on the machine. */ var start{JOBS} >= 0; var pastdue{JOBS} >= 0; var y{JOBS,JOBS} binary; /* There are many possible objectives, including total pastdue, maximum pastdue (i.e., tardiness), number of jobs pastdue. */ minimize OBJ : sum {k in JOBS} pastdue[k]; /* Order Constraints */ s.t. START {k in JOBS}: start[k] >= rel[k]; s.t. FINIS {k in JOBS}: start[k] + dur[k] <= due[k] + pastdue[k]; /* Machine Conflict Constraints */ s.t. DA {j in JOBS, k in JOBS : j < k}: start[j] + dur[j] <= start[k] + BigM*(1-y[j,k]); s.t. DB {j in JOBS, k in JOBS : j < k}: start[k] + dur[k] <= start[j] + BigM*y[j,k]; solve; /* Create Tables */ table tout {k in JOBS} OUT "CSV" "Schedule.csv" "table": k~Job, rel[k]~Release, start[k]~Start, start[k]+dur[k]~Finish, due[k]~Due; /* Print Report */ printf " Task Rel Dur Due Start Finish Pastdue\n"; printf {k in JOBS} "%5s %7g %7g %7g %7g %7g %7g\n", k,rel[k],dur[k],due[k],start[k],start[k]+dur[k],pastdue[k]; end; %%script glpsol -m Bottleneck.mod -d /dev/stdin -y results.txt --out output param: JOBS : rel dur due := A 2 5 10 B 5 6 21 C 4 8 15 D 0 4 10 E 0 2 5 F 8 3 15 G 9 2 22 ; end; print(open('results.txt').read()) import pandas pandas.read_csv("Schedule.csv")