/*======================================================================== 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.IO; using CLab.Data; using CLab.BDD; using CLab.CSP; using CLab.Exceptions; namespace CLab { /// /// The interface class for the library. The library is designed in such way, that /// everything should be done through this class. /// public class Clab { private CLabModus modus; private Casper.CspVariableOrdering cspVariableOrdering = Casper.CspVariableOrdering.vo_static; private BddCompileMethod bddCompileMethod = BddCompileMethod.cm_static; private String inputFileName; private CP cp; private Symbols symbols; private ClabCSP clabCSP; private ClabBDD clabBDD; private int statusUpdateCount = 0; private int initbddnodes = Common.INITBDDNODES; private int initdbcache = Common.BDDINITDBCACHE; private int maxincrease = Common.BDDMAXINCREASE; /// /// Delegate for updating status information during search. /// /// The new status information. public delegate void StatusEventHandler(int value); /// /// Initializes a new instance of the class. /// /// Name of the csp problem file. /// Thrown when an error occurs during initialization. public Clab(String fileName) { try { this.inputFileName = fileName; cp = new CP(inputFileName); symbols = new Symbols(cp); for (int i = 0; i < cp.Rules.Count; i++) { symbols.CheckExpressionType(cp.Rules[i]); } } catch (ClabSymbolException e) { throw new ClabException(e.Message, e); } catch (Exception e) { throw new ClabException(e.Message, e); } } /// /// Initializes a new instance of the class. /// /// The cp file stream. /// Thrown when an error occurs during initialization. public Clab(Stream xmlStream) { try { cp = new CP(xmlStream); symbols = new Symbols(cp); for (int i = 0; i < cp.Rules.Count; i++) { symbols.CheckExpressionType(cp.Rules[i]); } } catch (ClabXMLParserException 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); } } /// /// Initializes the specified modus, BDD if modus = 0 or CSP if modus = 1. /// /// The modus. /// The initial domain values, before the rules are applied. /// Thrown when an error occurs during initialization. public ValidDomains InitializeProblemSolver(CLabModus modus) { try { this.modus = modus; if (modus.Equals(CLabModus.bdd_modus)) { clabBDD = new ClabBDD(this, cp, symbols, initdbcache, initbddnodes, maxincrease); } else if (modus.Equals(CLabModus.csp_modus)) { clabCSP = new ClabCSP(this, cp, symbols); clabCSP.SetVariableOrdering(cspVariableOrdering); } else throw new ClabException("Invalid modus, Clab.cs"); } catch (ClabException) { throw; } ValidDomains vDomains = new ValidDomains(); try { if (modus == CLabModus.bdd_modus) { vDomains = clabBDD.GetValidDomains(); } else if (modus == CLabModus.csp_modus) { vDomains = clabCSP.GetValidDomains(); } else throw new ClabException("Invalid modus"); } catch (ClabException e) { throw new ClabException("Error getting original problem domains", e); } return vDomains; } /// /// Event for updating status information out of the library. /// public event StatusEventHandler StatusEvent; /// /// Gets the problem instance. /// /// The current instance. public CP Cp { get { return cp; } } /// /// Sets the CSP variable ordering. /// /// The variable ordering. public void SetCSPVariableOrdering(CspVariableOrdering varOrdering) { if (varOrdering == CspVariableOrdering.vo_static) this.cspVariableOrdering = Casper.CspVariableOrdering.vo_static; else this.cspVariableOrdering = Casper.CspVariableOrdering.vo_minwidth; if (clabCSP != null) { clabCSP.SetVariableOrdering(cspVariableOrdering); } } /// /// Sets the BDD compile method. /// /// public void SetBddCompileMethod(BddCompileMethod compileMethod) { this.bddCompileMethod = compileMethod; } /// /// Gets the valid domains for the constraint problem. /// /// Valid domains. /// public ValidDomains GetValidDomains() { try { ValidDomains vDomains = new ValidDomains(); if (modus == CLabModus.bdd_modus) { clabBDD.CompileAllExpressions(bddCompileMethod); vDomains = clabBDD.GetValidDomains(); } else if (modus == CLabModus.csp_modus) { clabCSP.RunCSPSearch(); vDomains = clabCSP.GetValidDomains(); } else throw new ClabException("Invalid modus"); return vDomains; } catch (ClabException e) { throw new ClabException("Could not get valid domains", e); } } /// /// Gets the valid domains for extra rule added by the user. The /// rule in this case is a chosen domain value for a single variable. /// /// The variable that has been assigned a domain value by the user. /// The selected domain value for the variable. /// The valid domains after search with the extra rule added. /// public ValidDomains GetValidDomainsExtraRule(String variable, String selectedDomain) { try { ValidDomains vDomains = new ValidDomains(); if (modus == CLabModus.bdd_modus) { clabBDD.UpdateResultBDDUserChoice(variable, selectedDomain); vDomains = clabBDD.GetValidDomains(); } else if (modus == CLabModus.csp_modus) { clabCSP.RunCSPSearchUserChoice(variable, selectedDomain); vDomains = clabCSP.GetValidDomains(); } else throw new ClabException("Invalid modus"); return vDomains; } catch (ClabException e) { throw new ClabException("Could not get valid domains, user select", e); } } /// /// Gets the valid domains for an extra rule. The rule can be any expression. /// /// The added expression. /// The valid domains after search with the extra rule added. /// public ValidDomains GetValidDomainsExtraRule(Expression expr) { try { ValidDomains vDomains = new ValidDomains(); if (modus == CLabModus.bdd_modus) { clabBDD.UpdateResultBddExpr(expr); vDomains = clabBDD.GetValidDomains(); } else if (modus == CLabModus.csp_modus) { symbols.CheckExpressionType(expr); clabCSP.AddExtraRule(expr); clabCSP.RunCSPSearch(); vDomains = clabCSP.GetValidDomains(); } else throw new ClabException("Invalid modus"); return vDomains; } catch (ClabException e) { throw new ClabException("Could not get valid domains for extra rule", e); } catch (ClabSymbolException e) { throw new ClabException("Could not get valid domains for extra rule", e); } } /// /// Updates the status of the currently checked value. /// /// The currently checked value. internal void UpdateStatus(int value) { if(StatusEvent!=null) StatusEvent(value); } /// /// Returns the number of variables. /// /// The number of variables. public int VariableCount() { return cp.Variables.Count; } /// /// Method which return the maximal number of calls to the /// status event for a search, depending on which modus /// is chosen. /// Can be used to set the max value of a progress bar. /// /// Number of status messages. public int StatusUpdateCount() { return statusUpdateCount; } /// /// Sets the status update count, which is /// the maximum number of status updates for /// a specific search. Can be used to set /// the maximum value of a progress bar. /// /// The suc. internal void SetStatusUpdateCount(int suc) { this.statusUpdateCount = suc; } /// /// Gets the unsatisfiable rule, if BDD modus is chosen. /// This information is not possible to retrive in CSP modus. /// /// public String GetUnsatisfiableRule() { if (modus == 0) { return clabBDD.UnsatisfiableRule; } else return ""; } /// /// Gets or sets the initial number of bdd nodes. /// /// The initbddnodes. public int Initbddnodes { get { return initbddnodes; } set { initbddnodes = value; } } /// /// Gets or sets the initial size of db cache. /// /// The initdbcache. public int Initdbcache { get { return initdbcache; } set { initdbcache = value; } } /// /// Gets or sets the BDD max increase number. /// /// The maxincrease. public int Maxincrease { get { return maxincrease; } set { maxincrease = value; } } } }