简体   繁体   中英

Optimizing MiniZinc constraints for a scheduling problem

I am trying to use MiniZinc to solve a scheduling problem. Here is the main setting:

  • I have a certain number of students
  • They rank 7 topics in order of preference
  • They will be assigned 4 of such topics
  • There is 4 time slots available in the timetable for all of these

Of course students cannot attend two topics at the same time, and there are also a minimal/maximal size for each topic (but there may be various classes of a same topic, or no class of another topic). This is the most important constraint and we could see that as a satisfiability problem, even though trying to maximize the hapinness of the students is a good bonus.

I tried the following approach, translating all my constraints:

 int: n; % number of students int: m; % number of topics int: c; % number of courses each student will take int: maxseats; % number of seats available per course max int: minseats; % number of seats minimum per course int: timeslots; % possible time slots for the courses set of int: STUDENTS=1..n; % students set of int: PREFERENCE=1..m; % possible preference rankings set of int: TOPICS=1..m; % different topics set of int: TIMESLOTS=1..timeslots; array[STUDENTS,TOPICS] of PREFERENCE: preference; % ranking of topics by each student array[STUDENTS,1..c] of var TOPICS: course; % topics assigned to each student array[TOPICS] of var TIMESLOTS: schedule; % time slot assigned to topics include "alldifferent.mzn"; constraint % students have different topics forall(student in STUDENTS)(alldifferent([course[student,i] | i in 1..c])); constraint % no student has two topics at the same time forall(student in STUDENTS)(forall(i,j in 1..c where i<j)(schedule[course[student,i]],= schedule[course[student;j]])): constraint % less students per topic than available seats (NOTE. groups can be duplicated) forall(topic in TOPICS)(sum(student in STUDENTS where exists(i in 1.,c)(course[student;i] = topic))(1) <= maxseats). constraint % more students per topic than the minimum forall(topic in TOPICS)(sum(student in STUDENTS where exists(i in 1.,c)(course[student;i] = topic))(1) >= minseats): var int. satisfaction = sum(student in STUDENTS)(sum(i in 1.,c)(preference[student, course[student;i]])); solve minimize satisfaction;

The problem is that this works for few students, but it is far from working in a reasonable time for my list of students (I have about 100, which I though was not that many, but even 20 does not reach any conclusion in ten minutes).

Here is part of my data file (cutting some students for simlplicity, but it is already too long:

 n = 10; m = 7; c = 3; maxseats=18; minseats=1; timeslots=4; preference =[| 1,2,5,3,7,4,6| 6,4,7,5,1,2,3| 1,2,6,4,5,7,3| 5,3,1,2,6,4,7| 5,2,1,6,3,7,4| 7,5,1,6,3,2,4| 1,7,6,4,5,3,2| 1,4,2,6,3,5,7| 4,6,1,5,2,3,7| 1,6,4,3,5,7,2| |];

Are there any relevant constraints or structure I can add to help the solvers to do the job?

I tried to tweak your model:

include "globals.mzn";
int: n; % number of students
int: m; % number of topics
int: c; % number of courses each student will take
int: maxseats; % number of seats available per course max
int: minseats; % number of seats minimum per course
int: timeslots; % possible time slots for the courses

set of int: STUDENTS=1..n; % students
set of int: PREFERENCE=1..m; % possible preference rankings
set of int: TOPICS=1..m; % different topics
set of int: TIMESLOTS=1..timeslots; 
set of int: COURSES=1..c;

array[STUDENTS,TOPICS] of PREFERENCE: preference; % ranking of topics by each student

array[STUDENTS,COURSES] of var TOPICS: course; % topics assigned to each student
array[TOPICS] of var TIMESLOTS: schedule; % time slot assigned to topics

constraint % students have different topics; we thus enforce topics per student to be sorted
  forall(student in STUDENTS, i in 1..c-1)(course[student,i] < course[student,i+1]); 
  
constraint % no student has two topics at the same time
  forall(student in STUDENTS)(alldifferent([schedule[course[student,i]] | i in COURSES])); 
  
constraint % students per topic within allowed bounds (NOTE : groups can be duplicated)
  forall(topic in TOPICS)(sum([(course[student,i] == topic)| student in STUDENTS, i in COURSES]) in minseats .. maxseats); 
  
var n..n*m: dissatisfaction = sum(student in STUDENTS)(sum(i in COURSES)(preference[student, course[student,i]])); 

constraint dissatisfaction < n * 5;

Sadly, for the given dataset, the solution time is still beyond my patience.


Update:

My second attempt with Boolean decision variables which represent the presence or absence of students per topic.

include "globals.mzn";
int: n; % number of students
int: m; % number of topics
int: c; % number of courses each student will take
int: maxseats; % number of seats available per course max
int: minseats; % number of seats minimum per course
int: timeslots; % possible time slots for the courses

set of int: STUDENTS=1..n; % students
set of int: PREFERENCE=1..m; % possible preference rankings
set of int: TOPICS=1..m; % different topics
set of int: TIMESLOTS=1..timeslots; 
set of int: COURSES=1..c;

array[STUDENTS,TOPICS] of PREFERENCE: preference; % ranking of topics by each student

array[TOPICS, STUDENTS] of var bool: course; % students assigned to topics
array[TOPICS] of var TIMESLOTS: schedule; % time slot assigned to topics
 
constraint % enforce the number of courses per student
  forall(student in STUDENTS)(c = sum([course[t, student] | t in TOPICS]));
  
constraint % no student has two topics at the same time
  forall(student in STUDENTS)(alldifferent([schedule[t] | t in TOPICS where course[t, student]])); 
  
constraint % students per topic within allowed bounds (NOTE : groups can be duplicated)
  forall(topic in TOPICS)(sum([course[topic, student] | student in STUDENTS]) in minseats .. maxseats); 
  
constraint %  limit the dissatisfaction of students
  max([preference[student, t] | student in STUDENTS, t in TOPICS where course[t, student]]) < 4;

Using solver backends Chuffed, Google OR Tools or COIN-BC, this is solved in under 10 seconds.
No solution is found, if the upper limit of worst preference value is lower than 3. This is no surprise with two topics to be chosen.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM