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 * @version CourseTT 1.3 (University Course Timetabling)<br> 024 * Copyright (C) 2012 Matej Lukac<br> 025 * <br> 026 * This library is free software; you can redistribute it and/or modify 027 * it under the terms of the GNU Lesser General Public License as 028 * published by the Free Software Foundation; either version 3 of the 029 * License, or (at your option) any later version. <br> 030 * <br> 031 * This library is distributed in the hope that it will be useful, but 032 * WITHOUT ANY WARRANTY; without even the implied warranty of 033 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 034 * Lesser General Public License for more details. <br> 035 * <br> 036 * You should have received a copy of the GNU Lesser General Public 037 * License along with this library; if not see 038 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 039 */ 040public class FlexibleConstraintCriterion extends TimetablingCriterion { 041 042 private boolean iDebug; 043 044 public FlexibleConstraintCriterion(){ 045 setValueUpdateType(ValueUpdateType.NoUpdate); 046 } 047 048 @Override 049 public void configure(DataProperties properties) { 050 super.configure(properties); 051 iWeight = properties.getPropertyDouble("FlexibleConstraint.Weight", 1.0d); 052 iDebug = properties.getPropertyBoolean("FlexibleConstraint.Debug", true); 053 } 054 055 @Override 056 public String getPlacementSelectionWeightName() { 057 return "Placement.FlexibleConstrPreferenceWeight"; 058 } 059 060 @Override 061 public void getInfo(Assignment<Lecture, Placement> assignment, 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.getContext(assignment).getPreference() > 0) { 073 violated++; 074 if (iDebug) { 075 if (debug == null) 076 debug = new StringBuilder(c.getOwner() + " (" + sDoubleFormat.format(c.getNrViolations(assignment, new HashSet<Placement>(), null)) + ")"); 077 else 078 debug.append("; " + c.getOwner() + " (" + sDoubleFormat.format(c.getNrViolations(assignment, 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(Assignment<Lecture, Placement> assignment, 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.getContext(assignment).getPreference() > 0) { 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(Assignment<Lecture, Placement> assignment, 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.getContext(assignment).getPreference(); 131 } 132 return ret; 133 } 134 135 @Override 136 public double getValue(Assignment<Lecture, Placement> assignment, 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(assignment, conflicts, assignments); 143 144 assignments.put(value.variable(), null); 145 for (FlexibleConstraint gc : value.variable().getFlexibleGroupConstraints()) 146 ret -= gc.getCurrentPreference(assignment, conflicts, assignments); 147 148 return ret; 149 } 150}