I'm trying to represent sum of integers from an integer a to an integer b of the form
\sum_{i=a}^b i
Of courese there is a closed form solution for this version, but in general I'd like to sum over expressions parameterized by i. I've currently tried to define a function symSum and described its behavior using universal quantifiers:
from z3 import *
s = Solver()
symSum = Function('symSum', IntSort(), IntSort(), IntSort())
a = Int('a')
b = Int('b')
s.add(ForAll([a,b],If(a > b,symSum(a,b) == 0,symSum(a,b) == a + symSum(a+1,b))))
x = Int('x')
s.add(x == symSum(1,5))
print(s.check())
print(s.model())
I have not gotten this code to terminate (I have only allowed it to run for a couple minutes at max though). Is this outside the capabilities of Z3?
EDIT:
Looking into this a bit more I was able to use recursive functions to define this!
from z3 import *
ctx = Context()
symSum = RecFunction('symSum', IntSort(ctx), IntSort(ctx), IntSort(ctx))
a = Int('a',ctx)
b = Int('b',ctx)
RecAddDefinition(symSum, [a,b], If(a > b, 0, a + symSum(a+1,b)))
x = Int('x',ctx)
s = Solver(ctx=ctx)
s.add(symSum(1,5) == x)
print(s.check())
print(s.model())
Yes; this is beyond the current capabilities of SMT solvers.
Imagine how you'd prove something like this by hand. You'd have to do induction on the natural numbers. SMT solvers do not perform induction, at least not out-of-the box. You can coax them to do so with a lot of helper lemmas and careful guiding via what's known as patterns; but it's not something they're designed for, or even good at. At least not for the time being.
See this answer for more details regarding a relevant question: Is it possible to prove this defined function is an involution in z3?
Having said that, recent versions of SMTLib does include capabilities for definitions recursive functions. (See https://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.6-r2017-07-18.pdf, Section 4.2.3.) And z3 and other solvers have some support for the new syntax, though they can't really prove any interesting properties of these functions. I suspect the direction of the community is that eventually some level of (user-guided) induction will become part of the toolbox offered by these solvers, but that is currently not the case for the time being.
Related
Consider these two formulae:
Exists y. Forall x. (y>x), which is unsat.
Forall x. Exists y. (y>x), which is sat.
Note that we cannot find “models” for the sat formula, e.g., using Z3 it outputs Z3Exception: model is not available for the following code:
phi = ForAll([x],Exists([y], lit))
s_def = Solver()
s_def.add(phi)
print(s_def.model())
Also, quantifier elimination does not output an elimination, but a satisfiability result
[[]] (i.e., True):
x, y = Reals('x, y')
t = Tactic("qe")
lit = (y>x)
ae = Goal()
ae.add(ForAll([x],Exists([y], lit)))
ae_qe = t(ae)
print(ae_qe)
I think this happens because the value of y fully depends on x (e.g., if x is 5 then y can be 6). Thus, I have some questions:
Am I right with this interpretation?
What would be the meaning of “a model of a universally quantified formula”?
Do we say a formula accepts quantifier elimination even if it never eliminates the quantifier but "only: evaluate to True or False?
Is there a way to synthetise or construct a model/function that represents a y that holds the constraint (y>x); e.g. f(x)=x+1. In other words, does it make sense that the quantifier elimination of a Forall x. Exists y. Phi(x,y) like the example would be Forall x. Phi(x,f(x))?
You get a model-not-available, because you didn't call check. A model is only available after a call to check. Try this:
from z3 import *
x, y = Ints('x y')
phi = ForAll([x], Exists([y], y > x))
s = Solver()
s.add(phi)
print(s.check())
print(s.model())
This prints:
sat
[]
Now, you're correct that you won't get a meaningful/helpful model when you have a universal-quantifier; because the model will depend on the choice of x in each case. (You only get values for top-level existentials.) This is why the model is printed as the empty-list.
Side Note In certain cases, you can use the skolemization trick (https://en.wikipedia.org/wiki/Skolem_normal_form) to get rid of the nested existential and get a mapping function, but this doesn't always work with SMT solvers as they can only build "finite" skolem functions. (For your example, there isn't such a finite function; i.e., a function that can be written as a case-analysis on the inputs, or an if-then-else chain.)
For your specific questions:
Yes; value of y depends on x and thus cannot be displayed as is. Sometimes skolemization will let you work around this, but SMT solvers can only build finite skolem-functions.
Model of a universally quantified formula is more or less meaningless. It's true for all values of the universally quantified variables. Only top-level existentials are meaningful in a model.
Quantifier elimination did work here; it got rid of the whole formula. Note that QE preserves satisfiability; so it has done its job.
This is the skolem function. As you noted, this skolem function is not finite (can't be written as a chain of finite if-then-elses on concrete values), and thus existing SMT solvers cannot find/print them for you. If you try, you'll see that the solver simply loops:
from z3 import *
x = Int('x')
skolem = Function('skolem', IntSort(), IntSort())
phi = ForAll([x], skolem(x) > x)
s = Solver()
s.add(phi)
print(s)
print(s.check())
print(s.model())
The above never terminates, unfortunately. This sort of problem is simply too complicated for the push-button approach of SMT solving.
Context: I'm using the Programming Z3 guide:
https://theory.stanford.edu/~nikolaj/programmingz3.html
It looks like Z3 now has built-in support for transitive-closure, but for the moment it's only accessible via Z3py:
https://theory.stanford.edu/~nikolaj/programmingz3.html#sec-transitive-closure
I have two questions:
(1) Is there any means of accessing TransitiveClosure via other APIs or the executable directly via "z3 -in", or is it just for Z3py at the moment?
(2) Is TransitiveClosure supposed to interoperate with push and pop? We built from the master branch earlier this week (commit 2788f72bbb6bfd6bdad2da2b4c37ef1bb502469d) and ran the following example:
from z3 import *
B = BoolSort()
S = DeclareSort('S')
a, b, c = Consts('a b c', S)
R = Function('R', S, S, B)
TCR = TransitiveClosure(R)
s = Solver()
s.add(R(a, b) == True)
s.push() # If this line is uncommented (or both are) the result is sat, which is wrong.
s.add(TCR(a, b) == False)
s.push() # But if THIS line is uncommented (or neither are), the result is unsat, which is correct.
print(s)
print(s.check())
As the comments indicate, a push() call between assertions about R and its transitive closure seem to break the link between the two relations. Not sure if this is a bug, or my own misunderstanding...
From the looks of it, it's also available via the C/C++ api as well:
https://github.com/Z3Prover/z3/blob/62de187d02d8d2e7a3667a31753c508f7c73aaa1/src/api/c%2B%2B/z3%2B%2B.h#L637-L639
I don't think it's available from the SMTLib interface (what you meant by z3 -in I presume), as it's itself returning a relation; and such higher-order constructs are usually not allowed in SMTLib. (But there might be a "magic" switch, of course; z3 is known to experiment with functionality that's not part of SMTLib.)
Regarding whether it should work with push/pop: I don't think the fixed-point engine in z3 allows for incremental solving; so I'm not surprised that it's behaving erratically. You should definitely report this behaviour at their issues site (https://github.com/Z3Prover/z3/issues) so they can at least issue an error message if you try to do incremental stuff, instead of spitting out misleading info. (Or maybe you hit a bug! So, that'd also be good for them to know.)
s.pop(),s.push() is not necessary.
# https://theory.stanford.edu/~nikolaj/programmingz3.html#sec-transitive-closure
from z3 import *
B = BoolSort()
S = DeclareSort('S')
R = Function('R', S, S, B)
TCR = TransitiveClosure(R)
a, b, c = Consts('a b c', S)
s = Solver()
s.add(R(a, b))
s.add(R(b, c))
s.add(Not(TCR(a, c))) # s.add(Not(R(a, c))) will be “sat”,because TCR is transitiveclosure but R is not.
print(s)
print(s.check()) # unsat
The Z3 input format is an extension of the one defined by SMT-LIB 2.0 standard. The input expressions need to write in prefix form. As for example rise4fun,
x + (y * 2) = 20 needs to be given input in the form of " (= (+ x (* 2 y)) 20)) ".
Z3 supports JAVA API. As for example, let us consider the below code which evaluates and checks satisfiability expressions: x+y = 500 and x + (y * 2) = 20.
final Context ctx = new Context();
final Solver solver = ctx.mkSimpleSolver();
IntExpr x = ctx.mkIntConst("x");
IntExpr y = ctx.mkIntConst("y");
IntExpr th = ctx.mkInt(500);
IntExpr th1 = ctx.mkInt(2);
IntExpr th2 = ctx.mkInt(20);
BoolExpr t1 = ctx.mkEq(ctx.mkAdd(x,y), th);
BoolExpr t2 = ctx.mkEq(ctx.mkAdd(x,ctx.mkMul(th1, y)), th2);
solver.add(t1);
solver.add(t2);
solver.check()
The problem is if an external user wants to give input to the solver, he cannot give it in the form of the general formula as " x+y = 500, x + (y * 2) = 20 ".
The input needs to be parsed and then should be written manually using JAVA API in prefix form (Note BoolExpr t2 in above code) to give the final expressions to Solver.
Is there any parser/library/API (Preferably JAVA or in any other language) which parses the general expressions with arithmetic operators(+, -, <, >, =), propositional logic connectors (And, OR), Quantifiers(ForAll, Exists) and then gives input to the Z3 Solvers ?
Please suggest and help.
This is precisely why people build high-level interfaces to SMT solvers. There are many choices here for z3:
Official Python interface to z3: https://ericpony.github.io/z3py-tutorial/guide-examples.htm This is supported by Microsoft directly, and is probably the easiest to use.
PySMT, which aims to cover as many SMT solvers as they can: https://github.com/pysmt/pysmt
Scala bindings: https://github.com/epfl-lara/ScalaZ3
Haskell SBV: http://hackage.haskell.org/package/sbv
Many others at various maturity levels for Racket, Go, Lisp.. You name it. You can find many of them on github.
The goal of these "wrappers" is to precisely save the end-user from all the details of intricate bindings, and provide something much easier and less-error prone to use. On the flip side, they require you to learn yet another library. In my experience, if the host language of your choice has such an implementation, it'd pay off nicely to use it. If not, you should build one!
I have the following questions:
A. If I have a variable x which I declare it (case 1) to be Bool (case 2) to be Int and assert x=0 or x=1 (case 3) to be Int and assert 0<=x<=1. What happens in Z3, or more generally in SMT, in each of the cases? Is, (case 1) desired since things happen at SAT and not SMT level? Do you have some reference paper here?
B. I have the following statement in Python (for using Z3 Python API)
tmp.append(sum([self.a[i * self.nrVM + k] * componentsRequirements[i][1] for i
in range(self.nrComp)]) <= self.MemProv[k])
where a is declared as a Z3 Int variable (0 or 1), componentsRequirements is a Python variable which is to be considered float, self.MemProv is declared as a Z3 Real variable.
The strange thing is that for float values for componentsRequirements, e.g 0.5, the constraint built by the solver considers it 0 and not 0.5. For example in:
(assert (<= (to_real (+ 0 (* 0 C1_VM2)
(* 0 C2_VM2)
(* 2 C3_VM2)
(* 2 C4_VM2)
(* 3 C5_VM2)
(* 1 C6_VM2)
(* 0 C7_VM2)
(* 2 C8_VM2)
(* 1 C9_VM2)
(* 2 C10_VM2)))
StorageProv2))
the 0 above should be actually 0.5. When changing a to a Real value then floats are considered, but this is admitted by us because of the semantics of a. I tried to use commutativity between a and componentsRequirements but with no success.
C. If I'd like to use x as type Bool and multiply it by an Int, I get, of course, an error (Bool*Real/Int not allowed), in Z3. Is there a way to overcome this problem but keeping the types of both multipliers? An example in this sense is the above (a - Bool, componentsRequirements - Real/Int):
a[i * self.nrVM + k] * componentsRequirements[i][1]
Thanks
Regarding A
Patrick gave a nice explanation for this one. In practice, you really have to try and see what happens. Different problems might exhibit different behavior due to when/how heuristics kick in. I don't think there's a general rule of thumb here. My personal preference would be to keep booleans as booleans and convert as necessary, but that's mostly from a programming/maintenance perspective, not an efficiency one.
Regarding B
Your "division" getting truncated problem is most likely the same as this: Retrieve a value in Z3Py yields unexpected result
You can either be explicit and write 1.0/2.0 etc.; or use:
from __future__ import division
at the top of your program.
Regarding C
SMTLib is a strongly typed language; you cannot multiply by a bool. You have to convert it to a number first. Something like (* (ite b 1 0) x), where b is your boolean. Or you can write a custom function that does this for you and call that instead; something like:
(define-fun mul_bool_int ((b Bool) (i Int)) Int (ite b i 0))
(assert (= 0 (mul_bool_int false 5)))
(assert (= 5 (mul_bool_int true 5)))
I honestly can't answer for z3 specifically, but I want to state my opinion on point A).
In general, the constraint x=0 v x=1 is abstracted into t1 v t2, where t1 is x=0 and t2 is x=1, at the SAT engine level.
Thus, the SAT engine might try to assign both t1 and t2 to true during the construction of a satisfiable truth assignment for the input formula. It is important to note that this is a contradiction in the theory of LAR, but the SAT engine is not capable of such reasoning. Therefore, the SAT engine might continue its search for a while after taking this decision.
When the LAR Solver is finally invoked, it will detect the LAR-unsatisfiability of the given (possibly partial) truth assignment. As a consequence, it (should) hand the clause not t1 or not t2 to the SAT engine as learning clause so as to block the bad assignment of values to be generated again.
If there are many of such bad assignments, it might require multiple calls to the LAR Solver so as to generate all blocking clauses that are needed to rectify the SAT truth assignment, possibly up to one for each of those bad combinations.
Upon receiving the conflict clause, the SAT engine will have to backjump to the place where it made the bad assignment and do the right decision. Obviously, not all the work done by the SAT engine since it made the bad assignment of values gets wasted: any useful clause that was learned in the meanwhile will certainly be re-used. However, this can still result in a noticeable performance hit on some formulas.
Compare all of this back-and-forth computation being wasted with simply declaring x as a Bool: now the SAT engine knows that it can only assign one of two values to it, and won't ever assign x and not x contemporarily.
In this specific situation, one might mitigate this problem by providing the necessary blocking clauses right into the input formula. However, it is not trivial to conclude that this is always the best practice: explicitly listing all known blocking clauses might result in an explosion of the formula size in some situations, and into an even worse degradation of performance in practice. The best advice is to try different approaches and perform an experimental evaluation before settling for any particular encoding of a problem.
Disclaimer: it is possible that some SMT solvers are smarter than others, and automatically generate appropriate blocking clauses for 0/1 variables upon parsing the formula or avoid this situation altogether through other means (i.e. afaik, Model-Based SMT solvers shouldn't incur in the same problem)
I'm seeing rather surprising behavior from ctx-solver-simplify, where the order of parameters to z3.And() seems to matter, using the latest version of Z3 from the master branch of https://git01.codeplex.com/z3 (89c1785b):
#!/usr/bin/python
import z3
a, b = z3.Bools('a b')
p = z3.Not(a)
q = z3.Or(a, b)
for e in z3.And(p, q), z3.And(q, p):
print e, '->', z3.Tactic('ctx-solver-simplify')(e)
produces:
And(Not(a), Or(a, b)) -> [[Not(a), Or(a, b)]]
And(Or(a, b), Not(a)) -> [[b, Not(a)]]
Is this a bug in Z3?
No, this is not a bug. The tactic ctx-solver-simplify is very expensive and inherently asymmetric. That is, the order the sub-formulas are visited affect the final result. This tactic is implemented in the file src/smt/tactic/ctx_solver_simplify_tactic.cpp. The code is quite readable. Note that, it uses a "SMT" solver (m_solver), and makes several calls to m_solver.check() while traversing the input formula. Each one of these calls can be quite expensive. For particular problem domains, we can implement a version of this tactic that is even more expensive, and avoids the asymmetry described in your question.
EDIT:
You may also consider the tactic ctx-simplify, it is cheaper than ctx-solver-simplify, but it is symmetric. The tactic ctx-simplify will essentially applies rules such as:
A \/ F[A] ==> A \/ F[false]
x != c \/ F[x] ==> F[c]
Where F[A] is a formula that may contain A. It is cheaper than ctx-solver-simplify because it does not invoke a SMT solver when it is traversing the formula. Here is an example using this tactic (also available online):
a, b = Bools('a b')
p = Not(a)
q = Or(a, b)
c = Bool('c')
t = Then('simplify', 'propagate-values', 'ctx-simplify')
for e in Or(c, And(p, q)), Or(c, And(q, p)):
print e, '->', t(e)
Regarding humand-readability, this was never a goal when implementing any tactic. Please, tell us if the tactic above is not good enough for your purposes.
I think it will be better to write a custom tactic because there are
other tradeoffs when you essentially ask for canonicity.
Z3 does not have any tactics that convert formulas into a canonical form.
So if you want something that always produces the same answer for formulas
that are ground equivalent you will have to write a new normalizer that
ensures this.
The ctx_solver_simplify_tactic furthermore makes some tradeoffs when simplifying formulas:
it avoids simplifying the same sub-formula multiple times. If it did, it could increase
the size of the resulting formula significantly (exponentially).