How to use z3 split clauses of unsat cores & try to find out unsat core again

后端 未结 1 1012
囚心锁ツ
囚心锁ツ 2021-01-24 12:22

Could you like to tell how to split clauses of unsat cores? And here is question 2 regarding after found out unsat cores, I will try to seek again. Would you like to tell how to

1条回答
  •  一生所求
    2021-01-24 13:01

    I'm not sure if I understood your question. It seems you have an assertion of the form (and c1 (and c2 c3)), and you want to track c1, c2 and c3 individually.

    In Z3, we use answer literals to track assertions. An answer literal is essentially a fresh Boolean that is used to track an assertion. That is, whether the assertion was used (by Z3) to show unsatisfiability of the whole set of assertions or not. For example, if we want to track assertion F, we create a fresh Boolean variable p and assert p implies F. Then, we provide p as an argument for the check method.

    If F is a big conjunction and we want to track its elements individually, we should extract its elements and create an answer literal for each one of them. Here is the complete example that does the trick. You can test it by including it in the example.cpp file that is included in the Z3 distribution. Note that you have to include #include.

    /**
       \brief Unsat core example 2
    */
    void unsat_core_example2() {
        std::cout << "unsat core example 2\n";
        context c;
        // The answer literal mechanism, described in the previous example,
        // tracks assertions. An assertion can be a complicated
        // formula containing containing the conjunction of many subformulas.
        expr p1 = c.bool_const("p1");
        expr x  = c.int_const("x");
        expr y  = c.int_const("y");
        solver s(c);
        expr F  = x > 10 && y > x && y < 5 && y > 0;
        s.add(implies(p1, F));
        expr assumptions[1] = { p1 };
        std::cout << s.check(1, assumptions) << "\n";
        expr_vector core = s.unsat_core();
        std::cout << core << "\n";
        std::cout << "size: " << core.size() << "\n";
        for (unsigned i = 0; i < core.size(); i++) {
            std::cout << core[i] << "\n";
        }
        // The core is not very informative, since p1 is tracking the formula F
        // that is a conjunction of subformulas.
        // Now, we use the following piece of code to break this conjunction
        // into individual subformulas. First, we flat the conjunctions by
        // using the method simplify.
        std::vector qs; // auxiliary vector used to store new answer literals.
        assert(F.is_app()); // I'm assuming F is an application.
        if (F.decl().decl_kind() == Z3_OP_AND) {
            // F is a conjunction
            std::cout << "F num. args (before simplify): " << F.num_args() << "\n";
            F = F.simplify();
            std::cout << "F num. args (after simplify):  " << F.num_args() << "\n";
            for (unsigned i = 0; i < F.num_args(); i++) {
                std::cout << "Creating answer literal q" << i << " for " << F.arg(i) << "\n";
                std::stringstream qname; qname << "q" << i;
                expr qi = c.bool_const(qname.str().c_str()); // create a new answer literal
                s.add(implies(qi, F.arg(i)));
                qs.push_back(qi);
            }
        }
        // The solver s already contains p1 => F
        // To disable F, we add (not p1) as an additional assumption
        qs.push_back(!p1);
        std::cout << s.check(qs.size(), &qs[0]) << "\n";
        expr_vector core2 = s.unsat_core();
        std::cout << core2 << "\n";
        std::cout << "size: " << core2.size() << "\n";
        for (unsigned i = 0; i < core2.size(); i++) {
            std::cout << core2[i] << "\n";
        }
    }
    

    0 讨论(0)
提交回复
热议问题