/* * Assert (B and not C) in ctx * - return the assertion code */ static int32_t forall_context_assert(ef_solver_t *solver, term_t b, term_t c) { context_t *ctx; term_t assertions[2]; ctx = solver->forall_context; assert(ctx != NULL && context_status(ctx) == STATUS_IDLE); assert(is_boolean_term(ctx->terms, b) && is_boolean_term(ctx->terms, c)); assertions[0] = b; assertions[1] = opposite_term(c); return assert_formulas(ctx, 2, assertions); }
/* * Abstraction of (eq t1 t2): * - if t1 and t2 are boolean, we rewrite the formula as (t1 ==> t2) AND (t2 ==> t1) * - if t1 and t2 are non boolean build a basic partition */ static epartition_t *eq_abstract_eq(eq_learner_t *learner, composite_term_t *eq, bool polarity) { term_t t1, t2; epartition_t *p1, *q1, *p2, *q2; epartition_manager_t *m; assert(eq->arity == 2); m = &learner->manager; t1 = eq->arg[0]; t2 = eq->arg[1]; assert(t1 != t2); if (is_boolean_term(learner->terms, t1)) { assert(is_boolean_term(learner->terms, t2)); /* * - for positive polarity, * let u2 = t2, then (t1 <==> t2) is (t1 <==> u2) * - for negative polarity * let u2 = (not t2), then (not (t1 <==> t2)) is equivalent to (t1 <==> u2) * - in both cases we compute * abs(t1 <==> u2) * = abs((t1 ==> u2) and (u2 ==> t1)) * = abs((not t1 or u2) and (not u2 or t1)) * = meet(join(abs(not t1), abs(u2)), join(abs(not t2), abs(t1))) */ p1 = eq_abstract(learner, t1, true); // abs(t1) q1 = eq_abstract(learner, t1, false); // abs(not t1) p2 = eq_abstract(learner, t2, polarity); // abs(u2) q2 = eq_abstract(learner, t2, !polarity); // abs(not u2) q1 = eq_abstract_join(m, q1, p2); // join(abs(not t1), abs(u2)) p1 = eq_abstract_join(m, q2, p1); // join(abs(not u2), abs(t1)) p2 = eq_abstract_meet(m, p1, q1); // meet .. // prevent memory leak delete_epartition(m, p1); delete_epartition(m, q1); return p2; } else { if (polarity) { return basic_epartition(t1, t2); } else { return empty_epartition(m); } } }
/* * Add assertion f to the exists context * - return the internalization code * - the exists context must not be UNSAT */ static int32_t update_exists_context(ef_solver_t *solver, term_t f) { context_t *ctx; smt_status_t status; int32_t code; ctx = solver->exists_context; assert(ctx != NULL && is_boolean_term(ctx->terms, f)); status = context_status(ctx); switch (status) { case STATUS_SAT: case STATUS_UNKNOWN: context_clear(ctx); assert(context_status(ctx) == STATUS_IDLE); case STATUS_IDLE: code = assert_formula(ctx, f); break; default: code = INTERNAL_ERROR; // should not happen break; } return code; }
/* * Store that f is abstracted to p * - there must not be a record for f in the cache */ static void cache_abstraction(eq_learner_t *learner, term_t f, epartition_t *p) { ptr_hmap_pair_t *r; assert(good_term(learner->terms, f) && is_boolean_term(learner->terms, f) && p != NULL); r = ptr_hmap_get(&learner->cache, f); assert(r->val == NULL); r->val = p; }
/* * Get abstraction for f in the cache * - this works only if the corresponding record exists */ static epartition_t *get_cached_abstraction(eq_learner_t *learner, term_t f) { ptr_hmap_pair_t *p; assert(good_term(learner->terms, f) && is_boolean_term(learner->terms, f)); p = ptr_hmap_find(&learner->cache, f); assert(p != NULL); return p->val; }
/* * Print the assignment for all boolean terms in array a * - n = size of the array */ static void model_pp_bool_assignments(yices_pp_t *printer, model_t *model, term_t *a, uint32_t n) { term_table_t *terms; uint32_t i; term_t t; terms = model->terms; for (i=0; i<n; i++) { t = a[i]; if (is_boolean_term(terms, t)) { model_pp_term_value(printer, model, t); } } }
/* * Print the assignment for all boolean terms in array a * - n = size of the array */ static void model_print_bool_assignments(FILE *f, model_t *model, term_t *a, uint32_t n) { term_table_t *terms; uint32_t i; term_t t; terms = model->terms; for (i=0; i<n; i++) { t = a[i]; if (is_boolean_term(terms, t)) { model_print_term_value(f, model, t); fputc('\n', f); } } }
/* * Temporary test. Check whether one of the input assertion is reduced * to false by simplification. This is checked independent of the * logic label. */ static bool benchmark_reduced_to_false(smt_benchmark_t *bench) { uint32_t i, n; term_t f; n = bench->nformulas; for (i=0; i<n; i++) { f = bench->formulas[i]; assert(is_boolean_term(__yices_globals.terms, f)); if (f == false_term) { return true; } } return false; }
/* * 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; }
/* * 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); }
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; }