/***************************************************************************************[Solver.cc]
 Glucose -- Copyright (c) 2013, Gilles Audemard, Laurent Simon
                                CRIL - Univ. Artois, France
                                LRI  - Univ. Paris Sud, France
 
Glucose sources are based on MiniSat (see below MiniSat copyrights). Permissions and copyrights of
Glucose are exactly the same as Minisat on which it is based on. (see below).

---------------

Copyright (c) 2003-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 <math.h>

#include "sat/glucose2/Sort.h"
#include "sat/glucose2/Constants.h"
#include "sat/glucose2/System.h"
#include "sat/glucose2/Solver.h"

#include "sat/glucose2/CGlucose.h"

ABC_NAMESPACE_IMPL_START

using namespace Gluco2;

//=================================================================================================
// Options:
namespace Gluco2 {
static const char* _cat = "CORE";
static const char* _cr = "CORE -- RESTART";
static const char* _cred = "CORE -- REDUCE";
static const char* _cm = "CORE -- MINIMIZE";
static const char* _certified = "CORE -- CERTIFIED UNSAT";




static BoolOption    opt_incremental              (_cat,"incremental",             "Use incremental SAT solving",                                            false);
static DoubleOption  opt_K                        (_cr, "K",                       "The constant used to force restart",                                     0.8,  DoubleRange(0, false, 1, false));           
static DoubleOption  opt_R                        (_cr, "R",                       "The constant used to block restart",                                     1.4,  DoubleRange(1, false, 5, false));           
static IntOption     opt_size_lbd_queue           (_cr, "szLBDQueue",              "The size of moving average for LBD (restarts)",                          50,   IntRange(10, INT32_MAX));
static IntOption     opt_size_trail_queue         (_cr, "szTrailQueue",            "The size of moving average for trail (block restarts)",                  5000, IntRange(10, INT32_MAX));

static IntOption     opt_first_reduce_db          (_cred, "firstReduceDB",         "The number of conflicts before the first reduce DB",                     2000, IntRange(0, INT32_MAX));
static IntOption     opt_inc_reduce_db            (_cred, "incReduceDB",           "Increment for reduce DB",                                                300,  IntRange(0, INT32_MAX));
static IntOption     opt_spec_inc_reduce_db       (_cred, "specialIncReduceDB",    "Special increment for reduce DB",                                        1000, IntRange(0, INT32_MAX));
static IntOption     opt_lb_lbd_frozen_clause     (_cred, "minLBDFrozenClause",    "Protect clauses if their LBD decrease and is lower than (for one turn)", 30,   IntRange(0, INT32_MAX));

static IntOption     opt_lb_size_minimzing_clause (_cm, "minSizeMinimizingClause", "The min size required to minimize clause",                               30, IntRange(3, INT32_MAX));
static IntOption     opt_lb_lbd_minimzing_clause  (_cm, "minLBDMinimizingClause",  "The min LBD required to minimize clause",                                6, IntRange(3, INT32_MAX));


static DoubleOption  opt_var_decay         (_cat, "var-decay",   "The variable activity decay factor",                                                       0.8,      DoubleRange(0, false, 1, false));
static DoubleOption  opt_clause_decay      (_cat, "cla-decay",   "The clause activity decay factor",                                                         0.999,    DoubleRange(0, false, 1, false));
static DoubleOption  opt_random_var_freq   (_cat, "rnd-freq",    "The frequency with which the decision heuristic tries to choose a random variable",        0, DoubleRange(0, true, 1, true));
static DoubleOption  opt_random_seed       (_cat, "rnd-seed",    "Used by the random variable selection",                                                    91648253, DoubleRange(0, false, HUGE_VAL, false));
static IntOption     opt_ccmin_mode        (_cat, "ccmin-mode",  "Controls conflict clause minimization (0=none, 1=basic, 2=deep)",                          2, IntRange(0, 2));
static IntOption     opt_phase_saving      (_cat, "phase-saving", "Controls the level of phase saving (0=none, 1=limited, 2=full)",                          2, IntRange(0, 2));
static BoolOption    opt_rnd_init_act      (_cat, "rnd-init",    "Randomize the initial activity",                                                           false);
/*
static IntOption     opt_restart_first     (_cat, "rfirst",      "The base restart interval",                                                                100, IntRange(1, INT32_MAX));
static DoubleOption  opt_restart_inc       (_cat, "rinc",        "Restart interval increase factor",                                                         2, DoubleRange(1, false, HUGE_VAL, false));
*/
static DoubleOption  opt_garbage_frac      (_cat, "gc-frac",     "The fraction of wasted memory allowed before a garbage collection is triggered",           0.20, DoubleRange(0, false, HUGE_VAL, false));


BoolOption    opt_certified_      (_certified, "certified",         "Certified UNSAT using DRUP format", false );
StringOption  opt_certified_file_ (_certified, "certified-output",  "Certified UNSAT output file",       "NULL");
};

//=================================================================================================
// Constructor/Destructor:


Solver::Solver() :

    // Parameters (user settable):
    //
    SolverType(0)
    , pCnfFunc(NULL)
    , nCallConfl(1000)
    , terminate_search_early(false)
    , pstop(NULL)
    , nRuntimeLimit(0)

    , verbosity      (0)
    , verbEveryConflicts(10000)
    , showModel      (0)
    , K              (opt_K)
    , R              (opt_R)
    , sizeLBDQueue   (opt_size_lbd_queue)
    , sizeTrailQueue   (opt_size_trail_queue)
    , firstReduceDB  (opt_first_reduce_db)
    , incReduceDB    (opt_inc_reduce_db)
    , specialIncReduceDB    (opt_spec_inc_reduce_db)
    , lbLBDFrozenClause (opt_lb_lbd_frozen_clause)
    , lbSizeMinimizingClause (opt_lb_size_minimzing_clause)
    , lbLBDMinimizingClause (opt_lb_lbd_minimzing_clause)
  , var_decay        (opt_var_decay)
  , clause_decay     (opt_clause_decay)
  , random_var_freq  (opt_random_var_freq)
  , random_seed      (opt_random_seed)
  , ccmin_mode       (opt_ccmin_mode)
  , phase_saving     (opt_phase_saving)
  , rnd_pol          (false)
  , rnd_init_act     (opt_rnd_init_act)
  , garbage_frac     (opt_garbage_frac)
  , certifiedOutput  (NULL)
  , certifiedUNSAT   (opt_certified_) 
    // Statistics: (formerly in 'SolverStats')
    //
  ,  nbRemovedClauses(0),nbReducedClauses(0), nbDL2(0),nbBin(0),nbUn(0) , nbReduceDB(0)
    , solves(0), starts(0), decisions(0), rnd_decisions(0), propagations(0),conflicts(0),conflictsRestarts(0),nbstopsrestarts(0),nbstopsrestartssame(0),lastblockatrestart(0)
  , dec_vars(0), clauses_literals(0), learnts_literals(0), max_literals(0), tot_literals(0)
    , curRestart(1)

  , ok                 (true)
  , cla_inc            (1)
  , var_inc            (1)
  , watches            (WatcherDeleted(ca))
  , watchesBin            (WatcherDeleted(ca))
  , qhead              (0)
  , simpDB_assigns     (-1)
  , simpDB_props       (0)
  , order_heap         (VarOrderLt(activity))
  , progress_estimate  (0)
  , remove_satisfied   (true)

    // Resource constraints:
    //
  , conflict_budget    (-1)
  , propagation_budget (-1)
  , asynch_interrupt   (false)
  , incremental(opt_incremental)
  , nbVarsInitialFormula(INT32_MAX)

  #ifdef CGLUCOSE_EXP
  //, jheap         (JustOrderLt(this))
  , jheap         (JustOrderLt2(this))
  #endif
{
  MYFLAG=0;  

  // Initialize only first time. Useful for incremental solving, useless otherwise
  lbdQueue.initSize(sizeLBDQueue);
  trailQueue.initSize(sizeTrailQueue);
  sumLBD = 0;
  nbclausesbeforereduce = firstReduceDB;
  totalTime4Sat=0;totalTime4Unsat=0;
  nbSatCalls=0;nbUnsatCalls=0;


  if(certifiedUNSAT) {
    if(!strcmp(opt_certified_file_,"NULL")) {
      certifiedOutput =  fopen("/dev/stdout", "wb");
    } else {
      certifiedOutput =  fopen(opt_certified_file_, "wb");           
    }
    //    fprintf(certifiedOutput,"o proof DRUP\n");
  }

  #ifdef CGLUCOSE_EXP
  jhead= 0;
  jftr = 0;
  travId = 0;
  travId_prev = 0;

  // allocate space for clause interpretation 
  vec<Lit> tmp; tmp.growTo(3); 
  itpc = ca.alloc(tmp);
  ca[itpc].shrink( ca[itpc].size() );

  nSkipMark = 0;
  #endif
}


Solver::~Solver()
{
}


/****************************************************************
 Set the incremental mode
****************************************************************/

// This function set the incremental mode to true.
// You can add special code for this mode here.

void Solver::setIncrementalMode() {
  incremental = true;
}

// Number of variables without selectors
void Solver::initNbInitialVars(int nb) {
  nbVarsInitialFormula = nb;
}


//=================================================================================================
// Minor methods:


// Creates a new SAT variable in the solver. If 'decision' is cleared, variable will not be
// used as a decision variable (NOTE! This has effects on the meaning of a SATISFIABLE result).
//
Var Solver::newVar(bool sign, bool dvar)
{
    int v = nVars();
    watches  .init(mkLit(v, false));
    watches  .init(mkLit(v, true ));
    watchesBin  .init(mkLit(v, false));
    watchesBin  .init(mkLit(v, true ));
    assigns  .push(l_Undef);
    vardata  .push(mkVarData(CRef_Undef, 0));
    //activity .push(0);
    activity .push(rnd_init_act ? drand(random_seed) * 0.00001 : 0);
    seen     .push(0);
    permDiff .push(0);
    polarity .push(sign);
    decision .push();
    trail    .capacity(v+1);
    

    #ifdef CGLUCOSE_EXP
    //jreason  .capacity(v+1);
    if( justUsage() ){
        //jdata    .push(mkJustData(false));
        //jwatch   .push(mkJustWatch());

        jlevel   .push(-1);
        jnext    .push(-1);

        var2FanoutN.growTo( nVars()<<1, toLit(~0));
        //var2FanoutP.growTo( nVars()<<1, toLit(~0));
        var2Fanout0.growTo( nVars(), toLit(~0));
        var2NodeData.growTo( nVars(), mkNodeData());
        var2TravId .growTo( nVars(), 0);

        setDecisionVar(v, dvar, false);
    } else 
        setDecisionVar(v, dvar);
    #else
    setDecisionVar(v, dvar);
    #endif

    return v;
}



bool Solver::addClause_(vec<Lit>& ps)
{
    assert(decisionLevel() == 0);
    if (!ok) return false;

    if ( 0 ) {
        for ( int i = 0; i < ps.size(); i++ )
            printf( "%s%d ", (toInt(ps[i]) & 1) ? "-":"", toInt(ps[i]) >> 1 );
        printf( "\n" );
    }

    // Check if clause is satisfied and remove false/duplicate literals:
    sort(ps);

    vec<Lit>    oc;
    oc.clear();

    Lit p; int i, j, flag = 0;
    if(certifiedUNSAT) {
      for (i = j = 0, p = lit_Undef; i < ps.size(); i++) {
        oc.push(ps[i]);
        if (value(ps[i]) == l_True || ps[i] == ~p || value(ps[i]) == l_False)
          flag = 1;
      }
    }

    for (i = j = 0, p = lit_Undef; i < ps.size(); i++)
      if (value(ps[i]) == l_True || ps[i] == ~p)
        return true;
      else if (value(ps[i]) != l_False && ps[i] != p)
        ps[j++] = p = ps[i];
    ps.shrink_(i - j);

    if ( 0 ) {
        for ( int i = 0; i < ps.size(); i++ )
            printf( "%s%d ", (toInt(ps[i]) & 1) ? "-":"", toInt(ps[i]) >> 1 );
        printf( "\n" );
    }
    
    if (flag && (certifiedUNSAT)) {
      for (i = j = 0, p = lit_Undef; i < ps.size(); i++)
        fprintf(certifiedOutput, "%i ", (var(ps[i]) + 1) * (-2 * sign(ps[i]) + 1));
      fprintf(certifiedOutput, "0\n");

      fprintf(certifiedOutput, "d ");
      for (i = j = 0, p = lit_Undef; i < oc.size(); i++)
        fprintf(certifiedOutput, "%i ", (var(oc[i]) + 1) * (-2 * sign(oc[i]) + 1));
      fprintf(certifiedOutput, "0\n");
    }

    if (ps.size() == 0)
        return ok = false;
    else if (ps.size() == 1){
        uncheckedEnqueue(ps[0]);
        return ok = (propagate() == CRef_Undef);
    }else{
        CRef cr = ca.alloc(ps, false);
        clauses.push(cr);
        attachClause(cr);
    }

    return true;
}


void Solver::attachClause(CRef cr) {
    const Clause& c = ca[cr];

    assert(c.size() > 1);
    if(c.size()==2) {
      watchesBin[~c[0]].push(Watcher(cr, c[1]));
      watchesBin[~c[1]].push(Watcher(cr, c[0]));
    } else {
      watches[~c[0]].push(Watcher(cr, c[1]));
      watches[~c[1]].push(Watcher(cr, c[0]));
    }
    if (c.learnt()) learnts_literals += c.size();
    else            clauses_literals += c.size(); }




void Solver::detachClause(CRef cr, bool strict) {
    const Clause& c = ca[cr];
    
    assert(c.size() > 1);
    if(c.size()==2) {
      if (strict){
        remove(watchesBin[~c[0]], Watcher(cr, c[1]));
        remove(watchesBin[~c[1]], Watcher(cr, c[0]));
      }else{
        // Lazy detaching: (NOTE! Must clean all watcher lists before garbage collecting this clause)
        watchesBin.smudge(~c[0]);
        watchesBin.smudge(~c[1]);
      }
    } else {
      if (strict){
        remove(watches[~c[0]], Watcher(cr, c[1]));
        remove(watches[~c[1]], Watcher(cr, c[0]));
      }else{
        // Lazy detaching: (NOTE! Must clean all watcher lists before garbage collecting this clause)
        watches.smudge(~c[0]);
        watches.smudge(~c[1]);
      }
    }
    if (c.learnt()) learnts_literals -= c.size();
    else            clauses_literals -= c.size(); }


void Solver::removeClause(CRef cr) {

  Clause& c = ca[cr];

  if (certifiedUNSAT) {
    fprintf(certifiedOutput, "d ");
    for (int i = 0; i < c.size(); i++)
      fprintf(certifiedOutput, "%i ", (var(c[i]) + 1) * (-2 * sign(c[i]) + 1));
    fprintf(certifiedOutput, "0\n");
  }

  detachClause(cr);
  // Don't leave pointers to free'd memory!
  if (locked(c)) vardata[var(c[0])].reason = CRef_Undef;
  c.mark(1);
  ca.free_(cr);
}


bool Solver::satisfied(const Clause& c) const {
  if(incremental)  // Check clauses with many selectors is too time consuming
    return (value(c[0]) == l_True) || (value(c[1]) == l_True);

  // Default mode.
    for (int i = 0; i < c.size(); i++)
        if (value(c[i]) == l_True)
            return true;
    return false; 
}

/************************************************************
 * Compute LBD functions
 *************************************************************/

inline unsigned int Solver::computeLBD(const vec<Lit> & lits,int end) {
  int nblevels = 0;
  MYFLAG++;

  if(incremental) { // ----------------- INCREMENTAL MODE
    if(end==-1) end = lits.size();
    unsigned int nbDone = 0;
    for(int i=0;i<lits.size();i++) {
      if(nbDone>=end) break;
      if(isSelector(var(lits[i]))) continue;
      nbDone++;
      int l = level(var(lits[i]));
      if (permDiff[l] != MYFLAG) {
        permDiff[l] = MYFLAG;
        nblevels++;
      }
    }
  } else { // -------- DEFAULT MODE. NOT A LOT OF DIFFERENCES... BUT EASIER TO READ
    for(int i=0;i<lits.size();i++) {
      int l = level(var(lits[i]));
      if (permDiff[l] != MYFLAG) {
        permDiff[l] = MYFLAG;
        nblevels++;
      }
    }
  }

  return nblevels;
}

inline unsigned int Solver::computeLBD(const Clause &c) {
  int nblevels = 0;
  MYFLAG++;

  if(incremental) { // ----------------- INCREMENTAL MODE
     int nbDone = 0;
    for(int i=0;i<c.size();i++) {
      if(nbDone>=c.sizeWithoutSelectors()) break;
      if(isSelector(var(c[i]))) continue;
      nbDone++;
      int l = level(var(c[i]));
      if (permDiff[l] != MYFLAG) {
        permDiff[l] = MYFLAG;
        nblevels++;
      }
    }
  } else { // -------- DEFAULT MODE. NOT A LOT OF DIFFERENCES... BUT EASIER TO READ
    for(int i=0;i<c.size();i++) {
      int l = level(var(c[i]));
      if (permDiff[l] != MYFLAG) {
        permDiff[l] = MYFLAG;
        nblevels++;
      }
    }
  }
  return nblevels;
}


/******************************************************************
 * Minimisation with binary reolution
 ******************************************************************/
void Solver::minimisationWithBinaryResolution(vec<Lit> &out_learnt) {
  
  // Find the LBD measure                                                                                                         
  unsigned int lbd = computeLBD(out_learnt);
  Lit p = ~out_learnt[0];
  
  if(lbd<=lbLBDMinimizingClause){
    MYFLAG++;
    
    for(int i = 1;i<out_learnt.size();i++) {
      permDiff[var(out_learnt[i])] = MYFLAG;
    }

    vec<Watcher>&  wbin  = watchesBin[p];
    int nb = 0;
    for(int k = 0;k<wbin.size();k++) {
      Lit imp = wbin[k].blocker;
      if(permDiff[var(imp)]==MYFLAG && value(imp)==l_True) {
        nb++;
        permDiff[var(imp)]= MYFLAG-1;
      }
      }
    int l = out_learnt.size()-1;
    if(nb>0) {
      nbReducedClauses++;
      for(int i = 1;i<out_learnt.size()-nb;i++) {
        if(permDiff[var(out_learnt[i])]!=MYFLAG) {
          Lit p = out_learnt[l];
          out_learnt[l] = out_learnt[i];
          out_learnt[i] = p;
          l--;i--;
        }
      }
      
      out_learnt.shrink_(nb);
      
    }
  }
}

// Revert to the state at given level (keeping all assignment at 'level' but not beyond).
//
void Solver::cancelUntil(int level) {
    if (decisionLevel() > level){

        #ifdef CGLUCOSE_EXP
        if( 0 < justUsage() ){

            for (int c = trail.size()-1; c >= trail_lim[level]; c--){
                Var      x  = var(trail[c]);
                assigns [x] = l_Undef;
                if (phase_saving > 1 || ((phase_saving == 1) && c > trail_lim.last()))
                    polarity[x] = sign(trail[c]);
                //gateClearJwatch(x, level);

                var2NodeData[x].now = false;
            }
            for (int l = decisionLevel(); l > level; l -- ){
                int q = jlevel[l], k;
                jlevel[l] = -1;
                while( -1 != q ){
                    k = jnext[q];
                    jnext[q] = -1;
                    Var v = var(trail[q]);
                    if( Solver::level(v) <= level ){
                        pushJustQueue(v,q);
                    }
                    q = k;
                }
            }
        } else 
        #endif
            for (int c = trail.size()-1; c >= trail_lim[level]; c--){
                Var      x  = var(trail[c]);
                assigns [x] = l_Undef;
                if (phase_saving > 1 || ((phase_saving == 1) && c > trail_lim.last()))
                    polarity[x] = sign(trail[c]);
                insertVarOrder(x);
            }

        jhead = qhead = trail_lim[level];

        trail.shrink_(trail.size() - trail_lim[level]);
        trail_lim.shrink_(trail_lim.size() - level);
    }
}


//=================================================================================================
// Major methods:


Lit Solver::pickBranchLit()
{
    Var next = var_Undef;

    // Random decision:
    if (drand(random_seed) < random_var_freq && !order_heap.empty()){
        next = order_heap[irand(random_seed,order_heap.size())];
        if (value(next) == l_Undef && decision[next])
            rnd_decisions++; }

    // Activity based decision:
    while (next == var_Undef || value(next) != l_Undef || !decision[next])
        if (order_heap.empty()){
            next = var_Undef;
            break;
        }else
            next = order_heap.removeMin();
    
    return next == var_Undef ? lit_Undef : mkLit(next, rnd_pol ? drand(random_seed) < 0.5 : (polarity[next] != 0));
}


/*_________________________________________________________________________________________________
|
|  analyze : (confl : Clause*) (out_learnt : vec<Lit>&) (out_btlevel : int&)  ->  [void]
|  
|  Description:
|    Analyze conflict and produce a reason clause.
|  
|    Pre-conditions:
|      * 'out_learnt' is assumed to be cleared.
|      * Current decision level must be greater than root level.
|  
|    Post-conditions:
|      * 'out_learnt[0]' is the asserting literal at level 'out_btlevel'.
|      * If out_learnt.size() > 1 then 'out_learnt[1]' has the greatest decision level of the 
|        rest of literals. There may be others from the same level though.
|  
|________________________________________________________________________________________________@*/
void Solver::analyze(CRef confl, vec<Lit>& out_learnt,vec<Lit>&selectors, int& out_btlevel,unsigned int &lbd,unsigned int &szWithoutSelectors)
{
    //double clk = Abc_Clock();
    heap_rescale = 0;

    int pathC = 0;
    Lit p     = lit_Undef;

    // Generate conflict clause:
    //
    out_learnt.push();      // (leave room for the asserting literal)
    int index   = trail.size() - 1;
    
    analyze_toclear.shrink_( analyze_toclear.size() );
    do{
        assert(confl != CRef_Undef); // (otherwise should be UIP)

        #ifdef CGLUCOSE_EXP
        Clause& c = ca[ lit_Undef != p ? castCRef(p): getConfClause(confl) ];
        #else
        Clause& c = ca[confl];
        #endif

        // Special case for binary clauses
        // The first one has to be SAT
        if( p != lit_Undef && c.size()==2 && value(c[0])==l_False) {

            assert(value(c[1])==l_True);
            Lit tmp = c[0];
            c[0] =  c[1], c[1] = tmp;
        }
        
        if (c.learnt()) 
            claBumpActivity(c);

#ifdef DYNAMICNBLEVEL               
        // DYNAMIC NBLEVEL trick (see competition'09 companion paper)
        if(c.learnt()  && c.lbd()>2) {
            unsigned int nblevels = computeLBD(c);
            if(nblevels+1<c.lbd() ) { // improve the LBD
                if(c.lbd()<=lbLBDFrozenClause) {
                    c.setCanBeDel(false);
                }
                // seems to be interesting : keep it for the next round
                c.setLBD(nblevels); // Update it
            }
        }
#endif


        for (int j = (p == lit_Undef) ? 0 : 1; j < c.size(); j++){
            Lit q = c[j];
            bool fBump = 0;

            if (!seen[var(q)] && level(var(q)) > 0){
                if(!isSelector(var(q))){
                    fBump = 1;
                    varBumpActivity(var(q));
                }
                seen[var(q)] = 1;
                if (level(var(q)) >= decisionLevel()) {
                    if( fBump )
                        analyze_toclear.push(q);
                    pathC++;
                    #ifdef UPDATEVARACTIVITY
                    // UPDATEVARACTIVITY trick (see competition'09 companion paper)
                    #ifdef CGLUCOSE_EXP
                    if(!isSelector(var(q)) && (reason(var(q))!= CRef_Undef)  
                    && ! isGateCRef(reason(var(q))) && ca[reason(var(q))].learnt())
                        lastDecisionLevel.push(q);
                    #else
                    if(!isSelector(var(q)) && (reason(var(q))!= CRef_Undef)  && ca[reason(var(q))].learnt()) 
                        lastDecisionLevel.push(q);
                    #endif
                    #endif

                } else {
                    if(isSelector(var(q))) {
                        assert(value(q) == l_False);
                        selectors.push(q);
                    } else 
                        out_learnt.push(q);
                }
            }
        }
        
        // Select next clause to look at:
        while (!seen[var(trail[index--])]);
        p     = trail[index+1];
        confl = reason(var(p));
        seen[var(p)] = 0;
        pathC--;

    }while (pathC > 0);
    out_learnt[0] = ~p;

    // Simplify conflict clause:
    //
    int i, j;

    for(i = 0;i<selectors.size();i++) out_learnt.push(selectors[i]);       


    #ifdef CGLUCOSE_EXP
    for(i = 0;i<out_learnt.size();i++)  
        analyze_toclear.push(out_learnt[i]);
    #else
    out_learnt.copyTo_(analyze_toclear);
    #endif
    if (ccmin_mode == 2){
        uint32_t abstract_level = 0;
        for (i = 1; i < out_learnt.size(); i++)
            abstract_level |= abstractLevel(var(out_learnt[i])); // (maintain an abstraction of levels involved in conflict)

        for (i = j = 1; i < out_learnt.size(); i++)
            if (reason(var(out_learnt[i])) == CRef_Undef || !litRedundant(out_learnt[i], abstract_level))
                out_learnt[j++] = out_learnt[i];
        
    }else if (ccmin_mode == 1){
        for (i = j = 1; i < out_learnt.size(); i++){
            Var x = var(out_learnt[i]);

            if (reason(x) == CRef_Undef)
                out_learnt[j++] = out_learnt[i];
            else{
                #ifdef CGLUCOSE_EXP
                Clause& c = ca[castCRef(out_learnt[i])];
                #else
                Clause& c = ca[reason(var(out_learnt[i]))];
                #endif
                // Thanks to Siert Wieringa for this bug fix!
                for (int k = ((c.size()==2) ? 0:1); k < c.size(); k++)
                    if (!seen[var(c[k])] && level(var(c[k])) > 0){
                        out_learnt[j++] = out_learnt[i];
                        break; }
            }
        }
    }else
        i = j = out_learnt.size();

    max_literals += out_learnt.size();
    out_learnt.shrink_(i - j);
    tot_literals += out_learnt.size();


    /* ***************************************
      Minimisation with binary clauses of the asserting clause
      First of all : we look for small clauses
      Then, we reduce clauses with small LBD.
      Otherwise, this can be useless
     */
    if(!incremental && out_learnt.size()<=lbSizeMinimizingClause) {
      minimisationWithBinaryResolution(out_learnt);
    }
    // Find correct backtrack level:
    //
    if (out_learnt.size() == 1)
        out_btlevel = 0;
    else{
        int max_i = 1;
        // Find the first literal assigned at the next-highest level:
        for (int i = 2; i < out_learnt.size(); i++)
            if (level(var(out_learnt[i])) > level(var(out_learnt[max_i])))
                max_i = i;
        // Swap-in this literal at index 1:
        Lit p             = out_learnt[max_i];
        out_learnt[max_i] = out_learnt[1];
        out_learnt[1]     = p;
        out_btlevel       = level(var(p));
    }


    // Compute the size of the clause without selectors (incremental mode)
    if(incremental) {
      szWithoutSelectors = 0;
      for(int i=0;i<out_learnt.size();i++) {
        if(!isSelector(var((out_learnt[i])))) szWithoutSelectors++; 
        else if(i>0) break;
      }
    } else 
      szWithoutSelectors = out_learnt.size();
    
    // Compute LBD
    lbd = computeLBD(out_learnt,out_learnt.size()-selectors.size());

  
#ifdef UPDATEVARACTIVITY
    // UPDATEVARACTIVITY trick (see competition'09 companion paper)
    if(lastDecisionLevel.size()>0) {
        for(int i = 0;i<lastDecisionLevel.size();i++) {
            Lit t = lastDecisionLevel[i];
            //assert( ca[reason(var(t))].learnt() );
            if(ca[reason(var(t))].lbd()<lbd)
                varBumpActivity(var(t));
        }
        lastDecisionLevel.shrink_( lastDecisionLevel.size() );
    } 
#endif


    if( justUsage() ){
        if( heap_rescale )
        {
            for (j = 0; j < analyze_toclear.size(); j++) seen[var(analyze_toclear[j])] = 0;

            analyze_toclear.shrink_( analyze_toclear.size() );
            for (j = 0; j < jheap.size(); j++){
                Var x = jheap[j];
                if( var2NodeData[x].now )
                    analyze_toclear.push(mkLit(x));
            }
            for (j = 0; j < analyze_toclear.size(); j++){
                Var x = var(analyze_toclear[j]);
//                jdata[x].act_fanin = activity[getFaninVar0(x)] > activity[getFaninVar1(x)]? activity[getFaninVar0(x)]: activity[getFaninVar1(x)];
//                jheap.update(x);
                if( activity[getFaninVar1(x)] > activity[getFaninVar0(x)] )
                    jheap.update( JustKey( activity[getFaninVar1(x)], x, jheap.data_attr(x) ) );
                else
                    jheap.update( JustKey( activity[getFaninVar0(x)], x, jheap.data_attr(x) ) );
            }

        } else {

            for (j = 0; j < analyze_toclear.size(); j++)
            {
                seen[var(analyze_toclear[j])] = 0;
                updateJustActivity(var(analyze_toclear[j]));
            }
        }
    } else
        for (j = 0; j < analyze_toclear.size(); j++) seen[var(analyze_toclear[j])] = 0;    // ('seen[]' is now cleared)
    for(j = 0 ; j<selectors.size() ; j++) seen[var(selectors[j])] = 0;
}


// Check if 'p' can be removed. 'abstract_levels' is used to abort early if the algorithm is
// visiting literals at levels that cannot be removed later.
bool Solver::litRedundant(Lit p, uint32_t abstract_levels)
{
    analyze_stack.shrink_( analyze_stack.size() ); analyze_stack.push(p);
    int top = analyze_toclear.size();
    while (analyze_stack.size() > 0){
        assert(reason(var(analyze_stack.last())) != CRef_Undef);
        #ifdef CGLUCOSE_EXP
        Clause& c = ca[castCRef(analyze_stack.last())]; analyze_stack.pop();
        #else
        Clause& c = ca[reason(var(analyze_stack.last()))]; analyze_stack.pop();
        #endif
        if(c.size()==2 && value(c[0])==l_False) {
          assert(value(c[1])==l_True);
          Lit tmp = c[0];
          c[0] =  c[1], c[1] = tmp;
        }

        for (int i = 1; i < c.size(); i++){
            Lit p  = c[i];
            if (!seen[var(p)] && level(var(p)) > 0){
                if (reason(var(p)) != CRef_Undef && (abstractLevel(var(p)) & abstract_levels) != 0){
                    seen[var(p)] = 1;
                    analyze_stack.push(p);
                    analyze_toclear.push(p);
                }else{
                    for (int j = top; j < analyze_toclear.size(); j++)
                        seen[var(analyze_toclear[j])] = 0;
                    analyze_toclear.shrink_(analyze_toclear.size() - top);
                    return false;
                }
            }
        }
    }

    return true;
}


/*_________________________________________________________________________________________________
|
|  analyzeFinal : (p : Lit)  ->  [void]
|  
|  Description:
|    Specialized analysis procedure to express the final conflict in terms of assumptions.
|    Calculates the (possibly empty) set of assumptions that led to the assignment of 'p', and
|    stores the result in 'out_conflict'.
|________________________________________________________________________________________________@*/
void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict)
{
    out_conflict.shrink_( out_conflict.size() );
    out_conflict.push(p);

    if (decisionLevel() == 0)
        return;

    seen[var(p)] = 1;

    for (int i = trail.size()-1; i >= trail_lim[0]; i--){
        Var x = var(trail[i]);
        if (seen[x]){
            if (reason(x) == CRef_Undef){
                assert(level(x) > 0);
                out_conflict.push(~trail[i]);
            }else{
              #ifdef CGLUCOSE_EXP
                Clause& c = ca[castCRef(trail[i])];
              #else
                Clause& c = ca[reason(x)];
              #endif
                //                for (int j = 1; j < c.size(); j++) Minisat (glucose 2.0) loop 
                // Bug in case of assumptions due to special data structures for Binary.
                // Many thanks to Sam Bayless (sbayless@cs.ubc.ca) for discover this bug.
                for (int j = ((c.size()==2) ? 0:1); j < c.size(); j++)
                    if (level(var(c[j])) > 0)
                        seen[var(c[j])] = 1;
            }  

            seen[x] = 0;
        }
    }

    seen[var(p)] = 0;
}

void Solver::uncheckedEnqueue(Lit p, CRef from)
{
    if( justUsage() && !isRoundWatch(var(p)) )
        return;
    assert(value(p) == l_Undef);
    assigns[var(p)] = lbool(!sign(p));
    vardata[var(p)] = mkVarData(from, decisionLevel());
    trail.push_(p);
}


/*_________________________________________________________________________________________________
|
|  propagate : [void]  ->  [Clause*]
|  
|  Description:
|    Propagates all enqueued facts. If a conflict arises, the conflicting clause is returned,
|    otherwise CRef_Undef.
|  
|    Post-conditions:
|      * the propagation queue is empty, even if there was a conflict.
|________________________________________________________________________________________________@*/
CRef Solver::propagate()
{
    CRef    confl     = CRef_Undef;
    int     num_props = 0;
    watches.cleanAll();
    watchesBin.cleanAll();
    while (qhead < trail.size()){
        Lit            p   = trail[qhead++];     // 'p' is enqueued fact to propagate.
        vec<Watcher>&  ws  = watches[p];
        Watcher        *i, *j, *end;
        num_props++;

        #ifdef CGLUCOSE_EXP
        if( 2 <= justUsage() ){
            CRef stats;
            if( CRef_Undef != (stats = gatePropagate(p)) ){
                confl = stats;
                if( l_True == value(var(p)) ) return confl;
            }
        }
        #endif

        // First, Propagate binary clauses 
        vec<Watcher>&  wbin  = watchesBin[p];
        for(int k = 0;k<wbin.size();k++) {
          Lit imp = wbin[k].blocker;
          if(value(imp) == l_False) {
            return wbin[k].cref;
          }
          if(value(imp) == l_Undef) {
            uncheckedEnqueue(imp,wbin[k].cref);
          }
        }



        for (i = j = (Watcher*)ws, end = i + ws.size();  i != end;){
            // Try to avoid inspecting the clause:
            Lit blocker = i->blocker;
            if (value(blocker) == l_True){
                *j++ = *i++; continue; }

            // Make sure the false literal is data[1]:
            CRef     cr        = i->cref;
            Clause&  c         = ca[cr];
            Lit      false_lit = ~p;
            if (c[0] == false_lit)
                c[0] = c[1], c[1] = false_lit;
            assert(c[1] == false_lit);
            i++;

            // If 0th watch is true, then clause is already satisfied.
            Lit     first = c[0];
            Watcher w     = Watcher(cr, first);
            if (first != blocker && value(first) == l_True){
              *j++ = w; continue; }

            // Look for new watch:
            if(incremental) { // ----------------- INCREMENTAL MODE
              int choosenPos = -1;
              for (int k = 2; k < c.size(); k++) {
                
                if (value(c[k]) != l_False){
                  if(decisionLevel()>assumptions.size()) {
                    choosenPos = k;
                    break;
                  } else {
                    choosenPos = k;
                    
                    if(value(c[k])==l_True || !isSelector(var(c[k]))) {
                      break;
                    }
                  }

                }
              }
              if(choosenPos!=-1) {
                c[1] = c[choosenPos]; c[choosenPos] = false_lit;
                watches[~c[1]].push(w);
                goto NextClause; }
            } else {  // ----------------- DEFAULT  MODE (NOT INCREMENTAL)
              for (int k = 2; k < c.size(); k++) {
                
                if (value(c[k]) != l_False){
                  c[1] = c[k]; c[k] = false_lit;
                  watches[~c[1]].push(w);
                  goto NextClause; }
              }
            }

            // Did not find watch -- clause is unit under assignment:
            *j++ = w;
            if (value(first) == l_False){
                confl = cr;
                qhead = trail.size();
                // Copy the remaining watches:
                while (i < end)
                    *j++ = *i++;
            }else {
                uncheckedEnqueue(first, cr);
          
                
            }
        NextClause:;
        }
        ws.shrink_(i - j);
    }
    propagations += num_props;
    simpDB_props -= num_props;

    return confl;
}






/*_________________________________________________________________________________________________
|
|  reduceDB : ()  ->  [void]
|  
|  Description:
|    Remove half of the learnt clauses, minus the clauses locked by the current assignment. Locked
|    clauses are clauses that are reason to some assignment. Binary clauses are never removed.
|________________________________________________________________________________________________@*/
struct reduceDB_lt { 
    ClauseAllocator& ca;
    reduceDB_lt(ClauseAllocator& ca_) : ca(ca_) {}
    bool operator () (CRef x, CRef y) { 
 
    // Main criteria... Like in MiniSat we keep all binary clauses
    if(ca[x].size()> 2 && ca[y].size()==2) return 1;
    
    if(ca[y].size()> 2 && ca[x].size()==2) return 0;
    if(ca[x].size()==2 && ca[y].size()==2) return 0;
    
    // Second one  based on literal block distance
    if(ca[x].lbd()> ca[y].lbd()) return 1;
    if(ca[x].lbd()< ca[y].lbd()) return 0;    
    
    // Finally we can use old activity or size, we choose the last one
    return ca[x].activity() < ca[y].activity();
    //return x->size() < y->size();
    //return ca[x].size() > 2 && (ca[y].size() == 2 || ca[x].activity() < ca[y].activity()); } 
    }    
};

void Solver::reduceDB()
{ 
  int i, j;
  nbReduceDB++;
  sort(learnts, reduceDB_lt(ca));

  // We have a lot of "good" clauses, it is difficult to compare them. Keep more !
  if(ca[learnts[learnts.size() / RATIOREMOVECLAUSES]].lbd()<=3) nbclausesbeforereduce +=specialIncReduceDB; 
  // Useless :-)
  if(ca[learnts.last()].lbd()<=5)  nbclausesbeforereduce +=specialIncReduceDB;   
  
  // Don't delete binary or locked clauses. From the rest, delete clauses from the first half
  // Keep clauses which seem to be usefull (their lbd was reduce during this sequence)

  int limit = learnts.size() / 2;
  for (i = j = 0; i < learnts.size(); i++){
    Clause& c = ca[learnts[i]];
    if (c.lbd()>2 && c.size() > 2 && c.canBeDel() &&  !locked(c) && (i < limit)) {
      removeClause(learnts[i]);
      nbRemovedClauses++;
    }
    else {
      if(!c.canBeDel()) limit++; //we keep c, so we can delete an other clause
      c.setCanBeDel(true);       // At the next step, c can be delete
      learnts[j++] = learnts[i];
    }
  }
  learnts.shrink_(i - j);
  checkGarbage();
}


void Solver::removeSatisfied(vec<CRef>& cs)
{
    int i, j;
    for (i = j = 0; i < cs.size(); i++){
        Clause& c = ca[cs[i]];
        if (satisfied(c)) 
            removeClause(cs[i]);
        else
            cs[j++] = cs[i];
    }
    cs.shrink_(i - j);
}


void Solver::rebuildOrderHeap()
{
    vec<Var> vs;
    for (Var v = 0; v < nVars(); v++)
        if (decision[v] && value(v) == l_Undef)
            vs.push(v);
    order_heap.build(vs);
}


/*_________________________________________________________________________________________________
|
|  simplify : [void]  ->  [bool]
|  
|  Description:
|    Simplify the clause database according to the current top-level assigment. Currently, the only
|    thing done here is the removal of satisfied clauses, but more things can be put here.
|________________________________________________________________________________________________@*/
bool Solver::simplify()
{
    assert(decisionLevel() == 0);

    if (!ok || propagate() != CRef_Undef)
        return ok = false;

    if (nAssigns() == simpDB_assigns || (simpDB_props > 0))
        return true;

    // Remove satisfied clauses:
    removeSatisfied(learnts);
    if (remove_satisfied)        // Can be turned off.
        removeSatisfied(clauses);

    checkGarbage();

    #ifdef CGLUCOSE_EXP
    if( !justUsage() )
    #endif
        rebuildOrderHeap();

    simpDB_assigns = nAssigns();
    simpDB_props   = clauses_literals + learnts_literals;   // (shouldn't depend on stats really, but it will do for now)

    return true;
}


/*_________________________________________________________________________________________________
|
|  search : (nof_conflicts : int) (params : const SearchParams&)  ->  [lbool]
|  
|  Description:
|    Search for a model the specified number of conflicts. 
|    NOTE! Use negative value for 'nof_conflicts' indicate infinity.
|  
|  Output:
|    'l_True' if a partial assigment that is consistent with respect to the clauseset is found. If
|    all variables are decision variables, this means that the clause set is satisfiable. 'l_False'
|    if the clause set is unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached.
|________________________________________________________________________________________________@*/
lbool Solver::search(int nof_conflicts)
{
    assert(ok);
    int         backtrack_level;
    int         conflictC = 0;
    vec<Lit>    learnt_clause,selectors;
    unsigned int nblevels,szWoutSelectors;
    bool blocked=false;
    starts++;

    for (;;){
        CRef confl = propagate();

        // exact conflict limit
        if ( !withinBudget() && confl != CRef_Undef ) {
          lbdQueue.fastclear();
          cancelUntil(0);
          return l_Undef; }

        if (confl != CRef_Undef){

            // CONFLICT
          conflicts++; conflictC++;conflictsRestarts++;
          if(conflicts%5000==0 && var_decay<0.95)
            var_decay += 0.01;

          if (verbosity >= 1 && conflicts%verbEveryConflicts==0){
            printf("c | %8d   %7d    %5d | %7d %8d %8d | %5d %8d   %6d %8d | %6.3f %% \n", 
                   (int)starts,(int)nbstopsrestarts, (int)(conflicts/starts), 
                   (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]), nClauses(), (int)clauses_literals, 
                   (int)nbReduceDB, nLearnts(), (int)nbDL2,(int)nbRemovedClauses, progressEstimate()*100);
          }
          if (decisionLevel() == 0) 
            return l_False;


          trailQueue.push(trail.size());
          // BLOCK RESTART (CP 2012 paper)
          if( conflictsRestarts>LOWER_BOUND_FOR_BLOCKING_RESTART && lbdQueue.isvalid()  && trail.size()>R*trailQueue.getavg()) {
            lbdQueue.fastclear();
            nbstopsrestarts++;
            if(!blocked) {lastblockatrestart=starts;nbstopsrestartssame++;blocked=true;}
          }

            learnt_clause.shrink_( learnt_clause.size() );
            selectors    .shrink_( selectors.size() );
            analyze(confl, learnt_clause, selectors,backtrack_level,nblevels,szWoutSelectors);

            lbdQueue.push(nblevels);
            sumLBD += nblevels;
            cancelUntil(backtrack_level);
            if (certifiedUNSAT) {
              for (int i = 0; i < learnt_clause.size(); i++)
                fprintf(certifiedOutput, "%i " , (var(learnt_clause[i]) + 1) *
                            (-2 * sign(learnt_clause[i]) + 1) );
              fprintf(certifiedOutput, "0\n");
            }

            if (learnt_clause.size() == 1){
              uncheckedEnqueue(learnt_clause[0]);nbUn++;
            }else{
                CRef cr = ca.alloc(learnt_clause, true);
                ca[cr].setLBD(nblevels); 
                ca[cr].setSizeWithoutSelectors(szWoutSelectors);
                if(nblevels<=2) nbDL2++; // stats
                if(ca[cr].size()==2) nbBin++; // stats
                learnts.push(cr);
                attachClause(cr);

                claBumpActivity(ca[cr]);
                uncheckedEnqueue(learnt_clause[0], cr);
            }
            varDecayActivity();
            claDecayActivity();

        }else{
            // Our dynamic restart, see the SAT09 competition compagnion paper 
            if ( (conflictsRestarts && lbdQueue.isvalid() && lbdQueue.getavg()*K > sumLBD/conflictsRestarts) || (pstop && *pstop) ) {
                lbdQueue.fastclear();
                progress_estimate = progressEstimate();
                int bt = 0;
                if(incremental) { // DO NOT BACKTRACK UNTIL 0.. USELESS
                    bt = (decisionLevel()<assumptions.size()) ? decisionLevel() : assumptions.size();
                }
                cancelUntil(bt);
                return l_Undef; 
            }

            // Simplify the set of problem clauses:
            if (decisionLevel() == 0 && !simplify()) {
                return l_False;
            }
            // Perform clause database reduction !
            if(conflicts>=curRestart* nbclausesbeforereduce)
            {
                assert(learnts.size()>0);
                curRestart = (conflicts/ nbclausesbeforereduce)+1;
                reduceDB();
                nbclausesbeforereduce += incReduceDB;
            }

            Lit next = lit_Undef;
            while (decisionLevel() < assumptions.size()){
                // Perform user provided assumption:
                Lit p = assumptions[decisionLevel()];
                if (value(p) == l_True){
                    // Dummy decision level:
                    newDecisionLevel();
                } else if (value(p) == l_False){
                    analyzeFinal(~p, conflict);
                    return l_False;
                } else {
                    next = p;
                    break;
                }
            }

            #ifdef CGLUCOSE_EXP
            // pick from JustQueue

            if (0 < justUsage())
            if ( next == lit_Undef ){
                int index = -1;
                decisions++;
                next = pickJustLit( index );
                if(next == lit_Undef)
                    return l_True;
                //addJwatch(var(next), j_reason);
                jnext[index] = jlevel[decisionLevel()+1];
                jlevel[decisionLevel()+1] = index;
            }
            #endif

            if (next == lit_Undef){
                // New variable decision:
                decisions++;
                next = pickBranchLit();

                if (next == lit_Undef){
                  // Model found:
                  return l_True;
                }
            }

            // Increase decision level and enqueue 'next'
            newDecisionLevel();
            uncheckedEnqueue(next);
        }
    }
}



double Solver::progressEstimate() const
{
    double  progress = 0;
    double  F = 1.0 / nVars();

    for (int i = 0; i <= decisionLevel(); i++){
        int beg = i == 0 ? 0 : trail_lim[i - 1];
        int end = i == decisionLevel() ? trail.size() : trail_lim[i];
        progress += pow(F, i) * (end - beg);
    }

    return progress / nVars();
}

void Solver::printIncrementalStats() {

  printf("c---------- Glucose Stats -------------------------\n");
  printf("c restarts              : %ld\n", starts);
  printf("c nb ReduceDB           : %ld\n", nbReduceDB);
  printf("c nb removed Clauses    : %ld\n", nbRemovedClauses);
  printf("c nb learnts DL2        : %ld\n", nbDL2);
  printf("c nb learnts size 2     : %ld\n", nbBin);
  printf("c nb learnts size 1     : %ld\n", nbUn);

  printf("c conflicts             : %ld\n", conflicts);
  printf("c decisions             : %ld\n", decisions);
  printf("c propagations          : %ld\n", propagations);

  printf("c SAT Calls             : %d in %g seconds\n", nbSatCalls,   totalTime4Sat);
  printf("c UNSAT Calls           : %d in %g seconds\n", nbUnsatCalls, totalTime4Unsat);
  printf("c--------------------------------------------------\n");


}


// NOTE: assumptions passed in member-variable 'assumptions'.
lbool Solver::solve_()
{

    #ifdef CGLUCOSE_EXP
    ResetJustData(false);
    #endif

    if(incremental && certifiedUNSAT) {
        printf("Can not use incremental and certified unsat in the same time\n");
        exit(-1);
    }

    conflict.shrink_(conflict.size());
    if (!ok){
      travId_prev = travId;
      return l_False;
    }
    double curTime = cpuTime();
    
    solves++;
    
    lbool   status        = l_Undef;
    if(!incremental && verbosity>=1) {
      printf("c ========================================[ MAGIC CONSTANTS ]==============================================\n");
      printf("c | Constants are supposed to work well together :-)                                                      |\n");
      printf("c | however, if you find better choices, please let us known...                                           |\n");
      printf("c |-------------------------------------------------------------------------------------------------------|\n");
    printf("c |                                |                                |                                     |\n"); 
    printf("c | - Restarts:                    | - Reduce Clause DB:            | - Minimize Asserting:               |\n");
    printf("c |   * LBD Queue    : %6d      |   * First     : %6d         |    * size < %3d                     |\n",lbdQueue.maxSize(),nbclausesbeforereduce,lbSizeMinimizingClause);
    printf("c |   * Trail  Queue : %6d      |   * Inc       : %6d         |    * lbd  < %3d                     |\n",trailQueue.maxSize(),incReduceDB,lbLBDMinimizingClause);
    printf("c |   * K            : %6.2f      |   * Special   : %6d         |                                     |\n",K,specialIncReduceDB);
    printf("c |   * R            : %6.2f      |   * Protected :  (lbd)< %2d     |                                     |\n",R,lbLBDFrozenClause);
    printf("c |                                |                                |                                     |\n"); 
printf("c ==================================[ Search Statistics (every %6d conflicts) ]=========================\n",verbEveryConflicts);
      printf("c |                                                                                                       |\n"); 

      printf("c |          RESTARTS           |          ORIGINAL         |              LEARNT              | Progress |\n");
      printf("c |       NB   Blocked  Avg Cfc |    Vars  Clauses Literals |   Red   Learnts    LBD2  Removed |          | pol-inconsist\n");
      printf("c =========================================================================================================\n");
    }

    // Search:
    int curr_restarts = 0;
    while (status == l_Undef){
      status = search(0); // the parameter is useless in glucose, kept to allow modifications
        if (!withinBudget() || terminate_search_early || (pstop && *pstop)) break;
        if (nRuntimeLimit && Abc_Clock() > nRuntimeLimit)                   break;
        curr_restarts++;
    }

    if (!incremental && verbosity >= 1)
      printf("c =========================================================================================================\n");


    if (certifiedUNSAT){ // Want certified output
      if (status == l_False)
        fprintf(certifiedOutput, "0\n");
      fclose(certifiedOutput);
    }


    if (status == l_True){

        if( justUsage() ){
            if( nSkipMark ){
                loadJust();
            } else {
                JustModel.shrink_(JustModel.size());
                assert(jheap.empty());
                //JustModel.growTo(nVars());
                int i = 0, j = 0;
                JustModel.push(toLit(0));
                for (; i < trail.size(); i++) 
                    if( isRoundWatch(var(trail[i])) && !isTwoFanin(var(trail[i])) )
                        JustModel.push(trail[i]), j++;
                JustModel[0] = toLit(j);
            }
            
        } else {
            // Extend & copy model:
            model.shrink_(model.size());
            model.growTo(nVars());
            for (int i = 0; i < trail.size(); i++) model[ var(trail[i]) ] = value(var(trail[i]));
        }
    }else if (status == l_False && conflict.size() == 0)
        ok = false;

    //#ifdef CGLUCOSE_EXP
    //if(status == l_True && 0 < justUsage())
    //  justCheck();
    //#endif

    cancelUntil(0);

    double finalTime = cpuTime();
    if(status==l_True) {
      nbSatCalls++; 
      totalTime4Sat +=(finalTime-curTime);
    }
    if(status==l_False) {
      nbUnsatCalls++; 
      totalTime4Unsat +=(finalTime-curTime);
    }

    // ABC callback
    if (pCnfFunc && !terminate_search_early) {// hack to avoid calling callback twise if the solver was terminated early
        int * pCex = NULL;
        int message = (status == l_True ? 1 : status == l_False ? 0 : -1);
        if (status == l_True) {
            pCex = new int[nVars()];
            for (int i = 0; i < nVars(); i++)
                pCex[i] = (model[i] == l_True);
        }
        
        int callback_result = pCnfFunc(pCnfMan, message, pCex);
        assert(callback_result == 0);
    }
    else if (pCnfFunc)
        terminate_search_early = false; // for next run

    travId_prev = travId;
    return status;
}

//=================================================================================================
// Writing CNF to DIMACS:
// 
// FIXME: this needs to be rewritten completely.

static Var mapVar(Var x, vec<Var>& map, Var& max)
{
    if (map.size() <= x || map[x] == -1){
        map.growTo(x+1, -1);
        map[x] = max++;
    }
    return map[x];
}


void Solver::toDimacs(FILE* f, Clause& c, vec<Var>& map, Var& max)
{
    if (satisfied(c)) return;

    for (int i = 0; i < c.size(); i++)
        if (value(c[i]) != l_False)
            fprintf(f, "%s%d ", sign(c[i]) ? "-" : "", mapVar(var(c[i]), map, max)+1);
    fprintf(f, "0\n");
}


void Solver::toDimacs(const char *file, const vec<Lit>& assumps)
{
    FILE* f = fopen(file, "wb");
    if (f == NULL)
        fprintf(stderr, "could not open file %s\n", file), exit(1);
    toDimacs(f, assumps);
    fclose(f);
}


void Solver::toDimacs(FILE* f, const vec<Lit>& assumps)
{
    // Handle case when solver is in contradictory state:
    if (!ok){
        fprintf(f, "p cnf 1 2\n1 0\n-1 0\n");
        return; }

    vec<Var> map; Var max = 0;

    // Cannot use removeClauses here because it is not safe
    // to deallocate them at this point. Could be improved.
    int i, cnt = 0;
    for (i = 0; i < clauses.size(); i++)
        if (!satisfied(ca[clauses[i]]))
            cnt++;
        
    for (i = 0; i < clauses.size(); i++)
        if (!satisfied(ca[clauses[i]])){
            Clause& c = ca[clauses[i]];
            for (int j = 0; j < c.size(); j++)
                if (value(c[j]) != l_False)
                    mapVar(var(c[j]), map, max);
        }

    // Assumptions are added as unit clauses:
    cnt += assumptions.size();

    fprintf(f, "p cnf %d %d\n", max, cnt);

    for (i = 0; i < assumptions.size(); i++){
        assert(value(assumptions[i]) != l_False);
        fprintf(f, "%s%d 0\n", sign(assumptions[i]) ? "-" : "", mapVar(var(assumptions[i]), map, max)+1);
    }

    for (i = 0; i < clauses.size(); i++)
        toDimacs(f, ca[clauses[i]], map, max);

    if (verbosity > 0)
        printf("Wrote %d clauses with %d variables.\n", cnt, max);
}


//=================================================================================================
// Garbage Collection methods:

void Solver::relocAll(ClauseAllocator& to)
{
    #ifdef CGLUCOSE_EXP
    if( CRef_Undef != itpc ){
      setItpcSize(3);
      ca.reloc(itpc, to);
    }
    #endif
    int v, s, i, j;
    // All watchers:
    //
    // for (int i = 0; i < watches.size(); i++)
    watches.cleanAll();
    watchesBin.cleanAll();
    for (v = 0; v < nVars(); v++)
        for (s = 0; s < 2; s++){
            Lit p = mkLit(v, s != 0);
            // printf(" >>> RELOCING: %s%d\n", sign(p)?"-":"", var(p)+1);
            vec<Watcher>& ws = watches[p];
            for (j = 0; j < ws.size(); j++)
                ca.reloc(ws[j].cref, to);
            vec<Watcher>& ws2 = watchesBin[p];
            for (j = 0; j < ws2.size(); j++)
                ca.reloc(ws2[j].cref, to);
        }

    // All reasons:
    //
    for (i = 0; i < trail.size(); i++){
        Var v = var(trail[i]);

        #ifdef CGLUCOSE_EXP
        if( isGateCRef(reason(v)) )
          continue;
        #endif
        if (reason(v) != CRef_Undef && (ca[reason(v)].reloced() || locked(ca[reason(v)])))
            ca.reloc(vardata[v].reason, to);
    }

    // All learnt:
    //
    for (i = 0; i < learnts.size(); i++)
        ca.reloc(learnts[i], to);

    // All original:
    //
    for (i = 0; i < clauses.size(); i++)
        ca.reloc(clauses[i], to);
}


void Solver::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()); 

    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);
}

void Solver::reset() 
{
    // Reset everything
    ok = true;
    K = (double)opt_K;
    R = (double)opt_R;
    firstReduceDB = opt_first_reduce_db;
    var_decay = (double)opt_var_decay;
    //max_var_decay = opt_max_var_decay;
    solves = starts = decisions = propagations = conflicts = conflictsRestarts = 0;
    curRestart = 1;
    cla_inc = var_inc = 1;
    watches.clear(false); // We don't free the memory, new calls should be of the same size order.
    watchesBin.clear(false); 
    //unaryWatches.clear(false);
    qhead = 0;
    simpDB_assigns = -1;
    simpDB_props = 0;
    order_heap.clear(false);
    progress_estimate = 0;
    //lastLearntClause = CRef_Undef;
    conflict_budget = -1;
    propagation_budget = -1;
    nbVarsInitialFormula = INT32_MAX;
    totalTime4Sat = 0.;
    totalTime4Unsat = 0.;
    nbSatCalls = nbUnsatCalls = 0;
    MYFLAG = 0;
    lbdQueue.clear(false);
    lbdQueue.initSize(sizeLBDQueue);
    trailQueue.clear(false);
    trailQueue.initSize(sizeTrailQueue);
    sumLBD = 0;
    nbclausesbeforereduce = firstReduceDB;
    //stats.clear();
    //stats.growTo(coreStatsSize, 0);
    clauses.clear(false);
    learnts.clear(false);
    //permanentLearnts.clear(false);
    //unaryWatchedClauses.clear(false);
    model   .shrink_(model   .size());
    conflict.shrink_(conflict.size());
    activity.shrink_(activity.size());
    assigns .shrink_(assigns .size());
    polarity.shrink_(polarity.size());
    //forceUNSAT.clear(false);
    decision   .shrink_(decision   .size());
    trail      .shrink_(trail      .size());
    trail_lim  .shrink_(trail_lim  .size());
    vardata    .shrink_(vardata    .size());
    assumptions.shrink_(assumptions.size());
    nbpos      .shrink_(nbpos      .size());
    permDiff   .shrink_(permDiff   .size());
    #ifdef UPDATEVARACTIVITY
    lastDecisionLevel.shrink_(lastDecisionLevel.size());
    #endif
    ca.clear();
    seen           .shrink_(seen.size());
    analyze_stack  .shrink_(analyze_stack  .size());
    analyze_toclear.shrink_(analyze_toclear.size());
    add_tmp.clear(false);
    assumptionPositions.clear(false);
    initialPositions.clear(false);

    #ifdef CGLUCOSE_EXP

    ResetJustData(false);

    //jwatch.shrink_(jwatch.size());
    //jdata .shrink_(jdata .size());

    jhead  = 0;
    travId = 0;
    travId_prev = 0;
    var2TravId   .shrink_(var2TravId.size());
    JustModel    .shrink_(JustModel .size());
    jlevel       .shrink_(jlevel.size());
    jnext        .shrink_(jnext.size());

    //var2FaninLits.shrink_(var2FaninLits.size());
    var2NodeData .shrink_(var2NodeData .size());
    var2Fanout0  .shrink_(var2Fanout0  .size());
    var2FanoutN  .shrink_(var2FanoutN  .size());
    //var2FanoutP.clear(false);
    if( CRef_Undef != itpc ){
        itpc = CRef_Undef;       // clause allocator has been cleared, do not worry 
        // allocate space for clause interpretation 
        vec<Lit> tmp; tmp.growTo(3); 
        itpc = ca.alloc(tmp);
        ca[itpc].shrink( ca[itpc].size() );
    }

    vMarked.shrink_( vMarked.size() );
    nSkipMark = 0;
    #endif
}

ABC_NAMESPACE_IMPL_END
