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