Search in sources :

Example 1 with StudentSectioningModel

use of org.cpsolver.studentsct.StudentSectioningModel in project cpsolver by UniTime.

the class RandomizedBacktrackNeighbourSelection method values.

/**
     * List of values of a variable.
     * {@link CourseRequest#computeRandomEnrollments(Assignment, int)} with the provided
     * limit is used for a {@link CourseRequest}.
     */
@Override
protected Iterator<Enrollment> values(BacktrackNeighbourSelection<Request, Enrollment>.BacktrackNeighbourSelectionContext<Request, Enrollment> context, Request variable) {
    if (variable instanceof CourseRequest) {
        final CourseRequest request = (CourseRequest) variable;
        final StudentSectioningModel model = (StudentSectioningModel) context.getModel();
        final Assignment<Request, Enrollment> assignment = context.getAssignment();
        List<Enrollment> values = (iMaxValues > 0 ? request.computeRandomEnrollments(assignment, iMaxValues) : request.computeEnrollments(assignment));
        Collections.sort(values, new Comparator<Enrollment>() {

            private HashMap<Enrollment, Double> iValues = new HashMap<Enrollment, Double>();

            private Double value(Enrollment e) {
                Double value = iValues.get(e);
                if (value == null) {
                    value = model.getStudentWeights().getWeight(assignment, e, (model.getDistanceConflict() == null ? null : model.getDistanceConflict().conflicts(e)), (model.getTimeOverlaps() == null ? null : model.getTimeOverlaps().conflicts(e)));
                    iValues.put(e, value);
                }
                return value;
            }

            @Override
            public int compare(Enrollment e1, Enrollment e2) {
                if (e1.equals(assignment.getValue(request)))
                    return -1;
                if (e2.equals(assignment.getValue(request)))
                    return 1;
                Double v1 = value(e1), v2 = value(e2);
                return v1.equals(v2) ? e1.compareTo(assignment, e2) : v2.compareTo(v1);
            }
        });
        return values.iterator();
    } else {
        return variable.computeEnrollments(context.getAssignment()).iterator();
    }
}
Also used : CourseRequest(org.cpsolver.studentsct.model.CourseRequest) HashMap(java.util.HashMap) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) Request(org.cpsolver.studentsct.model.Request) Enrollment(org.cpsolver.studentsct.model.Enrollment) StudentSectioningModel(org.cpsolver.studentsct.StudentSectioningModel)

Example 2 with StudentSectioningModel

use of org.cpsolver.studentsct.StudentSectioningModel 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 3 with StudentSectioningModel

use of org.cpsolver.studentsct.StudentSectioningModel in project cpsolver by UniTime.

the class CourseRequest method computeEnrollments.

/**
 * Recursive computation of enrollments
 *
 * @param enrollments
 *            list of enrollments to be returned
 * @param priority
 *            zero for the course, one for the first alternative, two for the second alternative
 * @param penalty
 *            penalty of the selected sections
 * @param course
 *            selected course
 * @param config
 *            selected configuration
 * @param sections
 *            sections selected so far
 * @param idx
 *            index of the subparts (a section of 0..idx-1 subparts has been
 *            already selected)
 * @param availableOnly
 *            only use available sections
 * @param skipSameTime
 *            for each possible times, pick only one section
 * @param selectedOnly
 *            select only sections that are selected (
 *            {@link CourseRequest#isSelected(Section)} is true)
 * @param random
 *            pick sections in a random order (useful when limit is used)
 * @param limit
 *            when above zero, limit the number of selected enrollments to
 *            this limit
 * @param ignoreDisabled
 *            are sections that are disabled for student scheduling allowed to be used
 * @param reservations
 *            list of applicable reservations
 */
private void computeEnrollments(Assignment<Request, Enrollment> assignment, Collection<Enrollment> enrollments, int priority, double penalty, Course course, Config config, HashSet<Section> sections, int idx, boolean availableOnly, boolean skipSameTime, boolean selectedOnly, boolean random, int limit) {
    if (limit > 0 && enrollments.size() >= limit)
        return;
    if (idx == 0) {
        // run only once for each configuration
        if (isNotAllowed(course, config))
            return;
        boolean canOverLimit = false;
        if (availableOnly) {
            for (Reservation r : getReservations(course)) {
                if (!r.canBatchAssignOverLimit())
                    continue;
                if (r.neverIncluded())
                    continue;
                if (!r.getConfigs().isEmpty() && !r.getConfigs().contains(config))
                    continue;
                if (r.getReservedAvailableSpace(assignment, this) < getWeight())
                    continue;
                canOverLimit = true;
                break;
            }
        }
        if (!canOverLimit) {
            if (availableOnly && config.getLimit() >= 0 && ConfigLimit.getEnrollmentWeight(assignment, config, this) > config.getLimit())
                return;
            if (availableOnly && course.getLimit() >= 0 && CourseLimit.getEnrollmentWeight(assignment, course, this) > course.getLimit())
                return;
            if (config.getOffering().hasReservations()) {
                boolean hasReservation = false, hasConfigReservation = false, reservationMustBeUsed = false;
                for (Reservation r : getReservations(course)) {
                    if (r.mustBeUsed())
                        reservationMustBeUsed = true;
                    if (availableOnly && r.getReservedAvailableSpace(assignment, this) < getWeight())
                        continue;
                    if (r.neverIncluded()) {
                    } else if (r.getConfigs().isEmpty()) {
                        hasReservation = true;
                    } else if (r.getConfigs().contains(config)) {
                        hasReservation = true;
                        hasConfigReservation = true;
                    }
                }
                if (!hasConfigReservation && config.getTotalUnreservedSpace() < getWeight())
                    return;
                if (!hasReservation && config.getOffering().getTotalUnreservedSpace() < getWeight())
                    return;
                if (availableOnly && !hasReservation && config.getOffering().getUnreservedSpace(assignment, this) < getWeight())
                    return;
                if (availableOnly && !hasConfigReservation && config.getUnreservedSpace(assignment, this) < getWeight())
                    return;
                if (!hasReservation && reservationMustBeUsed)
                    return;
            }
        }
    }
    if (config.getSubparts().size() == idx) {
        if (skipSameTime && sSameTimePrecise) {
            boolean waitListedOrSelected = false;
            if (!getSelectedChoices().isEmpty() || !getWaitlistedChoices().isEmpty()) {
                for (Section section : sections) {
                    if (isWaitlisted(section) || isSelected(section)) {
                        waitListedOrSelected = true;
                        break;
                    }
                }
            }
            if (!waitListedOrSelected) {
                for (Enrollment enrollment : enrollments) {
                    if (sameTimes(enrollment.getSections(), sections))
                        return;
                }
            }
        }
        Enrollment e = new Enrollment(this, priority, course, config, new HashSet<SctAssignment>(sections), null);
        if (isNotAllowed(e)) {
        } else if (!config.getOffering().hasReservations()) {
            enrollments.add(e);
        } else {
            boolean mustHaveReservation = config.getOffering().getTotalUnreservedSpace() < getWeight();
            boolean mustHaveConfigReservation = config.getTotalUnreservedSpace() < getWeight();
            boolean mustHaveSectionReservation = false;
            boolean containDisabledSection = false;
            for (Section s : sections) {
                if (s.getTotalUnreservedSpace() < getWeight()) {
                    mustHaveSectionReservation = true;
                }
                if (!getStudent().isAllowDisabled() && !s.isEnabled()) {
                    containDisabledSection = true;
                }
            }
            boolean canOverLimit = false;
            if (availableOnly) {
                for (Reservation r : getReservations(course)) {
                    if (!r.canBatchAssignOverLimit() || !r.isIncluded(e))
                        continue;
                    if (r.getReservedAvailableSpace(assignment, this) < getWeight())
                        continue;
                    if (containDisabledSection && !r.isAllowDisabled())
                        continue;
                    enrollments.add(new Enrollment(this, priority, null, config, new HashSet<SctAssignment>(sections), r));
                    canOverLimit = true;
                }
            }
            if (!canOverLimit) {
                boolean reservationMustBeUsed = false;
                reservations: for (Reservation r : (availableOnly ? getSortedReservations(assignment, course) : getReservations(course))) {
                    if (r.mustBeUsed())
                        reservationMustBeUsed = true;
                    if (!r.isIncluded(e))
                        continue;
                    if (availableOnly && r.getReservedAvailableSpace(assignment, this) < getWeight())
                        continue;
                    if (mustHaveConfigReservation && r.getConfigs().isEmpty())
                        continue;
                    if (mustHaveSectionReservation)
                        for (Section s : sections) if (r.getSections(s.getSubpart()) == null && s.getTotalUnreservedSpace() < getWeight())
                            continue reservations;
                    if (containDisabledSection && !r.isAllowDisabled())
                        continue;
                    enrollments.add(new Enrollment(this, priority, null, config, new HashSet<SctAssignment>(sections), r));
                    // only one available reservation suffice (the best matching one)
                    if (availableOnly)
                        return;
                }
                // a case w/o reservation
                if (!(mustHaveReservation || mustHaveConfigReservation || mustHaveSectionReservation) && !(availableOnly && config.getOffering().getUnreservedSpace(assignment, this) < getWeight()) && !reservationMustBeUsed && !containDisabledSection) {
                    enrollments.add(new Enrollment(this, priority, !getReservations(course).isEmpty(), null, config, new HashSet<SctAssignment>(sections), null));
                }
            }
        }
    } else {
        Subpart subpart = config.getSubparts().get(idx);
        HashSet<TimeLocation> times = (skipSameTime ? new HashSet<TimeLocation>() : null);
        List<Section> sectionsThisSubpart = subpart.getSections();
        if (skipSameTime) {
            sectionsThisSubpart = new ArrayList<Section>(subpart.getSections());
            Collections.sort(sectionsThisSubpart, new AssignmentComparator<Section, Request, Enrollment>(assignment));
        }
        List<Section> matchingSectionsThisSubpart = new ArrayList<Section>(subpart.getSections().size());
        boolean hasChildren = !subpart.getChildren().isEmpty();
        for (Section section : sectionsThisSubpart) {
            if (section.isCancelled())
                continue;
            if (!isRequired(section))
                continue;
            if (getInitialAssignment() != null && (getModel() != null && ((StudentSectioningModel) getModel()).getKeepInitialAssignments()) && !getInitialAssignment().getAssignments().contains(section))
                continue;
            if (isFixed() && !getFixedValue().getAssignments().contains(section))
                continue;
            if (section.getParent() != null && !sections.contains(section.getParent()))
                continue;
            if (section.isOverlapping(sections))
                continue;
            if (selectedOnly && hasSelection(section) && !isSelected(section))
                continue;
            if (isNotAllowed(course, section))
                continue;
            if (!getStudent().isAvailable(section)) {
                boolean canOverlap = false;
                for (Reservation r : getReservations(course)) {
                    if (!r.isAllowOverlap())
                        continue;
                    if (r.getSections(subpart) != null && !r.getSections(subpart).contains(section))
                        continue;
                    if (r.getReservedAvailableSpace(assignment, this) < getWeight())
                        continue;
                    canOverlap = true;
                    break;
                }
                if (!canOverlap)
                    continue;
            }
            boolean canOverLimit = false;
            if (availableOnly) {
                for (Reservation r : getReservations(course)) {
                    if (!r.canBatchAssignOverLimit())
                        continue;
                    if (r.getSections(subpart) != null && !r.getSections(subpart).contains(section))
                        continue;
                    if (r.getReservedAvailableSpace(assignment, this) < getWeight())
                        continue;
                    canOverLimit = true;
                    break;
                }
            }
            if (!canOverLimit) {
                if (availableOnly && section.getLimit() >= 0 && SectionLimit.getEnrollmentWeight(assignment, section, this) > section.getLimit())
                    continue;
                if (config.getOffering().hasReservations()) {
                    boolean hasReservation = false, hasSectionReservation = false, reservationMustBeUsed = false;
                    for (Reservation r : getReservations(course)) {
                        if (r.mustBeUsed())
                            reservationMustBeUsed = true;
                        if (availableOnly && r.getReservedAvailableSpace(assignment, this) < getWeight())
                            continue;
                        if (r.getSections(subpart) == null) {
                            hasReservation = true;
                        } else if (r.getSections(subpart).contains(section)) {
                            hasReservation = true;
                            hasSectionReservation = true;
                        }
                    }
                    if (!hasSectionReservation && section.getTotalUnreservedSpace() < getWeight())
                        continue;
                    if (availableOnly && !hasSectionReservation && section.getUnreservedSpace(assignment, this) < getWeight())
                        continue;
                    if (!hasReservation && reservationMustBeUsed)
                        continue;
                }
            }
            if (!getStudent().isAllowDisabled() && !section.isEnabled()) {
                boolean allowDisabled = false;
                for (Reservation r : getReservations(course)) {
                    if (!r.isAllowDisabled())
                        continue;
                    if (r.getSections(subpart) != null && !r.getSections(subpart).contains(section))
                        continue;
                    if (!r.getConfigs().isEmpty() && !r.getConfigs().contains(config))
                        continue;
                    allowDisabled = true;
                    break;
                }
                if (!allowDisabled)
                    continue;
            }
            if (skipSameTime && section.getTime() != null && !hasChildren && !times.add(section.getTime()) && !isSelected(section) && !isWaitlisted(section) && (section.getIgnoreConflictWithSectionIds() == null || section.getIgnoreConflictWithSectionIds().isEmpty()))
                continue;
            matchingSectionsThisSubpart.add(section);
        }
        if (random || limit > 0) {
            sectionsThisSubpart = new ArrayList<Section>(sectionsThisSubpart);
            Collections.shuffle(sectionsThisSubpart);
        }
        int i = 0;
        for (Section section : matchingSectionsThisSubpart) {
            sections.add(section);
            computeEnrollments(assignment, enrollments, priority, penalty + section.getPenalty(), course, config, sections, idx + 1, availableOnly, skipSameTime, selectedOnly, random, limit < 0 ? limit : Math.max(1, limit * (1 + i) / matchingSectionsThisSubpart.size()));
            sections.remove(section);
            i++;
        }
    }
}
Also used : TimeLocation(org.cpsolver.coursett.model.TimeLocation) ArrayList(java.util.ArrayList) Reservation(org.cpsolver.studentsct.reservation.Reservation) StudentSectioningModel(org.cpsolver.studentsct.StudentSectioningModel) HashSet(java.util.HashSet)

Example 4 with StudentSectioningModel

use of org.cpsolver.studentsct.StudentSectioningModel in project cpsolver by UniTime.

the class RandomizedBacktrackNeighbourSelection method values.

/**
 * List of values of a variable.
 * {@link CourseRequest#computeRandomEnrollments(Assignment, int)} with the provided
 * limit is used for a {@link CourseRequest}.
 */
@Override
protected Iterator<Enrollment> values(BacktrackNeighbourSelection<Request, Enrollment>.BacktrackNeighbourSelectionContext context, Request variable) {
    if (variable instanceof CourseRequest) {
        final CourseRequest request = (CourseRequest) variable;
        final StudentSectioningModel model = (StudentSectioningModel) context.getModel();
        final Assignment<Request, Enrollment> assignment = context.getAssignment();
        final Enrollment current = assignment.getValue(request);
        List<Enrollment> values = (iMaxValues > 0 ? request.computeRandomEnrollments(assignment, iMaxValues) : request.computeEnrollments(assignment));
        Collections.sort(values, new Comparator<Enrollment>() {

            private HashMap<Enrollment, Double> iValues = new HashMap<Enrollment, Double>();

            private Double value(Enrollment e) {
                Double value = iValues.get(e);
                if (value == null) {
                    if (model.getStudentQuality() != null)
                        value = model.getStudentWeights().getWeight(assignment, e, model.getStudentQuality().conflicts(e));
                    else
                        value = model.getStudentWeights().getWeight(assignment, e, (model.getDistanceConflict() == null ? null : model.getDistanceConflict().conflicts(e)), (model.getTimeOverlaps() == null ? null : model.getTimeOverlaps().conflicts(e)));
                    iValues.put(e, value);
                }
                return value;
            }

            @Override
            public int compare(Enrollment e1, Enrollment e2) {
                if (e1.equals(e2))
                    return 0;
                if (e1.equals(current))
                    return -1;
                if (e2.equals(current))
                    return 1;
                Double v1 = value(e1), v2 = value(e2);
                return v1.equals(v2) ? e1.compareTo(assignment, e2) : v2.compareTo(v1);
            }
        });
        return values.iterator();
    } else {
        return variable.computeEnrollments(context.getAssignment()).iterator();
    }
}
Also used : CourseRequest(org.cpsolver.studentsct.model.CourseRequest) HashMap(java.util.HashMap) CourseRequest(org.cpsolver.studentsct.model.CourseRequest) Request(org.cpsolver.studentsct.model.Request) Enrollment(org.cpsolver.studentsct.model.Enrollment) StudentSectioningModel(org.cpsolver.studentsct.StudentSectioningModel)

Example 5 with StudentSectioningModel

use of org.cpsolver.studentsct.StudentSectioningModel in project cpsolver by UniTime.

the class EnrollmentSelection method isAllowed.

/**
 * true, if it is allowed to assign given value
 * @param assignment current assignment
 * @param value given value
 * @param conflicts conflicting assignments
 * @return true if it is allowed
 */
public boolean isAllowed(Assignment<Request, Enrollment> assignment, Enrollment value, Set<Enrollment> conflicts) {
    if (value == null)
        return true;
    StudentSectioningModel model = (StudentSectioningModel) value.variable().getModel();
    if (model.getNrLastLikeRequests(false) == 0 || model.getNrRealRequests(false) == 0)
        return true;
    Request request = value.variable();
    if (request.getStudent().isDummy()) {
        if (conflicts == null)
            conflicts = value.variable().getModel().conflictValues(assignment, value);
        for (Enrollment conflict : conflicts) {
            if (!conflict.getRequest().getStudent().isDummy())
                return false;
        }
    } else {
        if (conflicts == null)
            conflicts = value.variable().getModel().conflictValues(assignment, value);
        if (conflicts.size() > (assignment.getValue(request) == null ? 1 : 0))
            return false;
    }
    return true;
}
Also used : Request(org.cpsolver.studentsct.model.Request) Enrollment(org.cpsolver.studentsct.model.Enrollment) StudentSectioningModel(org.cpsolver.studentsct.StudentSectioningModel)

Aggregations

StudentSectioningModel (org.cpsolver.studentsct.StudentSectioningModel)10 ArrayList (java.util.ArrayList)4 Enrollment (org.cpsolver.studentsct.model.Enrollment)4 Request (org.cpsolver.studentsct.model.Request)4 CourseRequest (org.cpsolver.studentsct.model.CourseRequest)3 HashMap (java.util.HashMap)2 HashSet (java.util.HashSet)2 LinkedSections (org.cpsolver.studentsct.constraint.LinkedSections)2 Student (org.cpsolver.studentsct.model.Student)2 TimeLocation (org.cpsolver.coursett.model.TimeLocation)1 RouletteWheelSelection (org.cpsolver.ifs.heuristics.RouletteWheelSelection)1 Course (org.cpsolver.studentsct.model.Course)1 Offering (org.cpsolver.studentsct.model.Offering)1 RequestGroup (org.cpsolver.studentsct.model.RequestGroup)1 Section (org.cpsolver.studentsct.model.Section)1 Subpart (org.cpsolver.studentsct.model.Subpart)1 Reservation (org.cpsolver.studentsct.reservation.Reservation)1