/*********************************************************************
; Copyright 2002-2009, 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.
*********************************************************************/
#include "main.h"

#ifdef TRIE
#include "trie.h"
 
struct trie *get_trie ()
{
  struct trie *p = ( struct trie * ) malloc ( sizeof ( struct trie ) );
  if (p == NULL) {
    fprintf ( stderr, "get_trie return NULL.\n");
    exit(1);
  }
  p->pos = p->neg = p->bro = NULL;
  return(p);
} 

struct trie *merge_tries (n1, n2)
     struct trie *n1, *n2;  
     /* do lazy clean and complete merge */
{
    if (n2 == NULL) return n1;  
    if (n2 == CLAUSE_MARK) { free_trie(n1); return n2;}
    if (n1 == NULL) return n2;
    if (n1 == CLAUSE_MARK) { free_trie(n2); return n1;}
    
    if (key_of(n2) < key_of(n1)) {
    n2->bro = merge_tries(n1, n2->bro);
    if (n2->bro == CLAUSE_MARK) { free_trie(n2); return CLAUSE_MARK; }
    return n2;
  }

  if (key_of(n1) < key_of(n2)) {
    n1->bro = merge_tries(n1->bro, n2);
    if (n1->bro == CLAUSE_MARK) { free_trie(n1); return CLAUSE_MARK; }
    return n1;
  }

  /* now, key_of(n1) == key_of(n2) */
  n1->bro = merge_tries(n1->bro, n2->bro);
  n2->bro = NULL;
  if (n1->bro == CLAUSE_MARK) {
    free_trie(n1);
    free_trie(n2);
    return CLAUSE_MARK;
  }

  n1->pos = merge_tries(n1->pos, n2->pos);
  n1->neg = merge_tries(n1->neg, n2->neg);
  free_trie_cell(n2);

  if (n1->pos == CLAUSE_MARK) {
    n1->bro = merge_tries(n1->bro, n1->neg);
    n1->neg = NULL;
  }
  if (n1->neg == CLAUSE_MARK) {
    n1->bro = merge_tries(n1->bro, n1->pos);
    n1->pos = NULL;
  }

  if (n1->bro == CLAUSE_MARK) { free_trie(n1); return CLAUSE_MARK; }
  return n1;
}

struct trie *trie_create_one_path (arr, count)
     int arr[], count;
{
  int sign;
  struct trie *first, *pre, *no;

  first = no = get_trie(); 
  set_key(no, lit_var(arr[count])); 
  sign = lit_sign(arr[count]);
  while (--count >= 0) {
    pre = no;
    no = get_trie();
    if (sign) pre->neg = no;
    else pre->pos = no;
    set_key(no, lit_var(arr[count])); 
    sign = lit_sign(arr[count]);
  }
  if (sign)
    no->neg = CLAUSE_MARK;
  else
    no->pos = CLAUSE_MARK;
  return first;
}

struct trie *trie_insert_clause2 (root, arr, count)
     struct trie *root; /* current root of the tree */
     int arr[]; /* current clause */
     int count; /* the length of the current clause-1 */
{
  int key;
  int sign, dep, signs[10];
  struct trie *no, *bro1, *bro2, *pars[MAX_LENGTH];

  key = lit_var(arr[count]);

  if ((no=roots[key]) == NULL) {
    roots[key] = no = trie_create_one_path (arr, count);
    for (dep = key-1; dep >= 0; dep--) {
      if (roots[dep] != NULL) {
	no->bro = roots[dep]->bro;
	roots[dep]->bro = no;
	return root;
      }
    }
    no->bro = root;
    return no;
  }

  dep = 0;
  bro1 = bro2 = NULL;

  while (no != NULL && count >= 0) {
    key = lit_var(arr[count]);
    sign = lit_sign(arr[count]); 
    
    if (key == key_of(no)) {
      if (sign == 1) {

	if HAS_POS_CL(no) {
	  print_x_subsume(key);
	  Subsume_num++;
	  return root; /* skip this clause */

	} else if (trie_subsume_clause(no->neg, arr, count)) {
	  print_x_skip(key);
	  count--;
	  bro1 = no;
	  no = no->bro; 
	} else {
	  count--;
	  pars[dep++] = no;
	  bro1 = NULL;
	  if (sign) no = no->pos; else no = no->neg;
	}
      } else { /* sign == 0 */

	if HAS_NEG_CL(no) {
	  print_x_subsume(key);
	  Subsume_num++;
	  return root; /* skip this clause */

	} else if (trie_subsume_clause(no->pos, arr, count)) {
	  print_x_skip(key);
	  count--;
	  bro1 = no;
	  no = no->bro; 
	} else {
	  count--;
	  bro1 = NULL;
	  if (sign) no = no->pos; else no = no->neg;
	}
      }
    } else if (key < key_of(no)) {
      bro2 = no;
      no = NULL;
    } else { /* (key > key_of(no)) */
      bro1 = no;
      no = bro1->bro;
      while ((no != NULL) && (key_of(no) < key)) {
	bro1 = no;
	no = bro1->bro;
      }
    }
  }

  if (count >= 0) {

    if (count == 0 && dep == 0) { /* a unit clause is found */ 
      key = lit_var(arr[0]);
      value_of_var(key) = 1-lit_sign(arr[0]);
      Unit_num++;

      trace(5,
	fprintf (stdout, "    x%d is set to %d by unit clause.\n",
		 key, value_of_var(key)));
      return root;
    }

    no = trie_create_one_path (arr, count);
    no->bro = bro2;
    if (bro1 == NULL) {
      if (dep--) {
	if (signs[key_of(pars[dep])])
	  pars[dep]->pos = no;
	else 
	  pars[dep]->neg = no;
	return root;
      } else {
	return no;
      }
    } else {
      bro1->bro = no;
      if (dep == 0) roots[key_of(no)] = no;
      return root;
    }
  }

  /* count < 0 */
  while (dep--) {
    no = pars[dep];
    sign = signs[key_of(no)];

    if (dep == 0) { /* if at depth 0, no is unit clause */
      key = key_of(no);
      /* assign_value(key, sign); */
      Unit_num++;

      trace(6, printf("    %sx%d is found be a unit clause.\n",
		 (sign)? "" : "-", key));
    }

    if (sign) {
      free_trie(no->pos);
      no->pos = CLAUSE_MARK;
    
      if (no->neg != NULL) {
	no->bro = merge_tries(no->bro, no->neg);
	no->neg = NULL;
      }
    } else {
      free_trie(no->neg);
      no->neg = CLAUSE_MARK;    
    
      if (no->pos != NULL) {
	no->bro = merge_tries(no->bro, no->pos);
	no->pos = NULL;
      }
    }
    
    if (no->bro != CLAUSE_MARK) return root;
  }
  return CLAUSE_MARK;
}

int trie_subsume_clause (no, arr, count)
     struct trie *no;
     int arr[]; /* current clause */
     int count; /* the length of the current clause */
{
  int key;
  while (no != NULL) {
    if (no == CLAUSE_MARK) return 1;
    if (count > 0) key = lit_var(arr[--count]); else return 0;
    if (key == key_of(no)) {
      if (lit_sign(arr[count])) no = no->neg;
      else no = no->pos;
    } else if (key > key_of(no)) {
      no = no->bro;
      while ((no != NULL) && (key > key_of(no))) {
	no = no->bro;
      }
    }
  }
  return 0;
} /* trie_subsume_clause */

int insert_clause_to_trie ( cl_arr, total )             
     int cl_arr[], total;
{
  if (Root == CLAUSE_MARK) return 1;

  if (total > 0) Root = trie_insert_clause2(Root, cl_arr, total-1);

  if (total == 0 || Root == CLAUSE_MARK) { /* an empty clause is found */
    trace(6, printf("    [C%ld] becomes empty.\n", Clause_num));
    return 1;
  }
  return 0;
}
 
free_trie (no)
     struct trie *no;
{
  struct trie *no2;
  while (no && no != CLAUSE_MARK) {
    /* if (no->pos && no->pos != CLAUSE_MARK) free_trie( no->pos );
       if (no->neg && no->neg != CLAUSE_MARK) free_trie( no->neg ); */
    free_trie(no->pos); 
    free_trie(no->neg);
    no2 = no;
    no = no->bro;
    free_trie_cell(no2);
  }
}

void trie_init ()
{
  int dep;

  Root = NULL;
  CLAUSE_MARK = get_trie();
  roots = (struct trie **) malloc(MAX_ATOM * sizeof(struct trie *));
  for (dep = 0; dep <= Max_atom; dep++) roots[dep] = NULL;
}

void print_trie (no)
     struct trie *no;
{
  /*
  printf("\nUnit Clauses: ");
  for (i = 1; i <= Max_atom; i++) 
    if (value_of_var(i) != DC) {
      if (value_of_var(i) == TT)
	fprintf(Sato_fp, "(%d) ", i);
      else
	fprintf(Sato_fp, "(-%d) ", i);
    }
    */
  printf("\nClause Tree:\n");
  if (no == NULL)
    printf("   nil");
  else if (no == CLAUSE_MARK)
    printf("   [C]");
  else 
    print_trie_aux(no, 0, "", "", "");
  printf("\n");
}

print_trie_aux (no, sign, leader, addition, arrow)
     struct trie *no;
     int sign;
     char *leader, *addition, *arrow;
     /* assume no != NULL */
{
  char leader2[1000];
  int i;
  i = 0;

  printf("\n%s%s", leader, arrow);

  if (sign == 1 || sign == 2)
    if (no == CLAUSE_MARK)
      printf("->[C]");
    else 
      printf("-x%d[%d]", key_of(no), psign_of(no));
  else 
    printf(" x%d[%d]", key_of(no), psign_of(no));

  if (no->pos != NULL) i++;
  if (no->neg != NULL) i++;
  if (no->bro != NULL) i++;

  str_cat(leader, addition, leader2);

  if (no->pos != NULL) {
    if (i == 1)
      print_trie_aux(no->pos, 1, leader2, "     ", " `-P-");
    else
      print_trie_aux(no->pos, 1, leader2, " |   ", " |-P-");
    i--;
  }

  if (no->neg != NULL) {
    if (i == 1)
      print_trie_aux(no->neg, 2, leader2, "     ", " `-N-");
    else
      print_trie_aux(no->neg, 2, leader2, " |   ", " |-N-");
    i--;
  }

  if (no->bro != NULL) {
      print_trie_aux(no->bro, 3, leader2, "", "");
    }
}

void print_clauses_in_trie ()
{
  int cl_arr[MAX_STACK];

  if (Root == CLAUSE_MARK) {
    fprintf(stderr, "\nAn empty clause is found.\n");
  } else if (Root != NULL) 
    print_cl_in_trie_aux(Root, 0, cl_arr);
}

print_cl_in_trie_aux (no, size, cl_arr)
     /* assume no != NULL */
     struct trie *no;
     int size, cl_arr[];
{
  int key; 

  if (no == CLAUSE_MARK) {
    print_clause(cl_arr, size);
    return;
  } else {
    key = key_of(no);
  }

  if (no->pos != NULL) {
    cl_arr[size] = (key << 1);
    print_cl_in_trie_aux(no->pos, size+1, cl_arr);
  }

  if (no->neg != NULL) {
    cl_arr[size] = (key << 1)+1;
    print_cl_in_trie_aux(no->neg, size+1, cl_arr);
  }

  if (no->bro != NULL) {
    print_cl_in_trie_aux(no->bro, size, cl_arr);
  }
}

mergesort_clause (arr, total)
     int arr[], total;
{
  int i, s=1;
  Size = total;

  while (s < Size) {
    s = s<<1;
    for (i = 0; i < Size; i += s) {
      mergesort_clause2(arr, i, s);
    }
  }
}

mergesort_clause2 (arr, p, s)
     int arr[], p, s;
{
  int r0;
  int r, x, y;
  int B[1000];

  if (s == 2) {
    r = p+1;
    if (r >= Size) return 0;
    x = arr[p];
    y = arr[r];
    if (x < y) {
      arr[p] = y;
      arr[r] = x;
    }
  } else {
    int q = p+(s>>1);
    int i;
    r = p+s;

    if (r >= Size) {
      r = Size; 
      if (r <= q) return 0;
    }
    r0 = r;

    x = arr[--q]; y = arr[--r];
    while (q < r && (x) >= (y)) { y = arr[--r]; }
    if (q < r) {
      s = 0; i = q+1;
      while (i < r) B[s++] = arr[i++];
      while (1) {
	if ((x) < (y)) {
	  arr[r--] = x;
	  if (q == p) { B[s++] = y; break; }
	  x = arr[--q];
	} else {
	  arr[r--] = y;
	  if (s == 0) break;
	  y = B[--s];
	}
      }
      while (s) arr[r--] = B[--s];
    }
  }
}
#endif
