问题
I am new to Z3 but have some prior experience using Prolog.
I have managed to solve the following "puzzle", i.e. to prove that the girl is a witch using Prolog, but am at a loss how to implement it in Z3 (in C++ or Python): https://www.netfunny.com/rhf/jokes/90q4/burnher.html
Do I need to declare Function() for assertions like
BURNS(x) /\ WOMAN(x)
and WOMAN(GIRL)
What about implications of the sort \forall x, ISMADEOFWOOD(x) => BURNS(x)
?
Any tips are appreciated
回答1:
It should be pointed out that SMT solvers (i.e., Z3) aren't usually good at reasoning with quantifiers in general, but this particular case is easy enough that it can handle without a sweat. (It's easy because all you have are uninterpreted sorts and booleans; there are no integers, reals, datatypes etc., to complicate the logic.) Also, there are some modeling differences when you use an SMT solver compared to Prolog's deduction strategy, so the modeling will be a bit different.
The crucial point is that Prolog uses the so-called closed-world-assumption viewpoint. That is, if it cannot show an implication, it'll decide that it isn't implied. An SMT solver does not do that: It will prove implications; but if you query a variable that isn't properly constrained (i.e., if it can be both True
or False
according to the assertions), then it's free to pick any interpretation. So, the modeling has to take that into account.
What does that mean for the current problem? We have to prove that the statements imply the girl is a witch. If they don't, we don't know whether she is or not. To do so, we assert the negation of the conclusion we want and check if the resulting system is unsatisfiable. If that's the case, then we can conclude our conclusion must be valid. If the result is satisfiable, then we have a counter-example model that we can investigate further. In this case, it'll mean there is insufficient evidence that the girl is a witch. (Note that adding the negation of the conclusion we want to prove is very typical of resolution proofs, and we're following the same strategy here.)
Given all this, here's how I would go about modeling it using the Python API, you should be able to translate this to C++ (or any other language with proper bindings) with relative ease. The clauses almost translate literally:
from z3 import *
Thing = DeclareSort('Thing')
GIRL = Const('GIRL', Thing)
DUCK = Const('DUCK', Thing)
BURNS = Function('BURNS', Thing, BoolSort())
FLOATS = Function('FLOATS', Thing, BoolSort())
WOMAN = Function('WOMAN', Thing, BoolSort())
WITCH = Function('WITCH', Thing, BoolSort())
SAMEWEIGHT = Function('SAMEWEIGHT', Thing, Thing, BoolSort())
ISMADEOFWOOD = Function('ISMADEOFWOOD', Thing, BoolSort())
s = Solver()
x = Const('x', Thing)
y = Const('y', Thing)
s.add(ForAll([x], Implies(And(BURNS(x), WOMAN(x)), WITCH(x))))
s.add(WOMAN(GIRL))
s.add(ForAll([x], Implies(ISMADEOFWOOD(x), BURNS(x))))
s.add(ForAll([x], Implies(FLOATS(x), ISMADEOFWOOD(x))))
s.add(FLOATS(DUCK))
s.add(ForAll([x, y], Implies(And(FLOATS(x), SAMEWEIGHT(x, y)), FLOATS(y))))
s.add(SAMEWEIGHT(DUCK, GIRL))
# To prove the girl is a witch, we assert the negation,
# and check if it is unsatisfiable.
s.add(Not(WITCH(GIRL)))
res = s.check()
if res == sat:
print("Nope, it doesn't follow that she's a witch!")
elif res == unsat:
print("Yes, she is a witch!")
else:
print("Hmm, solver said: ", res)
When I run this, I get:
Yes, she is a witch!
Too bad for her!
You can experiment by commenting out some of the assertions, and you'll see that z3 will say the system is sat
, i.e., it cannot conclude the girl is a witch. You can then look at the model itself in detail to find out what the assignments are.
You can read through https://ericpony.github.io/z3py-tutorial/advanced-examples.htm to see how to use basic Python API for uninterpreted sorts, quantifiers, and basic modeling. If you've specific questions, feel free to ask further..
来源:https://stackoverflow.com/questions/62720552/using-resolution-theorem-proving-with-z3