#include <stdio.h>
#define satbox_backtrack(lit,output) satbox_assert_aux(lit,output,0)

/* 

  Literal: 
     A literal is a variable with a sign. A variable is represented
     by a positive integer.
     One bit is used to denote the sign of a literal: 
              1 == positive, 0 == negative.

  Clause:
     Unit clauses are stored in V5[x]->value.
     Binary clauses are stored in Bcs[].
     Other clauses are stored on tapes:
       The clause head has three fields: head lit, tail lit, and -third (if 3-SAT) or
           a pointer to the clause body.
       The clause body is a list of literals+positions preceeded by its size (negated), 
       and tail index.
       Each literal is stored in 31-PBITS bits (with one bit representing its sign)
       and each position is stored in PBITS bits.

  Tape: 
     All non-unit, non-binary clauses (both head and body) are saved in an integer 
        array called Tape.
     An element in a tape can be 
          (i) a literal+position, 
         (ii) size of a clause (negated),
        (iii) head/tail indices, 
         (iv) zero, i.e., deleted clause, 
          (v) values of TL-clause.
 */

/***************************************************
 *
 *  TYPE Declaration
 *
 ***************************************************/

#define PBITS           10
#define TAPE            int*
#define lit0()          4
#define clause_offset() 2

/***************************************************
 *
 *  MACRO Declaration
 *
 ***************************************************/

/* Macros for the clause head */
#ifdef AGE
#define set_age_of_cl(cl,v) cl[3]=v
#define age_of_cl(cl) cl[3]
#define clause_head_size() 4
#else
#define clause_head_size() 3
#endif

#define ptr_for_binary(ks) (int*) (((ks)<<1)+1)
#define is_from_binary(p) ((unsigned int) p)&1
#define key_from_binary(p) (((int) p)>>1)
#define mark_deleted_clause(cl) *cl = 0;
#define undeleted_clause(cl) *cl 
#define set_body(cl,p) cl[2] = (int) p
#define get_body(cl) (int *) cl[2]
#define is_2cnf(cl) !cl[2]
#define is_3cnf(cl) (((unsigned int) cl[2])&1)
#define is_long_cl(cl) (cl[2]&&!(((unsigned int) cl[2])&1))
#define clean_third_lit(cl) cl[2]=0
#define set_third_lit(cl,v) cl[2]=((v)<<1)+1
#define third_lit(cl) (cl[2]>>1)

/* Macros for the special head/tail literals */
#define is_head(cl,lit) (*(cl) == lit)
#define get_head(cl) *cl
#define get_tail(cl) cl[1]
#define switch_head_3cnf(cl,head,thirdlit) set_third_lit(cl,cl[head]); cl[head]=thirdlit
#define switch_head_body(cl,head,p,otherpos,otherlit,lastpos) \
  p[otherpos]=(cl[head]<<PBITS)+lastpos; \
  cl[head]=otherlit

/* Macros for the clause body */
#define set_lit0(p,ks) *(p) = ks
#define get_lit0(p,i) p[i]
#define lp_set_lp(x,ks,pos) x = ((ks)<<PBITS)+pos
#define lp_set_lit(x,ks) x = (ks)<<PBITS
#define lp_get_lit(lp) (lp>>PBITS)
#define lp_get_var(lp) (lp>>(PBITS+1))
#define lp_get_position(lp) (lp & 1023)
#define is_literal(p) (*(p) > 0)
#define not_literal(p) (*(p) <= 0)
#define set_clause_size(p,size) *p = -(size+clause_offset())
#define size_of_clause(p) (-*p)  
#define negsize_clause(p) (*p)  
#define set_head_address(p,n) p[1]= (int) n
#define get_head_address(p) (int *) p[1]
#define set_head_pos(p,n) p[2]=n
#define set_head_pos_tim(p,n) p[2]=n; p[3]=Timer
#define get_head_pos(p) p[2]
#define set_body_stamp(p,n) p[3]=n
#define get_body_stamp(p) p[3]
#define mark_deleted_body(p) p[lit0()]=0
#define undeleted_body(p) p[lit0()]

/* Macros for nclauses */
#define is_normal(cl) (*cl > 0) 
#define set_tl_value(cl,v) get_head(cl) = -v; get_tail(cl) = v
#define is_tl_cl(cl) (get_head(cl) < 0) 
#define value_of(cl) -(*cl) 
#define cvalue(cl) get_tail(cl)
#define dec_cvalue(cl) --get_tail(cl)
#define set_ncl_val(cl,tt) get_tail(cl)=tt

/***************************************************
 *
 *  VARIABLE Declaration
 *
 ***************************************************/

int MAX_TAPE;
int TAPE_BLOCK;
TAPE *Tape_space;            /* a large storage space */
TAPE Tape_limit;             /* limit of each tape */
int Input_tape;
int Head_tape;
int Body_tape;
int last_Delete_num=0;
int *Deleted_heads=NULL;
int new_branches=400;
int cleaned_tape;

/* Local variables for handling non-horn clauses */
int **Nonhorns;
int Num_nonhorns;
#define Max_nonhorns 100

/* Local variables for handling user lemmas */
int **Lemmas;
int Num_lemmas;
#define Max_lemmas 2000

unsigned long Deleted_cells=0;

/* Total memory for variables: 8x4 bytes */

#ifdef AGE

/* age-clauses */

/* Ages is a collection of clauses parititioned by ages.
   Each partition is a list of pointers to clause tapes.
*/

int ***Ages;

/*
#define age_count_inc(ptrs) ((int) ptrs[0])++
#define age_count_dec(ptrs) --((int) ptrs[0])
#define age_count(ptrs) (int) *ptrs
#define age_max(ptrs) (int) ptrs[1]
#define age_set_count(ptrs,c) ptrs[0]=(int*)c
#define age_set_max(ptrs,c) (int) ptrs[1]=(int*)c
#define age_begin() 2
#define age_push_clause(ptrs,ptr) ptrs[age_count_inc(ptrs)] = ptr
*/


/***************************************************
 *
 *  FUN Declaration
 *
 ***************************************************/

ages_init() 
{
  int i;
  Ages = (int ***) malloc((SX.Max_atom) * (sizeof(int **)));
  for (i = 0; i < SX.Max_atom; i++) Ages[i] = NULL;
}

ages_insert_clause (a, cl)
     int a, *cl;
{
  int **ptrs = Ages[a];
  if (ptrs == NULL) {
    array_init(ptrs,int*);
    array_push(ptrs,int*,cl);
  } else {
    array_insert(ptrs,int*,cl);
  }
  Ages[a] = ptrs;
}

ages_delete_clauses (a)
     int a;
{
  int **ptrs = Ages[a];
  if (ptrs) {
    for (a = array_begin(); a < array_count(ptrs); a++) {
      ptrs[a][1] = ptrs[a][2] = 0; /* mark as deleted */
      Deleted_cells -= ptrs[a][0];
      SX.Delete_num++;
    }
    array_set_count(ptrs,array_begin());
  }
}
#endif

void tape_init ()
{
  int i;

  if (SX.Max_atom <= 100) MAX_TAPE = 32;
  else if (SX.Max_atom <= 1000) MAX_TAPE = 64;
  else if (SX.Max_atom <= 10000) MAX_TAPE = 128;
  else if (SX.Max_atom <= 100000) MAX_TAPE = 256;
  else MAX_TAPE = 512;
  TAPE_BLOCK = (MAX_TAPE*3) << (Flags[GROW]+1);

  Tape_space = (TAPE *) malloc((MAX_TAPE) * (sizeof(TAPE)));
  memory_count((sizeof(TAPE *)*MAX_TAPE));
  Tape_limit = (TAPE) malloc((MAX_TAPE) * (sizeof(int)));
  memory_count((sizeof(TAPE)*MAX_TAPE));

  for (i = 0; i < MAX_TAPE; i++) {
    Tape_space[i] = NULL;
    Tape_limit[i] = 0; 
  }
  Tape_space[0] = (TAPE) malloc((TAPE_BLOCK) * (sizeof(int)));
  if (!Tape_space[0]) { fprintf(stderr, "out of memory\n"); exit(0); }
  memory_count((sizeof(TAPE) * TAPE_BLOCK));
  Head_tape = 0;
  Body_tape = MAX_TAPE-1;

  /* Remember the first 100 Nonhorn input clauses */
  Nonhorns = (TAPE*) malloc((Max_nonhorns) * (sizeof(TAPE)));
  memory_count((sizeof(TAPE) * Max_nonhorns));
  Num_nonhorns = 0;

  /* Remember at most Max_lemmas */
  Lemmas = (TAPE*) malloc((Max_lemmas) * (sizeof(TAPE)));
  memory_count((sizeof(TAPE) * Max_lemmas));
  Num_lemmas = 0;
}

void decrease_dlength (much)
     int much;
{ 
  Flags[DLENGTH] -= much;
  cleaned_tape = MAX_TAPE-1;
  delete_clauses_on_tape(); 
  if (SX.Delete_num > last_Delete_num) {
    clean_body_tapes();
  }
}

int expanded_num=0;
void expand_tapes ()
{
  int i, k, j;
  TAPE *arr1;
  TAPE arr2;
  
  if (++expanded_num>3) return;
  j = MAX_TAPE;
  MAX_TAPE = MAX_TAPE*1.5;
  arr1 = (TAPE *) malloc(sizeof(TAPE *)*MAX_TAPE);
  if (!arr1) { 
    decrease_dlength(2);
    return;
  }
  arr2 = (TAPE) malloc(sizeof(TAPE)*MAX_TAPE);
  if (!arr2) { 
    decrease_dlength(2);
    free(arr1); 
    return; 
  }
  memory_count(sizeof(int)*MAX_TAPE);

  for (i=0; i <= Head_tape; i++) {
    arr1[i] = Tape_space[i];
    arr2[i] = Tape_limit[i];
  }
  i = MAX_TAPE-1;
  k = j-1;
  while (k>=Body_tape) {
    arr1[i] = Tape_space[k];
    arr2[i--] = Tape_limit[k--];
  }

  free(Tape_space);
  free(Tape_limit);
  Tape_space = arr1;
  Tape_limit = arr2;
  Body_tape = i+1;
  cleaned_tape += MAX_TAPE-j;

  for (i=Head_tape+1; i<Body_tape; i++) {
    arr1[i] = NULL;
    arr2[i] = 0;
  }

  trace(1, printf("c MAX_TAPE (%d) is expanded to %d\n", j, MAX_TAPE));
}

void adjust_tapes ()
{
  int i = ((Head_tape+1)*(Flags[GROW]+1)) << 2; 
  
  Input_tape = Head_tape;
  cleaned_tape = MAX_TAPE-1;
  trace(2, printf("c MAX_TAPE (%d) is expected to be %d\n", MAX_TAPE, i));
}

int *get_tape (s, i)
     int s, i;
{
  if (Tape_space[i] == NULL) {
    if ((Tape_space[i] = (TAPE) malloc((TAPE_BLOCK) * (sizeof(int)))) == NULL) {
      fprintf(stderr, "ABEND, malloc returns NULL (out of memory).\n");
      return NULL;
    }
    memory_count((sizeof(TAPE) * TAPE_BLOCK));
    /* printf("tape[%d] is ready (%d)\n", i, Input_tape);*/
  }
  Tape_limit[i] = s;
  return Tape_space[i];
}

int *get_body_tape (s)
     int s;
{
  int *p;

  if (!Tape_space[Body_tape]) return get_tape(s, Body_tape);
  if (Tape_limit[Body_tape]+s < TAPE_BLOCK) {
    p = Tape_space[Body_tape]+Tape_limit[Body_tape];
    Tape_limit[Body_tape] += s;
    return p;
  }
  if (Body_tape <= Head_tape+1) return NULL;
  --Body_tape;
  return get_tape(s, Body_tape);
}

int *get_head_tape (t)
     int t;
{
  int *p;

  if ((p=Deleted_heads)) {
    Deleted_heads = get_body(Deleted_heads);
    return p;
  }
  if (!Tape_space[t]) return get_tape(clause_head_size(), t);
  if (Tape_limit[t] < TAPE_BLOCK) {
    p = Tape_space[t]+Tape_limit[t];
    Tape_limit[t] += clause_head_size();
    return p;
  }
  if (t == 0) { 
    t = Head_tape;
    if (Tape_limit[t] < TAPE_BLOCK) {
      p = Tape_space[t]+Tape_limit[t];
      Tape_limit[t] += clause_head_size();
      return p;
    }
  }
  if (Body_tape <= Head_tape+1) return NULL;

  return get_tape(clause_head_size(), ++Head_tape);
}

int *clause_space ( s, t)
     int s, t;
{
  static int last_Branch_fail = 0;
  int *p, *cl;

  if (Body_tape <= Head_tape+1) {
    if (Num_lemmas) {
      clean_body_tapes();
    } else if (last_Branch_fail < SX.Branch_fail) {
      last_Branch_fail = SX.Branch_fail+new_branches;
      new_branches += 400;
      delete_clauses_on_tape(); 
      if (SX.Delete_num > last_Delete_num) {
	clean_body_tapes();
      }
    } else {
      expand_tapes();
    }
  }


  cl = get_head_tape(t);
  if (!cl) {
    if (Flags[DLENGTH] > 10) {
      decrease_dlength(2);
      return clause_space(s, t);
    }
    return NULL;
  }
  if (s == 3) return cl;
  p = get_body_tape(s+clause_offset());
  if (!p && Flags[DLENGTH] > 10) {
    decrease_dlength(2);  
    p = get_body_tape(s+clause_offset());
  }
  if (!p) { return NULL; }
  set_head_address(p, cl); 
  set_body(cl, p);
  return cl;
}

/* return the tape number where cl is residing */
int tape_number ( cl )
     int *cl;
{
  int i; 

  for (i=Input_tape; i <= Head_tape; i++) {
    if ((cl >= Tape_space[i]) && (cl < Tape_space[i]+Tape_limit[i])) 
      return i;
  }
  return -1;
}

void delete_clauses_on_tape ()
{
  int i, j, k, *cl, *cl2;

  trace(3, printf("Begin deleting clauses ...\n"));

  for (i = Input_tape+1; i <= Head_tape; i++) {
    cl = Tape_space[i];
    cl2 = cl+Tape_limit[i];
    while (cl < cl2) {
      if (undeleted_clause(cl) && is_long_cl(cl) && 
	  lit_value(get_head(cl)) && lit_value(get_tail(cl))) {
	int *p = get_body(cl);
	if (size_of_clause(p) > Flags[DLENGTH]) {
	  SX.Delete_num++;
	  set_lit_clauses_deleted(get_head(cl));
	  set_lit_clauses_deleted(get_tail(cl));
	  mark_deleted_body(p);
	  mark_deleted_clause(cl); 
	  set_body(cl,Deleted_heads);
	  Deleted_heads = cl;
	}
      }
      cl += clause_head_size();
    }
  }

  /* we need to remove the hts of deleted clauses */
  /* If this operation can be done lazily, then Deleted_heads cannot
   be used. */
  for (k = make_lit(SX.Max_atom,1); k >= 2; k--) 
    if (lit_clauses_deleted(k)) {
      int **pts = L5[k]->hts;
      reset_lit_clauses_deleted(k);
      j = array_count(pts);
      i = array_begin(); 
      while (i < j) {
	if (undeleted_clause(pts[i])) i++;
	else pts[i] = pts[--j];
      }
      array_set_count(pts,int*,i);
    }
}

void clean_body_tapes ()
{
  int limit, i, j, j2, k, t2, *bp, *bp2, *c3=NULL, *tape, *tape2;

  i = cleaned_tape;
  t2 = i;
  j2 = 0;
  tape2 = Tape_space[t2];

  while (i >= Body_tape) {
    limit = Tape_limit[i];
    tape = Tape_space[i--];
    for (j=0; j < limit; ++j){ 
      if ((k=tape[j]) < 0) {
	/* beginning of clause body */
	if (!tape[j+lit0()]) {
	  j = j-k-1;  /* ++j later by the for loop */
	} else {
	  if (j2-k >= TAPE_BLOCK) {
	    Tape_limit[t2] = j2;
	    tape2 = Tape_space[--t2];
	    bp2 = tape2;
	    j2 = 1;
	    tape2[0] = k;
	  } else {
	    bp2 = &tape2[j2];
	    tape2[j2++] = k;
	  }
	  bp = &tape[j];
	  // get_head_address(bp) == bp[1]
	  // if (c3) { printf("new"); print_clause(c3); }
	  c3 = get_head_address(bp); 
	  // { printf("old"); print_clause(c3); }
	  set_body(c3,bp2);
	  tape2[j2++] = tape[++j]; // head_address; may be negative
	  tape2[j2++] = tape[++j]; // head_pos; 
	  tape2[j2++] = tape[++j]; // body_stamp;
	}
      } else {
	tape2[j2++] = k;
      }
    }
  }

  Tape_limit[t2] = j2;
  for (j = Body_tape; j < t2; j++) Tape_limit[j] = 0;
  trace(1, printf("c %d clauses deleted (total=%d), %d tapes released\n",
		  SX.Delete_num-last_Delete_num, SX.Delete_num,
		  t2-Head_tape));
  Body_tape = cleaned_tape = t2;
  last_Delete_num = SX.Delete_num;
  if (t2-Head_tape < (MAX_TAPE>>2)) {
    expand_tapes();
  }
}

void print_clause (cl)
    int *cl;
{
  int i, j, *p;

  if (is_from_binary(cl)) {
    i = key_from_binary(cl);
    printf("from binary %s%d\n", (var_value(i))? "-" : "", i);
    return;
  }

  if (is_normal(cl)) {
    if (is_2cnf(cl)) {
      printf("size=2 ( ");
      printf("^"); print_lit(get_head(cl)); 
      printf("^"); print_lit(get_tail(cl));
      printf(")\n");
    } else if (is_3cnf(cl)) {
      printf("size=3 ( ");
      printf("^"); print_lit(get_head(cl)); 
      printf("^"); print_lit(get_tail(cl));
      print_lit(third_lit(cl));
      printf(")\n");
    } else {
      p = get_body(cl);
      j = size_of_clause(p);
      printf("size=%d ( ", j-clause_offset());
      printf("^"); print_lit(get_head(cl));
      printf("^"); print_lit(get_tail(cl)); 
      for (i = lit0(); i < j; i++) {
	printf("[%d,%d]", lit_timer(lp_get_lit(p[i])), lp_get_position(p[i]));
	print_lit(lp_get_lit(p[i]));
      }
      printf(") H%d, S%d, N%d \n", get_head_pos(p)-(lit0()-2), 
	     get_body_stamp(p), ((cl-Tape_space[0])));
    }
  } else {
    p = get_body(cl);
    j = size_of_clause(p);
    printf("size=%d cvalue=%d ( ", j, cvalue(cl));
    for (i = clause_offset(); i < j; i++) {
      print_lit(get_lit0(p,i));
    }
    printf(")\n");
  }
}

void print_clause2 (cl)
    int *cl;
{
  int i, j, *p;

  if (is_from_binary(cl)) {
    i = key_from_binary(cl);
    printf("from binary %s%d (%d)\n", 
	   (var_value(i))? "-" : "", i, var_level(i));
    return;
  }

  if (is_normal(cl)) {
    if (is_2cnf(cl)) {
      printf("size=2 ( ");
      printf("^"); print_lit(get_head(cl)); 
      printf("(%d) ", var_level(lit_var(get_head(cl))));
      printf("^"); print_lit(get_tail(cl));
      printf("(%d) ", var_level(lit_var(get_tail(cl))));
      printf(")\n");
    } else if (is_3cnf(cl)) {
      printf("size=3 ( ");
      printf("^"); print_lit(get_head(cl)); 
      printf("(%d) ", var_level(lit_var(get_head(cl))));
      printf("^"); print_lit(get_tail(cl));
      printf("(%d) ", var_level(lit_var(get_tail(cl))));
      print_lit(third_lit(cl));
      printf("(%d) ", var_level(lit_var(third_lit(cl))));
      printf(")\n");
    } else {
      p = get_body(cl);
      j = size_of_clause(p);
      printf("size=%d ( ", j-clause_offset());
      printf("^"); print_lit(get_head(cl));
      printf("(%d) ", var_level(lit_var(get_head(cl))));
      printf("^"); print_lit(get_tail(cl)); 
      printf("(%d) ", var_level(lit_var(get_tail(cl))));
      for (i = lit0(); i < j; i++) {
	// printf("[%d,%d]", lit_timer(lp_get_lit(p[i])), lp_get_position(p[i]));
	print_lit(lp_get_lit(p[i]));
	printf("(%d) ", var_level(lp_get_lit(p[i])));
      }
      printf(") H%d, S%d, N%d \n", get_head_pos(p)-(lit0()-2), 
	     get_body_stamp(p), ((cl-Tape_space[0])));
    }
  } else {
    p = get_body(cl);
    j = size_of_clause(p);
    printf("size=%d cvalue=%d ( ", j, cvalue(cl));
    for (i = clause_offset(); i < j; i++) {
      print_lit(get_lit0(p,i));
    }
    printf(")\n");
  }
}

void print_lit (lit)
     int lit;
{
  int k = lit_var(lit);

#ifdef FLEXIBLE
  if (var_value_flexible(k)) { printf("?"); } 
#endif

  if (!lit_sign(lit)) printf("-");
  printf("%d%s ", k, (var_value(k) == TT)? "+" : ((var_value(k) == FF)? "-" : "")); 
}

void print_clauses_on_tape (tape1, tape2)
     int tape1, tape2;
{
  int i;

  printf("all clauses on tapes %d-%d\n", tape1, tape2);
  for (i = tape1; i <= tape2; i++) {
    int *cl = Tape_space[i];
    int *cl2 = cl+Tape_limit[i];
    while (cl < cl2) {
      print_clause(cl);
      cl += clause_head_size();
    }
  }
}

void reset_all_clauses_stamps ()
{
  int i;

  for (i = Body_tape; i < MAX_TAPE; i++) {
    int *cl = Tape_space[i];
    int *cl2 = cl+Tape_limit[i];
    while (cl < cl2) {
      set_head_pos_tim(cl, 0);
      cl -= negsize_clause(cl);
    }
  }
}

int check_clause (cl)
     TAPE cl;
{
  if (lit_value(get_head(cl))) return 0;
  if (lit_value(get_tail(cl))) return 0;
  if (is_3cnf(cl)) {
    if (lit_value(third_lit(cl))) return 0;
  } else {
    int j;
    int *p = get_body(cl);
    for (j = 1; j < size_of_clause(cl); j++) if (lit_value(lp_get_lit(p[j]))) return 0;
  }
  trace(2, { printf("False cl: "); print_clause(cl);});
  trace(8, { print_var5_clause(lit_var(get_head(cl)), 3);
  print_var5_clause(lit_var(get_tail(cl)), 3);
  exit(0); });

  return 1;
}

#ifdef TLCLAUSE
check_nclause (cl)
     TAPE cl;
{
  int j, s=0;
  int *p = get_body(cl);

  for (j = clause_offset(); j < size_of_clause(p); j++) if (lit_value(p[j])) s++;
  s -= value_of(cl);
  if (s > 0) { 
    trace(2, { printf("False cl: "); print_clause(cl); }); return 1;
  }
  return 0;
}
#endif

int satbox_check_model ()
{
  int i;

  trace(2, printf("c Checking model ...\n"));

  for (i = 1; i <= SX.Max_atom; i++) {
    int *p, j;
    if (var_value(i)) {
      p = L5[make_lit(i,0)]->bicls;
      Empty_binary[0] = make_lit(i,0);
    } else {
      p = L5[make_lit(i,1)]->bicls;
      Empty_binary[0] = make_lit(i,1);
    }
    for (j = array_count(p)-1; j >= array_begin(); j--) if (!lit_value(p[j])) {
      Empty_binary[1] = p[j];
      trace(2, { printf("False cl: "); print_clause(Empty_binary);});
      return 1;
    }
  }

  for (i = 0; i <= Input_tape; i++) {
    TAPE cl = Tape_space[i];
    TAPE limit = Tape_space[i]+Tape_limit[i];

    while (cl < limit) {
       if (is_normal(cl)) {
	if (check_clause(cl)) return 1;
#ifdef TLCLAUSE
      } else if (check_nclause(cl)) { return 1; 
#endif
      }
      cl += clause_head_size();
    }
  }
  return 0;
}

/* Inserting a user lemma; see satbox.h for document */
int satbox_insert_lemma ( int *cl_arr, int size, int *output )
{
  int *gcl=NULL;
  int unit=-1;
  int i, j, l, maxlevel=0;

  trace(2, { printf("Lemma [%d]: (", Level); 
             for (i = 0; i < size; i++) {
	       j = cl_arr[i];
	       printf(" %s%d (%d,%d)", 
		      (lit_sign(j))? "" : "-", lit_var(j), 
		      lit_value(j),
		      var_level(lit_var(j)));
	     }
	     printf(" )\n");
  });

  for (i = 0; i < size; i++) {
    j = cl_arr[i];
    if (lit_value(j) == TT) {
      unit = -10;
      break;
    } else if (lit_value(j) == FF) {
      l = var_level(lit_var(j));
      if (l == 0) {
	cl_arr[i] = cl_arr[--size];
	i--;
      } else if (l > maxlevel) 
	maxlevel = l;
    } else if (unit == -1) {
      unit = j;
    } else unit = 0;
  }

  if (unit != -10 && size > 1) {
    gcl = insert_lemma_to_tape(cl_arr, size);
  }

  if (Num_lemmas < Max_lemmas) {
    Lemmas[Num_lemmas++] = gcl;
  } else {
    printf("Number of lemmas, %d, exceeds the limit\n", Max_lemmas);
    exit(1);
  }

  /* the lemma is a conflict */
  if (unit == -1) {
    i = satbox_backtrack(-maxlevel, output);
  } else if (unit && (unit != -10)) {
    New_unit = unit;
    New_unit_clause = gcl;
    i = satbox_assert_aux(0, output, -1);
  } else { 
    i = SAT;
    output[0] = Level;
    output[1] = 0;
  }
  Default_level = Level;
  return i;
}

/* Remove the last n lemmas inserted by calling satbox_insert_lemma 
   Remove also all the lemmas generated by satbox since the last deleted lemma. */
int satbox_remove_last_lemmas (int n)
{
  int *cl, *last_cl=NULL, x;

  trace(6, printf("Removing the last %d inserted lemmas\n", n));

  while (n--) {
    if ((cl = Lemmas[--Num_lemmas])) { last_cl = cl; }
  }

  /* try to remove all the lemmas generated by satbox since inserting last_cl */
  if (last_cl) {
    /* Obtain the tape containing last_cl */
    int i = tape_number(last_cl);
    int old_head_tape = Head_tape;

    if (i == -1) return 0;
    Head_tape = i;
    cl = last_cl;
    last_cl = Tape_space[i]+Tape_limit[i];
    Tape_limit[i] = (int) (cl-Tape_space[i]);

    while (1) {
      while (cl < last_cl) {
	if ((lit_value(get_head(cl)) == FF) || (lit_value(get_tail(cl)) == FF)) {
	  printf("Lemma in use: "); 
	  print_clause2(cl);
	  if (lit_value(get_head(cl)) == FF)
	    x = get_head(cl);
	  else
	    x = get_tail(cl);
	  x = var_level(lit_var(x));
	  printf("  forced backtrack to %d\n", x);
	  vstack_backup(x);
	}

	if (is_long_cl(cl)) {
	  int *body = get_body(cl);
	  mark_deleted_body(body);
	}
	/*
	mark_deleted_clause(cl);
	set_body(cl,Deleted_heads);
	Deleted_heads = cl;
	*/
	cl += clause_head_size();
      }

      if (i < old_head_tape) {
	i++;
	cl = Tape_space[i];
	last_cl = cl+Tape_limit[i];
      } else return 1;
    }
  }

  return 1;
}

void satbox_insert_clause( int *cl_arr, int total, int type )
{
  int i, value=0, *cl, *p;

  if (type == NORM) { 
    if (total == 1) { 
      satbox_insert_unit_clause(cl_arr[0]);
      return; 
    }
    if (total == 2) { 
      insert_binary_clause(cl_arr[0], cl_arr[1]); 
      return; 
    }
  } else {
    value=cl_arr[total];
    if (type == GTEQ || type == GRTR) { 
      if (type == GRTR) value++;
      if (value == 0) return; 
      if (value == 1) type = NORM; 
      else {
	/* changing GTEQ to LSEQ */
	for (i=0; i < total; i++) cl_arr[i] = NEG(cl_arr[i]);
	value = total-value;
	type = LSEQ;
      }
    } else if (type == LESS) { 
      type = LSEQ; value--; 
    } 
  }

  cl = clause_space(total, Head_tape);

  if (cl == NULL) {
    fprintf(stderr, "No space for input clauses (-g%d, -d%d)\n", 
	    Flags[GROW], Flags[DLENGTH]);
    exit(1);
  } 

  if (type == NORM) {
    value=1;
    for (i=0; i < total; i++) if (lit_sign(cl_arr[i]) == 0) { value=0; break; }
  }
  if (value) { // either type != NORM or positive clause 
    if (Num_nonhorns < Max_nonhorns) {
      Nonhorns[Num_nonhorns++] = cl;
    }
  }

  set_clause_size(cl, total);

#ifdef TLCLAUSE
  if (type) { 
    set_tl_value(cl,value);
    p = get_body(cl);
    set_clause_size(p,total);
    p += clause_offset();
    for (i = 0; i < total; i++) {
      int j;
      struct nlink *nl = get_nlink();
      set_lit0(p, cl_arr[i]);
      j = NEG(cl_arr[i]);
      nl->cl = cl;
      nl->next = L5[j]->ncls;
      L5[j]->ncls = nl;
      weight_add(*p,value); 
      weight_add(j,value); 
      p++;
    }
  } else 
#endif
  { 
#ifdef AGE
    set_age_of_cl(cl, age);
#endif

    /* set the head */
    get_head(cl) = cl_arr[0];
    insert_head_tail(cl,cl_arr[0]);
    // sblit_add_watched_satbox(cl_arr[0]);
    // weight_add1_satbox(cl_arr[0]); 

    /* set the tail */
    get_tail(cl) = cl_arr[1];
    insert_head_tail(cl, cl_arr[1]); 
    // weight_add1_satbox(cl_arr[1]); 
    // sblit_add_watched_satbox(cl_arr[1]);

    if (total == 3) {
      set_third_lit(cl,cl_arr[2]);
      // weight_add1_satbox(cl_arr[2]); 
    } else {
      p = get_body(cl);
      set_clause_size(p,total);
      set_head_pos_tim(p,0);
      p += lit0();

      for (i=2; i < total; i++) {
	lp_set_lit(*p, cl_arr[i]);
	// weight_add1_satbox(cl_arr[i]); 
	p++;
      }
    }
  }
  trace(9, { printf("IN(%d): ", type); print_clause(cl);});
}

int *insert_lemma_to_tape (cl_arr, total)
     int cl_arr[], total;
{
  int i, *cl, *p;

  cl = clause_space(total, (total<10)? Input_tape : Head_tape);
  if (cl == NULL) {
    printf("c no space for new clauses (-g%d, -d%d)\n", 
	    Flags[GROW], Flags[DLENGTH]);
    Flags[GROW] = 0;
    return NULL;
  }

  /* Assume the clause is sorted by level: First literal is at maximal level */
  /* set the head - maximal level */
  get_head(cl) = cl_arr[0];
  insert_head_tail(cl,cl_arr[0]);
  weight_add1_satbox(cl_arr[0]); 
  // sblit_add_watched_satbox(cl_arr[0]);

  /* set the tail - second maximal level */
  get_tail(cl) = cl_arr[1];
  insert_head_tail(cl, cl_arr[1]); 
  weight_add1_satbox(cl_arr[1]); 
  // sblit_add_watched_satbox(cl_arr[1]);

  if (total == 3) {
    set_third_lit(cl,cl_arr[2]);
    weight_add1_satbox(cl_arr[2]); 
  } else if (total > 3) {
    int last_p, last_l;

    p = get_body(cl);
    set_head_pos_tim(p, lit0());
    set_clause_size(p,total);
    p += total+lit0()-3;
    last_p = total-2+lit0();
    last_l = var_level(lit_var(cl_arr[total-1]));

    for (i=total-1; i > 1; i--) {
      weight_add1_satbox(cl_arr[i]); 
      if (var_level(lit_var(cl_arr[i])) > last_l) {
	last_l = var_level(lit_var(cl_arr[i]));
	last_p = i+lit0()-1;
      }
      lp_set_lp(*p, cl_arr[i], last_p);
      p--;
    }
  } else { /* total == 2 */ 
    clean_third_lit(cl);
  }

  return cl;
}

