Hi Gabriel,
The model looks good, just a few remarks:
1) I couldn't get it to produce solutions. There appears to be a bug in the alldifferent constraint, I fixed it like this:
constraint forall (s in Students)( alldifferent([ c_timeslot[sc_class[sc]] | sc in getChoicesOfStudent(s) ]) );
This could have been caught by using anonymous enums for all the index sets, but it's possible that that would have become a bit awkward to write.
With this fix, I can get a solution from Chuffed in about 25 seconds for the entire data set (no students commented out).
2) I'd remove the c_duration variables and replace the diff_n constraints with a more straightforward version:
constraint forall (c1, c2 in Classes where c1 < c2) (
( c_teacher[c1]=c_teacher[c2] /\ c_teacher[c1] != Null ) ->
( c_timeslot[c1] != c_timeslot[c2] )
);
constraint forall (c1, c2 in Classes where c1 < c2) (
( c_room[c1]=c_room[c2] /\ c_room[c1] != Null ) ->
( c_timeslot[c1] != c_timeslot[c2] )
);
This cuts down the solving time to 15 seconds.
3) The bin_packing_load is a slightly indirect way of expressing when classes are active. A more direct way, which seems to save another couple of seconds, would be
constraint forall (c in Classes) (
c_active[c] <-> exists (sc in StudentChoices) (sc_class[sc] = c)
);
Hope this helps!
Cheers,
Guido