001package org.cpsolver.exam.model; 002 003import java.util.ArrayList; 004import java.util.HashSet; 005import java.util.List; 006import java.util.Set; 007 008import org.cpsolver.ifs.assignment.Assignment; 009import org.cpsolver.ifs.model.Constraint; 010 011 012/** 013 * An instructor. <br> 014 * <br> 015 * 016 * @version ExamTT 1.3 (Examination Timetabling)<br> 017 * Copyright (C) 2008 - 2014 Tomas Muller<br> 018 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 019 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 020 * <br> 021 * This library is free software; you can redistribute it and/or modify 022 * it under the terms of the GNU Lesser General Public License as 023 * published by the Free Software Foundation; either version 3 of the 024 * License, or (at your option) any later version. <br> 025 * <br> 026 * This library is distributed in the hope that it will be useful, but 027 * 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. <br> 030 * <br> 031 * You should have received a copy of the GNU Lesser General Public 032 * License along with this library; if not see 033 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 034 */ 035public class ExamInstructor extends Constraint<Exam, ExamPlacement> { 036 private String iName; 037 private boolean iAllowDirectConflicts = true; 038 private List<ExamOwner> iOwners = new ArrayList<ExamOwner>(); 039 private boolean[] iAvailable = null; 040 041 public ExamInstructor(ExamModel model, long id, String name) { 042 super(); 043 iAllowDirectConflicts = model.getProperties().getPropertyBoolean("Instructor.AllowDirectConflicts", iAllowDirectConflicts); 044 iId = id; 045 iName = name; 046 } 047 048 /** 049 * True when direct instructor conflicts are not allowed. 050 * @return true if direct conflicts are allowed 051 */ 052 public boolean isAllowDirectConflicts() { 053 return iAllowDirectConflicts; 054 } 055 056 /** 057 * Set to true when direct instructor conflicts are not allowed. 058 * @param allowDirectConflicts true if direct conflicts are allowed 059 */ 060 public void setAllowDirectConflicts(boolean allowDirectConflicts) { 061 iAllowDirectConflicts = allowDirectConflicts; 062 } 063 064 /** 065 * Exam(s) enrolled by the instructor that are scheduled in the given period 066 * @param assignment current assignment 067 * @param period given period 068 * @return exams that are associated with this instructor and placed in the given period 069 */ 070 public Set<Exam> getExams(Assignment<Exam, ExamPlacement> assignment, ExamPeriod period) { 071 Set<Exam> exams = ((ExamModel)getModel()).getInstructorsOfPeriod(assignment, period).get(this); 072 return (exams != null ? exams : new HashSet<Exam>()); 073 // return getContext(assignment).getExams(period.getIndex()); 074 } 075 076 /** 077 * Exam(s) enrolled by the instructor that are scheduled in the given day 078 * @param assignment current assignment 079 * @param period given period 080 * @return exams that are associated with this instructor and placed in the day of the given period 081 */ 082 public Set<Exam> getExamsADay(Assignment<Exam, ExamPlacement> assignment, ExamPeriod period) { 083 Set<Exam> exams = ((ExamModel)getModel()).getInstructorsOfDay(assignment, period).get(this); 084 return (exams != null ? exams : new HashSet<Exam>()); 085 // return getContext(assignment).getExamsOfDay(period.getDay()); 086 } 087 088 /** 089 * Exam(s) enrolled by the instructor that are scheduled in the given day 090 * @param assignment current assignment 091 * @param day given day 092 * @return exams that are associated with this instructor and placed in the given day 093 */ 094 public Set<Exam> getExamsADay(Assignment<Exam, ExamPlacement> assignment, int day) { 095 Set<Exam> exams = ((ExamModel)getModel()).getInstructorsOfDay(assignment, day).get(this); 096 return (exams != null ? exams : new HashSet<Exam>()); 097 // return getContext(assignment).getExamsOfDay(day); 098 } 099 100 /** 101 * Compute conflicts between the given assignment of an exam and all the 102 * current assignments (of this instructor). Only not-allowed conflicts (see 103 * {@link ExamInstructor#isAllowDirectConflicts()}) are considered. 104 */ 105 @Override 106 public void computeConflicts(Assignment<Exam, ExamPlacement> assignment, ExamPlacement p, Set<ExamPlacement> conflicts) { 107 if (isAllowDirectConflicts()) 108 return; 109 Set<Exam> exams = ((ExamModel)getModel()).getInstructorsOfPeriod(assignment, p.getPeriod()).get(this); 110 if (exams != null) 111 for (Exam exam : exams) { 112 conflicts.add(assignment.getValue(exam)); 113 } 114 } 115 116 /** 117 * Check whether there is a conflict between the given assignment of an exam 118 * and all the current assignments (of this instructor). Only not-allowed 119 * conflicts (see {@link ExamInstructor#isAllowDirectConflicts()}) are 120 * considered. 121 */ 122 @Override 123 public boolean inConflict(Assignment<Exam, ExamPlacement> assignment, ExamPlacement p) { 124 if (isAllowDirectConflicts()) 125 return false; 126 Set<Exam> exams = ((ExamModel)getModel()).getInstructorsOfPeriod(assignment, p.getPeriod()).get(this); 127 return exams != null && !exams.isEmpty(); 128 } 129 130 /** 131 * True if the given exams can conflict (see 132 * {@link ExamInstructor#isAllowDirectConflicts()}), or if they are placed 133 * at different periods. 134 */ 135 @Override 136 public boolean isConsistent(ExamPlacement p1, ExamPlacement p2) { 137 if (isAllowDirectConflicts()) 138 return true; 139 return (p1.getPeriod() != p2.getPeriod()); 140 } 141 142 /** 143 * Compare two instructors for equality 144 */ 145 @Override 146 public boolean equals(Object o) { 147 if (o == null || !(o instanceof ExamInstructor)) 148 return false; 149 ExamInstructor s = (ExamInstructor) o; 150 return getId() == s.getId(); 151 } 152 153 /** 154 * Hash code 155 */ 156 @Override 157 public int hashCode() { 158 return (int) (getId() ^ (getId() >>> 32)); 159 } 160 161 /** 162 * Instructor name 163 */ 164 @Override 165 public String getName() { 166 return hasName() ? iName : String.valueOf(getId()); 167 } 168 169 /** 170 * Instructor name 171 * @return true if instructor name is set and not empty 172 */ 173 public boolean hasName() { 174 return (iName != null && iName.length() > 0); 175 } 176 177 /** 178 * Instructor name 179 */ 180 @Override 181 public String toString() { 182 return getName(); 183 } 184 185 /** 186 * Compare two instructors (by instructor ids) 187 * @param o another instructor 188 * @return comparison 189 */ 190 public int compareTo(ExamInstructor o) { 191 return toString().compareTo(o.toString()); 192 } 193 194 /** 195 * Courses and/or sections that this instructor is enrolled to 196 * 197 * @return list of {@link ExamOwner} 198 */ 199 public List<ExamOwner> getOwners() { 200 return iOwners; 201 } 202 203 @Override 204 public boolean isHard() { 205 return !isAllowDirectConflicts(); 206 } 207 208 /** 209 * True if the student is available (for examination timetabling) during the 210 * given period 211 * 212 * @param period 213 * a period 214 * @return true if a student can attend an exam at the given period, false 215 * if otherwise 216 */ 217 public boolean isAvailable(ExamPeriod period) { 218 return (iAvailable == null ? true : iAvailable[period.getIndex()]); 219 } 220 221 /** 222 * Set whether the student is available (for examination timetabling) during 223 * the given period 224 * 225 * @param period 226 * a period 227 * @param available 228 * true if a student can attend an exam at the given period, 229 * false if otherwise 230 */ 231 public void setAvailable(int period, boolean available) { 232 if (iAvailable == null) { 233 iAvailable = new boolean[((ExamModel)getModel()).getNrPeriods()]; 234 for (int i = 0; i < iAvailable.length; i++) 235 iAvailable[i] = true; 236 } 237 iAvailable[period] = available; 238 } 239 240 /* 241 @Override 242 public Context createAssignmentContext(Assignment<Exam, ExamPlacement> assignment) { 243 return new Context(assignment); 244 } 245 246 public class Context implements AssignmentConstraintContext<Exam, ExamPlacement> { 247 private Set<Exam>[] iTable; 248 private Set<Exam>[] iDayTable; 249 250 @SuppressWarnings("unchecked") 251 public Context(Assignment<Exam, ExamPlacement> assignment) { 252 ExamModel model = (ExamModel)getModel(); 253 iTable = new Set[model.getNrPeriods()]; 254 for (int i = 0; i < iTable.length; i++) 255 iTable[i] = new HashSet<Exam>(); 256 iDayTable = new Set[model.getNrDays()]; 257 for (int i = 0; i < iDayTable.length; i++) 258 iDayTable[i] = new HashSet<Exam>(); 259 for (Exam exam: variables()) { 260 ExamPlacement placement = assignment.getValue(exam); 261 if (placement != null) 262 assigned(assignment, placement); 263 } 264 } 265 266 @Override 267 public void assigned(Assignment<Exam, ExamPlacement> assignment, ExamPlacement placement) { 268 iTable[placement.getPeriod().getIndex()].add(placement.variable()); 269 iDayTable[placement.getPeriod().getDay()].add(placement.variable()); 270 } 271 272 @Override 273 public void unassigned(Assignment<Exam, ExamPlacement> assignment, ExamPlacement placement) { 274 iTable[placement.getPeriod().getIndex()].remove(placement.variable()); 275 iDayTable[placement.getPeriod().getDay()].remove(placement.variable()); 276 } 277 278 public Set<Exam> getExams(int period) { return iTable[period]; } 279 280 public Set<Exam> getExamsOfDay(int day) { return iDayTable[day]; } 281 } 282 */ 283}