The CLP Procedure
Example 4.7 Progressive Party Problem
This example demonstrates the use of the PACK constraint to solve an instance of the progressive party problem (Smith et al. 1996). In the original progressive party problem, a number of yacht crews and their boats congregate at a yachting rally. In order for each crew to socialize with as many other crews as possible, some of the boats are selected to serve as "host boats" for six rounds of parties. The crews of the host boats stay with their boats for all six rounds. The crews of the remaining boats, called "guest crews," are assigned to visit a different host boat in each round.
Given the number of boats at the rally, the capacity of each boat, and the size of each crew, the objective of the original problem is to assign all the guest crews to host boats for each of the six rounds, using the minimum number of host boats. The partitioning of crews into guests and hosts is fixed throughout all rounds. No two crews should meet more than once. The assignments are constrained by the spare capacities (total capacity minus crew size) of the host boats and the crew sizes of the guest boats. Some boats cannot be hosts (zero spare capacity), and other boats must be hosts.
In this instance of the problem, the designation of the minimum requirement of thirteen hosts is assumed (boats 1 through 12 and 14). The formulation solves up to nine rounds in distributed mode with 142 workers. The total capacities and crew sizes of the boats are shown in Figure 5.
Figure 5: Progressive Party Problem Input
| Progressive Party Problem Input |
| boatnum | capacity | crewsize |
|---|---|---|
| 1 | 6 | 2 |
| 2 | 8 | 2 |
| 3 | 12 | 2 |
| 4 | 12 | 2 |
| 5 | 12 | 4 |
| 6 | 12 | 4 |
| 7 | 12 | 4 |
| 8 | 10 | 1 |
| 9 | 10 | 2 |
| 10 | 10 | 2 |
| 11 | 10 | 2 |
| 12 | 10 | 3 |
| 13 | 8 | 4 |
| 14 | 8 | 2 |
| 15 | 8 | 3 |
| 16 | 12 | 6 |
| 17 | 8 | 2 |
| 18 | 8 | 2 |
| 19 | 8 | 4 |
| 20 | 8 | 2 |
| 21 | 8 | 4 |
| 22 | 8 | 5 |
| 23 | 7 | 4 |
| 24 | 7 | 4 |
| 25 | 7 | 2 |
| 26 | 7 | 2 |
| 27 | 7 | 4 |
| 28 | 7 | 5 |
| 29 | 6 | 2 |
| 30 | 6 | 4 |
| 31 | 6 | 2 |
| 32 | 6 | 2 |
| 33 | 6 | 2 |
| 34 | 6 | 2 |
| 35 | 6 | 2 |
| 36 | 6 | 2 |
| 37 | 6 | 4 |
| 38 | 6 | 5 |
| 39 | 9 | 7 |
| 40 | 0 | 2 |
| 41 | 0 | 3 |
| 42 | 0 | 4 |
The following statements and DATA steps process the data and designate host boats:
data hostability;
set capacities;
spareCapacity = capacity - crewsize;
run;
data hosts guests;
set hostability;
if (boatnum <= 12 or boatnum eq 14) then do;
output hosts;
end;
else do;
output guests;
end;
run;
/* sort so guest boats with larger crews appear first */
proc sort data=guests;
by descending crewsize;
run;
data capacities;
format boatnum capacity 2.;
set hosts guests;
seqno = _n_;
run;
To model the progressive party problem for the CLP solver, first define the following sets of variables:
Next, describe the set of constraints that are used in the model:
Alldifferent constraints ensure that a guest boat is not assigned to the same host boat in different rounds.
Reify constraints regulate the values that are assigned to the aforementioned indicator variables
.
The reified indicator variables appear in linear constraints to enforce the requirement to meet no more than once.
One pack constraint per round maintains the capacity limits of the host boats.
Finally, a symmetry-breaking linear constraint orders the host boat assignments for the highest-numbered guest boat across rounds.
The following statements call the CLP procedure to define the variables, specify the constraints, and solve the problem.
%let rounds=9;
%let numhosts=13;
%global maxcap;
%macro ppp(maxtime=600);
proc sql noprint;
select count(*) into :numboats from capacities;
select max(capacity) into :maxcap from capacities;
%do i = 0 %to &maxcap;
select count(*) into :numclass_&i from capacities where capacity = &i;
%end;
select crewsize, spareCapacity into
:crewsize_1-:crewsize_%scan(&numboats,1),
:cap_1-:cap_%scan(&numboats,1) from capacities order by seqno;
quit;
proc clp out=mylib.out varselect=FIFO
maxtime=&maxtime timetype=real;
/* assume first &numhosts boats are hosts */
/* process each round in turn */
%do t = 1 %to &rounds;
%do i = &numhosts+1 %to &numboats;
/* boat i assigned host value for round t */
var x_&i._&t = [1,&numhosts];
%end;
%do h = 1 %to &numhosts;
var L_&h._&t = [0,&&cap_&h]; /* load of host boat */
%end;
%end;
%do i = &numhosts+1 %to &numboats;
/* assign different host each round */
alldiff (x_&i._1-x_&i._&rounds);
%end;
%do t = 1 %to &rounds;
%do i = &numhosts+1 %to &numboats-1;
/* boat i assigned host value for round t */
%do j = &i+1 %to &numboats;
var m_&i._&j._&t = [0,1];
reify m_&i._&j._&t : (x_&i._&t = x_&j._&t);
%end;
%end;
%end;
%do i = &numhosts+1 %to &numboats-1;
%do j = &i+1 %to &numboats;
lincon 1 >= 0
%do t = 1 %to &rounds;
+ m_&i._&j._&t
%end;
;
%end;
%end;
/* honor capacities */
%do t = 1 %to &rounds;
PACK((
%do i = &numhosts+1 %to &numboats;
x_&i._&t
%end;
) (
%do i = &numhosts+1 %to &numboats;
&&crewsize_&i
%end;
) (
%do h = 1 %to &numhosts;
L_&h._&t
%end;
));
%end;
/* break symmetries */
%do t = 1 %to &rounds-1;
lincon x_%scan(&numboats,1)_&t < x_%scan(&numboats,1)_%eval(&t+1);
%end;
run;
%mend ppp;
%ppp;
The two charts in Output 4.7.1 show the boat assignments for the first two rounds.
The first segment of each row indicates the host boat, and the remaining labeled segments indicate the guest boats that visit it. The horizontal axis represents host boat capacity. The length of each labeled segment indicates the crew size of the boat. The length of an unlabeled segment indicates excess capacity of the host boat.
Output 4.7.1: Gantt Chart: Host Boat Schedule by Round


The chart in Output 4.7.2 shows all the guest boats that visit host boat 3 in each of the nine rounds. Once again, the horizontal axis represents capacity, and segment length indicates the crew size of the boat.
Output 4.7.2: Gantt Chart: Nine-Round Schedule by Host Boat

Finally, the chart in Output 4.7.3 displays the visitation schedule for all guest boats. The horizontal axis indicates the round, and the segment number identifies the host boat that is visited in that round.
Output 4.7.3: Gantt Chart: Guest Boat Schedules
