Resource-Constrained Scheduling Problem
/***************************************************************/
/* */
/* S A S S A M P L E L I B R A R Y */
/* */
/* NAME: clpe16 */
/* TITLE: Resource-Constrained Scheduling Problem */
/* with Nonstandard Temporal Constraints (clpde16) */
/* PRODUCT: OR */
/* SYSTEM: ALL */
/* KEYS: OR */
/* PROCS: CLP */
/* DATA: */
/* */
/* SUPPORT: UPDATE: */
/* REF: */
/* MISC: Example 16 from the CLP Procedure chapter of the */
/* Constraint Programming book. */
/* */
/***************************************************************/
data bridge;
format _ACTIVITY_ $3. _DESC_ $34. _RESOURCE_ $14.
_SUCCESSOR_ $3. _LAG_ $3. ;
input _ACTIVITY_ & _DESC_ & _DURATION_ _RESOURCE_ &
_SUCCESSOR_ & _LAG_ & _LAGDUR_;
_QTY_ = 1;
datalines;
a1 excavation (abutment 1) 4 excavator s1 . .
a2 excavation (pillar 1) 2 excavator s2 . .
a3 excavation (pillar 2) 2 excavator p1 . .
a4 excavation (pillar 3) 2 excavator p2 . .
a5 excavation (pillar 4) 2 excavator s5 . .
a6 excavation (abutment 2) 5 excavator s6 . .
ab1 concrete setting time (abutment 1) 1 . m1 . .
ab2 concrete setting time (pillar 1) 1 . m2 . .
ab3 concrete setting time (pillar 2) 1 . m3 . .
ab4 concrete setting time (pillar 3) 1 . m4 . .
ab5 concrete setting time (pillar 4) 1 . m5 . .
ab6 concrete setting time (abutment 2) 1 . m6 . .
b1 concrete foundation (abutment 1) 1 concrete mixer ab1 . .
b1 concrete foundation (abutment 1) 1 concrete mixer s1 ff -4
b2 concrete foundation (pillar 1) 1 concrete mixer ab2 . .
b2 concrete foundation (pillar 1) 1 concrete mixer s2 ff -4
b3 concrete foundation (pillar 2) 1 concrete mixer ab3 . .
b3 concrete foundation (pillar 2) 1 concrete mixer s3 ff -4
b4 concrete foundation (pillar 3) 1 concrete mixer ab4 . .
b4 concrete foundation (pillar 3) 1 concrete mixer s4 ff -4
b5 concrete foundation (pillar 4) 1 concrete mixer ab5 . .
b5 concrete foundation (pillar 4) 1 concrete mixer s5 ff -4
b6 concrete foundation (abutment 2) 1 concrete mixer ab6 . .
b6 concrete foundation (abutment 2) 1 concrete mixer s6 ff -4
l delivery of the preformed bearers 2 crane t1 . .
l delivery of the preformed bearers 2 crane t2 . .
l delivery of the preformed bearers 2 crane t3 . .
l delivery of the preformed bearers 2 crane t4 . .
l delivery of the preformed bearers 2 crane t5 . .
m1 masonry work (abutment 1) 16 bricklaying t1 . .
m1 masonry work (abutment 1) 16 bricklaying ua fs -2
m2 masonry work (pillar 1) 8 bricklaying t1 . .
m2 masonry work (pillar 1) 8 bricklaying t2 . .
m2 masonry work (pillar 1) 8 bricklaying ua fs -2
m3 masonry work (pillar 2) 8 bricklaying t2 . .
m3 masonry work (pillar 2) 8 bricklaying t3 . .
m3 masonry work (pillar 2) 8 bricklaying ua fs -2
m4 masonry work (pillar 3) 8 bricklaying t3 . .
m4 masonry work (pillar 3) 8 bricklaying t4 . .
m4 masonry work (pillar 3) 8 bricklaying ua fs -2
m5 masonry work (pillar 4) 8 bricklaying t4 . .
m5 masonry work (pillar 4) 8 bricklaying t5 . .
m5 masonry work (pillar 4) 8 bricklaying ua fs -2
m6 masonry work (abutment 2) 20 bricklaying t5 . .
m6 masonry work (abutment 2) 20 bricklaying ua fs -2
p1 foundation piles 2 20 pile driver s3 . .
p2 foundation piles 3 13 pile driver s4 . .
pa beginning of project 0 . a1 . .
pa beginning of project 0 . a2 . .
pa beginning of project 0 . a3 . .
pa beginning of project 0 . a4 . .
pa beginning of project 0 . a5 . .
pa beginning of project 0 . a6 . .
pa beginning of project 0 . l fse 30
pa beginning of project 0 . ue . .
pe end of project 0 . . . .
s1 formwork (abutment 1) 8 carpentry b1 . .
s1 formwork (abutment 1) 8 carpentry a1 sf -3
s2 formwork (pillar 1) 4 carpentry b2 . .
s2 formwork (pillar 1) 4 carpentry a2 sf -3
s3 formwork (pillar 2) 4 carpentry b3 . .
s3 formwork (pillar 2) 4 carpentry p1 sf -3
s4 formwork (pillar 3) 4 carpentry b4 . .
s4 formwork (pillar 3) 4 carpentry p2 sf -3
s5 formwork (pillar 4) 4 carpentry b5 . .
s5 formwork (pillar 4) 4 carpentry a5 sf -3
s6 formwork (abutment 2) 10 carpentry b6 . .
s6 formwork (abutment 2) 10 carpentry a6 sf -3
t1 positioning (preformed bearer 1) 12 crane v1 . .
t2 positioning (preformed bearer 2) 12 crane pe . .
t3 positioning (preformed bearer 3) 12 crane pe . .
t4 positioning (preformed bearer 4) 12 crane pe . .
t5 positioning (preformed bearer 5) 12 crane v2 . .
ua removal of the temporary housing 10 . pe . .
ue erection of temporary housing 10 . . . .
ue erection of temporary housing 10 . s1 ss 6
ue erection of temporary housing 10 . s2 ss 6
ue erection of temporary housing 10 . s3 ss 6
ue erection of temporary housing 10 . s4 ss 6
ue erection of temporary housing 10 . s5 ss 6
ue erection of temporary housing 10 . s6 ss 6
v1 filling 1 15 caterpillar pe . .
v2 filling 2 10 caterpillar pe . .
;
%macro resources;
proc sql;
create table bridge2 as
select a.*, b._duration_ as bdur from
bridge a left join bridge b
on a._SUCCESSOR_ = b._ACTIVITY_;
quit;
proc sort data=bridge2 nodup;
by _ACTIVITY_ _RESOURCE_ _SUCCESSOR_ _LAG_ _DURATION_ _LAGDUR_ _QTY_ bdur;
run;
proc sql noprint;
select count(distinct(_RESOURCE_)) into :rescnt from bridge
where _RESOURCE_ is not null;
select distinct(_RESOURCE_) into :res_1-:res_%eval(&rescnt.)
from bridge where _RESOURCE_ is not null;
create table resources as
select distinct _ACTIVITY_, _RESOURCE_, _DURATION_ from bridge;
quit;
%do i = 1 %to &rescnt.;
proc sql noprint;
select count(*)
into :actcnt_%eval(&i.)
from resources where _RESOURCE_ eq "&&res_&i..";
select _ACTIVITY_
into :act_%eval(&i.)_1-:act_%eval(&i.)_%eval(&&actcnt_&i..)
from resources where _RESOURCE_ eq "&&res_&i..";
select _DURATION_
into :dur_%eval(&i.)_1-:dur_%eval(&i.)_%eval(&&actcnt_&i..)
from resources where _RESOURCE_ eq "&&res_&i..";
quit;
%end;
%let makespan = 104; /* should be 104 with cumulative included */
data _NULL_;
set bridge2 end=lastobs;
retain start 1;
if start then do;
start = 0;
call execute('data condata; format _TYPE_ $3.;');
end;
if missing(_SUCCESSOR_) then do;
end;
else if _LAG_ eq '' then do;
call execute('_TYPE_ = "GE";');
call execute('_RHS_ = ' || _DURATION_ || ';');
call execute(_SUCCESSOR_ || ' = 1;');
call execute(_ACTIVITY_ || ' = -1;');
end;
else if _LAG_ eq 'ff' then do;
call execute('_TYPE_ = "GE";');
call execute('_RHS_ = ' || (_LAGDUR_ + _DURATION_ - bdur) || ';');
call execute(_SUCCESSOR_ || ' = 1;');
call execute(_ACTIVITY_ || ' = -1;');
end;
else if _LAG_ eq 'fs' then do;
call execute('_TYPE_ = "GE";');
call execute('_RHS_ = ' || (_LAGDUR_ + _DURATION_) || ';');
call execute(_SUCCESSOR_ || ' = 1;');
call execute(_ACTIVITY_ || ' = -1;');
end;
else if _LAG_ eq 'fse' then do;
call execute('_TYPE_ = "EQ";');
call execute('_RHS_ = ' || (_LAGDUR_ + _DURATION_) || ';');
call execute(_SUCCESSOR_ || ' = 1;');
call execute(_ACTIVITY_ || ' = -1;');
end;
else if _LAG_ eq 'sf' then do;
call execute('_TYPE_ = "GE";');
call execute('_RHS_ = ' || (_LAGDUR_ - bdur) || ';');
call execute(_SUCCESSOR_ || ' = 1;');
call execute(_ACTIVITY_ || ' = -1;');
end;
else if _LAG_ eq 'ss' then do;
call execute('_TYPE_ = "GE";');
call execute('_RHS_ = ' || _LAGDUR_ || ';');
call execute(_SUCCESSOR_ || ' = 1;');
call execute(_ACTIVITY_ || ' = -1;');
end;
if (_SUCCESSOR_ ne '') then do;
call execute('output;');
call execute(_SUCCESSOR_ || '=.; ');
call execute(_ACTIVITY_ || '=.; _TYPE_ = ""; _RHS_ = .;');
end;
if lastobs then do;
call execute('pe=1;_TYPE_="MIN";_RHS_=.;output;');
call execute('run;');
end;
run;
%mend resources;
%resources;
proc clp condata=condata varselect=wdeg out=out usecondatavars=1;
obj lb=0 ub=2000;
cumulative (start=( m1-m6 ) dur=( 16 8 8 8 8 20 ))
(start=( s1-s6 ) dur=( 8 4 4 4 4 10 ))
(start=( v1 v2 ) dur=( 15 10 ))
(start=( b1-b6 ) dur=( 1 1 1 1 1 1))
(start=( l t1-t5 ) dur=( 2 12 12 12 12 12 ))
(start=( a1-a6 ) dur=( 4 2 2 2 2 5))
(start=( p1 p2 ) dur=( 20 13 ));
run;
proc print data=out noobs;
run;
proc transpose data=out out=startdata
name=_ACTIVITY_ prefix=START;
run;
proc sql noprint;
create table schedule as
select a._ACTIVITY_ label="Activity", a._DESC_,
a._RESOURCE_ as Resource,
a._SUCCESSOR_, a._LAG_, a._QTY_, a._DURATION_,
a._LAGDUR_, (b.START1 + a._DURATION_) as finish,
b.start1 as start from bridge a left join
startdata b on a._ACTIVITY_ = b._ACTIVITY_
order by a._resource_, a._activity_, a._successor_;
quit;
title 'Zoned by Resource';
proc gantt data=schedule;
id _ACTIVITY_ ;
chart / es=start ef=finish scale=2
zone=Resource onezoneval
height=2 pcompress
ref=104 reflabel
nolegend nojobnum
/* activity = _ACTIVITY_ successor= _SUCCESSOR_ */;
run;