001 package net.sf.cpsolver.ifs.dbt; 002 003 004 import java.util.*; 005 006 import net.sf.cpsolver.ifs.extension.*; 007 import net.sf.cpsolver.ifs.model.*; 008 import net.sf.cpsolver.ifs.solver.*; 009 import net.sf.cpsolver.ifs.util.*; 010 011 /** 012 * Maintenance of arc consistency in dynamic backtracking. 013 * <br><br> 014 * The difference between {@link MacPropagation} and this DBT propagation is that all not-assigned values 015 * of an assigned variable are marked as nogood. Also, when a dead end is reached, unassignment or failure 016 * takes place. 017 * <br><br> 018 * This IFS solver extension is to be used only in case of dynamic backtracking and it has no parameters. 019 * 020 * 021 * @version 022 * IFS 1.1 (Iterative Forward Search)<br> 023 * Copyright (C) 2006 Tomáš Müller<br> 024 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 025 * Lazenska 391, 76314 Zlin, Czech Republic<br> 026 * <br> 027 * This library is free software; you can redistribute it and/or 028 * modify it under the terms of the GNU Lesser General Public 029 * License as published by the Free Software Foundation; either 030 * version 2.1 of the License, or (at your option) any later version. 031 * <br><br> 032 * This library is distributed in the hope that it will be useful, 033 * but 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. 036 * <br><br> 037 * You should have received a copy of the GNU Lesser General Public 038 * License along with this library; if not, write to the Free Software 039 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 040 * 041 */ 042 public class DbtPropagation extends MacPropagation implements SolverListener { 043 private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(DbtPropagation.class); 044 045 /** 046 * Constructor. No parameter is taken from properties. 047 */ 048 public DbtPropagation(Solver solver, DataProperties properties) { 049 super(solver, properties); 050 solver.addSolverListener(this); 051 } 052 053 /** 054 * Propagation takes place every time a value is assigned to a variable. 055 * <br><br> 056 * <li>Prints a warning if the value is nogood (should not never happen), 057 * <li>sets all other values of the variable to nogood (explanation is the assigned value itself), 058 * <li>runs propagation. 059 * 060 * @see MacPropagation#propagate(Variable) 061 */ 062 public void afterAssigned(long iteration, Value value) { 063 iIteration = iteration; 064 if (!isGood(value)) { 065 sLogger.warn(value.variable().getName()+" = "+value.getName()+" -- not good value assigned (noGood:"+noGood(value)+")"); 066 setGood(value); 067 } 068 069 HashSet noGood = new HashSet(1); 070 071 noGood.add(value); 072 for (Enumeration i = value.variable().values().elements(); i.hasMoreElements();) { 073 Value anotherValue = (Value) i.nextElement(); 074 if (anotherValue.equals(value) || !isGood(anotherValue)) continue; 075 setNoGood(anotherValue, noGood); 076 } 077 propagate(value.variable()); 078 } 079 080 /** 081 * Undo propagation when a value is unassigned. 082 * <br><br> 083 * <li>Prints an error if the value is nogood (should not never happen), 084 * <li>runs propagation undo. 085 * 086 * @see MacPropagation#undoPropagate(Variable) 087 */ 088 public void afterUnassigned(long iteration, Value value) { 089 iIteration = iteration; 090 if (!isGood(value)) { 091 sLogger.error(value.variable().getName()+" = "+value.getName()+" -- not good value unassigned (noGood:"+noGood(value)+")"); 092 } 093 undoPropagate(value.variable()); 094 } 095 096 /** 097 * If no variable is selected (all variables are assinged), unassign the last assigned variable. 098 * <br><br> 099 * Do not allow to select an assigned variable. 100 * <br><br> 101 * If no variable is selected (because all variables are assigned, see {@link DbtVariableSelection}): 102 * <ul> 103 * <li> find the last assigned variable and 104 * <li> unassign it (explanation is a union of assignments of all other variables). 105 * </ul> 106 * 107 * @see DbtVariableSelection#selectVariable(Solution) 108 */ 109 public boolean variableSelected(long iteration, Variable variable) { 110 if (variable == null) { 111 sLogger.debug("No variable selected -> backtrack."); 112 Variable lastVariable = null; 113 114 for (Enumeration i = getModel().assignedVariables().elements(); i.hasMoreElements();) { 115 Variable var = (Variable) i.nextElement(); 116 117 if (lastVariable == null || lastVariable.getAssignment().lastAssignmentIteration()<var.getAssignment().lastAssignmentIteration()) { 118 lastVariable = var; 119 } 120 } 121 if (lastVariable == null) { 122 sLogger.error("No assignment -> fail"); 123 getSolver().stopSolver(); 124 return false; 125 } 126 sLogger.debug("Unassign:" + lastVariable.getName()); 127 HashSet noGoods = new HashSet(); 128 129 for (Enumeration i = getModel().assignedVariables().elements(); i.hasMoreElements();) { 130 Variable var = (Variable) i.nextElement(); 131 132 if (!var.equals(lastVariable)) { 133 noGoods.add(var.getAssignment()); 134 } 135 } 136 Value value = lastVariable.getAssignment(); 137 138 lastVariable.unassign(iteration); 139 setNoGood(value, noGoods); 140 return false; 141 } 142 if (variable.getAssignment() != null) { 143 sLogger.error("Assigned value selected -- not supported by DBT."); 144 return false; 145 } 146 return true; 147 } 148 149 /** 150 * If no value is selected (because of a dead end), make some unassignments. 151 * <br><br> 152 * If no value is selected 153 * (e.g., because the selected variable has all values marked as nogood, see {@link DbtValueSelection}), 154 * <ul> 155 * <li> compute a union of explanations of all values, 156 * <ul><li> if it is empty fail (inconsistency is found),</ul> 157 * <li> otherwise pick the last assigned variable from the computed union of explanation and unassign it 158 * <ul>(explanation for that is the computed union of explanations without the last assignment).</ul> 159 * </ul> 160 * 161 * @see DbtVariableSelection#selectVariable(Solution) 162 */ 163 public boolean valueSelected(long iteration, Variable variable, Value value) { 164 if (variable != null && value == null) { 165 HashSet noGoods = new HashSet(); 166 167 for (Enumeration i = variable.values().elements(); i.hasMoreElements();) { 168 Value val = (Value) i.nextElement(); 169 if (noGood(val) != null) { 170 noGoods.addAll(noGood(val)); 171 } 172 } 173 if (noGoods.isEmpty()) { 174 sLogger.debug("Fail"); 175 getSolver().stopSolver(); 176 return false; 177 } 178 Variable lastVariable = null; 179 180 for (Iterator i = noGoods.iterator(); i.hasNext();) { 181 Value val = (Value) i.next(); 182 Variable var = val.variable(); 183 184 if (lastVariable == null || lastVariable.getAssignment().lastAssignmentIteration()<var.getAssignment().lastAssignmentIteration()) { 185 lastVariable = var; 186 } 187 } 188 Value assignment = lastVariable.getAssignment(); 189 190 noGoods.remove(assignment); 191 lastVariable.unassign(iteration); 192 setNoGood(assignment, noGoods); 193 } 194 return true; 195 } 196 197 public boolean neighbourSelected(long iteration, Neighbour neighbour) { 198 return true; 199 } 200 }