示例#1
0
文件: hnf.cpp 项目: NikolajBjorner/z3
 bool is_horn(expr* n) {
     expr* n1, *n2;
     while (is_forall(n)) n = to_quantifier(n)->get_expr();
     if (m.is_implies(n, n1, n2) && is_predicate(n2)) {
         if (is_var(n1)) {
             return true;
         }
         if (is_quantifier(n1)) {
             return false;
         }
         app* a1 = to_app(n1);
         if (m.is_and(a1)) {
             for (unsigned i = 0; i < a1->get_num_args(); ++i) {
                 if (!is_predicate(a1->get_arg(i)) && 
                     contains_predicate(a1->get_arg(i))) {                    
                     return false;
                 }
             }
         }
         else if (!is_predicate(a1) && contains_predicate(a1)) {
             return false;
         }
         return true;
     }    
     
     return false;
 }
示例#2
0
 bool is_implication(expr* f) {
     expr* e1;
     while (is_forall(f)) {
         f = to_quantifier(f)->get_expr();
     }
     while (m.is_implies(f, e1, f)) ;
     return is_predicate(f);
 }
示例#3
0
bool elim_bounds_cfg::reduce_quantifier(quantifier * q, 
                                     expr * n, 
                                     expr * const * new_patterns, 
                                     expr * const * new_no_patterns,
                                     expr_ref & result,
                                     proof_ref & result_pr) {
    if (!is_forall(q)) {
        return false;
    }
    unsigned num_vars = q->get_num_decls();
    ptr_buffer<expr> atoms;
    if (m.is_or(n))
        atoms.append(to_app(n)->get_num_args(), to_app(n)->get_args());
    else
        atoms.push_back(n);
    used_vars          used_vars;
    // collect non-candidates
    for (expr * a : atoms) {
        if (!is_bound(a))
            used_vars.process(a);
    }
    if (used_vars.uses_all_vars(q->get_num_decls())) {
        return false;
    }
    // collect candidates
    obj_hashtable<var> lowers;
    obj_hashtable<var> uppers;
    obj_hashtable<var> candidate_set;
    ptr_buffer<var>    candidates;
#define ADD_CANDIDATE(V) if (!lowers.contains(V) && !uppers.contains(V)) { candidate_set.insert(V); candidates.push_back(V); }
    for (expr * a : atoms) {
        var * lower = nullptr;
        var * upper = nullptr;
        if (is_bound(a, lower, upper)) {
            if (lower != nullptr && !used_vars.contains(lower->get_idx()) && lower->get_idx() < num_vars) {
                ADD_CANDIDATE(lower);
                lowers.insert(lower);
            }
            if (upper != nullptr && !used_vars.contains(upper->get_idx()) && upper->get_idx() < num_vars) {
                ADD_CANDIDATE(upper);
                uppers.insert(upper);
            }
        }
    }
    TRACE("elim_bounds", tout << "candidates:\n"; for (unsigned i = 0; i < candidates.size(); i++) tout << mk_pp(candidates[i], m) << "\n";);
示例#4
0
 void normalize(expr_ref& f) {
     bool is_positive = true;
     expr* e = 0;
     while (true) {
         if (is_forall(f) && is_positive) {
             f = to_quantifier(f)->get_expr();
         }
         else if (is_exists(f) && !is_positive) {
             f = to_quantifier(f)->get_expr();                    
         }
         else if (m.is_not(f, e)) {
             is_positive = !is_positive;
             f = e;
         }
         else {
             break;
         }
     }
     if (!is_positive) {
         f = m.mk_not(f);
     }
     
 }
示例#5
0
bool macro_finder::is_macro(expr * n, app_ref & head, expr_ref & def) {
    if (!is_forall(n))
        return false;
    TRACE("macro_finder", tout << "processing: " << mk_pp(n, m) << "\n";);
示例#6
0
/**
   \brief Little HACK for simplifying injectivity axioms
   
   \remark It is not covering all possible cases.
*/
bool simplify_inj_axiom(ast_manager & m, quantifier * q, expr_ref & result) {
    expr * n = q->get_expr();
    expr* arg1 = nullptr, * arg2 = nullptr, *narg = nullptr;
    expr* app1 = nullptr, * app2 = nullptr;
    expr* var1 = nullptr, * var2 = nullptr;
    if (is_forall(q) && m.is_or(n, arg1, arg2)) {
        if (m.is_not(arg2)) 
            std::swap(arg1, arg2);
        if (m.is_not(arg1, narg) && 
            m.is_eq(narg, app1, app2) && 
            m.is_eq(arg2, var1, var2)) {
            if (is_app(app1) &&
                is_app(app2) && 
                to_app(app1)->get_decl() == to_app(app2)->get_decl() &&
                to_app(app1)->get_num_args() == to_app(app2)->get_num_args() &&
                to_app(app1)->get_family_id() == null_family_id &&
                to_app(app1)->get_num_args() > 0 &&
                is_var(var1) && 
                is_var(var2) && 
                var1 != var2) {
                app * f1          = to_app(app1);
                app * f2          = to_app(app2);
                bool found_vars   = false;
                unsigned num      = f1->get_num_args();
                unsigned idx      = UINT_MAX;
                unsigned num_vars = 1;
                for (unsigned i = 0; i < num; i++) {
                    expr  * c1 = f1->get_arg(i);
                    expr  * c2 = f2->get_arg(i);
                    if (!is_var(c1) && !is_uninterp_const(c1))
                        return false;
                    if ((c1 == var1 && c2 == var2) || (c1 == var2 && c2 == var1)) {
                        if (found_vars)
                            return false;
                        found_vars = true;
                        idx = i;
                    }
                    else if (c1 == c2 && c1 != var1 && c1 != var2) {
                        if (is_var(c1)) {
                            ++num_vars;
                        }
                    }
                    else {
                        return false;
                    }
                }
                if (found_vars && !has_free_vars(q)) {
                    TRACE("inj_axiom", 
                          tout << "Cadidate for simplification:\n" << mk_ll_pp(q, m) << mk_pp(app1, m) << "\n" << mk_pp(app2, m) << "\n" <<
                          mk_pp(var1, m) << "\n" << mk_pp(var2, m) << "\nnum_vars: " << num_vars << "\n";);
                    // Building new (optimized) axiom
                    func_decl * decl      = f1->get_decl();
                    unsigned var_idx      = 0;
                    ptr_buffer<expr> f_args, inv_vars;
                    ptr_buffer<sort> decls;
                    buffer<symbol>   names;
                    
                    expr * var            = nullptr;
                    for (unsigned i = 0; i < num; i++) {
                        expr * c = f1->get_arg(i);
                        if (is_var(c)) {
                            names.push_back(symbol(i));
                            sort * s = decl->get_domain(i);
                            decls.push_back(s);
                            expr * new_c = m.mk_var(var_idx, s);
                            var_idx++;
                            f_args.push_back(new_c);
                            if (i == idx) {
                                var = new_c;
                            }
                            else {
                                inv_vars.push_back(new_c);
                            }
                        }
                        else {
                            SASSERT(is_uninterp_const(c));
                            f_args.push_back(c);
                        }
                    }
                    SASSERT(var != 0);
                    app * f    = m.mk_app(decl, f_args.size(), f_args.c_ptr());

                    ptr_vector<sort>  domain;
                    inv_vars.push_back(f);
                    for (unsigned i = 0; i < inv_vars.size(); ++i) {
                        domain.push_back(m.get_sort(inv_vars[i]));
                    }
                    sort * d              = decl->get_domain(idx);
                    func_decl * inv_decl  = m.mk_fresh_func_decl("inj", domain.size(), domain.c_ptr(), d);
                    
                    expr * proj = m.mk_app(inv_decl, inv_vars.size(), inv_vars.c_ptr());
                    expr * eq   = m.mk_eq(proj, var);
                    expr * p    = m.mk_pattern(f);
                    
                    // decls are in the wrong order...
                    // Remark: the sort of the var 0 must be in the last position.
                    std::reverse(decls.begin(), decls.end());
                    
                    result = m.mk_forall(decls.size(), decls.c_ptr(), names.c_ptr(), eq,
                                         0, symbol(), symbol(), 1, &p);
                    TRACE("inj_axiom", tout << "new axiom:\n" << mk_pp(result, m) << "\n";);
                    SASSERT(is_well_sorted(m, result));
                    return true;
                }
void pull_quant::pull_quant1(func_decl * d, unsigned num_children, expr * const * children, expr_ref & result) {
    ptr_buffer<sort>  var_sorts;
    buffer<symbol>    var_names;
    symbol            qid;
    int               w = INT_MAX;

    // The input formula is in Skolem normal form...
    // So all children are forall (positive context) or exists (negative context).
    // Remark: (AND a1 ...) may be represented (NOT (OR (NOT a1) ...)))
    // So, when pulling a quantifier over a NOT, it becomes an exists.
    
    if (m_manager.is_not(d)) {
        SASSERT(num_children == 1);
        expr * child = children[0];
        if (is_quantifier(child)) {
            quantifier * q = to_quantifier(child);
            expr * body = q->get_expr();
            result = m_manager.update_quantifier(q, !q->is_forall(), m_manager.mk_not(body));
        }
        else {
            result = m_manager.mk_not(child);
        }
        return;
    }

    bool found_quantifier = false;
    bool forall_children;

    for (unsigned i = 0; i < num_children; i++) {
        expr * child = children[i];
        if (is_quantifier(child)) {
            
            if (!found_quantifier) {
                found_quantifier = true;
                forall_children  = is_forall(child);
            }
            else {
                // Since the initial formula was in SNF, all children must be EXISTS or FORALL.
                SASSERT(forall_children == is_forall(child));
            }
            
            quantifier * nested_q = to_quantifier(child);
            if (var_sorts.empty()) {
                // use the qid of one of the nested quantifiers.
                qid = nested_q->get_qid();
            }
            w = std::min(w, nested_q->get_weight());
            unsigned j = nested_q->get_num_decls();
            while (j > 0) {
                --j;
                var_sorts.push_back(nested_q->get_decl_sort(j));
                symbol s = nested_q->get_decl_name(j);
                if (std::find(var_names.begin(), var_names.end(), s) != var_names.end())
                    var_names.push_back(m_manager.mk_fresh_var_name(s.is_numerical() ? 0 : s.bare_str()));
                else
                    var_names.push_back(s);
            }
        }
    }

    if (!var_sorts.empty()) {
        SASSERT(found_quantifier);
        // adjust the variable ids in formulas in new_children
        expr_ref_buffer   new_adjusted_children(m_manager);
        expr_ref          adjusted_child(m_manager);
        unsigned          num_decls = var_sorts.size();
        unsigned          shift_amount = 0;
        TRACE("pull_quant", tout << "Result num decls:" << num_decls << "\n";);