/* * Reset to the empty table */ void reset_intern_tbl(intern_tbl_t *tbl) { reset_int32_array(&tbl->map); reset_int32_array(&tbl->type); reset_uint8_array(&tbl->rank); if (tbl->cache != NULL) { int_hset_reset(tbl->cache); } if (tbl->queue != NULL) { int_queue_reset(tbl->queue); } }
/* * Flatten all terms in flat->queue to conjuncts * - all terms in the queue must also be in the cache * - f_ite: if true, flatten (ite c a b) * - f_iff: if true, flatten (iff a b) */ static void flattener_build_conjuncts(flattener_t *flat, bool f_ite, bool f_iff) { term_table_t *terms; int_queue_t *queue; composite_term_t *d; term_t t, u, v; uint32_t i, n; queue = &flat->queue; terms = flat->terms; while (! int_queue_is_empty(queue)) { t = int_queue_pop(queue); switch (term_kind(terms, t)) { case ITE_TERM: case ITE_SPECIAL: d = ite_term_desc(terms, t); assert(d->arity == 3); if (f_ite && is_boolean_term(terms, d->arg[1])) { assert(is_boolean_term(terms, d->arg[2])); /* * If t is (ite C A B) * u := (C => A) * v := (not C => B) * Otherwise, t is (not (ite C A B)) * u := (C => not A) * v := (not C => not B) */ u = d->arg[1]; // A v = d->arg[2]; // B if (is_neg_term(t)) { u = opposite_term(u); v = opposite_term(v); } u = mk_implies(flat->manager, d->arg[0], u); // (C => u) v = mk_implies(flat->manager, opposite_term(d->arg[0]), v); // (not C) => v flattener_push_term(flat, u); flattener_push_term(flat, v); continue; } break; case EQ_TERM: d = eq_term_desc(terms, t); assert(d->arity == 2); if (f_iff && is_boolean_term(terms, d->arg[0])) { assert(is_boolean_term(terms, d->arg[1])); /* * t is either (iff A B) or (not (iff A B)): */ u = d->arg[0]; // A v = d->arg[1]; // B if (is_neg_term(t)) { u = opposite_term(u); } // flatten to (u => v) and (v => u) t = mk_implies(flat->manager, u, v); // (u => v) u = mk_implies(flat->manager, v, u); // (v => u); flattener_push_term(flat, t); flattener_push_term(flat, u); continue; } break; case OR_TERM: if (is_neg_term(t)) { /* * t is (not (or a[0] ... a[n-1])) * it flattens to (and (not a[0]) ... (not a[n-1])) */ d = or_term_desc(terms, t); n = d->arity; for (i=0; i<n; i++) { flattener_push_term(flat, opposite_term(d->arg[i])); } continue; } break; default: break; } ivector_push(&flat->resu, t); } // clean up the cache assert(int_queue_is_empty(queue)); int_hset_reset(&flat->cache); }
/* * Process disjuncts and universal quantifiers * - input = all terms in the queue * - f_ite: if true, flatten (ite c a b) * - f_iff: if true, flatten (iff a b) */ static void flattener_forall_disjuncts(flattener_t *flat, bool f_ite, bool f_iff) { term_table_t *terms; int_queue_t *queue; composite_term_t *d; term_t t, u, v; uint32_t i, n; queue = &flat->queue; terms = flat->terms; while (! int_queue_is_empty(queue)) { t = int_queue_pop(queue); switch (term_kind(terms, t)) { case ITE_TERM: case ITE_SPECIAL: d = ite_term_desc(terms, t); assert(d->arity == 3); if (f_ite && is_boolean_term(terms, d->arg[1])) { assert(is_boolean_term(terms, d->arg[2])); /* * If t is (ite C A B) * u := (C AND A) * v := (not C AND B) * Otherwise, t is (not (ite C A B)) * u := (C AND not A) * v := (not C AND not B) */ u = d->arg[1]; // A v = d->arg[2]; // B if (is_neg_term(t)) { u = opposite_term(u); // NOT A v = opposite_term(v); // NOT B } u = mk_binary_and(flat->manager, d->arg[0], u); // (C AND u) v = mk_binary_and(flat->manager, opposite_term(d->arg[0]), v); // (not C) AND v flattener_push_term(flat, u); flattener_push_term(flat, v); continue; } break; case EQ_TERM: d = eq_term_desc(terms, t); assert(d->arity == 2); if (f_iff && is_boolean_term(terms, d->arg[0])) { assert(is_boolean_term(terms, d->arg[1])); /* * t is either (iff A B) or (not (iff A B)): */ u = d->arg[0]; // A v = d->arg[1]; // B if (is_neg_term(t)) { u = opposite_term(u); } // flatten to (u AND v) or ((not u) AND (not v)) t = mk_binary_and(flat->manager, u, v); // (u AND v) u = mk_binary_and(flat->manager, opposite_term(u), opposite_term(v)); // (not u AND not v); flattener_push_term(flat, t); flattener_push_term(flat, u); continue; } break; case OR_TERM: if (is_pos_term(t)) { /* * t is (or a[0] ... a[n-1]) */ d = or_term_desc(terms, t); n = d->arity; for (i=0; i<n; i++) { flattener_push_term(flat, d->arg[i]); } continue; } break; case FORALL_TERM: if (is_pos_term(t)) { d = forall_term_desc(terms, t); n = d->arity; assert(n >= 2); /* * t is (FORALL x_0 ... x_k : body) * body is the last argument in the term descriptor */ flattener_push_term(flat, d->arg[n-1]); continue; } break; default: break; } ivector_push(&flat->resu, t); } // clean up the cache assert(int_queue_is_empty(queue)); int_hset_reset(&flat->cache); }
/* * Reset queue/cache and vector */ void reset_flattener(flattener_t *flat) { int_queue_reset(&flat->queue); int_hset_reset(&flat->cache); ivector_reset(&flat->resu); }
/* * Check whether t occurs in v * - t must be a free root * - v must be a valid term */ static bool bfs_occurs_check(intern_tbl_t *tbl, term_t t, term_t v) { term_table_t *terms; int_queue_t *queue; int_hset_t *cache; int32_t x; bool found; assert(intern_tbl_root_is_free(tbl, t)); assert(is_pos_term(t) && term_kind(tbl->terms, t) == UNINTERPRETED_TERM); terms = tbl->terms; queue = intern_tbl_get_queue(tbl); cache = intern_tbl_get_cache(tbl); assert(int_queue_is_empty(queue) && int_hset_is_empty(cache)); bfs_visit_term(tbl, v); found = false; do { x = int_queue_pop(queue); switch (kind_for_idx(terms, x)) { case CONSTANT_TERM: case ARITH_CONSTANT: case BV64_CONSTANT: case BV_CONSTANT: case VARIABLE: break; case UNINTERPRETED_TERM: if (x == index_of(t)) { // found a cycle found = true; goto done; } break; case ARITH_EQ_ATOM: case ARITH_GE_ATOM: bfs_visit_term(tbl, integer_value_for_idx(terms, x)); break; case ITE_TERM: case ITE_SPECIAL: case APP_TERM: case UPDATE_TERM: case TUPLE_TERM: case EQ_TERM: case DISTINCT_TERM: case FORALL_TERM: case LAMBDA_TERM: case OR_TERM: case XOR_TERM: case ARITH_BINEQ_ATOM: case BV_ARRAY: case BV_DIV: case BV_REM: case BV_SDIV: case BV_SREM: case BV_SMOD: case BV_SHL: case BV_LSHR: case BV_ASHR: case BV_EQ_ATOM: case BV_GE_ATOM: case BV_SGE_ATOM: bfs_visit_composite(tbl, composite_for_idx(terms, x)); break; case BIT_TERM: case SELECT_TERM: bfs_visit_term(tbl, select_for_idx(terms, x)->arg); break; case POWER_PRODUCT: bfs_visit_pprod(tbl, pprod_for_idx(terms, x)); break; case ARITH_POLY: bfs_visit_poly(tbl, polynomial_for_idx(terms, x)); break; case BV64_POLY: bfs_visit_bvpoly64(tbl, bvpoly64_for_idx(terms, x)); break; case BV_POLY: bfs_visit_bvpoly(tbl, bvpoly_for_idx(terms, x)); break; default: assert(false); abort(); break; } } while (! int_queue_is_empty(queue)); done: int_hset_reset(cache); int_queue_reset(queue); return found; }
/* * 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; }