/* * Check whether t is a constant * - t must have positive polarity */ static bool term_is_constant(term_table_t *table, term_t t) { term_kind_t kind; assert(is_pos_term(t)); kind = term_kind(table, t); return kind == CONSTANT_TERM || kind == UNINTERPRETED_TERM; }
/* * Print the term map for every uinterpreted term present in ctx->intern_tbl * then print the core */ void dimacs_print_bvcontext(FILE *f, context_t *ctx) { term_table_t *terms; intern_tbl_t *intern; uint32_t i, n; term_t t; assert(ctx->core != NULL); fputs("c Autogenerated by Yices\n", f); fputs("c\n", f); terms = ctx->terms; intern = &ctx->intern; n = intern->map.top; for (i=0; i<n; i++) { t = pos_term(i); if (good_term(terms, t) && term_kind(terms, t) == UNINTERPRETED_TERM) { dimacs_print_term_map(f, ctx, t); } } fputs("c\n", f); dimacs_print_core(f, ctx->core); fflush(f); }
/* * Check whether r is a free root: * - r must be a root * - it's free if rank[r] < 255 (not frozen) or if r * is not in the table and is uninterpreted. */ bool intern_tbl_root_is_free(intern_tbl_t *tbl, term_t r) { assert(intern_tbl_is_root(tbl, r)); if (intern_tbl_term_present(tbl, r)) { return au8_read(&tbl->rank, index_of(r)) < 255; } else { return term_kind(tbl->terms, r) == UNINTERPRETED_TERM; } }
/* * Add t to the union-find structure: * - t must be uninterpreted * - this creates a new singleton class with t as root * and rank[t] is 0. */ static void partition_add(intern_tbl_t *tbl, term_t t) { type_t tau; assert(term_kind(tbl->terms, t) == UNINTERPRETED_TERM && ai32_read(&tbl->map, index_of(t)) == NULL_MAP); tau = term_type(tbl->terms, t); ai32_write(&tbl->type, index_of(t), tau); }
/* * Merge the classes of x and y * - both terms must be roots, present in the table * - x and y must be distinct and at least one of them * must be a free root */ static void partition_merge(intern_tbl_t *tbl, term_t x, term_t y) { uint8_t r_x, r_y; type_t tau_x, tau_y, tau; assert(intern_tbl_is_root(tbl, x) && intern_tbl_is_root(tbl, y) && x != y); tau_x = ai32_get(&tbl->type, index_of(x)); tau_y = ai32_get(&tbl->type, index_of(y)); assert(tau_x != NULL_TYPE && tau_y != NULL_TYPE); // intersection type tau = inf_type(tbl->types, tau_x, tau_y); assert(tau != NULL_TYPE); r_x = au8_read(&tbl->rank, index_of(x)); r_y = au8_read(&tbl->rank, index_of(y)); assert(r_x < 255 || r_y < 255); if (r_x < r_y) { // y stays root and is made parent of x in the union-find tree assert(term_kind(tbl->terms, x) == UNINTERPRETED_TERM); ai32_write(&tbl->map, index_of(x), (y ^ polarity_of(x))); // update type[y] if needed if (tau != tau_y) { ai32_write(&tbl->type, index_of(y), tau); } } else { // x stays root and is made parent of y in the tree assert(term_kind(tbl->terms, y) == UNINTERPRETED_TERM); ai32_write(&tbl->map, index_of(y), (x ^ polarity_of(y))); // update type[x] if needed if (tau != tau_x) { ai32_write(&tbl->type, index_of(x), tau); } // increase rank[x] if needed if (r_x == r_y) { assert(r_x < 254); au8_write(&tbl->rank, index_of(x), r_x + 1); } } }
/* * Store the substitution t --> u in the model * - t and u must be valid term indices * - t must be an uninterpreted term, not mapped to anything */ void model_add_substitution(model_t *model, term_t t, term_t u) { int_hmap_t *alias; int_hmap_pair_t *r; assert(term_kind(model->terms, t) == UNINTERPRETED_TERM && good_term(model->terms, u) && t != u && model->has_alias && int_hmap_find(&model->map, t) == NULL); alias = model->alias_map; if (alias == NULL) { alias = (int_hmap_t *) safe_malloc(sizeof(int_hmap_t)); init_int_hmap(alias, 0); // default size model->alias_map = alias; } r = int_hmap_get(alias, t); assert(r->val < 0); r->val = u; }
/* * Print the assignment for t as computed by the evaluator * - t must be a valid, uninterpreted term */ static void eval_print_term_value(FILE *f, evaluator_t *eval, term_t t) { model_t *model; char *name; value_t v; assert(term_kind(eval->model->terms, t) == UNINTERPRETED_TERM); model = eval->model; v = eval_in_model(eval, t); if (v >= 0) { // v = good value for t name = term_name(model->terms, t); if (name == NULL) { fprintf(f, "(= t!%"PRId32" ", t); } else { fprintf(f, "(= %s ", name); } vtbl_print_object(f, &model->vtbl, v); fputc(')', f); } }
/* * Print the assignment for t as computed by the evaluator * - t must be a valid, uninterpreted term */ static void eval_pp_term_value(yices_pp_t *printer, evaluator_t *eval, term_t t) { model_t *model; char *name; value_t v; assert(term_kind(eval->model->terms, t) == UNINTERPRETED_TERM); model = eval->model; v = eval_in_model(eval, t); if (v >= 0) { // v = good value for t pp_open_block(printer, PP_OPEN_EQ); name = term_name(model->terms, t); if (name == NULL) { pp_id(printer, "t!", t); } else { pp_string(printer, name); } vtbl_pp_object(printer, &model->vtbl, v); pp_close_block(printer, true); } }
/* * Print the assignment for i in model */ void model_pp_term_value(yices_pp_t *printer, model_t *model, term_t t) { char *name; value_t v; assert(term_kind(model->terms, t) == UNINTERPRETED_TERM); pp_open_block(printer, PP_OPEN_EQ); name = term_name(model->terms, t); if (name == NULL) { pp_id(printer, "t!", t); } else { pp_string(printer, name); } v = model_find_term_value(model, t); if (v == null_value) { pp_string(printer, "???"); } else { vtbl_pp_object(printer, &model->vtbl, v); } pp_close_block(printer, true); }
/* * Main abstraction function */ static epartition_t *eq_abstract(eq_learner_t *learner, term_t f, bool polarity) { term_table_t *terms; epartition_t *a; assert(is_boolean_term(learner->terms, f)); a = find_cached_abstraction(learner, signed_term(f, polarity)); if (a == NULL) { // not in the cache // remove top-level negation if (is_neg_term(f)) { f = opposite_term(f); polarity = !polarity; } // explore f terms = learner->terms; switch (term_kind(terms, f)) { case EQ_TERM: a = eq_abstract_eq(learner, eq_term_desc(terms, f), polarity); break; case ITE_TERM: case ITE_SPECIAL: a = eq_abstract_ite(learner, ite_term_desc(terms, f), polarity); break; case OR_TERM: a = eq_abstract_or(learner, or_term_desc(terms, f), polarity); break; default: a = empty_epartition(&learner->manager); break; } cache_abstraction(learner, signed_term(f, polarity), a); } return a; }
/* * Print the assignment for t in model * - the format is (= <t's name> <value>) */ void model_print_term_value(FILE *f, model_t *model, term_t t) { char *name; value_t v; assert(term_kind(model->terms, t) == UNINTERPRETED_TERM); name = term_name(model->terms, t); if (name == NULL) { fprintf(f, "(= t!%"PRId32" ", t); } else { fprintf(f, "(= %s ", name); } v = model_find_term_value(model, t); if (v == null_value) { /* * ??) is a C trigraph so "???)" can't be written as is. */ fputs("???"")", f); } else { vtbl_print_object(f, &model->vtbl, v); fputc(')', f); } }
/* * 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; }
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; }
/* * Check for equality that trivially reduce to false */ static bool false_eq(term_table_t *table, term_t t1, term_t t2) { return t1 != t2 && term_kind(table, t1) == CONSTANT_TERM && term_kind(table, t2) == CONSTANT_TERM; }
static bool term_is_uconst(term_table_t *table, term_t t) { assert(is_pos_term(t)); return term_kind(table, t) == UNINTERPRETED_TERM; }
/* * 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); }
/* * 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); }
/* * Filter function for model_collect_terms * - aux is a term table * - return true if term t should be printed in the assignments (i.e., t has a name) */ static bool term_to_print(void *aux, term_t t) { return term_kind(aux, t) == UNINTERPRETED_TERM && term_name(aux, t) != NULL; }