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 }