% % Use selectedSubjects as decision variables! % include "globals.mzn"; enum SUBJECTS; int: blocksAllowed; % the number of blocks allowed int: maxTaughtSubjects; % the maximum number of scheduled subjects to be taught 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, j in CHOICE, b in BLOCKS)(selectedSubject[s,j] = b -> block[b,selection[s,j]] = 1); 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: taughtSubjects = sum(dec); constraint taughtSubjects <= maxTaughtSubjects; array[int] of var BLOCKS: flatChoice = [selectedSubject[s,j] | s in SELECTIONS, j in CHOICE]; % top of search symmetry break constraint forall(c in CHOICE)(selectedSubject[SELECTIONS[1],c] = c); % search annotation: dec are the decision variables, fail first (so what), select 1 before 0, complete search % solve :: int_search(flatChoice,first_fail,indomain_min,complete) minimize taughtSubjects; solve :: int_search(flatChoice,first_fail,indomain_min,complete) satisfy; 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\nnumber of taught subjects: \(taughtSubjects) \n\n"]; % output [join("\n", ["selection \(s): " ++ join("",[format(selectedSubject[s,c]) ++ " "| c in CHOICE]) | s in SELECTIONS])]; % % NOTES: % - minimise teaching where possible! % - 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) %