use of org.cpsolver.studentsct.model.Enrollment in project cpsolver by UniTime.
the class TimeOverlapConflictTable method createTable.
/**
* Create report
*
* @param assignment current assignment
* @param includeLastLikeStudents
* true, if last-like students should be included (i.e.,
* {@link Student#isDummy()} is true)
* @param includeRealStudents
* true, if real students should be included (i.e.,
* {@link Student#isDummy()} is false)
* @param useAmPm use 12-hour format
* @return report as comma separated text file
*/
public CSVFile createTable(Assignment<Request, Enrollment> assignment, boolean includeLastLikeStudents, boolean includeRealStudents, boolean useAmPm) {
CSVFile csv = new CSVFile();
csv.setHeader(new CSVFile.CSVField[] { new CSVFile.CSVField("Course"), new CSVFile.CSVField("Total\nConflicts"), new CSVFile.CSVField("Class"), new CSVFile.CSVField("Meeting Time"), new CSVFile.CSVField("Time\nConflicts"), new CSVFile.CSVField("% of Total\nConflicts"), new CSVFile.CSVField("Conflicting\nClass"), new CSVFile.CSVField("Conflicting\nMeeting Time"), new CSVFile.CSVField("Overlap [min]"), new CSVFile.CSVField("Joined\nConflicts"), new CSVFile.CSVField("% of Total\nConflicts") });
Set<Conflict> confs = new HashSet<Conflict>();
for (Request r1 : getModel().variables()) {
Enrollment e1 = assignment.getValue(r1);
if (e1 == null || r1 instanceof FreeTimeRequest)
continue;
for (Request r2 : r1.getStudent().getRequests()) {
Enrollment e2 = assignment.getValue(r2);
if (r2 instanceof FreeTimeRequest) {
FreeTimeRequest ft = (FreeTimeRequest) r2;
confs.addAll(iTOC.conflicts(e1, ft.createEnrollment()));
} else if (e2 != null && r1.getId() < r2.getId()) {
confs.addAll(iTOC.conflicts(e1, e2));
}
}
}
HashMap<Course, Set<Long>> totals = new HashMap<Course, Set<Long>>();
HashMap<CourseSection, Map<CourseSection, Double>> conflictingPairs = new HashMap<CourseSection, Map<CourseSection, Double>>();
HashMap<CourseSection, Set<Long>> sectionOverlaps = new HashMap<CourseSection, Set<Long>>();
for (Conflict conflict : confs) {
if (conflict.getStudent().isDummy() && !includeLastLikeStudents)
continue;
if (!conflict.getStudent().isDummy() && !includeRealStudents)
continue;
if (conflict.getR1() == null || conflict.getR1() instanceof FreeTimeRequest || conflict.getR2() == null || conflict.getR2() instanceof FreeTimeRequest)
continue;
Section s1 = (Section) conflict.getS1(), s2 = (Section) conflict.getS2();
Request r1 = conflict.getR1();
Course c1 = assignment.getValue(conflict.getR1()).getCourse();
Request r2 = conflict.getR2();
Course c2 = assignment.getValue(conflict.getR2()).getCourse();
CourseSection a = new CourseSection(c1, s1);
CourseSection b = new CourseSection(c2, s2);
Set<Long> students = totals.get(c1);
if (students == null) {
students = new HashSet<Long>();
totals.put(c1, students);
}
students.add(r1.getStudent().getId());
students = totals.get(c2);
if (students == null) {
students = new HashSet<Long>();
totals.put(c2, students);
}
students.add(r2.getStudent().getId());
Set<Long> total = sectionOverlaps.get(a);
if (total == null) {
total = new HashSet<Long>();
sectionOverlaps.put(a, total);
}
total.add(r1.getStudent().getId());
Map<CourseSection, Double> pair = conflictingPairs.get(a);
if (pair == null) {
pair = new HashMap<CourseSection, Double>();
conflictingPairs.put(a, pair);
}
Double prev = pair.get(b);
pair.put(b, r2.getWeight() + (prev == null ? 0.0 : prev.doubleValue()));
total = sectionOverlaps.get(b);
if (total == null) {
total = new HashSet<Long>();
sectionOverlaps.put(b, total);
}
total.add(r2.getStudent().getId());
pair = conflictingPairs.get(b);
if (pair == null) {
pair = new HashMap<CourseSection, Double>();
conflictingPairs.put(b, pair);
}
prev = pair.get(a);
pair.put(a, r1.getWeight() + (prev == null ? 0.0 : prev.doubleValue()));
}
Comparator<Course> courseComparator = new Comparator<Course>() {
@Override
public int compare(Course a, Course b) {
int cmp = a.getName().compareTo(b.getName());
if (cmp != 0)
return cmp;
return a.getId() < b.getId() ? -1 : a.getId() == b.getId() ? 0 : 1;
}
};
Comparator<Section> sectionComparator = new Comparator<Section>() {
@Override
public int compare(Section a, Section b) {
int cmp = a.getSubpart().getConfig().getOffering().getName().compareTo(b.getSubpart().getConfig().getOffering().getName());
if (cmp != 0)
return cmp;
cmp = a.getSubpart().getInstructionalType().compareTo(b.getSubpart().getInstructionalType());
// cmp = a.getName().compareTo(b.getName());
if (cmp != 0)
return cmp;
return a.getId() < b.getId() ? -1 : a.getId() == b.getId() ? 0 : 1;
}
};
TreeSet<Course> courses = new TreeSet<Course>(courseComparator);
courses.addAll(totals.keySet());
for (Course course : courses) {
Set<Long> total = totals.get(course);
TreeSet<Section> sections = new TreeSet<Section>(sectionComparator);
for (Map.Entry<CourseSection, Set<Long>> entry : sectionOverlaps.entrySet()) if (course.equals(entry.getKey().getCourse()))
sections.add(entry.getKey().getSection());
boolean firstCourse = true;
for (Section section : sections) {
Set<Long> sectionOverlap = sectionOverlaps.get(new CourseSection(course, section));
Map<CourseSection, Double> pair = conflictingPairs.get(new CourseSection(course, section));
boolean firstClass = true;
for (CourseSection other : new TreeSet<CourseSection>(pair.keySet())) {
List<CSVFile.CSVField> line = new ArrayList<CSVFile.CSVField>();
line.add(new CSVFile.CSVField(firstCourse && firstClass ? course.getName() : ""));
line.add(new CSVFile.CSVField(firstCourse && firstClass ? total.size() : ""));
line.add(new CSVFile.CSVField(firstClass ? section.getSubpart().getName() + " " + section.getName(course.getId()) : ""));
line.add(new CSVFile.CSVField(firstClass ? section.getTime() == null ? "" : section.getTime().getDayHeader() + " " + section.getTime().getStartTimeHeader(useAmPm) + " - " + section.getTime().getEndTimeHeader(useAmPm) : ""));
line.add(new CSVFile.CSVField(firstClass && sectionOverlap != null ? String.valueOf(sectionOverlap.size()) : ""));
line.add(new CSVFile.CSVField(firstClass && sectionOverlap != null ? sDF2.format(((double) sectionOverlap.size()) / total.size()) : ""));
line.add(new CSVFile.CSVField(other.getCourse().getName() + " " + other.getSection().getSubpart().getName() + " " + other.getSection().getName(other.getCourse().getId())));
line.add(new CSVFile.CSVField(other.getSection().getTime().getDayHeader() + " " + other.getSection().getTime().getStartTimeHeader(useAmPm) + " - " + other.getSection().getTime().getEndTimeHeader(useAmPm)));
line.add(new CSVFile.CSVField(sDF1.format(5 * iTOC.share(section, other.getSection()))));
line.add(new CSVFile.CSVField(sDF1.format(pair.get(other))));
line.add(new CSVFile.CSVField(sDF2.format(pair.get(other) / total.size())));
csv.addLine(line);
firstClass = false;
}
firstCourse = false;
}
csv.addLine();
}
return csv;
}
use of org.cpsolver.studentsct.model.Enrollment in project cpsolver by UniTime.
the class MultiCriteriaBranchAndBoundSelection method backTrack.
/** branch & bound search */
public void backTrack(int idx) {
if (iTimeout > 0 && (JProf.currentTimeMillis() - iT0) > iTimeout) {
iTimeoutReached = true;
return;
}
if (idx == iCurrentAssignment.length) {
if (iBestAssignment == null || iComparator.compare(iAssignment, iCurrentAssignment, iBestAssignment) < 0)
saveBest();
return;
} else if (iBestAssignment != null && !iComparator.canImprove(iAssignment, idx, iCurrentAssignment, iBestAssignment)) {
return;
}
Request request = iStudent.getRequests().get(idx);
if (!canAssign(request, idx)) {
backTrack(idx + 1);
return;
}
List<Enrollment> values = null;
if (request instanceof CourseRequest) {
CourseRequest courseRequest = (CourseRequest) request;
if (!courseRequest.getSelectedChoices().isEmpty()) {
values = courseRequest.getSelectedEnrollments(iAssignment, true);
if (values != null && !values.isEmpty()) {
boolean hasNoConflictValue = false;
for (Enrollment enrollment : values) {
if (inConflict(idx, enrollment))
continue;
hasNoConflictValue = true;
iCurrentAssignment[idx] = enrollment;
backTrack(idx + 1);
iCurrentAssignment[idx] = null;
}
if (hasNoConflictValue && iBranchWhenSelectedHasNoConflict)
return;
}
}
values = iValues.get(courseRequest);
if (values == null) {
values = values(courseRequest);
iValues.put(courseRequest, values);
}
} else {
values = request.computeEnrollments(iAssignment);
}
boolean hasNoConflictValue = false;
for (Enrollment enrollment : values) {
if (inConflict(idx, enrollment))
continue;
hasNoConflictValue = true;
iCurrentAssignment[idx] = enrollment;
backTrack(idx + 1);
iCurrentAssignment[idx] = null;
}
if (canLeaveUnassigned(request) || (!hasNoConflictValue && request instanceof CourseRequest))
backTrack(idx + 1);
}
use of org.cpsolver.studentsct.model.Enrollment in project cpsolver by UniTime.
the class SwapStudentSelection method bestSwap.
/**
* Identify the best swap for the given student
*
* @param assignment current assignment
* @param conflict
* conflicting enrollment
* @param enrl
* enrollment that is visited (to be assigned to the given
* student)
* @param problematicStudents
* the current set of problematic students
* @return best alternative enrollment for the student of the conflicting
* enrollment
*/
public static Enrollment bestSwap(Assignment<Request, Enrollment> assignment, Enrollment conflict, Enrollment enrl, Set<Student> problematicStudents) {
Enrollment bestEnrollment = null;
double bestValue = 0;
for (Enrollment enrollment : conflict.getRequest().values(assignment)) {
if (conflict.variable().getModel().inConflict(assignment, enrollment))
continue;
double value = enrollment.toDouble(assignment);
if (bestEnrollment == null || bestValue > value) {
bestEnrollment = enrollment;
bestValue = value;
}
}
if (bestEnrollment == null && problematicStudents != null) {
boolean added = false;
for (Enrollment enrollment : conflict.getRequest().values(assignment)) {
Set<Enrollment> conflicts = conflict.variable().getModel().conflictValues(assignment, enrollment);
for (Enrollment c : conflicts) {
if (enrl.getStudent().isDummy() && !c.getStudent().isDummy())
continue;
if (enrl.getStudent().equals(c.getStudent()) || conflict.getStudent().equals(c.getStudent()))
continue;
problematicStudents.add(c.getStudent());
}
}
if (!added && !enrl.getStudent().equals(conflict.getStudent()))
problematicStudents.add(conflict.getStudent());
}
return bestEnrollment;
}
use of org.cpsolver.studentsct.model.Enrollment 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);
}
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;
}
use of org.cpsolver.studentsct.model.Enrollment in project cpsolver by UniTime.
the class Test method load.
/** Load student sectioning model
* @param cfg solver configuration
* @return loaded solution
**/
public static Solution<Request, Enrollment> load(DataProperties cfg) {
StudentSectioningModel model = null;
Assignment<Request, Enrollment> assignment = null;
try {
if (cfg.getProperty("Test.CombineStudents") == null) {
model = new StudentSectioningModel(cfg);
assignment = new DefaultSingleAssignment<Request, Enrollment>();
new StudentSectioningXMLLoader(model, assignment).load();
} else {
Solution<Request, Enrollment> solution = combineStudents(cfg, new File(cfg.getProperty("Test.CombineStudentsLastLike", cfg.getProperty("General.Input", "." + File.separator + "solution.xml"))), new File(cfg.getProperty("Test.CombineStudents")));
model = (StudentSectioningModel) solution.getModel();
assignment = solution.getAssignment();
}
if (cfg.getProperty("Test.ExtraStudents") != null) {
StudentSectioningXMLLoader extra = new StudentSectioningXMLLoader(model, assignment);
extra.setInputFile(new File(cfg.getProperty("Test.ExtraStudents")));
extra.setLoadOfferings(false);
extra.setLoadStudents(true);
extra.setStudentFilter(new ExtraStudentFilter(model));
extra.load();
}
if (cfg.getProperty("Test.LastLikeCourseDemands") != null)
loadLastLikeCourseDemandsXml(model, new File(cfg.getProperty("Test.LastLikeCourseDemands")));
if (cfg.getProperty("Test.StudentInfos") != null)
loadStudentInfoXml(model, new File(cfg.getProperty("Test.StudentInfos")));
if (cfg.getProperty("Test.CrsReq") != null)
loadCrsReqFiles(model, cfg.getProperty("Test.CrsReq"));
} catch (Exception e) {
sLog.error("Unable to load model, reason: " + e.getMessage(), e);
return null;
}
if (cfg.getPropertyBoolean("Debug.DistanceConflict", false))
DistanceConflict.sDebug = true;
if (cfg.getPropertyBoolean("Debug.BranchBoundSelection", false))
BranchBoundSelection.sDebug = true;
if (cfg.getPropertyBoolean("Debug.SwapStudentsSelection", false))
SwapStudentSelection.sDebug = true;
if (cfg.getPropertyBoolean("Debug.TimeOverlaps", false))
TimeOverlapsCounter.sDebug = true;
if (cfg.getProperty("CourseRequest.SameTimePrecise") != null)
CourseRequest.sSameTimePrecise = cfg.getPropertyBoolean("CourseRequest.SameTimePrecise", false);
Logger.getLogger(BacktrackNeighbourSelection.class).setLevel(cfg.getPropertyBoolean("Debug.BacktrackNeighbourSelection", false) ? Level.DEBUG : Level.INFO);
if (cfg.getPropertyBoolean("Test.FixPriorities", false))
fixPriorities(model);
return new Solution<Request, Enrollment>(model, assignment);
}
Aggregations