/*======================================================================== 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 Iesi.Collections; using System.Text; using Casper.Data; using Casper.Algorithm; using Casper.Algorithm.VariableOrdering; using Casper.Exceptions; namespace Casper { /// /// The interface of the Casper library. This class supports searching /// for valid domains, and reducing domains based on user selected domain values, /// using the CSP algorithm "Select value forward checking", and "Generalized look ahead". /// public class Csp { private List casperVarDoms; private CSPExpressions expressions; private Boolean omitTestOnSingleValuedDomains = false; private Hashtable varIDToVarListIndex; private ConstraintGraph cGraph; private CspVariableOrdering variableOrdering = CspVariableOrdering.vo_static; private GeneralizedLookahead lookahead; /// /// Delegate used to present status for which /// variable is currently searched for valid domains. /// /// public delegate void StatusChanged(int currentlyRunVar); /// /// Initializes a new instance of the class. /// The default Implementation of is used. /// /// The expressions. /// The list with variables/domains. public Csp(CSPExpressions expressions, List casperVarDoms) { this.expressions = expressions; this.casperVarDoms = casperVarDoms; varIDToVarListIndex = new Hashtable(); for (int i = 0; i < casperVarDoms.Count; i++) { varIDToVarListIndex[casperVarDoms[i].VarID] = i; } } /// /// Initializes a new instance of the class. /// objects must be added /// afterwards, to use the "valid domains" methods. The default /// implementation of is used. /// /// The expressions. public Csp(CSPExpressions expressions) { this.expressions = expressions; casperVarDoms = new List(); varIDToVarListIndex = new Hashtable(); } /// /// Initializes a new instance of the class. /// objects must be added, /// and a consistent implementation of /// must be set afterwards, to use the "valid domains" methods. /// public Csp() { casperVarDoms = new List(); varIDToVarListIndex = new Hashtable(); } /// /// Gets or sets the constraint graph. /// /// The constraint graph. public ConstraintGraph CGraph { get { return cGraph; } set { cGraph = value; } } /// /// Gets the variable ordering. /// public CspVariableOrdering VariableOrdering { get { return variableOrdering; } } /// /// Sets the variable ordering, if /// object is initialized. /// /// The varorder. public void SetVariableOrdering(CspVariableOrdering varorder) { variableOrdering = varorder; if (lookahead != null) lookahead.VariableOrdering = varorder; } /// /// Gets or sets the expressions. /// /// The expressions. public CSPExpressions Expressions { get { return expressions; } set { expressions = value; } } /// /// Gets the variable and domain list. /// public List CasperVarDoms { get { return casperVarDoms; } } /// /// Gets or sets a value indicating whether single /// valued domains should be omited. /// /// /// true if single valued domains should be omited; otherwise, false. /// public Boolean OmitTestOnSingleValuedDomains { get { return omitTestOnSingleValuedDomains; } set { omitTestOnSingleValuedDomains = value; } } /// /// Event to present search status. /// public event StatusChanged StatusChangedEvent; /// /// Adds a new variable and domain to the problem. /// /// The new variable and domain /// The index "vardom" is placed on. public int AddCasperVarDom(CasperVarDom vardom) { casperVarDoms.Add(vardom); varIDToVarListIndex[vardom.VarID] = casperVarDoms.Count - 1; return casperVarDoms.Count - 1; } /// /// This method reduces the domain list of "var" to /// only consist of "domainVal" and runs the /// method. /// /// /// /// /// public List ValidDomainsUserChoice(CasperVarDom var, int domainVal){ List tempList = new List(); tempList.Add(domainVal); var.DomainValues = tempList; try { return ValidDomains(); } catch (CasperException e) { throw new CasperException("Valid Domains with user choice could not be run", e); } } /// /// This method runs the forward checking algorithm in the /// class. If /// the data field omitTestOnSIgnleDomains is set to true, /// one valued domain variables are jumped over. /// /// List of variables with valid domains or null if no solution exists /// public List ValidDomains() { lookahead = new GeneralizedLookahead(this.expressions, variableOrdering, CGraph); foreach (CasperVarDom cVarDom in casperVarDoms) { if(StatusChangedEvent!=null) StatusChangedEvent(cVarDom.VarID); List validDomains = new List(); List dValues = cVarDom.DomainValues; if (omitTestOnSingleValuedDomains && cVarDom.DomainValues.Count == 1) continue; foreach (int domainValue in dValues) { if (cVarDom.ValidValues.Contains(domainValue)) { validDomains.Add(domainValue); continue; } List reducedTestDom = new List(); reducedTestDom.Add(domainValue); cVarDom.DomainValues = reducedTestDom; List validDomainValues; try { validDomainValues = lookahead.LookAhead(casperVarDoms); } catch (CasperException e) { throw new CasperException("Valid domains could not be run.", e); } if (validDomainValues != null) { for (int i = 0; i < validDomainValues.Count; i++) { LookAheadVarDom var = validDomainValues[i]; if (var.VarID == cVarDom.VarID) validDomains.Add(domainValue); else { int index = (int)varIDToVarListIndex[var.VarID]; CasperVarDom cvar = casperVarDoms[index]; cvar.ValidValues.Add(var.SelectedValue); } } } } cVarDom.DomainValues = validDomains; if (validDomains.Count == 0) { casperVarDoms = null; return null; } } CleanUp(); return casperVarDoms; } /// /// Internal method for cleaning up before /// starting a new valid domains search. /// private void CleanUp() { foreach (CasperVarDom vardom in casperVarDoms) { vardom.ValidValues.Clear(); } } } }