/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // /////////////////////////////////////////////////////////////////////////////// using System; using System.Collections; using System.Text; using System.IO; //using Microsoft.Zap; namespace SharpSAT { //This class implements the C# interface for a SAT solver public class SATSolver : SharpSATSolver { [Microsoft.Contracts.NotDelayed] public SATSolver() {} /* * This part is the conventional clause based SAT solver * formula is represented in Conjunctive Normal Form (CNF) * which is a conjunction of clauses, each of which is a * disjunction of literals * * Variables are indexed from 1 up to NumVariables. * The number of variables can be set upfront using * SetNumVariables or dynamically increased in the * solving process. */ public double SessionCpuTime () { return base.session_cpu_time();} public double TotalCpuTime() { return base.total_cpu_time(); } #region Managing Clause Database #region Managing Clause Groups public int AllocGID () { return base.alloc_gid(); } public void FreeGID (int gid) { base.free_gid(gid);} public int MergeGroup (int g1, int g2) { return base.merge_clause_group (g1, g2); } public void DeleteGroup (int gid) { base.delete_clause_group(gid); } #endregion public void SetNumVariables(int a) { base.set_num_variables(a); } public int GetNumVariables() { return base.num_variables(); } public int AddVariable() { return base.add_variable(); } public int AddClause( int[] lits, int gid, bool do_check) { return base.add_clause (lits, gid, do_check); } public int AddClause ( int[] lits ) { return base.add_clause (lits, 0, true /*check */); } public int AddClause (int[] lits, int gid) { return base.add_clause (lits, gid, true /*check */); } public int AddClauseNoCheck ( int[] lits ) { return base.add_clause (lits, 0, false /*check */); } public int AddClauseNoCheck ( int[] lits, int gid ) { return base.add_clause (lits, gid, false /*check */);} #endregion #region Solving Instance public void SetBranchable(int vid) { base.set_branchable(vid, true); } public void UnsetBranchable(int vid) { base.set_branchable(vid, false); } public int VariableValue(int vid) { return base.var_value(vid); } public int LiteralValue(int lit) { int v = base.lit_value( lit ); return ((v&1) == v)? v: 2; } public SATStatus Solve() { return base.solve(); } public SATStatus ContinueSolve() { return base.solve(); } public void Reset() { base.reset(); } public void Restart() { base.restart();} #endregion #region Unsat Core and Interpolants //public void EnableTraceGen() { base.enable_rtrace(true); } //public void DisableProofGen() { base.enable_rtrace(false);} // return null if instance is SAT public UnsatCore GenUnsatCore() { return base.gen_unsat_core(); } // return -1 if instance is SAT public int GenInterpolantFromClauseGroups (int a_gid, int b_gid) { return base.gen_interpolant_from_clauses(a_gid, b_gid); } // return -1 if and(a,b) is SAT public int GenInterpolantFromSignals ( int signal_a, int signal_b) { if (signal_a == zero() || signal_b == zero()) throw new Exception("One of the Input is Zero for Interpolation"); return base.gen_interpolant_from_signals(signal_a, signal_b); } // gretay - change start // return -1 if and(a,b) is SAT public int GenInterpolantFromSignalsEx( int signal_a, int signal_b) { if (signal_a == zero() || signal_b == zero()) throw new Exception("One of the Input is Zero for Interpolation"); return base.gen_interpolant_from_signals_ex(signal_a, signal_b); } public void SetInterpolant(int cl_uid, int i) { base.set_interpolant(cl_uid, i); } // gretay - change end #endregion /* given two Boolean formulas represented by s1 and s2, return the logic formula * corresponding to AND(s1,s2), OR(s1,s2)... etc */ public int Constraint (int s) { return base.constraint(s); } public void ReleaseConstraint(int c) { base.release_constraint(c); } #region Structure Interface public int GetOne () { return base.one() ; } public int GetZero () { return base.zero(); } public int CreatePI() { return base.new_pi(); } public int NthPI(int n) { return base.nth_pi(n); } public void ConvertVarsToPI() { base.convert_vars_to_pi(); } public int And(int a, int b) { return base.band(a, b); } public int Or(int a, int b) { return base.bor(a, b); } public int Not(int a) { return base.bnot(a); } public int Xor(int a, int b) { return base.bxor(a, b); } public int Equ(int a, int b) { return base.bequ(a, b); } public int Imp(int a, int b) { return base.bimp(a, b); } public bool IsNegated(int s) { return IS_NEGATED(s); } public int NonNegated(int s) { return NON_NEGATED(s); } public void Reference(int a) { base.reference(a); } public void Deref(int a) { base.deref(a); } public int NumPI() { return base.num_pi(); } public int PiVarValue (int k) { return base.pi_var_value(k); } //note: start from 0, up to NumPI - 1 public int PrimaryInput(int k) { return base.nth_pi(k); } public int LeftChild(int sig) { return base.left_child(sig); } public int RightChild(int sig) { return base.right_child(sig); } public NodeType NdType (int sig) { return base.node_type(sig); } public int NodeToPI (int sig) { return base.node_to_pi(sig); } public int AllocFlag () { return base.alloc_flag(); } public void ClearFlag(int flag_id) { base.clear_flag_for_all(flag_id); } public bool IsNodeFlagSet(int s, int flag_id) { return base.is_flag_set(s, flag_id); } /* orig[] and replace[] should have the same size. Given a Boolean formula * represented by s, function compose will generate a new Boolean formula * that rename all orig[i] to replace[i] in s. */ public int Compose (int s, int [] orig, int [] replace ) { return base.compose(s, orig, replace); } /* Mark the transitive fanins and fanouts of a signal s. After marking * nodes belong to the fanin/fanout set are marked for the flag. A node * can be tested for whether it belongs to the set using IsNodeFlagSet() */ public void MarkTransitiveFanins(int s, int flag) { base.mark_transitive_fanins(s, flag); } public void MarkTransitiveOuts(int s, int flag) { base.mark_transitive_fanouts(s, flag); } #endregion #region TestSAT //two examples of how to use the interface /* Test if logic formula represented by s is satisfiable (i.e. exist a * primary inputs assignment such that s evaluate to true. */ public SATStatus TestSAT (int s) { if (s == GetZero()) return SATStatus.UNSATISFIABLE; else if (s == GetOne()) return SATStatus.SATISFIABLE; int c = Constraint(s); SATStatus status = Solve(); ReleaseConstraint (c); return status; } /* Test if logic formula represented by s is satisfiable. If it is, * return the satisfiable primary input assignments, otherwise return * null. Notice this function has about the same complexity as * TestSAT(), so you should avoid calling testSAT first and then based * on the result call FindSATAssignment. If you don't know whether s is * satisfiable, call FindSatAssignment directly, and based on the return * value you should know if s is satisfiable or not. */ public int[] FindSatAssignment (int s) { int[] pi_values = null; if (s == GetZero()) return null; else if (s == GetOne()) { pi_values = new int[NumPI()]; for (int i=0; i< pi_values.Length; ++i) pi_values[i] = 2; return pi_values; } else { int c = Constraint(s); SATStatus status = Solve(); if (status == SATStatus.SATISFIABLE) { pi_values = new int[NumPI()]; for (int i=0; i< NumPI(); ++i) { int l = LiteralValue(PrimaryInput(i)); if (l != 0 && l != 1) pi_values[i] = 2; else pi_values[i] = l; } } ReleaseConstraint(c); return pi_values; } } #endregion public int DecisionLevel() { return d_level(); } public int [] AssignmentAtLevel(int l ) { return assignment_stack(l).ToArray(); } public ObjVector AssignmentStack() { return assignment_stack(); } public void MakeDecision (int svar) { base.make_decision(svar); } public void SetHookObject (SATHook hk) { base.hook = hk; } //(a & b & c => d) reasons[!a, !b, !c] imply=d // reasons can be null public void AddImplication (int [] reasons, int imply) { base.add_new_implication(reasons, imply); } public int EnumExistQuantify (int s, int [] bound) { return base.enum_exist_quantify_smart (s, bound); } public int [] FindSmallModel () { return base.find_small_model(); } #region ToString Methods /* return the string representation of this particular node */ public string ToString (int sig, MyHashtable nameMap) { string result = sig.ToString() + "\t= "; if (IsNegated(sig)) { int t = NonNegated(sig); result += "Not(" + t.ToString() + ")\n" + ToString (t, nameMap); } else { NodeType tp = NdType(sig); switch (tp) { case NodeType.UNKNOWN: case NodeType.FREE: case NodeType.CONSTANT: case NodeType.VARIABLE: result += "ERROR"; break; case NodeType.AND: case NodeType.XOR: int l = LeftChild(sig); int r = RightChild(sig); string lstr, rstr; lstr = l.ToString(); rstr = r.ToString(); if (tp == NodeType.AND) result += "AND (" + lstr + ", " + rstr + ")"; else result += "XOR (" + lstr + ", " + rstr + ")"; break; case NodeType.PI: int sig_pi = NodeToPI(sig); if (sig_pi != -1) { if (nameMap.Contains(sig_pi)) result += nameMap[sig_pi]; else result += "PI" + sig_pi.ToString(); } else result += "ERROR"; break; } result += "\n"; } return result; } /* return the string representation of the whole * tree rooted at this particular node */ public string TreeToString (int sig, MyHashtable nameMap) { MyHashtable inqueue = new MyHashtable(); Queue todo = new Queue(); todo.Enqueue (sig); StringBuilder result = new StringBuilder(); while (todo.Count != 0) { int nd = (int)todo.Dequeue(); int l = LeftChild(nd); int r = RightChild(nd); NodeType tp = NdType(nd); if (tp == NodeType.AND || tp == NodeType.XOR) { if (!inqueue.Contains(l)) { todo.Enqueue(l); inqueue.Add (l, null); } if (!inqueue.Contains(r)) { todo.Enqueue(r); inqueue.Add (r, null); } } result.Append (ToString(nd, nameMap)); } return result.ToString(); } } #endregion }