use of org.cpsolver.studentsct.model.CourseRequest in project cpsolver by UniTime.
the class MaxOverExpectedConstraint method computeConflicts.
@Override
public void computeConflicts(Assignment<Request, Enrollment> assignment, Enrollment value, Set<Enrollment> conflicts) {
if (!value.isCourseRequest())
return;
CourseRequest cr = (CourseRequest) value.variable();
OnlineSectioningModel model = (OnlineSectioningModel) getModel();
double basePenalty = model.getOverExpected(assignment, value, value, conflicts);
if (basePenalty > iMaxOverExpected) {
conflicts.add(value);
return;
}
RouletteWheelSelection<Enrollment> selection = new RouletteWheelSelection<Enrollment>();
for (Request r : cr.getStudent().getRequests()) {
Enrollment e = assignment.getValue(r);
if (e != null && !r.equals(value.variable()) && !conflicts.contains(e) && e.isCourseRequest()) {
double penalty = model.getOverExpected(assignment, e, value, conflicts);
if (penalty > 0.0)
selection.add(e, penalty);
}
}
while (selection.getRemainingPoints() + basePenalty > iMaxOverExpected && selection.hasMoreElements()) {
conflicts.add(selection.nextElement());
}
}
use of org.cpsolver.studentsct.model.CourseRequest in project cpsolver by UniTime.
the class PriorityStudentWeights method getWeight.
@Override
public double getWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
double weight = getCachedWeight(enrollment.getRequest());
switch(enrollment.getPriority()) {
case 1:
weight *= iFirstAlternativeFactor;
break;
case 2:
weight *= iSecondAlternativeFactor;
break;
}
if (enrollment.isCourseRequest() && iBalancingFactor != 0.0) {
double configUsed = enrollment.getConfig().getEnrollmentTotalWeight(assignment, enrollment.getRequest()) + enrollment.getRequest().getWeight();
double disbalanced = 0;
double total = 0;
for (Section section : enrollment.getSections()) {
Subpart subpart = section.getSubpart();
if (subpart.getSections().size() <= 1)
continue;
double used = section.getEnrollmentTotalWeight(assignment, enrollment.getRequest()) + enrollment.getRequest().getWeight();
// sections have limits -> desired size is section limit x (total enrollment / total limit)
// unlimited sections -> desired size is total enrollment / number of sections
double desired = (subpart.getLimit() > 0 ? section.getLimit() * (configUsed / subpart.getLimit()) : configUsed / subpart.getSections().size());
if (used > desired)
disbalanced += Math.min(enrollment.getRequest().getWeight(), used - desired) / enrollment.getRequest().getWeight();
else
disbalanced -= Math.min(enrollment.getRequest().getWeight(), desired - used) / enrollment.getRequest().getWeight();
total++;
}
if (disbalanced > 0)
weight *= (1.0 - disbalanced / total * iBalancingFactor);
}
if (iMPP) {
double difference = getDifference(enrollment);
if (difference > 0.0)
weight *= (1.0 - difference * iPerturbationFactor);
}
if (iSelectionFactor != 0.0) {
double selection = getSelection(enrollment);
if (selection > 0.0)
weight *= (1.0 - selection * iSelectionFactor);
}
if (enrollment.isCourseRequest() && iGroupFactor != 0.0) {
double sameGroup = 0.0;
int groupCount = 0;
for (RequestGroup g : ((CourseRequest) enrollment.getRequest()).getRequestGroups()) {
if (g.getCourse().equals(enrollment.getCourse())) {
sameGroup += g.getEnrollmentSpread(assignment, enrollment, iGroupBestRatio, iGroupFillRatio);
groupCount++;
}
}
if (groupCount > 0) {
double difference = 1.0 - sameGroup / groupCount;
weight *= (1.0 - difference * iGroupFactor);
}
}
return round(weight);
}
use of org.cpsolver.studentsct.model.CourseRequest in project cpsolver by UniTime.
the class StudentSectioningXMLLoader method loadCourseRequest.
/**
* Load course request
* @param requestEl request element
* @param student parent student
* @param offeringTable offering table
* @param courseTable course table
* @return loaded course request
*/
public CourseRequest loadCourseRequest(Element requestEl, Student student, Map<Long, Offering> offeringTable, Map<Long, Course> courseTable) {
List<Course> courses = new ArrayList<Course>();
courses.add(courseTable.get(Long.valueOf(requestEl.attributeValue("course"))));
for (Iterator<?> k = requestEl.elementIterator("alternative"); k.hasNext(); ) courses.add(courseTable.get(Long.valueOf(((Element) k.next()).attributeValue("course"))));
Long timeStamp = null;
if (requestEl.attributeValue("timeStamp") != null)
timeStamp = Long.valueOf(requestEl.attributeValue("timeStamp"));
CourseRequest courseRequest = new CourseRequest(Long.parseLong(requestEl.attributeValue("id")), Integer.parseInt(requestEl.attributeValue("priority")), "true".equals(requestEl.attributeValue("alternative")), student, courses, "true".equals(requestEl.attributeValue("waitlist", "false")), RequestPriority.valueOf(requestEl.attributeValue("importance", "true".equals(requestEl.attributeValue("critical", "false")) ? RequestPriority.Critical.name() : RequestPriority.Normal.name())), timeStamp);
if (iWaitlistCritical && RequestPriority.Critical.isCritical(courseRequest) && !courseRequest.isAlternative())
courseRequest.setWaitlist(true);
if (requestEl.attributeValue("weight") != null)
courseRequest.setWeight(Double.parseDouble(requestEl.attributeValue("weight")));
for (Iterator<?> k = requestEl.elementIterator("waitlisted"); k.hasNext(); ) {
Element choiceEl = (Element) k.next();
courseRequest.getWaitlistedChoices().add(new Choice(offeringTable.get(Long.valueOf(choiceEl.attributeValue("offering"))), choiceEl.getText()));
}
for (Iterator<?> k = requestEl.elementIterator("selected"); k.hasNext(); ) {
Element choiceEl = (Element) k.next();
courseRequest.getSelectedChoices().add(new Choice(offeringTable.get(Long.valueOf(choiceEl.attributeValue("offering"))), choiceEl.getText()));
}
for (Iterator<?> k = requestEl.elementIterator("required"); k.hasNext(); ) {
Element choiceEl = (Element) k.next();
courseRequest.getRequiredChoices().add(new Choice(offeringTable.get(Long.valueOf(choiceEl.attributeValue("offering"))), choiceEl.getText()));
}
groups: for (Iterator<?> k = requestEl.elementIterator("group"); k.hasNext(); ) {
Element groupEl = (Element) k.next();
long gid = Long.parseLong(groupEl.attributeValue("id"));
String gname = groupEl.attributeValue("name", "g" + gid);
Course course = courseTable.get(Long.valueOf(groupEl.attributeValue("course")));
for (RequestGroup g : course.getRequestGroups()) {
if (g.getId() == gid) {
courseRequest.addRequestGroup(g);
continue groups;
}
}
courseRequest.addRequestGroup(new RequestGroup(gid, gname, course));
}
return courseRequest;
}
use of org.cpsolver.studentsct.model.CourseRequest in project cpsolver by UniTime.
the class Test method fixWeights.
private static void fixWeights(StudentSectioningModel model) {
HashMap<Course, Integer> lastLike = new HashMap<Course, Integer>();
HashMap<Course, Integer> real = new HashMap<Course, Integer>();
HashSet<Long> lastLikeIds = new HashSet<Long>();
HashSet<Long> realIds = new HashSet<Long>();
for (Student student : model.getStudents()) {
if (student.isDummy()) {
if (!lastLikeIds.add(Long.valueOf(student.getId()))) {
sLog.error("Two last-like student with id " + student.getId());
}
} else {
if (!realIds.add(Long.valueOf(student.getId()))) {
sLog.error("Two real student with id " + student.getId());
}
}
for (Request request : student.getRequests()) {
if (request instanceof CourseRequest) {
CourseRequest courseRequest = (CourseRequest) request;
Course course = courseRequest.getCourses().get(0);
Integer cnt = (student.isDummy() ? lastLike : real).get(course);
(student.isDummy() ? lastLike : real).put(course, Integer.valueOf((cnt == null ? 0 : cnt.intValue()) + 1));
}
}
}
for (Student student : new ArrayList<Student>(model.getStudents())) {
if (student.isDummy() && realIds.contains(Long.valueOf(student.getId()))) {
sLog.warn("There is both last-like and real student with id " + student.getId());
long newId = -1;
while (true) {
newId = 1 + (long) (999999999L * Math.random());
if (!realIds.contains(Long.valueOf(newId)) && !lastLikeIds.contains(Long.valueOf(newId)))
break;
}
lastLikeIds.remove(Long.valueOf(student.getId()));
lastLikeIds.add(Long.valueOf(newId));
student.setId(newId);
sLog.warn(" -- last-like student id changed to " + student.getId());
}
for (Request request : new ArrayList<Request>(student.getRequests())) {
if (!student.isDummy()) {
request.setWeight(1.0);
continue;
}
if (request instanceof CourseRequest) {
CourseRequest courseRequest = (CourseRequest) request;
Course course = courseRequest.getCourses().get(0);
Integer lastLikeCnt = lastLike.get(course);
Integer realCnt = real.get(course);
courseRequest.setWeight(getLastLikeStudentWeight(course, realCnt == null ? 0 : realCnt.intValue(), lastLikeCnt == null ? 0 : lastLikeCnt.intValue()));
} else
request.setWeight(1.0);
if (request.getWeight() <= 0.0) {
model.removeVariable(request);
student.getRequests().remove(request);
}
}
if (student.getRequests().isEmpty()) {
model.getStudents().remove(student);
}
}
}
use of org.cpsolver.studentsct.model.CourseRequest in project cpsolver by UniTime.
the class Test method onlineSectioning.
/**
* Online sectioning test
* @param cfg solver configuration
* @return resultant solution
* @throws Exception thrown when the sectioning fails
*/
public static Solution<Request, Enrollment> onlineSectioning(DataProperties cfg) throws Exception {
Solution<Request, Enrollment> solution = load(cfg);
if (solution == null)
return null;
StudentSectioningModel model = (StudentSectioningModel) solution.getModel();
Assignment<Request, Enrollment> assignment = solution.getAssignment();
solution.addSolutionListener(new TestSolutionListener());
double startTime = JProf.currentTimeSec();
Solver<Request, Enrollment> solver = new Solver<Request, Enrollment>(cfg);
solver.setInitalSolution(solution);
solver.initSolver();
OnlineSelection onlineSelection = new OnlineSelection(cfg);
onlineSelection.init(solver);
double totalPenalty = 0, minPenalty = 0, maxPenalty = 0;
double minAvEnrlPenalty = 0, maxAvEnrlPenalty = 0;
double totalPrefPenalty = 0, minPrefPenalty = 0, maxPrefPenalty = 0;
double minAvEnrlPrefPenalty = 0, maxAvEnrlPrefPenalty = 0;
int nrChoices = 0, nrEnrollments = 0, nrCourseRequests = 0;
int chChoices = 0, chCourseRequests = 0, chStudents = 0;
int choiceLimit = model.getProperties().getPropertyInt("Test.ChoicesLimit", -1);
File outDir = new File(model.getProperties().getProperty("General.Output", "."));
outDir.mkdirs();
PrintWriter pw = new PrintWriter(new FileWriter(new File(outDir, "choices.csv")));
List<Student> students = model.getStudents();
try {
@SuppressWarnings("rawtypes") Class studentOrdClass = Class.forName(model.getProperties().getProperty("Test.StudentOrder", StudentRandomOrder.class.getName()));
@SuppressWarnings("unchecked") StudentOrder studentOrd = (StudentOrder) studentOrdClass.getConstructor(new Class[] { DataProperties.class }).newInstance(new Object[] { model.getProperties() });
students = studentOrd.order(model.getStudents());
} catch (Exception e) {
sLog.error("Unable to reorder students, reason: " + e.getMessage(), e);
}
ShutdownHook hook = new ShutdownHook(solver);
Runtime.getRuntime().addShutdownHook(hook);
for (Student student : students) {
if (student.nrAssignedRequests(assignment) > 0)
// skip students with assigned courses (i.e., students
continue;
// already assigned by a batch sectioning process)
sLog.info("Sectioning student: " + student);
BranchBoundSelection.Selection selection = onlineSelection.getSelection(assignment, student);
BranchBoundNeighbour neighbour = selection.select();
if (neighbour != null) {
StudentPreferencePenalties penalties = null;
if (selection instanceof OnlineSelection.EpsilonSelection) {
OnlineSelection.EpsilonSelection epsSelection = (OnlineSelection.EpsilonSelection) selection;
penalties = epsSelection.getPenalties();
for (int i = 0; i < neighbour.getAssignment().length; i++) {
Request r = student.getRequests().get(i);
if (r instanceof CourseRequest) {
nrCourseRequests++;
chCourseRequests++;
int chChoicesThisRq = 0;
CourseRequest request = (CourseRequest) r;
for (Enrollment x : request.getAvaiableEnrollments(assignment)) {
nrEnrollments++;
if (epsSelection.isAllowed(i, x)) {
nrChoices++;
if (choiceLimit <= 0 || chChoicesThisRq < choiceLimit) {
chChoices++;
chChoicesThisRq++;
}
}
}
}
}
chStudents++;
if (chStudents == 100) {
pw.println(sDF.format(((double) chChoices) / chCourseRequests));
pw.flush();
chStudents = 0;
chChoices = 0;
chCourseRequests = 0;
}
}
for (int i = 0; i < neighbour.getAssignment().length; i++) {
if (neighbour.getAssignment()[i] == null)
continue;
Enrollment enrollment = neighbour.getAssignment()[i];
if (enrollment.getRequest() instanceof CourseRequest) {
CourseRequest request = (CourseRequest) enrollment.getRequest();
double[] avEnrlMinMax = getMinMaxAvailableEnrollmentPenalty(assignment, request);
minAvEnrlPenalty += avEnrlMinMax[0];
maxAvEnrlPenalty += avEnrlMinMax[1];
totalPenalty += enrollment.getPenalty();
minPenalty += request.getMinPenalty();
maxPenalty += request.getMaxPenalty();
if (penalties != null) {
double[] avEnrlPrefMinMax = penalties.getMinMaxAvailableEnrollmentPenalty(assignment, enrollment.getRequest());
minAvEnrlPrefPenalty += avEnrlPrefMinMax[0];
maxAvEnrlPrefPenalty += avEnrlPrefMinMax[1];
totalPrefPenalty += penalties.getPenalty(enrollment);
minPrefPenalty += penalties.getMinPenalty(enrollment.getRequest());
maxPrefPenalty += penalties.getMaxPenalty(enrollment.getRequest());
}
}
}
neighbour.assign(assignment, solution.getIteration());
sLog.info("Student " + student + " enrolls into " + neighbour);
onlineSelection.updateSpace(assignment, student);
} else {
sLog.warn("No solution found.");
}
solution.update(JProf.currentTimeSec() - startTime);
solution.saveBest();
}
if (chCourseRequests > 0)
pw.println(sDF.format(((double) chChoices) / chCourseRequests));
pw.flush();
pw.close();
HashMap<String, String> extra = new HashMap<String, String>();
sLog.info("Overall penalty is " + getPerc(totalPenalty, minPenalty, maxPenalty) + "% (" + sDF.format(totalPenalty) + "/" + sDF.format(minPenalty) + ".." + sDF.format(maxPenalty) + ")");
extra.put("Overall penalty", getPerc(totalPenalty, minPenalty, maxPenalty) + "% (" + sDF.format(totalPenalty) + "/" + sDF.format(minPenalty) + ".." + sDF.format(maxPenalty) + ")");
extra.put("Overall available enrollment penalty", getPerc(totalPenalty, minAvEnrlPenalty, maxAvEnrlPenalty) + "% (" + sDF.format(totalPenalty) + "/" + sDF.format(minAvEnrlPenalty) + ".." + sDF.format(maxAvEnrlPenalty) + ")");
if (onlineSelection.isUseStudentPrefPenalties()) {
sLog.info("Overall preference penalty is " + getPerc(totalPrefPenalty, minPrefPenalty, maxPrefPenalty) + "% (" + sDF.format(totalPrefPenalty) + "/" + sDF.format(minPrefPenalty) + ".." + sDF.format(maxPrefPenalty) + ")");
extra.put("Overall preference penalty", getPerc(totalPrefPenalty, minPrefPenalty, maxPrefPenalty) + "% (" + sDF.format(totalPrefPenalty) + "/" + sDF.format(minPrefPenalty) + ".." + sDF.format(maxPrefPenalty) + ")");
extra.put("Overall preference available enrollment penalty", getPerc(totalPrefPenalty, minAvEnrlPrefPenalty, maxAvEnrlPrefPenalty) + "% (" + sDF.format(totalPrefPenalty) + "/" + sDF.format(minAvEnrlPrefPenalty) + ".." + sDF.format(maxAvEnrlPrefPenalty) + ")");
extra.put("Average number of choices", sDF.format(((double) nrChoices) / nrCourseRequests) + " (" + nrChoices + "/" + nrCourseRequests + ")");
extra.put("Average number of enrollments", sDF.format(((double) nrEnrollments) / nrCourseRequests) + " (" + nrEnrollments + "/" + nrCourseRequests + ")");
}
hook.setExtra(extra);
return solution;
}
Aggregations