001package org.cpsolver.studentsct.weights; 002 003import java.text.DecimalFormat; 004import java.util.ArrayList; 005import java.util.BitSet; 006import java.util.HashSet; 007import java.util.Set; 008 009import org.cpsolver.coursett.model.Placement; 010import org.cpsolver.coursett.model.RoomLocation; 011import org.cpsolver.coursett.model.TimeLocation; 012import org.cpsolver.ifs.assignment.Assignment; 013import org.cpsolver.ifs.assignment.DefaultSingleAssignment; 014import org.cpsolver.ifs.solution.Solution; 015import org.cpsolver.ifs.util.DataProperties; 016import org.cpsolver.ifs.util.ToolBox; 017import org.cpsolver.studentsct.StudentSectioningModel; 018import org.cpsolver.studentsct.extension.DistanceConflict; 019import org.cpsolver.studentsct.extension.StudentQuality; 020import org.cpsolver.studentsct.extension.StudentQuality.Conflict; 021import org.cpsolver.studentsct.extension.TimeOverlapsCounter; 022import org.cpsolver.studentsct.model.Choice; 023import org.cpsolver.studentsct.model.Config; 024import org.cpsolver.studentsct.model.Course; 025import org.cpsolver.studentsct.model.CourseRequest; 026import org.cpsolver.studentsct.model.Enrollment; 027import org.cpsolver.studentsct.model.Instructor; 028import org.cpsolver.studentsct.model.Offering; 029import org.cpsolver.studentsct.model.Request; 030import org.cpsolver.studentsct.model.RequestGroup; 031import org.cpsolver.studentsct.model.SctAssignment; 032import org.cpsolver.studentsct.model.Section; 033import org.cpsolver.studentsct.model.Student; 034import org.cpsolver.studentsct.model.Subpart; 035 036 037/** 038 * New weighting model. It tries to obey the following principles: 039 * <ul> 040 * <li> Total student weight is between zero and one (one means student got the best schedule) 041 * <li> Weight of the given priority course is higher than sum of the remaining weights the student can get 042 * <li> First alternative is better than the following course 043 * <li> Second alternative is better than the second following course 044 * <li> Distance conflicts are considered secondary (priorities should be maximized first) 045 * <li> If alternative sections are otherwise equal, use the better balanced one 046 * </ul> 047 * 048 * @version StudentSct 1.3 (Student Sectioning)<br> 049 * Copyright (C) 2007 - 2014 Tomáš Müller<br> 050 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 051 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 052 * <br> 053 * This library is free software; you can redistribute it and/or modify 054 * it under the terms of the GNU Lesser General Public License as 055 * published by the Free Software Foundation; either version 3 of the 056 * License, or (at your option) any later version. <br> 057 * <br> 058 * This library is distributed in the hope that it will be useful, but 059 * WITHOUT ANY WARRANTY; without even the implied warranty of 060 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 061 * Lesser General Public License for more details. <br> 062 * <br> 063 * You should have received a copy of the GNU Lesser General Public 064 * License along with this library; if not see 065 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 066 */ 067 068public class PriorityStudentWeights implements StudentWeights { 069 protected double iPriorityFactor = 0.5010; 070 protected double iFirstAlternativeFactor = 0.5010; 071 protected double iSecondAlternativeFactor = 0.2510; 072 protected double iDistanceConflict = 0.0100; 073 protected double iShortDistanceConflict = 0.1000; 074 protected double iTimeOverlapFactor = 0.5000; 075 protected double iTimeOverlapMaxLimit = 0.5000; 076 protected boolean iLeftoverSpread = false; 077 protected double iBalancingFactor = 0.0050; 078 protected double iNoTimeFactor = 0.0100; 079 protected double iOnlineFactor = 0.0100; 080 protected double iPastFactor = 0.0000; 081 protected double iReservationNotFollowedFactor = 0.1000; 082 protected double iAlternativeRequestFactor = 0.1260; 083 protected double iProjectedStudentWeight = 0.0100; 084 protected boolean iMPP = false; 085 protected double iPerturbationFactor = 0.100; 086 protected double iSelectionFactor = 0.100; 087 protected double iSameChoiceWeight = 0.900; 088 protected double iSameTimeWeight = 0.700; 089 protected double iSameConfigWeight = 0.500; 090 protected double iGroupFactor = 0.100; 091 protected double iGroupBestRatio = 0.95; 092 protected double iGroupFillRatio = 0.05; 093 protected boolean iAdditiveWeights = false; 094 protected boolean iMaximizeAssignment = false; 095 protected boolean iPreciseComparison = false; 096 protected double[] iQalityWeights; 097 protected boolean iImprovedBound = true; 098 protected double iCriticalBoost = 1.0; 099 protected double iPriortyBoost = 1.0; 100 101 public PriorityStudentWeights(DataProperties config) { 102 iPriorityFactor = config.getPropertyDouble("StudentWeights.Priority", iPriorityFactor); 103 iFirstAlternativeFactor = config.getPropertyDouble("StudentWeights.FirstAlternative", iFirstAlternativeFactor); 104 iSecondAlternativeFactor = config.getPropertyDouble("StudentWeights.SecondAlternative", iSecondAlternativeFactor); 105 iDistanceConflict = config.getPropertyDouble("StudentWeights.DistanceConflict", iDistanceConflict); 106 iShortDistanceConflict = config.getPropertyDouble("StudentWeights.ShortDistanceConflict", iShortDistanceConflict); 107 iTimeOverlapFactor = config.getPropertyDouble("StudentWeights.TimeOverlapFactor", iTimeOverlapFactor); 108 iTimeOverlapMaxLimit = config.getPropertyDouble("StudentWeights.TimeOverlapMaxLimit", iTimeOverlapMaxLimit); 109 iLeftoverSpread = config.getPropertyBoolean("StudentWeights.LeftoverSpread", iLeftoverSpread); 110 iBalancingFactor = config.getPropertyDouble("StudentWeights.BalancingFactor", iBalancingFactor); 111 iAlternativeRequestFactor = config.getPropertyDouble("StudentWeights.AlternativeRequestFactor", iAlternativeRequestFactor); 112 iProjectedStudentWeight = config.getPropertyDouble("StudentWeights.ProjectedStudentWeight", iProjectedStudentWeight); 113 iMPP = config.getPropertyBoolean("General.MPP", false); 114 iPerturbationFactor = config.getPropertyDouble("StudentWeights.Perturbation", iPerturbationFactor); 115 iSelectionFactor = config.getPropertyDouble("StudentWeights.Selection", iSelectionFactor); 116 iSameChoiceWeight = config.getPropertyDouble("StudentWeights.SameChoice", iSameChoiceWeight); 117 iSameTimeWeight = config.getPropertyDouble("StudentWeights.SameTime", iSameTimeWeight); 118 iSameConfigWeight = config.getPropertyDouble("StudentWeights.SameConfig", iSameConfigWeight); 119 iGroupFactor = config.getPropertyDouble("StudentWeights.SameGroup", iGroupFactor); 120 iGroupBestRatio = config.getPropertyDouble("StudentWeights.GroupBestRatio", iGroupBestRatio); 121 iGroupFillRatio = config.getPropertyDouble("StudentWeights.GroupFillRatio", iGroupFillRatio); 122 iNoTimeFactor = config.getPropertyDouble("StudentWeights.NoTimeFactor", iNoTimeFactor); 123 iOnlineFactor = config.getPropertyDouble("StudentWeights.OnlineFactor", iOnlineFactor); 124 iPastFactor = config.getPropertyDouble("StudentWeights.PastFactor", iPastFactor); 125 iReservationNotFollowedFactor = config.getPropertyDouble("StudentWeights.ReservationNotFollowedFactor", iReservationNotFollowedFactor); 126 iAdditiveWeights = config.getPropertyBoolean("StudentWeights.AdditiveWeights", iAdditiveWeights); 127 iMaximizeAssignment = config.getPropertyBoolean("StudentWeights.MaximizeAssignment", iMaximizeAssignment); 128 iPreciseComparison = config.getPropertyBoolean("StudentWeights.PreciseComparison", iPreciseComparison); 129 iQalityWeights = new double[StudentQuality.Type.values().length]; 130 for (StudentQuality.Type type: StudentQuality.Type.values()) { 131 iQalityWeights[type.ordinal()] = config.getPropertyDouble(type.getWeightName(), type.getWeightDefault()); 132 } 133 iImprovedBound = config.getPropertyBoolean("StudentWeights.ImprovedBound", iImprovedBound); 134 iPriortyBoost = config.getPropertyDouble("StudentWeights.PriortyBoost", 1.0); 135 iCriticalBoost = config.getPropertyDouble("StudentWeights.CriticalBoost", 1.0); 136 } 137 138 public double getWeight(Request request) { 139 if (request.getStudent().isDummy() && iProjectedStudentWeight >= 0.0) { 140 double weight = iProjectedStudentWeight; 141 if (request.isAlternative()) 142 weight *= iAlternativeRequestFactor; 143 return weight; 144 } 145 double total = 1000000.0; 146 int nrReq = request.getStudent().nrRequests(); 147 double remain = (iLeftoverSpread ? Math.floor(1000000.0 * Math.pow(iPriorityFactor, nrReq) / nrReq) : 0.0); 148 for (int idx = 0; idx < request.getStudent().getRequests().size(); idx++) { 149 Request r = request.getStudent().getRequests().get(idx); 150 boolean last = (idx + 1 == request.getStudent().getRequests().size()); 151 boolean lastNotAlt = !r.isAlternative() && (last || request.getStudent().getRequests().get(1 + idx).isAlternative()); 152 double w = Math.ceil(iPriorityFactor * total) + remain; 153 if (!iLeftoverSpread && lastNotAlt) { 154 w = total; 155 } else { 156 total -= w; 157 } 158 if (r.equals(request)) { 159 return w / 1000000.0; 160 } 161 } 162 return 0.0; 163 } 164 165 public double getBoostedWeight(Request request) { 166 double weight = getWeight(request); 167 if (iPriortyBoost != 1.0) { 168 Double boost = request.getStudent().getPriority().getBoost(); 169 if (boost != null) 170 weight *= boost * iPriortyBoost; 171 } 172 if (iCriticalBoost != 1.0) { 173 Double boost = request.getRequestPriority().getBoost(); 174 if (boost != null) 175 weight *= boost * iCriticalBoost; 176 } 177 return weight; 178 } 179 180 public double getCachedWeight(Request request) { 181 double[] cache = (double[])request.getExtra(); 182 if (cache == null) { 183 double base = getBoostedWeight(request); 184 cache = new double[]{base, computeBound(base, request)}; 185 request.setExtra(cache); 186 } 187 return cache[0]; 188 } 189 190 /** 191 * Return how much the given enrollment is different from the initial enrollment 192 * @param enrollment given enrollment 193 * @return 0.0 when all the sections are the same, 1.0 when all the section are different (including different times) 194 */ 195 protected double getDifference(Enrollment enrollment) { 196 if (enrollment.getStudent().isDummy() || !enrollment.isCourseRequest()) return 1.0; 197 Enrollment other = enrollment.getRequest().getInitialAssignment(); 198 if (other != null) { 199 double similarSections = 0.0; 200 if (enrollment.getConfig().equals(other.getConfig())) { 201 // same configurations -- compare sections of matching subpart 202 for (Section section: enrollment.getSections()) { 203 for (Section initial: other.getSections()) { 204 if (section.getSubpart().equals(initial.getSubpart())) { 205 if (section.equals(initial)) { 206 similarSections += 1.0; 207 } else if (section.sameChoice(initial)) { 208 similarSections += iSameChoiceWeight; 209 } else if (section.sameTime(initial)) { 210 similarSections += iSameTimeWeight; 211 } 212 break; 213 } 214 } 215 } 216 } else { 217 // different configurations -- compare sections of matching itype 218 for (Section section: enrollment.getSections()) { 219 for (Section initial: other.getSections()) { 220 if (section.sameChoice(initial)) { 221 similarSections += iSameChoiceWeight; 222 break; 223 } else if (section.sameInstructionalType(initial) && section.sameTime(initial)) { 224 similarSections += iSameTimeWeight; 225 break; 226 } 227 } 228 } 229 } 230 return 1.0 - similarSections / enrollment.getAssignments().size(); 231 } 232 return 1.0; 233 } 234 235 /** 236 * Return how much the given enrollment is different from the selection (if any) 237 * @param enrollment given enrollment 238 * @return 0.0 when all the sections are the same, 1.0 when all the section are different (including different times) 239 */ 240 public double getSelection(Enrollment enrollment) { 241 if (enrollment.getStudent().isDummy()) return 1.0; 242 if (enrollment.isCourseRequest()) { 243 CourseRequest cr = (CourseRequest)enrollment.getRequest(); 244 if (!cr.getSelectedChoices().isEmpty()) { 245 double similarSections = 0.0; 246 for (Section section: enrollment.getSections()) { 247 double bestChoice = 0.0; 248 for (Choice ch: cr.getSelectedChoices()) { 249 if (bestChoice < 1.0 && ch.sameSection(section)) { 250 bestChoice = 1.0; 251 } else if (bestChoice < iSameChoiceWeight && ch.sameChoice(section)) { 252 bestChoice = iSameChoiceWeight; 253 } else if (bestChoice < iSameTimeWeight && ch.sameOffering(section) && ch.sameInstructionalType(section) && ch.sameTime(section)) { 254 bestChoice = iSameTimeWeight; 255 } else if (bestChoice < iSameConfigWeight && ch.sameConfiguration(section)) { 256 bestChoice = iSameConfigWeight; 257 } 258 } 259 similarSections += bestChoice; 260 } 261 return 1.0 - similarSections / enrollment.getAssignments().size(); 262 } else { 263 return 1.0; 264 } 265 } else { 266 return 1.0; 267 } 268 } 269 270 271 @Override 272 public double getBound(Request request) { 273 double[] cache = (double[])request.getExtra(); 274 if (cache == null) { 275 double base = getBoostedWeight(request); 276 cache = new double[]{base, computeBound(base, request)}; 277 request.setExtra(cache); 278 } 279 return cache[1]; 280 } 281 282 protected double computeBound(double base, Request request) { 283 if (!iImprovedBound) return base; 284 if (iAdditiveWeights) { 285 double weight = 0.0; 286 if (request instanceof CourseRequest) { 287 CourseRequest cr = (CourseRequest)request; 288 if (iNoTimeFactor != 0.0 && !cr.getCourses().isEmpty()) { 289 weight += iNoTimeFactor * cr.getCourses().get(0).getArrHrsBound(); 290 } 291 if (iOnlineFactor != 0.0 && !cr.getCourses().isEmpty()) { 292 weight += iOnlineFactor * cr.getCourses().get(0).getOnlineBound(); 293 } 294 if (iPastFactor != 0.0 && !cr.getCourses().isEmpty()) { 295 weight += iPastFactor * cr.getCourses().get(0).getPastBound(); 296 } 297 if (iMPP && cr.getInitialAssignment() == null) { 298 weight += iPerturbationFactor; 299 } 300 if (iSelectionFactor != 0.0 && cr.getSelectedChoices().isEmpty()) { 301 weight += iSelectionFactor; 302 } 303 } 304 return round(base * (1.0 - weight)); 305 } else { 306 double weight = base; 307 if (request instanceof CourseRequest) { 308 CourseRequest cr = (CourseRequest)request; 309 if (iNoTimeFactor != 0.0 && !cr.getCourses().isEmpty()) { 310 weight *= (1.0 - iNoTimeFactor * cr.getCourses().get(0).getArrHrsBound()); 311 } 312 if (iOnlineFactor != 0.0 && !cr.getCourses().isEmpty()) { 313 weight *= (1.0 - iOnlineFactor * cr.getCourses().get(0).getOnlineBound()); 314 } 315 if (iPastFactor != 0.0 && !cr.getCourses().isEmpty()) { 316 weight *= (1.0 - iPastFactor * cr.getCourses().get(0).getPastBound()); 317 } 318 if (iMPP && cr.getInitialAssignment() == null) { 319 weight *= (1.0 - iPerturbationFactor); 320 } 321 if (iSelectionFactor != 0.0 && cr.getSelectedChoices().isEmpty()) { 322 weight *= (1.0 - iSelectionFactor); 323 } 324 } 325 return round(weight); 326 } 327 } 328 329 protected double round(double value) { 330 return Math.ceil(1000000.0 * value) / 1000000.0; 331 } 332 333 protected double getBaseWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment) { 334 double weight = getCachedWeight(enrollment.getRequest()); 335 switch (enrollment.getTruePriority()) { 336 case 0: break; 337 case 1: weight *= iFirstAlternativeFactor; break; 338 case 2: weight *= iSecondAlternativeFactor; break; 339 default: 340 weight *= Math.pow(iFirstAlternativeFactor, enrollment.getTruePriority()); 341 } 342 return weight; 343 } 344 345 @Override 346 public double getWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment) { 347 if (iAdditiveWeights) 348 return getWeightAdditive(assignment, enrollment); 349 else 350 return getWeightMultiplicative(assignment, enrollment); 351 } 352 353 public double getWeightMultiplicative(Assignment<Request, Enrollment> assignment, Enrollment enrollment) { 354 double weight = getBaseWeight(assignment, enrollment); 355 if (enrollment.isCourseRequest() && iNoTimeFactor != 0.0) { 356 int noTimeSections = 0, total = 0; 357 for (Section section: enrollment.getSections()) { 358 if (!section.hasTime()) noTimeSections ++; 359 total ++; 360 } 361 if (noTimeSections > 0) 362 weight *= (1.0 - iNoTimeFactor * noTimeSections / total); 363 } 364 if (enrollment.isCourseRequest() && iOnlineFactor != 0.0) { 365 int onlineSections = 0, total = 0; 366 for (Section section: enrollment.getSections()) { 367 if (section.isOnline()) onlineSections ++; 368 total ++; 369 } 370 if (onlineSections > 0) 371 weight *= (1.0 - iOnlineFactor * onlineSections / total); 372 } 373 if (enrollment.isCourseRequest() && iPastFactor != 0.0) { 374 int pastSections = 0, total = 0; 375 for (Section section: enrollment.getSections()) { 376 if (section.isPast()) pastSections ++; 377 total ++; 378 } 379 if (pastSections > 0) 380 weight *= (1.0 - iPastFactor * pastSections / total); 381 } 382 if (enrollment.getTruePriority() < enrollment.getPriority()) { 383 weight *= (1.0 - iReservationNotFollowedFactor); 384 } 385 if (enrollment.isCourseRequest() && iBalancingFactor != 0.0) { 386 double configUsed = enrollment.getConfig().getEnrollmentTotalWeight(assignment, enrollment.getRequest()) + enrollment.getRequest().getWeight(); 387 double disbalanced = 0; 388 double total = 0; 389 for (Section section: enrollment.getSections()) { 390 Subpart subpart = section.getSubpart(); 391 if (subpart.getSections().size() <= 1) continue; 392 double used = section.getEnrollmentTotalWeight(assignment, enrollment.getRequest()) + enrollment.getRequest().getWeight(); 393 // sections have limits -> desired size is section limit x (total enrollment / total limit) 394 // unlimited sections -> desired size is total enrollment / number of sections 395 double desired = (subpart.getLimit() > 0 396 ? section.getLimit() * (configUsed / subpart.getLimit()) 397 : configUsed / subpart.getSections().size()); 398 if (used > desired) 399 disbalanced += Math.min(enrollment.getRequest().getWeight(), used - desired) / enrollment.getRequest().getWeight(); 400 else 401 disbalanced -= Math.min(enrollment.getRequest().getWeight(), desired - used) / enrollment.getRequest().getWeight(); 402 total ++; 403 } 404 if (disbalanced > 0) 405 weight *= (1.0 - disbalanced / total * iBalancingFactor); 406 } 407 if (iMPP) { 408 double difference = getDifference(enrollment); 409 if (difference > 0.0) 410 weight *= (1.0 - difference * iPerturbationFactor); 411 } 412 if (iSelectionFactor != 0.0) { 413 double selection = getSelection(enrollment); 414 if (selection > 0.0) 415 weight *= (1.0 - selection * iSelectionFactor); 416 } 417 if (enrollment.isCourseRequest() && iGroupFactor != 0.0) { 418 double sameGroup = 0.0; int groupCount = 0; 419 for (RequestGroup g: ((CourseRequest)enrollment.getRequest()).getRequestGroups()) { 420 if (g.getCourse().equals(enrollment.getCourse())) { 421 sameGroup += g.getEnrollmentSpread(assignment, enrollment, iGroupBestRatio, iGroupFillRatio); 422 groupCount ++; 423 } 424 } 425 if (groupCount > 0) { 426 double difference = 1.0 - sameGroup / groupCount; 427 weight *= (1.0 - difference * iGroupFactor); 428 } 429 } 430 return round(weight); 431 } 432 433 public double getWeightAdditive(Assignment<Request, Enrollment> assignment, Enrollment enrollment) { 434 double base = getBaseWeight(assignment, enrollment); 435 double weight = 0.0; 436 if (enrollment.isCourseRequest() && iNoTimeFactor != 0.0) { 437 int noTimeSections = 0, total = 0; 438 for (Section section: enrollment.getSections()) { 439 if (!section.hasTime()) noTimeSections ++; 440 total ++; 441 } 442 if (noTimeSections > 0) 443 weight += iNoTimeFactor * noTimeSections / total; 444 } 445 if (enrollment.isCourseRequest() && iOnlineFactor != 0.0) { 446 int onlineSections = 0, total = 0; 447 for (Section section: enrollment.getSections()) { 448 if (section.isOnline()) onlineSections ++; 449 total ++; 450 } 451 if (onlineSections > 0) 452 weight += iOnlineFactor * onlineSections / total; 453 } 454 if (enrollment.isCourseRequest() && iPastFactor != 0.0) { 455 int pastSections = 0, total = 0; 456 for (Section section: enrollment.getSections()) { 457 if (section.isPast()) pastSections ++; 458 total ++; 459 } 460 if (pastSections > 0) 461 weight += iPastFactor * pastSections / total; 462 } 463 if (enrollment.getTruePriority() < enrollment.getPriority()) { 464 weight += iReservationNotFollowedFactor; 465 } 466 if (enrollment.isCourseRequest() && iBalancingFactor != 0.0) { 467 double configUsed = enrollment.getConfig().getEnrollmentTotalWeight(assignment, enrollment.getRequest()) + enrollment.getRequest().getWeight(); 468 double disbalanced = 0; 469 double total = 0; 470 for (Section section: enrollment.getSections()) { 471 Subpart subpart = section.getSubpart(); 472 if (subpart.getSections().size() <= 1) continue; 473 double used = section.getEnrollmentTotalWeight(assignment, enrollment.getRequest()) + enrollment.getRequest().getWeight(); 474 // sections have limits -> desired size is section limit x (total enrollment / total limit) 475 // unlimited sections -> desired size is total enrollment / number of sections 476 double desired = (subpart.getLimit() > 0 477 ? section.getLimit() * (configUsed / subpart.getLimit()) 478 : configUsed / subpart.getSections().size()); 479 if (used > desired) 480 disbalanced += Math.min(enrollment.getRequest().getWeight(), used - desired) / enrollment.getRequest().getWeight(); 481 else 482 disbalanced -= Math.min(enrollment.getRequest().getWeight(), desired - used) / enrollment.getRequest().getWeight(); 483 total ++; 484 } 485 if (disbalanced > 0) 486 weight += disbalanced / total * iBalancingFactor; 487 } 488 if (iMPP) { 489 double difference = getDifference(enrollment); 490 if (difference > 0.0) 491 weight += difference * iPerturbationFactor; 492 } 493 if (iSelectionFactor != 0.0) { 494 double selection = getSelection(enrollment); 495 if (selection > 0.0) 496 weight += selection * iSelectionFactor; 497 } 498 if (enrollment.isCourseRequest() && iGroupFactor != 0.0) { 499 double sameGroup = 0.0; int groupCount = 0; 500 for (RequestGroup g: ((CourseRequest)enrollment.getRequest()).getRequestGroups()) { 501 if (g.getCourse().equals(enrollment.getCourse())) { 502 sameGroup += g.getEnrollmentSpread(assignment, enrollment, iGroupBestRatio, iGroupFillRatio); 503 groupCount ++; 504 } 505 } 506 if (groupCount > 0) { 507 double difference = 1.0 - sameGroup / groupCount; 508 weight += difference * iGroupFactor; 509 } 510 } 511 return round(base * (1.0 - weight)); 512 } 513 514 @Override 515 public double getDistanceConflictWeight(Assignment<Request, Enrollment> assignment, DistanceConflict.Conflict c) { 516 if (iAdditiveWeights) { 517 if (c.getR1().getPriority() < c.getR2().getPriority()) { 518 return round(getBaseWeight(assignment, c.getE2()) * (c.getStudent().isNeedShortDistances() ? iShortDistanceConflict : iDistanceConflict)); 519 } else { 520 return round(getBaseWeight(assignment, c.getE1()) * (c.getStudent().isNeedShortDistances() ? iShortDistanceConflict : iDistanceConflict)); 521 } 522 } else { 523 if (c.getR1().getPriority() < c.getR2().getPriority()) { 524 return round(getWeightMultiplicative(assignment, c.getE2()) * (c.getStudent().isNeedShortDistances() ? iShortDistanceConflict : iDistanceConflict)); 525 } else { 526 return round(getWeightMultiplicative(assignment, c.getE1()) * (c.getStudent().isNeedShortDistances() ? iShortDistanceConflict : iDistanceConflict)); 527 } 528 } 529 } 530 531 @Override 532 public double getTimeOverlapConflictWeight(Assignment<Request, Enrollment> assignment, Enrollment e, TimeOverlapsCounter.Conflict c) { 533 if (e == null || e.getRequest() == null) return 0.0; 534 double toc = Math.min(iTimeOverlapFactor * c.getShare() / e.getNrSlots(), iTimeOverlapMaxLimit); 535 if (iAdditiveWeights) { 536 return round(getBaseWeight(assignment, e) * toc); 537 } else { 538 return round(getWeightMultiplicative(assignment, e) * toc); 539 } 540 } 541 542 @Override 543 public double getWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment, Set<DistanceConflict.Conflict> distanceConflicts, Set<TimeOverlapsCounter.Conflict> timeOverlappingConflicts) { 544 if (iAdditiveWeights) { 545 double base = getBaseWeight(assignment, enrollment); 546 double dc = 0.0; 547 if (distanceConflicts != null) { 548 for (DistanceConflict.Conflict c: distanceConflicts) { 549 Enrollment other = (c.getE1().equals(enrollment) ? c.getE2() : c.getE1()); 550 if (other.getRequest().getPriority() <= enrollment.getRequest().getPriority()) 551 dc += base * (c.getStudent().isNeedShortDistances() ? iShortDistanceConflict : iDistanceConflict); 552 else 553 dc += getBaseWeight(assignment, other) * (c.getStudent().isNeedShortDistances() ? iShortDistanceConflict : iDistanceConflict); 554 } 555 } 556 double toc = 0.0; 557 if (timeOverlappingConflicts != null) { 558 for (TimeOverlapsCounter.Conflict c: timeOverlappingConflicts) { 559 toc += base * Math.min(iTimeOverlapFactor * c.getShare() / enrollment.getNrSlots(), iTimeOverlapMaxLimit); 560 Enrollment other = (c.getE1().equals(enrollment) ? c.getE2() : c.getE1()); 561 if (other.getRequest() != null) 562 toc += getBaseWeight(assignment, other) * Math.min(iTimeOverlapFactor * c.getShare() / other.getNrSlots(), iTimeOverlapMaxLimit); 563 } 564 } 565 return round(getWeight(assignment, enrollment) - dc - toc); 566 } else { 567 double base = getWeightMultiplicative(assignment, enrollment); 568 double dc = 0.0; 569 if (distanceConflicts != null) { 570 for (DistanceConflict.Conflict c: distanceConflicts) { 571 Enrollment other = (c.getE1().equals(enrollment) ? c.getE2() : c.getE1()); 572 if (other.getRequest().getPriority() <= enrollment.getRequest().getPriority()) 573 dc += base * (c.getStudent().isNeedShortDistances() ? iShortDistanceConflict : iDistanceConflict); 574 else 575 dc += getWeightMultiplicative(assignment, other) * (c.getStudent().isNeedShortDistances() ? iShortDistanceConflict : iDistanceConflict); 576 } 577 } 578 double toc = 0.0; 579 if (timeOverlappingConflicts != null) { 580 for (TimeOverlapsCounter.Conflict c: timeOverlappingConflicts) { 581 toc += base * Math.min(iTimeOverlapFactor * c.getShare() / enrollment.getNrSlots(), iTimeOverlapMaxLimit); 582 Enrollment other = (c.getE1().equals(enrollment) ? c.getE2() : c.getE1()); 583 if (other.getRequest() != null) 584 toc += getWeightMultiplicative(assignment, other) * Math.min(iTimeOverlapFactor * c.getShare() / other.getNrSlots(), iTimeOverlapMaxLimit); 585 } 586 } 587 return round(base - dc - toc); 588 } 589 } 590 591 592 @Override 593 public boolean isBetterThanBestSolution(Solution<Request, Enrollment> currentSolution) { 594 if (currentSolution.getBestInfo() == null) return true; 595 if (iMaximizeAssignment) { 596 long acr = Math.round(((StudentSectioningModel)currentSolution.getModel()).getContext(currentSolution.getAssignment()).getAssignedCourseRequestWeight()); 597 long bcr = Math.round(((StudentSectioningModel)currentSolution.getModel()).getBestAssignedCourseRequestWeight()); 598 if (acr != bcr) 599 return acr > bcr; 600 } 601 return ((StudentSectioningModel)currentSolution.getModel()).getTotalValue(currentSolution.getAssignment(), iPreciseComparison) < currentSolution.getBestValue(); 602 } 603 604 @Override 605 public boolean isFreeTimeAllowOverlaps() { 606 return false; 607 } 608 609 /** 610 * Test case -- run to see the weights for a few courses 611 * @param args program arguments 612 */ 613 public static void main(String[] args) { 614 PriorityStudentWeights pw = new PriorityStudentWeights(new DataProperties()); 615 DecimalFormat df = new DecimalFormat("0.000000"); 616 Student s = new Student(0l); 617 new CourseRequest(1l, 0, false, s, ToolBox.toList( 618 new Course(1, "A", "1", new Offering(0, "A")), 619 new Course(1, "A", "2", new Offering(0, "A")), 620 new Course(1, "A", "3", new Offering(0, "A"))), false, null); 621 new CourseRequest(2l, 1, false, s, ToolBox.toList( 622 new Course(1, "B", "1", new Offering(0, "B")), 623 new Course(1, "B", "2", new Offering(0, "B")), 624 new Course(1, "B", "3", new Offering(0, "B"))), false, null); 625 new CourseRequest(3l, 2, false, s, ToolBox.toList( 626 new Course(1, "C", "1", new Offering(0, "C")), 627 new Course(1, "C", "2", new Offering(0, "C")), 628 new Course(1, "C", "3", new Offering(0, "C"))), false, null); 629 new CourseRequest(4l, 3, false, s, ToolBox.toList( 630 new Course(1, "D", "1", new Offering(0, "D")), 631 new Course(1, "D", "2", new Offering(0, "D")), 632 new Course(1, "D", "3", new Offering(0, "D"))), false, null); 633 new CourseRequest(5l, 4, false, s, ToolBox.toList( 634 new Course(1, "E", "1", new Offering(0, "E")), 635 new Course(1, "E", "2", new Offering(0, "E")), 636 new Course(1, "E", "3", new Offering(0, "E"))), false, null); 637 new CourseRequest(6l, 5, true, s, ToolBox.toList( 638 new Course(1, "F", "1", new Offering(0, "F")), 639 new Course(1, "F", "2", new Offering(0, "F")), 640 new Course(1, "F", "3", new Offering(0, "F"))), false, null); 641 new CourseRequest(7l, 6, true, s, ToolBox.toList( 642 new Course(1, "G", "1", new Offering(0, "G")), 643 new Course(1, "G", "2", new Offering(0, "G")), 644 new Course(1, "G", "3", new Offering(0, "G"))), false, null); 645 646 Assignment<Request, Enrollment> assignment = new DefaultSingleAssignment<Request, Enrollment>(); 647 Placement p = new Placement(null, new TimeLocation(1, 90, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>()); 648 for (Request r: s.getRequests()) { 649 CourseRequest cr = (CourseRequest)r; 650 double[] w = new double[] {0.0, 0.0, 0.0}; 651 for (int i = 0; i < cr.getCourses().size(); i++) { 652 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 653 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 654 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 655 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 656 w[i] = pw.getWeight(assignment, e, null, null); 657 } 658 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 659 } 660 661 System.out.println("With one distance conflict:"); 662 for (Request r: s.getRequests()) { 663 CourseRequest cr = (CourseRequest)r; 664 double[] w = new double[] {0.0, 0.0, 0.0}; 665 for (int i = 0; i < cr.getCourses().size(); i++) { 666 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 667 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 668 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 669 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 670 Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>(); 671 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next())); 672 w[i] = pw.getWeight(assignment, e, dc, null); 673 } 674 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 675 } 676 677 System.out.println("With two distance conflicts:"); 678 for (Request r: s.getRequests()) { 679 CourseRequest cr = (CourseRequest)r; 680 double[] w = new double[] {0.0, 0.0, 0.0}; 681 for (int i = 0; i < cr.getCourses().size(); i++) { 682 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 683 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 684 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 685 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 686 Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>(); 687 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next())); 688 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, 689 new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null))); 690 w[i] = pw.getWeight(assignment, e, dc, null); 691 } 692 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 693 } 694 695 System.out.println("With 25% time overlapping conflict:"); 696 for (Request r: s.getRequests()) { 697 CourseRequest cr = (CourseRequest)r; 698 double[] w = new double[] {0.0, 0.0, 0.0}; 699 for (int i = 0; i < cr.getCourses().size(); i++) { 700 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 701 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 702 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 703 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 704 Set<TimeOverlapsCounter.Conflict> toc = new HashSet<TimeOverlapsCounter.Conflict>(); 705 toc.add(new TimeOverlapsCounter.Conflict(s, 3, e, sections.iterator().next(), e, sections.iterator().next())); 706 w[i] = pw.getWeight(assignment, e, null, toc); 707 } 708 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 709 } 710 711 System.out.println("Disbalanced sections (by 2 / 10 students):"); 712 for (Request r: s.getRequests()) { 713 CourseRequest cr = (CourseRequest)r; 714 double[] w = new double[] {0.0, 0.0, 0.0}; 715 for (int i = 0; i < cr.getCourses().size(); i++) { 716 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 717 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 718 Subpart x = new Subpart(0, "Lec", "Lec", cfg, null); 719 Section a = new Section(0, 10, "x", x, p, null); 720 new Section(1, 10, "y", x, p, null); 721 sections.add(a); 722 a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 723 a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 724 cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 725 cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 726 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 727 w[i] = pw.getWeight(assignment, e, null, null); 728 } 729 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 730 } 731 732 System.out.println("Same choice sections:"); 733 pw.iMPP = true; 734 for (Request r: s.getRequests()) { 735 CourseRequest cr = (CourseRequest)r; 736 double[] w = new double[] {0.0, 0.0, 0.0}; 737 for (int i = 0; i < cr.getCourses().size(); i++) { 738 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 739 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 740 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 741 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 742 Set<SctAssignment> other = new HashSet<SctAssignment>(); 743 other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 744 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 745 w[i] = pw.getWeight(assignment, e, null, null); 746 } 747 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 748 } 749 750 System.out.println("Same time sections:"); 751 for (Request r: s.getRequests()) { 752 CourseRequest cr = (CourseRequest)r; 753 double[] w = new double[] {0.0, 0.0, 0.0}; 754 for (int i = 0; i < cr.getCourses().size(); i++) { 755 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 756 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 757 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 758 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 759 Set<SctAssignment> other = new HashSet<SctAssignment>(); 760 other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, new Instructor(1l, null, "Josef Novak", null))); 761 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 762 w[i] = pw.getWeight(assignment, e, null, null); 763 } 764 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 765 } 766 767 System.out.println("Different time sections:"); 768 Placement q = new Placement(null, new TimeLocation(1, 102, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>()); 769 for (Request r: s.getRequests()) { 770 CourseRequest cr = (CourseRequest)r; 771 double[] w = new double[] {0.0, 0.0, 0.0}; 772 for (int i = 0; i < cr.getCourses().size(); i++) { 773 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 774 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 775 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 776 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 777 Set<SctAssignment> other = new HashSet<SctAssignment>(); 778 other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), q, null)); 779 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 780 w[i] = pw.getWeight(assignment, e, null, null); 781 } 782 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 783 } 784 785 System.out.println("Two sections, one same choice, one same time:"); 786 for (Request r: s.getRequests()) { 787 CourseRequest cr = (CourseRequest)r; 788 double[] w = new double[] {0.0, 0.0, 0.0}; 789 for (int i = 0; i < cr.getCourses().size(); i++) { 790 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 791 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 792 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 793 sections.add(new Section(1, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, null)); 794 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 795 Set<SctAssignment> other = new HashSet<SctAssignment>(); 796 other.add(new Section(2, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 797 other.add(new Section(3, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, null, new Instructor(1l, null, "Josef Novak", null))); 798 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 799 w[i] = pw.getWeight(assignment, e, null, null); 800 } 801 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 802 } 803 804 } 805 806 @Override 807 public double getWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment, Set<StudentQuality.Conflict> qualityConflicts) { 808 if (iAdditiveWeights) { 809 double base = getBaseWeight(assignment, enrollment); 810 double penalty = 0.0; 811 if (qualityConflicts != null) { 812 for (StudentQuality.Conflict c: qualityConflicts) { 813 switch (c.getType().getType()) { 814 case REQUEST: 815 if (enrollment.isCourseRequest()) 816 penalty += base * iQalityWeights[c.getType().ordinal()] * c.getWeight(enrollment); 817 break; 818 case BOTH: 819 Enrollment other = c.getOther(enrollment); 820 penalty += base * iQalityWeights[c.getType().ordinal()] * c.getWeight(enrollment); 821 penalty += getBaseWeight(assignment, other) * iQalityWeights[c.getType().ordinal()] * c.getWeight(other); 822 break; 823 case LOWER: 824 other = c.getOther(enrollment); 825 if (other.getRequest().getPriority() <= enrollment.getRequest().getPriority()) 826 penalty += base * iQalityWeights[c.getType().ordinal()] * c.getWeight(enrollment); 827 else 828 penalty += getBaseWeight(assignment, other) * iQalityWeights[c.getType().ordinal()] * c.getWeight(other); 829 break; 830 case HIGHER: 831 other = c.getOther(enrollment); 832 if (other.getRequest().getPriority() >= enrollment.getRequest().getPriority()) 833 penalty += base * iQalityWeights[c.getType().ordinal()] * c.getWeight(enrollment); 834 else 835 penalty += getBaseWeight(assignment, other) * iQalityWeights[c.getType().ordinal()] * c.getWeight(other); 836 } 837 } 838 } 839 return round(getWeight(assignment, enrollment) - penalty); 840 } else { 841 double base = getWeightMultiplicative(assignment, enrollment); 842 double penalty = 0.0; 843 if (qualityConflicts != null) { 844 for (StudentQuality.Conflict c: qualityConflicts) { 845 Enrollment other = c.getOther(enrollment); 846 switch (c.getType().getType()) { 847 case REQUEST: 848 if (enrollment.isCourseRequest()) 849 penalty += base * iQalityWeights[c.getType().ordinal()] * c.getWeight(enrollment); 850 else if (other.isCourseRequest()) 851 penalty += getWeightMultiplicative(assignment, other) * iQalityWeights[c.getType().ordinal()] * c.getWeight(other); 852 break; 853 case BOTH: 854 penalty += base * iQalityWeights[c.getType().ordinal()] * c.getWeight(enrollment); 855 if (other.getRequest() != null) 856 penalty += getWeightMultiplicative(assignment, other) * iQalityWeights[c.getType().ordinal()] * c.getWeight(other); 857 break; 858 case LOWER: 859 other = c.getOther(enrollment); 860 if (other.getRequest().getPriority() <= enrollment.getRequest().getPriority()) 861 penalty += base * iQalityWeights[c.getType().ordinal()] * c.getWeight(enrollment); 862 else if (other.getRequest() != null) 863 penalty += getWeightMultiplicative(assignment, other) * iQalityWeights[c.getType().ordinal()] * c.getWeight(other); 864 break; 865 case HIGHER: 866 other = c.getOther(enrollment); 867 if (other.getRequest().getPriority() >= enrollment.getRequest().getPriority()) 868 penalty += base * iQalityWeights[c.getType().ordinal()] * c.getWeight(enrollment); 869 else if (other.getRequest() != null) 870 penalty += getWeightMultiplicative(assignment, other) * iQalityWeights[c.getType().ordinal()] * c.getWeight(other); 871 } 872 } 873 } 874 return round(base - penalty); 875 } 876 } 877 878 @Override 879 public double getStudentQualityConflictWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment, Conflict conflict) { 880 switch (conflict.getType().getType()) { 881 case BOTH: 882 if (enrollment == null || enrollment.getRequest() == null) return 0.0; 883 if (iAdditiveWeights) { 884 return round(getBaseWeight(assignment, enrollment) * iQalityWeights[conflict.getType().ordinal()] * conflict.getWeight(enrollment)); 885 } else { 886 return round(getWeightMultiplicative(assignment, enrollment) * iQalityWeights[conflict.getType().ordinal()] * conflict.getWeight(enrollment)); 887 } 888 case REQUEST: 889 if (enrollment == null || enrollment.getRequest() == null || !enrollment.isCourseRequest()) return 0.0; 890 if (iAdditiveWeights) { 891 return round(getBaseWeight(assignment, enrollment) * iQalityWeights[conflict.getType().ordinal()] * conflict.getWeight(enrollment)); 892 } else { 893 return round(getWeightMultiplicative(assignment, enrollment) * iQalityWeights[conflict.getType().ordinal()] * conflict.getWeight(enrollment)); 894 } 895 case LOWER: 896 if (iAdditiveWeights) { 897 if (conflict.getR1().getPriority() < conflict.getR2().getPriority()) { 898 return round(getBaseWeight(assignment, conflict.getE2()) * iQalityWeights[conflict.getType().ordinal()] * conflict.getWeight(conflict.getE2())); 899 } else { 900 return round(getBaseWeight(assignment, conflict.getE1()) * iQalityWeights[conflict.getType().ordinal()] * conflict.getWeight(conflict.getE1())); 901 } 902 } else { 903 if (conflict.getR1().getPriority() < conflict.getR2().getPriority()) { 904 return round(getWeightMultiplicative(assignment, conflict.getE2()) * iQalityWeights[conflict.getType().ordinal()] * conflict.getWeight(conflict.getE2())); 905 } else { 906 return round(getWeightMultiplicative(assignment, conflict.getE1()) * iQalityWeights[conflict.getType().ordinal()] * conflict.getWeight(conflict.getE1())); 907 } 908 } 909 case HIGHER: 910 if (iAdditiveWeights) { 911 if (conflict.getR1().getPriority() > conflict.getR2().getPriority()) { 912 return round(getBaseWeight(assignment, conflict.getE2()) * iQalityWeights[conflict.getType().ordinal()] * conflict.getWeight(conflict.getE2())); 913 } else { 914 return round(getBaseWeight(assignment, conflict.getE1()) * iQalityWeights[conflict.getType().ordinal()] * conflict.getWeight(conflict.getE1())); 915 } 916 } else { 917 if (conflict.getR1().getPriority() < conflict.getR2().getPriority()) { 918 return round(getWeightMultiplicative(assignment, conflict.getE2()) * iQalityWeights[conflict.getType().ordinal()] * conflict.getWeight(conflict.getE2())); 919 } else { 920 return round(getWeightMultiplicative(assignment, conflict.getE1()) * iQalityWeights[conflict.getType().ordinal()] * conflict.getWeight(conflict.getE1())); 921 } 922 } 923 default: 924 return 0.0; 925 } 926 } 927}