/*======================================================================== 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.Text; using System.Collections; using CLab.Exceptions; using CLab.Data; using Casper; using Casper.Data; using Casper.Exceptions; using Iesi.Collections; namespace CLab.CSP { /// /// The main class for finding valid solutions with the CSP approach. /// The class is designed to be used by , which /// provides the data needed for this class to work. /// public class ClabCSP { private CSPLayout layout; private CSPExpressionBuilder builder; private Csp csp; private Clab clab; private ValidDomains vDomains; private Hashtable cpVarToVDomainID; private Casper.CspVariableOrdering variableOrdering; private Boolean initialSearchIsRun = false; /// /// Initializes a new instance of the class. /// /// The object. /// The object of the problem. /// The object of the problem. /// public ClabCSP(Clab clab, CP cp, Symbols symbols) { this.clab = clab; clab.SetStatusUpdateCount(cp.Variables.Count); cpVarToVDomainID = new Hashtable(); try { layout = new CSPLayout(cp); List casperVarDoms = layout.MakeCasperVarDoms(); builder = new CSPExpressionBuilder(layout, cp, symbols); CSPExpressions expressions = builder.BuildCSPExpressions(); csp = new Csp(expressions, casperVarDoms); csp.CGraph = builder.ConstraintGraph; CreateValidDomainsData(); csp.SetVariableOrdering(variableOrdering); } catch (ClabInternalErrorException e) { throw new ClabException(e.Message, e); } catch (ClabInvalidExpressionException e) { throw new ClabException(e.Message, e); } catch (ClabSymbolException e) { throw new ClabException(e.Message, e); } catch (Exception e) { throw new ClabException(e.Message, e); } } /// /// Gets the of the problem. /// /// The CSP layout of the problem. public CSPLayout Layout { get { return layout; } } /// /// Gets the object of the problem. /// /// The CSP object. public Csp Csp { get { return csp; } } /// /// Sets the variable ordering. /// /// The variable ordering. public void SetVariableOrdering(Casper.CspVariableOrdering variableOrder) { this.variableOrdering = variableOrder; if (csp != null) { csp.SetVariableOrdering(variableOrdering); } } /// /// Creates the instance for this problem. /// It is filled with the data of the problem, except for the domain information. /// A mapping from valid domain index to cp variable index is also created. /// private void CreateValidDomainsData() { vDomains = new ValidDomains(); List varIDToCPVar = layout.VarIDToCPVar; foreach (String cpVar in varIDToCPVar) { String typeName = layout.GetTypeName(cpVar); CPTypes TypeFormat = layout.GetTypeFormat(typeName); ValidDomain valid = new ValidDomain(cpVar, typeName, TypeFormat); int validId = vDomains.addValidDomain(valid); cpVarToVDomainID[cpVar] = validId; } } /// /// Updates the instance with the domain information from /// the current object. Before a search is run, all domain values /// are possible and returned. /// /// The valid domains. /// public ValidDomains GetValidDomains() { List casperVarDoms = csp.CasperVarDoms; if (casperVarDoms == null) { for (int i = 0; i < vDomains.ValidDoms.Count; i++) { ValidDomain vd = vDomains.ValidDoms[i]; vd.EmptyValidDomain(); } return vDomains; } for (int i = 0; i < casperVarDoms.Count; i++) { CasperVarDom varDom = casperVarDoms[i]; String cpVar = layout.GetCPVarFromVarID(varDom.VarID); int validIndex = (int)cpVarToVDomainID[cpVar]; ValidDomain vDomain = vDomains.ValidDoms[validIndex]; vDomain.EmptyValidDomain(); List vDomainInts = varDom.DomainValues; for (int j = 0; j < vDomainInts.Count; j++) { try { vDomain.AddValidDomain(layout.GetDomainStringFromDomainInt(cpVar, vDomainInts[j])); } catch (ClabException) { throw; } } } return vDomains; } /// /// Runs the CSP search with the expressions defined, and /// return the valid domaines for the problem. /// /// public void RunCSPSearch() { csp.StatusChangedEvent -= new Csp.StatusChanged(this.ObserveStatusChanged); csp.StatusChangedEvent += new Csp.StatusChanged(this.ObserveStatusChanged); try { csp.ValidDomains(); initialSearchIsRun = true; } catch (CasperException e) { throw new ClabException("CSP search could not be run", e); } } /// /// Runs the CSP search reduced with a user chosen domain value /// for a variable. Returns the valid domaines for the problem after /// this reduction. /// /// The chosen variable. /// The chosen domain value. /// public void RunCSPSearchUserChoice(String var, String domVal) { if (!initialSearchIsRun) throw new ClabException("Initial CSP search not run"); csp.StatusChangedEvent -= new Csp.StatusChanged(this.ObserveStatusChanged); csp.StatusChangedEvent += new Csp.StatusChanged(this.ObserveStatusChanged); int casperVarIndex = layout.GetCasperVarDomIndex(var); CasperVarDom vd = csp.CasperVarDoms[casperVarIndex]; int chosenDomainInt = layout.GetDomainIntFromDomainString(var, domVal); csp.OmitTestOnSingleValuedDomains = true; try { csp.ValidDomainsUserChoice(vd, chosenDomainInt); } catch (CasperException e) { throw new ClabException("CSP search with user choice could not be run", e); } } /// /// Adds an extra rule to the problem. Does not run a search for /// valid solutions, this has to be done, to get the reduced valid domaines /// after adding the new expression. /// /// The new expression. /// public void AddExtraRule(Expression newExpr) { try { CSPExprWrapper cspExprW = builder.BuildCSPExpression(newExpr); csp.Expressions.AddWrappedExpr(cspExprW); } catch (ClabInternalErrorException e) { throw new ClabException("Extra rule could not be added", e); } } /// /// Observes the status for changes, and updates the current /// instance. /// /// The currently run var. public void ObserveStatusChanged(int currentlyRunVar) { clab.UpdateStatus(currentlyRunVar); } } }