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.solver.Solver; 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 boolean init(Solver<Lecture, Placement> solver) { 050 super.init(solver); 051 052 iWeight = solver.getProperties().getPropertyDouble("FlexibleConstraint.Weight", 1.0d); 053 iDebug = solver.getProperties().getPropertyBoolean("FlexibleConstraint.Debug", true); 054 return true; 055 } 056 057 @Override 058 public String getPlacementSelectionWeightName() { 059 return "Placement.FlexibleConstrPreferenceWeight"; 060 } 061 062 @Override 063 public void getInfo(Assignment<Lecture, Placement> assignment, Map<String, String> info) { 064 TimetableModel m = (TimetableModel)getModel(); 065 if (m.getFlexibleConstraints().isEmpty()) return; 066 067 for (FlexibleConstraintType type: FlexibleConstraintType.values()) { 068 StringBuilder debug = null; 069 int violated = 0, constraints = 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 if (iDebug) { 077 if (debug == null) 078 debug = new StringBuilder(c.getOwner() + " (" + sDoubleFormat.format(c.getNrViolations(assignment, new HashSet<Placement>(), null)) + ")"); 079 else 080 debug.append("; " + c.getOwner() + " (" + sDoubleFormat.format(c.getNrViolations(assignment, new HashSet<Placement>(), null)) + ")"); 081 } 082 } 083 } 084 } 085 086 if (constraints > 0) { 087 info.put(type.getName() + " Constraints", getPerc(violated, 0, constraints) + "% (" + violated + ")"); 088 if (iDebug && violated > 0) info.put(type.getName() + " Violations", debug.toString()); 089 } 090 } 091 } 092 093 @Override 094 public void getInfo(Assignment<Lecture, Placement> assignment, Map<String, String> info, Collection<Lecture> variables) { 095 for (FlexibleConstraintType type: FlexibleConstraintType.values()) { 096 097 Set<FlexibleConstraint> constraints = new HashSet<FlexibleConstraint>(); 098 for (Lecture lecture : variables) { 099 for (FlexibleConstraint c : lecture.getFlexibleGroupConstraints()) { 100 if (type.equals(c.getType())) constraints.add(c); 101 } 102 } 103 104 if (!constraints.isEmpty()) { 105 int violated = 0; 106 StringBuilder debug = null; 107 for (FlexibleConstraint c : constraints) { 108 if (c.getContext(assignment).getPreference() > 0) { 109 violated++; 110 if (iDebug) { 111 if (debug == null) 112 debug = new StringBuilder(c.getOwner()); 113 else 114 debug.append("; " + c.getOwner()); 115 } 116 } 117 } 118 info.put(type.getName() + " Constraints", getPerc(violated, 0, constraints.size()) + "% (" + violated + ")"); 119 if (iDebug && violated > 0) info.put(type.getName() + " Violations", debug.toString()); 120 } 121 } 122 } 123 124 @Override 125 public double getValue(Assignment<Lecture, Placement> assignment, Collection<Lecture> variables) { 126 Set<FlexibleConstraint> flexibleConstraints = new HashSet<FlexibleConstraint>(); 127 for (Lecture lecture: variables){ 128 flexibleConstraints.addAll(lecture.getFlexibleGroupConstraints()); 129 } 130 int ret = 0; 131 for (FlexibleConstraint gc: flexibleConstraints){ 132 ret += gc.getContext(assignment).getPreference(); 133 } 134 return ret; 135 } 136 137 @Override 138 public double getValue(Assignment<Lecture, Placement> assignment, Placement value, Set<Placement> conflicts) { 139 HashMap<Lecture, Placement> assignments = new HashMap<Lecture, Placement>(); 140 assignments.put(value.variable(), value); 141 142 double ret = 0.0; 143 for (FlexibleConstraint gc : value.variable().getFlexibleGroupConstraints()) 144 ret += gc.getCurrentPreference(assignment, conflicts, assignments); 145 146 assignments.put(value.variable(), null); 147 for (FlexibleConstraint gc : value.variable().getFlexibleGroupConstraints()) 148 ret -= gc.getCurrentPreference(assignment, conflicts, assignments); 149 150 return ret; 151 } 152}