/*********************************************************************
; Copyright 2002-2005, Hantao Zhang (HZ).  All rights reserved. 
; By using this software the USER indicates that he or she has read, 
; understood and will comply with the following:
;
; --- HZ hereby grants USER nonexclusive permission to use, copy and/or
; modify this software for internal, noncommercial, research purposes only.
; Any distribution, including commercial sale or license, of this software,
; copies of the software, its associated documentation and/or modifications
; of either is strictly prohibited without the prior consent of HZ.  Title
; to copyright to this software and its associated documentation shall at
; all times remain with HZ.  Appropriate copyright notice shall be placed
; on all software copies, and a complete copy of this notice shall be
; included in all copies of the associated documentation.  No right is
; granted to use in advertising, publicity or otherwise any trademark,
; service mark, or the name of HZ.  Software and/or its associated
; documentation identified as "confidential," if any, will be protected
; from unauthorized use/disclosure with the same degree of care USER
; regularly employs to safeguard its own such information.
;
; --- This software and any associated documentation is provided "as is," and
; HZ MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
; THOSE OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT
; USE OF THE SOFTWARE, MODIFICATIONS, OR ASSOCIATED DOCUMENTATION WILL
; NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER INTELLECTUAL
; PROPERTY RIGHTS OF A THIRD PARTY.  HZ, the University of Iowa,
; its Regents, officers, and employees shall not be liable under any
; circumstances for any direct, indirect, special, incidental, or
; consequential damages with respect to any claim by USER or any third
; party on account of or arising from the use, or inability to use, this
; software or its associated documentation, even if HZ has been advised
; of the possibility of those damages.
*********************************************************************/
#define IN_MAIN

#include "main.h"
#include "satbox.h"
#include "weight.h"

#ifndef PC
#include "clocks.h" 
extern struct clock Clocks[ MAX_CLOCKS ];
#endif

/* Global variables */
char *fname_out = NULL;

#define CHECKTIME 14400 
// 14400sec = 4 hours
// 21600sec = 6 hours
int Checkpoint;

int Model_read=0;
int *Model=NULL;

FILE *Efile=NULL;
FILE *Xfile=NULL;

/* #define TP_ALLOC_SIZE 32700 */
#define TP_ALLOC_SIZE MAX_SHORT
#define ARG_TYPE unsigned

/* static unsigned long Branch_mark = 1;*/

/*************
 *
 *   main()
 *
 *************/
#ifndef SATBOX_LIBRARY_ONLY
int main (argc, argv)
     int argc;
     char **argv;
{
  FILE *fin;
  int res;

  if ( argc == 1 ) print_menu();

  satbox_init_flags();
  fin = command_line_check( argc, argv );
  clock_init();
  init_database();

#ifndef TEST
  handle_guide_path(1);
#endif
  res = saton(fin); 
  if (res) {
#ifndef TEST
    handle_guide_path(3);
    if (HOURS || MINUTES) append_cmd_line(argc, argv);
#endif
  }

  if (satbox_flag(TRACE) >= 0) print_command(stdout, 1, argc, argv);
  return (Branch_succ > 0)? 1 : 0;
}
#endif

void p_banner (argc, argv)
     int argc;
     char *argv[];
{
  char host[64];

#ifdef PC
  str_copy("pc", host);
#else
  if (gethostname(host, 64) != 0) str_copy("???", host);
#endif

  printf("c ------- SATBOX %s, %s on %s ------\n", 
	 SATBOX_VERSION, VERSION_DATE, host);
  print_command(stdout, 0, argc, argv);
  printf("\n");
}  /* print_banner */

void print_menu()
{
  printf("Usage: sato <Input_file> [<Options>]\n\n");
  printf("Options are:\n");
  printf("   -e fname : give the file name of unfinished jobs (default: unfinish)\n");
  printf("   -g<n>    : set the amount of space for lemmas (default: 5)\n");
  printf("   -h<n>    : set the number of hours to be run (default: 47)\n");
  printf("   -m<n>    : set the number of minutes to be run (default: 0)\n");
  printf("   +m<n>    : set the number of expected models (default: 1)\n");
  printf("   -n       : rename variable names to make name space compact\n");

/*
  printf("   -s<n>    : select an atom in clauses for branching:\n");
  printf("               n = 0: the system will pick a strategy for you;\n"
  printf("               n = 1: the atom with the minimal index;\n");
  printf("               n = 2: a variable in a shortest positive clause;\n");
  printf("               n = 3: a variant of n = 3;\n");
  printf("               n = 4: a variable with most occurrences;\n");
  printf("               n = 5: a variable with most occurrences in binary clauses;\n");
  printf("               n = 6: a variable with most Jeroslow-Wang weight.\n");
*/

#ifdef MORETRACE
  printf("   -t<n>    : set the trace level (1: default; 2-4: search; 5-8: build; 9: all)\n\n");
#else
  printf("   -t       : do not print models\n\n");
#endif

  printf("Input_file is a file name. The input consists of a list of clauses, each of\n");
  printf("    which is a list of nonzero integers separated by 0 (DIMACS Format).\n\n");
  printf("    Example: To input clauses p1|p2, -p1|p3|p4, and p2|-p3|p4 in\n");
  printf("       DIMACS Format\n");
  printf("       1 2 0   \n");
  printf("       -1 3 4 0\n");
  printf("       2 -3 4 0\n\n");
  printf("    Tautologies and duplicated literals are always removed.\n");
  printf("    E.g., (1 1 -2 -4) is the same as (1 -2 -4).\n\n");

  exit ( 0 );
}

FILE *open_fname_out (mode)
     char *mode;
{
  FILE *fout;
  char s[100];

  if (fname_out == NULL) {
    sprintf(s, "unfinish");
    fname_out = (char *) strdup(s);
  } else if (mode[0] == 'w') {
    sprintf(s, "%s.new", fname_out);
  } else sprintf(s, "%s", fname_out);

  fout = fopen(s,"w");
  if (fout == NULL) fout = stdout;
  return (fout);
}

void save_untouched (fout)
     FILE *fout;
{
  int i;

  while ((i = getc ( Efile )) != EOF && i != '(' && i != 'T')
    skip_chars_until( Efile, '\n' ); 
  if (i != EOF) {
    fprintf(fout, "Untouched jobs:\n"); putc( i, fout );
    while ((i = getc( Efile )) != EOF) putc( i, fout );
  }
}

void append_cmd_line(argc, argv)
     int argc;
     char *argv[];
{
  FILE *fout;

  fout = fopen(fname_out, "a");
  print_command(fout, 1, argc, argv);
  fclose(fout);
}

void print_command (fout, flag, argc, argv)
     FILE *fout; int flag, argc; char *argv[];
{
  int i;
  fprintf(fout, "c The job \"%s", argv[0]);
  for (i = 1; i < argc; i++) fprintf(fout, " %s", argv[i]);
#ifdef PC
  fprintf(fout, "\", (pid: %d) %s\n", 
	  getpid(), (flag)? "ended" : "started");
#else
  fprintf(fout, "\", (pid: %d) %s at %s", 
	  getpid(), (flag)? "ended" : "started", get_time());
#endif
}

FILE *command_line_check (argc, argv)
     int argc;
     char **argv;
{
  int i, temp;
  FILE *fin=NULL;

  /* Default */
  Efile = fin = NULL;

  memory_count_set(0);
  random_seed = -(time_in_second);
  Stop = -1;  /* Inputing clauses */

  CHOICE2 = 0;
  HOURS = 47;    /* default: 47 hours */
  LINE = 20;
  MINUTES = 0;
  MODEL = 1;
  RANJUM = 0;
  RENAME = 0;
  RESTRICT = 0;
  TRIE = 1;
  SBX = 0;
  SELECT = 0;
  OLDV = 0;

  i = 0;
  while (++i < argc) {
    if (argv[i][0] == '?') {
	print_menu();
    } else if (argv[i][0] == '+')  {
      temp = str_int(argv[i], 2);
      if (argv[i][1] == 'j') {
	RANJUM = temp+1;
      } else if (argv[i][1] == 'm') {
	MODEL = temp;
      } 
    } else if (argv[i][0] == '-')  {
      temp = str_int(argv[i], 2);

      if (argv[i][1] == 'e') {
	i++;
	fname_out = (char *) strdup(argv[i]);
	if ((Efile = fopen (fname_out, "r")) == NULL) 
	  fprintf(stderr, "c %s ignores invalid parameter : %s\n",
		  argv [0], fname_out );
      } else if (argv[i][1] == 'b') {
	satbox_set_flag(BINARY, temp);
      } else if (argv[i][1] == 'd') {
	if (temp && (temp < 5)) 
	  satbox_set_flag(DLENGTH, 5);
	else
	  satbox_set_flag(DLENGTH, temp);
      } else if (argv[i][1] == 'g') {
	satbox_set_flag(GROW, temp);
      } else if (argv[i][1] == 'h') {
	HOURS = temp;
#ifdef MINONE
      } else if (argv[i][1] == 'I') {
	MINVAR = temp;
#endif
      } else if (argv[i][1] == 'j') {
	satbox_set_flag(JUMP, temp);
      } else if (argv[i][1] == 'l') {
	LINE = temp;
      } else if (argv[i][1] == 'm') {
	HOURS = 0;
	MINUTES = temp;
      } else if (argv[i][1] == 'p') {
	TRIE = temp;  /* using TRIE for pre-processing */
      } else if (argv[i][1] == 'n') {
	RENAME = temp+1;
      } else if (argv[i][1] == 'r') {
	RESTRICT = temp;
      } else if (argv[i][1] == 's') {
	SELECT = temp;
      } else if (argv[i][1] == 't') {
	satbox_set_flag(TRACE, temp);
      } else if (argv[i][1] == 'v') {
	if (temp) CHOICE2 = 1;
	else satbox_set_flag(CHOICE, TT);
      } else if (argv[i][1] == 'x') {
	i++;
	SBX = 1;
	if ((Xfile = fopen (argv[i], "r")) == NULL) {
	  fprintf(stderr, "c %s ignores invalid sbx file: %s\n",
		  argv[0], argv[i] );
	  exit(0);
	}
      } else {
	fprintf(stderr, "c %s ignores invalid parameter : %s\n",
		argv[0], argv[i] );
      }
    } else if (i > 1) {
      fprintf ( stderr, "c %s ignores invalid parameter : %s\n",
	       argv[0], argv[i] );
    }
  }

  if (satbox_flag(TRACE) >= 0) {
    p_banner(argc, argv);
    if (fname_out != NULL) 
      printf( "File \"%s\" is open for the extra clauses.\n", fname_out );
  }

  if (!SBX || (argv[1][0] != '-' && argv[1][0] != '+')) {
    if (SBX) SBX = 3;
    if ((fin = fopen ( Input_file=argv[1], "r" ) ) == NULL) {
      fprintf ( stderr, "c %s can't open file : %s\n",
		argv [0], Input_file );
      exit(1);
    } else {
      int ch;

      if (satbox_flag(TRACE) >= 0) 
	printf( "c Reading clauses in DIMACS format from file \"%s\".\n", argv[1] );

      /* fix Max_atom and Clause_num if possible */
      ch = getc ( fin );  
      while (ch != EOF) {
	while (ch == '\n') ch = getc ( fin ); 
	if (ch != 'p') {
	  skip_chars_until( fin, '\n'); 
	  ch = getc ( fin ); 
	}
	if (ch == EOF) {     
	  if (satbox_flag(TRACE) >= 0) printf("c The input file is empty.\n"); exit(0); 
	}
	if (ch == 'p' &&
	    getc(fin) == ' ' &&
	    getc(fin) == 'c' &&
	    getc(fin) == 'n' &&
	    getc(fin) == 'f' ) {
	  fscanf(fin, "%d", &Max_atom);
	  fscanf(fin, "%d", &Clause_num0);
	  if (satbox_flag(TRACE) >= 0) 
	    printf("c Max_atom = %d, Clause_num = %d\n", Max_atom, Clause_num0);
	  if (Max_atom >= 1000000) 
	    { fprintf(stderr, "c Variable Number (%d) >= %d\n", 
		      Max_atom, 1000000); exit(1); }
	  ch = EOF;
	}
      }
    }
  }

  return fin;
}

/* the main function of sato: return 1 if satisfiable; 0 otherwise.  */
int saton (file)
     FILE *file;
{
  int i = 0, j;

  check_stop(0);
  if (file) {
#ifdef PC
    i = build(file);
#else
    CLOCK_START(BUILD_TIME)
    i = build(file);
    CLOCK_STOP(BUILD_TIME)
#endif

    if (i != 0) {
      Branch_num = 1;
      printf("c An empty clause is found!\n");
      printf("s UNSATISFIABLE\n");
      return 0;
    }
    trace(2, printf("c Starting the search ...\n")); 
  }

#ifdef PC
  i = search();
#else
  CLOCK_START(SEARCH_TIME)
  i = search();
  CLOCK_STOP(SEARCH_TIME)
#endif
 
  j=p_stats(stdout);
  if (satbox_flag(TRACE)>0 && Branch_succ) print_guide_path(stdout);

  if (satbox_flag(TRACE) > -1) print_times(stdout);
  if (satbox_flag(TRACE) == -1) exit(j);
  return i;
}

int build (file)
     FILE *file;
{
  int j;

  j = input_clauses(file);
  if (file && file != stdin) fclose(file);
  if (satbox_flag(TRACE) >= 0) p_input_stats(stdout);
  fflush(stdout);
  record_keeping();
  Stop = 0;
  return j;
}

int search ()
{
  Branch_num = 1;
  Branch_succ = 0;
  Branch_skip = 0;
  Max_cand = (RENAME>1)? RENAME : Max_atom;

  return saton_search();
}

void p_input_stats ()
{
  if (Clause_num == 0) {
    printf("c There are no input clauses (the format may be wrong).\n\n");
    exit(0);
   } else if ((Clause_num - Subsume_num) == 1) {
    printf("c Only one input clause is read.\n\n");
    /* exit(0);*/
  } else if (Subsume_num > 0)
    printf("c There are %d input clauses (%d unit, %d subsumed, %d retained).\n", 
	    Clause_num, Unit_num, Subsume_num, Clause_num+Unit_num-Subsume_num);

  printf("c The mallocated memory is %10.2f Kbytes.\n", memory_count_get());
}

void p_paras ( )
{
  if (MODEL == 0) 
    printf ( "Search for all models.\n" );
  else if (MODEL == 1)    
    printf ( "Search only one model.\n" );
  else
    printf ( "Search for %d models.\n", MODEL );

  if (SELECT == 1) 
    printf ( "Branch on a variable with the minimal indices.\n" );
  else if (SELECT == 2) 
    printf ( "Branch on a variable of the shortest positive clauses.\n" );

  printf ( "Set the trace level to %d.\n", satbox_flag(TRACE) );

  printf("\n");
}

int p_stats ()
{
  if (Branch_succ > 0) {
    printf("c The number of found models is %d.\n", Branch_succ);
    if (satbox_flag(TRACE) == -1) { return 10; }
  } else if (Stop == 0 && Branch_skip == 0) {
    printf("c The clause set is unsatisfiable.\n");
    if (satbox_flag(TRACE) == -1) { printf("s UNSATISFIABLE\n"); return 20; }
  } else {
    printf("c The search is incomplete.\n");
    if (satbox_flag(TRACE) == -1) { printf("s UNKNOWN\n"); return 0; }
  } 

  if (Branch_num == 1) {
    printf("c There is only one branch (%d succeeded, %ld failed).\n", 
	    Branch_succ, satbox_branch_fail());
  } else if (Branch_skip > 0) {
    printf("c There are %ld branches (%d succeeded, %ld failed, %d skipped, %d jumped).\n", 
	    Branch_num, Branch_succ, satbox_branch_fail(), Branch_skip, satbox_branch_jump());
  } else {
    printf("c There are %ld branches (%d succeeded, %ld failed, %d jumped).\n", 
	    Branch_num, Branch_succ, satbox_branch_fail(), satbox_branch_jump());
  }
  return 0;
}

/*
void skip_guide_path (r)
     float r;
{
  int o = satbox_branch_open();

  if (r < 0.95 && r > 0.2) {
    int k = (int) (r*20.0);
    if (o > k) {
      int j = (rand()%(o-k))+k; 
      trace(1, printf("Skip %d levels (%d %d)\n", o-j, o, k));
      Branch_skip++;
      save_skipped_guide_path(j);
    }
  }    
}
*/

int check_stop (flag)
     int flag;
{
#ifndef TEST
  static long initial;
  static long previous;
  static long total_time;
#endif

  if (!flag) {

#ifndef TEST
    total_time = getSATlimit("SATTIMEOUT");
    if (total_time == 0) { 
      total_time = 3600*HOURS+60*MINUTES; 
    }
    printf("c Timeout set after %ld seconds\n", total_time);

    initial = time_in_second;
    previous = 0;
#endif

    Checkpoint = (RANJUM)? (1 << (RANJUM+10)) - 1 : (1 << 12) - 1;
    // checkpoint = (RANJUM)? (1 << RANJUM) - 1 : (1 << 14) - 1;
    // printf("checkpoint = %ld\n", checkpoint); 
    if (SELECT < 4) satbox_set_flag(NONHORN, 1);
    return 0;

  } else if (!HOURS && !MINUTES) {
    handle_guide_path(0, stdin);
    return Stop=STOP_PART; 
  } else if (!(Branch_num & Checkpoint)) {

#ifndef TEST
    long used_time = time_in_second-initial;
#endif

    flag = 0;

    if ((used_time < 0) || (used_time >= total_time)) {
      // printf("total time = %ld, used time = %ld\n", total_time, used_time);
      return Stop=STOP_TIME;
    }

    if (satbox_flag(RESTART) && 
	(satbox_flag(RESTART) < 4) && 
	(used_time > (satbox_flag(RESTART) << 3))) {
      satbox_set_conflict_cl_level(1);
      return Stop=STOP_PART; 
    }

    /* print out the guiding path every CHECKTIME */ 
    if ((used_time - previous) > CHECKTIME) {
      previous = used_time;

      // skip some points in the guiding path 
      if (RANJUM) {
	float r = 1.0-((float) used_time)/total_time;
	if (r > 0.1)
	  flag = handle_guide_path((int)(r*128), stdin);
	else
	  handle_guide_path(2, stdin);
      } else {
	handle_guide_path(2, stdin);
      }

#ifdef PC
      trace(1, {
	printf("c branches = %d\n", Branch_num);
	fflush(stdout);});
#else
      trace(1, {
	printf("c branches = %ld     %s", Branch_num, get_time());
	fflush(stdout);});
#endif
      return flag;
    }
  }
  return 0;
}

void bug (i)
     int i;
{
#ifdef PRIVATE
  printf("<<<<<<<<<<<<< BUG%d >>>>>>>>>>>>>\n", i);
#else
  i = 1;
#endif
}

int handle_guide_path (flag)
     int flag;
{
  // flag = 0: HOURS == 0 && MINUTES == 0
  // flag = 1: initiation
  // flag = 2: middle of search
  // flag = 3: end of search
  // flag > 3: random jump

  static int msgout[MAX_LENGTH];
  int MSIZE, i;
  FILE *fout;

  if (flag >= 4) { // random jumping
    FILE *f;
    char name[100];
    int backup[MAX_STACK];
    int j=0, k=64, x=0, idx;

    idx = satbox_collect_selected(backup);
    if (idx > 8) j = 8; else j = idx;
    for (i = 0; i < j; i++) { 
      if (backup[i]>0) {
	x++; // counting open points
	if (k > flag) { j = 0; break; }
	flag -= k;
      }
      if (flag >= k) { break; }
      k = (k>>1);
    }

    if (j == 0) {
      j = satbox_conflict_cl_level();
      if (x < j) {
	if (!fname_out) 
	  sprintf(name, "skipped.gp");
	else
	  sprintf(name, "%s.gp", fname_out);
	f = fopen(name, "a");
	// fprintf(f, "Skipped job is:\n((");
	fprintf(f, "((");
	MSIZE = msgout[0];
	if (MSIZE > 1) for (i = MSIZE-1; i > 0; i--) 
	  fprintf(f, " %s%d", (lit_sign(msgout[i]))? "" : "-", lit_var(msgout[i]));
	fprintf(f, " 0 )\n");

	// skip some branches 
	x = (rand()%(j-x))+x;
	Branch_skip +=j-x;
	output_skipped_guide_path(f, idx, backup, x);
	fprintf(f, ")\n");
	fclose(f);
	return -x;
      } 
    } 
  }

  else if (flag == 2) { /* middle of search */
    FILE *fout;
    fout = open_fname_out("w");
    fprintf(fout, "Under search:\n((");

    MSIZE = msgout[0];
    if (MSIZE > 1) for (i = MSIZE-1; i > 0; i--)
      fprintf(fout, " %s%d", (lit_sign(msgout[i]))? "" : "-", lit_var(msgout[i]));
    fprintf(fout, " 0 )\n ");
    print_guide_path(fout);
    fprintf(fout, ")\n");
    fclose(fout);

  } else if (flag == 1) { // beginning of search 
    int cl_arr [MAX_LENGTH];
    int total, ch, j;

    j = 0;
    msgout[0] = 1;
    msgout[1] = 0;

    if (Efile == NULL) return 0;

    ch = getc ( Efile );  
    while (ch != EOF && (ch != '(' || (ch = getc ( Efile )) != '(')) {
      skip_chars_until( Efile, '\n' ); 
      ch = getc ( Efile );                /* skip it */
    }

    /* read the extra unit clauses */
    if (ch != EOF) {
      char buffer[MAX_STACK];
      i=0;
      while ((buffer[i++]=getc(Efile)) != ')'); buffer[i]='\n';
      // fgets(buffer, MAX_STACK, Efile); 
      line = buffer;
      total = read_one_clause( buffer, Efile, cl_arr, &j, &ch);
      MSIZE = 1;

      if (total > 0) {
	printf("One set of extra unit clauses is read:\n    ");
	print_input_clause(cl_arr, total, NORM);

	reverse(cl_arr, total);
	for (i = 0; i < total; i++) {
	  msgout[MSIZE++] = ch = cl_arr[i];
	  satbox_insert_unit_clause(ch);
	}
      }
	
      /* read in the old values */
      ch = getc ( Efile );  
      while ( ch != EOF && ch != '(') ch = getc ( Efile );  
      if (ch != EOF) {
	total = read_guide_path(Efile, Old_value);
	if (total > 0) {
	  printf("\nA guiding path is read:\n    ");
	  print_read_guide_path(Old_value, total);
	  reverse(Old_value, total);
	  i = total;
	  while (i-- && !OLDV) {
	    if (Old_value[i]&1) {
	      OLDV = i+1;
	    } else {
	      msgout[MSIZE++] = ch = Old_value[i]>>1;
	      satbox_insert_unit_clause(ch);
	    }
	  }
	}
      }
      msgout[0] = MSIZE;
      printf("\n");
    }
    fclose(Efile);
  } else if (flag == 0) { // HOURS == 0 && MINUTES == 0

    FILE *fout;
    int backup[MAX_STACK], idx=0;
    fout = open_fname_out("w");

    idx = satbox_collect_selected(backup);
    fprintf(fout, "((");
    MSIZE = msgout[0];
    if (MSIZE > 1) for (i = 1; i < MSIZE; i++)
      fprintf(fout, " %s%d", (lit_sign(msgout[i]))? "" : "-", lit_var(msgout[i]));

    fprintf(fout, " 0 ) ");
    output_guide_path(fout, idx, backup);
    fprintf(fout, ")\n");
    fclose(fout); 
  } else if (flag == 3) { // end of search
    fout = open_fname_out("w");
    fprintf(fout, "Unfinished job is:\n((");

    MSIZE = msgout[0];
    if (MSIZE > 1) for (i = MSIZE-1; i > 0; i--) 
      fprintf(fout, " %s%d", (lit_sign(msgout[i]))? "" : "-", lit_var(msgout[i]));
    fprintf(fout, " 0 )\n");
    print_guide_path(fout);
    fprintf(fout, ")\n");
    /* if (Efile != NULL) save_untouched(Efile, fout);*/
    fclose(fout);
  }

  return 0;
}

void sblit_add_watched_satbox (int sblit) {}; /* not used here */

int value_of_var_satbox(i) int i; { return value_of_var(i); }
int insert_unit_cl_satbox (i, sign)  int i, sign; { return insert_cl_1(i, sign); }

void guide_path_add_satbox (flag, lit)
     int flag, lit;
{
  Old_value[OLDV++] = (lit<<1)+flag;
}

void print_guide_path (f)
     FILE *f;
{
  int backup[MAX_STACK], idx;
  
  idx = satbox_collect_selected(backup);
  output_guide_path(f, idx, backup);
  fflush(f);
}

void output_skipped_guide_path (f, idx, backup, s)
     FILE *f;
     int idx, backup[], s;
{
  int i, j=0, k;

  fprintf(f, "( ");
  for (i = 0; i < idx; i++) {
    k = backup[i];
    if (k > 0) {
      if (j >= s) fprintf(f, "f"); 
      else { j++; fprintf(f, "s"); }
    } else { fprintf(f, "s"); k = -k; }

    if (satbox_var_value(k) == FF) 
      fprintf(f, "-%d ", k);
    else
      fprintf(f, "%d ", k);
  }
  fprintf(f, ")");
}

void output_guide_path (f, idx, backup)
     FILE *f;
     int idx, backup[];
{
  int i, k;

  fprintf(f, "( ");

  for (i = 0; i < idx; i++) {
    k = backup[i];
    if (k > 0) { fprintf(f, "f"); }
    else { fprintf(f, "s"); k = -k; }

    if (satbox_var_value(k) == FF) 
      fprintf(f, "-%d ", k);
    else 
      fprintf(f, "%d ", k);
  }
  fprintf(f, ")");
}

int read_guide_path ( FILE *f, int *keys )
{
  int total, key;
  int ch;
  
  total = 0;
  while (1) {
    ch = getc ( f );  

    while (ch != EOF && ch != 'f' && ch != 's' && ch != ')') 
      ch = getc ( f );  
    if (ch == EOF) return 0;
    if (ch == ')') {
      skip_chars_until( f, '\n' ); 
      return total;
    }
    fscanf(f, "%d", &key);
    key = (key>0)? make_lit(key,1) : make_lit(-key, 0);
    keys[total++] = (ch == 'f')? (key << 1)+1 : key<<1;
  }
}

void print_read_guide_path (keys, total)
     int keys[], total;
{
  int i, k;
  printf("( ");
  for (i = 0; i < total; i++) {
    if (keys[i]&1) 
      printf("f"); 
    else
      printf("s");
    k = keys[i]>>1;
    printf("%s%d ", lit_sign(k)? "" : "-", lit_var(k));
  }
  printf(")\n");
}

/* To be used with "SATRAM" or "SATTIMEOUT" */
/* Return the limit or:
   0  if the variable is not set or
      if there was a problem in atoi (variable isn't a number) */
int getSATlimit (char *name) {
  char * value = (char *) getenv(name);
  if (value == NULL) return(0);
  return atoi(value);
}

void adjust_record ()
{
  Stop = 0;

  satbox_set_flag(RESTART, RESTART+1);
  if (satbox_flag(RESTART) == 3) { SELECT = 10; }
  else if (satbox_flag(RESTART) > 3) { 
    SELECT = 6; 
  }
#ifdef MORETRACE
  printf("Restart #%d (-s%d, -g%d)\n", 
	 satbox_flag(RESTART)-1, SELECT, satbox_flag(GROW));
#endif
}

void init_database ()
{
  int i;

  if (Max_atom == 0) { 
    if (SBX==1) return;
    printf("Warning: Max_atom = 0\n"); 
    exit(0); 
  }

  VD5 = (struct vardata5 **) malloc (sizeof(struct vardata5 *)*(MAX_ATOM));
  memory_count(sizeof(struct vardata5)*(MAX_ATOM));

  for (i=1; i < (MAX_ATOM); i++)  {
    struct vardata5 *xl;

    VD5[i] = xl = (struct vardata5 *) malloc(sizeof(struct vardata5));
    xl->weight = 0;
    xl->order = 0;
    xl->vorder = i;
  }

  Old_value = (int *) malloc(sizeof(int)*Max_atom);
  memory_count(sizeof(int) * (Max_atom));
  VarOrder = (int *) malloc(sizeof(int)*Max_atom);
  memory_count(sizeof(int *) * (Max_atom));

  if (LINE == 4000 || LINE == 4001) {
    FILE *f;

    if ((f = fopen("model", "r"))) {
      int i, k;
      Model_read=1;
      Model = (int *) malloc(sizeof(int)*(MAX_ATOM));
      memory_count(sizeof(int) * (MAX_ATOM));
      for (i = 1; i <= Max_atom; i++) {
	fscanf(f, "%d", &k);
	if (i == k || -i == k) 
	  Model[i] = (k > 0)? TT : FF;
	else {
	  printf("warning: %d != |%d|\n", i, k);
	  Model[i] = DC;
	}
      }
      fclose(f);
    }
  }

  LD5 = (struct litdata5 **) malloc (sizeof(struct litdata5 *)*(MAX_ATOM<<1));
  memory_count(sizeof(struct litdata5)*(MAX_ATOM<<1));

  for (i=2; i < (MAX_ATOM<<1); i++)  {
    struct litdata5 *xl;

    LD5[i] = xl = (struct litdata5 *) malloc(sizeof(struct litdata5));
    xl->weight_new = 0;
    xl->weight = 0;
  }

  Subsume_num = Trcl_num = Bicl_num = 0;
  Unit_num = POS_num = NH_num = 0;

  satbox_init_input(Max_atom);
}

int model_read_satbox() { return Model_read; }
int model_value_satbox ( int var ) { return Model[var]; }

void pure_literal_check ()
{ 
  int i;

  for (i = 1; i <= Max_atom; i++) {
    int x0 = make_lit(i,0);
    int x1 = make_lit(i,1);

    if (value_of_var(i) == DC) {
      if (!weight_new_val(x0)) {
	print_x_pure(x1);
	satbox_insert_unit_clause(x1);
	Pure_num++; 
      } else if (!weight_new_val(x1)) { 
	print_x_pure(x0);
	satbox_insert_unit_clause(x0);
	Pure_num++;
      }
    }
  }
}

int saton_satbox_commands()
{
  int i, k, output[MAX_STACK];    
  int ch, ch2, ch3;

  while (1) {
  beginning:
    ch = getc ( Xfile );  
    if (ch == EOF) { fclose(Xfile); return 0; }
    if (ch == '\n') { continue; }
    if (ch == '#') skip_chars_until( Xfile, '\n' ); 
    else {
      ch2 = getc ( Xfile );  
      ch3 = getc ( Xfile );  
      
      if (ch=='i'&&ch2=='n'&& ch3=='i') {
	// ini
	fscanf(Xfile, "%d", &k);
	if (SBX != 1) {
	  printf("ERROR: Not the first command: ini %d\n", k);
	  exit(0);
	}
	Max_atom = k;
	satbox_init(k);
	init_database();
	SBX = 2;
      } else if (ch=='f'&&ch2=='l'&& ch3=='g') {
	// flg
	fscanf(Xfile, "%d", &k);
	fscanf(Xfile, "%d", &i);
	satbox_set_flag(k, i);
	if (SBX < 3) {
	  printf("WARNING: wrong place: flg %d %d\n", k, i);
	} 
	SBX = 3;
      } else if (ch=='w'&&ch2=='a'&& ch3=='t') {
	// wat
	fscanf(Xfile, "%d", &k);
	i = satbox_var_is_watched(k);
	trace(2, printf("wat: watched(x%d) = %d\n", k, i));
      } else if (ch=='c'&&ch2=='l'&& ch3=='a') {
	// cla
	if (SBX > 4) {
	  printf("ERROR: insert_clause after search\n");
	  exit(0);
	}
	SBX = 4;
	fscanf(Xfile, "%d", &k);
	for (i = 0; i < k; i++) { fscanf(Xfile, "%d", &(output[i])); }

	/* check for literals and clauses subsumed by unit clauses */
	{ 
	  int plen=0, total = k;
	  i = 0;
	  while (i < total) {
	    k = output[i]>>1;
	    if (value_of_var(k) == DC) {
	      weight_add1_satbox(output[i]); 
	      if (lit_sign(output[i])) ++plen;
	      i++;
	    } else if (value_of_var(k)==lit_sign(output[i])) {
	      /* the clause is subsumed */
	      Subsume_num++;

	      trace(7, printf("      [C%d] is subsumed by unit clause (%d).\n",
			      Clause_num, (value_of_var(k))? k : -k));

	      goto beginning;

	    } else { /* the literal is subsumed */

	      output[i] = output[--total];
	      trace(7, 
		    printf("    %d in [C%d] is skipped due to a unit clause.\n",
			   k, Clause_num));
	    }
	  }

	  if (plen > 1) {
	    NH_num++;
	    if (plen == total) { POS_num++; }
	  }

	  if (total == 0) {
	    trace(4, printf("    [C%d] becomes empty.\n", Clause_num));
	    Stop = STOP_FAIL;
	    return 1;
	  }
	  k = total;
	}

	satbox_insert_clause(output, k, 0);

      } else if (ch=='u'&&ch2=='n'&& ch3=='i') {
	// uni
	if (SBX > 4) {
	  printf("ERROR: insert_clause after search\n");
	  exit(0);
	}
	SBX = 4;
	fscanf(Xfile, "%d", &k);
	satbox_insert_unit_clause(k);
      } else if (ch=='s'&&ch2=='e'&& ch3=='a') {
	// sea
	if (SBX < 3) {
	  printf("WARNING: no clauses inserted\n");
	}
	SBX = 5;
	satbox_init_search(output);
	print_output_result("init search");
      } else if (ch=='r'&&ch2=='s'&& ch3=='e') {
	// rse
	if (SBX < 5) {
	  printf("WARNING: rse: search hasn't started\n");
	}
	SBX = 6;
	satbox_restart_search();
      } else if (ch=='c'&&ch2=='k'&& ch3=='m') {
	// ckm
	if (SBX < 5) {
	  printf("WARNING: ckm: search hasn't started\n");
	}
	satbox_check_model();
      } else if (ch=='s'&&ch2=='t'&& ch3=='y') {
	// sty
	if (SBX < 5) {
	  printf("WARNING: sty: search hasn't started\n");
	}
	fscanf(Xfile, "%d", &k);
	i = satbox_strategy(k);
      } else if (ch=='b'&&ch2=='a'&& ch3=='k') {
	// bak
	if (SBX < 5) {
	  printf("WARNING: bak: search hasn't started\n");
	}
	fscanf(Xfile, "%d", &k);
	i = satbox_backtrack(k, output);
	print_output_result("backtrack");
      } else if (ch=='a'&&ch2=='s'&& ch3=='t') {
	// ast
	if (SBX < 5) {
	  printf("WARNING: ast: search hasn't started\n");
	}
	fscanf(Xfile, "%d", &k);
	for (i = 0; i < k; i++) { fscanf(Xfile, "%d", &(output[i])); }
	i = satbox_assert_true(k, output);
	print_output_result("assert_true");
      } else if (ch=='d'&&ch2=='e'&& ch3=='c') {
	// dec
	if (SBX < 5) {
	  printf("WARNING: dec: search hasn't started\n");
	}
	fscanf(Xfile, "%d", &k);
	i = satbox_decide_true(k, output);
	print_output_result("decide_true");
      } else if (ch=='l'&&ch2=='e'&& ch3=='m') {
	// lem
	if (SBX < 5) {
	  printf("WARNING: lem: search hasn't started\n");
	}
	fscanf(Xfile, "%d", &k);
	for (i = 0; i < k; i++) { fscanf(Xfile, "%d", &(output[i])); }
	i = satbox_insert_lemma(output, k, output);
	print_output_result("insert_lemma");
      } else if (ch=='r'&&ch2=='e'&& ch3=='m') {
	// rem
	if (SBX < 5) {
	  printf("WARNING: rem: search hasn't started\n");
	}
	fscanf(Xfile, "%d", &k);
	i = satbox_remove_last_lemmas(k);
      } else if (ch=='b'&&ch2=='k'&& ch3=='t') {
	// bkt
	if (SBX < 5) {
	  printf("WARNING: bkt: search hasn't started\n");
	}
	fscanf(Xfile, "%d", &k);
	satbox_back_to(k);
      } else if (ch=='v'&&ch2=='l'&& ch3=='v') {
	// vlv
	if (SBX < 5) {
	  printf("WARNING: vlv: search hasn't started\n");
	}
	fscanf(Xfile, "%d", &k);
	i = satbox_var_level(k);
      } else if (ch=='l'&&ch2=='v'&& ch3=='a') {
	// lva
	fscanf(Xfile, "%d", &k);
	i = satbox_lit_value(k);
	trace(2, printf("lva: %sx%d = %d\n", ((lit_sign(k))? "" : "-"), lit_var(k), i));
      } else if (ch=='v'&&ch2=='v'&& ch3=='a') {
	// vva
	fscanf(Xfile, "%d", &k);
	i = satbox_var_value(k);
	trace(2, printf("vva: x%d = %d\n", k, i));
      } else if (ch=='q'&&ch2=='u'&& ch3=='i') {
	// qui
	fclose(Xfile);
	return 0;
      } else {
	trace(2, printf("c unknown command: %c%c%c\n", ch, ch2, ch3));
	skip_chars_until( Xfile, '\n' ); 
      }
    }
  }
}

int saton_dpll_search()
{
  int i, res, output[MAX_STACK];    

  pure_literal_check();

  if (satbox_init_search(output) == UNSAT) return UNSAT;
  print_output_result("begin with");

  /* Using the guiding path */
  while (OLDV) {
    res = Old_value[--OLDV];
    i = res>>1;

    if (satbox_var_value(lit_var(i)) == DC) {
      if (res&1) 
	res=satbox_decide_true(i, output);
      else {
	output[0] = i;
	res=satbox_assert_true(1, output);
      }
      if (!(res&1)) return Stop = STOP_FAIL;
      print_output_result("at");
    } else if (res) OLDV = 0;
  }
 
  VarOrderFirst = 0;
  VarOrderSize = 0;
  for (i = 1; i <= Max_atom; i++) VarOrder[VarOrderSize++] = i;

 start:
  /* the major loop goes here. */
  while (1) {
    i = select_next_literal();
    if (!i) break;

    if (i < 0) { 
      if ((res=satbox_backtrack(0, output))) {
	print_output_result("back to");
      }
    } else {
      Branch_num++;
      // print_let_x_have(i);
      if ((res=satbox_decide_true(i, output))) { /* consistent assignment */
	print_output_result("down to");
      }
    }
     
    if (!res) {
      if (output[0] == RESTART_NOW) {
	satbox_restart_search();
	goto start;
      } else return Stop = STOP_FAIL;
    }

    if ((res=check_stop(1))) {
      if (res < 0) {
	if ((res=satbox_backtrack(res, output))) {
	  print_output_result("random jump to");
	}
      } else if ((res == STOP_PART) && satbox_flag(RESTART)) {
	if (satbox_flag(TRACE) < 0) { adjust_record(); }
	satbox_restart_search();
	goto start;
      } else if (satbox_flag(TRACE) >= 0) {
	printf("\nc The search is aborted with search tree path:\n");
	print_guide_path(stdout);
	printf("\n");
      }
      break;
    }
  } /* while */

  if (i) return Stop;
  if (satbox_check_model()) { 
    if (satbox_backtrack(0, output) == UNSAT) return Stop;
    print_output_result(" back to");
    goto start;
  }
  Branch_succ++;
  print_model(stdout);
  return Stop = STOP_SUCC;
}

int saton_search ()
{
  if (satbox_flag(TRACE) >= 0) 
    printf("c There are %d clauses on %d variables (%d binary, %d non-Horn).\n", 
	   Clause_num, Max_atom, Bicl_num, NH_num);
  if (SBX) {
    return saton_satbox_commands();
  } else {
    return saton_dpll_search();
  }
}

int select_next_literal ()
{
  int i, s;

  if (satbox_flag(GROW)) {
    if (SELECT < 3 || SELECT > 8) ;
    else if (CHOICE2) { weight_update1(); }
    else { weight_update0(); }
  }
    stop0();

  if (SELECT < 2) s=weight_strategy_satbox(); 
  else if (SELECT >= 8) s=basic_strategy_satbox(); 
  else s=satbox_strategy(SELECT);

  if (s > 0) s = s^satbox_flag(CHOICE);
  return s;
}

#ifndef SATBOX_LIBRARY_ONLY
int dpllt_reason_satbox ( int lit, int *lits )
{ 
  if (SBX) {
    int i, k, ch;
    while (1) {
      ch = getc( Xfile );
      if (ch == EOF) { 	  
	printf("WARNING: lost in dpllt_reason_satbox\n");
	exit(0);
      }
      if (ch == '\n') continue;
      if (ch != 'r') skip_chars_until( Xfile, '\n' ); 
      else if ( getc(Xfile)=='e' && getc(Xfile)=='a' ) {
	fscanf(Xfile, "%d", &k);
	if (k != lit) {
	  printf("Warning: %d is expected in dpllt_reason_satbox: %d\n", lit, k);
	}
	fscanf(Xfile, "%d", &k);
	for (i = 0; i < k; i++) { fscanf(Xfile, "%d", &(lits[i])); }
	return k;
      }
    }
  }
  return 0; 
}
#endif
