001package org.cpsolver.coursett.constraint;
002
003import java.util.BitSet;
004import java.util.Enumeration;
005import java.util.Set;
006
007import org.cpsolver.coursett.Constants;
008import org.cpsolver.coursett.criteria.additional.InstructorConflict;
009import org.cpsolver.coursett.model.Lecture;
010import org.cpsolver.coursett.model.Placement;
011import org.cpsolver.coursett.model.TimeLocation;
012import org.cpsolver.ifs.assignment.Assignment;
013
014/**
015 * Soft version of the instructor constraint.
016 * 
017 * @author  Tomáš Müller
018 * @version CourseTT 1.3 (University Course Timetabling)<br>
019 *          Copyright (C) 2006 - 2014 Tomáš Müller<br>
020 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
021 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
022 * <br>
023 *          This library is free software; you can redistribute it and/or modify
024 *          it under the terms of the GNU Lesser General Public License as
025 *          published by the Free Software Foundation; either version 3 of the
026 *          License, or (at your option) any later version. <br>
027 * <br>
028 *          This library is distributed in the hope that it will be useful, but
029 *          WITHOUT ANY WARRANTY; without even the implied warranty of
030 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
031 *          Lesser General Public License for more details. <br>
032 * <br>
033 *          You should have received a copy of the GNU Lesser General Public
034 *          License along with this library; if not see
035 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
036 */
037public class SoftInstructorConstraint extends InstructorConstraint {
038
039    public SoftInstructorConstraint(Long id, String puid, String name, boolean ignDist) {
040        super(id, puid, name, ignDist);
041    }
042    
043 
044    @Override
045    public void computeConflicts(Assignment<Lecture, Placement> assignment, Placement placement, Set<Placement> conflicts) {
046        return;
047    }
048    
049    @Override
050    public boolean inConflict(Assignment<Lecture, Placement> assignment, Placement placement) {
051        return false;
052    }
053
054    @Override
055    public boolean isConsistent(Placement p1, Placement p2) {
056        return true;
057    }
058    
059    @Override
060    public boolean isHard() {
061        return false;
062    }
063    
064    @Override
065    public InstructorConstraintContext createAssignmentContext(Assignment<Lecture, Placement> assignment) {
066        return new SoftInstructorConstraintContext(assignment);
067    }
068    
069    public int getConflicts(Assignment<Lecture, Placement> assignment) {
070        return ((SoftInstructorConstraintContext)getContext(assignment)).getConflicts();
071    }
072    
073    public int getConflicts(Assignment<Lecture, Placement> assignment, Placement placement) {
074        if (((SoftInstructorConstraintContext)getContext(assignment)).inConflict(assignment, placement)) return 1;
075        return 0;
076    }
077    
078    public int getWorstConflicts() {
079        if (variables().size() < 2) return 0;
080        return variables().size() - 1;
081    }
082
083    public class SoftInstructorConstraintContext extends InstructorConstraintContext {
084        private int iConficts = 0;
085
086        public SoftInstructorConstraintContext(Assignment<Lecture, Placement> assignment) {
087            super(assignment);
088            iConficts = countConflicts(assignment);
089            getModel().getCriterion(InstructorConflict.class).inc(assignment, iConficts);
090        }
091        
092        @Override
093        public void assigned(Assignment<Lecture, Placement> assignment, Placement placement) {
094            super.assigned(assignment, placement);
095            getModel().getCriterion(InstructorConflict.class).inc(assignment, -iConficts);
096            iConficts = countConflicts(assignment);
097            getModel().getCriterion(InstructorConflict.class).inc(assignment, iConficts);
098        }
099        
100        @Override
101        public void unassigned(Assignment<Lecture, Placement> assignment, Placement placement) {
102            super.unassigned(assignment, placement);
103            getModel().getCriterion(InstructorConflict.class).inc(assignment, -iConficts);
104            iConficts = countConflicts(assignment);
105            getModel().getCriterion(InstructorConflict.class).inc(assignment, iConficts);
106        }
107        
108        public int getConflicts() { return iConficts; }
109        
110        protected int countConflicts(Assignment<Lecture, Placement> assignment) {
111            int conflicts = 0;
112            for (Lecture lecture: variables()) {
113                Placement placement = assignment.getValue(lecture);
114                if (placement != null && inConflict(assignment, placement))
115                    conflicts ++;
116            }
117            return conflicts;
118        }
119        
120        public boolean inConflict(Assignment<Lecture, Placement> assignment, Placement placement) {
121            Lecture lecture = placement.variable();
122            Placement current = assignment.getValue(lecture);
123            BitSet weekCode = placement.getTimeLocation().getWeekCode();
124            
125            if (!isAvailable(lecture, placement)) return true;
126            
127            for (Enumeration<Integer> e = placement.getTimeLocation().getSlots(); e.hasMoreElements();) {
128                int slot = e.nextElement();
129                for (Placement p : getPlacements(slot)) {
130                    if (!p.equals(current) && p.getTimeLocation().shareWeeks(weekCode)) {
131                        if (p.canShareRooms(placement) && p.sameRooms(placement))
132                            continue;
133                        return true;
134                    }
135                }
136            }
137            if (!isIgnoreDistances()) {
138                for (Enumeration<Integer> e = placement.getTimeLocation().getStartSlots(); e.hasMoreElements();) {
139                    int startSlot = e.nextElement();
140                    
141                    int prevSlot = startSlot - 1;
142                    if (prevSlot >= 0 && (prevSlot / Constants.SLOTS_PER_DAY) == (startSlot / Constants.SLOTS_PER_DAY)) {
143                        for (Placement c : getPlacements(prevSlot, placement)) {
144                            if (lecture.equals(c.variable())) continue;
145                            if (c.canShareRooms(placement) && c.sameRooms(placement)) continue;
146                            if (Placement.getDistanceInMeters(getDistanceMetric(), placement, c) > getDistanceMetric().getInstructorProhibitedLimit())
147                                return true;
148                        }
149                    }
150                    int nextSlot = startSlot + placement.getTimeLocation().getLength();
151                    if ((nextSlot / Constants.SLOTS_PER_DAY) == (startSlot / Constants.SLOTS_PER_DAY)) {
152                        for (Placement c : getPlacements(nextSlot, placement)) {
153                            if (lecture.equals(c.variable())) continue;
154                            if (c.canShareRooms(placement) && c.sameRooms(placement)) continue;
155                            if (Placement.getDistanceInMeters(getDistanceMetric(), placement, c) > getDistanceMetric().getInstructorProhibitedLimit())
156                                return true;
157                        }
158                    }
159                    
160                    if (getDistanceMetric().doComputeDistanceConflictsBetweenNonBTBClasses()) {
161                        TimeLocation t1 = placement.getTimeLocation();
162                        for (Lecture other: variables()) {
163                            Placement otherPlacement = assignment.getValue(other);
164                            if (otherPlacement == null || other.equals(placement.variable())) continue;
165                            TimeLocation t2 = otherPlacement.getTimeLocation();
166                            if (t1 == null || t2 == null || !t1.shareDays(t2) || !t1.shareWeeks(t2)) continue;
167                            if (t1.getStartSlot() + t1.getLength() < t2.getStartSlot()) {
168                                if (Placement.getDistanceInMinutes(getDistanceMetric(), placement, otherPlacement) > t1.getBreakTime() + Constants.SLOT_LENGTH_MIN * (t2.getStartSlot() - t1.getStartSlot() - t1.getLength()))
169                                    return true;
170                            } else if (t2.getStartSlot() + t2.getLength() < t1.getStartSlot()) {
171                                if (Placement.getDistanceInMinutes(getDistanceMetric(), placement, otherPlacement) >  t2.getBreakTime() + Constants.SLOT_LENGTH_MIN * (t1.getStartSlot() - t2.getStartSlot() - t2.getLength()))
172                                    return true;
173                            }
174                        }
175                    }
176                }
177            }
178            return false;
179        }
180    }
181}