001 package net.sf.cpsolver.coursett.constraint; 002 003 import java.util.Enumeration; 004 import java.util.HashSet; 005 import java.util.Hashtable; 006 import java.util.Set; 007 import java.util.Vector; 008 009 import org.apache.log4j.Logger; 010 011 012 import net.sf.cpsolver.coursett.Constants; 013 import net.sf.cpsolver.coursett.model.Lecture; 014 import net.sf.cpsolver.coursett.model.Placement; 015 import net.sf.cpsolver.coursett.model.TimeLocation; 016 import net.sf.cpsolver.coursett.model.TimetableModel; 017 import net.sf.cpsolver.ifs.model.Constraint; 018 import net.sf.cpsolver.ifs.model.Value; 019 import net.sf.cpsolver.ifs.model.Variable; 020 import net.sf.cpsolver.ifs.util.FastVector; 021 022 /** 023 * Group constraint. 024 * <br> 025 * This constraint expresses relations between several classes, e.g., that two sections of the same lecture can not 026 * be taught at the same time, or that some classes have to be taught one immediately after another. It can be either 027 * hard or soft. 028 * <br><br> 029 * Following constraints are now supported: 030 * <table border='1'><tr><th>Constraint</th><th>Comment</th></tr> 031 * <tr><td>SAME_TIME</td><td>Same time: given classes have to be taught in the same hours. If the classes are of different length, the smaller one cannot start before the longer one and it cannot end after the longer one.</td></tr> 032 * <tr><td>SAME_DAYS</td><td>Same days: given classes have to be taught in the same day. If the classes are of different time patterns, the days of one class have to form a subset of the days of the other class.</td></tr> 033 * <tr><td>BTB</td><td>Back-to-back constraint: given classes have to be taught in the same room and they have to follow one strictly after another.</td></tr> 034 * <tr><td>BTB_TIME</td><td>Back-to-back constraint: given classes have to follow one strictly after another, but they can be taught in different rooms.</td></tr> 035 * <tr><td>DIFF_TIME</td><td>Different time: given classes cannot overlap in time.</td></tr> 036 * <tr><td>NHB(1), NHB(1.5), NHB(2), ... NHB(8)</td><td>Number of hours between: between the given classes, the exact number of hours have to be kept.</td></tr> 037 * <tr><td>SAME_START</td><td>Same starting hour: given classes have to start in the same hour.</td></tr> 038 * <tr><td>SAME_ROOM</td><td>Same room: given classes have to be placed in the same room.</td></tr> 039 * <tr><td>NHB_GTE(1)</td><td>Greater than or equal to 1 hour between: between the given classes, the number of hours have to be one or more.</td></tr> 040 * <tr><td>NHB_LT(6)</td><td>Less than 6 hours between: between the given classes, the number of hours have to be less than six.</td></tr> 041 * </table> 042 * 043 * @version 044 * CourseTT 1.1 (University Course Timetabling)<br> 045 * Copyright (C) 2006 Tomáš Müller<br> 046 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 047 * Lazenska 391, 76314 Zlin, Czech Republic<br> 048 * <br> 049 * This library is free software; you can redistribute it and/or 050 * modify it under the terms of the GNU Lesser General Public 051 * License as published by the Free Software Foundation; either 052 * version 2.1 of the License, or (at your option) any later version. 053 * <br><br> 054 * This library is distributed in the hope that it will be useful, 055 * but WITHOUT ANY WARRANTY; without even the implied warranty of 056 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 057 * Lesser General Public License for more details. 058 * <br><br> 059 * You should have received a copy of the GNU Lesser General Public 060 * License along with this library; if not, write to the Free Software 061 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 062 */ 063 064 public class GroupConstraint extends Constraint { 065 private static Logger sLogger = Logger.getLogger(GroupConstraint.class); 066 private Long iId; 067 private int iPreference; 068 private String iType; 069 private boolean iIsRequired; 070 private boolean iIsProhibited; 071 private int iLastPreference = 0; 072 073 /** Same time: given classes have to be taught in the same hours. If the classes are of different length, the smaller one cannot start before the longer one and it cannot end after the longer one.*/ 074 public static String TYPE_SAME_TIME = "SAME_TIME"; 075 /** Same days: given classes have to be taught in the same day. If the classes are of different time patterns, the days of one class have to form a subset of the days of the other class. */ 076 public static String TYPE_SAME_DAYS = "SAME_DAYS"; 077 /** Back-to-back constraint: given classes have to be taught in the same room and they have to follow one strictly after another. */ 078 public static String TYPE_BTB = "BTB"; 079 /** Back-to-back constraint: given classes have to follow one strictly after another, but they can be taught in different rooms. */ 080 public static String TYPE_BTB_TIME = "BTB_TIME"; 081 /** Different time: given classes cannot overlap in time. */ 082 public static String TYPE_DIFF_TIME = "DIFF_TIME"; 083 /** One hour between: between the given classes, the exact number of hours have to be kept.*/ 084 public static String TYPE_NHB_1 = "NHB(1)"; 085 /** Two hours between: between the given classes, the exact number of hours have to be kept.*/ 086 public static String TYPE_NHB_2 = "NHB(2)"; 087 /** Three hours between: between the given classes, the exact number of hours have to be kept.*/ 088 public static String TYPE_NHB_3 = "NHB(3)"; 089 /** Four hours between: between the given classes, the exact number of hours have to be kept.*/ 090 public static String TYPE_NHB_4 = "NHB(4)"; 091 /** Five hours between: between the given classes, the exact number of hours have to be kept.*/ 092 public static String TYPE_NHB_5 = "NHB(5)"; 093 /** Six hours between: between the given classes, the exact number of hours have to be kept.*/ 094 public static String TYPE_NHB_6 = "NHB(6)"; 095 /** Seven hours between: between the given classes, the exact number of hours have to be kept.*/ 096 public static String TYPE_NHB_7 = "NHB(7)"; 097 /** Eight hours between: between the given classes, the exact number of hours have to be kept.*/ 098 public static String TYPE_NHB_8 = "NHB(8)"; 099 /** Same room: given classes have to placed in the same room.*/ 100 public static String TYPE_SAME_START = "SAME_START"; 101 /** Same room: given classes have to placed in the same room.*/ 102 public static String TYPE_SAME_ROOM = "SAME_ROOM"; 103 /** Greater than or equal to 1 hour between: between the given classes, the number of hours have to be one or more.*/ 104 public static String TYPE_NHB_GTE_1 = "NHB_GTE(1)"; 105 /** Less than 6 hours between: between the given classes, the number of hours have to be less than six. */ 106 public static String TYPE_NHB_LT_6 = "NHB_LT(6)"; 107 /** One and half hour between: between the given classes, the exact number of hours have to be kept.*/ 108 public static String TYPE_NHB_1_5 = "NHB(1.5)"; 109 /** Four and half hours between: between the given classes, the exact number of hours have to be kept.*/ 110 public static String TYPE_NHB_4_5 = "NHB(4.5)"; 111 public static String TYPE_SAME_STUDENTS = "SAME_STUDENTS"; 112 public static String TYPE_SAME_INSTR = "SAME_INSTR"; 113 public static String TYPE_CAN_SHARE_ROOM = "CAN_SHARE_ROOM"; 114 public static String TYPE_PRECEDENCE = "PRECEDENCE"; 115 public static String TYPE_BTB_DAY = "BTB_DAY"; 116 public static String TYPE_MEET_WITH = "MEET_WITH"; 117 public static String TYPE_NDB_GT_1 = "NDB_GT_1"; 118 public static String TYPE_CH_NOTOVERLAP = "CH_NOTOVERLAP"; 119 public static String TYPE_FOLLOWING_DAY = "FOLLOWING_DAY"; 120 public static String TYPE_EVERY_OTHER_DAY = "EVERY_OTHER_DAY"; 121 122 123 public GroupConstraint() {} 124 125 public void addVariable(Variable variable) { 126 if (!variables().contains(variable)) super.addVariable(variable); 127 if (isChildrenNotOverlap(getType())) { 128 Lecture lecture = (Lecture)variable; 129 if (lecture.getChildrenSubpartIds()!=null) { 130 for (Enumeration e1=lecture.getChildrenSubpartIds();e1.hasMoreElements();) { 131 Long subpartId = (Long)e1.nextElement(); 132 for (Enumeration e2=lecture.getChildren(subpartId).elements();e2.hasMoreElements();) { 133 Lecture ch = (Lecture)e2.nextElement(); 134 if (!variables().contains(ch)) super.addVariable(ch); 135 } 136 } 137 } 138 } 139 } 140 141 public void removeVariable(Variable variable) { 142 if (variables().contains(variable)) super.removeVariable(variable); 143 if (isChildrenNotOverlap(getType())) { 144 Lecture lecture = (Lecture)variable; 145 if (lecture.getChildrenSubpartIds()!=null) { 146 for (Enumeration e1=lecture.getChildrenSubpartIds();e1.hasMoreElements();) { 147 Long subpartId = (Long)e1.nextElement(); 148 for (Enumeration e2=lecture.getChildren(subpartId).elements();e2.hasMoreElements();) { 149 Lecture ch = (Lecture)e2.nextElement(); 150 if (variables().contains(ch)) super.removeVariable(ch); 151 } 152 } 153 } 154 } 155 } 156 157 /** Constructor 158 * @param id constraint id 159 * @param type constraString type (e.g, "SAME_TIME") 160 * @param preference time preferent ("R" for required, "P" for prohibited, "-2", "-1", "1", "2" for soft preference) 161 */ 162 public GroupConstraint(Long id, String type, String preference) { 163 iId=id; 164 iType=type; 165 iIsRequired=preference.equals(Constants.sPreferenceRequired); 166 iIsProhibited=preference.equals(Constants.sPreferenceProhibited); 167 iPreference=Constants.preference2preferenceLevel(preference); 168 } 169 170 /** Constraint id */ 171 public Long getConstraintId() { return iId; } 172 public long getId() { return (iId==null?-1:iId.longValue()); } 173 /** ConstraString type (e.g, {@link GroupConstraint#TYPE_SAME_TIME} */ 174 public String getType() { return iType; } 175 public void setType(String type) { iType = type; } 176 /** Is constraint required */ 177 public boolean isRequired() { return iIsRequired; } 178 /** Is constraint prohibited */ 179 public boolean isProhibited() { return iIsProhibited; } 180 /** Prolog reference: "R" for required, "P" for prohibited", "-2",.."2" for preference */ 181 public String getPrologPreference() { return Constants.preferenceLevel2preference(iPreference); } 182 183 184 public boolean isConsistent(Value value1, Value value2) { 185 if (!isHard()) return true; 186 if (!isSatisfiedPair((Lecture)value1.variable(), (Placement)value1, (Lecture)value2.variable(), (Placement)value2)) 187 return false; 188 if (isBackToBack(getType())) { 189 Hashtable assignments = new Hashtable(); 190 assignments.put(value1.variable(), value1); 191 assignments.put(value2.variable(), value2); 192 if (!isSatisfiedSeq(assignments, false, null)) 193 return false; 194 } 195 return true; 196 } 197 198 public void computeConflicts(Value value, Set conflicts) { 199 if (!isHard()) return; 200 for (Enumeration e=variables().elements();e.hasMoreElements();) { 201 Variable v = (Variable)e.nextElement(); 202 if (v.equals(value.variable())) continue; //ignore this variable 203 if (v.getAssignment()==null) continue; //there is an unassigned variable -- great, still a chance to get violated 204 if (!isSatisfiedPair((Lecture)v, (Placement)v.getAssignment(), (Lecture)value.variable(), (Placement)value)) 205 conflicts.add(v.getAssignment()); 206 } 207 Hashtable assignments = new Hashtable(); 208 assignments.put(value.variable(), value); 209 if (!isSatisfiedSeq(assignments, true, conflicts)) 210 conflicts.add(value); 211 } 212 213 public boolean inConflict(Value value) { 214 if (!isHard()) return false; 215 for (Enumeration e=variables().elements();e.hasMoreElements();) { 216 Variable v = (Variable)e.nextElement(); 217 if (v.equals(value.variable())) continue; //ignore this variable 218 if (v.getAssignment()==null) continue; //there is an unassigned variable -- great, still a chance to get violated 219 if (!isSatisfiedPair((Lecture)v, (Placement)v.getAssignment(), (Lecture)value.variable(), (Placement)value)) 220 return true; 221 } 222 Hashtable assignments = new Hashtable(); 223 assignments.put(value.variable(), value); 224 return isSatisfiedSeq(assignments, true, null); 225 } 226 227 /** Constraint preference (0 if prohibited or reqired) */ 228 public int getPreference() { 229 return iPreference; 230 } 231 232 /** Current constraint preference (0 if prohibited or reqired, depends on current satisfaction of the constraint) */ 233 public int getCurrentPreference() { 234 if (isHard()) return 0; //no preference 235 if (countAssignedVariables()<2) return 0; 236 if (iPreference<0) { //preference version (violated -> 0, satisfied -> preference) 237 for (Enumeration e1=variables().elements();e1.hasMoreElements();) { 238 Variable v1 = (Variable)e1.nextElement(); 239 if (v1.getAssignment()==null) continue; 240 for (Enumeration e2=variables().elements();e2.hasMoreElements();) { 241 Variable v2 = (Variable)e2.nextElement(); 242 if (v2.getAssignment()==null) continue; 243 if (v1.equals(v2)) continue; 244 if (!isSatisfiedPair((Lecture)v1, (Placement)v1.getAssignment(), (Lecture)v2, (Placement)v2.getAssignment())) 245 return 0; 246 } 247 } 248 if (!isSatisfiedSeq(null, true, null)) 249 return 0; 250 return iPreference; 251 } else { //discouraged version (violated -> prefernce, satisfied -> 0) 252 for (Enumeration e1=variables().elements();e1.hasMoreElements();) { 253 Variable v1 = (Variable)e1.nextElement(); 254 if (v1.getAssignment()==null) continue; 255 for (Enumeration e2=variables().elements();e2.hasMoreElements();) { 256 Variable v2 = (Variable)e2.nextElement(); 257 if (v2.getAssignment()==null) continue; 258 if (v1.equals(v2)) continue; 259 if (!isSatisfiedPair((Lecture)v1, (Placement)v1.getAssignment(), (Lecture)v2, (Placement)v2.getAssignment())) 260 return iPreference; 261 } 262 } 263 if (!isSatisfiedSeq(null, true, null)) 264 return iPreference; 265 return 0; 266 } 267 } 268 269 /** Current constraint preference (if given placement is assigned) */ 270 public int getCurrentPreference(Placement placement) { 271 //if (isHard()) return 0; //no preference 272 if (iPreference<0) { //preference version 273 for (Enumeration e1=variables().elements();e1.hasMoreElements();) { 274 Variable v1 = (Variable)e1.nextElement(); 275 if (v1.getAssignment()==null) continue; 276 if (v1.equals(placement.variable())) continue; 277 if (!isSatisfiedPair((Lecture)v1, (Placement)v1.getAssignment(), (Lecture)placement.variable(), placement)) 278 return 0; 279 } 280 if (isBackToBack(getType())) { 281 Hashtable assignment = new Hashtable(); 282 assignment.put(placement.variable(), placement); 283 if (!isSatisfiedSeq(assignment, true, null)) 284 return 0; 285 } 286 return iPreference; 287 } else { //discouraged version 288 for (Enumeration e1=variables().elements();e1.hasMoreElements();) { 289 Variable v1 = (Variable)e1.nextElement(); 290 if (v1.getAssignment()==null) continue; 291 if (v1.equals(placement.variable())) continue; 292 if (!isSatisfiedPair((Lecture)v1, (Placement)v1.getAssignment(), (Lecture)placement.variable(), placement)) 293 return iPreference; 294 } 295 if (isBackToBack(getType())) { 296 Hashtable assignment = new Hashtable(); 297 assignment.put(placement.variable(), placement); 298 if (!isSatisfiedSeq(assignment, true, null)) 299 return iPreference; 300 } 301 return 0; 302 } 303 } 304 305 public void unassigned(long iteration, Value value) { 306 super.unassigned(iteration, value); 307 if (iIsRequired || iIsProhibited) return; 308 ((TimetableModel)getModel()).getGlobalGroupConstraintPreferenceCounter().dec(iLastPreference); 309 iLastPreference = getCurrentPreference(); 310 ((TimetableModel)getModel()).getGlobalGroupConstraintPreferenceCounter().inc(iLastPreference); 311 } 312 313 public void assigned(long iteration, Value value) { 314 super.assigned(iteration, value); 315 if (iIsRequired || iIsProhibited) return; 316 ((TimetableModel)getModel()).getGlobalGroupConstraintPreferenceCounter().dec(iLastPreference); 317 iLastPreference = getCurrentPreference(); 318 ((TimetableModel)getModel()).getGlobalGroupConstraintPreferenceCounter().inc(iLastPreference); 319 } 320 321 public String toString() { 322 StringBuffer sb = new StringBuffer(); 323 sb.append(getName()); 324 sb.append(" between "); 325 for (Enumeration e=variables().elements();e.hasMoreElements();) { 326 Variable v = (Variable)e.nextElement(); 327 sb.append(v.getName()); 328 if (e.hasMoreElements()) sb.append(", "); 329 } 330 return sb.toString(); 331 } 332 333 public boolean isHard() {return iIsRequired || iIsProhibited; } 334 335 public String getName() { 336 return getName(iType); 337 } 338 339 public static String getName(String type) { 340 return type; 341 } 342 343 private static int getGapMin(String type) { 344 if (type.equals(TYPE_BTB)) return 0; 345 else if (type.equals(TYPE_BTB_TIME)) return 0; 346 else if (type.equals(TYPE_NHB_1)) return 6*2; 347 else if (type.equals(TYPE_NHB_1_5)) return 6*3; 348 else if (type.equals(TYPE_NHB_2)) return 6*4; 349 else if (type.equals(TYPE_NHB_3)) return 6*6; 350 else if (type.equals(TYPE_NHB_4)) return 6*8; 351 else if (type.equals(TYPE_NHB_4_5)) return 6*9; 352 else if (type.equals(TYPE_NHB_5)) return 6*10; 353 else if (type.equals(TYPE_NHB_6)) return 6*12; 354 else if (type.equals(TYPE_NHB_7)) return 6*14; 355 else if (type.equals(TYPE_NHB_8)) return 6*16; 356 else if (type.equals(TYPE_NHB_GTE_1)) return 6*1; 357 else if (type.equals(TYPE_NHB_LT_6)) return 0; 358 return -1; 359 } 360 361 private static int getGapMax(String type) { 362 if (type.equals(TYPE_BTB)) return 0; 363 else if (type.equals(TYPE_BTB_TIME)) return 0; 364 else if (type.equals(TYPE_NHB_1)) return 6*2; 365 else if (type.equals(TYPE_NHB_1_5)) return 6*3; 366 else if (type.equals(TYPE_NHB_2)) return 6*4; 367 else if (type.equals(TYPE_NHB_3)) return 6*6; 368 else if (type.equals(TYPE_NHB_4)) return 6*8; 369 else if (type.equals(TYPE_NHB_4_5)) return 6*9; 370 else if (type.equals(TYPE_NHB_5)) return 6*10; 371 else if (type.equals(TYPE_NHB_6)) return 6*12; 372 else if (type.equals(TYPE_NHB_7)) return 6*14; 373 else if (type.equals(TYPE_NHB_8)) return 6*16; 374 else if (type.equals(TYPE_NHB_GTE_1)) return Constants.SLOTS_PER_DAY; 375 else if (type.equals(TYPE_NHB_LT_6)) return 6*11; 376 return -1; 377 } 378 379 private static boolean isBackToBack(String type) { 380 if (type.equals(TYPE_BTB)) return true; 381 if (type.equals(TYPE_BTB_TIME)) return true; 382 if (type.equals(TYPE_NHB_1)) return true; 383 if (type.equals(TYPE_NHB_1_5)) return true; 384 if (type.equals(TYPE_NHB_2)) return true; 385 if (type.equals(TYPE_NHB_3)) return true; 386 if (type.equals(TYPE_NHB_4)) return true; 387 if (type.equals(TYPE_NHB_4_5)) return true; 388 if (type.equals(TYPE_NHB_5)) return true; 389 if (type.equals(TYPE_NHB_6)) return true; 390 if (type.equals(TYPE_NHB_7)) return true; 391 if (type.equals(TYPE_NHB_8)) return true; 392 if (type.equals(TYPE_NHB_GTE_1)) return true; 393 if (type.equals(TYPE_NHB_LT_6)) return true; 394 return false; 395 } 396 397 private static boolean isBackToBackTime(String type) { 398 if (type.equals(TYPE_BTB_TIME)) return true; 399 if (type.equals(TYPE_NHB_1)) return true; 400 if (type.equals(TYPE_NHB_1_5)) return true; 401 if (type.equals(TYPE_NHB_2)) return true; 402 if (type.equals(TYPE_NHB_3)) return true; 403 if (type.equals(TYPE_NHB_4)) return true; 404 if (type.equals(TYPE_NHB_4_5)) return true; 405 if (type.equals(TYPE_NHB_5)) return true; 406 if (type.equals(TYPE_NHB_6)) return true; 407 if (type.equals(TYPE_NHB_7)) return true; 408 if (type.equals(TYPE_NHB_8)) return true; 409 if (type.equals(TYPE_NHB_GTE_1)) return true; 410 if (type.equals(TYPE_NHB_LT_6)) return true; 411 return false; 412 } 413 414 private static boolean sameRoom(String type) { 415 if (type.equals(TYPE_SAME_ROOM)) return true; 416 if (type.equals(TYPE_MEET_WITH)) return true; 417 return false; 418 } 419 420 private static boolean isPrecedence(String type) { 421 if (type.equals(TYPE_PRECEDENCE)) return true; 422 return false; 423 } 424 425 private boolean isPrecedence(Placement p1, Placement p2, boolean firstGoesFirst) { 426 int ord1 = variables().indexOf(p1.variable()); 427 int ord2 = variables().indexOf(p2.variable()); 428 TimeLocation t1=null, t2=null; 429 if (ord1<ord2) { 430 if (firstGoesFirst) { 431 t1 = p1.getTimeLocation(); t2 = p2.getTimeLocation(); 432 } else { 433 t2 = p1.getTimeLocation(); t1 = p2.getTimeLocation(); 434 } 435 } else { 436 if (!firstGoesFirst) { 437 t1 = p1.getTimeLocation(); t2 = p2.getTimeLocation(); 438 } else { 439 t2 = p1.getTimeLocation(); t1 = p2.getTimeLocation(); 440 } 441 } 442 return t1.getStartSlots().nextInt()+t1.getLength()<=t2.getStartSlots().nextInt(); 443 } 444 445 private static boolean sameStudents(String type) { 446 if (type.equals(TYPE_SAME_STUDENTS)) return true; 447 return false; 448 } 449 450 private static boolean sameInstructor(String type) { 451 if (type.equals(TYPE_SAME_INSTR)) return true; 452 return false; 453 } 454 455 public static boolean canShareRooms(String type) { 456 if (type.equals(TYPE_CAN_SHARE_ROOM)) return true; 457 if (type.equals(TYPE_MEET_WITH)) return true; 458 return false; 459 } 460 461 private static boolean sameStartHour(String type) { 462 return (type.equals(TYPE_SAME_START)); 463 } 464 465 private static boolean sameHours(String type) { 466 return (type.equals(TYPE_SAME_TIME) || type.equals(TYPE_MEET_WITH)); 467 } 468 469 private static boolean sameDays(String type) { 470 if (type.equals(TYPE_SAME_DAYS) || type.equals(TYPE_MEET_WITH)) return true; 471 return false; 472 } 473 474 private static boolean notOverlap(String type) { 475 return (type.equals(TYPE_DIFF_TIME)); 476 } 477 478 private static boolean isBackToBackDay(String type) { 479 return (type.equals(TYPE_BTB_DAY)); 480 } 481 482 private static boolean isBackToBackDays(TimeLocation t1, TimeLocation t2) { 483 int f1 = -1, f2 = -1, e1 = -1, e2 = -1; 484 for (int i=0;i<Constants.DAY_CODES.length;i++) { 485 if ((t1.getDayCode()&Constants.DAY_CODES[i])!=0) { 486 if (f1<0) f1 = i; 487 e1 = i; 488 } 489 if ((t2.getDayCode()&Constants.DAY_CODES[i])!=0) { 490 if (f2<0) f2 = i; 491 e2 = i; 492 } 493 } 494 return (e1+1==f2) || (e2+1==f1); 495 } 496 497 private static boolean isNrDaysBetweenGreaterThanOne(String type) { 498 return (type.equals(TYPE_NDB_GT_1)); 499 } 500 501 private static boolean isChildrenNotOverlap(String type) { 502 return (type.equals(TYPE_CH_NOTOVERLAP)); 503 } 504 505 private static boolean isFollowingDay(String type) { 506 return (type.equals(TYPE_FOLLOWING_DAY)); 507 } 508 509 private static boolean isEveryOtherDay(String type) { 510 return (type.equals(TYPE_EVERY_OTHER_DAY)); 511 } 512 513 private static boolean isNrDaysBetweenGreaterThanOne(TimeLocation t1, TimeLocation t2) { 514 int f1 = -1, f2 = -1, e1 = -1, e2 = -1; 515 for (int i=0;i<Constants.DAY_CODES.length;i++) { 516 if ((t1.getDayCode()&Constants.DAY_CODES[i])!=0) { 517 if (f1<0) f1 = i; 518 e1 = i; 519 } 520 if ((t2.getDayCode()&Constants.DAY_CODES[i])!=0) { 521 if (f2<0) f2 = i; 522 e2 = i; 523 } 524 } 525 return (e1-f2>2) || (e2-f1>2); 526 } 527 528 private boolean isFollowingDay(Placement p1, Placement p2, boolean firstGoesFirst) { 529 int ord1 = variables().indexOf(p1.variable()); 530 int ord2 = variables().indexOf(p2.variable()); 531 TimeLocation t1=null, t2=null; 532 if (ord1<ord2) { 533 if (firstGoesFirst) { 534 t1 = p1.getTimeLocation(); t2 = p2.getTimeLocation(); 535 } else { 536 t2 = p1.getTimeLocation(); t1 = p2.getTimeLocation(); 537 } 538 } else { 539 if (!firstGoesFirst) { 540 t1 = p1.getTimeLocation(); t2 = p2.getTimeLocation(); 541 } else { 542 t2 = p1.getTimeLocation(); t1 = p2.getTimeLocation(); 543 } 544 } 545 int f1 = -1, f2 = -1, e1 = -1, e2 = -1; 546 for (int i=0;i<Constants.DAY_CODES.length;i++) { 547 if ((t1.getDayCode()&Constants.DAY_CODES[i])!=0) { 548 if (f1<0) f1 = i; 549 e1 = i; 550 } 551 if ((t2.getDayCode()&Constants.DAY_CODES[i])!=0) { 552 if (f2<0) f2 = i; 553 e2 = i; 554 } 555 } 556 return ((e1+1)%Constants.NR_DAYS_WEEK==f2); 557 } 558 559 private boolean isEveryOtherDay(Placement p1, Placement p2, boolean firstGoesFirst) { 560 int ord1 = variables().indexOf(p1.variable()); 561 int ord2 = variables().indexOf(p2.variable()); 562 TimeLocation t1=null, t2=null; 563 if (ord1<ord2) { 564 if (firstGoesFirst) { 565 t1 = p1.getTimeLocation(); t2 = p2.getTimeLocation(); 566 } else { 567 t2 = p1.getTimeLocation(); t1 = p2.getTimeLocation(); 568 } 569 } else { 570 if (!firstGoesFirst) { 571 t1 = p1.getTimeLocation(); t2 = p2.getTimeLocation(); 572 } else { 573 t2 = p1.getTimeLocation(); t1 = p2.getTimeLocation(); 574 } 575 } 576 int f1 = -1, f2 = -1, e1 = -1, e2 = -1; 577 for (int i=0;i<Constants.DAY_CODES.length;i++) { 578 if ((t1.getDayCode()&Constants.DAY_CODES[i])!=0) { 579 if (f1<0) f1 = i; 580 e1 = i; 581 } 582 if ((t2.getDayCode()&Constants.DAY_CODES[i])!=0) { 583 if (f2<0) f2 = i; 584 e2 = i; 585 } 586 } 587 return ((e1+2)%Constants.NR_DAYS_WEEK==f2); 588 } 589 590 private static boolean sameDays(int[] days1, int[] days2) { 591 if (days2.length<days1.length) return sameDays(days2,days1); 592 int i2=0; 593 for (int i1=0;i1<days1.length;i1++) { 594 int d1 = days1[i1]; 595 while (true) { 596 if (i2==days2.length) return false; 597 int d2 = days2[i2]; 598 if (d1==d2) break; 599 i2++; 600 if (i2==days2.length) return false; 601 } 602 i2++; 603 } 604 return true; 605 } 606 607 private static boolean sameHours(int start1, int len1, int start2, int len2) { 608 if (len1>len2) return sameHours(start2, len2, start1, len1); 609 start1 %= Constants.SLOTS_PER_DAY; 610 start2 %= Constants.SLOTS_PER_DAY; 611 return (start1>=start2 && start1+len1<=start2+len2); 612 } 613 614 private static boolean canFill(int totalGap, int gapMin, int gapMax, Vector lengths) { 615 if (gapMin<=totalGap && totalGap<=gapMax) return true; 616 if (totalGap<2*gapMin) return false; 617 for (int i=0;i<lengths.size();i++) { 618 int length = ((Integer)lengths.elementAt(i)).intValue(); lengths.removeElementAt(i); 619 for (int gap=gapMin;gap<=gapMax;gap++) 620 if (canFill(totalGap-gap-length,gapMin, gapMax, lengths)) return true; 621 lengths.insertElementAt(new Integer(length), i); 622 } 623 return false; 624 } 625 626 private boolean isSatisfiedSeq(Hashtable assignments, boolean considerCurrentAssignments, Set conflicts) { 627 if (conflicts==null) 628 return isSatisfiedSeqCheck(assignments, considerCurrentAssignments, conflicts); 629 else { 630 Set bestConflicts = isSatisfiedRecursive(0, assignments, considerCurrentAssignments, conflicts, new HashSet(), null); 631 if (bestConflicts==null) return false; 632 conflicts.addAll(bestConflicts); 633 return true; 634 } 635 } 636 637 private Set isSatisfiedRecursive(int idx, Hashtable assignments, boolean considerCurrentAssignments, Set conflicts, Set newConflicts, Set bestConflicts) { 638 if (idx==variables().size() && newConflicts.isEmpty()) return bestConflicts; 639 if (isSatisfiedSeqCheck(assignments, considerCurrentAssignments, conflicts)) { 640 if (bestConflicts==null || bestConflicts.size()>newConflicts.size()) 641 return new HashSet(newConflicts); 642 return bestConflicts; 643 } 644 if (idx==variables().size()) return bestConflicts; 645 bestConflicts = isSatisfiedRecursive(idx+1, assignments, considerCurrentAssignments, conflicts, newConflicts, bestConflicts); 646 Lecture lecture = (Lecture)variables().elementAt(idx); 647 if (assignments!=null && assignments.containsKey(lecture)) return bestConflicts; 648 Placement placement = (Placement)(assignments==null?null:assignments.get(lecture)); 649 if (placement==null && considerCurrentAssignments) placement = (Placement)lecture.getAssignment(); 650 if (placement==null) return bestConflicts; 651 if (conflicts!=null && conflicts.contains(placement)) return bestConflicts; 652 conflicts.add(placement); 653 newConflicts.add(placement); 654 bestConflicts = isSatisfiedRecursive(idx+1,assignments, considerCurrentAssignments, conflicts, newConflicts, bestConflicts); 655 newConflicts.remove(placement); 656 conflicts.remove(placement); 657 return bestConflicts; 658 } 659 660 661 private boolean isSatisfiedSeqCheck(Hashtable assignments, boolean considerCurrentAssignments, Set conflicts) { 662 int gapMin = getGapMin(getType()); 663 int gapMax = getGapMax(getType()); 664 if (gapMin<0 || gapMax<0) return true; 665 666 Vector lengths = new FastVector(); 667 668 Placement [] res = new Placement[Constants.SLOTS_PER_DAY]; 669 for (int i=0;i<Constants.SLOTS_PER_DAY;i++) res[i]=null; 670 671 Vector unAssignedLectures = new Vector(); 672 int nrLectures=0; 673 String roomId = null; 674 675 for (Enumeration e=variables().elements();e.hasMoreElements();) { 676 Lecture lecture = (Lecture)e.nextElement(); 677 Placement placement = (Placement)(assignments==null?null:assignments.get(lecture)); 678 if (placement==null && considerCurrentAssignments) placement = (Placement)lecture.getAssignment(); 679 if (placement==null) { 680 lengths.addElement(new Integer(((TimeLocation)lecture.timeLocations().firstElement()).getLength())); 681 } else if (conflicts!=null && conflicts.contains(placement)) { 682 lengths.addElement(new Integer(((TimeLocation)lecture.timeLocations().firstElement()).getLength())); 683 } else { 684 int pos=placement.getTimeLocation().getStartSlot(); 685 int length=placement.getTimeLocation().getLength(); 686 for (int j=pos;j<pos+length;j++) { 687 if (res[j]!=null) { 688 if (conflicts==null) return false; 689 if (!assignments.containsKey(lecture)) 690 conflicts.add(placement); 691 else if (!assignments.containsKey(res[j].variable())) 692 conflicts.add(res[j]); 693 } 694 } 695 for (int j=pos;j<pos+length;j++) res[j]=placement; 696 nrLectures++; 697 } 698 } 699 if (nrLectures<=1) return true; 700 701 if (iIsRequired || (!iIsProhibited && iPreference<0)) { 702 int i=0; 703 Placement p=res[i]; 704 while (p==null) p=res[++i]; 705 i+=res[i].getTimeLocation().getLength(); 706 nrLectures--; 707 while (nrLectures>0) { 708 int gap=0; 709 while (i<Constants.SLOTS_PER_DAY && res[i]==null) { gap++; i++; } 710 if (i==Constants.SLOTS_PER_DAY) break; 711 if (!canFill(gap, gapMin, gapMax, lengths)) return false; 712 p=res[i]; 713 i+=res[i].getTimeLocation().getLength(); 714 nrLectures--; 715 } 716 } else if (iIsProhibited || (!iIsRequired && iPreference>0)) { 717 int i=0; 718 Placement p=res[i]; 719 while (p==null) p=res[++i]; 720 i+=res[i].getTimeLocation().getLength(); 721 nrLectures--; 722 while (nrLectures>0) { 723 int gap=0; 724 while (i<Constants.SLOTS_PER_DAY && res[i]==null) { gap++; i++; } 725 if (i==Constants.SLOTS_PER_DAY) break; 726 if ((gapMin==0 || !canFill(gap, 0, gapMin-1, lengths)) && 727 (gapMax>=Constants.SLOTS_PER_DAY || !canFill(gap, gapMax+1, Constants.SLOTS_PER_DAY, lengths))) { 728 return false; 729 } 730 p=res[i]; 731 i+=res[i].getTimeLocation().getLength(); 732 nrLectures--; 733 } 734 } 735 return true; 736 } 737 738 public boolean isSatisfied() { 739 if (isHard()) return true; 740 if (countAssignedVariables()<2) return true; 741 return (getPreference()<0 && getCurrentPreference()<0) || getPreference()==0 || (getPreference()>0 && getCurrentPreference()==0); 742 } 743 744 public boolean isChildrenNotOverlap(Lecture lec1, Placement plc1, Lecture lec2, Placement plc2) { 745 if (lec1.getSchedulingSubpartId().equals(lec2.getSchedulingSubpartId())) { 746 //same subpart 747 boolean overlap = plc1.getTimeLocation().hasIntersection(plc2.getTimeLocation()); 748 749 if (overlap && lec1.getParent()!=null && variables().contains(lec1.getParent()) && lec2.getParent()!=null && variables().contains(lec2.getParent())) { 750 //children overlaps 751 Placement p1 = (Placement)lec1.getParent().getAssignment(); 752 Placement p2 = (Placement)lec2.getParent().getAssignment(); 753 //parents not overlap, but children do 754 if (p1!=null && p2!=null && !p1.getTimeLocation().hasIntersection(p2.getTimeLocation())) return false; 755 } 756 757 if (!overlap && lec1.getChildrenSubpartIds()!=null && lec2.getChildrenSubpartIds()!=null) { 758 //parents not overlap 759 for (Enumeration e1=lec1.getChildrenSubpartIds();e1.hasMoreElements();) { 760 Long subpartId = (Long)e1.nextElement(); 761 for (Enumeration e2=lec1.getChildren(subpartId).elements();e2.hasMoreElements();) { 762 Lecture c1 = (Lecture)e2.nextElement(); 763 if (c1.getAssignment()==null) continue; 764 for (Enumeration e3=lec2.getChildren(subpartId).elements();e3.hasMoreElements();) { 765 Lecture c2 = (Lecture)e3.nextElement(); 766 if (c2.getAssignment()==null) continue; 767 if (!c1.getSchedulingSubpartId().equals(c2.getSchedulingSubpartId())) continue; 768 Placement p1 = (Placement)c1.getAssignment(); 769 Placement p2 = (Placement)c2.getAssignment(); 770 //parents not overlap, but children do 771 if (p1.getTimeLocation().hasIntersection(p2.getTimeLocation())) return false; 772 } 773 } 774 } 775 } 776 } else { 777 //different subpart 778 } 779 return true; 780 } 781 782 private boolean isSatisfiedPair(Lecture lec1, Placement plc1, Lecture lec2, Placement plc2) { 783 if (iIsRequired || (!iIsProhibited && iPreference<0)) { 784 if (sameRoom(getType()) || (isBackToBack(getType()) && !isBackToBackTime(getType()))) { 785 if (!plc1.sameRooms(plc2)) return false; 786 } 787 if (sameStartHour(getType())) { 788 if ((plc1.getTimeLocation().getStartSlot()%Constants.SLOTS_PER_DAY) != 789 (plc2.getTimeLocation().getStartSlot()%Constants.SLOTS_PER_DAY)) 790 return false; 791 } 792 if (sameHours(getType())) { 793 if (!sameHours(plc1.getTimeLocation().getStartSlot(), plc1.getTimeLocation().getLength(), 794 plc2.getTimeLocation().getStartSlot(), plc2.getTimeLocation().getLength())) 795 return false; 796 } 797 if (sameDays(getType()) || isBackToBack(getType())) { 798 if (!sameDays(plc1.getTimeLocation().getDaysArray(), plc2.getTimeLocation().getDaysArray())) 799 return false; 800 } 801 if (notOverlap(getType())) { 802 if (plc1.getTimeLocation().hasIntersection(plc2.getTimeLocation())) 803 return false; 804 } 805 if (sameStudents(getType())) { 806 if (JenrlConstraint.isInConflict(plc1,plc2)) return false; 807 } 808 if (sameInstructor(getType())) { 809 TimeLocation t1=plc1.getTimeLocation(), t2=plc2.getTimeLocation(); 810 if (t1.shareDays(t2) && t1.shareWeeks(t2)) { 811 if (t1.shareHours(t2)) return false; //overlap 812 int s1 = t1.getStartSlot() % Constants.SLOTS_PER_DAY; 813 int s2 = t2.getStartSlot() % Constants.SLOTS_PER_DAY; 814 if (s1+t1.getLength()==s2 || s2+t2.getLength()==s1) { //back-to-back 815 double distance = Placement.getDistance(plc1,plc2); 816 TimetableModel m = (TimetableModel)getModel(); 817 if (distance>m.getInstructorProhibitedLimit()) 818 return false; 819 } 820 } 821 } 822 if (isPrecedence(getType())) { 823 return isPrecedence(plc1, plc2, true); 824 } 825 if (isBackToBackDay(getType())) { 826 if (sameDays(plc1.getTimeLocation().getDaysArray(), plc2.getTimeLocation().getDaysArray())) return false; 827 return isBackToBackDays(plc1.getTimeLocation(),plc2.getTimeLocation()); 828 } 829 if (isNrDaysBetweenGreaterThanOne(getType())) { 830 if (sameDays(plc1.getTimeLocation().getDaysArray(), plc2.getTimeLocation().getDaysArray())) return false; 831 return isNrDaysBetweenGreaterThanOne(plc1.getTimeLocation(),plc2.getTimeLocation()); 832 } 833 if (isChildrenNotOverlap(getType())) { 834 return isChildrenNotOverlap(lec1, plc1, lec2, plc2); 835 } 836 if (isFollowingDay(getType())) { 837 return isFollowingDay(plc1,plc2, true); 838 } 839 if (isEveryOtherDay(getType())) { 840 return isEveryOtherDay(plc1,plc2, true); 841 } 842 } else if (iIsProhibited || (!iIsRequired && iPreference>0)) { 843 if (sameRoom(getType())) { 844 if (plc1.sameRooms(plc2)) 845 return false; 846 } 847 if (sameHours(getType())) { 848 if (plc1.getTimeLocation().shareHours(plc2.getTimeLocation())) 849 return false; 850 } 851 if (sameStartHour(getType())) { 852 if ((plc1.getTimeLocation().getStartSlot()%Constants.SLOTS_PER_DAY) == 853 (plc2.getTimeLocation().getStartSlot()%Constants.SLOTS_PER_DAY)) 854 return false; 855 } 856 if (sameDays(getType())) { 857 if (plc1.getTimeLocation().shareDays(plc2.getTimeLocation())) 858 return false; 859 } 860 if (notOverlap(getType())) { 861 if (!plc1.getTimeLocation().hasIntersection(plc2.getTimeLocation())) 862 return false; 863 } 864 if (isBackToBack(getType())) { //still same time 865 if (!sameDays(plc1.getTimeLocation().getDaysArray(), plc2.getTimeLocation().getDaysArray())) 866 return false; 867 if (!isBackToBackTime(getType())) { //still same room 868 if (!plc1.sameRooms(plc2)) 869 return false; 870 } 871 } 872 if (isPrecedence(getType())) { 873 return isPrecedence(plc1, plc2, false); 874 } 875 if (isBackToBackDay(getType())) { 876 if (sameDays(plc1.getTimeLocation().getDaysArray(), plc2.getTimeLocation().getDaysArray())) return false; 877 return !isBackToBackDays(plc1.getTimeLocation(),plc2.getTimeLocation()); 878 } 879 if (isNrDaysBetweenGreaterThanOne(getType())) { 880 if (sameDays(plc1.getTimeLocation().getDaysArray(), plc2.getTimeLocation().getDaysArray())) return false; 881 return !isNrDaysBetweenGreaterThanOne(plc1.getTimeLocation(),plc2.getTimeLocation()); 882 } 883 if (isFollowingDay(getType())) { 884 return isFollowingDay(plc1, plc2, false); 885 } 886 if (isEveryOtherDay(getType())) { 887 return isEveryOtherDay(plc1, plc2, false); 888 } 889 } 890 return true; 891 } 892 893 /* 894 public void getInfo(Dictionary info) { 895 StringBuffer varNames = new StringBuffer(); 896 for (Enumeration e=variables().elements();e.hasMoreElements();) { 897 Variable variable = (Variable)e.nextElement(); 898 varNames.append(varNames.length()>0?", ":""); 899 varNames.append(variable.getName()); 900 if (variable.getAssignment()!=null) 901 varNames.append(" "+variable.getAssignment().getName()); 902 } 903 info.put("gc"+iId, iType).getDescription()+" (pref="+getDescription()+" ("+iIsRequired+"/"+iIsProhibited+"/"+iPreference+")"+", current="+getCurrentPreference()+", vars=["+varNames+"])"); 904 } 905 */ 906 907 /* 908 public static class GroupConstraintTypes { 909 private static Vector sGroupConstraintTypes = null; 910 911 static { 912 try { 913 sGroupConstraintTypes = new Vector(); 914 for (Iterator i=DistributionType.findAll().iterator();i.hasNext();) { 915 DistributionType type = (DistributionType)i.next(); 916 sGroupConstraintTypes.addElement(new GroupConstraintType(type.getRequirementId().intValue(),type.getReference(),type.getLabel())); 917 } 918 } catch (Exception e) { 919 sLogger.error(e.getMessage(),e); 920 sGroupConstraintTypes.addElement(new GroupConstraintType(1,"BTB","back-to-back")); 921 sGroupConstraintTypes.addElement(new GroupConstraintType(2,"BTB_TIME","back-to-back time")); 922 sGroupConstraintTypes.addElement(new GroupConstraintType(3,"SAME_TIME","same time")); 923 sGroupConstraintTypes.addElement(new GroupConstraintType(4,"SAME_DAYS","same days")); 924 sGroupConstraintTypes.addElement(new GroupConstraintType(5,"NHB(1)","1 hr between")); 925 sGroupConstraintTypes.addElement(new GroupConstraintType(6,"NHB(2)","2 hrs between")); 926 sGroupConstraintTypes.addElement(new GroupConstraintType(7,"NHB(3)","3 hrs between")); 927 sGroupConstraintTypes.addElement(new GroupConstraintType(8,"NHB(4)","4 hrs between")); 928 sGroupConstraintTypes.addElement(new GroupConstraintType(9,"NHB(5)","5 hrs between")); 929 sGroupConstraintTypes.addElement(new GroupConstraintType(10,"NHB(6)","6 hrs between")); 930 sGroupConstraintTypes.addElement(new GroupConstraintType(11,"NHB(7)","7 hrs between")); 931 sGroupConstraintTypes.addElement(new GroupConstraintType(12,"NHB(8)","8 hrs between")); 932 sGroupConstraintTypes.addElement(new GroupConstraintType(13,"DIFF_TIME","different time")); 933 sGroupConstraintTypes.addElement(new GroupConstraintType(14,"NHB(1.5)","1.5 hrs between")); 934 sGroupConstraintTypes.addElement(new GroupConstraintType(15,"NHB(4.5)","4.5 hrs between")); 935 sGroupConstraintTypes.addElement(new GroupConstraintType(16,"SAME_START","same start time")); 936 sGroupConstraintTypes.addElement(new GroupConstraintType(17,"SAME_ROOM","same room")); 937 sGroupConstraintTypes.addElement(new GroupConstraintType(18,"NHB_GTE(1)","greater than or equal to 1 hour between")); 938 sGroupConstraintTypes.addElement(new GroupConstraintType(19,"NHB_LT(6)","less than 6 hours between")); 939 } 940 if (getGroupConstraintType("SAME_STUDENTS")==null) 941 sGroupConstraintTypes.addElement(new GroupConstraintType(20,"SAME_STUDENTS","same students")); 942 if (getGroupConstraintType("SAME_INSTR")==null) 943 sGroupConstraintTypes.addElement(new GroupConstraintType(21,"SAME_INSTR","same instructor")); 944 if (getGroupConstraintType("CAN_SHARE_ROOM")==null) 945 sGroupConstraintTypes.addElement(new GroupConstraintType(22,"CAN_SHARE_ROOM","can share rooms")); 946 if (getGroupConstraintType("PRECEDENCE")==null) 947 sGroupConstraintTypes.addElement(new GroupConstraintType(24,"PRECEDENCE","precedence")); 948 if (getGroupConstraintType("BTB_DAY")==null) 949 sGroupConstraintTypes.addElement(new GroupConstraintType(26,"BTB_DAY","back-to-back day")); 950 if (getGroupConstraintType("MIN_GRUSE(10x1h)")==null) 951 sGroupConstraintTypes.addElement(new GroupConstraintType(27,"MIN_GRUSE(10x1h)","minimize use of 1h groups")); 952 if (getGroupConstraintType("MIN_GRUSE(5x2h)")==null) 953 sGroupConstraintTypes.addElement(new GroupConstraintType(28,"MIN_GRUSE(5x2h)","minimize use of 2h groups")); 954 if (getGroupConstraintType("MIN_GRUSE(3x3h)")==null) 955 sGroupConstraintTypes.addElement(new GroupConstraintType(29,"MIN_GRUSE(3x3h)","minimize use of 3h groups")); 956 if (getGroupConstraintType("MIN_GRUSE(2x5h)")==null) 957 sGroupConstraintTypes.addElement(new GroupConstraintType(30,"MIN_GRUSE(2x5h)","minimize use of 5h groups")); 958 if (getGroupConstraintType("MEET_WITH")==null) 959 sGroupConstraintTypes.addElement(new GroupConstraintType(31,"MEET_WITH","meet together")); 960 if (getGroupConstraintType("NDB_GT_1")==null) 961 sGroupConstraintTypes.addElement(new GroupConstraintType(32,"NDB_GT_1",">1d btw")); 962 if (getGroupConstraintType("CH_NOTOVERLAP")==null) 963 sGroupConstraintTypes.addElement(new GroupConstraintType(33,"NDB_GT_1","ch no overlap")); 964 if (getGroupConstraintType("FOLLOWING_DAY")==null) 965 sGroupConstraintTypes.addElement(new GroupConstraintType(34,"FOLLOWING_DAY","following day")); 966 if (getGroupConstraintType("EVERY_OTHER_DAY")==null) 967 sGroupConstraintTypes.addElement(new GroupConstraintType(35,"EVERY_OTHER_DAY","every other day")); 968 } 969 970 public static Enumeration elements() { 971 return sGroupConstraintTypes.elements(); 972 } 973 974 public static int size() { 975 return sGroupConstraintTypes.size(); 976 } 977 978 public static GroupConstraintType elementAt(int i) { 979 return (GroupConstraintType) sGroupConstraintTypes.elementAt(i); 980 } 981 982 public static GroupConstraintType getGroupConstraintType(int id) { 983 for (Enumeration e=sGroupConstraintTypes.elements();e.hasMoreElements();) { 984 GroupConstraintType gc = (GroupConstraintType)e.nextElement(); 985 if (gc.getId()==id) return gc; 986 } 987 return null; 988 } 989 990 public static GroupConstraintType getGroupConstraintType(String type) { 991 for (Enumeration e=sGroupConstraintTypes.elements();e.hasMoreElements();) { 992 GroupConstraintType gc = (GroupConstraintType)e.nextElement(); 993 if (gc.getType().equalsIgnoreCase(type)) return gc; 994 } 995 return null; 996 } 997 998 public static class GroupConstraintType implements Comparable { 999 int iId; 1000 String iType; 1001 String iDescription; 1002 1003 private GroupConstraintType(int id, String type, String desc) { 1004 iId = id; 1005 iType = type; 1006 iDescription = desc; 1007 } 1008 1009 public int getId() { 1010 return iId; 1011 } 1012 public String getType() { 1013 return iType; 1014 } 1015 public String getDescription() { 1016 return iDescription; 1017 } 1018 1019 public boolean equals(Object o) { 1020 if (o==null || !(o instanceof GroupConstraintType)) return false; 1021 return getId() == ((GroupConstraintType)o; 1022 } 1023 1024 public int compareTo(Object o) { 1025 if (o==null || !(o instanceof GroupConstraintType)) return 0; 1026 GroupConstraintType g = (GroupConstraintType)o; 1027 return getId() - ((GroupConstraintType)o; 1028 } 1029 1030 } 1031 } 1032 */ 1033 }