001package net.sf.cpsolver.coursett.criteria; 002 003import java.util.Collection; 004import java.util.HashMap; 005import java.util.HashSet; 006import java.util.Map; 007import java.util.Set; 008 009import net.sf.cpsolver.coursett.constraint.FlexibleConstraint; 010import net.sf.cpsolver.coursett.constraint.FlexibleConstraint.FlexibleConstraintType; 011import net.sf.cpsolver.coursett.model.Lecture; 012import net.sf.cpsolver.coursett.model.Placement; 013import net.sf.cpsolver.coursett.model.TimetableModel; 014import net.sf.cpsolver.ifs.solver.Solver; 015 016/** 017 * The class encapsulates various flexible constraints concerning compact timetables of 018 * instructors. 019 * 020 * <br> 021 * @version CourseTT 1.2 (University Course Timetabling)<br> 022 * Copyright (C) 2012 Matej Lukac<br> 023 * <br> 024 * This library is free software; you can redistribute it and/or modify 025 * it under the terms of the GNU Lesser General Public License as 026 * published by the Free Software Foundation; either version 3 of the 027 * License, or (at your option) any later version. <br> 028 * <br> 029 * This library is distributed in the hope that it will be useful, but 030 * WITHOUT ANY WARRANTY; without even the implied warranty of 031 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 032 * Lesser General Public License for more details. <br> 033 * <br> 034 * You should have received a copy of the GNU Lesser General Public 035 * License along with this library; if not see 036 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 037 */ 038public class FlexibleConstraintCriterion extends TimetablingCriterion { 039 040 private boolean iDebug; 041 042 public FlexibleConstraintCriterion(){ 043 iValueUpdateType = ValueUpdateType.NoUpdate; 044 } 045 046 @Override 047 public boolean init(Solver<Lecture, Placement> solver) { 048 super.init(solver); 049 050 iWeight = solver.getProperties().getPropertyDouble("FlexibleConstraint.Weight", 1.0d); 051 iDebug = solver.getProperties().getPropertyBoolean("FlexibleConstraint.Debug", true); 052 return true; 053 } 054 055 @Override 056 public String getPlacementSelectionWeightName() { 057 return "Placement.FlexibleConstrPreferenceWeight"; 058 } 059 060 @Override 061 public void getInfo(Map<String, String> info) { 062 TimetableModel m = (TimetableModel)getModel(); 063 if (m.getFlexibleConstraints().isEmpty()) return; 064 065 for (FlexibleConstraintType type: FlexibleConstraintType.values()) { 066 StringBuilder debug = null; 067 int violated = 0, constraints = 0; 068 069 for (FlexibleConstraint c : m.getFlexibleConstraints()) { 070 if (type.equals(c.getType())) { 071 constraints ++; 072 if (!c.isConsistent(null, null)) { 073 violated++; 074 if (iDebug) { 075 if (debug == null) 076 debug = new StringBuilder(c.getOwner() + " (" + sDoubleFormat.format(c.getNrViolations(new HashSet<Placement>(), null)) + ")"); 077 else 078 debug.append("; " + c.getOwner() + " (" + sDoubleFormat.format(c.getNrViolations(new HashSet<Placement>(), null)) + ")"); 079 } 080 } 081 } 082 } 083 084 if (constraints > 0) { 085 info.put(type.getName() + " Constraints", getPerc(violated, 0, constraints) + "% (" + violated + ")"); 086 if (iDebug && violated > 0) info.put(type.getName() + " Violations", debug.toString()); 087 } 088 } 089 } 090 091 @Override 092 public void getInfo(Map<String, String> info, Collection<Lecture> variables) { 093 for (FlexibleConstraintType type: FlexibleConstraintType.values()) { 094 095 Set<FlexibleConstraint> constraints = new HashSet<FlexibleConstraint>(); 096 for (Lecture lecture : variables) { 097 for (FlexibleConstraint c : lecture.getFlexibleGroupConstraints()) { 098 if (type.equals(c.getType())) constraints.add(c); 099 } 100 } 101 102 if (!constraints.isEmpty()) { 103 int violated = 0; 104 StringBuilder debug = null; 105 for (FlexibleConstraint c : constraints) { 106 if (!c.isConsistent(null, null)) { 107 violated++; 108 if (iDebug) { 109 if (debug == null) 110 debug = new StringBuilder(c.getOwner()); 111 else 112 debug.append("; " + c.getOwner()); 113 } 114 } 115 } 116 info.put(type.getName() + " Constraints", getPerc(violated, 0, constraints.size()) + "% (" + violated + ")"); 117 if (iDebug && violated > 0) info.put(type.getName() + " Violations", debug.toString()); 118 } 119 } 120 } 121 122 @Override 123 public double getValue(Collection<Lecture> variables) { 124 Set<FlexibleConstraint> flexibleConstraints = new HashSet<FlexibleConstraint>(); 125 for (Lecture lecture: variables){ 126 flexibleConstraints.addAll(lecture.getFlexibleGroupConstraints()); 127 } 128 int ret = 0; 129 for (FlexibleConstraint gc: flexibleConstraints){ 130 ret += gc.getCurrentPreference(null, null); 131 } 132 return ret; 133 } 134 135 @Override 136 public double getValue(Placement value, Set<Placement> conflicts) { 137 HashMap<Lecture, Placement> assignments = new HashMap<Lecture, Placement>(); 138 assignments.put(value.variable(), value); 139 140 double ret = 0.0; 141 for (FlexibleConstraint gc : value.variable().getFlexibleGroupConstraints()) 142 ret += gc.getCurrentPreference(conflicts, assignments); 143 144 assignments.put(value.variable(), null); 145 for (FlexibleConstraint gc : value.variable().getFlexibleGroupConstraints()) 146 ret -= gc.getCurrentPreference(conflicts, assignments); 147 148 return ret; 149 } 150}