mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 13:29:12 +00:00 
			
		
		
		
	Replace; #define __STDC_LIMIT_MACROS #define __STDC_FORMAT_MACROS With #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS #endif #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif This fixes a compile warning if you are defining these macros in your CXXFLAGS (as some distros do).
		
			
				
	
	
		
			731 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			731 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#ifndef __STDC_FORMAT_MACROS
 | 
						|
#define __STDC_FORMAT_MACROS
 | 
						|
#endif
 | 
						|
#ifndef __STDC_LIMIT_MACROS
 | 
						|
#define __STDC_LIMIT_MACROS
 | 
						|
#endif
 | 
						|
/***********************************************************************************[SimpSolver.cc]
 | 
						|
Copyright (c) 2006,      Niklas Een, Niklas Sorensson
 | 
						|
Copyright (c) 2007-2010, 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 "Sort.h"
 | 
						|
#include "SimpSolver.h"
 | 
						|
#include "System.h"
 | 
						|
 | 
						|
using namespace Minisat;
 | 
						|
 | 
						|
//=================================================================================================
 | 
						|
// Options:
 | 
						|
 | 
						|
 | 
						|
static const char* _cat = "SIMP";
 | 
						|
 | 
						|
static BoolOption   opt_use_asymm        (_cat, "asymm",        "Shrink clauses by asymmetric branching.", false);
 | 
						|
static BoolOption   opt_use_rcheck       (_cat, "rcheck",       "Check if a clause is already implied. (costly)", false);
 | 
						|
static BoolOption   opt_use_elim         (_cat, "elim",         "Perform variable elimination.", true);
 | 
						|
static IntOption    opt_grow             (_cat, "grow",         "Allow a variable elimination step to grow by a number of clauses.", 0);
 | 
						|
static IntOption    opt_clause_lim       (_cat, "cl-lim",       "Variables are not eliminated if it produces a resolvent with a length above this limit. -1 means no limit", 20,   IntRange(-1, INT32_MAX));
 | 
						|
static IntOption    opt_subsumption_lim  (_cat, "sub-lim",      "Do not check if subsumption against a clause larger than this. -1 means no limit.", 1000, IntRange(-1, INT32_MAX));
 | 
						|
static DoubleOption opt_simp_garbage_frac(_cat, "simp-gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered during simplification.",  0.5, DoubleRange(0, false, HUGE_VAL, false));
 | 
						|
 | 
						|
 | 
						|
//=================================================================================================
 | 
						|
// Constructor/Destructor:
 | 
						|
 | 
						|
 | 
						|
SimpSolver::SimpSolver() :
 | 
						|
    grow               (opt_grow)
 | 
						|
  , clause_lim         (opt_clause_lim)
 | 
						|
  , subsumption_lim    (opt_subsumption_lim)
 | 
						|
  , simp_garbage_frac  (opt_simp_garbage_frac)
 | 
						|
  , use_asymm          (opt_use_asymm)
 | 
						|
  , use_rcheck         (opt_use_rcheck)
 | 
						|
  , use_elim           (opt_use_elim)
 | 
						|
  , extend_model       (true)
 | 
						|
  , merges             (0)
 | 
						|
  , asymm_lits         (0)
 | 
						|
  , eliminated_vars    (0)
 | 
						|
  , elimorder          (1)
 | 
						|
  , use_simplification (true)
 | 
						|
  , occurs             (ClauseDeleted(ca))
 | 
						|
  , elim_heap          (ElimLt(n_occ))
 | 
						|
  , bwdsub_assigns     (0)
 | 
						|
  , n_touched          (0)
 | 
						|
{
 | 
						|
    vec<Lit> dummy(1,lit_Undef);
 | 
						|
    ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below.
 | 
						|
    bwdsub_tmpunit        = ca.alloc(dummy);
 | 
						|
    remove_satisfied      = false;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
SimpSolver::~SimpSolver()
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
Var SimpSolver::newVar(lbool upol, bool dvar) {
 | 
						|
    Var v = Solver::newVar(upol, dvar);
 | 
						|
 | 
						|
    frozen    .insert(v, (char)false);
 | 
						|
    eliminated.insert(v, (char)false);
 | 
						|
 | 
						|
    if (use_simplification){
 | 
						|
        n_occ     .insert( mkLit(v), 0);
 | 
						|
        n_occ     .insert(~mkLit(v), 0);
 | 
						|
        occurs    .init  (v);
 | 
						|
        touched   .insert(v, 0);
 | 
						|
        elim_heap .insert(v);
 | 
						|
    }
 | 
						|
    return v; }
 | 
						|
 | 
						|
 | 
						|
void SimpSolver::releaseVar(Lit l)
 | 
						|
{
 | 
						|
    assert(!isEliminated(var(l)));
 | 
						|
    if (!use_simplification && var(l) >= max_simp_var)
 | 
						|
        // Note: Guarantees that no references to this variable is
 | 
						|
        // left in model extension datastructure. Could be improved!
 | 
						|
        Solver::releaseVar(l);
 | 
						|
    else
 | 
						|
        // Otherwise, don't allow variable to be reused.
 | 
						|
        Solver::addClause(l);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp)
 | 
						|
{
 | 
						|
    vec<Var> extra_frozen;
 | 
						|
    lbool    result = l_True;
 | 
						|
 | 
						|
    do_simp &= use_simplification;
 | 
						|
 | 
						|
    if (do_simp){
 | 
						|
        // Assumptions must be temporarily frozen to run variable elimination:
 | 
						|
        for (int i = 0; i < assumptions.size(); i++){
 | 
						|
            Var v = var(assumptions[i]);
 | 
						|
 | 
						|
            // If an assumption has been eliminated, remember it.
 | 
						|
            assert(!isEliminated(v));
 | 
						|
 | 
						|
            if (!frozen[v]){
 | 
						|
                // Freeze and store.
 | 
						|
                setFrozen(v, true);
 | 
						|
                extra_frozen.push(v);
 | 
						|
            } }
 | 
						|
 | 
						|
        result = lbool(eliminate(turn_off_simp));
 | 
						|
    }
 | 
						|
 | 
						|
    if (result == l_True)
 | 
						|
        result = Solver::solve_();
 | 
						|
    else if (verbosity >= 1)
 | 
						|
        printf("===============================================================================\n");
 | 
						|
 | 
						|
    if (result == l_True && extend_model)
 | 
						|
        extendModel();
 | 
						|
 | 
						|
    if (do_simp)
 | 
						|
        // Unfreeze the assumptions that were frozen:
 | 
						|
        for (int i = 0; i < extra_frozen.size(); i++)
 | 
						|
            setFrozen(extra_frozen[i], false);
 | 
						|
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
bool SimpSolver::addClause_(vec<Lit>& ps)
 | 
						|
{
 | 
						|
#ifndef NDEBUG
 | 
						|
    for (int i = 0; i < ps.size(); i++)
 | 
						|
        assert(!isEliminated(var(ps[i])));
 | 
						|
#endif
 | 
						|
 | 
						|
    int nclauses = clauses.size();
 | 
						|
 | 
						|
    if (use_rcheck && implied(ps))
 | 
						|
        return true;
 | 
						|
 | 
						|
    if (!Solver::addClause_(ps))
 | 
						|
        return false;
 | 
						|
 | 
						|
    if (use_simplification && clauses.size() == nclauses + 1){
 | 
						|
        CRef          cr = clauses.last();
 | 
						|
        const Clause& c  = ca[cr];
 | 
						|
 | 
						|
        // NOTE: the clause is added to the queue immediately and then
 | 
						|
        // again during 'gatherTouchedClauses()'. If nothing happens
 | 
						|
        // in between, it will only be checked once. Otherwise, it may
 | 
						|
        // be checked twice unnecessarily. This is an unfortunate
 | 
						|
        // consequence of how backward subsumption is used to mimic
 | 
						|
        // forward subsumption.
 | 
						|
        subsumption_queue.insert(cr);
 | 
						|
        for (int i = 0; i < c.size(); i++){
 | 
						|
            occurs[var(c[i])].push(cr);
 | 
						|
            n_occ[c[i]]++;
 | 
						|
            touched[var(c[i])] = 1;
 | 
						|
            n_touched++;
 | 
						|
            if (elim_heap.inHeap(var(c[i])))
 | 
						|
                elim_heap.increase(var(c[i]));
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void SimpSolver::removeClause(CRef cr)
 | 
						|
{
 | 
						|
    const Clause& c = ca[cr];
 | 
						|
 | 
						|
    if (use_simplification)
 | 
						|
        for (int i = 0; i < c.size(); i++){
 | 
						|
            n_occ[c[i]]--;
 | 
						|
            updateElimHeap(var(c[i]));
 | 
						|
            occurs.smudge(var(c[i]));
 | 
						|
        }
 | 
						|
 | 
						|
    Solver::removeClause(cr);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool SimpSolver::strengthenClause(CRef cr, Lit l)
 | 
						|
{
 | 
						|
    Clause& c = ca[cr];
 | 
						|
    assert(decisionLevel() == 0);
 | 
						|
    assert(use_simplification);
 | 
						|
 | 
						|
    // FIX: this is too inefficient but would be nice to have (properly implemented)
 | 
						|
    // if (!find(subsumption_queue, &c))
 | 
						|
    subsumption_queue.insert(cr);
 | 
						|
 | 
						|
    if (c.size() == 2){
 | 
						|
        removeClause(cr);
 | 
						|
        c.strengthen(l);
 | 
						|
    }else{
 | 
						|
        detachClause(cr, true);
 | 
						|
        c.strengthen(l);
 | 
						|
        attachClause(cr);
 | 
						|
        remove(occurs[var(l)], cr);
 | 
						|
        n_occ[l]--;
 | 
						|
        updateElimHeap(var(l));
 | 
						|
    }
 | 
						|
 | 
						|
    return c.size() == 1 ? enqueue(c[0]) && propagate() == CRef_Undef : true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Returns FALSE if clause is always satisfied ('out_clause' should not be used).
 | 
						|
bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause)
 | 
						|
{
 | 
						|
    merges++;
 | 
						|
    out_clause.clear();
 | 
						|
 | 
						|
    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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Returns FALSE if clause is always satisfied.
 | 
						|
bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, int& size)
 | 
						|
{
 | 
						|
    merges++;
 | 
						|
 | 
						|
    bool  ps_smallest = _ps.size() < _qs.size();
 | 
						|
    const Clause& ps  =  ps_smallest ? _qs : _ps;
 | 
						|
    const Clause& qs  =  ps_smallest ? _ps : _qs;
 | 
						|
    const Lit*  __ps  = (const Lit*)ps;
 | 
						|
    const Lit*  __qs  = (const Lit*)qs;
 | 
						|
 | 
						|
    size = ps.size()-1;
 | 
						|
 | 
						|
    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;
 | 
						|
                }
 | 
						|
            size++;
 | 
						|
        }
 | 
						|
        next:;
 | 
						|
    }
 | 
						|
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void SimpSolver::gatherTouchedClauses()
 | 
						|
{
 | 
						|
    if (n_touched == 0) return;
 | 
						|
 | 
						|
    int i,j;
 | 
						|
    for (i = j = 0; i < subsumption_queue.size(); i++)
 | 
						|
        if (ca[subsumption_queue[i]].mark() == 0)
 | 
						|
            ca[subsumption_queue[i]].mark(2);
 | 
						|
 | 
						|
    for (i = 0; i < nVars(); i++)
 | 
						|
        if (touched[i]){
 | 
						|
            const vec<CRef>& cs = occurs.lookup(i);
 | 
						|
            for (j = 0; j < cs.size(); j++)
 | 
						|
                if (ca[cs[j]].mark() == 0){
 | 
						|
                    subsumption_queue.insert(cs[j]);
 | 
						|
                    ca[cs[j]].mark(2);
 | 
						|
                }
 | 
						|
            touched[i] = 0;
 | 
						|
        }
 | 
						|
 | 
						|
    for (i = 0; i < subsumption_queue.size(); i++)
 | 
						|
        if (ca[subsumption_queue[i]].mark() == 2)
 | 
						|
            ca[subsumption_queue[i]].mark(0);
 | 
						|
 | 
						|
    n_touched = 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool SimpSolver::implied(const vec<Lit>& c)
 | 
						|
{
 | 
						|
    assert(decisionLevel() == 0);
 | 
						|
 | 
						|
    trail_lim.push(trail.size());
 | 
						|
    for (int i = 0; i < c.size(); i++)
 | 
						|
        if (value(c[i]) == l_True){
 | 
						|
            cancelUntil(0);
 | 
						|
            return true;
 | 
						|
        }else if (value(c[i]) != l_False){
 | 
						|
            assert(value(c[i]) == l_Undef);
 | 
						|
            uncheckedEnqueue(~c[i]);
 | 
						|
        }
 | 
						|
 | 
						|
    bool result = propagate() != CRef_Undef;
 | 
						|
    cancelUntil(0);
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Backward subsumption + backward subsumption resolution
 | 
						|
bool SimpSolver::backwardSubsumptionCheck(bool verbose)
 | 
						|
{
 | 
						|
    int cnt = 0;
 | 
						|
    int subsumed = 0;
 | 
						|
    int deleted_literals = 0;
 | 
						|
    assert(decisionLevel() == 0);
 | 
						|
 | 
						|
    while (subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()){
 | 
						|
 | 
						|
        // Empty subsumption queue and return immediately on user-interrupt:
 | 
						|
        if (asynch_interrupt){
 | 
						|
            subsumption_queue.clear();
 | 
						|
            bwdsub_assigns = trail.size();
 | 
						|
            break; }
 | 
						|
 | 
						|
        // Check top-level assignments by creating a dummy clause and placing it in the queue:
 | 
						|
        if (subsumption_queue.size() == 0 && bwdsub_assigns < trail.size()){
 | 
						|
            Lit l = trail[bwdsub_assigns++];
 | 
						|
            ca[bwdsub_tmpunit][0] = l;
 | 
						|
            ca[bwdsub_tmpunit].calcAbstraction();
 | 
						|
            subsumption_queue.insert(bwdsub_tmpunit); }
 | 
						|
 | 
						|
        CRef    cr = subsumption_queue.peek(); subsumption_queue.pop();
 | 
						|
        Clause& c  = ca[cr];
 | 
						|
 | 
						|
        if (c.mark()) continue;
 | 
						|
 | 
						|
        if (verbose && verbosity >= 2 && cnt++ % 1000 == 0)
 | 
						|
            printf("subsumption left: %10d (%10d subsumed, %10d deleted literals)\r", subsumption_queue.size(), subsumed, deleted_literals);
 | 
						|
 | 
						|
        assert(c.size() > 1 || value(c[0]) == l_True);    // Unit-clauses should have been propagated before this point.
 | 
						|
 | 
						|
        // 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]);
 | 
						|
 | 
						|
        // Search all candidates:
 | 
						|
        vec<CRef>& _cs = occurs.lookup(best);
 | 
						|
        CRef*       cs = (CRef*)_cs;
 | 
						|
 | 
						|
        for (int j = 0; j < _cs.size(); j++)
 | 
						|
            if (c.mark())
 | 
						|
                break;
 | 
						|
            else if (!ca[cs[j]].mark() &&  cs[j] != cr && (subsumption_lim == -1 || ca[cs[j]].size() < subsumption_lim)){
 | 
						|
                Lit l = c.subsumes(ca[cs[j]]);
 | 
						|
 | 
						|
                if (l == lit_Undef)
 | 
						|
                    subsumed++, removeClause(cs[j]);
 | 
						|
                else if (l != lit_Error){
 | 
						|
                    deleted_literals++;
 | 
						|
 | 
						|
                    if (!strengthenClause(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 SimpSolver::asymm(Var v, CRef cr)
 | 
						|
{
 | 
						|
    Clause& c = ca[cr];
 | 
						|
    assert(decisionLevel() == 0);
 | 
						|
 | 
						|
    if (c.mark() || satisfied(c)) return true;
 | 
						|
 | 
						|
    trail_lim.push(trail.size());
 | 
						|
    Lit l = lit_Undef;
 | 
						|
    for (int i = 0; i < c.size(); i++)
 | 
						|
        if (var(c[i]) != v && value(c[i]) != l_False)
 | 
						|
            uncheckedEnqueue(~c[i]);
 | 
						|
        else
 | 
						|
            l = c[i];
 | 
						|
 | 
						|
    if (propagate() != CRef_Undef){
 | 
						|
        cancelUntil(0);
 | 
						|
        asymm_lits++;
 | 
						|
        if (!strengthenClause(cr, l))
 | 
						|
            return false;
 | 
						|
    }else
 | 
						|
        cancelUntil(0);
 | 
						|
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool SimpSolver::asymmVar(Var v)
 | 
						|
{
 | 
						|
    assert(use_simplification);
 | 
						|
 | 
						|
    const vec<CRef>& cls = occurs.lookup(v);
 | 
						|
 | 
						|
    if (value(v) != l_Undef || cls.size() == 0)
 | 
						|
        return true;
 | 
						|
 | 
						|
    for (int i = 0; i < cls.size(); i++)
 | 
						|
        if (!asymm(v, cls[i]))
 | 
						|
            return false;
 | 
						|
 | 
						|
    return backwardSubsumptionCheck();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void mkElimClause(vec<uint32_t>& elimclauses, Lit x)
 | 
						|
{
 | 
						|
    elimclauses.push(toInt(x));
 | 
						|
    elimclauses.push(1);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void mkElimClause(vec<uint32_t>& elimclauses, Var v, Clause& c)
 | 
						|
{
 | 
						|
    int first = elimclauses.size();
 | 
						|
    int v_pos = -1;
 | 
						|
 | 
						|
    // Copy clause to elimclauses-vector. Remember position where the
 | 
						|
    // variable 'v' occurs:
 | 
						|
    for (int i = 0; i < c.size(); i++){
 | 
						|
        elimclauses.push(toInt(c[i]));
 | 
						|
        if (var(c[i]) == v)
 | 
						|
            v_pos = i + first;
 | 
						|
    }
 | 
						|
    assert(v_pos != -1);
 | 
						|
 | 
						|
    // Swap the first literal with the 'v' literal, so that the literal
 | 
						|
    // containing 'v' will occur first in the clause:
 | 
						|
    uint32_t tmp = elimclauses[v_pos];
 | 
						|
    elimclauses[v_pos] = elimclauses[first];
 | 
						|
    elimclauses[first] = tmp;
 | 
						|
 | 
						|
    // Store the length of the clause last:
 | 
						|
    elimclauses.push(c.size());
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
bool SimpSolver::eliminateVar(Var v)
 | 
						|
{
 | 
						|
    assert(!frozen[v]);
 | 
						|
    assert(!isEliminated(v));
 | 
						|
    assert(value(v) == l_Undef);
 | 
						|
 | 
						|
    // Split the occurrences into positive and negative:
 | 
						|
    //
 | 
						|
    const vec<CRef>& cls = occurs.lookup(v);
 | 
						|
    vec<CRef>        pos, neg;
 | 
						|
    for (int i = 0; i < cls.size(); i++)
 | 
						|
        (find(ca[cls[i]], mkLit(v)) ? pos : neg).push(cls[i]);
 | 
						|
 | 
						|
    // Check wether the increase in number of clauses stays within the allowed ('grow'). Moreover, no
 | 
						|
    // clause must exceed the limit on the maximal clause size (if it is set):
 | 
						|
    //
 | 
						|
    int cnt         = 0;
 | 
						|
    int clause_size = 0;
 | 
						|
 | 
						|
    for (int i = 0; i < pos.size(); i++)
 | 
						|
        for (int j = 0; j < neg.size(); j++)
 | 
						|
            if (merge(ca[pos[i]], ca[neg[j]], v, clause_size) && 
 | 
						|
                (++cnt > cls.size() + grow || (clause_lim != -1 && clause_size > clause_lim)))
 | 
						|
                return true;
 | 
						|
 | 
						|
    // Delete and store old clauses:
 | 
						|
    eliminated[v] = true;
 | 
						|
    setDecisionVar(v, false);
 | 
						|
    eliminated_vars++;
 | 
						|
 | 
						|
    if (pos.size() > neg.size()){
 | 
						|
        for (int i = 0; i < neg.size(); i++)
 | 
						|
            mkElimClause(elimclauses, v, ca[neg[i]]);
 | 
						|
        mkElimClause(elimclauses, mkLit(v));
 | 
						|
    }else{
 | 
						|
        for (int i = 0; i < pos.size(); i++)
 | 
						|
            mkElimClause(elimclauses, v, ca[pos[i]]);
 | 
						|
        mkElimClause(elimclauses, ~mkLit(v));
 | 
						|
    }
 | 
						|
 | 
						|
    for (int i = 0; i < cls.size(); i++)
 | 
						|
        removeClause(cls[i]); 
 | 
						|
 | 
						|
    // Produce clauses in cross product:
 | 
						|
    vec<Lit>& resolvent = add_tmp;
 | 
						|
    for (int i = 0; i < pos.size(); i++)
 | 
						|
        for (int j = 0; j < neg.size(); j++)
 | 
						|
            if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) && !addClause_(resolvent))
 | 
						|
                return false;
 | 
						|
 | 
						|
    // Free occurs list for this variable:
 | 
						|
    occurs[v].clear(true);
 | 
						|
    
 | 
						|
    // Free watchers lists for this variable, if possible:
 | 
						|
    if (watches[ mkLit(v)].size() == 0) watches[ mkLit(v)].clear(true);
 | 
						|
    if (watches[~mkLit(v)].size() == 0) watches[~mkLit(v)].clear(true);
 | 
						|
 | 
						|
    return backwardSubsumptionCheck();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool SimpSolver::substitute(Var v, Lit x)
 | 
						|
{
 | 
						|
    assert(!frozen[v]);
 | 
						|
    assert(!isEliminated(v));
 | 
						|
    assert(value(v) == l_Undef);
 | 
						|
 | 
						|
    if (!ok) return false;
 | 
						|
 | 
						|
    eliminated[v] = true;
 | 
						|
    setDecisionVar(v, false);
 | 
						|
    const vec<CRef>& cls = occurs.lookup(v);
 | 
						|
    
 | 
						|
    vec<Lit>& subst_clause = add_tmp;
 | 
						|
    for (int i = 0; i < cls.size(); i++){
 | 
						|
        Clause& c = ca[cls[i]];
 | 
						|
 | 
						|
        subst_clause.clear();
 | 
						|
        for (int j = 0; j < c.size(); j++){
 | 
						|
            Lit p = c[j];
 | 
						|
            subst_clause.push(var(p) == v ? x ^ sign(p) : p);
 | 
						|
        }
 | 
						|
 | 
						|
        removeClause(cls[i]);
 | 
						|
 | 
						|
        if (!addClause_(subst_clause))
 | 
						|
            return ok = false;
 | 
						|
    }
 | 
						|
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void SimpSolver::extendModel()
 | 
						|
{
 | 
						|
    int i, j;
 | 
						|
    Lit x;
 | 
						|
 | 
						|
    for (i = elimclauses.size()-1; i > 0; i -= j){
 | 
						|
        for (j = elimclauses[i--]; j > 1; j--, i--)
 | 
						|
            if (modelValue(toLit(elimclauses[i])) != l_False)
 | 
						|
                goto next;
 | 
						|
 | 
						|
        x = toLit(elimclauses[i]);
 | 
						|
        model[var(x)] = lbool(!sign(x));
 | 
						|
    next:;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool SimpSolver::eliminate(bool turn_off_elim)
 | 
						|
{
 | 
						|
    if (!simplify())
 | 
						|
        return false;
 | 
						|
    else if (!use_simplification)
 | 
						|
        return true;
 | 
						|
 | 
						|
    // Main simplification loop:
 | 
						|
    //
 | 
						|
    while (n_touched > 0 || bwdsub_assigns < trail.size() || elim_heap.size() > 0){
 | 
						|
 | 
						|
        gatherTouchedClauses();
 | 
						|
        // printf("  ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n", cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns);
 | 
						|
        if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()) && 
 | 
						|
            !backwardSubsumptionCheck(true)){
 | 
						|
            ok = false; goto cleanup; }
 | 
						|
 | 
						|
        // Empty elim_heap and return immediately on user-interrupt:
 | 
						|
        if (asynch_interrupt){
 | 
						|
            assert(bwdsub_assigns == trail.size());
 | 
						|
            assert(subsumption_queue.size() == 0);
 | 
						|
            assert(n_touched == 0);
 | 
						|
            elim_heap.clear();
 | 
						|
            goto cleanup; }
 | 
						|
 | 
						|
        // printf("  ## (time = %6.2f s) ELIM: vars = %d\n", cpuTime(), elim_heap.size());
 | 
						|
        for (int cnt = 0; !elim_heap.empty(); cnt++){
 | 
						|
            Var elim = elim_heap.removeMin();
 | 
						|
            
 | 
						|
            if (asynch_interrupt) break;
 | 
						|
 | 
						|
            if (isEliminated(elim) || value(elim) != l_Undef) continue;
 | 
						|
 | 
						|
            if (verbosity >= 2 && cnt % 100 == 0)
 | 
						|
                printf("elimination left: %10d\r", elim_heap.size());
 | 
						|
 | 
						|
            if (use_asymm){
 | 
						|
                // Temporarily freeze variable. Otherwise, it would immediately end up on the queue again:
 | 
						|
                bool was_frozen = frozen[elim];
 | 
						|
                frozen[elim] = true;
 | 
						|
                if (!asymmVar(elim)){
 | 
						|
                    ok = false; goto cleanup; }
 | 
						|
                frozen[elim] = was_frozen; }
 | 
						|
 | 
						|
            // At this point, the variable may have been set by assymetric branching, so check it
 | 
						|
            // again. Also, don't eliminate frozen variables:
 | 
						|
            if (use_elim && value(elim) == l_Undef && !frozen[elim] && !eliminateVar(elim)){
 | 
						|
                ok = false; goto cleanup; }
 | 
						|
 | 
						|
            checkGarbage(simp_garbage_frac);
 | 
						|
        }
 | 
						|
 | 
						|
        assert(subsumption_queue.size() == 0);
 | 
						|
    }
 | 
						|
 cleanup:
 | 
						|
 | 
						|
    // If no more simplification is needed, free all simplification-related data structures:
 | 
						|
    if (turn_off_elim){
 | 
						|
        touched  .clear(true);
 | 
						|
        occurs   .clear(true);
 | 
						|
        n_occ    .clear(true);
 | 
						|
        elim_heap.clear(true);
 | 
						|
        subsumption_queue.clear(true);
 | 
						|
 | 
						|
        use_simplification    = false;
 | 
						|
        remove_satisfied      = true;
 | 
						|
        ca.extra_clause_field = false;
 | 
						|
        max_simp_var          = nVars();
 | 
						|
 | 
						|
        // Force full cleanup (this is safe and desirable since it only happens once):
 | 
						|
        rebuildOrderHeap();
 | 
						|
        garbageCollect();
 | 
						|
    }else{
 | 
						|
        // Cheaper cleanup:
 | 
						|
        checkGarbage();
 | 
						|
    }
 | 
						|
 | 
						|
    if (verbosity >= 1 && elimclauses.size() > 0)
 | 
						|
        printf("|  Eliminated clauses:     %10.2f Mb                                      |\n", 
 | 
						|
               double(elimclauses.size() * sizeof(uint32_t)) / (1024*1024));
 | 
						|
 | 
						|
    return ok;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//=================================================================================================
 | 
						|
// Garbage Collection methods:
 | 
						|
 | 
						|
 | 
						|
void SimpSolver::relocAll(ClauseAllocator& to)
 | 
						|
{
 | 
						|
    if (!use_simplification) return;
 | 
						|
 | 
						|
    // All occurs lists:
 | 
						|
    //
 | 
						|
    for (int i = 0; i < nVars(); i++){
 | 
						|
        occurs.clean(i);
 | 
						|
        vec<CRef>& cs = occurs[i];
 | 
						|
        for (int j = 0; j < cs.size(); j++)
 | 
						|
            ca.reloc(cs[j], to);
 | 
						|
    }
 | 
						|
 | 
						|
    // Subsumption queue:
 | 
						|
    //
 | 
						|
    for (int i = subsumption_queue.size(); i > 0; i--){
 | 
						|
        CRef cr = subsumption_queue.peek(); subsumption_queue.pop();
 | 
						|
        if (ca[cr].mark()) continue;
 | 
						|
        ca.reloc(cr, to);
 | 
						|
        subsumption_queue.insert(cr);
 | 
						|
    }
 | 
						|
        
 | 
						|
    // Temporary clause:
 | 
						|
    //
 | 
						|
    ca.reloc(bwdsub_tmpunit, to);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void SimpSolver::garbageCollect()
 | 
						|
{
 | 
						|
    // Initialize the next region to a size corresponding to the estimated utilization degree. This
 | 
						|
    // is not precise but should avoid some unnecessary reallocations for the new region:
 | 
						|
    ClauseAllocator to(ca.size() - ca.wasted()); 
 | 
						|
 | 
						|
    to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields.
 | 
						|
    relocAll(to);
 | 
						|
    Solver::relocAll(to);
 | 
						|
    if (verbosity >= 2)
 | 
						|
        printf("|  Garbage collection:   %12d bytes => %12d bytes             |\n", 
 | 
						|
               ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size);
 | 
						|
    to.moveTo(ca);
 | 
						|
}
 |