/* * We visit terms breadth-first to check for cycles. * The index of all visited terms are stored in subst->cache. * The terms to process are stored in subst->queue. */ static void bfs_visit_index(intern_tbl_t *tbl, int32_t i) { if (kind_for_idx(tbl->terms, i) == UNINTERPRETED_TERM) { // replace i by its root i = index_of(intern_tbl_get_root(tbl, pos_term(i))); } if (int_hset_add(tbl->cache, i)) { // i has not been seen before int_queue_push(tbl->queue, i); } }
/* * Print what's mapped to t in the context's internalization table. * - if t is mapped to a Boolean, the corresponding DIMACS literal is printed * - if t is mapped to a bitvector then the corresponding literal array is printed * - otherwise we print "non boolean" */ void dimacs_print_internalized_term(FILE *f, context_t *ctx, term_t t) { intern_tbl_t *intern; type_table_t *types; term_t r; type_t tau; int32_t code; uint32_t polarity; intern = &ctx->intern; types = ctx->types; r = intern_tbl_get_root(intern, t); if (t != r) { // substitution: t --> r (can't deal with this) fputs("eliminated", f); } else if (intern_tbl_root_is_mapped(intern, r)) { // t = r is mapped to something polarity = polarity_of(r); r = unsigned_term(r); tau = intern_tbl_type_of_root(intern, r); if (is_boolean_type(tau)) { // Boolean term code = intern_tbl_map_of_root(intern, r); assert(code_is_valid(code)); dimacs_print_bool_code(f, code, polarity); } else if (is_bv_type(types, tau)) { // Bitvector term code = intern_tbl_map_of_root(intern, r); assert(code_is_valid(code)); assert(polarity == 0); dimacs_print_bv_code(f, ctx, code); } else { // Can't be converted to DIMACS fputs("non boolean", f); } } else { // r not mapped to anything fputs("not internalized", f); } }
/* * Check whether f is a range constraint * - if so return a term t and fill in vector v with the formula's constants * - otherwise, return NULL_TERM * * Side effect: use queue and cache. * v may be modified even if the function returns NULL_TERM. */ static term_t formula_is_range_constraint(sym_breaker_t *breaker, term_t f, ivector_t *v) { int_queue_t *queue; int_hset_t *cache; term_table_t *terms; intern_tbl_t *intern; term_t r, t; term_t x, a, y, b; uint32_t neqs; queue = &breaker->queue; cache = &breaker->cache; terms = breaker->terms; intern = &breaker->ctx->intern; assert(int_queue_is_empty(queue) && int_hset_is_empty(cache)); push_term(queue, cache, f); neqs = 0; t = NULL_TERM; y = NULL_TERM; // prevent GCC warning b = NULL_TERM; // prevent GCC warning /* * Invariants: * - neqs = number of equality atoms seen so far * - if neq == 1, then the first equality is stored as (y == b) where b is a constant * - if neq >= 2, then all equalities seen so far were of the form (x == constant) */ do { // r := root of the first term in the queue r = intern_tbl_get_root(intern, int_queue_pop(queue)); switch (match_term(breaker->ctx, r, &a, &x)) { case MATCH_FALSE: // skip false terms break; case MATCH_OR: push_children(queue, cache, or_term_desc(terms, r)); break; case MATCH_EQ: assert(term_is_constant(terms, a)); if (neqs == 0) { y = x; b = a; } else if (neqs == 1) { /* * First equality: (y == b). Second equality: (x == a) */ if (y == x) { // y is the common term, a and b are constant ivector_push(v, b); ivector_push(v, a); } else if (y == a && term_is_uconst(terms, x)) { // y is the common term, b and x are constant ivector_push(v, b); ivector_push(v, a); } else if (x == b && term_is_uconst(terms, y)) { // b is the common term, y and a are constant ivector_push(v, y); ivector_push(v, a); y = b; } else if (a == b && term_is_uconst(terms, y) && term_is_uconst(terms, x)) { // b is the common term, y and x are constant ivector_push(v, y); ivector_push(v, x); y = b; } else { // abort goto done; } } else { /* * All equalities so far have the form (y == constant) * - the current equality is (x == a) */ if (y == x) { ivector_push(v, a); // match } else if (y == a && term_is_constant(terms, x)) { ivector_push(v, x); // swap a and x } else { // no match goto done; } } neqs ++; break; case MATCH_IFF: /* * the returned term x is equivalent to t */ push_term(queue, cache, x); break; default: // abort goto done; } } while (! int_queue_is_empty(queue)); assert(y != NULL_TERM && t == NULL_TERM); if (neqs >= 2) { assert(v->size == neqs); t = y; } done: int_queue_reset(queue); int_hset_reset(cache); return t; }
static match_code_t match_term(context_t *ctx, term_t t, term_t *a, term_t *x) { composite_term_t *eq; term_table_t *terms; match_code_t code; term_t t1, t2; if (term_is_false(ctx, t)) { code = MATCH_FALSE; } else { code = MATCH_OTHER; terms = ctx->terms; switch (term_kind(terms, t)) { case OR_TERM: if (is_pos_term(t)) { code = MATCH_OR; } break; case EQ_TERM: eq = eq_term_desc(terms, t); t1 = intern_tbl_get_root(&ctx->intern, eq->arg[0]); t2 = intern_tbl_get_root(&ctx->intern, eq->arg[1]); if (is_boolean_term(terms, t1)) { assert(is_boolean_term(terms, t2)); /* * t is either (iff t1 t2) or (not (iff t1 t2)) * we rewrite (not (iff t1 t2)) to (iff t1 (not t2)) */ if (is_neg_term(t)) { t2 = opposite_term(t2); } /* * Check whether t1 or t2 is true or false */ if (term_is_true(ctx, t1)) { code = MATCH_IFF; *x = t2; } else if (term_is_false(ctx, t1)) { code = MATCH_IFF; *x = opposite_term(t2); } else if (term_is_true(ctx, t2)) { code = MATCH_IFF; *x = t1; } else if (term_is_false(ctx, t2)) { code = MATCH_IFF; *x = opposite_term(t1); } } else if (t1 != t2) { /* * t1 and t2 are not Boolean * if t1 and t2 are equal, we return MATCH_OTHER, since (eq t1 t2) is true */ assert(is_pos_term(t1) && is_pos_term(t2)); if (false_eq(terms, t1, t2)) { code = MATCH_FALSE; } else if (term_is_constant(terms, t1)) { *a = t1; *x = t2; code = MATCH_EQ; } else if (term_is_constant(terms, t2)) { *a = t2; *x = t1; code = MATCH_EQ; } } break; default: break; } } return code; }