use of org.cpsolver.studentsct.model.Offering in project cpsolver by UniTime.
the class Test method loadLastLikeCourseDemandsXml.
/**
* Load last-like students from an XML file (the one that is used to load
* last like course demands table in the timetabling application)
* @param model problem model
* @param xml an XML file
*/
public static void loadLastLikeCourseDemandsXml(StudentSectioningModel model, File xml) {
try {
Document document = (new SAXReader()).read(xml);
Element root = document.getRootElement();
HashMap<Course, List<Request>> requests = new HashMap<Course, List<Request>>();
long reqId = 0;
for (Iterator<?> i = root.elementIterator("student"); i.hasNext(); ) {
Element studentEl = (Element) i.next();
Student student = new Student(Long.parseLong(studentEl.attributeValue("externalId")));
student.setDummy(true);
int priority = 0;
HashSet<Course> reqCourses = new HashSet<Course>();
for (Iterator<?> j = studentEl.elementIterator("studentCourse"); j.hasNext(); ) {
Element courseEl = (Element) j.next();
String subjectArea = courseEl.attributeValue("subject");
String courseNbr = courseEl.attributeValue("courseNumber");
Course course = null;
offerings: for (Offering offering : model.getOfferings()) {
for (Course c : offering.getCourses()) {
if (c.getSubjectArea().equals(subjectArea) && c.getCourseNumber().equals(courseNbr)) {
course = c;
break offerings;
}
}
}
if (course == null && courseNbr.charAt(courseNbr.length() - 1) >= 'A' && courseNbr.charAt(courseNbr.length() - 1) <= 'Z') {
String courseNbrNoSfx = courseNbr.substring(0, courseNbr.length() - 1);
offerings: for (Offering offering : model.getOfferings()) {
for (Course c : offering.getCourses()) {
if (c.getSubjectArea().equals(subjectArea) && c.getCourseNumber().equals(courseNbrNoSfx)) {
course = c;
break offerings;
}
}
}
}
if (course == null) {
sLog.warn("Course " + subjectArea + " " + courseNbr + " not found.");
} else {
if (!reqCourses.add(course)) {
sLog.warn("Course " + subjectArea + " " + courseNbr + " already requested.");
} else {
List<Course> courses = new ArrayList<Course>(1);
courses.add(course);
CourseRequest request = new CourseRequest(reqId++, priority++, false, student, courses, false, null);
List<Request> requestsThisCourse = requests.get(course);
if (requestsThisCourse == null) {
requestsThisCourse = new ArrayList<Request>();
requests.put(course, requestsThisCourse);
}
requestsThisCourse.add(request);
}
}
}
if (!student.getRequests().isEmpty())
model.addStudent(student);
}
for (Map.Entry<Course, List<Request>> entry : requests.entrySet()) {
Course course = entry.getKey();
List<Request> requestsThisCourse = entry.getValue();
double weight = getLastLikeStudentWeight(course, 0, requestsThisCourse.size());
for (Request request : requestsThisCourse) {
request.setWeight(weight);
}
}
} catch (Exception e) {
sLog.error(e.getMessage(), e);
}
}
use of org.cpsolver.studentsct.model.Offering in project cpsolver by UniTime.
the class SectionLimitCheck method check.
/**
* Check for sections that have more students enrolled than it is allowed,
* i.e., the sum of requests weights is above the section limit
* @param assignment current assignment
* @return false, if there is such a case
*/
public boolean check(Assignment<Request, Enrollment> assignment) {
sLog.info("Checking section limits...");
boolean ret = true;
for (Offering offering : getModel().getOfferings()) {
for (Config config : offering.getConfigs()) {
for (Subpart subpart : config.getSubparts()) {
for (Section section : subpart.getSections()) {
if (section.getLimit() < 0)
continue;
double used = section.getEnrollmentWeight(assignment, null);
if (used - section.getMaxEnrollmentWeight(assignment) > section.getLimit()) {
sLog.error("Section " + section.getName() + " exceeds its limit " + sDF.format(used) + ">" + section.getLimit() + " for more than one student (W:" + section.getMaxEnrollmentWeight(assignment) + ")");
ret = false;
} else if (Math.round(used) > section.getLimit()) {
sLog.debug("Section " + section.getName() + " exceeds its limit " + sDF.format(used) + ">" + section.getLimit() + " for less than one student (W:" + section.getMaxEnrollmentWeight(assignment) + ")");
}
}
}
}
}
return ret;
}
use of org.cpsolver.studentsct.model.Offering in project cpsolver by UniTime.
the class StudentSectioningModel method toString.
@Override
public String toString(Assignment<Request, Enrollment> assignment) {
double groupSpread = 0.0;
double groupCount = 0;
for (Offering offering : iOfferings) {
for (Course course : offering.getCourses()) {
for (RequestGroup group : course.getRequestGroups()) {
groupSpread += group.getAverageSpread(assignment) * group.getEnrollmentWeight(assignment, null);
groupCount += group.getEnrollmentWeight(assignment, null);
}
}
}
String priority = "";
for (StudentPriority sp : StudentPriority.values()) {
if (sp.ordinal() < StudentPriority.Normal.ordinal()) {
if (iTotalPriorityCRWeight[sp.ordinal()] > 0.0)
priority += sp.code() + "PCR:" + sDecimalFormat.format(100.0 * getContext(assignment).iAssignedPriorityCRWeight[sp.ordinal()] / iTotalPriorityCRWeight[sp.ordinal()]) + "%, ";
if (iTotalPriorityCriticalCRWeight[RequestPriority.Critical.ordinal()][sp.ordinal()] > 0.0)
priority += sp.code() + "PCC:" + sDecimalFormat.format(100.0 * getContext(assignment).iAssignedPriorityCriticalCRWeight[RequestPriority.Critical.ordinal()][sp.ordinal()] / iTotalPriorityCriticalCRWeight[RequestPriority.Critical.ordinal()][sp.ordinal()]) + "%, ";
if (iTotalPriorityCriticalCRWeight[RequestPriority.Important.ordinal()][sp.ordinal()] > 0.0)
priority += sp.code() + "PCI:" + sDecimalFormat.format(100.0 * getContext(assignment).iAssignedPriorityCriticalCRWeight[RequestPriority.Important.ordinal()][sp.ordinal()] / iTotalPriorityCriticalCRWeight[RequestPriority.Important.ordinal()][sp.ordinal()]) + "%, ";
}
}
return (getNrRealStudents(false) > 0 ? "RRq:" + getNrAssignedRealRequests(assignment, false) + "/" + getNrRealRequests(false) + ", " : "") + (getNrLastLikeStudents(false) > 0 ? "DRq:" + getNrAssignedLastLikeRequests(assignment, false) + "/" + getNrLastLikeRequests(false) + ", " : "") + (getNrRealStudents(false) > 0 ? "RS:" + getNrCompleteRealStudents(assignment, false) + "/" + getNrRealStudents(false) + ", " : "") + (getNrLastLikeStudents(false) > 0 ? "DS:" + getNrCompleteLastLikeStudents(assignment, false) + "/" + getNrLastLikeStudents(false) + ", " : "") + (iTotalCRWeight > 0.0 ? "CR:" + sDecimalFormat.format(100.0 * getContext(assignment).getAssignedCourseRequestWeight() / iTotalCRWeight) + "%, " : "") + (iTotalSelCRWeight > 0.0 ? "S:" + sDoubleFormat.format(100.0 * (0.3 * getContext(assignment).iAssignedSelectedConfigWeight + 0.7 * getContext(assignment).iAssignedSelectedSectionWeight) / iTotalSelCRWeight) + "%, " : "") + (iTotalCriticalCRWeight[RequestPriority.Critical.ordinal()] > 0.0 ? "CC:" + sDecimalFormat.format(100.0 * getContext(assignment).getAssignedCriticalCourseRequestWeight(RequestPriority.Critical) / iTotalCriticalCRWeight[RequestPriority.Critical.ordinal()]) + "%, " : "") + (iTotalCriticalCRWeight[RequestPriority.Important.ordinal()] > 0.0 ? "IC:" + sDecimalFormat.format(100.0 * getContext(assignment).getAssignedCriticalCourseRequestWeight(RequestPriority.Important) / iTotalCriticalCRWeight[RequestPriority.Important.ordinal()]) + "%, " : "") + priority + "V:" + sDecimalFormat.format(-getTotalValue(assignment)) + (getDistanceConflict() == null ? "" : ", DC:" + getDistanceConflict().getTotalNrConflicts(assignment)) + (getTimeOverlaps() == null ? "" : ", TOC:" + getTimeOverlaps().getTotalNrConflicts(assignment)) + (iMPP ? ", IS:" + sDecimalFormat.format(100.0 * getContext(assignment).iAssignedSameSectionWeight / iTotalMPPCRWeight) + "%" : "") + (iMPP ? ", IT:" + sDecimalFormat.format(100.0 * getContext(assignment).iAssignedSameTimeWeight / iTotalMPPCRWeight) + "%" : "") + ", %:" + sDecimalFormat.format(-100.0 * getTotalValue(assignment) / (getStudents().size() - iNrDummyStudents + (iProjectedStudentWeight < 0.0 ? iNrDummyStudents * (iTotalDummyWeight / iNrDummyRequests) : iProjectedStudentWeight * iTotalDummyWeight))) + (groupCount > 0 ? ", SG:" + sDecimalFormat.format(100.0 * groupSpread / groupCount) + "%" : "") + (getStudentQuality() == null ? "" : ", SQ:{" + getStudentQuality().toString(assignment) + "}");
}
use of org.cpsolver.studentsct.model.Offering in project cpsolver by UniTime.
the class StudentSectioningModel method getInfo.
/**
* Model info
*/
@Override
public Map<String, String> getInfo(Assignment<Request, Enrollment> assignment) {
Map<String, String> info = super.getInfo(assignment);
StudentSectioningModelContext context = getContext(assignment);
if (!getStudents().isEmpty())
info.put("Students with complete schedule", sDoubleFormat.format(100.0 * context.nrComplete() / getStudents().size()) + "% (" + context.nrComplete() + "/" + getStudents().size() + ")");
String priorityComplete = "";
for (StudentPriority sp : StudentPriority.values()) {
if (sp != StudentPriority.Dummy && iNrPriorityStudents[sp.ordinal()] > 0)
priorityComplete += (priorityComplete.isEmpty() ? "" : "\n") + sp.name() + ": " + sDoubleFormat.format(100.0 * context.iNrCompletePriorityStudents[sp.ordinal()] / iNrPriorityStudents[sp.ordinal()]) + "% (" + context.iNrCompletePriorityStudents[sp.ordinal()] + "/" + iNrPriorityStudents[sp.ordinal()] + ")";
}
if (!priorityComplete.isEmpty())
info.put("Students with complete schedule (priority students)", priorityComplete);
if (getStudentQuality() != null) {
int confs = getStudentQuality().getTotalPenalty(StudentQuality.Type.Distance, assignment);
int shortConfs = getStudentQuality().getTotalPenalty(StudentQuality.Type.ShortDistance, assignment);
if (confs > 0 || shortConfs > 0) {
info.put("Student distance conflicts", confs + (shortConfs == 0 ? "" : " (" + getDistanceMetric().getShortDistanceAccommodationReference() + ": " + shortConfs + ")"));
}
} else if (getDistanceConflict() != null) {
int confs = getDistanceConflict().getTotalNrConflicts(assignment);
if (confs > 0) {
int shortConfs = getDistanceConflict().getTotalNrShortConflicts(assignment);
info.put("Student distance conflicts", confs + (shortConfs == 0 ? "" : " (" + getDistanceConflict().getDistanceMetric().getShortDistanceAccommodationReference() + ": " + shortConfs + ")"));
}
}
if (getStudentQuality() != null) {
int shareCR = getStudentQuality().getContext(assignment).countTotalPenalty(StudentQuality.Type.CourseTimeOverlap, assignment);
int shareFT = getStudentQuality().getContext(assignment).countTotalPenalty(StudentQuality.Type.FreeTimeOverlap, assignment);
int shareUN = getStudentQuality().getContext(assignment).countTotalPenalty(StudentQuality.Type.Unavailability, assignment);
if (shareCR + shareFT + shareUN > 0)
info.put("Time overlapping conflicts", sDoubleFormat.format((5.0 * (shareCR + shareFT + shareUN)) / iStudents.size()) + " mins per student\n" + "(" + sDoubleFormat.format(5.0 * shareCR / iStudents.size()) + " between courses, " + sDoubleFormat.format(5.0 * shareFT / iStudents.size()) + " free time" + (shareUN == 0 ? "" : ", " + sDoubleFormat.format(5.0 * shareUN / iStudents.size()) + " teaching assignments") + "; " + sDoubleFormat.format((shareCR + shareFT + shareUN) / 12.0) + " hours total)");
} else if (getTimeOverlaps() != null && getTimeOverlaps().getTotalNrConflicts(assignment) != 0) {
info.put("Time overlapping conflicts", sDoubleFormat.format(5.0 * getTimeOverlaps().getTotalNrConflicts(assignment) / iStudents.size()) + " mins per student (" + sDoubleFormat.format(getTimeOverlaps().getTotalNrConflicts(assignment) / 12.0) + " hours total)");
}
if (getStudentQuality() != null) {
int confLunch = getStudentQuality().getTotalPenalty(StudentQuality.Type.LunchBreak, assignment);
if (confLunch > 0)
info.put("Schedule Quality: Lunch conflicts", sDoubleFormat.format(20.0 * confLunch / getNrRealStudents(false)) + "% (" + confLunch + ")");
int confTravel = getStudentQuality().getTotalPenalty(StudentQuality.Type.TravelTime, assignment);
if (confTravel > 0)
info.put("Schedule Quality: Travel time", sDoubleFormat.format(((double) confTravel) / getNrRealStudents(false)) + " mins per student (" + sDecimalFormat.format(confTravel / 60.0) + " hours total)");
int confBtB = getStudentQuality().getTotalPenalty(StudentQuality.Type.BackToBack, assignment);
if (confBtB > 0)
info.put("Schedule Quality: Back-to-back classes", sDoubleFormat.format(((double) confBtB) / getNrRealStudents(false)) + " per student (" + confBtB + ")");
int confWorkDay = getStudentQuality().getTotalPenalty(StudentQuality.Type.WorkDay, assignment);
if (confWorkDay > 0)
info.put("Schedule Quality: Work day", sDoubleFormat.format(5.0 * confWorkDay / getNrRealStudents(false)) + " mins over " + new DecimalFormat("0.#").format(getProperties().getPropertyInt("WorkDay.WorkDayLimit", 6 * 12) / 12.0) + " hours a day per student\n(from start to end, " + sDoubleFormat.format(confWorkDay / 12.0) + " hours total)");
int early = getStudentQuality().getTotalPenalty(StudentQuality.Type.TooEarly, assignment);
if (early > 0) {
int min = getProperties().getPropertyInt("WorkDay.EarlySlot", 102) * Constants.SLOT_LENGTH_MIN + Constants.FIRST_SLOT_TIME_MIN;
int h = min / 60;
int m = min % 60;
String time = (getProperties().getPropertyBoolean("General.UseAmPm", true) ? (h > 12 ? h - 12 : h) + ":" + (m < 10 ? "0" : "") + m + (h >= 12 ? "p" : "a") : h + ":" + (m < 10 ? "0" : "") + m);
info.put("Schedule Quality: Early classes", sDoubleFormat.format(5.0 * early / iStudents.size()) + " mins before " + time + " per student (" + sDoubleFormat.format(early / 12.0) + " hours total)");
}
int late = getStudentQuality().getTotalPenalty(StudentQuality.Type.TooLate, assignment);
if (late > 0) {
int min = getProperties().getPropertyInt("WorkDay.LateSlot", 210) * Constants.SLOT_LENGTH_MIN + Constants.FIRST_SLOT_TIME_MIN;
int h = min / 60;
int m = min % 60;
String time = (getProperties().getPropertyBoolean("General.UseAmPm", true) ? (h > 12 ? h - 12 : h) + ":" + (m < 10 ? "0" : "") + m + (h >= 12 ? "p" : "a") : h + ":" + (m < 10 ? "0" : "") + m);
info.put("Schedule Quality: Late classes", sDoubleFormat.format(5.0 * late / iStudents.size()) + " mins after " + time + " per student (" + sDoubleFormat.format(late / 12.0) + " hours total)");
}
int accFT = getStudentQuality().getTotalPenalty(StudentQuality.Type.AccFreeTimeOverlap, assignment);
if (accFT > 0) {
info.put("Accommodations: Free time conflicts", sDoubleFormat.format(5.0 * accFT / getStudentsWithAccommodation(getStudentQuality().getStudentQualityContext().getFreeTimeAccommodation())) + " mins per student, " + sDoubleFormat.format(accFT / 12.0) + " hours total");
}
int accBtB = getStudentQuality().getTotalPenalty(StudentQuality.Type.AccBackToBack, assignment);
if (accBtB > 0) {
info.put("Accommodations: Back-to-back classes", sDoubleFormat.format(((double) accBtB) / getStudentsWithAccommodation(getStudentQuality().getStudentQualityContext().getBackToBackAccommodation())) + " non-BTB classes per student, " + accBtB + " total");
}
int accBbc = getStudentQuality().getTotalPenalty(StudentQuality.Type.AccBreaksBetweenClasses, assignment);
if (accBbc > 0) {
info.put("Accommodations: Break between classes", sDoubleFormat.format(((double) accBbc) / getStudentsWithAccommodation(getStudentQuality().getStudentQualityContext().getBreakBetweenClassesAccommodation())) + " BTB classes per student, " + accBbc + " total");
}
int shortConfs = getStudentQuality().getTotalPenalty(StudentQuality.Type.ShortDistance, assignment);
if (shortConfs > 0) {
info.put("Accommodations: Distance conflicts", sDoubleFormat.format(((double) shortConfs) / getStudentsWithAccommodation(getStudentQuality().getDistanceMetric().getShortDistanceAccommodationReference())) + " short distance conflicts per student, " + shortConfs + " total");
}
}
int nrLastLikeStudents = getNrLastLikeStudents(false);
if (nrLastLikeStudents != 0 && nrLastLikeStudents != getStudents().size()) {
int nrRealStudents = getStudents().size() - nrLastLikeStudents;
int nrLastLikeCompleteStudents = getNrCompleteLastLikeStudents(assignment, false);
int nrRealCompleteStudents = context.nrComplete() - nrLastLikeCompleteStudents;
if (nrLastLikeStudents > 0)
info.put("Projected students with complete schedule", sDecimalFormat.format(100.0 * nrLastLikeCompleteStudents / nrLastLikeStudents) + "% (" + nrLastLikeCompleteStudents + "/" + nrLastLikeStudents + ")");
if (nrRealStudents > 0)
info.put("Real students with complete schedule", sDecimalFormat.format(100.0 * nrRealCompleteStudents / nrRealStudents) + "% (" + nrRealCompleteStudents + "/" + nrRealStudents + ")");
int nrLastLikeRequests = getNrLastLikeRequests(false);
int nrRealRequests = variables().size() - nrLastLikeRequests;
int nrLastLikeAssignedRequests = context.getNrAssignedLastLikeRequests();
int nrRealAssignedRequests = assignment.nrAssignedVariables() - nrLastLikeAssignedRequests;
if (nrLastLikeRequests > 0)
info.put("Projected assigned requests", sDecimalFormat.format(100.0 * nrLastLikeAssignedRequests / nrLastLikeRequests) + "% (" + nrLastLikeAssignedRequests + "/" + nrLastLikeRequests + ")");
if (nrRealRequests > 0)
info.put("Real assigned requests", sDecimalFormat.format(100.0 * nrRealAssignedRequests / nrRealRequests) + "% (" + nrRealAssignedRequests + "/" + nrRealRequests + ")");
}
context.getInfo(assignment, info);
double groupSpread = 0.0;
double groupCount = 0;
for (Offering offering : iOfferings) {
for (Course course : offering.getCourses()) {
for (RequestGroup group : course.getRequestGroups()) {
groupSpread += group.getAverageSpread(assignment) * group.getEnrollmentWeight(assignment, null);
groupCount += group.getEnrollmentWeight(assignment, null);
}
}
}
if (groupCount > 0)
info.put("Same group", sDecimalFormat.format(100.0 * groupSpread / groupCount) + "%");
return info;
}
use of org.cpsolver.studentsct.model.Offering in project cpsolver by UniTime.
the class StudentSectioningModel method clearOnlineSectioningInfos.
/**
* Empty online student sectioning infos for all sections (see
* {@link Section#getSpaceExpected()} and {@link Section#getSpaceHeld()}).
*/
public void clearOnlineSectioningInfos() {
for (Offering offering : iOfferings) {
for (Config config : offering.getConfigs()) {
for (Subpart subpart : config.getSubparts()) {
for (Section section : subpart.getSections()) {
section.setSpaceExpected(0);
section.setSpaceHeld(0);
}
}
}
}
}
Aggregations