001 package net.sf.cpsolver.exam.model;
002
003 import java.util.HashSet;
004 import java.util.Iterator;
005 import java.util.Set;
006 import java.util.Vector;
007
008 import net.sf.cpsolver.ifs.model.Constraint;
009 import net.sf.cpsolver.ifs.model.Value;
010
011 /**
012 * An instructor.
013 * <br><br>
014 *
015 * @version
016 * ExamTT 1.1 (Examination Timetabling)<br>
017 * Copyright (C) 2008 Tomáš Müller<br>
018 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
019 * Lazenska 391, 76314 Zlin, Czech Republic<br>
020 * <br>
021 * This library is free software; you can redistribute it and/or
022 * modify it under the terms of the GNU Lesser General Public
023 * License as published by the Free Software Foundation; either
024 * version 2.1 of the License, or (at your option) any later version.
025 * <br><br>
026 * This library is distributed in the hope that it will be useful,
027 * but WITHOUT ANY WARRANTY; without even the implied warranty of
028 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
029 * Lesser General Public License for more details.
030 * <br><br>
031 * You should have received a copy of the GNU Lesser General Public
032 * License along with this library; if not, write to the Free Software
033 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
034 */
035 public class ExamInstructor extends Constraint {
036 private HashSet[] iTable;
037 private HashSet[] iDayTable;
038 private String iName;
039 private boolean iAllowDirectConflicts = true;
040 private Vector iOwners = new Vector();
041 private boolean[] iAvailable = null;
042
043 public ExamInstructor(ExamModel model, long id, String name) {
044 super();
045 iAllowDirectConflicts = model.getProperties().getPropertyBoolean("Instructor.AllowDirectConflicts", iAllowDirectConflicts);
046 iAssignedVariables = null;
047 iId = id;
048 iName = name;
049 iTable = new HashSet[model.getNrPeriods()];
050 for (int i=0;i<iTable.length;i++) iTable[i]=new HashSet();
051 iDayTable = new HashSet[model.getNrDays()];
052 for (int i=0;i<iDayTable.length;i++) iDayTable[i]=new HashSet();
053 }
054
055 /**
056 * True when direct instructor conflicts are not allowed.
057 */
058 public boolean isAllowDirectConflicts() {
059 return iAllowDirectConflicts;
060 }
061
062 /**
063 * Set to true when direct instructor conflicts are not allowed.
064 */
065 public void setAllowDirectConflicts(boolean allowDirectConflicts) {
066 iAllowDirectConflicts = allowDirectConflicts;
067 }
068
069 /**
070 * Exam(s) enrolled by the instructor that are scheduled in the given period
071 */
072 public Set getExams(ExamPeriod period) { return iTable[period.getIndex()]; }
073 /**
074 * Exam(s) enrolled by the instructor that are scheduled in the given day
075 */
076 public Set getExamsADay(ExamPeriod period) { return iDayTable[period.getDay()]; }
077 /**
078 * Exam(s) enrolled by the instructor that are scheduled in the given day
079 */
080 public Set getExamsADay(int day) { return iDayTable[day]; }
081
082 /**
083 * Compute conflicts between the given assignment of an exam and all the current assignments (of this instructor).
084 * Only not-allowed conflicts (see {@link ExamInstructor#isAllowDirectConflicts()}) are considered.
085 */
086 public void computeConflicts(Value value, Set conflicts) {
087 if (isAllowDirectConflicts()) return;
088 ExamPlacement p = (ExamPlacement)value;
089 for (Iterator i=iTable[p.getPeriod().getIndex()].iterator();i.hasNext();) {
090 Exam exam = (Exam)i.next();
091 conflicts.add(exam.getAssignment());
092 }
093 }
094
095 /**
096 * Check whether there is a conflict between the given assignment of an exam and all the current assignments (of this instructor).
097 * Only not-allowed conflicts (see {@link ExamInstructor#isAllowDirectConflicts()}) are considered.
098 */
099 public boolean inConflict(Value value) {
100 if (isAllowDirectConflicts()) return false;
101 ExamPlacement p = (ExamPlacement)value;
102 return !iTable[p.getPeriod().getIndex()].isEmpty();
103 }
104
105 /**
106 * True if the given exams can conflict (see {@link ExamInstructor#isAllowDirectConflicts()}),
107 * or if they are placed at different periods.
108 */
109 public boolean isConsistent(Value value1, Value value2) {
110 if (isAllowDirectConflicts()) return true;
111 ExamPlacement p1 = (ExamPlacement)value1;
112 ExamPlacement p2 = (ExamPlacement)value2;
113 return (p1.getPeriod()!=p2.getPeriod());
114 }
115
116 /**
117 * An exam was assigned, update instructor assignment table
118 */
119 public void afterAssigned(long iteration, Value value) {
120 ExamPlacement p = (ExamPlacement)value;
121 iTable[p.getPeriod().getIndex()].add(value.variable());
122 iDayTable[p.getPeriod().getDay()].add(value.variable());
123 }
124
125 /**
126 * An exam was unassigned, update instructor assignment table
127 */
128 public void afterUnassigned(long iteration, Value value) {
129 ExamPlacement p = (ExamPlacement)value;
130 iTable[p.getPeriod().getIndex()].remove(value.variable());
131 iDayTable[p.getPeriod().getDay()].remove(value.variable());
132 }
133
134 /**
135 * Compare two instructors for equality
136 */
137 public boolean equals(Object o) {
138 if (o==null || !(o instanceof ExamInstructor)) return false;
139 ExamInstructor s = (ExamInstructor)o;
140 return getId()==s.getId();
141 }
142
143 /**
144 * Hash code
145 */
146 public int hashCode() {
147 return (int)(getId() ^ (getId() >>> 32));
148 }
149
150 /**
151 * Instructor name
152 */
153 public String getName() {
154 return hasName()?iName:String.valueOf(getId());
155 }
156
157 /**
158 * Instructor name
159 */
160 public boolean hasName() {
161 return (iName!=null && iName.length()>0);
162 }
163
164 /**
165 * Instructor name
166 */
167 public String toString() {
168 return getName();
169 }
170
171 /**
172 * Compare two instructors (by instructor ids)
173 */
174 public int compareTo(Object o) {
175 return toString().compareTo(o.toString());
176 }
177
178 /**
179 * Courses and/or sections that this instructor is enrolled to
180 * @return list of {@link ExamOwner}
181 */
182 public Vector getOwners() {
183 return iOwners;
184 }
185
186 public boolean isHard() {
187 return !isAllowDirectConflicts();
188 }
189
190 /**
191 * True if the student is available (for examination timetabling) during the given period
192 * @param period a period
193 * @return true if a student can attend an exam at the given period, false if otherwise
194 */
195 public boolean isAvailable(ExamPeriod period) {
196 return (iAvailable==null?true:iAvailable[period.getIndex()]);
197 }
198
199 /**
200 * Set whether the student is available (for examination timetabling) during the given period
201 * @param period a period
202 * @param available true if a student can attend an exam at the given period, false if otherwise
203 */
204 public void setAvailable(int period, boolean available) {
205 if (iAvailable==null) {
206 iAvailable = new boolean[iTable.length];
207 for (int i=0;i<iTable.length;i++) iAvailable[i]=true;
208 }
209 iAvailable[period]=available;
210 }
211 }