use of org.cpsolver.studentsct.heuristics.selection.BranchBoundSelection.BranchBoundNeighbour in project cpsolver by UniTime.
the class Test method section.
public boolean section(Student original) {
OnlineSectioningModel model = new TestModel(iModel.getProperties());
model.setOverExpectedCriterion(iModel.getOverExpectedCriterion());
Student student = new Student(original.getId());
Hashtable<CourseRequest, Set<Section>> preferredSectionsForCourse = new Hashtable<CourseRequest, Set<Section>>();
Map<Long, Section> classTable = new HashMap<Long, Section>();
synchronized (iModel) {
for (Request request : original.getRequests()) {
Request clonnedRequest = addRequest(student, original, request, classTable, model);
Enrollment enrollment = assignment().getValue(request);
if (enrollment != null && enrollment.isCourseRequest()) {
Set<Section> sections = new HashSet<Section>();
for (Section section : enrollment.getSections()) sections.add(classTable.get(section.getId()));
preferredSectionsForCourse.put((CourseRequest) clonnedRequest, sections);
}
}
}
model.addStudent(student);
model.setDistanceConflict(new DistanceConflict(iModel.getDistanceConflict().getDistanceMetric(), model.getProperties()));
model.setTimeOverlaps(new TimeOverlapsCounter(null, model.getProperties()));
for (LinkedSections link : iModel.getLinkedSections()) {
List<Section> sections = new ArrayList<Section>();
for (Offering offering : link.getOfferings()) for (Subpart subpart : link.getSubparts(offering)) for (Section section : link.getSections(subpart)) {
Section x = classTable.get(section.getId());
if (x != null)
sections.add(x);
}
if (sections.size() >= 2)
model.addLinkedSections(link.isMustBeUsed(), sections);
}
OnlineSectioningSelection selection = null;
if (model.getProperties().getPropertyBoolean("StudentWeights.MultiCriteria", true)) {
selection = new MultiCriteriaBranchAndBoundSelection(iModel.getProperties());
} else {
selection = new SuggestionSelection(model.getProperties());
}
selection.setModel(model);
selection.setPreferredSections(preferredSectionsForCourse);
selection.setRequiredSections(new Hashtable<CourseRequest, Set<Section>>());
selection.setRequiredFreeTimes(new HashSet<FreeTimeRequest>());
long t0 = JProf.currentTimeMillis();
Assignment<Request, Enrollment> newAssignment = new AssignmentMap<Request, Enrollment>();
BranchBoundNeighbour neighbour = selection.select(newAssignment, student);
long time = JProf.currentTimeMillis() - t0;
inc("[C] CPU Time", time);
if (neighbour == null) {
inc("[F] Failure");
} else {
if (iSuggestions) {
StudentPreferencePenalties penalties = new StudentPreferencePenalties(StudentPreferencePenalties.sDistTypePreference);
double maxOverExpected = 0;
int assigned = 0;
double penalty = 0.0;
Hashtable<CourseRequest, Set<Section>> enrollments = new Hashtable<CourseRequest, Set<Section>>();
List<RequestSectionPair> pairs = new ArrayList<RequestSectionPair>();
for (int i = 0; i < neighbour.getAssignment().length; i++) {
Enrollment enrl = neighbour.getAssignment()[i];
if (enrl != null && enrl.isCourseRequest() && enrl.getAssignments() != null) {
assigned++;
for (Section section : enrl.getSections()) {
maxOverExpected += model.getOverExpected(newAssignment, section, enrl.getRequest());
pairs.add(new RequestSectionPair(enrl.variable(), section));
}
enrollments.put((CourseRequest) enrl.variable(), enrl.getSections());
penalty += penalties.getPenalty(enrl);
}
}
penalty /= assigned;
inc("[S] Initial Penalty", penalty);
double nrSuggestions = 0.0, nrAccepted = 0.0, totalSuggestions = 0.0, nrTries = 0.0;
for (int i = 0; i < pairs.size(); i++) {
RequestSectionPair pair = pairs.get(i);
SuggestionsBranchAndBound suggestionBaB = null;
if (model.getProperties().getPropertyBoolean("StudentWeights.MultiCriteria", true)) {
suggestionBaB = new MultiCriteriaBranchAndBoundSuggestions(model.getProperties(), student, newAssignment, new Hashtable<CourseRequest, Set<Section>>(), new HashSet<FreeTimeRequest>(), enrollments, pair.getRequest(), pair.getSection(), null, maxOverExpected, iModel.getProperties().getPropertyBoolean("StudentWeights.PriorityWeighting", true));
} else {
suggestionBaB = new SuggestionsBranchAndBound(model.getProperties(), student, newAssignment, new Hashtable<CourseRequest, Set<Section>>(), new HashSet<FreeTimeRequest>(), enrollments, pair.getRequest(), pair.getSection(), null, maxOverExpected);
}
long x0 = JProf.currentTimeMillis();
TreeSet<SuggestionsBranchAndBound.Suggestion> suggestions = suggestionBaB.computeSuggestions();
inc("[S] Suggestion CPU Time", JProf.currentTimeMillis() - x0);
totalSuggestions += suggestions.size();
if (!suggestions.isEmpty())
nrSuggestions += 1.0;
nrTries += 1.0;
SuggestionsBranchAndBound.Suggestion best = null;
for (SuggestionsBranchAndBound.Suggestion suggestion : suggestions) {
int a = 0;
double p = 0.0;
for (int j = 0; j < suggestion.getEnrollments().length; j++) {
Enrollment e = suggestion.getEnrollments()[j];
if (e != null && e.isCourseRequest() && e.getAssignments() != null) {
p += penalties.getPenalty(e);
a++;
}
}
p /= a;
if (a > assigned || (assigned == a && p < penalty)) {
best = suggestion;
}
}
if (best != null) {
nrAccepted += 1.0;
Enrollment[] e = best.getEnrollments();
for (int j = 0; j < e.length; j++) if (e[j] != null && e[j].getAssignments() == null)
e[j] = null;
neighbour = new BranchBoundNeighbour(student, best.getValue(), e);
assigned = 0;
penalty = 0.0;
enrollments.clear();
pairs.clear();
for (int j = 0; j < neighbour.getAssignment().length; j++) {
Enrollment enrl = neighbour.getAssignment()[j];
if (enrl != null && enrl.isCourseRequest() && enrl.getAssignments() != null) {
assigned++;
for (Section section : enrl.getSections()) pairs.add(new RequestSectionPair(enrl.variable(), section));
enrollments.put((CourseRequest) enrl.variable(), enrl.getSections());
penalty += penalties.getPenalty(enrl);
}
}
penalty /= assigned;
inc("[S] Improved Penalty", penalty);
}
}
inc("[S] Final Penalty", penalty);
if (nrSuggestions > 0) {
inc("[S] Classes with suggestion", nrSuggestions);
inc("[S] Avg. # of suggestions", totalSuggestions / nrSuggestions);
inc("[S] Suggestion acceptance rate [%]", nrAccepted / nrSuggestions);
} else {
inc("[S] Student with no suggestions available", 1.0);
}
if (!pairs.isEmpty())
inc("[S] Probability that a class has suggestions [%]", nrSuggestions / nrTries);
}
List<Enrollment> enrollments = new ArrayList<Enrollment>();
i: for (int i = 0; i < neighbour.getAssignment().length; i++) {
Request request = original.getRequests().get(i);
Enrollment clonnedEnrollment = neighbour.getAssignment()[i];
if (clonnedEnrollment != null && clonnedEnrollment.getAssignments() != null) {
if (request instanceof FreeTimeRequest) {
enrollments.add(((FreeTimeRequest) request).createEnrollment());
} else {
for (Course course : ((CourseRequest) request).getCourses()) if (course.getId() == clonnedEnrollment.getCourse().getId())
for (Config config : course.getOffering().getConfigs()) if (config.getId() == clonnedEnrollment.getConfig().getId()) {
Set<Section> assignments = new HashSet<Section>();
for (Subpart subpart : config.getSubparts()) for (Section section : subpart.getSections()) {
if (clonnedEnrollment.getSections().contains(section)) {
assignments.add(section);
}
}
Reservation reservation = null;
if (clonnedEnrollment.getReservation() != null) {
for (Reservation r : course.getOffering().getReservations()) if (r.getId() == clonnedEnrollment.getReservation().getId()) {
reservation = r;
break;
}
}
enrollments.add(new Enrollment(request, clonnedEnrollment.getPriority(), course, config, assignments, reservation));
continue i;
}
}
}
}
synchronized (iModel) {
for (Request r : original.getRequests()) {
Enrollment e = assignment().getValue(r);
r.setInitialAssignment(e);
if (e != null)
updateSpace(assignment(), e, true);
}
for (Request r : original.getRequests()) if (assignment().getValue(r) != null)
assignment().unassign(0, r);
boolean fail = false;
for (Enrollment enrl : enrollments) {
if (iModel.conflictValues(assignment(), enrl).isEmpty()) {
assignment().assign(0, enrl);
} else {
fail = true;
break;
}
}
if (fail) {
for (Request r : original.getRequests()) if (assignment().getValue(r) != null)
assignment().unassign(0, r);
for (Request r : original.getRequests()) if (r.getInitialAssignment() != null)
assignment().assign(0, r.getInitialAssignment());
for (Request r : original.getRequests()) if (assignment().getValue(r) != null)
updateSpace(assignment(), assignment().getValue(r), false);
} else {
for (Enrollment enrl : enrollments) updateSpace(assignment(), enrl, false);
}
if (fail)
return false;
}
neighbour.assign(newAssignment, 0);
int a = 0, u = 0, np = 0, zp = 0, pp = 0, cp = 0;
double over = 0;
double p = 0.0;
for (Request r : student.getRequests()) {
if (r instanceof CourseRequest) {
Enrollment e = newAssignment.getValue(r);
if (e != null) {
for (Section s : e.getSections()) {
if (s.getPenalty() < 0.0)
np++;
if (s.getPenalty() == 0.0)
zp++;
if (s.getPenalty() > 0.0)
pp++;
if (s.getLimit() > 0) {
p += s.getPenalty();
cp++;
}
over += model.getOverExpected(newAssignment, s, r);
}
a++;
} else {
u++;
}
}
}
inc("[A] Student");
if (over > 0.0)
inc("[O] Over", over);
if (a > 0)
inc("[A] Assigned", a);
if (u > 0)
inc("[A] Not Assigned", u);
inc("[V] Value", neighbour.value(newAssignment));
if (zp > 0)
inc("[P] Zero penalty", zp);
if (np > 0)
inc("[P] Negative penalty", np);
if (pp > 0)
inc("[P] Positive penalty", pp);
if (cp > 0)
inc("[P] Average penalty", p / cp);
}
inc("[T0] Time <10ms", time < 10 ? 1 : 0);
inc("[T1] Time <100ms", time < 100 ? 1 : 0);
inc("[T2] Time <250ms", time < 250 ? 1 : 0);
inc("[T3] Time <500ms", time < 500 ? 1 : 0);
inc("[T4] Time <1s", time < 1000 ? 1 : 0);
inc("[T5] Time >=1s", time >= 1000 ? 1 : 0);
return true;
}
use of org.cpsolver.studentsct.heuristics.selection.BranchBoundSelection.BranchBoundNeighbour in project cpsolver by UniTime.
the class MultiCriteriaBranchAndBoundSelection method select.
/**
* Execute branch & bound, return the best found schedule for the selected
* student.
*/
public BranchBoundNeighbour select() {
iT0 = JProf.currentTimeMillis();
iTimeoutReached = false;
iCurrentAssignment = new Enrollment[iStudent.getRequests().size()];
iBestAssignment = null;
int i = 0;
for (Request r : iStudent.getRequests()) iCurrentAssignment[i++] = iAssignment.getValue(r);
saveBest();
for (int j = 0; j < iCurrentAssignment.length; j++) iCurrentAssignment[j] = null;
iValues = new HashMap<CourseRequest, List<Enrollment>>();
backTrack(0);
iT1 = JProf.currentTimeMillis();
if (iBestAssignment == null)
return null;
return new BranchBoundNeighbour(iStudent, iComparator.getTotalWeight(iAssignment, iBestAssignment), iBestAssignment);
}
use of org.cpsolver.studentsct.heuristics.selection.BranchBoundSelection.BranchBoundNeighbour 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