/**************************************************** Satz written by Peter G. Stock (... 1999) based on Satz originally written by Chu Min Li (September 1996) ****************************************************/ #include #include #include #include #include #include typedef signed char s_char; typedef unsigned char u_char; #define TRUE 1 #define FALSE 0 #define NONE -1 #define DEAD 0 #define LIVE 1 #define WORD_LENGTH 50 #define WEIGHT 5 #define T 10 #define RESOLVANT_LENGTH 3 #define MAX_NODE_NUMBER 6000 /* test if the new clause is redundant or subsumed by another */ #define OLD_CLAUSE_REDUNDANT 77 #define NEW_CLAUSE_REDUNDANT 7 /* the tables of variables and clauses are statically allocated. Modify the parameters tab_variable_size and tab_clause_size before compilation if necessary */ #define tab_variable_size 5000 #define tab_clause_size 100000 #define multiple_tab_clause_size 2*tab_clause_size /* macro definitions */ #define positive(literal) literal < NUM_VARS #define negative(literal) literal >= NUM_VARS #define get_var_from_lit(negative_literal) negative_literal-NUM_VARS #define complement(lit1, lit2) ((lit1", clause_length[i]); } } printf("\n"); } /* ---------------------------------------------------------------------------------- */ void remove_clauses(int *clauses) /* called twice in backtracking, twice in unitclause_process, twice in simple_propagate, twice in examine, twice in examine1, three times in choose_and_instantiate_variable_in_clause */ { int clause; for(clause=*clauses; clause!=NONE; clause=*(++clauses)) { if (clause_state[clause] == LIVE) { clause_state[clause] = DEAD; push(clause, CLAUSE_STACK); } } } /* ---------------------------------------------------------------------------------- */ void simple_manage_clauses(register int *clauses) /* called twice in backtracking, once in examine, twice in examine1, once in choose_and_instantiate_variable_in_clause */ { int clause; for(clause=*clauses; clause!=NONE; clause=*(++clauses)) { if (clause_state[clause] == LIVE) { switch (clause_length[clause]) { case 2: push(clause, UNITCLAUSE_STACK); clause_length[clause]--; break; default: clause_length[clause]--; push(clause, MANAGEDCLAUSE_STACK); } } } } int manage_clauses(register int *clauses) /* called twice in unitclause_process */ { int clause; for(clause=*clauses; clause!=NONE; clause=*(++clauses)) { if (clause_state[clause] == LIVE) { switch (clause_length[clause]) { case 1: return FALSE; case 2: push(clause, UNITCLAUSE_STACK); clause_length[clause]--; break; default: clause_length[clause]--; push(clause, MANAGEDCLAUSE_STACK); } } } return TRUE; } void my_simple_manage_clauses(register int *clauses) /* called twice in examine, twice in examine1 */ { int clause; for(clause=*clauses; clause!=NONE; clause=*(++clauses)) { if (clause_state[clause] == LIVE) { switch (clause_length[clause]) { case 2: push(clause, MY_UNITCLAUSE_STACK); clause_length[clause]--; break; default: clause_length[clause]--; push(clause, MY_MANAGEDCLAUSE_STACK); } } } } int my_manage_clauses(register int *clauses) /* called twice in branch */ { int clause; for(clause=*clauses; clause!=NONE; clause=*(++clauses)) { if (clause_state[clause] == LIVE) { switch (clause_length[clause]) { case 1: return FALSE; case 2: push(clause, MY_UNITCLAUSE_STACK); clause_length[clause]--; break; default: clause_length[clause]--; push(clause, MY_MANAGEDCLAUSE_STACK); } } } return TRUE; } /* ---------------------------------------------------------------------------------- */ int backtracking(void) /* called twice in unitclause_process */ { int var, index; /**/ int val; UNITCLAUSE_STACK_fill_pointer = 0; NUM_BACK++; do { var = pop(VARIABLE_STACK); if (var_rest_value[var] == NONE) var_state[var] = LIVE; else { for (index = saved_clause_stack[var]; index < CLAUSE_STACK_fill_pointer; index++) clause_state[CLAUSE_STACK[index]] = LIVE; CLAUSE_STACK_fill_pointer = saved_clause_stack[var]; for (index = saved_managedclause_stack[var]; index < MANAGEDCLAUSE_STACK_fill_pointer; index++) clause_length[MANAGEDCLAUSE_STACK[index]]++; MANAGEDCLAUSE_STACK_fill_pointer = saved_managedclause_stack[var]; var_current_value[var] = var_rest_value[var]; var_rest_value[var] = NONE; push(var, VARIABLE_STACK); if (var_current_value[var] == FALSE) { simple_manage_clauses(pos_in[var]); remove_clauses(neg_in[var]); } else { simple_manage_clauses(neg_in[var]); remove_clauses(pos_in[var]); } /***/ #ifdef verbose if (var_current_value[var]==TRUE) val = 'T'; else val = 'F'; printf("Backtrack branch: %d -> %c\n", var+1, val); #ifdef print_tree print_formula(); #endif #endif /***/ return TRUE; } } while (VARIABLE_STACK_fill_pointer != 0); return FALSE; } void unitclause_process(void) /* called three times in choose_and_instantiate_variable_in_clause, once in main */ { int var, i, unitclause, lit, *lits, unitclause_position; for (unitclause_position = 0; unitclause_position < UNITCLAUSE_STACK_fill_pointer; unitclause_position++) { unitclause = UNITCLAUSE_STACK[unitclause_position]; clause_length[unitclause]++; if (clause_state[unitclause] == LIVE) { NUM_UNIT++; lits = sat[unitclause]; for(lit=*lits; lit!=NONE; lit=*(++lits)) { if (positive(lit)) { var = lit; if (var_state[var] == LIVE) { var_current_value[var] = TRUE; var_rest_value[var] = NONE; if (manage_clauses(neg_in[var]) == TRUE) { var_state[var] = DEAD; push(var, VARIABLE_STACK); remove_clauses(pos_in[var]); /***/ #ifdef verbose printf("Unit: %d -> %c\n", var+1, 'T'); #ifdef print_tree print_formula(); #endif #endif /***/ break; } else { for (i=unitclause_position+1; i %c\n", var+1, 'T'); #endif /***/ backtracking(); return; } } } else { var = get_var_from_lit(lit); if (var_state[var] == LIVE) { var_current_value[var] = FALSE; var_rest_value[var] = NONE; if (manage_clauses(pos_in[var]) == TRUE) { var_state[var] = DEAD; push(var, VARIABLE_STACK); remove_clauses(neg_in[var]); /***/ #ifdef verbose printf("Unit: %d -> %c\n", var+1, 'F'); #ifdef print_tree print_formula(); #endif #endif /***/ break; } else { for (i=unitclause_position+1; i %c\n", var+1, 'F'); #endif /***/ backtracking(); return; } } } } } } UNITCLAUSE_STACK_fill_pointer = 0; } /* ---------------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------------- */ void reset_context(void) /* called three times in examine, four times in examine1 */ { int i; MY_UNITCLAUSE_STACK_fill_pointer = 0; for (i=0; i %c\n", var+1, 'T'); #ifdef print_tree print_formula(); #endif #endif /***/ } else if (get_pos_clause_num(var) == 0) { NUM_PURE++; var_current_value[var] = FALSE; var_rest_value[var] = NONE; var_state[var] = DEAD; push(var, VARIABLE_STACK); remove_clauses(neg_in[var]); /***/ #ifdef verbose printf("Pure: %d -> %c\n", var+1, 'F'); #ifdef print_tree print_formula(); #endif #endif /***/ } else { pos2 = num_pos_clause_of_length2[var]; neg2 = num_neg_clause_of_length2[var]; if ((neg2>0) && (pos2>0) && ((neg2+pos2)>3) ) { if (examine(var) == NONE) { saved_num_back = NUM_BACK; unitclause_process(); if (NUM_BACK > saved_num_back) return; } } } } } if (TESTED_VAR_STACK_fill_pointer < T) { /* TESTED_VAR_STACK_fill_pointer = 0; */ for (var=0; var0) && (pos2>0) && ((neg2>1) || (pos2>1)) ) if (reduce_if_negative_num[var] == 0) if (examine(var) == NONE) { saved_num_back = NUM_BACK; unitclause_process(); if (NUM_BACK > saved_num_back) return; } } } if (TESTED_VAR_STACK_fill_pointer < T) { TESTED_VAR_STACK_fill_pointer = 0; for (var=0; var saved_num_back) return; } } for (i=0; i max_num_clauses) { chosen_var = var; max_num_clauses = num_clauses; } } } if (chosen_var == NONE) return; var_state[chosen_var] = DEAD; saved_clause_stack[chosen_var] = CLAUSE_STACK_fill_pointer; saved_managedclause_stack[chosen_var] = MANAGEDCLAUSE_STACK_fill_pointer; push(chosen_var, VARIABLE_STACK); var_current_value[chosen_var] = TRUE; var_rest_value[chosen_var] = FALSE; simple_manage_clauses(neg_in[chosen_var]); remove_clauses(pos_in[chosen_var]); /***/ #ifdef verbose if (var_current_value[chosen_var]==TRUE) val = 'T'; else val = 'F'; printf("Branch: %d -> %c\n", chosen_var+1, val); #ifdef print_tree print_formula(); #endif #endif /***/ } /* ---------------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------------- */ void remove_link(int clause) /* called once in search_redundence */ { int lit; int *lits; struct node *pnode1, *pnode2, *pnode; lits = sat[clause]; for (lit=*lits; lit!=NONE; lit=*(++lits)) { pnode = (positive(lit) ? node_pos_in[lit] : node_neg_in[get_var_from_lit(lit)]); if (pnode == NULL) return; if (pnode->clause == clause) { if (positive(lit)) node_pos_in[lit] = pnode->next; else node_neg_in[get_var_from_lit(lit)] = pnode->next; } else for (pnode1=pnode, pnode2=pnode->next; pnode2!=NULL; pnode2=pnode2->next) { if (pnode2->clause == clause) { pnode1->next = pnode2->next; break; } else pnode1 = pnode2; } } } s_char redundant(int *new_clause, int *old_clause) /* called once in search_redundence */ { int j1=0, j2=0, lit1, lit2, old_clause_diff=0, new_clause_diff=0; while (((lit1=old_clause[j1]) != NONE) && ((lit2=new_clause[j2]) != NONE)) { if (smaller_than(lit1, lit2)) { j1++; old_clause_diff++; } else if (smaller_than(lit2, lit1)) { j2++; new_clause_diff++; } else if (complement(lit1, lit2)) { return FALSE; /* old_clause_diff++; new_clause_diff++; j1++; j2++; */ } else { j1++; j2++; } } if ((lit1 == NONE) && (old_clause_diff == 0)) /* the new clause is redundant or subsumed */ return NEW_CLAUSE_REDUNDANT; if ((lit2 == NONE) && (new_clause_diff == 0)) /* the old clause is redundant or subsumed */ return OLD_CLAUSE_REDUNDANT; return FALSE; } int search_redundence(int *lits) /* called once in add_resolvant, once in build_sat_instance */ { int lit, is_red; int *old_lits, *new_lits; struct node *pnode; new_lits = lits; for (lit=*lits; lit!=NONE; lit=*(++lits)) { for (pnode = (positive(lit) ? node_pos_in[lit] : node_neg_in[get_var_from_lit(lit)]); pnode != NULL; pnode = pnode->next) { old_lits = sat[pnode->clause]; is_red = redundant(new_lits, old_lits); if (is_red == OLD_CLAUSE_REDUNDANT) { /* printf("old clause %d is redundant\n", pnode->clause); */ clause_state[pnode->clause] = DEAD; remove_link(pnode->clause); } else if (is_red == NEW_CLAUSE_REDUNDANT) { return NEW_CLAUSE_REDUNDANT; } } } return FALSE; } /* ---------------------------------------------------------------------------------- */ s_char get_resolvant(int *clause1, int *clause2, int *resolvant) /* called once in add_resolvant */ { int lit1, lit2, num_diff=0, num_iden=0, num_opps=0, j1=0, j2=0, j, limited_length; while (((lit1=clause1[j1]) != NONE) && ((lit2=clause2[j2]) != NONE)) { if (complement(lit1, lit2)) { j1++; j2++; num_opps++; } else if (lit1 == lit2) { j1++; j2++; num_iden++; } else if (smaller_than(lit1, lit2)) { num_diff++; j1++; } else { num_diff++; j2++; } } if (num_opps == 1) { if (clause1[j1] == NONE) { for ( ; clause2[j2] != NONE; j2++) num_diff++; } else { for ( ; clause1[j1] != NONE; j1++) num_diff++; } if ((j1==1) || (j2==1)) limited_length = RESOLVANT_LENGTH; else if ((j1==2) && (j2==2)) limited_length = 1; else if (j1next) { old_lits = sat[pnode->clause]; is_res = get_resolvant(new_lits, old_lits, resolvant); if (is_res != FALSE) { is_red = search_redundence(resolvant); if (is_red != NEW_CLAUSE_REDUNDANT) { res = (int *) malloc((RESOLVANT_LENGTH+1)*sizeof(int)); clause_state[NUM_CLAUSES] = LIVE; j = 0; while ((res[j]=resolvant[j]) != NONE) ++j; if (j==0) return NONE; sat[NUM_CLAUSES] = res; clause_length[NUM_CLAUSES++] = j; } } } return TRUE; } /* ---------------------------------------------------------------------------------- */ struct node *allocate_node(void) /* called once in set_link */ { struct resource *presource; if (CLAUSE_NODES_pointer == MAX_NODE_NUMBER) { CLAUSE_NODES = (struct node *) malloc(MAX_NODE_NUMBER*sizeof(struct node)); CLAUSE_NODES_pointer = 0; presource = (struct resource *) malloc(sizeof(struct resource)); presource->next = resources; resources = presource; presource->pnode = CLAUSE_NODES; } return &(CLAUSE_NODES[CLAUSE_NODES_pointer++]); } void set_link(int clause) /* called once in build_sat_instance */ { int lit; int *lits; struct node *pnode; lits = sat[clause]; for (lit=*lits; lit!=NONE; lit=*(++lits)) { pnode = allocate_node(); pnode->clause = clause; if (positive(lit)) { pnode->next = node_pos_in[lit]; node_pos_in[lit] = pnode; } else { pnode->next = node_neg_in[get_var_from_lit(lit)]; node_neg_in[get_var_from_lit(lit)] = pnode; } } } void free_resources(void) /* called once in build_sat_instance */ { struct resource *presource; while (resources != NULL) { free(resources->pnode); presource = resources; resources = resources->next; free(presource); } } int* copy_clauses(struct node *node_in) /* called twice in build_sat_instance */ { int j=0, *in; struct node *pnode; pnode = node_in; while (pnode != NULL) { j++; pnode = pnode->next; } in = (int *) malloc((j+1)*sizeof(int)); j = 0; pnode = node_in; while (pnode != NULL) { in[j] = pnode->clause; j++; pnode = pnode->next; } in[j] = NONE; return in; } /* ---------------------------------------------------------------------------------- */ s_char build_sat_instance(char *input_file) /* called three times in build */ { FILE* fp_in = fopen(input_file, "r"); char ch, tautology, word[WORD_LENGTH]; int i, j, length, ii, jj, lit, tmp, lits[tab_variable_size], *plit, NUM_CLAUSES1; if (fp_in == NULL) return FALSE; fscanf(fp_in, "%c", &ch); while (ch != 'p') { while (ch != '\n') fscanf(fp_in, "%c", &ch); fscanf(fp_in, "%c", &ch); } fscanf(fp_in, "%s%d%d", word, &NUM_VARS, &NUM_CLAUSES); for (i=0; i abs(lits[jj])) { tmp = lits[jj]; lits[jj] = lit; lit = tmp; } else if (lit == lits[jj]) { lits[jj--] = lits[--length]; lits[length] = 0; printf("literal %d is redundant in clause %d\n", lit, i); } else if (abs(lit) == lits[jj]) { printf("clause %d is a tautology\n", i); tautology = TRUE; break; } } if (tautology == TRUE) break; else lits[ii] = lit; } if (tautology == FALSE) { sat[i] = (int *) malloc((length+1)*sizeof(int)); for (j=0; lits[j]!=0; j++) { if (lits[j] > 0) sat[i][j] = lits[j]-1; else sat[i][j] = abs(lits[j]) + NUM_VARS -1; } sat[i][j] = NONE; clause_length[i] = length; clause_state[i] = LIVE; } else { /* mistake with this bit? */ /* NUM_CLAUSES--; */ i--; } } fclose(fp_in); for (i=0; itms_utime; switch (build(argc, argv)) { case FALSE: printf("Input file error\n"); return -1; case TRUE: /***/ #ifdef verbose print_formula(); #endif /***/ do { if (UNITCLAUSE_STACK_fill_pointer == 0) choose_and_instantiate_variable_in_clause(); unitclause_process(); } while ((VARIABLE_STACK_fill_pointer != 0) && (!(satisfiable()))); break; case NONE: /* printf("An empty resolvant is found!\n");*/ break; } times(a_tms); endtime = a_tms->tms_utime; if (satisfiable()) { if (verify_solution()) return_value = 1; else return_value = -1; } else return_value = 0; printf("%d %5.3f %d %d %d %d\n", return_value, (double)(endtime-begintime)/CLK_TCK, NUM_BRANCH, NUM_BACK, NUM_UNIT, NUM_PURE); return return_value; }