/****************************************************************************************[Solver.C]
MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/

#include "Solver.h"
#include "Sort.h"
#include <cmath>
#include <iostream>


// #define _MINISAT_DEFAULT_VSS

// #define __PRINT
//=================================================================================================
// Constructor/Destructor:


Solver::Solver() :

    // Parameters: (formerly in 'SearchParams')
    var_decay(1 / 0.95), clause_decay(1 / 0.999), random_var_freq(0.02)
  , restart_first(100), restart_inc(1.5), learntsize_factor((double)1/(double)3), learntsize_inc(1.1)

    // More parameters:
    //
  , expensive_ccmin  (true)
  , polarity_mode    (polarity_false)
  , verbosity        (0)

    // Statistics: (formerly in 'SolverStats')
    //
  , starts(0), decisions(0), rnd_decisions(0), propagations(0), conflicts(0)
  , clauses_literals(0), learnts_literals(0), max_literals(0), tot_literals(0)

  , ok               (true)
  , cla_inc          (1)
  , var_inc          (1)
  , qhead            (0)
  , simpDB_assigns   (-1)
  , simpDB_props     (0)
  , order_heap       (VarOrderLt(activity))
  , random_seed      (91648253)
  , progress_estimate(0)
  , remove_satisfied (true)
  , minDecisionLevel ((unsigned)(-1))
{}


Solver::~Solver()
{
    for (int i = 0; i < learnts.size(); i++) free(learnts[i]);
    for (int i = 0; i < clauses.size(); i++) free(clauses[i]);
}


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


// Creates a new SAT variable in the solver. If 'decision_var' 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, double act, bool dvar)
{
    int v = nVars();
    watches   .push();          // (list for positive literal)
    watches   .push();          // (list for negative literal)
    reason    .push(NULL);
    assigns   .push(toInt(l_Undef));
    level     .push(-1);
    activity  .push(act);
    original_activity  .push(act);
    seen      .push(0);

    polarity    .push((char)sign);
    decision_var.push((char)dvar);

    insertVarOrder(v);
    return v;
}


bool Solver::addClause(vec<Lit>& ps)
{
#ifdef __PRINT
  for (int i = 0; i < ps.size(); i++) {
    if (_literal_count.find(ps[i]) == _literal_count.end())
      _literal_count[ps[i]] = 1;
    else
      _literal_count[ps[i]]++;
  }
#endif

  if (!ok)
    return false;

  // Check if clause is satisfied and remove false/duplicate literals:
  // Special attention is put on single and double literal clauses
  if (ps.size() == 1 || 
      (ps.size() == 2 && ps[0] == ps[1])) {
    // Unary or Binary with a duplicate literal
    if (value(ps[0]) == l_True) {
#ifdef __PRINT
      printf("---satisfied---\n");
#endif
      return true;
    } else if (value(ps[0]) == l_False) {
#ifdef __PRINT
      printf("Clause empty after simplification\n");
#endif
      return ok = false;
    } else {
      uncheckedEnqueue(ps[0]);
      return ok = (propagate() == NULL);
    }
  } else if (ps.size() == 2) {
    // Real Binary clauses
    if (value(ps[0]) == l_True ||
	value(ps[1]) == l_True ||
	ps[0] == ~ps[1]) {
#ifdef __PRINT
      printf("---satisfied---\n");
#endif
      return true;
    } else if (value(ps[0]) == l_False) {
      if (value(ps[1]) == l_False) {
#ifdef __PRINT
	printf("Clause empty after simplification\n");
#endif
	return ok = false;
      } else {
	uncheckedEnqueue(ps[1]);
	return ok = (propagate() == NULL);
      }
    } else {
      if (value(ps[1]) == l_False) {
	uncheckedEnqueue(ps[0]);
	return ok = (propagate() == NULL);
      } else {
	Clause* c = Clause_new(ps, false);
	clauses.push(c);
	attachClause(*c);
      }
    }
  } else {
    sort(ps);
    Lit p; int i, j;
    for (i = j = 0, p = lit_Undef; i < ps.size(); i++)
      if (value(ps[i]) == l_True || ps[i] == ~p) {
#ifdef __PRINT
	printf("---satisfied---\n");
#endif
	return true;
      }
      else if (value(ps[i]) != l_False && ps[i] != p)
	ps[j++] = p = ps[i];
    ps.shrink(i - j);

    if (ps.size() == 0) {
#ifdef __PRINT
      printf("Clause empty after simplification\n");
#endif
      return ok = false;
    }
    else if (ps.size() == 1){
      uncheckedEnqueue(ps[0]);
      return ok = (propagate() == NULL);
    }else{
      Clause* c = Clause_new(ps, false);

      clauses.push(c);
      attachClause(*c);

#ifdef __PRINT
      //      printf("Simplified: ");
      //      printClause(*c);
      //      printf("\n");
#endif      
    }
  }
  return true;
}

void Solver::addConflictingClause(vec<Lit>& lits) {
  if (lits.size() == 1) {
    if (value(lits[0]) == l_True)
      return;
    
    if (value(lits[0]) == l_False) {
      if (level[var(lits[0])] == 0) {
	ok = false;
	return;
      }
      cancelUntil(level[var(lits[0])] - 1);
    }
    uncheckedEnqueue(~lits[0]);
  } else {
    vec<Lit>    learnt_clause;
    int backtrack_level;

    for (int i = 1; i < lits.size(); i++) {
      if (value(lits[0]) == l_False) {
	if (value(lits[i]) != l_False){
	  Lit tmp = lits[0];
	  lits[0] = lits[i];
	  lits[i] = tmp;
	}
      } else if (value(lits[1]) == l_False) {
	if (value(lits[i]) != l_False){
	  Lit tmp = lits[1];
	  lits[1] = lits[i];
	  lits[i] = tmp;
	  break;
	}
      }
    }

    if (value(lits[0]) == l_False) {
      for (int i = 1; i < lits.size(); i++) {
	if (level[var(lits[i])] > level[var(lits[0])]) {
	  Lit tmp = lits[0];
	  lits[0] = lits[i];
	  lits[i] = tmp;
	}
      }
    }

    if (value(lits[1]) == l_False) {
      for (int i = 2; i < lits.size(); i++) {
	if (level[var(lits[i])] > level[var(lits[1])]) {
	  Lit tmp = lits[1];
	  lits[1] = lits[i];
	  lits[i] = tmp;
	}
      }
    }

    Clause* confl = Clause_new(lits, true);
    clauses.push(confl);
    attachClause(*confl);


    
    if (value(lits[0]) != l_False) {
      if (value(lits[1]) == l_False) {
	uncheckedEnqueue(lits[0], confl);
      }
      return;
    }

    int maxLevel = level[var(lits[0])];
    cancelUntil(maxLevel);
    if (maxLevel == 0) {
      ok = false;
      return;
    }

    learnt_clause.clear();
    analyze(confl, learnt_clause, backtrack_level);
    cancelUntil(backtrack_level);
    
    if (learnt_clause.size() == 1){
      uncheckedEnqueue(learnt_clause[0]);
    }else{
      Clause* c = Clause_new(learnt_clause, true);
      learnts.push(c);
      attachClause(*c);
      claBumpActivity(*c);
      uncheckedEnqueue(learnt_clause[0], c);
    }

#ifdef _MINISAT_DEFAULT_VSS
    varDecayActivity();
#endif
    claDecayActivity();
  }
}


void Solver::attachClause(Clause& c) {
  watches[toInt(~c[0])].push(&c);
  watches[toInt(~c[1])].push(&c);
  if (c.learnt()) learnts_literals += c.size();
  else            clauses_literals += c.size(); }


void Solver::detachClause(Clause& c) {
    remove(watches[toInt(~c[0])], &c);
    remove(watches[toInt(~c[1])], &c);
    if (c.learnt()) learnts_literals -= c.size();
    else            clauses_literals -= c.size(); }


void Solver::removeClause(Clause& c) {
    detachClause(c);
    free(&c); }


bool Solver::satisfied(const Clause& c) const {
    for (int i = 0; i < c.size(); i++)
        if (value(c[i]) == l_True)
            return true;
    return false; }


// Revert to the state at given level (keeping all assignment at 'level' but not beyond).
//
void Solver::cancelUntil(int level) {
    if (decisionLevel() > level){
        for (int c = trail.size()-1; c >= trail_lim[level]; c--){
            Var     x  = var(trail[c]);
            assigns[x] = toInt(l_Undef);
            insertVarOrder(x); }
        qhead = trail_lim[level];
        trail.shrink(trail.size() - trail_lim[level]);
        trail_lim.shrink(trail_lim.size() - level);
    } }


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


Lit Solver::pickBranchLit(int polarity_mode, double random_var_freq)
{
  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 (toLbool(assigns[next]) == l_Undef && decision_var[next])
      rnd_decisions++; }
  */

  // Activity based decision:
  while (next == var_Undef || toLbool(assigns[next]) != l_Undef || !decision_var[next]) {
    if (order_heap.empty()){
      next = var_Undef;
      break;
    }else
      next = order_heap.removeMin();
  }

  if (next == var_Undef) return lit_Undef;

  bool sign = false;

  
  switch (polarity_mode){
  case polarity_true:  sign = false; break;
  case polarity_false: sign = true;  break;
  case polarity_user:  sign = polarity[next]; break;
  case polarity_rnd:   sign = irand(random_seed, 2); break;
  }

  sign = !polarity[next];

  //  do {
  //    int var;
  //    std::cin >> var;
  //    sign = !(var > 0);
  //    next = Var(abs(var) - 1);
  //  } while(toLbool(assigns[next]) != l_Undef);

  //  std::cout << "var: " << var << " sign: " << sign << std::endl;

  return next == var_Undef ? lit_Undef : Lit(next, sign);
}


/*_________________________________________________________________________________________________
|
|  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'.
|  
|  Effect:
|    Will undo part of the trail, upto but not beyond the assumption of the current decision level.
|________________________________________________________________________________________________@*/
void Solver::analyze(Clause* confl, vec<Lit>& out_learnt, int& out_btlevel)
{
  int pathC = 0;
  Lit p     = lit_Undef;

  // Generate conflict clause:
  //
  out_learnt.push();      // (leave room for the asserting literal)
  int index   = trail.size() - 1;
  out_btlevel = 0;

  do{
    Clause& c = *confl;

    #ifdef __PRINT
    printf("Explain: ");
    printClause(c);
    printf("\n");
    #endif

      if (c.learnt())
	claBumpActivity(c);

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

	if (!seen[var(q)] && level[var(q)] > 0){
	  #ifdef _MINISAT_DEFAULT_VSS
	  varBumpActivity(var(q));
	  #endif
	  seen[var(q)] = 1;
	  if (level[var(q)] >= decisionLevel()) {
	    pathC++;
	  }else{
	    out_learnt.push(q);
	    if (level[var(q)] > out_btlevel)
	      out_btlevel = level[var(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;
  if (expensive_ccmin){
    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)

    out_learnt.copyTo(analyze_toclear);
    for (i = j = 1; i < out_learnt.size(); i++)
      if (reason[var(out_learnt[i])] == NULL || !litRedundant(out_learnt[i], abstract_level))
	out_learnt[j++] = out_learnt[i];
  }else{
    out_learnt.copyTo(analyze_toclear);
    for (i = j = 1; i < out_learnt.size(); i++){
      Clause& c = *reason[var(out_learnt[i])];
      for (int k = 1; k < c.size(); k++)
	if (!seen[var(c[k])] && level[var(c[k])] > 0){
	  out_learnt[j++] = out_learnt[i];
	  break; }
    }
  }
  max_literals += out_learnt.size();
  out_learnt.shrink(i - j);
  tot_literals += out_learnt.size();

  // Find correct backtrack level:
  //
  if (out_learnt.size() == 1)
    out_btlevel = 0;
  else{
    int max_i = 1;
    for (int i = 2; i < out_learnt.size(); i++)
      if (level[var(out_learnt[i])] > level[var(out_learnt[max_i])])
	max_i = i;
    Lit p             = out_learnt[max_i];
    out_learnt[max_i] = out_learnt[1];
    out_learnt[1]     = p;
    out_btlevel       = level[var(p)];
  }

#ifdef __PRINT
  printf("Learnt: ");
  for (int i = 0; i < out_learnt.size(); i++) {
    printf("%s%d ", sign(out_learnt[i]) ? "-" : "", var(out_learnt[i]));
    if (value(out_learnt[i]) != l_False)
      exit(1);
  }
  printf("\n");
#endif

  for (int j = 0; j < analyze_toclear.size(); j++) seen[var(analyze_toclear[j])] = 0;    // ('seen[]' is now cleared)

  
}


// 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.clear(); analyze_stack.push(p);
    int top = analyze_toclear.size();
    while (analyze_stack.size() > 0){
        Clause& c = *reason[var(analyze_stack.last())]; analyze_stack.pop();

        for (int i = 1; i < c.size(); i++){
            Lit p  = c[i];
            if (!seen[var(p)] && level[var(p)] > 0){
                if (reason[var(p)] != NULL && (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.clear();
    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] == NULL){
                out_conflict.push(~trail[i]);
            }else{
                Clause& c = *reason[x];
                for (int j = 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, Clause* from)
{
#ifdef __PRINT  
  if (from) {
    printClause(*from);
  }
  
  printf("--> ");
  printLit(p);
  printf("\n");

  if (decisionLevel() == 0) {
    printf("Zl: ");
    printLit(p);
    printf("\n");

  }
#endif
    

  assigns [var(p)] = toInt(lbool(!sign(p)));  // <<== abstract but not uttermost effecient
  level   [var(p)] = decisionLevel();
  reason  [var(p)] = from;
  trail.push(p);
}


/*_________________________________________________________________________________________________
|
|  propagate : [void]  ->  [Clause*]
|  
|  Description:
|    Propagates all enqueued facts. If a conflict arises, the conflicting clause is returned,
|    otherwise NULL.
|  
|    Post-conditions:
|      * the propagation queue is empty, even if there was a conflict.
|________________________________________________________________________________________________@*/
Clause* Solver::propagate()
{
    Clause* confl     = NULL;
    int     num_props = 0;

    while (qhead < trail.size()){
        Lit            p   = trail[qhead++];     // 'p' is enqueued fact to propagate.
        vec<Clause*>&  ws  = watches[toInt(p)];
        Clause         **i, **j, **end;
        num_props++;

        for (i = j = (Clause**)ws, end = i + ws.size();  i != end;){
            Clause& c = **i++;

            // Make sure the false literal is data[1]:
            Lit false_lit = ~p;
            if (c[0] == false_lit)
                c[0] = c[1], c[1] = false_lit;


            // If 0th watch is true, then clause is already satisfied.
            Lit first = c[0];
            if (value(first) == l_True){
                *j++ = &c;
            }else{
                // Look for new watch:
                for (int k = 2; k < c.size(); k++)
                    if (value(c[k]) != l_False){
                        c[1] = c[k]; c[k] = false_lit;
                        watches[toInt(~c[1])].push(&c);
                        goto FoundWatch; }

                // Did not find watch -- clause is unit under assignment:
                *j++ = &c;
                if (value(first) == l_False){
                    confl = &c;

#ifdef __PRINT
		    printf("Conflict: ");
		    printClause(*confl);
		    printf("\n");

		    /*
		    vec<Lit> learnt_clause;
		    int backtrack_level;
		    analyze(confl, learnt_clause, backtrack_level);
		    */

#endif

                    qhead = trail.size();
                    // Copy the remaining watches:
                    while (i < end)
                        *j++ = *i++;
                }else
                    uncheckedEnqueue(first, &c);
            }
        FoundWatch:;
        }
        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 { bool operator () (Clause* x, Clause* y) { return x->size() > 2 && (y->size() == 2 || x->activity() < y->activity()); } };
void Solver::reduceDB()
{
    int     i, j;
    double  extra_lim = cla_inc / learnts.size();    // Remove any clause below this activity

    sort(learnts, reduceDB_lt());
    for (i = j = 0; i < learnts.size() / 2; i++){
        if (learnts[i]->size() > 2 && !locked(*learnts[i]))
            removeClause(*learnts[i]);
        else
            learnts[j++] = learnts[i];
    }
    for (; i < learnts.size(); i++){
        if (learnts[i]->size() > 2 && !locked(*learnts[i]) && learnts[i]->activity() < extra_lim)
            removeClause(*learnts[i]);
        else
            learnts[j++] = learnts[i];
    }
    learnts.shrink(i - j);
}


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


/*_________________________________________________________________________________________________
|
|  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()
{

  if (!ok || propagate() != NULL) {
        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);

    // Remove fixed variables from the variable heap:
    order_heap.filter(VarFilter(*this));

    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) (nof_learnts : int) (params : const SearchParams&)  ->  [lbool]
|  
|  Description:
|    Search for a model the specified number of conflicts, keeping the number of learnt clauses
|    below the provided limit. NOTE! Use negative value for 'nof_conflicts' or 'nof_learnts' to
|    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, int nof_learnts)
{
  int         backtrack_level;
  int         conflictC = 0;
  vec<Lit>    learnt_clause;

  starts++;

  bool first = true;

  for (;;){
    Clause* confl = propagate();


    if (confl != NULL){
      // CONFLICT
      conflicts++; conflictC++;

      if (decisionLevel() == 0) return l_False;
      
      first = false;

      learnt_clause.clear();
      analyze(confl, learnt_clause, backtrack_level);
      cancelUntil(backtrack_level);

#ifdef __PRINT
      char c1 = sign(learnt_clause[0]) ? '-' : '+';
      char c2 = polarity[var(learnt_clause[0])] == 0 ? '-' : '+'; 
      if (decisionLevel() < minDecisionLevel && 
	  original_activity[var(learnt_clause[0])] > 0) {
	printf("Conflict record: ");
	printLit(learnt_clause[0]);
	printf(" .%d.\t.%d. %c .%c .%g\n", decisionLevel(), trail.size(), 
	       c1, c2, original_activity[var(learnt_clause[0])]);
	if (decisionLevel() == 0) {
	  minDecisionLevel = (unsigned)(-1);
	} else {
	  minDecisionLevel = decisionLevel();
	}
      }
#endif

      if (learnt_clause.size() == 1){
	uncheckedEnqueue(learnt_clause[0]);
      }else{
	Clause* c = Clause_new(learnt_clause, true);
	learnts.push(c);
	attachClause(*c);
	claBumpActivity(*c);
	uncheckedEnqueue(learnt_clause[0], c);
      }

      #ifdef _MINISAT_DEFAULT_VSS
      varDecayActivity();
      #endif
      claDecayActivity();

    }else{

      // NO CONFLICT

      if (nof_conflicts >= 0 && conflictC >= nof_conflicts){
	// Reached bound on number of conflicts:
	progress_estimate = progressEstimate();
	// cancelUntil(0);
	return l_Undef; }

      // Simplify the set of problem clauses:
      if (decisionLevel() == 0 && !simplify())
	return l_False;

      if (nof_learnts >= 0 && learnts.size()-nAssigns() >= nof_learnts)
	// Reduce the set of learnt clauses:
	reduceDB();

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




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

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

#ifdef __PRINT
	printf("Decision: ");
	printLit(next);
	printf("\t.%f.\t.%d.\t.%d.", activity[var(next)], decisionLevel(), trail.size());
	printf("\n");
#endif
		

      }

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

    //#ifdef __PRINT
    //    printTrail();
    //#endif
  }
}


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


lbool Solver::solve(const vec<Lit>& assumps)
{
  model.clear();
  conflict.clear();

  if (!ok) {
    return false;
  }

  assumps.copyTo(assumptions);

  double  nof_conflicts = restart_first;
  double  nof_learnts   = nClauses() * learntsize_factor;
  lbool   status        = l_Undef;

  if (verbosity >= 1){
    reportf("============================[ Search Statistics ]==============================\n");
    reportf("| Conflicts |          ORIGINAL         |          LEARNT          | Progress |\n");
    reportf("|           |    Vars  Clauses Literals |    Limit  Clauses Lit/Cl |          |\n");
    reportf("===============================================================================\n");
  }

  // Search:
  while (status == l_Undef){
    if (verbosity >= 1)
      reportf("| .%9d. | .%7d. .%8d. .%8d. | .%8d. .%8d. .%6.0f. | .%6.3f. %% |\n", (int)conflicts, order_heap.size(), nClauses(), (int)clauses_literals, (int)nof_learnts, nLearnts(), (double)learnts_literals/nLearnts(), progress_estimate*100), fflush(stdout);
    status = search((int)nof_conflicts, (int)nof_learnts);
    nof_conflicts *= restart_inc;
    nof_learnts   *= learntsize_inc;
  }

  if (verbosity >= 1)
    reportf("===============================================================================\n");


  if (status == l_True){
    // Extend & copy model:
    model.growTo(nVars());
    for (int i = 0; i < nVars(); i++) 
      model[i] = value(i);
    //    printTrail();
#ifdef _DEBUG
    verifyModel();
#endif
  }else{
    if (conflict.size() == 0) {
      ok = false;
    }
  }

  //  cancelUntil(0);
  return status;
}

//=================================================================================================
// Debug methods:


void Solver::verifyModel()
{
  bool failed = false;
  for (int i = 0; i < clauses.size(); i++){
    Clause& c = *clauses[i];
    for (int j = 0; j < c.size(); j++)
      if (modelValue(c[j]) == l_True)
	goto next;

    reportf("unsatisfied clause: ");
    printClause(*clauses[i]);
    reportf("\n");
    failed = true;
  next:;
  }


  //  reportf("Verified %d original clauses.\n", clauses.size());
}


void Solver::checkLiteralCount()
{
  // Check that sizes are calculated correctly:
  int cnt = 0;
  for (int i = 0; i < clauses.size(); i++)
    if (clauses[i]->mark() == 0)
      cnt += clauses[i]->size();

  if ((int)clauses_literals != cnt){
    fprintf(stderr, "literal count: %d, real value = %d\n", (int)clauses_literals, cnt);
  }
}
