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