001 package net.sf.cpsolver.coursett.constraint; 002 003 import java.util.BitSet; 004 import java.util.Enumeration; 005 import java.util.HashSet; 006 import java.util.Set; 007 import java.util.Vector; 008 009 import net.sf.cpsolver.coursett.Constants; 010 import net.sf.cpsolver.coursett.model.Lecture; 011 import net.sf.cpsolver.coursett.model.Placement; 012 import net.sf.cpsolver.coursett.model.TimeLocation; 013 import net.sf.cpsolver.coursett.model.TimetableModel; 014 import net.sf.cpsolver.ifs.model.Constraint; 015 import net.sf.cpsolver.ifs.model.Value; 016 import net.sf.cpsolver.ifs.util.FastVector; 017 018 /** 019 * Instructor constraint. 020 * <br> 021 * Classes with this instructor can not overlap in time. Also, for back-to-back classes, 022 * there is the following reasoning:<ul> 023 * <li>if the distance is equal or below {@link TimetableModel#getInstructorNoPreferenceLimit()} .. no preference 024 * <li>if the distance is above {@link TimetableModel#getInstructorNoPreferenceLimit()} and below {@link TimetableModel#getInstructorDiscouragedLimit()} .. constraint is discouraged (soft, preference = 1) 025 * <li>if the distance is above {@link TimetableModel#getInstructorDiscouragedLimit()} and below {@link TimetableModel#getInstructorProhibitedLimit()} .. constraint is strongly discouraged (soft, preference = 2) 026 * <li>if the distance is above {@link TimetableModel#getInstructorProhibitedLimit()} .. constraint is prohibited (hard) 027 * </ul> 028 * <br> 029 * When {@link InstructorConstraint#isIgnoreDistances()} is set to true, the constraint never prohibits two back-to-back classes (but it still tries to minimize the above back-to-back preferences). 030 * 031 * @version 032 * CourseTT 1.1 (University Course Timetabling)<br> 033 * Copyright (C) 2006 Tomáš Müller<br> 034 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 035 * Lazenska 391, 76314 Zlin, Czech Republic<br> 036 * <br> 037 * This library is free software; you can redistribute it and/or 038 * modify it under the terms of the GNU Lesser General Public 039 * License as published by the Free Software Foundation; either 040 * version 2.1 of the License, or (at your option) any later version. 041 * <br><br> 042 * This library is distributed in the hope that it will be useful, 043 * but WITHOUT ANY WARRANTY; without even the implied warranty of 044 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 045 * Lesser General Public License for more details. 046 * <br><br> 047 * You should have received a copy of the GNU Lesser General Public 048 * License along with this library; if not, write to the Free Software 049 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 050 */ 051 052 public class InstructorConstraint extends Constraint { 053 054 public int iPreference = 0; 055 056 /** table iResource[slot] = lecture using this resource placed in the given time slot (null if empty) */ 057 protected Vector[] iResource; 058 private Long iResourceId; 059 private String iName; 060 private String iPuid; 061 private Vector[] iAvailable = null; 062 private boolean iIgnoreDistances = false; 063 private Long iType = null; 064 065 066 /** Constructor 067 * @param id instructor id 068 * @param name instructor name 069 */ 070 public InstructorConstraint(Long id, String puid, String name, boolean ignDist) { 071 iResourceId = id; 072 iName = name; 073 iPuid = puid; 074 iIgnoreDistances = ignDist; 075 iResource = new Vector[Constants.SLOTS_PER_DAY * Constants.DAY_CODES.length]; 076 for (int i=0;i<iResource.length;i++) 077 iResource[i]=new FastVector(3); 078 } 079 080 public Vector getPlacements(int slot, Placement placement) { 081 return getPlacements(slot, placement.getTimeLocation().getWeekCode()); 082 } 083 084 public Vector getPlacements(int slot, BitSet weekCode) { 085 Vector placements = new FastVector(iResource[slot].size()); 086 for (Enumeration e=iResource[slot].elements();e.hasMoreElements();) { 087 Placement p = (Placement)e.nextElement(); 088 if (p.getTimeLocation().shareWeeks(weekCode)) 089 placements.addElement(p); 090 } 091 return placements; 092 } 093 094 public Placement getPlacement(int slot, int day) { 095 for (Enumeration e=iResource[slot].elements();e.hasMoreElements();) { 096 Placement p = (Placement)e.nextElement(); 097 if (p.getTimeLocation().hasDay(day)) 098 return p; 099 } 100 return null; 101 } 102 103 public void setNotAvailable(Placement placement) { 104 if (iAvailable==null) { 105 iAvailable = new Vector[Constants.SLOTS_PER_DAY * Constants.DAY_CODES.length]; 106 for (int i=0;i<iResource.length;i++) 107 iAvailable[i]=null; 108 } 109 for (Enumeration e=placement.getTimeLocation().getSlots();e.hasMoreElements();) { 110 int slot = ((Integer)e.nextElement()).intValue(); 111 if (iAvailable[slot]==null) 112 iAvailable[slot] = new Vector(1); 113 iAvailable[slot].addElement(placement); 114 } 115 } 116 public boolean isAvailable(int slot) { 117 if (iAvailable==null) return true; 118 return (iAvailable[slot]==null || iAvailable[slot].isEmpty()); 119 } 120 public boolean isAvailable(Lecture lecture, TimeLocation time) { 121 if (iAvailable==null) return true; 122 for (Enumeration e=time.getSlots();e.hasMoreElements();) { 123 int slot = ((Integer)e.nextElement()).intValue(); 124 if (iAvailable[slot]!=null) { 125 for (Enumeration f=iAvailable[slot].elements();f.hasMoreElements();) { 126 Placement p = (Placement)f.nextElement(); 127 if (lecture.canShareRoom((Lecture)p.variable())) continue; 128 if (time.shareWeeks(p.getTimeLocation())) return false; 129 } 130 } 131 } 132 return true; 133 } 134 public boolean isAvailable(Lecture lecture, Placement placement) { 135 if (iAvailable==null) return true; 136 for (Enumeration e=placement.getTimeLocation().getSlots();e.hasMoreElements();) { 137 int slot = ((Integer)e.nextElement()).intValue(); 138 if (iAvailable[slot]!=null) { 139 for (Enumeration f=iAvailable[slot].elements();f.hasMoreElements();) { 140 Placement p = (Placement)f.nextElement(); 141 if (lecture.canShareRoom((Lecture)p.variable()) && placement.sameRooms(p)) continue; 142 if (placement.getTimeLocation().shareWeeks(p.getTimeLocation())) return false; 143 } 144 } 145 } 146 if (!iIgnoreDistances) { 147 TimetableModel m = (TimetableModel)getModel(); 148 for (Enumeration e=placement.getTimeLocation().getStartSlots();e.hasMoreElements();) { 149 int startSlot = ((Integer)e.nextElement()).intValue(); 150 int prevSlot = startSlot-1; 151 if (prevSlot>=0 && (prevSlot/Constants.SLOTS_PER_DAY) == (startSlot/Constants.SLOTS_PER_DAY)) { 152 if (iAvailable[prevSlot]!=null) { 153 for (Enumeration f=iAvailable[prevSlot].elements();f.hasMoreElements();) { 154 Placement p = (Placement)f.nextElement(); 155 if (lecture.canShareRoom((Lecture)p.variable()) && placement.sameRooms(p)) continue; 156 if (placement.getTimeLocation().shareWeeks(p.getTimeLocation()) && Placement.getDistance(p,placement)>m.getInstructorProhibitedLimit()) 157 return false; 158 } 159 } 160 } 161 int nextSlot = startSlot+placement.getTimeLocation().getLength(); 162 if ((nextSlot/Constants.SLOTS_PER_DAY) == (startSlot/Constants.SLOTS_PER_DAY)) { 163 if (iAvailable[nextSlot]!=null) { 164 for (Enumeration f=iAvailable[nextSlot].elements();f.hasMoreElements();) { 165 Placement p = (Placement)f.nextElement(); 166 if (lecture.canShareRoom((Lecture)p.variable()) && placement.sameRooms(p)) continue; 167 if (placement.getTimeLocation().shareWeeks(p.getTimeLocation()) && Placement.getDistance(p,placement)>m.getInstructorProhibitedLimit()) 168 return false; 169 } 170 } 171 } 172 } 173 } 174 return true; 175 } 176 public Vector[] getAvailableArray() { 177 return iAvailable; 178 } 179 180 /** Back-to-back preference of two placements (3 means prohibited) */ 181 public int getDistancePreference(Placement p1, Placement p2) { 182 if (!p1.getTimeLocation().shareDays(p2.getTimeLocation())) return 0; 183 if (!p1.getTimeLocation().shareWeeks(p2.getTimeLocation())) return 0; 184 int s1 = p1.getTimeLocation().getStartSlot() % Constants.SLOTS_PER_DAY; 185 int s2 = p2.getTimeLocation().getStartSlot() % Constants.SLOTS_PER_DAY; 186 if (s1+p1.getTimeLocation().getLength()!=s2 && s2+p2.getTimeLocation().getLength()!=s1) return 0; 187 double distance = Placement.getDistance(p1,p2); 188 TimetableModel m = (TimetableModel)p1.variable().getModel(); 189 if (distance<=m.getInstructorNoPreferenceLimit()) return Constants.sPreferenceLevelNeutral; 190 if (distance<=m.getInstructorDiscouragedLimit()) return Constants.sPreferenceLevelDiscouraged; 191 if (iIgnoreDistances || distance<=m.getInstructorProhibitedLimit()) return Constants.sPreferenceLevelStronglyDiscouraged; 192 return Constants.sPreferenceLevelProhibited; 193 } 194 195 /** Resource id */ 196 public Long getResourceId() { return iResourceId; } 197 /** Resource name */ 198 public String getName() { return iName; } 199 200 public void computeConflicts(Value value, Set conflicts) { 201 Lecture lecture = (Lecture) value.variable(); 202 Placement placement = (Placement) value; 203 BitSet weekCode = placement.getTimeLocation().getWeekCode(); 204 205 for (Enumeration e=placement.getTimeLocation().getSlots();e.hasMoreElements();) { 206 int slot = ((Integer)e.nextElement()).intValue(); 207 for (Enumeration f=iResource[slot].elements();f.hasMoreElements();) { 208 Placement p = (Placement)f.nextElement(); 209 if (!p.equals(lecture.getAssignment()) && p.getTimeLocation().shareWeeks(weekCode)) { 210 if (p.canShareRooms(placement) && p.sameRooms(placement)) continue; 211 conflicts.add(p); 212 } 213 } 214 } 215 if (!iIgnoreDistances) { 216 TimetableModel m = (TimetableModel)getModel(); 217 for (Enumeration e=placement.getTimeLocation().getStartSlots();e.hasMoreElements();) { 218 int startSlot = ((Integer)e.nextElement()).intValue(); 219 int prevSlot = startSlot-1; 220 if (prevSlot>=0 && (prevSlot/Constants.SLOTS_PER_DAY) == (startSlot/Constants.SLOTS_PER_DAY)) { 221 Vector conf = getPlacements(prevSlot,placement); 222 for (Enumeration i=conf.elements();i.hasMoreElements();) { 223 Placement c = (Placement)i.nextElement(); 224 if (lecture.equals(c.variable())) continue; 225 if (Placement.getDistance(placement,c)>m.getInstructorProhibitedLimit()) { 226 if (c.canShareRooms(placement) && c.sameRooms(placement)) continue; 227 conflicts.add(c); 228 } 229 } 230 } 231 int nextSlot = startSlot+placement.getTimeLocation().getLength(); 232 if ((nextSlot/Constants.SLOTS_PER_DAY) == (startSlot/Constants.SLOTS_PER_DAY)) { 233 Vector conf = getPlacements(nextSlot,placement); 234 for (Enumeration i=conf.elements();i.hasMoreElements();) { 235 Placement c = (Placement)i.nextElement(); 236 if (lecture.equals(c.variable())) continue; 237 if (Placement.getDistance(placement,c)>m.getInstructorProhibitedLimit()) { 238 if (c.canShareRooms(placement) && c.sameRooms(placement)) continue; 239 conflicts.add(c); 240 } 241 } 242 } 243 } 244 } 245 } 246 247 public boolean inConflict(Value value) { 248 Lecture lecture = (Lecture) value.variable(); 249 Placement placement = (Placement) value; 250 BitSet weekCode = placement.getTimeLocation().getWeekCode(); 251 for (Enumeration e=placement.getTimeLocation().getSlots();e.hasMoreElements();) { 252 int slot = ((Integer)e.nextElement()).intValue(); 253 for (Enumeration f=iResource[slot].elements();f.hasMoreElements();) { 254 Placement p = (Placement)f.nextElement(); 255 if (!p.equals(lecture.getAssignment()) && p.getTimeLocation().shareWeeks(weekCode)) { 256 if (p.canShareRooms(placement) && p.sameRooms(placement)) continue; 257 return true; 258 } 259 } 260 } 261 if (!iIgnoreDistances) { 262 TimetableModel m = (TimetableModel)getModel(); 263 for (Enumeration e=placement.getTimeLocation().getStartSlots();e.hasMoreElements();) { 264 int startSlot = ((Integer)e.nextElement()).intValue(); 265 int prevSlot = startSlot-1; 266 if (prevSlot>=0 && (prevSlot/Constants.SLOTS_PER_DAY) == (startSlot/Constants.SLOTS_PER_DAY)) { 267 Vector conf = getPlacements(prevSlot,placement); 268 for (Enumeration i=conf.elements();i.hasMoreElements();) { 269 Placement c = (Placement)i.nextElement(); 270 if (lecture.equals(c.variable())) continue; 271 if (Placement.getDistance(placement,c)>m.getInstructorProhibitedLimit()) { 272 if (c.canShareRooms(placement) && c.sameRooms(placement)) continue; 273 return true; 274 } 275 } 276 } 277 int nextSlot = startSlot+placement.getTimeLocation().getLength(); 278 if ((nextSlot/Constants.SLOTS_PER_DAY) == (startSlot/Constants.SLOTS_PER_DAY)) { 279 Vector conf = getPlacements(nextSlot,placement); 280 for (Enumeration i=conf.elements();i.hasMoreElements();) { 281 Placement c = (Placement)i.nextElement(); 282 if (lecture.equals(c.variable())) continue; 283 if (Placement.getDistance(placement,c)>m.getInstructorProhibitedLimit()) { 284 if (c.canShareRooms(placement) && c.sameRooms(placement)) continue; 285 return true; 286 } 287 } 288 } 289 } 290 } 291 return false; 292 } 293 294 public boolean isConsistent(Value value1, Value value2) { 295 Placement p1 = (Placement) value1; 296 Placement p2 = (Placement) value2; 297 if (p1.canShareRooms(p2) && p1.sameRooms(p2)) return true; 298 if (p1.getTimeLocation().hasIntersection(p2.getTimeLocation())) return false; 299 return getDistancePreference(p1,p2)!=Constants.sPreferenceLevelProhibited; 300 } 301 302 public void assigned(long iteration, Value value) { 303 super.assigned(iteration, value); 304 Placement placement = (Placement) value; 305 iPreference += getPreference(value); 306 for (Enumeration e=placement.getTimeLocation().getSlots();e.hasMoreElements();) { 307 int slot = ((Integer)e.nextElement()).intValue(); 308 iResource[slot].addElement(placement); 309 } 310 } 311 312 public void unassigned(long iteration, Value value) { 313 super.unassigned(iteration, value); 314 Placement placement = (Placement) value; 315 iPreference -= getPreference(value); 316 for (Enumeration e=placement.getTimeLocation().getSlots();e.hasMoreElements();) { 317 int slot = ((Integer)e.nextElement()).intValue(); 318 iResource[slot].removeElement(placement); 319 } 320 } 321 322 /** Lookup table getResource()[slot] -> lecture using this resource placed in the given time slot (null if empty) */ 323 public Vector getResource(int slot) { return iResource[slot]; } 324 public Placement[] getResourceOfWeek(int startDay) { 325 Placement[] ret = new Placement[iResource.length]; 326 for (int i=0;i<iResource.length;i++) { 327 ret[i]=getPlacement(i,startDay+(i/Constants.SLOTS_PER_DAY)); 328 } 329 return ret; 330 } 331 332 /** Number of useless slots for this resource */ 333 public int countUselessSlots() { 334 int ret = 0; 335 for (int d=0;d<Constants.DAY_CODES.length;d++) { 336 for (int s=1;s<Constants.SLOTS_PER_DAY-1;s++) { 337 int slot = d*Constants.SLOTS_PER_DAY+s; 338 if (iResource[slot-1]!=null && iResource[slot]==null && iResource[slot+1]!=null) 339 ret++; 340 } 341 } 342 return ret; 343 } 344 345 /** Resource usage usage */ 346 protected void printUsage(StringBuffer sb) { 347 for (int slot=0;slot<iResource.length;slot++) { 348 for (Enumeration e=iResource[slot].elements();e.hasMoreElements();) { 349 Placement p = (Placement)e.nextElement(); 350 int day = slot / Constants.SLOTS_PER_DAY; 351 int time = slot * Constants.SLOT_LENGTH_MIN + Constants.FIRST_SLOT_TIME_MIN; 352 int h = time / 60; 353 int m = time % 60; 354 String d = Constants.DAY_NAMES_SHORT[day]; 355 int slots = p.getTimeLocation().getLength(); 356 time += (30*slots); 357 int h2 = time / 60; 358 int m2 = time % 60; 359 sb.append(sb.length()==0?"":",\n ").append("["+d+(h>12?h-12:h)+":"+(m<10?"0":"")+m+(h>=12?"p":"a")+"-"+(h2>12?h2-12:h2)+":"+(m2<10?"0":"")+m2+(h2>=12?"p":"a")+"]=").append(p.variable().getName()); 360 slot+=slots-1; 361 //sb.append(sb.length()==0?"":", ").append("s"+(slot+1)+"=").append(((Lecture)getResource()[slot]).getName()); 362 } 363 } 364 } 365 366 public String toString() { 367 return "Instructor "+getName(); 368 } 369 370 /** Back-to-back preference of the given placement */ 371 public int getPreference(Value value) { 372 Lecture lecture = (Lecture)value.variable(); 373 Placement placement = (Placement)value; 374 int pref = 0; 375 TimetableModel m = (TimetableModel)getModel(); 376 HashSet used = new HashSet(); 377 for (Enumeration e=placement.getTimeLocation().getStartSlots();e.hasMoreElements();) { 378 int startSlot = ((Integer)e.nextElement()).intValue(); 379 int prevSlot = startSlot-1; 380 if (prevSlot>=0 && (prevSlot/Constants.SLOTS_PER_DAY) == (startSlot/Constants.SLOTS_PER_DAY)) { 381 Vector conf = getPlacements(prevSlot,placement); 382 for (Enumeration i=conf.elements();i.hasMoreElements();) { 383 Placement c = (Placement)i.nextElement(); 384 if (lecture.equals(c.variable())) continue; 385 if (!used.add(c)) continue; 386 double dist = Placement.getDistance(placement,c); 387 if (dist>m.getInstructorNoPreferenceLimit() && dist<=m.getInstructorDiscouragedLimit()) pref+=Constants.sPreferenceLevelDiscouraged; 388 if (dist>m.getInstructorDiscouragedLimit() && (dist<=m.getInstructorProhibitedLimit() || iIgnoreDistances)) pref+=Constants.sPreferenceLevelStronglyDiscouraged; 389 if (!iIgnoreDistances && dist>m.getInstructorProhibitedLimit()) pref += Constants.sPreferenceLevelProhibited; 390 } 391 } 392 int nextSlot = startSlot+placement.getTimeLocation().getLength(); 393 if ((nextSlot/Constants.SLOTS_PER_DAY) == (startSlot/Constants.SLOTS_PER_DAY)) { 394 Vector conf = getPlacements(nextSlot,placement); 395 for (Enumeration i=conf.elements();i.hasMoreElements();) { 396 Placement c = (Placement)i.nextElement(); 397 if (lecture.equals(c.variable())) continue; 398 if (!used.add(c)) continue; 399 double dist = Placement.getDistance(placement,c); 400 if (dist>m.getInstructorNoPreferenceLimit() && dist<=m.getInstructorDiscouragedLimit()) pref+=Constants.sPreferenceLevelDiscouraged; 401 if (dist>m.getInstructorDiscouragedLimit() && (dist<=m.getInstructorProhibitedLimit() || iIgnoreDistances)) pref+=Constants.sPreferenceLevelStronglyDiscouraged; 402 if (!iIgnoreDistances && dist>m.getInstructorProhibitedLimit()) pref = Constants.sPreferenceLevelProhibited; 403 } 404 } 405 } 406 return pref; 407 } 408 409 public int getPreferenceCombination(Value value) { 410 Lecture lecture = (Lecture)value.variable(); 411 Placement placement = (Placement)value; 412 int pref = 0; 413 HashSet used = new HashSet(); 414 TimetableModel m = (TimetableModel)getModel(); 415 for (Enumeration e=placement.getTimeLocation().getStartSlots();e.hasMoreElements();) { 416 int startSlot = ((Integer)e.nextElement()).intValue(); 417 int prevSlot = startSlot-1; 418 if (prevSlot>=0 && (prevSlot/Constants.SLOTS_PER_DAY) == (startSlot/Constants.SLOTS_PER_DAY)) { 419 Vector conf = getPlacements(prevSlot,placement); 420 for (Enumeration i=conf.elements();i.hasMoreElements();) { 421 Placement c = (Placement)i.nextElement(); 422 if (lecture.equals(c.variable())) continue; 423 if (!used.add(c)) continue; 424 double dist = Placement.getDistance(placement,c); 425 if (dist>m.getInstructorNoPreferenceLimit() && dist<=m.getInstructorDiscouragedLimit()) pref = Math.max(pref,Constants.sPreferenceLevelDiscouraged); 426 if (dist>m.getInstructorDiscouragedLimit() && (dist<=m.getInstructorProhibitedLimit() || iIgnoreDistances)) pref = Math.max(pref,Constants.sPreferenceLevelStronglyDiscouraged); 427 if (!iIgnoreDistances && dist>m.getInstructorProhibitedLimit()) pref = Math.max(pref,Constants.sPreferenceLevelProhibited); 428 } 429 } 430 int nextSlot = startSlot+placement.getTimeLocation().getLength(); 431 if ((nextSlot/Constants.SLOTS_PER_DAY) == (startSlot/Constants.SLOTS_PER_DAY)) { 432 Vector conf = getPlacements(nextSlot,placement); 433 for (Enumeration i=conf.elements();i.hasMoreElements();) { 434 Placement c = (Placement)i.nextElement(); 435 if (lecture.equals(c.variable())) continue; 436 if (!used.add(c)) continue; 437 double dist = Placement.getDistance(placement,c); 438 if (dist>m.getInstructorNoPreferenceLimit() && dist<=m.getInstructorDiscouragedLimit()) pref = Math.max(pref,Constants.sPreferenceLevelDiscouraged); 439 if (dist>m.getInstructorDiscouragedLimit() && (dist<=m.getInstructorProhibitedLimit() || iIgnoreDistances)) pref = Math.max(pref,Constants.sPreferenceLevelStronglyDiscouraged); 440 if (!iIgnoreDistances && dist>m.getInstructorProhibitedLimit()) pref = Math.max(pref,Constants.sPreferenceLevelProhibited); 441 } 442 } 443 } 444 return pref; 445 } 446 447 /** Overall back-to-back preference of this instructor */ 448 public int getPreference() { 449 /* 450 if (iPreference!=countPreference()) { 451 System.err.println("InstructorConstraint.getPreference() is not working properly"); 452 } 453 */ 454 return iPreference; 455 } 456 public int countPreference() { 457 int pref = 0; 458 HashSet used = new HashSet(); 459 TimetableModel m = (TimetableModel)getModel(); 460 for (int slot=1;slot<iResource.length;slot++) { 461 if ((slot%Constants.SLOTS_PER_DAY)==0) continue; 462 for (Enumeration e=iResource[slot].elements();e.hasMoreElements();) { 463 Placement placement = (Placement)e.nextElement(); 464 Vector prevPlacements = getPlacements(slot-1,placement); 465 for (Enumeration i=prevPlacements.elements();i.hasMoreElements();) { 466 Placement prevPlacement = (Placement)i.nextElement(); 467 if (!used.add(prevPlacement)) continue; 468 double dist = Placement.getDistance(prevPlacement,placement); 469 if (dist>m.getInstructorNoPreferenceLimit() && dist<=m.getInstructorDiscouragedLimit()) pref+=Constants.sPreferenceLevelDiscouraged; 470 if (dist>m.getInstructorDiscouragedLimit()) pref+=Constants.sPreferenceLevelStronglyDiscouraged; 471 } 472 } 473 } 474 return pref; 475 } 476 477 /** Worst back-to-back preference of this instructor */ 478 public int getWorstPreference() { 479 return Constants.sPreferenceLevelStronglyDiscouraged*(variables().size()-1); 480 } 481 482 public String getPuid() { 483 return iPuid; 484 } 485 486 public boolean isIgnoreDistances() { 487 return iIgnoreDistances; 488 } 489 490 public Long getType() { return iType; } 491 public void setType(Long type) { iType = type; } 492 }