///////////////////////////////////////////////////////////////
//
// Academic Advising Domain
//
// Author: Libby Ferland (libby.knouse@uky.edu)
//
// In this domain, a student may take courses at a given cost
// and passes the course with a probability determined by how
// many of the prerequisites they have successfully passed.
// A student also receives a penalty at each time step if they
// have not yet graduated from their program (i.e., completed
// all required courses). We allow multiple courses to be
// taken in a semester in some instances.
//
// Modified for competition and translation purposes by Scott Sanner.
//
///////////////////////////////////////////////////////////////
domain academic_advising_mdp {
types {
course : object;
};
pvariables {
// Nonfluents: course prerequisites
PREREQ(course, course) : { non-fluent, bool, default = false }; // First argument is a prereq of second argument
// Nonfluents: course passing probabilities
PRIOR_PROB_PASS_NO_PREREQ(course) : { non-fluent, real, default = 0.8 }; // Probability of passing a course with no prereqs
PRIOR_PROB_PASS(course) : { non-fluent, real, default = 0.2 }; // Probability of passing a course regardless of prereq status
// Nonfluents: program requirements for graduation
PROGRAM_REQUIREMENT(course) : { non-fluent, bool, default = false }; // Specifies whether course is program requirement
// Nonfluents: costs/penalties
COURSE_COST(course) : { non-fluent, real, default = -1 }; // Cost for taking a course
COURSE_RETAKE_COST(course) : { non-fluent, real, default = -2 }; // Cost for re-taking a course (heavily discouraged)
PROGRAM_INCOMPLETE_PENALTY : { non-fluent, real, default = -5 }; // Penalty at each time step for having an incomplete program
// State
passed(course) : { state-fluent, bool, default = false };
taken(course) : { state-fluent, bool, default = false };
// Action
takeCourse(course) : { action-fluent, bool, default = false };
};
cpfs {
// Determine whether each course was passed
// Modification: differentiate courses with no prereqs since should be easier to pass such introductory courses
// For courses with prereqs:
// if PRIOR_PROB_PASS=.2 and 0 out of 3 prereqs were taken, the distribution is Bernoulli(.2 + .8 * (0/4)) = Bernoulli(.2)
// 1 out of 3 prereqs were taken, the distribution is Bernoulli(.2 + .8 * (1/4)) = Bernoulli(.4)
// 3 out of 3 prereqs were taken, the distribution is Bernoulli(.2 + .8 * (3/4)) = Bernoulli(.8)
passed'(?c) =
if (takeCourse(?c) ^ ~passed(?c)) // If take a course and not already passed
then [ if (~exists_{?c2 : course} PREREQ(?c2,?c))
then Bernoulli( PRIOR_PROB_PASS_NO_PREREQ(?c) )
else Bernoulli((PRIOR_PROB_PASS(?c)) +
(1 – PRIOR_PROB_PASS(?c))*[[sum_{?c2 : course} (PREREQ(?c2,?c) ^ passed(?c2))]
/ [1 + sum_{?c2 : course} PREREQ(?c2,?c)]]) ]
else
passed(?c); // Value persists if course not taken or already passed
taken'(?c) = taken(?c) | takeCourse(?c);
};
// A student is assessed a cost for taking each course and a penalty for not completing their program
reward =
[sum_{?c : course} [COURSE_COST(?c) * (takeCourse(?c) ^ ~taken(?c))]]
+ [sum_{?c : course} [COURSE_RETAKE_COST(?c) * (takeCourse(?c) ^ taken(?c))]]
+ [PROGRAM_INCOMPLETE_PENALTY * ~[forall_{?c : course} (PROGRAM_REQUIREMENT(?c) => passed(?c))]];
}