University of Calgary
Rob Kremer
TA Assignment Problem

CPSC 433: Artifical Intelligence
Fall 2013
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, Apple Pages .pages format, 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-name 2nd occurance: do nothing (warning message)

::= instructor // instructor-name 2nd occurance: do nothing (warning message)

::= course // course-name 2nd occurance: do nothing (warning message)

::= senior-course // course-name 2nd occurance: set the course to senior (regardless)

::= grad-course // course-name 2nd occurance: set the course to grad (regardless)

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

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

::= timeslot // timeslot-name 2nd occurance: do nothing (warning message)

::= instructs // instructor-name, course-name, lecture-name instructor 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-name TA 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-name TA/course doesn't exist: ignore (error message);
Already assigned: ignore (error message);

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

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

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


::= taking // TA, course-name, lecture-name TA/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 ignored (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 2010-03-15 5:42
Rob Kremer