bacp_1.mzn 4.91 KB
% The balanced academic curriculum problem: see
% http://www.dcs.st-and.ac.uk/~ianm/CSPLib/prob/prob030/spec.html
%
% A curriculum is a set of courses with prerequisites.
%
% Each course must be assigned within a set number of periods.
%
% A course cannot be scheduled before its prerequisites.
%
% Each course confers a number of academic credits (it's "load").
%
% Students have lower and upper bounds on the number of credits
% they can study for in a given period.
%
% Students have lower and upper bounds on the number of courses
% they can study for in a given period.
%
% The goal is to assign a period to every course satisfying these
% criteria, minimising the load for all periods.

include "globals.mzn";




%curriculum.mzn.model
n_courses = 50;
n_periods = 10;
load_per_period_lb = 2;
load_per_period_ub = 100;
courses_per_period_lb = 2;
courses_per_period_ub = 10;
course_load = [6, 3, 5, 3, 7, 8, 1, 9, 4, 9, 8, 8, 4, 5, 6, 3, 2, 1, 3, 1, 1, 2, 6, 7, 6, 10, 10, 1, 7, 3, 4, 2, 7, 9, 7, 4, 6, 7, 2, 2, 5, 9, 9, 10, 4, 6, 4, 5, 6, 6, ];
constraint prerequisite(3, 1);
constraint prerequisite(4, 1);
constraint prerequisite(5, 1);
constraint prerequisite(6, 1);
constraint prerequisite(7, 1);
constraint prerequisite(6, 2);
constraint prerequisite(8, 2);
constraint prerequisite(11, 3);
constraint prerequisite(11, 4);
constraint prerequisite(16, 4);
constraint prerequisite(16, 5);
constraint prerequisite(11, 6);
constraint prerequisite(14, 6);
constraint prerequisite(16, 8);
constraint prerequisite(13, 9);
constraint prerequisite(14, 9);
constraint prerequisite(17, 11);
constraint prerequisite(19, 11);
constraint prerequisite(17, 12);
constraint prerequisite(19, 12);
constraint prerequisite(18, 13);
constraint prerequisite(17, 14);
constraint prerequisite(18, 14);
constraint prerequisite(23, 17);
constraint prerequisite(21, 19);
constraint prerequisite(26, 21);
constraint prerequisite(27, 21);
constraint prerequisite(30, 22);
constraint prerequisite(24, 23);
constraint prerequisite(25, 23);
constraint prerequisite(27, 23);
constraint prerequisite(33, 25);
constraint prerequisite(34, 27);
constraint prerequisite(35, 27);
constraint prerequisite(35, 28);
constraint prerequisite(33, 29);
constraint prerequisite(34, 29);
constraint prerequisite(35, 30);
constraint prerequisite(36, 31);
constraint prerequisite(38, 31);
constraint prerequisite(39, 31);
constraint prerequisite(40, 31);
constraint prerequisite(43, 31);
constraint prerequisite(40, 32);
constraint prerequisite(37, 33);
constraint prerequisite(38, 33);
constraint prerequisite(40, 33);
constraint prerequisite(38, 34);
constraint prerequisite(41, 34);
constraint prerequisite(41, 35);
constraint prerequisite(42, 35);
constraint prerequisite(44, 36);
constraint prerequisite(45, 36);
constraint prerequisite(45, 37);
constraint prerequisite(44, 40);
constraint prerequisite(45, 40);
constraint prerequisite(47, 40);
constraint prerequisite(44, 41);
constraint prerequisite(45, 41);
constraint prerequisite(46, 41);
constraint prerequisite(46, 42);
constraint prerequisite(47, 42);
constraint prerequisite(44, 43);
constraint prerequisite(45, 43);
constraint prerequisite(49, 46);
constraint prerequisite(48, 47);
constraint prerequisite(50, 47);




int: n_courses;
int: n_periods;
int: load_per_period_lb;
int: load_per_period_ub;
int: courses_per_period_lb;
int: courses_per_period_ub;
array [1..n_courses] of int: course_load;
int: max_course_load = sum(c in courses)(course_load[c]);

set of int: courses = 1..n_courses;
set of int: periods = 1..n_periods;

% period course is assigned to
array [courses] of var periods: course_period;
% whether period i has course j assigned
array [periods, courses] of var 0..1: x;
% total load for each period
array [periods] of var load_per_period_lb..load_per_period_ub: load;
% optimisation target
var load_per_period_lb..load_per_period_ub: objective;

constraint forall(p in periods) (
    forall(c in courses) (x[p,c] = bool2int(course_period[c] = p)) /\
    sum(i in courses) (x[p,i]) >= courses_per_period_lb /\
    sum(i in courses) (x[p,i]) <= courses_per_period_ub /\
    load[p] = sum(c in courses) (x[p,c] * course_load[c]) /\
    load[p] >= load_per_period_lb /\
    load[p] <= objective
);

% prerequisite(a, b) means "course a has prerequisite course b".

predicate prerequisite(courses: a, courses: b) =
    course_period[b] < course_period[a];

% add some redundant linear constraints

constraint forall(p in 0..n_periods-1) (
    let {
		var 0..max_course_load: l = sum(c in courses) (bool2int(course_period[c] > p) * course_load[c])
	} in 
        l >= (n_periods-p) * load_per_period_lb /\
        l <= (n_periods-p) * objective
    );

solve :: seq_search([
      int_search([x[i,j] | i in periods, j in courses], input_order, indomain_max, complete),
      int_search([objective], input_order, indomain_min, complete)
    ]) minimize objective;

output 
    [show(c) ++ "-" ++ show(course_period[c]) ++ "\t" | c in courses ] ++ ["\n"] ++
    ["objective = ", show(objective)];