Search in sources :

Example 1 with Offering

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);
    }
}
Also used : HashMap(java.util.HashMap) SAXReader(org.dom4j.io.SAXReader) Element(org.dom4j.Element) ArrayList(java.util.ArrayList) Document(org.dom4j.Document) List(java.util.List) ArrayList(java.util.ArrayList) Course(org.cpsolver.studentsct.model.Course) HashSet(java.util.HashSet) Request(org.cpsolver.studentsct.model.Request) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) Student(org.cpsolver.studentsct.model.Student) Offering(org.cpsolver.studentsct.model.Offering) IOException(java.io.IOException) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) Map(java.util.Map) HashMap(java.util.HashMap)

Example 2 with Offering

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;
}
Also used : Config(org.cpsolver.studentsct.model.Config) Subpart(org.cpsolver.studentsct.model.Subpart) Offering(org.cpsolver.studentsct.model.Offering) Section(org.cpsolver.studentsct.model.Section)

Example 3 with Offering

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) + "}");
}
Also used : RequestGroup(org.cpsolver.studentsct.model.RequestGroup) StudentPriority(org.cpsolver.studentsct.model.Student.StudentPriority) Course(org.cpsolver.studentsct.model.Course) Offering(org.cpsolver.studentsct.model.Offering)

Example 4 with Offering

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;
}
Also used : RequestGroup(org.cpsolver.studentsct.model.RequestGroup) DecimalFormat(java.text.DecimalFormat) StudentPriority(org.cpsolver.studentsct.model.Student.StudentPriority) Course(org.cpsolver.studentsct.model.Course) Offering(org.cpsolver.studentsct.model.Offering) Constraint(org.cpsolver.ifs.model.Constraint)

Example 5 with Offering

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);
                }
            }
        }
    }
}
Also used : Config(org.cpsolver.studentsct.model.Config) Subpart(org.cpsolver.studentsct.model.Subpart) Offering(org.cpsolver.studentsct.model.Offering) Section(org.cpsolver.studentsct.model.Section)

Aggregations

Offering (org.cpsolver.studentsct.model.Offering)25 Section (org.cpsolver.studentsct.model.Section)18 Subpart (org.cpsolver.studentsct.model.Subpart)16 Course (org.cpsolver.studentsct.model.Course)15 Config (org.cpsolver.studentsct.model.Config)13 HashSet (java.util.HashSet)10 CourseRequest (org.cpsolver.studentsct.model.CourseRequest)10 Enrollment (org.cpsolver.studentsct.model.Enrollment)10 Request (org.cpsolver.studentsct.model.Request)10 HashMap (java.util.HashMap)8 Student (org.cpsolver.studentsct.model.Student)8 Element (org.dom4j.Element)8 ArrayList (java.util.ArrayList)7 TreeSet (java.util.TreeSet)6 DistanceConflict (org.cpsolver.studentsct.extension.DistanceConflict)5 TimeOverlapsCounter (org.cpsolver.studentsct.extension.TimeOverlapsCounter)5 DecimalFormat (java.text.DecimalFormat)4 Map (java.util.Map)4 Set (java.util.Set)4 Placement (org.cpsolver.coursett.model.Placement)4