void distribute_forall::reduce1_quantifier(quantifier * q) { // This transformation is applied after skolemization/quantifier elimination. So, all quantifiers are universal. SASSERT(q->is_forall()); // This transformation is applied after basic pre-processing steps. // So, we can assume that // 1) All (and f1 ... fn) are already encoded as (not (or (not f1 ... fn))) // 2) All or-formulas are flat (or f1 (or f2 f3)) is encoded as (or f1 f2 f3) expr * e = get_cached(q->get_expr()); if (m_manager.is_not(e) && m_manager.is_or(to_app(e)->get_arg(0))) { // found target for simplification // (forall X (not (or F1 ... Fn))) // --> // (and (forall X (not F1)) // ... // (forall X (not Fn))) app * or_e = to_app(to_app(e)->get_arg(0)); unsigned num_args = or_e->get_num_args(); expr_ref_buffer new_args(m_manager); for (unsigned i = 0; i < num_args; i++) { expr * arg = or_e->get_arg(i); expr_ref not_arg(m_manager); // m_bsimp.mk_not applies basic simplifications. For example, if arg is of the form (not a), then it will return a. m_bsimp.mk_not(arg, not_arg); quantifier_ref tmp_q(m_manager); tmp_q = m_manager.update_quantifier(q, not_arg); expr_ref new_q(m_manager); elim_unused_vars(m_manager, tmp_q, new_q); new_args.push_back(new_q); } expr_ref result(m_manager); // m_bsimp.mk_and actually constructs a (not (or ...)) formula, // it will also apply basic simplifications. m_bsimp.mk_and(new_args.size(), new_args.c_ptr(), result); cache_result(q, result); } else { cache_result(q, m_manager.update_quantifier(q, e)); } }
void bv_elim_star::reduce1_quantifier(quantifier* q) { quantifier_ref r(m_manager); proof_ref pr(m_manager); m_bv_elim.elim(q, r); if (m_manager.fine_grain_proofs()) { pr = m_manager.mk_rewrite(q, r.get()); } else { pr = 0; } cache_result(q, r, pr); }
subpaving::var process_mul(app * t, unsigned depth, mpz & n, mpz & d) { unsigned num_args = t->get_num_args(); if (num_args <= 1) found_non_simplified(); rational k; expr * m; if (m_autil.is_numeral(t->get_arg(0), k)) { if (num_args != 2) found_non_simplified(); qm().set(n, k.to_mpq().numerator()); qm().set(d, k.to_mpq().denominator()); m = t->get_arg(1); } else { qm().set(n, 1); qm().set(d, 1); m = t; } expr * const * margs; unsigned sz; if (m_autil.is_mul(m)) { margs = to_app(m)->get_args(); sz = to_app(m)->get_num_args(); } else { margs = &m; sz = 1; } scoped_mpz n_arg(qm()); scoped_mpz d_arg(qm()); sbuffer<subpaving::power> pws; for (unsigned i = 0; i < sz; i++) { expr * arg = margs[i]; unsigned k; as_power(arg, arg, k); subpaving::var x_arg = process(arg, depth+1, n_arg, d_arg); qm().power(n_arg, k, n_arg); qm().power(d_arg, k, d_arg); qm().mul(n, n_arg, n); qm().mul(d, d_arg, d); if (x_arg != subpaving::null_var) pws.push_back(subpaving::power(x_arg, k)); } subpaving::var x; if (pws.empty()) x = subpaving::null_var; else if (pws.size() == 1 && pws[0].degree() == 1) x = pws[0].get_var(); else x = s().mk_monomial(pws.size(), pws.c_ptr()); cache_result(t, x, n, d); return x; }
void distribute_forall::reduce1(expr * n) { switch (n->get_kind()) { case AST_VAR: cache_result(n, n); break; case AST_APP: reduce1_app(to_app(n)); break; case AST_QUANTIFIER: reduce1_quantifier(to_quantifier(n)); break; default: UNREACHABLE(); } }
subpaving::var process_add(app * t, unsigned depth, mpz & n, mpz & d) { unsigned num_args = t->get_num_args(); mpz_buffer ns(qm()), ds(qm()); var_buffer xs; scoped_mpq c(qm()), c_arg(qm()); scoped_mpz n_arg(qm()), d_arg(qm()); for (unsigned i = 0; i < num_args; i++) { expr * arg = t->get_arg(i); subpaving::var x_arg = process(arg, depth+1, n_arg, d_arg); if (x_arg == subpaving::null_var) { qm().set(c_arg, n_arg, d_arg); qm().add(c, c_arg, c); } else { xs.push_back(x_arg); ns.push_back(n_arg); ds.push_back(d_arg); } } qm().set(d, c.get().denominator()); unsigned sz = xs.size(); for (unsigned i = 0; i < sz; i++) { qm().lcm(d, ds[i], d); } scoped_mpz & k = d_arg; qm().div(d, c.get().denominator(), k); scoped_mpz sum_c(qm()); qm().mul(c.get().numerator(), k, sum_c); for (unsigned i = 0; i < sz; i++) { qm().div(d, ds[i], k); qm().mul(ns[i], k, ns[i]); } subpaving::var x; if (sz == 0) { qm().set(n, sum_c); x = subpaving::null_var; } else { x = s().mk_sum(sum_c, sz, ns.c_ptr(), xs.c_ptr()); qm().set(n, 1); } cache_result(t, x, n, d); return x; }
subpaving::var process_power(app * t, unsigned depth, mpz & n, mpz & d) { rational k; SASSERT(t->get_num_args() == 2); if (!m_autil.is_numeral(t->get_arg(1), k) || !k.is_int() || !k.is_unsigned()) { qm().set(n, 1); qm().set(d, 1); return mk_var_for(t); } unsigned _k = k.get_unsigned(); subpaving::var x = process(t->get_arg(0), depth+1, n, d); if (x != subpaving::null_var) { subpaving::power p(x, _k); x = s().mk_monomial(1, &p); } qm().power(n, _k, n); qm().power(d, _k, d); cache_result(t, x, n, d); return x; }
void distribute_forall::reduce1_app(app * a) { SASSERT(a); unsigned num_args = a->get_num_args(); unsigned j = num_args; bool reduced = false; m_new_args.reserve(num_args); app * na = a; while(j > 0) { --j; SASSERT(is_cached(a->get_arg(j))); expr * c = get_cached(a->get_arg(j)); SASSERT(c!=0); if (c != a->get_arg(j)) reduced = true; m_new_args[j] = c; } if (reduced) { na = m_manager.mk_app(a->get_decl(), num_args, m_new_args.c_ptr()); } cache_result(a, na); }
static const char* remap_file(const char* syscall_name, const char* pathname, char* buffer, usage_t usage) { char* pos; int debug = EKAM_DEBUG; /* Ad-hoc debugging can be accomplished by setting debug = 1 when a particular file pattern * is matched. */ if (debug) { fprintf(stderr, "remap for %s (%s): %s\n", syscall_name, (usage == READ ? "read" : "write"), pathname); } init_streams(); if (strlen(pathname) >= PATH_MAX) { /* Too long. */ if (debug) fprintf(stderr, " name too long\n"); errno = ENAMETOOLONG; return NULL; } if (get_cached_result(pathname, buffer, usage)) { if (debug) fprintf(stderr, " cached: %s\n", buffer); return buffer; } flockfile(ekam_call_stream); if (strncmp(pathname, TAG_PROVIDER_PREFIX, strlen(TAG_PROVIDER_PREFIX)) == 0) { /* A tag reference. Construct the tag name in |buffer|. */ strcpy(buffer, pathname + strlen(TAG_PROVIDER_PREFIX)); if (usage == READ) { /* Change first slash to a colon to form a tag. E.g. "header/foo.h" becomes * "header:foo.h". */ pos = strchr(buffer, '/'); if (pos == NULL) { /* This appears to be a tag type without a name, so it should look like a directory. * We can use the current directory. TODO: Return some fake empty directory instead. */ funlockfile(ekam_call_stream); strcpy(buffer, "."); if (debug) fprintf(stderr, " is directory\n"); return buffer; } *pos = ':'; canonicalizePath(pos + 1); if (strcmp(buffer, "canonical:.") == 0) { /* HACK: Don't try to remap top directory. */ funlockfile(ekam_call_stream); if (debug) fprintf(stderr, " current directory\n"); return "src"; } } /* Ask ekam to remap the file name. */ fputs(usage == READ ? "findProvider " : "newProvider ", ekam_call_stream); fputs(buffer, ekam_call_stream); fputs("\n", ekam_call_stream); } else if (strcmp(pathname, TMP) == 0 || strcmp(pathname, VAR_TMP) == 0 || strncmp(pathname, TMP_PREFIX, strlen(TMP_PREFIX)) == 0 || strncmp(pathname, VAR_TMP_PREFIX, strlen(VAR_TMP_PREFIX)) == 0) { /* Temp file. Ignore. */ funlockfile(ekam_call_stream); if (debug) fprintf(stderr, " temp file: %s\n", pathname); return pathname; } else { if (strncmp(pathname, current_dir, strlen(current_dir)) == 0) { /* The app is trying to open files in the current directory by absolute path. Treat it * exactly as if it had used a relative path. */ pathname = pathname + strlen(current_dir); } else if (pathname[0] == '/') { /* Absolute path. Note the access but don't remap. */ if (usage == WRITE) { /* Cannot write to absolute paths. */ funlockfile(ekam_call_stream); errno = EACCES; if (debug) fprintf(stderr, " absolute path, can't write\n"); return NULL; } fputs("noteInput ", ekam_call_stream); fputs(pathname, ekam_call_stream); fputs("\n", ekam_call_stream); fflush(ekam_call_stream); if (ferror_unlocked(ekam_call_stream)) { funlockfile(ekam_call_stream); fprintf(stderr, "error: Ekam call stream broken.\n"); abort(); } cache_result(pathname, pathname, usage); funlockfile(ekam_call_stream); if (debug) fprintf(stderr, " absolute path: %s\n", pathname); return pathname; } /* Path in current directory. */ strcpy(buffer, pathname); canonicalizePath(buffer); if (strcmp(buffer, ".") == 0) { /* HACK: Don't try to remap current directory. */ funlockfile(ekam_call_stream); if (debug) fprintf(stderr, " current directory\n"); return "src"; } else { /* Ask ekam to remap the file name. */ fputs(usage == READ ? "findInput " : "newOutput ", ekam_call_stream); fputs(buffer, ekam_call_stream); fputs("\n", ekam_call_stream); } } fflush(ekam_call_stream); if (ferror_unlocked(ekam_call_stream)) { funlockfile(ekam_call_stream); fprintf(stderr, "error: Ekam call stream broken.\n"); abort(); } /* Carefully lock the return stream then unlock the call stream, so that we know that * responses will be received in the correct order. */ flockfile(ekam_return_stream); funlockfile(ekam_call_stream); /* Read response from Ekam. */ if (fgets(buffer, PATH_MAX, ekam_return_stream) == NULL) { funlockfile(ekam_return_stream); fprintf(stderr, "error: Ekam return stream broken.\n"); abort(); } /* Done reading. */ funlockfile(ekam_return_stream); /* Remove the trailing newline. */ pos = strchr(buffer, '\n'); if (pos == NULL) { fprintf(stderr, "error: Path returned from Ekam was too long.\n"); abort(); } *pos = '\0'; if (*buffer == '\0') { /* Not found. */ errno = ENOENT; if (debug) fprintf(stderr, " ekam says no such file\n"); return NULL; } cache_result(pathname, buffer, usage); if (debug) fprintf(stderr, " remapped to: %s\n", buffer); return buffer; }