The Car Sequencing Problem (oclpe07)
/***************************************************************/
/* */
/* S A S S A M P L E L I B R A R Y */
/* */
/* NAME: oclpe07 */
/* TITLE: The Car Sequencing Problem (oclpe07) */
/* PRODUCT: OR */
/* SYSTEM: ALL */
/* KEYS: OR */
/* PROCS: OPTMODEL, GANTT, SQL */
/* DATA: */
/* */
/* SUPPORT: UPDATE: */
/* REF: */
/* MISC: Example 7 from the CLP solver chapter of the */
/* Mathematical Programming book. */
/* */
/***************************************************************/
data class_data;
input class cars_cls;
datalines;
1 1
2 1
3 2
4 2
5 2
6 2
;
data option_data;
input option max blSz class1-class6;
datalines;
1 1 2 1 0 0 0 1 1
2 2 3 0 0 1 1 0 1
3 1 3 1 0 0 0 1 0
4 2 5 1 1 0 1 0 0
5 1 5 0 0 1 0 0 0
;
%macro car_sequencing(outdata);
proc optmodel;
set CLASSES;
num nClasses = card(CLASSES);
num cars_cls {CLASSES};
read data class_data into CLASSES=[class] cars_cls;
set OPTIONS;
num max {OPTIONS};
num blSz {OPTIONS};
num list {OPTIONS, CLASSES};
num cars_opt {i in OPTIONS} =
sum {k in CLASSES} cars_cls[k] * list[i,k];
read data option_data into OPTIONS=[option] max blSz
{k in CLASSES} <list[option,k]=col('class'||k)>;
num nCars = sum {k in CLASSES} cars_cls[k];
set SLOTS = 1..nCars;
/* Declare Variables */
/* Slot variables: S[i] - class of car assigned to Slot i */
var S {SLOTS} integer >= 1 <= nClasses;
/* Option variables: O[i,j]
- indicates if class assigned to Slot i needs Option j */
var O {SLOTS, OPTIONS} binary;
/* Capacity Constraints: for each option j */
/* Installed in at most max[j] cars out of every sequence of
blSz[j] cars */
con CapacityCon {j in OPTIONS, i in 0..(nCars-blSz[j])}:
sum {k in 1..blSz[j]} O[i+k,j] <= max[j];
/* Demand Constraints: for each class k */
/* Exactly cars_cls[k] cars */
con MeetDemandCon:
gcc(S, setof{k in CLASSES} <k,cars_cls[k],cars_cls[k]>);
/* Element Constraints: For each slot i and each option j */
/* relate the slot variable to the option variables. */
/* O[i,j] = list[j,S[i]] */
con OptionsAtSlotCon {i in SLOTS, j in OPTIONS}:
element(S[i], {k in CLASSES} list[j,k], O[i,j]);
/* Redundant Constraints to improve efficiency - for every */
/* option j. */
/* At most max[j] out of every sequence of blSz[j] cars */
/* requires option j. */
/* All the other slots contain at least cars_opt[j] - max[j]*/
/* cars with option j */
con BoundRemainingCon {j in OPTIONS, i in 1..(nCars/blSz[j])}:
sum {k in 1..(nCars-i*blSz[j])} O[k,j] >= cars_opt[j] - i * max[j];
solve with CLP / varselect=minrmaxc findall;
/* Replicate typical PROC CLP output from PROC OPTMODEL arrays */
create data &outdata.(drop=sol) from [sol]=(1.._NSOL_)
{i in SLOTS} <col('S_'||i)=S[i].sol[sol]>
{i in SLOTS, j in OPTIONS} <col('O_'||i||'_'||j)=O[i,j].sol[sol]>;
quit;
%mend;
%car_sequencing(sequence_out);
%macro car_sequencing_gantt;
/* map classes to colors */
%let class1 = red;
%let class2 = blue;
%let class3 = gray;
%let class4 = blue;
%let class5 = cyan;
%let class6 = yellow;
/* set patterns */
%do i=1 %to 6;
pattern&i. v=s color=&&class&i.;
%end;
proc sort data=sequence_out;
by
%do j = 1 %to 10;
S_&j
%end;
;
run;
data carseq_ds(keep=S_1-S_10);
set sequence_out;
run;
proc format;
value stage
0.5 = '1'
9.5 = '10'
10.5 = ' '
;
run;
data schedule;
format _label $8.;
format s_start stage.;
label solution='Solution';
set carseq_ds;
keep _pattern _label segmt_no solution s_start s_finish;
retain solution 1;
%do i = 1 %to 10;
s_start=%eval(&i-1)+0.5;
s_finish=&i+0.5;
segmt_no = &i;
nextpat = 0; /* ensure no match */
%do j = 1 %to 6;
if S_&i eq &j then do;
_label = "Class %eval(&j)";
_pattern = &j;
end;
if S_&i eq %eval(&j+1) then do;
nextpat = &j;
end;
%end;
if mod(nextpat - _pattern,4) ne 0 then do;
s_finish = s_finish - 0.05;
end;
output;
%end;
solution = solution + 1;
run;
data labels;
_y=-1;
_lvar="_label";
_xvar="s_start";
_hlabel=1.0;
_yoffset = -0.6;
_xoffset = 0.25;
run;
goptions htext=1.5;
title1 j=c h=5pct 'Car Sequencing Problem';
title2 j=c h=3pct 'Assembly Sequence for All Six Solutions';
proc gantt data=schedule labdata=labels;
chart /
pcompress
skip=3
nojobnum
nolegend
mindate=0.5
useformat
labsplit='/'
increment=1
barht=2
baroff=0.8
;
id solution;
run;
%mend car_sequencing_gantt;
%car_sequencing_gantt;