about summary refs log tree commit diff homepage
path: root/stp/sat/Simplifier.C
diff options
context:
space:
mode:
Diffstat (limited to 'stp/sat/Simplifier.C')
-rw-r--r--stp/sat/Simplifier.C542
1 files changed, 542 insertions, 0 deletions
diff --git a/stp/sat/Simplifier.C b/stp/sat/Simplifier.C
new file mode 100644
index 00000000..1c192e20
--- /dev/null
+++ b/stp/sat/Simplifier.C
@@ -0,0 +1,542 @@
+/************************************************************************************[Simplifier.C]
+MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+#include "Solver.h"
+
+namespace MINISAT {
+
+static const int grow = 0;
+
+//#define WEAKEN
+//#define MATING
+//#define ASSYMM
+
+bool Solver::assymmetricBranching(Clause& c)
+{
+    assert(decisionLevel() == 0);
+
+    //fprintf(stderr, "assymmetric branching on clause: "); printClause(c); fprintf(stderr, "\n");
+    if (satisfied(c)){
+        //fprintf(stderr, "subsumed.\n");
+        return true; }
+
+    int      old;
+    vec<Lit> copy; for (int i = 0; i < c.size(); i++) copy.push(c[i]);
+
+    do {
+        assert(copy.size() == c.size());
+
+        old = copy.size();
+
+        //fprintf(stderr, "checking that clause is normalized\n");
+        //for (int i = 0; i < copy.size(); i++)
+        //    assert(value(copy[i]) == l_Undef);
+
+        for (int i = 0; i < copy.size(); i++){
+            trail_lim.push(trail.size());
+            //fprintf(stderr, " -- trying to delete literal "); printLit(copy[i]); 
+            for (int j = 0; j < copy.size(); j++)
+                if (j != i)
+                    check(enqueue(~copy[j]));
+
+            if (propagate() != NULL){
+                //fprintf(stderr, " succeeded\n");
+                cancelUntil(0);
+                Lit l = copy[i];
+                assert(find(copy, l));
+                remove(copy, l);
+                if (!strengthen(c, l))
+                    return false;
+                i--;
+
+                if (c.size() == 1)
+                    return propagate() == NULL;
+                else
+                    assert(qhead == trail.size());
+            }
+            else
+                //fprintf(stderr, " failed\n");
+
+            cancelUntil(0);
+        }
+
+        //} while (false);
+    } while (copy.size() < old);
+
+    return true;
+}
+
+// Returns FALSE if clause is always satisfied ('out_clause' should not be used). 
+//bool Solver::merge(const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause)
+bool Solver::merge(const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause)
+{  
+    stats.merges++;
+
+    bool  ps_smallest = _ps.size() < _qs.size();
+    const Clause& ps =  ps_smallest ? _qs : _ps;
+    const Clause& qs =  ps_smallest ? _ps : _qs;
+
+    for (int i = 0; i < qs.size(); i++){
+        if (var(qs[i]) != v){
+            for (int j = 0; j < ps.size(); j++)
+                if (var(ps[j]) == var(qs[i])) {
+                    if (ps[j] == ~qs[i])
+                        return false;
+                    else
+                        goto next;
+                }
+            out_clause.push(qs[i]);
+        }
+        next:;
+    }
+
+    for (int i = 0; i < ps.size(); i++)
+        if (var(ps[i]) != v)
+            out_clause.push(ps[i]);
+
+    return true;
+}
+
+
+void Solver::gather(vec<Clause*>& clauses)
+{
+    //fprintf(stderr, "Gathering clauses for backwards subsumption\n");
+    int ntouched = 0;
+    assert(touched.size() == occurs.size());
+    clauses.clear();
+    for (int i = 0; i < touched.size(); i++)
+        if (touched[i]){
+            const vec<Clause*>& cs = getOccurs(i);
+            ntouched++;
+            for (int j = 0; j < cs.size(); j++)
+                if (cs[j]->mark() == 0){
+                    clauses.push(cs[j]);
+                    cs[j]->mark(2);
+                }
+            touched[i] = 0;
+        }
+
+    //fprintf(stderr, "Touched variables %d of %d yields %d clauses to check\n", ntouched, touched.size(), clauses.size());
+    for (int i = 0; i < clauses.size(); i++)
+        clauses[i]->mark(0);
+}
+
+
+/*_________________________________________________________________________________________________
+|
+|  subsumes : (_c : ClauseId) (c : Clause&) (_d : ClauseId) (d : Clause&)  ->  bool
+|
+|  Description:
+|     Checks if c subsumes d, and at the same time, if c can be used to simplify d by subsumption
+|     resolution.
+|    
+|  Input:
+|     Indices into the 'clauses' vector _c, _d, and references to the corresponding clauses c, d.
+|
+|  Result:
+|     lit_Error  - No subsumption or simplification
+|     lit_Undef  - Clause c subsumes d
+|     l          - The literal l can be deleted from d
+|________________________________________________________________________________________________@*/
+inline Lit Solver::subsumes(const Clause& c, const Clause& d)
+{
+    stats.subsumption_checks++;
+    if (d.size() < c.size() || (c.abstraction() & ~d.abstraction()) != 0)
+        return lit_Error;
+
+    Lit ret = lit_Undef;
+
+    for (int i = 0; i < c.size(); i++) {
+        // search for c[i] or ~c[i]
+        for (int j = 0; j < d.size(); j++)
+            if (c[i] == d[j])
+                goto ok;
+            else if (ret == lit_Undef && c[i] == ~d[j]){
+                ret = c[i];
+                goto ok;
+            }
+
+        // did not find it
+        stats.subsumption_misses++;
+        return lit_Error;
+    ok:;
+    }
+
+    return ret;
+}
+
+
+// Backward subsumption + backward subsumption resolution
+bool Solver::backwardSubsumptionCheck()
+{
+    while (subsumption_queue.size() > 0 || qhead < trail.size()){
+
+        // if propagation queue is non empty, take the first literal and
+        // create a dummy unit clause
+        if (qhead < trail.size()){
+            Lit l = trail[qhead++];
+            (*bwdsub_tmpunit)[0] = l;
+            assert(bwdsub_tmpunit->mark() == 0);
+            subsumption_queue.push(bwdsub_tmpunit);
+        }
+        Clause&  c = *subsumption_queue.last(); subsumption_queue.pop();
+
+        if (c.mark())
+            continue;
+
+        if (c.size() == 1 && !enqueue(c[0]))
+            return false; 
+
+        // (1) find best variable to scan
+        Var best = var(c[0]);
+        for (int i = 1; i < c.size(); i++)
+            if (occurs[var(c[i])].size() < occurs[best].size())
+                best = var(c[i]);
+
+        // (2) search all candidates
+        const vec<Clause*>& cs = getOccurs(best);
+
+        for (int j = 0; j < cs.size(); j++)
+            if (cs[j] != &c){
+                if (cs[j]->mark())
+                    continue;
+                if (c.mark())
+                    break;
+
+                //fprintf(stderr, "backward candidate "); printClause(*cs[j]); fprintf(stderr, "\n"); 
+                Lit l = subsumes(c, *cs[j]);
+                if (l == lit_Undef){
+                    //fprintf(stderr, "clause backwards subsumed\n");
+                    //fprintf(stderr, " >> clause %d: ", cs[j]->mark()); printClause(*cs[j]); fprintf(stderr, "\n");
+                    //fprintf(stderr, " >> clause %d: ", c.mark()); printClause(c); fprintf(stderr, "\n");
+                    removeClause(*cs[j], false);
+                }else if (l != lit_Error){
+                    //fprintf(stderr, "backwards subsumption resolution\n");
+                    //fprintf(stderr, " >> clause %d: ", cs[j]->mark()); printClause(*cs[j]); fprintf(stderr, "\n");
+                    //fprintf(stderr, " >> clause %d: ", c.mark()); printClause(c); fprintf(stderr, "\n");
+
+                    assert(cs[j]->size() > 1);
+                    assert(find(*cs[j], ~l));
+
+                    subsumption_queue.push(cs[j]);
+                    if (!strengthen(*cs[j], ~l))
+                        return false;
+
+                    // did current candidate get deleted from cs? then check candidate at index j again
+                    if (var(l) == best)
+                        j--;
+                }
+            }
+    }
+
+    return true;
+}
+
+
+bool Solver::eliminateVar(Var v, bool fail)
+{
+    assert(hasVarProp(v, p_frozen));
+
+    vec<Clause*>  pos, neg;
+    const vec<Clause*>& cls = getOccurs(v);
+
+    if (value(v) != l_Undef || cls.size() == 0)
+        return true;
+
+    //fprintf(stderr, "trying to eliminate var %d\n", v+1);
+    for (int i = 0; i < cls.size(); i++){
+        //fprintf(stderr, "clause: "); printClause(*cls[i]); fprintf(stderr, "\n");
+        if (find(*cls[i], Lit(v)))
+            pos.push(cls[i]);
+        else{
+            assert(find(*cls[i], ~Lit(v)));
+            neg.push(cls[i]);
+        }
+    }
+
+#ifdef WEAKEN
+    vec<int> posc(pos.size(), 0);
+    vec<int> negc(neg.size(), 0);
+#endif
+    // check if number of clauses decreases
+    int      cnt = 0;
+    vec<Lit> resolvent;
+    for (int i = 0; i < pos.size(); i++)
+        for (int j = 0; j < neg.size(); j++){
+            resolvent.clear();
+            if (merge(*pos[i], *neg[j], v, resolvent)){
+                cnt++;
+#ifdef WEAKEN
+                posc[i]++;
+                negc[j]++;
+#endif
+            }
+#ifndef WEAKEN
+            if (cnt > cls.size() + grow)
+                return true;
+#else
+#ifdef MATING
+            if (cnt > cls.size() + grow)
+                if (posc[i] > 0)
+                    break;
+#endif
+#endif
+            assert(pos.size() <= n_occ[toInt(Lit(v))]);
+            assert(neg.size() <= n_occ[toInt(~Lit(v))]);
+        }
+
+#ifdef WEAKEN
+#ifdef MATING
+    for (int i = 0; i < neg.size(); i++)
+        if (negc[i] == 0)
+            for (int j = 0; j < pos.size(); j++){
+                resolvent.clear();
+                if (merge(*neg[i], *pos[j], v, resolvent)){
+                    negc[i]++;
+                    break;
+                }
+            }
+#endif
+    for (int i = 0; i < pos.size(); i++)
+        if (posc[i] == 0)
+            removeClause(*pos[i], false);
+
+    for (int i = 0; i < neg.size(); i++)
+        if (negc[i] == 0)
+            removeClause(*neg[i], false);
+
+    if (cnt > cls.size() + grow)
+        return true;
+#endif    
+    //if (pos.size() != n_occ[toInt(Lit(v))])
+    //    fprintf(stderr, "pos.size() = %d, n_occ[toInt(Lit(v))] = %d\n", pos.size(), n_occ[toInt(Lit(v))]);
+    assert(pos.size() == n_occ[toInt(Lit(v))]);
+    //if (neg.size() != n_occ[toInt(~Lit(v))])
+    //    fprintf(stderr, "neg.size() = %d, n_occ[toInt(Lit(v))] = %d\n", neg.size(), n_occ[toInt(Lit(v))]);
+    assert(neg.size() == n_occ[toInt(~Lit(v))]);
+    assert(cnt <= cls.size() + grow);
+    setVarProp(v, p_decisionvar, false);
+
+    // produce clauses in cross product
+    int top = clauses.size();
+    for (int i = 0; i < pos.size(); i++)
+        for (int j = 0; j < neg.size(); j++){
+            resolvent.clear();
+#ifdef WEAKEN
+            if (pos[i]->mark() == 1)
+                break;
+            if (neg[j]->mark() == 1)
+                continue;
+#endif
+
+            if (merge(*pos[i], *neg[j], v, resolvent)){
+                int i, j;
+                for (i = j = 0; i < resolvent.size(); i++)
+                    if (value(resolvent[i]) == l_True)
+                        goto next;
+                    else if (value(resolvent[i]) == l_Undef)
+                        resolvent[j++] = resolvent[i];
+                resolvent.shrink(i - j);
+
+                if (resolvent.size() == 1){
+                    if (!enqueue(resolvent[0]))
+                        return false;
+                }else{
+                    int apa = clauses.size();
+                    check(newClause(resolvent, false, true));
+                    assert(apa + 1 == clauses.size());
+                }
+            }
+            next:;
+        }
+
+    if (fail){
+        fprintf(stderr, "eliminated var %d, %d <= %d\n", v+1, cnt, cls.size());
+        fprintf(stderr, "previous clauses:\n");
+        for (int i = 0; i < cls.size(); i++){
+            printClause(*cls[i]);
+            fprintf(stderr, "\n");
+        }
+        
+        fprintf(stderr, "new clauses:\n");
+        for (int i = top; i < clauses.size(); i++){
+            printClause(*clauses[i]);
+            fprintf(stderr, "\n");
+        }
+
+        assert(0); }
+
+    //fprintf(stderr, "eliminated var %d, %d <= %d\n", v+1, cnt, cls.size());
+    //fprintf(stderr, "previous clauses:\n");
+    //for (int i = 0; i < cls.size(); i++){
+    //    printClause(*cls[i]);
+    //    fprintf(stderr, "\n");
+    //}
+    //
+    //fprintf(stderr, "new clauses:\n");
+    //for (int i = top; i < clauses.size(); i++){
+    //    printClause(*clauses[i]);
+    //    fprintf(stderr, "\n");
+    //}
+
+    // delete + store old clauses
+    eliminated_var.push(v);
+    eliminated_lim.push(eliminated.size());
+    for (int i = 0; i < cls.size(); i++){
+        eliminated.push(Clause_new(*cls[i]));
+
+#ifdef WEAKEN
+        if (cls[i]->mark() == 0)
+#endif
+            removeClause(*cls[i], false); 
+
+    }
+
+    assert(subsumption_queue.size() == 0);
+    for (int i = top; i < clauses.size(); i++)
+#ifdef ASSYMM
+        if (clauses[i]->mark() == 0)
+            if (!assymmetricBranching(*clauses[i]))
+                return false;
+            else
+                subsumption_queue.push(clauses[i]);
+#else
+        if (clauses[i]->mark() == 0)
+            subsumption_queue.push(clauses[i]);
+#endif
+
+    return backwardSubsumptionCheck();
+}
+
+
+void Solver::extendModel()
+{
+    assert(eliminated_var.size() == eliminated_lim.size());
+    for (int i = eliminated_var.size()-1; i >= 0; i--){
+        Var v = eliminated_var[i];
+        Lit l = lit_Undef;
+
+        //fprintf(stderr, "extending var %d\n", v+1);
+
+        for (int j = eliminated_lim[i]; j < (i+1 >= eliminated_lim.size() ? eliminated.size() : eliminated_lim[i+1]); j++){
+            assert(j < eliminated.size());
+            Clause& c = *eliminated[j];
+
+            //fprintf(stderr, "checking clause: "); printClause(c); fprintf(stderr, "\n");
+
+            for (int k = 0; k < c.size(); k++)
+                if (var(c[k]) == v)
+                    l = c[k];
+                else if (value(c[k]) != l_False)
+                    goto next;
+
+            assert(l != lit_Undef);
+            //fprintf(stderr, "Fixing var %d to %d\n", v+1, !sign(l));
+
+            assigns[v] = toInt(lbool(!sign(l)));
+            break;
+
+        next:;
+        }
+
+        if (value(v) == l_Undef)
+            assigns[v] = toInt(l_True);
+    }
+}
+
+
+bool Solver::eliminate()
+{
+    assert(subsumption);
+
+    int cnt = 0;
+    //fprintf(stderr, "eliminating variables\n");
+
+#ifdef INVARIANTS
+    // check that all clauses are simplified
+    fprintf(stderr, "Checking that all clauses are normalized prior to variable elimination\n");
+    for (int i = 0; i < clauses.size(); i++)
+        if (clauses[i]->mark() == 0){
+            Clause& c = *clauses[i];
+            for (int j = 0; j < c.size(); j++)
+                assert(value(c[j]) == l_Undef);
+        }
+    fprintf(stderr, "done.\n");
+#endif
+
+    for (;;){
+        gather(subsumption_queue);
+
+        if (subsumption_queue.size() == 0 && heap.size() == 0)
+            break;
+
+        //fprintf(stderr, "backwards subsumption: %10d\n", subsumption_queue.size());
+        if (!backwardSubsumptionCheck())
+            return false;
+
+        //fprintf(stderr, "variable elimination:  %10d\n", heap.size());
+        cnt = 0;
+        for (;;){
+            assert(!heap.empty() || heap.size() == 0);
+            if (heap.empty())
+                break;
+
+            Var elim = heap.getmin();
+
+            assert(hasVarProp(elim, p_frozen));
+
+            //for (int i = 1; i < heap.heap.size(); i++)
+            //    assert(heap.comp(elim, heap.heap[i]) || !heap.comp(elim, heap.heap[i]));
+
+            //if (cnt++ % 100 == 0)
+            //    fprintf(stderr, "left %10d\r", heap.size());
+            
+            if (!eliminateVar(elim))
+                return false;
+        }
+    }
+#ifdef INVARIANTS
+    // check that no more subsumption is possible
+    fprintf(stderr, "Checking that no more subsumption is possible\n");
+    cnt = 0;
+    for (int i = 0; i < clauses.size(); i++){
+        if (cnt++ % 1000 == 0)
+            fprintf(stderr, "left %10d\r", clauses.size() - i);
+        for (int j = 0; j < i; j++)
+            assert(clauses[i]->mark() ||
+                   clauses[j]->mark() ||
+                   subsumes(*clauses[i], *clauses[j]) == lit_Error);
+    }
+    fprintf(stderr, "done.\n");
+
+    // check that no more elimination is possible
+    fprintf(stderr, "Checking that no more elimination is possible\n");
+    for (int i = 0; i < nVars(); i++){
+        if (hasVarProp(i, p_frozen))
+            eliminateVar(i, true);
+    }
+    fprintf(stderr, "done.\n");
+
+#endif
+
+    assert(qhead == trail.size());
+
+    return true;
+}
+};