0

I need to use Z3_parse_smtlib2_string to parse some SMTLIB strings into Z3 using the C++ API, and the use the Z3 C++ API to find the unsat core of this.

I know that there are other ways to find the unsat core as described here and here that are easier and less cumbersome, but I really want to be able to do this using only data structures parsed from strings to Z3. The reason is that I am trying to automate something using Z3.

It is obvious that if I passed this SMTLIB program into Z3, it is UNSAT.

(declare-const p0 Bool)
(assert(= p0 true)) (assert(= p0 false))
(assert (exists ((x Int)) (= 3 x)))

What I want to do, is to be able to get the unsat core programmatically using Z3. What I did was to read each of those lines separately into Z3 and give them a name using solver.add(expr, name), using the program below.

void my_test() {
    context c1;
    solver s(c1);

    std::string declare = "(declare-const p0 Bool)";
    std::string testing = "(assert(= p0 true)) (assert(= p0 false))";
    std::string obvious = "(assert (exists ((x Int)) (= 3 x)))";

    Z3_ast parsed1 = Z3_parse_smtlib2_string(c1, declare.c_str(), 0,0,0,0,0,0);
    expr e1(c1, parsed1);

    Z3_ast parsed2 = Z3_parse_smtlib2_string(c1, testing.c_str(), 0,0,0,0,0,0);
    expr e2(c1, parsed2);
    std::cout << "what: " << e2 << std::endl;

    Z3_ast parsed3 = Z3_parse_smtlib2_string(c1, obvious.c_str(), 0,0,0,0,0,0);
    expr e3(c1, parsed3);

    s.add(e1, "declare");
    s.add(e2, "testing");
    s.add(e3, "obvious");

    if (s.check() == z3::sat) {
        std::cout << "SAT!\n";
        model m = s.get_model();
        std::cout << m << std::endl;
    } else {
        std::cout << "UNSAT!\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";
        }
    }
}

I expect to get the unsat core to be just declare, since that is clearly false, while the other expressions are clearly valid. However, Z3 gives me this response:

(error "line 1 column 11: unknown constant p0")
(error "line 1 column 31: unknown constant p0")
what: true
SAT!
(define-fun testing () Bool
  true)
(define-fun declare () Bool
  true)
(define-fun obvious () Bool
  true)

Which is clearly wrong, since declare, which references (assert(= p0 true)) (assert(= p0 false)), is SAT! Obviously this should be UNSAT. Also, I do in fact declare p0, but Z3 doesn't seem to know that I declared it already.

Any ideas what I'm doing wrong?

Community
  • 1
  • 1
ndb
  • 127
  • 1
  • 10

1 Answers1

1

The second call to Z3_parse_smtlib2_string does not know about the declaration in the first call:

Z3_ast parsed2 = Z3_parse_smtlib2_string(c1, testing.c_str(), 0,0,0,0,0,0);

The bunch of zero's in the end means "do not assume anything else", so it doesn't know that p0 exists. For more details see the Z3_parse_smtlib2_string in the API documentation; in your case you want to pass a non-empty decls.

Christoph Wintersteiger
  • 8,234
  • 1
  • 16
  • 30