use of org.cpsolver.studentsct.model.Section in project cpsolver by UniTime.
the class LinkedSections method hasFullMatch.
/**
* Check if the given enrollment fully matches this constraint
* @param enrollment an enrollment
* @return true, if there is a full match
*/
protected boolean hasFullMatch(Enrollment enrollment) {
// not assigned or not course request
if (enrollment == null || enrollment.getCourse() == null)
return false;
Map<Subpart, Set<Section>> subparts = iSections.get(enrollment.getCourse().getOffering());
// offering is not in the link
if (subparts == null || subparts.isEmpty())
return false;
boolean match = false, partial = false;
for (Section section : enrollment.getSections()) {
Set<Section> sections = subparts.get(section.getSubpart());
if (sections != null) {
if (sections.contains(section))
match = true;
else
partial = true;
}
}
return match && !partial;
}
use of org.cpsolver.studentsct.model.Section in project cpsolver by UniTime.
the class InevitableStudentConflicts method enrollment2string.
/**
* Convert given enrollment to a string (comma separated list of subpart
* names and time assignments only)
*/
private static String enrollment2string(Enrollment enrollment) {
StringBuffer sb = new StringBuffer();
Collection<SctAssignment> assignments = enrollment.getAssignments();
if (enrollment.isCourseRequest()) {
assignments = new TreeSet<SctAssignment>(new Comparator<SctAssignment>() {
@Override
public int compare(SctAssignment a1, SctAssignment a2) {
Section s1 = (Section) a1;
Section s2 = (Section) a2;
return s1.getSubpart().compareTo(s2.getSubpart());
}
});
assignments.addAll(enrollment.getAssignments());
}
for (Iterator<? extends SctAssignment> i = assignments.iterator(); i.hasNext(); ) {
SctAssignment a = i.next();
if (a instanceof Section)
sb.append(((Section) a).getSubpart().getName() + " ");
if (a.getTime() != null)
sb.append(a.getTime().getLongName(true));
if (i.hasNext())
sb.append(", ");
}
return sb.toString();
}
use of org.cpsolver.studentsct.model.Section 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.model.Section in project cpsolver by UniTime.
the class DistanceConflictTable 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("Room"), new CSVFile.CSVField("Distance\nConflicts"), new CSVFile.CSVField("% of Total\nConflicts"), new CSVFile.CSVField("Conflicting\nClass"), new CSVFile.CSVField("Conflicting\nMeeting Time"), new CSVFile.CSVField("Conflicting\nRoom"), new CSVFile.CSVField("Distance [m]"), new CSVFile.CSVField("Distance [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 CourseRequest))
continue;
confs.addAll(iDC.conflicts(e1));
for (Request r2 : r1.getStudent().getRequests()) {
Enrollment e2 = assignment.getValue(r2);
if (e2 == null || r1.getId() >= r2.getId() || !(r2 instanceof CourseRequest))
continue;
confs.addAll(iDC.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;
Section s1 = conflict.getS1(), s2 = conflict.getS2();
Course c1 = null, c2 = null;
Request r1 = null, r2 = null;
for (Request request : conflict.getStudent().getRequests()) {
Enrollment enrollment = assignment.getValue(request);
if (enrollment == null || !enrollment.isCourseRequest())
continue;
if (c1 == null && enrollment.getAssignments().contains(s1)) {
c1 = enrollment.getCourse();
r1 = request;
Set<Long> total = totals.get(enrollment.getCourse());
if (total == null) {
total = new HashSet<Long>();
totals.put(enrollment.getCourse(), total);
}
total.add(enrollment.getStudent().getId());
}
if (c2 == null && enrollment.getAssignments().contains(s2)) {
c2 = enrollment.getCourse();
r2 = request;
Set<Long> total = totals.get(enrollment.getCourse());
if (total == null) {
total = new HashSet<Long>();
totals.put(enrollment.getCourse(), total);
}
total.add(enrollment.getStudent().getId());
}
}
if (c1 == null) {
sLog.error("Unable to find a course for " + s1);
continue;
}
if (c2 == null) {
sLog.error("Unable to find a course for " + s2);
continue;
}
CourseSection a = new CourseSection(c1, s1);
CourseSection b = new CourseSection(c2, s2);
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;
String rooms = "";
if (section.getRooms() != null)
for (RoomLocation r : section.getRooms()) {
if (!rooms.isEmpty())
rooms += "\n";
rooms += r.getName();
}
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 ? rooms : ""));
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)));
String or = "";
if (other.getSection().getRooms() != null)
for (RoomLocation r : other.getSection().getRooms()) {
if (!or.isEmpty())
or += "\n";
or += r.getName();
}
line.add(new CSVFile.CSVField(or));
line.add(new CSVFile.CSVField(sDF2.format(Placement.getDistanceInMeters(iDM, section.getPlacement(), other.getSection().getPlacement()))));
line.add(new CSVFile.CSVField(String.valueOf(Placement.getDistanceInMinutes(iDM, section.getPlacement(), other.getSection().getPlacement()))));
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.Section in project cpsolver by UniTime.
the class RequestGroupTable method create.
@Override
public CSVFile create(Assignment<Request, Enrollment> assignment, DataProperties properties) {
boolean useAmPm = properties.getPropertyBoolean("useAmPm", true);
CSVFile csv = new CSVFile();
csv.setHeader(new CSVFile.CSVField[] { new CSVFile.CSVField("Group"), new CSVFile.CSVField("Course"), new CSVFile.CSVField("Total\nSpread"), new CSVFile.CSVField("Group\nEnrollment"), new CSVFile.CSVField("Class"), new CSVFile.CSVField("Meeting Time"), new CSVFile.CSVField("Class\nSpread"), new CSVFile.CSVField("Class\nEnrollment"), new CSVFile.CSVField("Class\nLimit") });
TreeSet<RequestGroup> groups = new TreeSet<RequestGroup>(new Comparator<RequestGroup>() {
@Override
public int compare(RequestGroup g1, RequestGroup g2) {
int cmp = g1.getName().compareTo(g2.getName());
if (cmp != 0)
return cmp;
cmp = g1.getCourse().getName().compareTo(g2.getCourse().getName());
if (cmp != 0)
return cmp;
if (g1.getId() < g2.getId())
return -1;
if (g1.getId() > g2.getId())
return 1;
return (g1.getCourse().getId() < g2.getCourse().getId() ? -1 : g1.getCourse().getId() > g2.getCourse().getId() ? 1 : 0);
}
});
for (Offering offering : iModel.getOfferings()) for (Course course : offering.getCourses()) groups.addAll(course.getRequestGroups());
for (RequestGroup group : groups) {
double groupEnrollment = group.getEnrollmentWeight(assignment, null);
double groupSpread = group.getAverageSpread(assignment);
for (Config config : group.getCourse().getOffering().getConfigs()) for (Subpart subpart : config.getSubparts()) for (Section section : subpart.getSections()) {
double s = group.getSectionWeight(assignment, section, null);
if (s > 0.00001) {
csv.addLine(new CSVFile.CSVField[] { new CSVFile.CSVField(group.getName()), new CSVFile.CSVField(group.getCourse().getName()), new CSVFile.CSVField(sDF.format(100.0 * groupSpread)), new CSVFile.CSVField(Math.round(groupEnrollment)), new CSVFile.CSVField(section.getSubpart().getName() + " " + section.getName(group.getCourse().getId())), new CSVFile.CSVField(section.getTime() == null ? "" : section.getTime().getDayHeader() + " " + section.getTime().getStartTimeHeader(useAmPm) + " - " + section.getTime().getEndTimeHeader(useAmPm)), new CSVFile.CSVField(sDF.format(100.0 * group.getSectionSpread(assignment, section))), new CSVFile.CSVField(Math.round(group.getSectionWeight(assignment, section, null))), new CSVFile.CSVField(section.getLimit()) });
}
}
}
return csv;
}
Aggregations