University of Calgary
Rob Kremer
Room Allocation Problem

CPSC 433: Artifical Intelligence
Winter 2006
Department of Computer Science
Computer
Science


Problem Description

The assignment is based on the department's on-going problem of allocating graduate student TAs for undergraduate lab and tutorial sessions (called simple "labs" from now on).

The task is to assign graduate TAs to each of the undergrad lab, maximizing the happiness of the TAs. There are a large number of factors which our model uses to measure the "goodness" of a solution. These are modeled as constraints.

A few simple relations are defined:

instructs: TA -> Lab ; instructs(ta,lab) means TA ta is assigned to Lab lab.

lab-count: TA -> int ; lab-count(ta,n) means TA ta has exactly n distinct instances of instructs(ta,lab).

Hard Constraints

There are a few mandatory constraints that may not be violated. Any TA assignment that violates these is not considered a solution. These are:

//every TA is assigned at most MAX_LABS labs
FORALL ta:TA . lab-count(ta) <= MAX_LABS)

//every TA is assigned at least MIN_LABS labs (if the TA *has* a lab assignment)
FORALL ta:TA . lab-count(ta)/=0 -> lab-count(ta) >= MIN_LABS)

// no lab has more than one TA assigned to it
FORALL course:Course, lab:Lab | has-lab(course,?,lab) . ~ EXISTS ta1,ta2:TA | ta1/= ta2 . instructs(ta1,lab) /\ instructs(ta2,lab)

//every lab has a TA assigned to it
FORALL course:Course, lab:Lab | has-lab(course,?,lab). EXITS ta:TA . instructs(ta,course,lab)

//no TA is assigned simultanious labs
FORALL ta:TA, c1,c2:Course, b1,b2:Lab | (c1=c2 => b1 /= b2) /\ instructs(ta,c1,b1) /\ instructs(ta,c2,b2) . ~ EXISTS t1,t2 | at(c1,b1,t1) /\ at(c2,b2,t2) . conflicts(t1,t2)

//no TA is assigned a lab that conflicts with his/her own courses
FORALL ta:TA, course:Course, lab:Lab | instructs(ta,course,lab) .
    ((~ EXISTS c:Course, lec:Lecture | taking(ta,c,lec) . EXISTS t1,t2 | at(course,lab,t1) /\ at(c,lec,t2)) . conflicts(t1,t2)) /\
    ((~ EXISTS c:Course, b:Lab | taking(ta,c,b) . EXISTS t1,t2 | at(course,lab,t1) /\ at(c,b,t2)) . conflicts(t1,t2)))

where:
    lab-count(TA) is a function that returns the number of labs a TA instructs.

Soft Constraints

There are also a large number of "soft" constraints that may be violated (and since some of these constraints actually conflict with each other, sometimes must be violated). These all have a penalty associated with them (reflecting their importance). Your job is to come up with a solution that maximizes the utility function that naturally arises from these soft constraints and their penalty weightings. I have, of course, written my own version of this utility function that (I believe) precisely conforms to the these constraints, and I will test your program's solutions against my utility function. You will have to write your own utility function to test your program.

The soft constraints are available in PDF, Microsoft Word .doc format, and RTF. You will note that some of the formal semantics in the soft constraints table are omitted. These should be filled in on the table and the complete table should be submitted as an appendix to your group paper.


Input/Output Formats

The input and output file formats are the same, namely, a set of ASCII-format predicates, one per line. The BNF for this format is:

file::={ predicate \n }*  
predicate::=predicateName ( params )  
params::=value {, value }*  


 // -- PARAMETER LIST ---- ERROR HANDLING--
predicateName::=TA// TA-name2nd occurance: do nothing (warning message)

::=instructor// instructor-name2nd occurance: do nothing (warning message)

::=course// course-name2nd occurance: do nothing (warning message)

::=senior-course// course-name2nd occurance: set the course to senior (regardless)

::=grad-course// course-name2nd occurance: set the course to grad (regardless)

::=lecture// course-name, lecture-nameCourse doesn't exist: ignore (error message);
2nd occurance: do nothing (warning message)

::=lab// course-name, lecture-name, lab-nameCourse or lecture doesn't exist: ignore (error message);
2nd occurance: do nothing (warning message)

::=timeslot// timeslot-name2nd occurance: do nothing (warning message)

::=instructs// instructor-name, course-name, lecture-nameinstructor doesn't exist: ignore (error message);
course/lecture doesn't exist: ignore (error message);
2nd occurence: do nothing (warning message)

::=instructs// TA-name, course-name, lab-nameTA doesn't exist: ignore (error message);
course/lab doesn't exist: ignore (error message);
2nd occurence: do nothing (warning message)

::=at// course-name, lab-name|lecture-name, timeslot-name

course/lab/lecture/timeslot doesn't exit: ignore (error message);
lab/lecture already has a timeslot: ignore (error message);


::=knows// TA-name, course-name

TA/course doesn't exist: ignore (error message);
2nd occurence: do nothing


::=prefers1// TA-name, course-name

TA/course doesn't exist: ignore (error message);
Already assigned: ignore (error message);


::=prefers2// TA-name, course-nameTA/course doesn't exist: ignore (error message);
Already assigned: ignore (error message);

::=prefers3// TA-name, course-nameTA/course doesn't exist: ignore (error message);
Already assigned: ignore (error message);

::=prefers// instructor-name, course-name, TA-name

instructor/course/TA doesn't exist: ignore (error message)
2nd occurence: do nothing


::=taking// TA, course-name, lecture-nameTA/course/lecture doesn't exist: ignore (error message);
2nd occurance: do nothing

::=conflicts// timeslot-name, timeslot-name timeslot doesn't exist: create it;
2nd occurance: do nothing
 ::=maxlabs// int  
 ::=minlabs// int 
 
   
value::=

TA-name
| instructor-name
|
lab-name
|
course-name
|
lecture-name
|
timeslot-name

  
name::=" {char}+ "  

::=letter {letter-or-digit }*  
set::={ {name {, name}*} }  
TA-name::=name  
instructor-name::=name  
lab-name::=name  
course-name::=name  
lecture-name::=name  
timeslot-name::=name  

There are a few input constraints you must observe. Otherwise the offending input predicate should be ingored (with an appropriate error message to stderr, of course):

FORALL c:Course-name, lec1,lec2:Lecture-name, b1,b2:Lab-name |
  lab(c,lec1,b1) /\ lab(c,lec2,b2) /\ lec1 /= lec2 .
    b1 /= b2
No course can have the a lab name associated with more than one lecture name.
  

There are also a few inference rules that you must observe when reading input files. These may be hard-coded if you wish.

course(c):-senior-course(c)// a senior course is a course
course(c):-grad-course(c)// a grad course is a course
conflicts(a,b):-conflicts(b,a)// conflicts are symetric
conflicts(a,b):-a = b// conflicts are reflexive
knows(ta,c):-prefers1(ta,c) \/ prefers2(ta,c) \/ prefers3(ta,c)// TAs know the courses they prefer
knows(ta,c):-course(c) /\ ~senior-course(c) /\ ~grad-course(c)// all TAs know junior courses

Parser

You will be pleased to learn that I have saved you the effort of writing a parser for the file format. See the JavaDoc documentation. You can download the following JAVA classes: :

(or download them all in a jar file which includes the .class files and manifest as well).

It is highly recommended that you use this parser for your assignment, as it will save you a lot of trouble, it works, and might avoid some possible problems with your assessment and demos. These classes make use of the JAVA reflect package, so that you need only define methods a_predicateName() (to assert a predicate as true) and/or e_predicateName() (to evaluate the truth value of a predicate). Your methods must also, of course, support the appropriate parameter list. You may define additional predicates if you wish, but the assessment will only require you to interpret the predicates listed here. Be warned that the only predicate type expected in your output file is the instructs(TA-name,course-name,lab-name) predicate (and perhaps comments).


Sample Input

You can use the following sample texts as a test suite for your program. You will be tested on other scenarios.

There is a long case (and an easier version and a solution), and a trivial case:

minlabs(2)
maxlabs(3)

// Time slots
timeslot(MWF800)
timeslot(MWF900)
timeslot(MWF1000)
timeslot(MWF1100)
timeslot(MWF1200)
timeslot(MWF1300)
timeslot(MWF1400)
timeslot(MWF1500)
timeslot(MWF1600)
timeslot(MW800)
timeslot(MW900)
timeslot(MW1000)
timeslot(MW1100)
timeslot(MW1200)
timeslot(MW1300)
timeslot(MW1400)
timeslot(MW1500)
timeslot(MW1600)
timeslot(TR800)
timeslot(TR930)
timeslot(TR1100)
timeslot(TR1230)
timeslot(TR1400)
timeslot(TR1530)
conflicts(MWF800,MW800)
conflicts(MWF900,MW900)
conflicts(MWF1000,MW1000)
conflicts(MWF1100,MW1100)
conflicts(MWF1200,MW1200)
conflicts(MWF1300,MW1300)
conflicts(MWF1400,MW1400)
conflicts(MWF1500,MW1500)
conflicts(MWF1600,MW1600)


// Courses

course(CPSC231)

senior-course(SENG411)
lecture(SENG411,L01)
at(SENG411,L01,MWF1300)

senior-course(CPSC433)
lecture(CPSC433,L01)
at(CPSC433,L01,TR1400)
lab(CPSC433,L01,B01)
at(CPSC433,B01,MW1100)

grad-course(LING601)
lecture(LING601,L01)
at(LING601,L01,TR1400)


// Instructors

instructor(Kremer)
instructs(Kremer,CPSC433,L01)

// TAs
TA(Heard)
prefers1(Heard,CPSC433)
prefers2(Heard,CPSC231)
prefers3(Heard,SENG411)
knows(Heard,CPSC433)
knows(Heard,CPSC231)
knows(Heard,SENG411)

taking(Heard,LING601,L01)

// Instructor prefers
prefers(Kremer,Heard,CPSC433)

The following is the solution suggested to the above problem. My utility function rates its utility at 0.

instructs(Heard,CPSC433,B01)

 


UofC
CPSC 433: Artificial Intelligence
Department of Computer Science

Last updated 2006-11-27 9:25
Rob Kremer