Search in sources :

Example 26 with Subpart

use of org.cpsolver.studentsct.model.Subpart in project cpsolver by UniTime.

the class EqualWeightCriterion method canImprove.

@Override
public boolean canImprove(Assignment<Request, Enrollment> assignment, int maxIdx, Enrollment[] current, Enrollment[] best) {
    // 0. best number of assigned course requests (including alternativity &
    // priority)
    int currentAssignedCourseReq = 0, bestAssignedCourseReq = 0;
    int currentAssignedRequests = 0, bestAssignedRequests = 0;
    int currentAssignedPriority = 0, bestAssignedPriority = 0;
    int currentAssignedAlternativity = 0, bestAssignedAlternativity = 0;
    int currentNotFollowedReservations = 0, bestNotFollowedReservations = 0;
    int alt = 0;
    for (int idx = 0; idx < current.length; idx++) {
        if (idx < maxIdx) {
            if (current[idx] != null && current[idx].getAssignments() != null) {
                currentAssignedRequests++;
                if (current[idx].isCourseRequest())
                    currentAssignedCourseReq++;
                currentAssignedPriority += current[idx].getTruePriority() * current[idx].getTruePriority();
                currentAssignedAlternativity += (current[idx].getRequest().isAlternative() ? 1 : 0);
                if (current[idx].getTruePriority() < current[idx].getPriority())
                    currentNotFollowedReservations++;
            } else if (!isFreeTime(idx) && !getRequest(idx).isAlternative()) {
                alt++;
            }
        } else {
            if (!getRequest(idx).isAlternative()) {
                currentAssignedRequests++;
                if (!isFreeTime(idx))
                    currentAssignedCourseReq++;
            } else if (alt > 0) {
                currentAssignedRequests++;
                currentAssignedCourseReq++;
                alt--;
                currentAssignedAlternativity++;
            }
        }
        if (best[idx] != null && best[idx].getAssignments() != null) {
            bestAssignedRequests++;
            if (best[idx].isCourseRequest())
                bestAssignedCourseReq++;
            bestAssignedPriority += best[idx].getTruePriority() * best[idx].getTruePriority();
            bestAssignedAlternativity += (best[idx].getRequest().isAlternative() ? 1 : 0);
            if (best[idx].getTruePriority() < best[idx].getPriority())
                bestNotFollowedReservations++;
        }
    }
    if (currentAssignedCourseReq > bestAssignedCourseReq)
        return true;
    if (bestAssignedCourseReq > currentAssignedCourseReq)
        return false;
    if (currentAssignedPriority < bestAssignedPriority)
        return true;
    if (bestAssignedPriority < currentAssignedPriority)
        return false;
    if (currentAssignedAlternativity < bestAssignedAlternativity)
        return true;
    if (bestAssignedAlternativity < currentAssignedAlternativity)
        return false;
    // 0.1. allowed, but not available sections
    int notAvailable = 0;
    for (int idx = 0; idx < current.length; idx++) {
        if (best[idx] != null && best[idx].getAssignments() != null && best[idx].getRequest() instanceof CourseRequest && best[idx].getReservation() != null && best[idx].getReservation().canAssignOverLimit()) {
            for (Section section : best[idx].getSections()) {
                if (section.getLimit() == 0)
                    notAvailable++;
            }
        }
        if (idx < maxIdx && current[idx] != null && current[idx].getAssignments() != null && current[idx].getRequest() instanceof CourseRequest && current[idx].getReservation() != null && current[idx].getReservation().canAssignOverLimit()) {
            for (Section section : current[idx].getSections()) {
                if (section.getLimit() == 0)
                    notAvailable--;
            }
        }
    }
    if (notAvailable > 0) {
        return true;
    }
    // 0.5. avoid course time overlaps & unavailabilities
    if (getModel().getStudentQuality() != null) {
        int bestTimeOverlaps = 0, currentTimeOverlaps = 0;
        for (int idx = 0; idx < current.length; idx++) {
            if (best[idx] != null && best[idx].getRequest() instanceof CourseRequest) {
                for (int x = 0; x < idx; x++) {
                    if (best[x] != null && best[x].getRequest() instanceof CourseRequest)
                        bestTimeOverlaps += getModel().getStudentQuality().penalty(StudentQuality.Type.CourseTimeOverlap, best[x], best[idx]);
                }
            }
            if (current[idx] != null && idx < maxIdx && current[idx].getRequest() instanceof CourseRequest) {
                for (int x = 0; x < idx; x++) {
                    if (current[x] != null && current[x].getRequest() instanceof CourseRequest)
                        currentTimeOverlaps += getModel().getStudentQuality().penalty(StudentQuality.Type.CourseTimeOverlap, current[x], current[idx]);
                }
            }
        }
        for (int idx = 0; idx < current.length; idx++) {
            if (best[idx] != null && best[idx].getAssignments() != null && best[idx].isCourseRequest()) {
                bestTimeOverlaps += getModel().getStudentQuality().penalty(StudentQuality.Type.Unavailability, best[idx]);
            }
            if (current[idx] != null && idx < maxIdx && current[idx].getAssignments() != null && current[idx].isCourseRequest()) {
                currentTimeOverlaps += getModel().getStudentQuality().penalty(StudentQuality.Type.Unavailability, current[idx]);
            }
        }
        if (currentTimeOverlaps < bestTimeOverlaps)
            return true;
        if (bestTimeOverlaps < currentTimeOverlaps)
            return false;
    } else if (getModel().getTimeOverlaps() != null) {
        int bestTimeOverlaps = 0, currentTimeOverlaps = 0;
        for (int idx = 0; idx < current.length; idx++) {
            if (best[idx] != null && best[idx].getRequest() instanceof CourseRequest) {
                for (int x = 0; x < idx; x++) {
                    if (best[x] != null && best[x].getRequest() instanceof CourseRequest)
                        bestTimeOverlaps += getModel().getTimeOverlaps().nrConflicts(best[x], best[idx]);
                }
            }
            if (current[idx] != null && idx < maxIdx && current[idx].getRequest() instanceof CourseRequest) {
                for (int x = 0; x < idx; x++) {
                    if (current[x] != null && current[x].getRequest() instanceof CourseRequest)
                        currentTimeOverlaps += getModel().getTimeOverlaps().nrConflicts(current[x], current[idx]);
                }
            }
        }
        for (int idx = 0; idx < current.length; idx++) {
            if (best[idx] != null && best[idx].getAssignments() != null && best[idx].isCourseRequest()) {
                bestTimeOverlaps += getModel().getTimeOverlaps().nrNotAvailableTimeConflicts(best[idx]);
            }
            if (current[idx] != null && idx < maxIdx && current[idx].getAssignments() != null && current[idx].isCourseRequest()) {
                currentTimeOverlaps += getModel().getTimeOverlaps().nrNotAvailableTimeConflicts(current[idx]);
            }
        }
        if (currentTimeOverlaps < bestTimeOverlaps)
            return true;
        if (bestTimeOverlaps < currentTimeOverlaps)
            return false;
    }
    // 1. maximize number of penalties
    double bestPenalties = 0, currentPenalties = 0;
    for (int idx = 0; idx < current.length; idx++) {
        if (best[idx] != null) {
            for (Section section : best[idx].getSections()) bestPenalties += getModel().getOverExpected(assignment, best, idx, section, best[idx].getRequest());
        }
        if (current[idx] != null && idx < maxIdx) {
            for (Section section : current[idx].getSections()) currentPenalties += getModel().getOverExpected(assignment, current, idx, section, current[idx].getRequest());
        }
    }
    if (currentPenalties < bestPenalties)
        return true;
    if (bestPenalties < currentPenalties)
        return false;
    // 2. best number of assigned requests (including free time requests)
    if (currentAssignedRequests > bestAssignedRequests)
        return true;
    if (bestAssignedRequests > currentAssignedRequests)
        return false;
    // 3. maximize selection
    int bestSelected = 0, currentSelected = 0;
    for (int idx = 0; idx < current.length; idx++) {
        if (best[idx] != null && best[idx].isCourseRequest()) {
            Set<Section> preferred = getPreferredSections(best[idx].getRequest());
            if (preferred != null && !preferred.isEmpty()) {
                for (Section section : best[idx].getSections()) if (preferred.contains(section)) {
                    if (idx < maxIdx)
                        bestSelected++;
                } else if (idx >= maxIdx)
                    bestSelected--;
            }
        }
        if (current[idx] != null && idx < maxIdx && current[idx].isCourseRequest()) {
            Set<Section> preferred = getPreferredSections(current[idx].getRequest());
            if (preferred != null && !preferred.isEmpty()) {
                for (Section section : current[idx].getSections()) if (preferred.contains(section))
                    currentSelected++;
            }
        }
    }
    if (currentSelected > bestSelected)
        return true;
    if (bestSelected > currentSelected)
        return false;
    // 3.5 maximize preferences
    double bestSelectedConfigs = 0, currentSelectedConfigs = 0;
    double bestSelectedSections = 0, currentSelectedSections = 0;
    for (int idx = 0; idx < current.length; idx++) {
        if (best[idx] != null && best[idx].getAssignments() != null && best[idx].isCourseRequest()) {
            bestSelectedSections += best[idx].percentSelectedSameSection();
            bestSelectedConfigs += best[idx].percentSelectedSameConfig();
            if (idx >= maxIdx) {
                bestSelectedSections -= 1.0;
                bestSelectedConfigs -= 1.0;
            }
        }
        if (current[idx] != null && idx < maxIdx && current[idx].getAssignments() != null && current[idx].isCourseRequest()) {
            currentSelectedSections += current[idx].percentSelectedSameSection();
            currentSelectedConfigs += current[idx].percentSelectedSameConfig();
        }
    }
    if (0.3 * currentSelectedConfigs + 0.7 * currentSelectedSections > 0.3 * bestSelectedConfigs + 0.7 * bestSelectedSections)
        return true;
    if (0.3 * bestSelectedConfigs + 0.7 * bestSelectedSections > 0.3 * currentSelectedConfigs + 0.7 * currentSelectedSections)
        return false;
    // 3.9 minimize enrollments where the reservation is not followed
    if (currentNotFollowedReservations < bestNotFollowedReservations)
        return true;
    if (bestNotFollowedReservations < currentNotFollowedReservations)
        return false;
    // 3.95 avoid past sections
    int bestPast = 0, currentPast = 0;
    for (int idx = 0; idx < current.length; idx++) {
        if (best[idx] != null && best[idx].getAssignments() != null) {
            for (Section section : best[idx].getSections()) {
                if (section.isPast())
                    bestPast++;
            }
        }
        if (current[idx] != null && idx < maxIdx && current[idx].getAssignments() != null) {
            for (Section section : current[idx].getSections()) {
                if (section.isPast())
                    currentPast++;
            }
        }
    }
    if (currentPast < bestPast)
        return true;
    if (bestPast < currentPast)
        return false;
    // 4-5. solution quality
    if (getModel().getStudentQuality() != null) {
        double bestQuality = 0, currentQuality = 0;
        for (StudentQuality.Type type : StudentQuality.Type.values()) {
            for (int idx = 0; idx < current.length; idx++) {
                if (best[idx] != null) {
                    bestQuality += iQalityWeights[type.ordinal()] * getModel().getStudentQuality().penalty(type, best[idx]);
                    for (int x = 0; x < idx; x++) {
                        if (best[x] != null)
                            bestQuality += iQalityWeights[type.ordinal()] * getModel().getStudentQuality().penalty(type, best[x], best[idx]);
                    }
                }
                if (current[idx] != null && idx < maxIdx) {
                    currentQuality += iQalityWeights[type.ordinal()] * getModel().getStudentQuality().penalty(type, current[idx]);
                    for (int x = 0; x < idx; x++) {
                        if (current[x] != null)
                            currentQuality += iQalityWeights[type.ordinal()] * getModel().getStudentQuality().penalty(type, current[x], current[idx]);
                    }
                }
            }
        }
        if (currentQuality < bestQuality)
            return true;
        if (bestQuality < currentQuality)
            return false;
    } else {
        // 4. avoid time overlaps
        if (getModel().getTimeOverlaps() != null) {
            int bestTimeOverlaps = 0, currentTimeOverlaps = 0;
            for (int idx = 0; idx < current.length; idx++) {
                if (best[idx] != null) {
                    for (int x = 0; x < idx; x++) {
                        if (best[x] != null)
                            bestTimeOverlaps += getModel().getTimeOverlaps().nrConflicts(best[x], best[idx]);
                        else if (getStudent().getRequests().get(x) instanceof FreeTimeRequest)
                            bestTimeOverlaps += getModel().getTimeOverlaps().nrConflicts(((FreeTimeRequest) getStudent().getRequests().get(x)).createEnrollment(), best[idx]);
                    }
                }
                if (current[idx] != null && idx < maxIdx) {
                    for (int x = 0; x < idx; x++) {
                        if (current[x] != null)
                            currentTimeOverlaps += getModel().getTimeOverlaps().nrConflicts(current[x], current[idx]);
                        else if (getStudent().getRequests().get(x) instanceof FreeTimeRequest)
                            currentTimeOverlaps += getModel().getTimeOverlaps().nrConflicts(((FreeTimeRequest) getStudent().getRequests().get(x)).createEnrollment(), current[idx]);
                    }
                }
            }
            for (int idx = 0; idx < current.length; idx++) {
                if (best[idx] != null && best[idx].getAssignments() != null && best[idx].isCourseRequest()) {
                    bestTimeOverlaps += getModel().getTimeOverlaps().nrNotAvailableTimeConflicts(best[idx]);
                }
                if (current[idx] != null && idx < maxIdx && current[idx].getAssignments() != null && current[idx].isCourseRequest()) {
                    currentTimeOverlaps += getModel().getTimeOverlaps().nrNotAvailableTimeConflicts(current[idx]);
                }
            }
            if (currentTimeOverlaps < bestTimeOverlaps)
                return true;
            if (bestTimeOverlaps < currentTimeOverlaps)
                return false;
        }
        // 5. avoid distance conflicts
        if (getModel().getDistanceConflict() != null) {
            int bestDistanceConf = 0, currentDistanceConf = 0;
            for (int idx = 0; idx < current.length; idx++) {
                if (best[idx] != null) {
                    bestDistanceConf += getModel().getDistanceConflict().nrConflicts(best[idx]);
                    for (int x = 0; x < idx; x++) {
                        if (best[x] != null)
                            bestDistanceConf += getModel().getDistanceConflict().nrConflicts(best[x], best[idx]);
                    }
                }
                if (current[idx] != null && idx < maxIdx) {
                    currentDistanceConf += getModel().getDistanceConflict().nrConflicts(current[idx]);
                    for (int x = 0; x < idx; x++) {
                        if (current[x] != null)
                            currentDistanceConf += getModel().getDistanceConflict().nrConflicts(current[x], current[idx]);
                    }
                }
            }
            if (currentDistanceConf < bestDistanceConf)
                return true;
            if (bestDistanceConf < currentDistanceConf)
                return false;
        }
    }
    // 6. avoid no-time and online sections (no-time first, online second)
    int bestNoTime = 0, currentNoTime = 0;
    int bestOnline = 0, currentOnline = 0;
    for (int idx = 0; idx < current.length; idx++) {
        if (best[idx] != null) {
            for (Section section : best[idx].getSections()) {
                if (!section.hasTime())
                    bestNoTime++;
                if (section.isOnline())
                    bestOnline++;
            }
        }
        if (current[idx] != null && idx < maxIdx) {
            for (Section section : current[idx].getSections()) {
                if (!section.hasTime())
                    currentNoTime++;
                if (section.isOnline())
                    currentOnline++;
            }
        }
    }
    if (currentNoTime < bestNoTime)
        return true;
    if (bestNoTime < currentNoTime)
        return false;
    if (currentOnline < bestOnline)
        return true;
    if (bestOnline < currentOnline)
        return false;
    // 7. balance sections
    double bestUnavailableSize = 0.0, currentUnavailableSize = 0.0;
    int bestAltSectionsWithLimit = 0, currentAltSectionsWithLimit = 0;
    for (int idx = 0; idx < current.length; idx++) {
        if (best[idx] != null) {
            for (Section section : best[idx].getSections()) {
                Subpart subpart = section.getSubpart();
                // skip unlimited and single section subparts
                if (subpart.getSections().size() <= 1 || subpart.getLimit() <= 0)
                    continue;
                // average size
                double averageSize = ((double) subpart.getLimit()) / subpart.getSections().size();
                // section is below average
                if (section.getLimit() < averageSize)
                    bestUnavailableSize += (averageSize - section.getLimit()) / averageSize;
                bestAltSectionsWithLimit++;
            }
        }
        if (current[idx] != null && idx < maxIdx) {
            for (Section section : current[idx].getSections()) {
                Subpart subpart = section.getSubpart();
                // skip unlimited and single section subparts
                if (subpart.getSections().size() <= 1 || subpart.getLimit() <= 0)
                    continue;
                // average size
                double averageSize = ((double) subpart.getLimit()) / subpart.getSections().size();
                // section is below average
                if (section.getLimit() < averageSize)
                    currentUnavailableSize += (averageSize - section.getLimit()) / averageSize;
                currentAltSectionsWithLimit++;
            }
        }
    }
    double bestUnavailableSizeFraction = (bestUnavailableSize > 0 ? bestUnavailableSize / bestAltSectionsWithLimit : 0.0);
    double currentUnavailableSizeFraction = (currentUnavailableSize > 0 ? currentUnavailableSize / currentAltSectionsWithLimit : 0.0);
    if (currentUnavailableSizeFraction < bestUnavailableSizeFraction)
        return true;
    if (bestUnavailableSizeFraction < currentUnavailableSizeFraction)
        return false;
    // 8. average penalty sections
    double bestPenalty = 0.0, currentPenalty = 0.0;
    for (int idx = 0; idx < current.length; idx++) {
        if (best[idx] != null) {
            for (Section section : best[idx].getSections()) bestPenalty += section.getPenalty() / best[idx].getSections().size();
            if (idx >= maxIdx && best[idx].isCourseRequest())
                bestPenalty -= ((CourseRequest) best[idx].getRequest()).getMinPenalty();
        }
        if (current[idx] != null && idx < maxIdx) {
            for (Section section : current[idx].getSections()) currentPenalty += section.getPenalty() / current[idx].getSections().size();
        }
    }
    if (currentPenalty < bestPenalty)
        return true;
    if (bestPenalty < currentPenalty)
        return false;
    return true;
}
Also used : FreeTimeRequest(org.cpsolver.studentsct.model.FreeTimeRequest) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) StudentQuality(org.cpsolver.studentsct.extension.StudentQuality) Subpart(org.cpsolver.studentsct.model.Subpart) Section(org.cpsolver.studentsct.model.Section)

Example 27 with Subpart

use of org.cpsolver.studentsct.model.Subpart in project cpsolver by UniTime.

the class TableauReport method create.

@Override
public CSVFile create(Assignment<Request, Enrollment> assignment, DataProperties properties) {
    CSVFile csv = new CSVFile();
    boolean simple = properties.getPropertyBoolean("simple", false);
    if (simple) {
        csv.setHeader(new CSVFile.CSVField[] { new CSVFile.CSVField("__Student"), new CSVFile.CSVField("Student"), new CSVFile.CSVField("Course"), new CSVFile.CSVField("Course Limit"), new CSVFile.CSVField("Primary"), new CSVFile.CSVField("Priority"), new CSVFile.CSVField("Alternativity"), new CSVFile.CSVField("Enrolled"), new CSVFile.CSVField("Request Type") });
    } else {
        csv.setHeader(new CSVFile.CSVField[] { new CSVFile.CSVField("__Student"), new CSVFile.CSVField("Student"), new CSVFile.CSVField("Course"), new CSVFile.CSVField("Course Limit"), new CSVFile.CSVField("Controlling Course"), new CSVFile.CSVField("Primary"), new CSVFile.CSVField("Priority"), new CSVFile.CSVField("Alternativity"), new CSVFile.CSVField("Enrolled"), new CSVFile.CSVField("Credits"), new CSVFile.CSVField("Sections"), new CSVFile.CSVField("Preferred Sections"), new CSVFile.CSVField("Required Sections"), new CSVFile.CSVField("Instructional Method"), new CSVFile.CSVField("Preferred Instructional Methods"), new CSVFile.CSVField("Required Instructional Methods"), new CSVFile.CSVField("Request Type") });
    }
    for (Student student : getModel().getStudents()) {
        if (student.isDummy())
            continue;
        int regPriority = 1, altPriority = 1;
        for (Request r : student.getRequests()) {
            if (r instanceof CourseRequest) {
                CourseRequest cr = (CourseRequest) r;
                Enrollment e = cr.getAssignment(assignment);
                int primary = (cr.isAlternative() ? 0 : 1);
                int priority = 0;
                if (cr.isAlternative())
                    priority = altPriority++;
                else
                    priority = regPriority++;
                int alternativity = 0;
                for (Course course : cr.getCourses()) {
                    int enrolled = (e != null && e.getCourse().equals(course) ? 1 : 0);
                    String sect = null;
                    if (e != null && e.getCourse().equals(course)) {
                        sect = "";
                        Set<String> added = new HashSet<String>();
                        for (Section s : e.getSections()) {
                            String x = s.getName(e.getCourse().getId());
                            if (x.indexOf('-') > 0)
                                x = x.substring(0, x.indexOf('-'));
                            if (added.add(x))
                                sect += (sect.isEmpty() ? "" : ",") + x;
                        }
                    }
                    String imR = "", sctR = "";
                    Set<String> addedR = new HashSet<String>();
                    for (Choice ch : cr.getRequiredChoices()) {
                        if (course.getOffering().equals(ch.getOffering())) {
                            if (ch.getConfigId() != null) {
                                for (Config cfg : ch.getOffering().getConfigs()) {
                                    if (ch.getConfigId().equals(cfg.getId())) {
                                        String im = cfg.getInstructionalMethodReference();
                                        if (im != null && addedR.add(im))
                                            imR += (imR.isEmpty() ? "" : ",") + im;
                                    }
                                }
                            }
                            if (ch.getSectionId() != null) {
                                String x = ch.getOffering().getSection(ch.getSectionId()).getName(course.getId());
                                if (x.indexOf('-') > 0)
                                    x = x.substring(0, x.indexOf('-'));
                                if (addedR.add(x))
                                    sctR += (sctR.isEmpty() ? "" : ",") + x;
                            }
                        }
                    }
                    for (Reservation rs : cr.getReservations(course)) {
                        if (rs.mustBeUsed()) {
                            for (Map.Entry<Subpart, Set<Section>> ent : rs.getSections().entrySet()) {
                                for (Section s : ent.getValue()) {
                                    String x = s.getName(course.getId());
                                    if (x.indexOf('-') > 0)
                                        x = x.substring(0, x.indexOf('-'));
                                    if (addedR.add(x))
                                        sctR += (sctR.isEmpty() ? "" : ",") + x;
                                }
                            }
                            if (rs.getSections().isEmpty()) {
                                for (Config cfg : rs.getConfigs()) {
                                    String im = cfg.getInstructionalMethodReference();
                                    if (im != null && addedR.add(im))
                                        imR += (imR.isEmpty() ? "" : ",") + im;
                                }
                            }
                        }
                    }
                    String imP = "", sctP = "";
                    for (Choice ch : cr.getSelectedChoices()) {
                        Set<String> added = new HashSet<String>();
                        if (course.getOffering().equals(ch.getOffering())) {
                            if (ch.getConfigId() != null) {
                                for (Config cfg : ch.getOffering().getConfigs()) {
                                    if (ch.getConfigId().equals(cfg.getId())) {
                                        String im = cfg.getInstructionalMethodReference();
                                        if (im != null && added.add(im))
                                            imP += (imP.isEmpty() ? "" : ",") + im;
                                    }
                                }
                            }
                            if (ch.getSectionId() != null) {
                                String x = ch.getOffering().getSection(ch.getSectionId()).getName(course.getId());
                                if (x.indexOf('-') > 0)
                                    x = x.substring(0, x.indexOf('-'));
                                if (added.add(x))
                                    sctP += (sctP.isEmpty() ? "" : ",") + x;
                            }
                        }
                    }
                    if (simple)
                        csv.addLine(new CSVFile.CSVField[] { new CSVFile.CSVField(student.getId()), new CSVFile.CSVField(student.getExternalId()), new CSVFile.CSVField(course.getName()), new CSVFile.CSVField(course.getLimit() < 0 ? null : course.getLimit()), new CSVFile.CSVField(primary == 1 ? "Yes" : "No"), new CSVFile.CSVField(priority), new CSVFile.CSVField(alternativity), new CSVFile.CSVField(enrolled == 1 ? "Yes" : "No"), new CSVFile.CSVField(cr.getRequestPriority() == null ? "" : cr.getRequestPriority().name()) });
                    else
                        csv.addLine(new CSVFile.CSVField[] { new CSVFile.CSVField(student.getId()), new CSVFile.CSVField(student.getExternalId()), new CSVFile.CSVField(course.getName()), new CSVFile.CSVField(course.getLimit() < 0 ? null : course.getLimit()), new CSVFile.CSVField(course.getOffering().getCourses().size() <= 1 ? null : course.getOffering().getName()), new CSVFile.CSVField(primary == 1 ? "Yes" : "No"), new CSVFile.CSVField(priority), new CSVFile.CSVField(alternativity), new CSVFile.CSVField(enrolled == 1 ? "Yes" : "No"), new CSVFile.CSVField(enrolled == 1 ? e.getCredit() : course.getCreditValue() == null ? 0f : course.getCreditValue()), new CSVFile.CSVField(sect), new CSVFile.CSVField(sctP), new CSVFile.CSVField(sctR), new CSVFile.CSVField(e != null ? e.getConfig().getInstructionalMethodReference() : null), new CSVFile.CSVField(imP), new CSVFile.CSVField(imR), new CSVFile.CSVField(cr.getRequestPriority() == null ? "" : cr.getRequestPriority().name()) });
                    alternativity++;
                }
            }
        }
    }
    return csv;
}
Also used : CSVFile(org.cpsolver.ifs.util.CSVFile) Choice(org.cpsolver.studentsct.model.Choice) Set(java.util.Set) HashSet(java.util.HashSet) Config(org.cpsolver.studentsct.model.Config) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) Request(org.cpsolver.studentsct.model.Request) Student(org.cpsolver.studentsct.model.Student) Section(org.cpsolver.studentsct.model.Section) Reservation(org.cpsolver.studentsct.reservation.Reservation) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) Subpart(org.cpsolver.studentsct.model.Subpart) Enrollment(org.cpsolver.studentsct.model.Enrollment) Course(org.cpsolver.studentsct.model.Course) Map(java.util.Map) HashSet(java.util.HashSet)

Example 28 with Subpart

use of org.cpsolver.studentsct.model.Subpart in project cpsolver by UniTime.

the class UnbalancedSectionsTable 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("Class"), new CSVFile.CSVField("Meeting Time"), new CSVFile.CSVField("Enrollment"), new CSVFile.CSVField("Target"), new CSVFile.CSVField("Limit"), new CSVFile.CSVField("Disbalance [%]") });
    TreeSet<Offering> offerings = new TreeSet<Offering>(new Comparator<Offering>() {

        @Override
        public int compare(Offering o1, Offering o2) {
            int cmp = o1.getName().compareToIgnoreCase(o2.getName());
            if (cmp != 0)
                return cmp;
            return o1.getId() < o2.getId() ? -1 : o2.getId() == o2.getId() ? 0 : 1;
        }
    });
    offerings.addAll(getModel().getOfferings());
    Offering last = null;
    for (Offering offering : offerings) {
        for (Config config : offering.getConfigs()) {
            double configEnrl = 0;
            for (Enrollment e : config.getEnrollments(assignment)) {
                if (e.getStudent().isDummy() && !includeLastLikeStudents)
                    continue;
                if (!e.getStudent().isDummy() && !includeRealStudents)
                    continue;
                configEnrl += e.getRequest().getWeight();
            }
            for (Subpart subpart : config.getSubparts()) {
                if (subpart.getSections().size() <= 1)
                    continue;
                if (subpart.getLimit() > 0) {
                    // sections have limits -> desired size is section limit x (total enrollment / total limit)
                    double ratio = configEnrl / subpart.getLimit();
                    for (Section section : subpart.getSections()) {
                        double enrl = 0.0;
                        for (Enrollment e : section.getEnrollments(assignment)) {
                            if (e.getStudent().isDummy() && !includeLastLikeStudents)
                                continue;
                            if (!e.getStudent().isDummy() && !includeRealStudents)
                                continue;
                            enrl += e.getRequest().getWeight();
                        }
                        double desired = ratio * section.getLimit();
                        if (Math.abs(desired - enrl) >= Math.max(1.0, 0.1 * section.getLimit())) {
                            if (last != null && !offering.equals(last))
                                csv.addLine();
                            csv.addLine(new CSVFile.CSVField[] { new CSVFile.CSVField(offering.equals(last) ? "" : offering.getName()), new CSVFile.CSVField(section.getSubpart().getName() + " " + section.getName()), new CSVFile.CSVField(section.getTime() == null ? "" : section.getTime().getDayHeader() + " " + section.getTime().getStartTimeHeader(useAmPm) + " - " + section.getTime().getEndTimeHeader(useAmPm)), new CSVFile.CSVField(sDF1.format(enrl)), new CSVFile.CSVField(sDF2.format(desired)), new CSVFile.CSVField(sDF1.format(section.getLimit())), new CSVFile.CSVField(sDF2.format(Math.min(1.0, Math.max(-1.0, (enrl - desired) / section.getLimit())))) });
                            last = offering;
                        }
                    }
                } else {
                    // unlimited sections -> desired size is total enrollment / number of sections
                    for (Section section : subpart.getSections()) {
                        double enrl = 0.0;
                        for (Enrollment e : section.getEnrollments(assignment)) {
                            if (e.getStudent().isDummy() && !includeLastLikeStudents)
                                continue;
                            if (!e.getStudent().isDummy() && !includeRealStudents)
                                continue;
                            enrl += e.getRequest().getWeight();
                        }
                        double desired = configEnrl / subpart.getSections().size();
                        if (Math.abs(desired - enrl) >= Math.max(1.0, 0.1 * desired)) {
                            if (last != null && !offering.equals(last))
                                csv.addLine();
                            csv.addLine(new CSVFile.CSVField[] { new CSVFile.CSVField(offering.equals(last) ? "" : offering.getName()), new CSVFile.CSVField(section.getSubpart().getName() + " " + section.getName()), new CSVFile.CSVField(section.getTime() == null ? "" : section.getTime().getDayHeader() + " " + section.getTime().getStartTimeHeader(useAmPm) + " - " + section.getTime().getEndTimeHeader(useAmPm)), new CSVFile.CSVField(sDF1.format(enrl)), new CSVFile.CSVField(sDF2.format(desired)), new CSVFile.CSVField(""), new CSVFile.CSVField(sDF2.format(Math.min(1.0, Math.max(-1.0, (enrl - desired) / desired)))) });
                            last = offering;
                        }
                    }
                }
            }
        }
    }
    return csv;
}
Also used : CSVFile(org.cpsolver.ifs.util.CSVFile) TreeSet(java.util.TreeSet) Config(org.cpsolver.studentsct.model.Config) Subpart(org.cpsolver.studentsct.model.Subpart) Enrollment(org.cpsolver.studentsct.model.Enrollment) Offering(org.cpsolver.studentsct.model.Offering) Section(org.cpsolver.studentsct.model.Section)

Example 29 with Subpart

use of org.cpsolver.studentsct.model.Subpart in project cpsolver by UniTime.

the class PriorityStudentWeights method getWeight.

@Override
public double getWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
    double weight = getCachedWeight(enrollment.getRequest());
    switch(enrollment.getPriority()) {
        case 1:
            weight *= iFirstAlternativeFactor;
            break;
        case 2:
            weight *= iSecondAlternativeFactor;
            break;
    }
    if (enrollment.isCourseRequest() && iBalancingFactor != 0.0) {
        double configUsed = enrollment.getConfig().getEnrollmentTotalWeight(assignment, enrollment.getRequest()) + enrollment.getRequest().getWeight();
        double disbalanced = 0;
        double total = 0;
        for (Section section : enrollment.getSections()) {
            Subpart subpart = section.getSubpart();
            if (subpart.getSections().size() <= 1)
                continue;
            double used = section.getEnrollmentTotalWeight(assignment, enrollment.getRequest()) + enrollment.getRequest().getWeight();
            // sections have limits -> desired size is section limit x (total enrollment / total limit)
            // unlimited sections -> desired size is total enrollment / number of sections
            double desired = (subpart.getLimit() > 0 ? section.getLimit() * (configUsed / subpart.getLimit()) : configUsed / subpart.getSections().size());
            if (used > desired)
                disbalanced += Math.min(enrollment.getRequest().getWeight(), used - desired) / enrollment.getRequest().getWeight();
            else
                disbalanced -= Math.min(enrollment.getRequest().getWeight(), desired - used) / enrollment.getRequest().getWeight();
            total++;
        }
        if (disbalanced > 0)
            weight *= (1.0 - disbalanced / total * iBalancingFactor);
    }
    if (iMPP) {
        double difference = getDifference(enrollment);
        if (difference > 0.0)
            weight *= (1.0 - difference * iPerturbationFactor);
    }
    if (iSelectionFactor != 0.0) {
        double selection = getSelection(enrollment);
        if (selection > 0.0)
            weight *= (1.0 - selection * iSelectionFactor);
    }
    if (enrollment.isCourseRequest() && iGroupFactor != 0.0) {
        double sameGroup = 0.0;
        int groupCount = 0;
        for (RequestGroup g : ((CourseRequest) enrollment.getRequest()).getRequestGroups()) {
            if (g.getCourse().equals(enrollment.getCourse())) {
                sameGroup += g.getEnrollmentSpread(assignment, enrollment, iGroupBestRatio, iGroupFillRatio);
                groupCount++;
            }
        }
        if (groupCount > 0) {
            double difference = 1.0 - sameGroup / groupCount;
            weight *= (1.0 - difference * iGroupFactor);
        }
    }
    return round(weight);
}
Also used : CourseRequest(org.cpsolver.studentsct.model.CourseRequest) Subpart(org.cpsolver.studentsct.model.Subpart) RequestGroup(org.cpsolver.studentsct.model.RequestGroup) Section(org.cpsolver.studentsct.model.Section)

Example 30 with Subpart

use of org.cpsolver.studentsct.model.Subpart in project cpsolver by UniTime.

the class StudentSectioningModel method getExtendedInfo.

/**
 * Model extended info. Some more information (that is more expensive to
 * compute) is added to an ordinary {@link Model#getInfo(Assignment)}.
 */
@Override
public Map<String, String> getExtendedInfo(Assignment<Request, Enrollment> assignment) {
    Map<String, String> info = getInfo(assignment);
    /*
        double dc = 0;
        if (getDistanceConflict() != null && getDistanceConflict().getTotalNrConflicts(assignment) != 0) {
            Set<DistanceConflict.Conflict> conf = getDistanceConflict().getAllConflicts(assignment);
            int sdc = 0;
            for (DistanceConflict.Conflict c: conf) {
                dc += avg(c.getR1().getWeight(), c.getR2().getWeight()) * iStudentWeights.getDistanceConflictWeight(assignment, c);
                if (c.getStudent().isNeedShortDistances()) sdc ++;
            }
            if (!conf.isEmpty())
                info.put("Student distance conflicts", conf.size() + (sdc > 0 ? " (" + getDistanceConflict().getDistanceMetric().getShortDistanceAccommodationReference() + ": " + sdc + ", weighted: " : " (weighted: ") + sDecimalFormat.format(dc) + ")");
        }
        */
    if (getStudentQuality() == null && getTimeOverlaps() != null && getTimeOverlaps().getTotalNrConflicts(assignment) != 0) {
        Set<TimeOverlapsCounter.Conflict> conf = getTimeOverlaps().getContext(assignment).computeAllConflicts(assignment);
        int share = 0, crShare = 0;
        for (TimeOverlapsCounter.Conflict c : conf) {
            share += c.getShare();
            if (c.getR1() instanceof CourseRequest && c.getR2() instanceof CourseRequest)
                crShare += c.getShare();
        }
        if (share > 0)
            info.put("Time overlapping conflicts", sDoubleFormat.format(5.0 * share / iStudents.size()) + " mins per student\n(" + sDoubleFormat.format(5.0 * crShare / iStudents.size()) + " between courses; " + sDoubleFormat.format(getTimeOverlaps().getTotalNrConflicts(assignment) / 12.0) + " hours total)");
    }
    /*
        info.put("Overall solution value", sDecimalFormat.format(total - dc - toc) + (dc == 0.0 && toc == 0.0 ? "" :
            " (" + (dc != 0.0 ? "distance: " + sDecimalFormat.format(dc): "") + (dc != 0.0 && toc != 0.0 ? ", " : "") + 
            (toc != 0.0 ? "overlap: " + sDecimalFormat.format(toc) : "") + ")")
            );
        */
    double disbWeight = 0;
    int disbSections = 0;
    int disb10Sections = 0;
    int disb10Limit = getProperties().getPropertyInt("Info.ListDisbalancedSections", 0);
    Set<String> disb10SectionList = (disb10Limit == 0 ? null : new TreeSet<String>());
    for (Offering offering : getOfferings()) {
        for (Config config : offering.getConfigs()) {
            double enrl = config.getEnrollmentTotalWeight(assignment, null);
            for (Subpart subpart : config.getSubparts()) {
                if (subpart.getSections().size() <= 1)
                    continue;
                if (subpart.getLimit() > 0) {
                    // sections have limits -> desired size is section limit x (total enrollment / total limit)
                    double ratio = enrl / subpart.getLimit();
                    for (Section section : subpart.getSections()) {
                        double desired = ratio * section.getLimit();
                        disbWeight += Math.abs(section.getEnrollmentTotalWeight(assignment, null) - desired);
                        disbSections++;
                        if (Math.abs(desired - section.getEnrollmentTotalWeight(assignment, null)) >= Math.max(1.0, 0.1 * section.getLimit())) {
                            disb10Sections++;
                            if (disb10SectionList != null)
                                disb10SectionList.add(section.getSubpart().getConfig().getOffering().getName() + " " + section.getSubpart().getName() + " " + section.getName());
                        }
                    }
                } else {
                    // unlimited sections -> desired size is total enrollment / number of sections
                    for (Section section : subpart.getSections()) {
                        double desired = enrl / subpart.getSections().size();
                        disbWeight += Math.abs(section.getEnrollmentTotalWeight(assignment, null) - desired);
                        disbSections++;
                        if (Math.abs(desired - section.getEnrollmentTotalWeight(assignment, null)) >= Math.max(1.0, 0.1 * desired)) {
                            disb10Sections++;
                            if (disb10SectionList != null)
                                disb10SectionList.add(section.getSubpart().getConfig().getOffering().getName() + " " + section.getSubpart().getName() + " " + section.getName());
                        }
                    }
                }
            }
        }
    }
    if (disbSections != 0) {
        double assignedCRWeight = getContext(assignment).getAssignedCourseRequestWeight();
        info.put("Average disbalance", sDecimalFormat.format(assignedCRWeight == 0 ? 0.0 : 100.0 * disbWeight / assignedCRWeight) + "% (" + sDecimalFormat.format(disbWeight / disbSections) + ")");
        String list = "";
        if (disb10SectionList != null) {
            int i = 0;
            for (String section : disb10SectionList) {
                if (i == disb10Limit) {
                    list += "\n...";
                    break;
                }
                list += "\n" + section;
                i++;
            }
        }
        info.put("Sections disbalanced by 10% or more", sDecimalFormat.format(disbSections == 0 ? 0.0 : 100.0 * disb10Sections / disbSections) + "% (" + disb10Sections + ")" + (list.isEmpty() ? "" : "\n" + list));
    }
    int assCR = 0, priCR = 0;
    for (Request r : variables()) {
        if (r instanceof CourseRequest && !r.getStudent().isDummy()) {
            CourseRequest cr = (CourseRequest) r;
            Enrollment e = assignment.getValue(cr);
            if (e != null) {
                assCR++;
                if (!cr.isAlternative() && cr.getCourses().get(0).equals(e.getCourse()))
                    priCR++;
            }
        }
    }
    if (assCR > 0)
        info.put("Assigned priority course requests", sDoubleFormat.format(100.0 * priCR / assCR) + "% (" + priCR + "/" + assCR + ")");
    int[] missing = new int[] { 0, 0, 0, 0, 0 };
    int incomplete = 0;
    for (Student student : getStudents()) {
        if (student.isDummy())
            continue;
        int nrRequests = 0;
        int nrAssignedRequests = 0;
        for (Request r : student.getRequests()) {
            // ignore free times
            if (!(r instanceof CourseRequest))
                continue;
            if (!r.isAlternative())
                nrRequests++;
            if (r.isAssigned(assignment))
                nrAssignedRequests++;
        }
        if (nrAssignedRequests < nrRequests) {
            missing[Math.min(nrRequests - nrAssignedRequests, missing.length) - 1]++;
            incomplete++;
        }
    }
    for (int i = 0; i < missing.length; i++) if (missing[i] > 0)
        info.put("Students missing " + (i == 0 ? "1 course" : i + 1 == missing.length ? (i + 1) + " or more courses" : (i + 1) + " courses"), sDecimalFormat.format(100.0 * missing[i] / incomplete) + "% (" + missing[i] + ")");
    // + " [precise: " + sDoubleFormat.format(getTotalValue(assignment, true)) + "]");
    info.put("Overall solution value", sDoubleFormat.format(getTotalValue(assignment)));
    int nrStudentsBelowMinCredit = 0, nrStudents = 0;
    for (Student student : getStudents()) {
        if (student.isDummy())
            continue;
        if (student.hasMinCredit()) {
            nrStudents++;
            float credit = student.getAssignedCredit(assignment);
            if (credit < student.getMinCredit() && !student.isComplete(assignment))
                nrStudentsBelowMinCredit++;
        }
    }
    if (nrStudentsBelowMinCredit > 0)
        info.put("Students below min credit", sDoubleFormat.format(100.0 * nrStudentsBelowMinCredit / nrStudents) + "% (" + nrStudentsBelowMinCredit + "/" + nrStudents + ")");
    int[] notAssignedPriority = new int[] { 0, 0, 0, 0, 0, 0, 0 };
    int[] assignedChoice = new int[] { 0, 0, 0, 0, 0 };
    int notAssignedTotal = 0, assignedChoiceTotal = 0;
    int avgPriority = 0, avgChoice = 0;
    for (Student student : getStudents()) {
        if (student.isDummy())
            continue;
        for (Request r : student.getRequests()) {
            // ignore free times
            if (!(r instanceof CourseRequest))
                continue;
            Enrollment e = r.getAssignment(assignment);
            if (e == null) {
                if (!r.isAlternative()) {
                    notAssignedPriority[Math.min(r.getPriority(), notAssignedPriority.length - 1)]++;
                    notAssignedTotal++;
                    avgPriority += r.getPriority();
                }
            } else {
                assignedChoice[Math.min(e.getTruePriority(), assignedChoice.length - 1)]++;
                assignedChoiceTotal++;
                avgChoice += e.getTruePriority();
            }
        }
    }
    for (int i = 0; i < notAssignedPriority.length; i++) if (notAssignedPriority[i] > 0)
        info.put("Priority: Not-assigned priority " + (i + 1 == notAssignedPriority.length ? (i + 1) + "+" : (i + 1)) + " course requests", sDecimalFormat.format(100.0 * notAssignedPriority[i] / notAssignedTotal) + "% (" + notAssignedPriority[i] + ")");
    if (notAssignedTotal > 0)
        info.put("Priority: Average not-assigned priority", sDecimalFormat.format(1.0 + ((double) avgPriority) / notAssignedTotal));
    for (int i = 0; i < assignedChoice.length; i++) if (assignedChoice[i] > 0)
        info.put("Choice: assigned " + (i == 0 ? "1st" : i == 1 ? "2nd" : i == 2 ? "3rd" : i + 1 == assignedChoice.length ? (i + 1) + "th+" : (i + 1) + "th") + " course choice", sDecimalFormat.format(100.0 * assignedChoice[i] / assignedChoiceTotal) + "% (" + assignedChoice[i] + ")");
    if (assignedChoiceTotal > 0)
        info.put("Choice: Average assigned choice", sDecimalFormat.format(1.0 + ((double) avgChoice) / assignedChoiceTotal));
    int nbrSections = 0, nbrFullSections = 0, nbrSections98 = 0, nbrSections95 = 0, nbrSections90 = 0, nbrSectionsDis = 0;
    int enrlSections = 0, enrlFullSections = 0, enrlSections98 = 0, enrlSections95 = 0, enrlSections90 = 0, enrlSectionsDis = 0;
    int nbrOfferings = 0, nbrFullOfferings = 0, nbrOfferings98 = 0, nbrOfferings95 = 0, nbrOfferings90 = 0;
    int enrlOfferings = 0, enrlOfferingsFull = 0, enrlOfferings98 = 0, enrlOfferings95 = 0, enrlOfferings90 = 0;
    for (Offering offering : getOfferings()) {
        int offeringLimit = 0, offeringEnrollment = 0;
        for (Config config : offering.getConfigs()) {
            int configLimit = config.getLimit();
            for (Subpart subpart : config.getSubparts()) {
                int subpartLimit = 0;
                for (Section section : subpart.getSections()) {
                    if (section.isCancelled())
                        continue;
                    int enrl = section.getEnrollments(assignment).size();
                    if (section.getLimit() < 0 || subpartLimit < 0)
                        subpartLimit = -1;
                    else
                        subpartLimit += (section.isEnabled() ? section.getLimit() : enrl);
                    nbrSections++;
                    enrlSections += enrl;
                    if (section.getLimit() >= 0 && section.getLimit() <= enrl) {
                        nbrFullSections++;
                        enrlFullSections += enrl;
                    }
                    if (!section.isEnabled() && (enrl > 0 || section.getLimit() >= 0)) {
                        nbrSectionsDis++;
                        enrlSectionsDis += enrl;
                    }
                    if (section.getLimit() >= 0 && (section.getLimit() - enrl) <= Math.round(0.02 * section.getLimit())) {
                        nbrSections98++;
                        enrlSections98 += enrl;
                    }
                    if (section.getLimit() >= 0 && (section.getLimit() - enrl) <= Math.round(0.05 * section.getLimit())) {
                        nbrSections95++;
                        enrlSections95 += enrl;
                    }
                    if (section.getLimit() >= 0 && (section.getLimit() - enrl) <= Math.round(0.10 * section.getLimit())) {
                        nbrSections90++;
                        enrlSections90 += enrl;
                    }
                }
                if (configLimit < 0 || subpartLimit < 0)
                    configLimit = -1;
                else
                    configLimit = Math.min(configLimit, subpartLimit);
            }
            if (offeringLimit < 0 || configLimit < 0)
                offeringLimit = -1;
            else
                offeringLimit += configLimit;
            offeringEnrollment += config.getEnrollments(assignment).size();
        }
        nbrOfferings++;
        enrlOfferings += offeringEnrollment;
        if (offeringLimit >= 0 && offeringEnrollment >= offeringLimit) {
            nbrFullOfferings++;
            enrlOfferingsFull += offeringEnrollment;
        }
        if (offeringLimit >= 0 && (offeringLimit - offeringEnrollment) <= Math.round(0.02 * offeringLimit)) {
            nbrOfferings98++;
            enrlOfferings98 += offeringEnrollment;
        }
        if (offeringLimit >= 0 && (offeringLimit - offeringEnrollment) <= Math.round(0.05 * offeringLimit)) {
            nbrOfferings95++;
            enrlOfferings95 += offeringEnrollment;
        }
        if (offeringLimit >= 0 && (offeringLimit - offeringEnrollment) <= Math.round(0.10 * offeringLimit)) {
            nbrOfferings90++;
            enrlOfferings90 += offeringEnrollment;
        }
    }
    if (enrlOfferings90 > 0 && enrlOfferings > 0)
        info.put("Full Offerings", (nbrFullOfferings > 0 ? nbrFullOfferings + " with no space (" + sDecimalFormat.format(100.0 * nbrFullOfferings / nbrOfferings) + "% of all offerings, " + sDecimalFormat.format(100.0 * enrlOfferingsFull / enrlOfferings) + "% assignments)\n" : "") + (nbrOfferings98 > nbrFullOfferings ? nbrOfferings98 + " with &leq; 2% available (" + sDecimalFormat.format(100.0 * nbrOfferings98 / nbrOfferings) + "% of all offerings, " + sDecimalFormat.format(100.0 * enrlOfferings98 / enrlOfferings) + "% assignments)\n" : "") + (nbrOfferings95 > nbrOfferings98 ? nbrOfferings95 + " with &leq; 5% available (" + sDecimalFormat.format(100.0 * nbrOfferings95 / nbrOfferings) + "% of all offerings, " + sDecimalFormat.format(100.0 * enrlOfferings95 / enrlOfferings) + "% assignments)\n" : "") + (nbrOfferings90 > nbrOfferings95 ? nbrOfferings90 + " with &leq; 10% available (" + sDecimalFormat.format(100.0 * nbrOfferings90 / nbrOfferings) + "% of all offerings, " + sDecimalFormat.format(100.0 * enrlOfferings90 / enrlOfferings) + "% assignments)" : ""));
    if ((enrlSections90 > 0 || nbrSectionsDis > 0) && enrlSections > 0)
        info.put("Full Sections", (nbrFullSections > 0 ? nbrFullSections + " with no space (" + sDecimalFormat.format(100.0 * nbrFullSections / nbrSections) + "% of all sections, " + sDecimalFormat.format(100.0 * enrlFullSections / enrlSections) + "% assignments)\n" : "") + (nbrSectionsDis > 0 ? nbrSectionsDis + " disabled (" + sDecimalFormat.format(100.0 * nbrSectionsDis / nbrSections) + "% of all sections, " + sDecimalFormat.format(100.0 * enrlSectionsDis / enrlSections) + "% assignments)\n" : "") + (enrlSections98 > nbrFullSections ? nbrSections98 + " with &leq; 2% available (" + sDecimalFormat.format(100.0 * nbrSections98 / nbrSections) + "% of all sections, " + sDecimalFormat.format(100.0 * enrlSections98 / enrlSections) + "% assignments)\n" : "") + (nbrSections95 > enrlSections98 ? nbrSections95 + " with &leq; 5% available (" + sDecimalFormat.format(100.0 * nbrSections95 / nbrSections) + "% of all sections, " + sDecimalFormat.format(100.0 * enrlSections95 / enrlSections) + "% assignments)\n" : "") + (nbrSections90 > nbrSections95 ? nbrSections90 + " with &leq; 10% available (" + sDecimalFormat.format(100.0 * nbrSections90 / nbrSections) + "% of all sections, " + sDecimalFormat.format(100.0 * enrlSections90 / enrlSections) + "% assignments)" : ""));
    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 > 0) {
            Set<Student> students = new HashSet<Student>();
            for (StudentQuality.Conflict c : getStudentQuality().getContext(assignment).computeAllConflicts(StudentQuality.Type.CourseTimeOverlap, assignment)) {
                students.add(c.getStudent());
            }
            info.put("Time overlaps: courses", students.size() + " students (avg " + sDoubleFormat.format(5.0 * shareCR / students.size()) + " mins)");
        }
        if (shareFT > 0) {
            Set<Student> students = new HashSet<Student>();
            for (StudentQuality.Conflict c : getStudentQuality().getContext(assignment).computeAllConflicts(StudentQuality.Type.FreeTimeOverlap, assignment)) {
                students.add(c.getStudent());
            }
            info.put("Time overlaps: free times", students.size() + " students (avg " + sDoubleFormat.format(5.0 * shareFT / students.size()) + " mins)");
        }
        if (shareUN > 0) {
            Set<Student> students = new HashSet<Student>();
            for (StudentQuality.Conflict c : getStudentQuality().getContext(assignment).computeAllConflicts(StudentQuality.Type.Unavailability, assignment)) {
                students.add(c.getStudent());
            }
            info.put("Time overlaps: teaching assignments", students.size() + " students (avg " + sDoubleFormat.format(5.0 * shareUN / students.size()) + " mins)");
        }
    } else if (getTimeOverlaps() != null && getTimeOverlaps().getTotalNrConflicts(assignment) != 0) {
        Set<TimeOverlapsCounter.Conflict> conf = getTimeOverlaps().getContext(assignment).computeAllConflicts(assignment);
        int shareCR = 0, shareFT = 0, shareUN = 0;
        Set<Student> studentsCR = new HashSet<Student>();
        Set<Student> studentsFT = new HashSet<Student>();
        Set<Student> studentsUN = new HashSet<Student>();
        for (TimeOverlapsCounter.Conflict c : conf) {
            if (c.getR1() instanceof CourseRequest && c.getR2() instanceof CourseRequest) {
                shareCR += c.getShare();
                studentsCR.add(c.getStudent());
            } else if (c.getS2() instanceof Unavailability) {
                shareUN += c.getShare();
                studentsUN.add(c.getStudent());
            } else {
                shareFT += c.getShare();
                studentsFT.add(c.getStudent());
            }
        }
        if (shareCR > 0)
            info.put("Time overlaps: courses", studentsCR.size() + " students (avg " + sDoubleFormat.format(5.0 * shareCR / studentsCR.size()) + " mins)");
        if (shareFT > 0)
            info.put("Time overlaps: free times", studentsFT.size() + " students (avg " + sDoubleFormat.format(5.0 * shareFT / studentsFT.size()) + " mins)");
        if (shareUN > 0)
            info.put("Time overlaps: teaching assignments", studentsUN.size() + " students (avg " + sDoubleFormat.format(5.0 * shareUN / studentsUN.size()) + " mins)");
    }
    return info;
}
Also used : Set(java.util.Set) TreeSet(java.util.TreeSet) HashSet(java.util.HashSet) Config(org.cpsolver.studentsct.model.Config) Unavailability(org.cpsolver.studentsct.model.Unavailability) TreeSet(java.util.TreeSet) Enrollment(org.cpsolver.studentsct.model.Enrollment) HashSet(java.util.HashSet) StudentQuality(org.cpsolver.studentsct.extension.StudentQuality) Request(org.cpsolver.studentsct.model.Request) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) Student(org.cpsolver.studentsct.model.Student) Offering(org.cpsolver.studentsct.model.Offering) Section(org.cpsolver.studentsct.model.Section) Constraint(org.cpsolver.ifs.model.Constraint) TimeOverlapsCounter(org.cpsolver.studentsct.extension.TimeOverlapsCounter) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) DistanceConflict(org.cpsolver.studentsct.extension.DistanceConflict) StudentConflict(org.cpsolver.studentsct.constraint.StudentConflict) Subpart(org.cpsolver.studentsct.model.Subpart)

Aggregations

Subpart (org.cpsolver.studentsct.model.Subpart)44 Section (org.cpsolver.studentsct.model.Section)40 Config (org.cpsolver.studentsct.model.Config)23 CourseRequest (org.cpsolver.studentsct.model.CourseRequest)22 Offering (org.cpsolver.studentsct.model.Offering)16 Course (org.cpsolver.studentsct.model.Course)13 Request (org.cpsolver.studentsct.model.Request)13 HashSet (java.util.HashSet)12 Set (java.util.Set)12 TreeSet (java.util.TreeSet)10 Enrollment (org.cpsolver.studentsct.model.Enrollment)10 Map (java.util.Map)8 Element (org.dom4j.Element)7 HashMap (java.util.HashMap)6 FreeTimeRequest (org.cpsolver.studentsct.model.FreeTimeRequest)6 Student (org.cpsolver.studentsct.model.Student)6 BitSet (java.util.BitSet)5 DistanceConflict (org.cpsolver.studentsct.extension.DistanceConflict)5 StudentQuality (org.cpsolver.studentsct.extension.StudentQuality)5 TimeOverlapsCounter (org.cpsolver.studentsct.extension.TimeOverlapsCounter)5