/*======================================================================== Copyright (C) 2006 by Geir-Tore Lindsve, Torbjørn Meistad and Yngve Raudberget, hereby refered to as "the authors". All rights reserved Permission is hereby granted, without written agreement and without license or royalty fees, to use, reproduce, prepare derivative works, distribute, and display this software and its documentation for NONCOMMERCIAL RESEARCH AND EDUCATIONAL PURPOSES, provided that (1) the above copyright notice and the following two paragraphs appear in all copies of the source code and (2) redistributions, including without limitation binaries, reproduce these notices in the supporting documentation. IN NO EVENT SHALL THE AUTHORS, OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. ========================================================================*/ using System; using System.Collections.Generic; using System.Collections; using System.Text; using Iesi.Collections; using Casper.Exceptions; using Casper.Data; using Casper.Algorithm.VariableOrdering; namespace Casper.Algorithm { /// /// Implementation of "Generalized lookahead" with "Select value forward checking". /// public class GeneralizedLookahead { /// /// Constant which represent the minimum width variable ordering. /// public const int MINWIDTHORDER = 1; /// /// Constant which represent ascending variable ordering. /// public const int ASCENDINGORDER = 0; private LookaheadVariables vars; private Consistent consistent; private Hashtable allRemovedValues; private Hashtable affectedVariables; private Hashtable assignedVars; private CspVariableOrdering variableOrdering; private ConstraintGraph cGraph; /// /// Initializes a new instance of the class. /// /// The expressions. /// The variable ordering. /// The constraint graph. public GeneralizedLookahead(CSPExpressions expressions, CspVariableOrdering variableOrdering, ConstraintGraph cGraph) { this.consistent = new Consistent(expressions); this.variableOrdering = variableOrdering; this.cGraph = cGraph; } /// /// Gets or sets the variables. /// /// The variables. internal LookaheadVariables Vars { get { return vars; } set { vars = value; } } /// /// Adds a variable to the hashtable over assigned variables. /// /// The variable. private void AddVarToAssignedVars(LookAheadVarDom var) { this.assignedVars.Add(var.VarID, var); } /// /// Removes a variable from the hashtable over assigned variables. /// /// The variable. internal void RemoveVarFromAssignedVars(LookAheadVarDom var) { this.assignedVars.Remove(var.VarID); } /// /// Gets or sets the variable ordering. /// /// The variable ordering. public CspVariableOrdering VariableOrdering { get { return variableOrdering; } set { variableOrdering = value; } } /// /// The Generalized Lookahead routine from Dechter page 133 /// /// List of CasperVarDom objects, with variable and domain data /// List of objects implementing the IConsistentVar interface /// public List LookAhead(List varDoms) { List prevAssign = new List(); this.allRemovedValues = new Hashtable(); this.affectedVariables = new Hashtable(); this.assignedVars = new Hashtable(); vars = MakeLookAheadVarDoms(varDoms, variableOrdering, cGraph); int i = 0; LookAheadVarDom varDom = vars.GetVar(0); int? selectedValue = null; while (varDom != null) { try { selectedValue = SelectValue(varDom, i); } catch (CasperException) { throw; } if (selectedValue == null) //backtrack { if (prevAssign.Count > 0) { RemoveVarFromAssignedVars(prevAssign[prevAssign.Count - 1]); prevAssign.RemoveAt(prevAssign.Count - 1); } i--; if (i < 0) return null; //no solutions found BacktrackDomains(vars.GetVar(i)); } else //step forward { prevAssign.Add(varDom); AddVarToAssignedVars(varDom); i++; } varDom = vars.GetVar(i); } return prevAssign; } /// /// Implementation of Select Value Forward Checking from Dechter page 134 /// Internal method used by the LookAhead method /// /// Variable to be checked /// The index "var" has in the variable list /// Selected value if a value could be selected; otherwise null. /// public int? SelectValue(LookAheadVarDom var, int i)//current domain will keep track of removed values { var.GetNextValue(true); AddVarToAssignedVars(var); while (var.SelectedValue != null) { if (i > 0) { LookAheadVarDom prev = vars.GetVar(i - 1); Remove(var, prev); } var.AddToRemoved((int)var.SelectedValue); Boolean emptyDomain; try { emptyDomain = ForwardCheck(var, i);//checks for consistency with other variables } catch (CasperException) { throw; } if (!emptyDomain) { var.UpdateDomainWithRemoved(); RemoveVarFromAssignedVars(var); return var.SelectedValue; } var.GetNextValue(false); } var.UpdateDomainWithRemoved(); RemoveVarFromAssignedVars(var); return null; } /// /// Loops through future variables with respect to the current variable. /// This method checks if one of the future variables' domains is empty /// with the current assignment. /// /// The variable we are currently investigating. /// The index "currentVar" has in the variable list /// true if a following domain becomes empty; otherwise false. /// public Boolean ForwardCheck(LookAheadVarDom currentVar, int i) { int k = i + 1; LookAheadVarDom nextVar = vars.GetVar(k); while (nextVar != null) { int domainSize; AddVarToAssignedVars(nextVar); try { domainSize = PruneNextDomain(currentVar, nextVar); } catch (CasperException) { throw; } RemoveVarFromAssignedVars(nextVar); if (domainSize == 0)//the assignment of currentVar is not consistent with nextVar { BacktrackDomains(currentVar); return true; } k++; nextVar = vars.GetVar(k); } return false; } /// /// Checks each domain value for the future variables domains in forwardCheck /// Here we do the actual consistency check with the provided /// consistency implementation. /// /// Currently checked variable /// The variable and domain the method runs consistency check on /// The domain size of "nextVar" after consistency check /// public int PruneNextDomain(LookAheadVarDom currentVar, LookAheadVarDom nextVar) { try { nextVar.GetNextValue(true); while ((nextVar.SelectedValue) != null) { if (!this.consistent.IsConsistent(assignedVars, currentVar, nextVar)) { Remove(nextVar, currentVar); nextVar.AddToRemoved((int)nextVar.SelectedValue); } nextVar.GetNextValue(false); } nextVar.UpdateDomainWithRemoved(); return nextVar.DomainSize(); } catch (CasperException) { throw; } } /// /// Updates the AllRemovedValues-structure with the removed value of /// variable "victim" caused by variable "villain". /// /// The victim. /// The villain. public void Remove(LookAheadVarDom victim, LookAheadVarDom villain) { HybridSet victimsOfVillain = (HybridSet)affectedVariables[villain]; if (victimsOfVillain == null) { victimsOfVillain = new HybridSet(); affectedVariables[villain] = victimsOfVillain; } victimsOfVillain.Add(victim);//updates the affectedVariables structure with the current victim RemovedValues removedValues = (RemovedValues)allRemovedValues[victim]; if (removedValues == null) { removedValues = new RemovedValues(); allRemovedValues[victim] = removedValues; } removedValues.Insert((int)victim.SelectedValue, villain); } /// /// This method backtracks the changes the variable /// "villain" executed on the other variables' domains. /// /// The villain. public void BacktrackDomains(LookAheadVarDom villain)//inserts values back into the value list { Set victims = (HybridSet)affectedVariables[villain]; foreach (LookAheadVarDom victim in victims) { RemovedValues removedValuesVictim = (RemovedValues)allRemovedValues[victim]; HybridSet tempSet = (HybridSet)removedValuesVictim.RemValStructure[villain]; if (tempSet != null) victim.ResetDomain(tempSet); removedValuesVictim.Remove(villain); } affectedVariables[villain] = null; } /// /// Method for making LookAheadVar objects from CasperVarDom objects, /// for internal use in this class. Different variable orderings can /// be made with the constraint graph. /// /// List of "CasperVarDom" objects. /// The var order. /// The constraint graph. /// The variables. /// public LookaheadVariables MakeLookAheadVarDoms(List casperVarDoms, CspVariableOrdering varOrder, ConstraintGraph Graph) { try { LookaheadVariables lAheadVars = new LookaheadVariables(varOrder, cGraph); foreach (CasperVarDom cVarDom in casperVarDoms) { List domVals = cVarDom.DomainValues; Set lAheadDoms = new HybridSet(); foreach (int domVal in domVals) { lAheadDoms.Add(domVal); } lAheadVars.VarDoms.Add(cVarDom.VarID,new LookAheadVarDom(cVarDom.VarID, lAheadDoms)); } return lAheadVars; } catch (CasperException) { throw; } } } }