Search in sources :

Example 16 with Section

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

the class OnlineSectioningCriterion method compare.

@Override
public int compare(Assignment<Request, Enrollment> assignment, Enrollment[] current, Enrollment[] best) {
    if (best == null)
        return -1;
    // 0. best priority & alternativity ignoring free time requests
    boolean ft = false;
    for (int idx = 0; idx < current.length; idx++) {
        if (isFreeTime(idx)) {
            ft = true;
            continue;
        }
        if (best[idx] != null && best[idx].getAssignments() != null) {
            if (current[idx] == null || current[idx].getSections() == null)
                // higher priority request assigned
                return 1;
            if (best[idx].getPriority() < current[idx].getPriority())
                // less alternative request assigned
                return 1;
        } else {
            if (current[idx] != null && current[idx].getAssignments() != null)
                // higher priority request assigned
                return -1;
        }
    }
    // 0.5. avoid course time overlaps & unavailabilities
    if (getModel().getTimeOverlaps() != null) {
        int bestTimeOverlaps = 0, currentTimeOverlaps = 0;
        for (int idx = 0; idx < current.length; idx++) {
            if (best[idx] != null && best[idx].getAssignments() != null && best[idx].getRequest() instanceof CourseRequest) {
                for (int x = 0; x < idx; x++) {
                    if (best[x] != null && best[x].getAssignments() != null && best[x].getRequest() instanceof CourseRequest)
                        bestTimeOverlaps += getModel().getTimeOverlaps().nrConflicts(best[x], best[idx]);
                }
                for (int x = 0; x < idx; x++) {
                    if (current[x] != null && current[x].getAssignments() != 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 && current[idx].getAssignments() != null && current[idx].isCourseRequest()) {
                currentTimeOverlaps += getModel().getTimeOverlaps().nrNotAvailableTimeConflicts(current[idx]);
            }
        }
        if (currentTimeOverlaps < bestTimeOverlaps)
            return -1;
        if (bestTimeOverlaps < currentTimeOverlaps)
            return 1;
    }
    // 1. minimize number of penalties
    double bestPenalties = 0, currentPenalties = 0;
    for (int idx = 0; idx < current.length; idx++) {
        if (best[idx] != null && best[idx].getAssignments() != null && best[idx].isCourseRequest()) {
            for (Section section : best[idx].getSections()) bestPenalties += getModel().getOverExpected(assignment, section, best[idx].getRequest());
            for (Section section : current[idx].getSections()) currentPenalties += getModel().getOverExpected(assignment, section, current[idx].getRequest());
        }
    }
    if (currentPenalties < bestPenalties)
        return -1;
    if (bestPenalties < currentPenalties)
        return 1;
    // 2. best priority & alternativity including free time requests
    if (ft) {
        for (int idx = 0; idx < current.length; idx++) {
            if (best[idx] != null && best[idx].getAssignments() != null) {
                if (current[idx] == null || current[idx].getSections() == null)
                    // higher priority request assigned
                    return 1;
                if (best[idx].getPriority() < current[idx].getPriority())
                    // less alternative request assigned
                    return 1;
            } else {
                if (current[idx] != null && current[idx].getAssignments() != null)
                    // higher priority request assigned
                    return -1;
            }
        }
    }
    // 3. maximize selection
    int bestSelected = 0, currentSelected = 0;
    for (int idx = 0; idx < current.length; idx++) {
        if (best[idx] != null && best[idx].getAssignments() != 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))
                    bestSelected++;
                for (Section section : current[idx].getSections()) if (preferred.contains(section))
                    currentSelected++;
            }
        }
    }
    if (currentSelected > bestSelected)
        return -1;
    if (bestSelected > currentSelected)
        return 1;
    // 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 (current[idx] != null && 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 -1;
    if (0.3 * bestSelectedConfigs + 0.7 * bestSelectedSections > 0.3 * currentSelectedConfigs + 0.7 * currentSelectedSections)
        return 1;
    // 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 && best[idx].getAssignments() != null) {
                for (int x = 0; x < idx; x++) {
                    if (best[x] != null && best[x].getAssignments() != 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]);
                }
                for (int x = 0; x < idx; x++) {
                    if (current[x] != null && current[x].getAssignments() != 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 && current[idx].getAssignments() != null && current[idx].isCourseRequest()) {
                currentTimeOverlaps += getModel().getTimeOverlaps().nrNotAvailableTimeConflicts(current[idx]);
            }
        }
        if (currentTimeOverlaps < bestTimeOverlaps)
            return -1;
        if (bestTimeOverlaps < currentTimeOverlaps)
            return 1;
    }
    // 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 && best[idx].getAssignments() != null) {
                for (int x = 0; x < idx; x++) {
                    if (best[x] != null && best[x].getAssignments() != null)
                        bestDistanceConf += getModel().getDistanceConflict().nrConflicts(best[x], best[idx]);
                }
                for (int x = 0; x < idx; x++) {
                    if (current[x] != null && current[x].getAssignments() != null)
                        currentDistanceConf += getModel().getDistanceConflict().nrConflicts(current[x], current[idx]);
                }
            }
        }
        if (currentDistanceConf < bestDistanceConf)
            return -1;
        if (bestDistanceConf < currentDistanceConf)
            return 1;
    }
    // 6. avoid no-time sections
    int bestNoTime = 0, currentNoTime = 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.getTime() == null)
                bestNoTime++;
            for (Section section : current[idx].getSections()) if (section.getTime() == null)
                currentNoTime++;
        }
    }
    if (currentNoTime < bestNoTime)
        return -1;
    if (bestNoTime < currentNoTime)
        return 1;
    // 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 && best[idx].getAssignments() != 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++;
            }
            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 -1;
    if (bestUnavailableSizeFraction < currentUnavailableSizeFraction)
        return 1;
    // 8. average penalty sections
    double bestPenalty = 0.0, currentPenalty = 0.0;
    for (int idx = 0; idx < current.length; idx++) {
        if (best[idx] != null && best[idx].getAssignments() != null) {
            for (Section section : best[idx].getSections()) bestPenalty += section.getPenalty();
            for (Section section : current[idx].getSections()) currentPenalty += section.getPenalty();
        }
    }
    if (currentPenalty < bestPenalty)
        return -1;
    if (bestPenalty < currentPenalty)
        return 1;
    return 0;
}
Also used : FreeTimeRequest(org.cpsolver.studentsct.model.FreeTimeRequest) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) Subpart(org.cpsolver.studentsct.model.Subpart) Section(org.cpsolver.studentsct.model.Section)

Example 17 with Section

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

the class ShuffleStudentsSelection method init.

@Override
public void init(Solver<Request, Enrollment> solver) {
    StudentSectioningModel model = (StudentSectioningModel) solver.currentSolution().getModel();
    iQueue = new LinkedList<Shuffle>();
    Assignment<Request, Enrollment> assignment = solver.currentSolution().getAssignment();
    // Check all request groups that have a spread < 1.0 
    RouletteWheelSelection<RequestGroup> groups = new RouletteWheelSelection<RequestGroup>();
    for (Offering offering : model.getOfferings()) {
        for (Course course : offering.getCourses()) {
            for (RequestGroup group : course.getRequestGroups()) {
                double spread = group.getAverageSpread(solver.currentSolution().getAssignment());
                if (spread >= 1.0)
                    continue;
                groups.add(group, 1.0 - spread);
            }
        }
    }
    // If there are some, pick one randomly (using roulette wheel selection)
    if (groups.hasMoreElements()) {
        RequestGroup group = groups.nextElement();
        RouletteWheelSelection<Subpart> subparts = new RouletteWheelSelection<Subpart>();
        for (CourseRequest cr : group.getRequests()) {
            Enrollment e = assignment.getValue(cr);
            if (e != null)
                for (Section section : e.getSections()) if (group.getSectionSpread(assignment, section) < 1.0)
                    subparts.addExisting(section.getSubpart(), 1.0);
        }
        if (subparts.hasMoreElements()) {
            // Pick a subpart that has sections with a section spread < 1.0
            Subpart subpart = subparts.nextElement();
            RouletteWheelSelection<Section> sections = new RouletteWheelSelection<Section>();
            section: for (Section section : subpart.getSections()) {
                // Only take sections that all requests can use
                for (CourseRequest cr : group.getRequests()) {
                    boolean match = false;
                    for (Enrollment e : cr.values(assignment)) if (e.getSections().contains(section)) {
                        match = true;
                        break;
                    }
                    if (!match)
                        continue section;
                }
                // Take sections with conflicts with lower probability
                int nrConflicts = 0;
                if (!section.isAllowOverlap())
                    requests: for (CourseRequest cr : group.getRequests()) {
                        for (Request r : cr.getStudent().getRequests()) {
                            if (r.equals(cr))
                                continue;
                            Enrollment e = assignment.getValue(r);
                            if (e != null && !e.isAllowOverlap() && section.isOverlapping(e.getSections())) {
                                nrConflicts++;
                                continue requests;
                            }
                        }
                    }
                sections.add(section, 1 + group.getRequests().size() - nrConflicts);
            }
            Set<Section> filter = new HashSet<Section>();
            double space = 0.0;
            // Pick enough sections
            while (sections.hasMoreElements()) {
                Section section = sections.nextElement();
                if (filter.add(section)) {
                    if (section.getLimit() < 0)
                        break;
                    space += section.getLimit();
                }
                if (space >= group.getTotalWeight())
                    break;
            }
            // Add all requests that should be moved into the queue
            for (CourseRequest cr : group.getRequests()) {
                Shuffle shuffle = new Shuffle(group, cr, filter);
                Enrollment e = assignment.getValue(cr);
                if (e != null && shuffle.matchFilter(e))
                    continue;
                iQueue.add(shuffle);
            }
        } else {
            // No subpart -> no section filter
            for (CourseRequest cr : group.getRequests()) iQueue.add(new Shuffle(group, cr, null));
        }
    }
    // Shuffle the queue
    Collections.shuffle((LinkedList<Shuffle>) iQueue);
    // Initialize the backtrack selection, if needed
    if (iBacktrack == null) {
        try {
            iBacktrack = new ShuffleBacktrackNeighbourSelection(solver.getProperties());
            iBacktrack.init(solver);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }
    // Change progress
    Progress.getInstance(solver.currentSolution().getModel()).setPhase("Shuffling students along request groups...", iQueue.size());
}
Also used : RouletteWheelSelection(org.cpsolver.ifs.heuristics.RouletteWheelSelection) Request(org.cpsolver.studentsct.model.Request) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) Offering(org.cpsolver.studentsct.model.Offering) Section(org.cpsolver.studentsct.model.Section) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) RequestGroup(org.cpsolver.studentsct.model.RequestGroup) Subpart(org.cpsolver.studentsct.model.Subpart) Enrollment(org.cpsolver.studentsct.model.Enrollment) Course(org.cpsolver.studentsct.model.Course) StudentSectioningModel(org.cpsolver.studentsct.StudentSectioningModel) HashSet(java.util.HashSet)

Example 18 with Section

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

the class ResectioningWeights method getWeight.

@Override
public double getWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
    double weight = super.getWeight(assignment, enrollment);
    if (enrollment.isCourseRequest() && enrollment.getAssignments() != null && iLastSectionProvider != null) {
        int sameChoice = 0;
        int sameTime = 0;
        int sameRooms = 0;
        int sameName = 0;
        for (Section section : enrollment.getSections()) {
            if (iLastSectionProvider.sameLastChoice(section))
                sameChoice++;
            if (iLastSectionProvider.sameLastTime(section))
                sameTime++;
            if (iLastSectionProvider.sameLastRoom(section))
                sameRooms++;
            if (iLastSectionProvider.sameLastName(section, enrollment.getCourse()))
                sameName++;
        }
        CourseRequest cr = (CourseRequest) enrollment.getRequest();
        if (sameChoice == 0 && !cr.getSelectedChoices().isEmpty()) {
            for (Section section : enrollment.getSections()) {
                if (cr.isSelected(section)) {
                    sameChoice++;
                    continue;
                }
            }
        }
        double size = enrollment.getAssignments().size();
        double sameChoiceFraction = (size - sameChoice) / size;
        double sameTimeFraction = (size - sameTime) / size;
        double sameRoomsFraction = (size - sameRooms) / size;
        double sameNameFraction = (size - sameName) / size;
        double base = getBaseWeight(assignment, enrollment);
        weight -= sameChoiceFraction * base * iSameChoiceFactor;
        weight -= sameTimeFraction * base * iSameTimeFactor;
        weight -= sameRoomsFraction * base * iSameRoomsFactor;
        weight -= sameNameFraction * base * iSameNameFactor;
    }
    return weight;
}
Also used : CourseRequest(org.cpsolver.studentsct.model.CourseRequest) Section(org.cpsolver.studentsct.model.Section)

Example 19 with Section

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

the class StudentSchedulingAssistantWeights method best.

private double[] best(Assignment<Request, Enrollment> assignment, CourseRequest cr) {
    double[] cached = iCache.get(cr);
    if (cached != null)
        return cached;
    double bestTime = 0;
    Double bestOverExpected = null;
    Double bestAvgPenalty = null;
    double bestSelected = 0.0;
    for (Course course : cr.getCourses()) {
        for (Config config : course.getOffering().getConfigs()) {
            int size = config.getSubparts().size();
            double sectionsWithTime = 0;
            double overExpected = 0;
            double penalty = 0;
            double selectedSections = 0;
            for (Subpart subpart : config.getSubparts()) {
                boolean hasTime = false;
                Double sectionPenalty = null;
                Double sectionOverExpected = null;
                boolean hasSelection = false;
                for (Section section : subpart.getSections()) {
                    if (section.getLimit() == 0)
                        continue;
                    if (section.getTime() != null)
                        hasTime = true;
                    if (!cr.getSelectedChoices().isEmpty() && cr.isSelected(section))
                        hasSelection = true;
                    if (sectionPenalty == null || sectionPenalty > section.getPenalty())
                        sectionPenalty = section.getPenalty();
                    double oexp = getOverExpected(assignment, section, cr);
                    if (sectionOverExpected == null || sectionOverExpected > oexp)
                        sectionOverExpected = oexp;
                }
                if (hasTime)
                    sectionsWithTime++;
                if (sectionPenalty != null)
                    penalty += sectionPenalty;
                if (hasSelection)
                    selectedSections++;
                if (sectionOverExpected != null)
                    overExpected += sectionOverExpected;
            }
            if (sectionsWithTime / size > bestTime)
                bestTime = sectionsWithTime / size;
            if (bestOverExpected == null || overExpected < bestOverExpected)
                bestOverExpected = overExpected;
            if (bestAvgPenalty == null || penalty / size < bestAvgPenalty)
                bestAvgPenalty = penalty / size;
            if (selectedSections / size > bestSelected)
                bestSelected = selectedSections / size;
        }
    }
    cached = new double[] { bestTime, (bestOverExpected == null ? 0.0 : bestOverExpected), (bestAvgPenalty == null ? 0.0 : bestAvgPenalty), bestSelected };
    iCache.put(cr, cached);
    return cached;
}
Also used : Config(org.cpsolver.studentsct.model.Config) Subpart(org.cpsolver.studentsct.model.Subpart) Course(org.cpsolver.studentsct.model.Course) Section(org.cpsolver.studentsct.model.Section)

Example 20 with Section

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

the class StudentSchedulingAssistantWeights method getWeight.

@Override
public double getWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
    if (!enrollment.isCourseRequest())
        return getBaseWeight(assignment, enrollment);
    if (enrollment.getAssignments().isEmpty())
        return 0;
    double base = getBaseWeight(assignment, enrollment);
    double weight = base;
    int size = enrollment.getAssignments().size();
    CourseRequest cr = (CourseRequest) enrollment.getRequest();
    double[] best = best(assignment, cr);
    double hasTime = 0;
    double oexp = 0;
    double penalty = 0.0;
    for (Section section : enrollment.getSections()) {
        if (section.getTime() != null)
            hasTime++;
        oexp += getOverExpected(assignment, section, cr);
        penalty += section.getPenalty();
    }
    double noTime = best[0] - (hasTime / size);
    double overExpected = oexp - best[1];
    double avgPenalty = (penalty / size) - best[2];
    int nrSelected = 0;
    if (!cr.getSelectedChoices().isEmpty()) {
        for (Section section : enrollment.getSections()) if (cr.isSelected(section))
            nrSelected++;
    }
    double unselectedFraction = best[3] - (nrSelected / size);
    double unavailableSize = 0;
    double altSectionsWithLimit = 0;
    for (Section section : enrollment.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)
            unavailableSize += (averageSize - section.getLimit()) / averageSize;
        altSectionsWithLimit++;
    }
    double unavailableSizeFraction = (unavailableSize > 0 ? unavailableSize / altSectionsWithLimit : 0.0);
    weight -= overExpected * base * iOverExpectedFactor;
    weight -= unselectedFraction * base * iSelectionFactor;
    weight -= noTime * base * iNoTimeFactor;
    weight -= unavailableSizeFraction * base * iAvailabilityFactor;
    weight -= avgPenalty * iPenaltyFactor;
    return round(weight);
}
Also used : CourseRequest(org.cpsolver.studentsct.model.CourseRequest) Subpart(org.cpsolver.studentsct.model.Subpart) Section(org.cpsolver.studentsct.model.Section)

Aggregations

Section (org.cpsolver.studentsct.model.Section)59 Subpart (org.cpsolver.studentsct.model.Subpart)34 CourseRequest (org.cpsolver.studentsct.model.CourseRequest)32 Config (org.cpsolver.studentsct.model.Config)23 Request (org.cpsolver.studentsct.model.Request)22 Course (org.cpsolver.studentsct.model.Course)19 Enrollment (org.cpsolver.studentsct.model.Enrollment)19 Offering (org.cpsolver.studentsct.model.Offering)17 HashSet (java.util.HashSet)14 FreeTimeRequest (org.cpsolver.studentsct.model.FreeTimeRequest)14 ArrayList (java.util.ArrayList)13 Set (java.util.Set)11 TreeSet (java.util.TreeSet)10 HashMap (java.util.HashMap)9 Map (java.util.Map)9 Element (org.dom4j.Element)9 Student (org.cpsolver.studentsct.model.Student)7 CSVFile (org.cpsolver.ifs.util.CSVFile)6 DistanceConflict (org.cpsolver.studentsct.extension.DistanceConflict)6 RoomLocation (org.cpsolver.coursett.model.RoomLocation)5