proc clp out=out allsolns; var (X1-X6) = [1,6]; alldiff(); lincon X1 ne 1, X1 ne 2, X2 ne 1, X2 ne 2, X3 ne 3, X3 ne 4, X4 ne 3, X4 ne 4, X5 ne 5, X5 ne 6, X6 ne 5, X6 ne 6; run; %macro optmodel(version); proc optmodel; num num_people = 6; %if &version = 1 %then %do; num num_years = 8; %end; %else %do; num num_years = comb(num_people-2,2); %end; set PEOPLE = 1..num_people; set YEARS = 1..num_years; /* Assign[giver,receiver,year] = 1 if giver gives to receiver in that year, 0 otherwise */ var Assign {PEOPLE, PEOPLE, YEARS} binary; con Give_once_per_year {giver in PEOPLE, year in YEARS}: sum {receiver in PEOPLE} Assign[giver,receiver,year] = 1; con Receive_once_per_year {receiver in PEOPLE, year in YEARS}: sum {giver in PEOPLE} Assign[giver,receiver,year] = 1; /* do not give to self or spouse */ num spouse {person in PEOPLE} = (if mod(person,2) = 1 then person + 1 else person - 1); print spouse; for {giver in PEOPLE, receiver in {giver,spouse[giver]}, year in YEARS} do; fix Assign[giver,receiver,year] = 0; end; con Give_to_everyone {giver in PEOPLE, receiver in PEOPLE diff {giver,spouse[giver]}}: %if &version = 1 %then %do; sum {year in YEARS} Assign[giver,receiver,year] = 2; %end; %else %do; sum {year in YEARS} Assign[giver,receiver,year] >= 1; %end; set COUPLES = setof {giver in PEOPLE: mod(giver,2) = 1} ; set PAIRS = {i in PEOPLE, j in PEOPLE: i ne j}; var AssignCouplePair { in COUPLES, PAIRS, YEARS} binary; /* if AssignCouplePair[giver1,giver2,receiver1,receiver2,year] = 1 then Assign[giver1,receiver1,year] = 1 */ con AssignCouplePair_def1 { in COUPLES, in PAIRS, year in YEARS}: AssignCouplePair[giver1,giver2,receiver1,receiver2,year] <= Assign[giver1,receiver1,year]; /* if AssignCouplePair[giver1,giver2,receiver1,receiver2,year] = 1 then Assign[giver2,receiver2,year] = 1 */ con AssignCouplePair_def2 { in COUPLES, in PAIRS, year in YEARS}: AssignCouplePair[giver1,giver2,receiver1,receiver2,year] <= Assign[giver2,receiver2,year]; /* for some year, either AssignCouplePair[giver1,giver2,receiver1,receiver2,year] = 1 or AssignCouplePair[giver1,giver2,receiver2,receiver1,year] = 1 */ con Cover_each_pair { in COUPLES, in PAIRS: receiver1 < receiver2 and card({giver1,giver2} inter {receiver1,receiver2}) = 0}: sum {year in YEARS} (AssignCouplePair[giver1,giver2,receiver1,receiver2,year] + AssignCouplePair[giver1,giver2,receiver2,receiver1,year]) >= 1; /* if Assign[giver,receiver,year] = 1 and Assign[giver,receiver,year+1] = 1 then IsRepeat[giver,year] = 1 */ var IsRepeat {giver in PEOPLE, year in YEARS} binary; con IsRepeat_def {giver in PEOPLE, receiver in PEOPLE, year in YEARS}: Assign[giver,receiver,year] + Assign[giver,receiver,(if year = num_years then 1 else year+1)] - 1 <= IsRepeat[giver,year]; /* minimize the number of repeats */ min NumRepeats = sum {giver in PEOPLE, year in YEARS} IsRepeat[giver,year]; solve; num assignment {year in YEARS, giver in PEOPLE}; for {year in YEARS, giver in PEOPLE} do; for {receiver in PEOPLE: Assign[giver,receiver,year].sol > 0.5} do; assignment[year,giver] = receiver; leave; end; end; print assignment; quit; %mend optmodel; %optmodel(1) %optmodel(2)