% % Produce blocks and doing so, minimize amount of teaching % include "globals.mzn"; enum SUBJECTS; int: blocksAllowed; % the number of blocks allowed int: maxTaughtSubjects; % the maximum number of scheduled subjects to be taught, not used int: maxSubjectsPerBlock; % the maximum number of subjects that can be in a block int: minOccurenceSubject; % the minimum number of times a subject has to occur array[int,int] of SUBJECTS: selection; % set of k-selections of subjects set of int: SELECTIONS = index_set_1of2(selection); set of int: CHOICE = index_set_2of2(selection); set of int: BLOCKS = 1..blocksAllowed; array[BLOCKS,SUBJECTS] of var 0..1: block; % block[b,s] = 1 <-> subject s is taught in block b array[SELECTIONS,CHOICE] of var BLOCKS: selectedSubject; constraint forall(b in BLOCKS,s in SELECTIONS,j in CHOICE)(block[b,selection[s,j]] = 0 -> selectedSubject[s,j] != b); constraint forall(s in SELECTIONS)(alldifferent([selectedSubject[s,j] | j in CHOICE])); constraint forall(b in BLOCKS)(sum(row(block,b)) <= maxSubjectsPerBlock); constraint forall(s in SUBJECTS)(sum(col(block,s)) >= minOccurenceSubject); % symmetry break ... only useful in optimisation or unsat? constraint forall(b in 1..blocksAllowed-1)(lex_greatereq(row(block,b),row(block,b+1))); % flattened array of blocks array[int] of var 0..1: dec = [block[i,j] | i in BLOCKS,j in SUBJECTS]; var int: subjectsTaught = sum(dec); % search annotation: dec are the decision variables, fail first (so what), select 1 before 0, complete search %solve :: int_search(dec,first_fail,indomain_max,complete) satisfy; solve :: int_search(dec,first_fail,indomain_max,complete) minimize subjectsTaught; %solve minimize sum(dec); output [join("\n", ["block \(b): " ++ join("",[(if fix(block[b,s]) = 1 then format(SUBJECTS[s]) ++ " " else "" endif) | s in SUBJECTS]) | b in BLOCKS])]; output ["\n\(subjectsTaught)"]; % % NOTES: % - get jth column of 2d array -> col(x,j) % - get ith row of 2d array -> row(x,i) % - index set of 1d array -> index_set(x) % - row index set of 2d array -> index_set_1of2(x) % - col index set of 2d array -> index_set_2of2(x) %