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