001    package ttsolver.constraint;
002    
003    import ifs.model.*;
004    import ifs.util.*;
005    import java.util.*;
006    import ttsolver.model.*;
007    
008    /**
009     * Join student enrollment constraint.
010     * <br>
011     * This constraint is placed between all pairs of classes where there is at least one student attending both classes.
012     * It represents a number of student conflicts (number of joined enrollments), if the given two classes overlap in time.
013     * <br>
014     * Also, it dynamically maintains the counter of all student conflicts. It is a soft constraint.
015     *
016     *
017     * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomáš Müller</a>
018     * @version 1.0
019     */
020    
021    public class JenrlConstraint extends BinaryConstraint {
022        private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(JenrlConstraint.class);
023        private Counter iGlobalViolations;
024        private long iJenrl;
025        private boolean iAdded = false;
026        
027        /** Constructor
028         * @param jenrl number of joined enrollments
029         * @param globalViolations global counter of student conflicts
030         */
031        public JenrlConstraint(long jenrl, Counter globalViolations) {
032            super();
033            iJenrl = jenrl;
034            iGlobalViolations = globalViolations;
035        }
036    
037        /** Set global counter of student conflicts */
038        public void setViolatedCounter(Counter globalViolations) { iGlobalViolations = globalViolations; }
039        
040        public void computeConflicts(Value value, Set conflicts) {
041        }
042        
043        public boolean inConflict(Value value) {
044            return false;
045        }
046        
047        public boolean isConsistent(Value value1, Value value2) {
048            return true;
049        }
050        
051        public void unassigned(long iteration, Value value) {
052            super.unassigned(iteration, value);
053            if (iAdded) {
054                iGlobalViolations.dec(iJenrl);
055                iAdded=false;
056                ((Lecture)first()).removeActiveJenrl(this);
057                ((Lecture)second()).removeActiveJenrl(this);
058            }
059        }
060        
061        /** Returns true if the given placements are overlapping or they are back-to-back and too far for students.*/
062       public static boolean isInConflict(Placement p1, Placement p2) {
063           if (p1==null || p2==null) return false;
064           TimeLocation t1=p1.getTimeLocation(), t2=p2.getTimeLocation();
065           if (!t1.shareDays(t2)) return false;
066           if (t1.shareHours(t2)) return true;
067           //if (t1.hasIntersection(t2)) return true;
068           //if (!Placement.shareDays(p1,p2)) return false;
069           int s1 = t1.getStartSlot(), s2 = t2.getStartSlot();
070           if (s1+t1.getNrHalfHoursPerMeeting()!=s2 &&
071               s2+t2.getNrHalfHoursPerMeeting()!=s1) return false;
072           double distance = Placement.getDistance(p1,p2);
073           if (distance <= 67.0) return false;
074           if (distance <= 100.0 && (
075               (t1.getLength()==3 && s1+t1.getLength()==s2) ||
076               (t2.getLength()==3 && s2+t2.getLength()==s1)))
077               return false;
078           return true;
079       }
080    
081       public void assigned(long iteration, Value value) {
082           super.assigned(iteration, value);
083           if (second()==null || first().getAssignment()==null || second().getAssignment()==null) return;
084            //if (v1.getInitialAssignment()!=null && v2.getInitialAssignment()!=null && v1.getAssignment().equals(v1.getInitialAssignment()) && v2.getAssignment().equals(v2.getInitialAssignment())) return;
085            if (isInConflict((Placement)first().getAssignment(),(Placement)second().getAssignment())) {
086                iAdded=true;
087                iGlobalViolations.inc(iJenrl);
088                ((Lecture)first()).addActiveJenrl(this);
089                ((Lecture)second()).addActiveJenrl(this);
090            }
091        }
092    
093       /** Number of joined enrollments if the given value is assigned to the given variable */
094        public long jenrl(Variable variable, Value value) {
095            Lecture anotherLecture = (Lecture)(first().equals(variable)?second():first());
096            if (anotherLecture.getAssignment()==null) return 0;
097            Lecture lecture = (Lecture) variable;
098            return (isInConflict((Placement)anotherLecture.getAssignment(),(Placement)value)?iJenrl:0);
099        }
100    
101        /** True if the given two lectures overlap in time */
102        public boolean isInConflict() {
103            return iAdded;
104        }
105    
106        /** True if the given two lectures overlap in time */
107        public boolean isInConflictPrecise() {
108            return isInConflict((Placement)first().getAssignment(),(Placement)second().getAssignment());
109        }
110    
111        /** Increment the number of joined enrollments (during student final sectioning) */
112        public void incJenrl() {
113            if (iJenrl==0) {
114                ((Lecture)first()).addActiveJenrl(this);
115                ((Lecture)second()).addActiveJenrl(this);
116            }
117            iJenrl++;
118            if (iAdded) iGlobalViolations.inc(1);
119        }
120        
121        /** Decrement the number of joined enrollments (during student final sectioning) */
122        public void decJenrl() {
123            iJenrl--;
124            if (iAdded) iGlobalViolations.dec(1);
125            if (iJenrl==0) {
126                ((Lecture)first()).removeActiveJenrl(this);
127                ((Lecture)second()).removeActiveJenrl(this);
128            }
129        }
130    
131        /** Number of joined enrollments (during student final sectioning) */
132        public long getJenrl() { return iJenrl; }
133        public boolean isHard() { return false; }
134        
135        public String toString() {
136            return "JENR{"+first().getName()+","+second().getName()+","+(iAdded?iJenrl:0)+"/"+iJenrl+"}";
137        }
138           
139    }