001package org.cpsolver.studentsct.constraint;
002
003import java.util.Set;
004
005import org.cpsolver.ifs.assignment.Assignment;
006import org.cpsolver.ifs.model.Constraint;
007import org.cpsolver.studentsct.model.Enrollment;
008import org.cpsolver.studentsct.model.Request;
009import org.cpsolver.studentsct.model.Student;
010
011
012/**
013 * This constraints ensures that a student is not enrolled into sections that
014 * are overlapping in time.
015 * 
016 * <br>
017 * <br>
018 * 
019 * @version StudentSct 1.3 (Student Sectioning)<br>
020 *          Copyright (C) 2007 - 2014 Tomas Muller<br>
021 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
022 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
023 * <br>
024 *          This library is free software; you can redistribute it and/or modify
025 *          it under the terms of the GNU Lesser General Public License as
026 *          published by the Free Software Foundation; either version 3 of the
027 *          License, or (at your option) any later version. <br>
028 * <br>
029 *          This library is distributed in the hope that it will be useful, but
030 *          WITHOUT ANY WARRANTY; without even the implied warranty of
031 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
032 *          Lesser General Public License for more details. <br>
033 * <br>
034 *          You should have received a copy of the GNU Lesser General Public
035 *          License along with this library; if not see
036 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
037 */
038public class StudentConflict extends Constraint<Request, Enrollment> {
039    
040    /**
041     * Constructor
042     * @param student student for which the constraint is created
043     */
044    public StudentConflict(Student student) {
045        super();
046        for (Request request : student.getRequests())
047            addVariable(request);
048    }
049
050    /**
051     * A given enrollment is conflicting when the student is enrolled into
052     * another course / free time request that has an assignment that is
053     * overlapping with one or more assignments of the given section. See
054     * {@link Enrollment#isOverlapping(Enrollment)} for more details. All such
055     * overlapping enrollments are added into the provided set of conflicts.
056     * 
057     * @param enrollment
058     *            {@link Enrollment} that is being considered
059     * @param conflicts
060     *            resultant list of conflicting enrollments
061     */
062    @Override
063    public void computeConflicts(Assignment<Request, Enrollment> assignment, Enrollment enrollment, Set<Enrollment> conflicts) {
064        // for all assigned course requests -> if overlapping with this
065        // enrollment -> conflict
066        for (Request request : variables()) {
067            if (request.equals(enrollment.getRequest()))
068                continue;
069            Enrollment e = assignment.getValue(request);
070            if (e == null)
071                continue;
072            if (enrollment.isOverlapping(e))
073                conflicts.add(e);
074        }
075
076        // if this enrollment cannot be assigned (student already has a full
077        // schedule) -> unassignd a lowest priority request
078        if (!enrollment.getAssignments().isEmpty() && !enrollment.getStudent().canAssign(assignment, enrollment.getRequest())) {
079            Enrollment lowestPriorityEnrollment = null;
080            int lowestPriority = -1;
081            for (Request request : variables()) {
082                if (request.equals(enrollment.getRequest()))
083                    continue;
084                Enrollment e = assignment.getValue(request);
085                if (e == null)
086                    continue;
087                if (lowestPriority < request.getPriority()) {
088                    lowestPriority = request.getPriority();
089                    lowestPriorityEnrollment = e;
090                }
091            }
092            if (lowestPriorityEnrollment != null)
093                conflicts.add(lowestPriorityEnrollment);
094        }
095    }
096
097    /** Two enrollments are consistent if they are not overlapping in time */
098    @Override
099    public boolean isConsistent(Enrollment e1, Enrollment e2) {
100        return !e1.isOverlapping(e2);
101    }
102
103    /**
104     * A given enrollment is conflicting when the student is enrolled into
105     * another course / free time request that has an assignment that is
106     * overlapping with one or more assignments of the given section. See
107     * {@link Enrollment#isOverlapping(Enrollment)} for more details.
108     * 
109     * @param enrollment
110     *            {@link Enrollment} that is being considered
111     * @return true, if the student is enrolled into another enrollment of a
112     *         different request that is overlapping in time with the given
113     *         enrollment
114     */
115    @Override
116    public boolean inConflict(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
117        // for all assigned course requests -> if overlapping with this
118        // enrollment -> conflict
119        for (Request request : variables()) {
120            if (request.equals(enrollment.getRequest()))
121                continue;
122            Enrollment e = assignment.getValue(request);
123            if (e == null)
124                continue;
125            if (enrollment.isOverlapping(e))
126                return true;
127        }
128
129        // if this enrollment cannot be assigned (student already has a full
130        // schedule) -> conflict
131        if (!enrollment.getStudent().canAssign(assignment, enrollment.getRequest()))
132            return true;
133
134        // nothing above -> no conflict
135        return false;
136    }
137
138    @Override
139    public String toString() {
140        return "StudentConflicts";
141    }
142}