Wherefore?
The usecase context in which my problem occures
I define 3 random item of a triangle. Microsoft Z3 should output:
Are the constraints satisfiabe or are there invalid input values?
A model for all the other triangle items where all the variables are assigned to concrete values.
In order to constrain the items i need to assert triangle equalities - i wanted to start out with the Pythagorean Theorem ((h_c² + p² = b²) ^ (h_c² + q² = a²)).
The Problem
I know that Microsoft Z3 has only limited capabilities to solve non-linear arithematic problems. But even some hand calculators are able to solve a very simplified version like this:
(set-option :print-success true)
(set-option :produce-proofs true)
(declare-const a Real)
(declare-const b Real)
(assert (= a 1.0))
(assert (= b 1.0))
(assert
(exists
((c Real))
(=
(+
(* a a)
(* b b)
)
(* c c)
)
)
)
(check-sat)
(get-model)
The Question
Is there a way to get Microsoft Z3 to solve the Pythagorean Theorem if two values are given?
Or: Is there another theorem prover which is able to handle these case of non-linear arithmetic?
Thanks for your help concerning that - If anything is unclear, please comment.
Z3 has a new solver (nlsat) for nonlinear arithmetic. It is more efficient than other solvers (see this article). The new solver is complete for quantifier-free problems.
However, the new solver does not support proof generation. If we disable proof generation, then Z3 will use nlsat and easily solve the problem. Based on your question, it seems you are really looking for solutions, thus disabling proof generation does not seem to be an issue.
Moreover, Z3 does not produce approximate solutions (like hand calculators).
It uses a precise representation for real algebraic numbers.
We can also ask Z3 to display the result in decimal notation (option :pp-decimal).
Here is your example online.
In this example, when precise representation is used, Z3 will display the following result for c.
(root-obj (+ (^ x 2) (- 2)) 1)
It is saying that c is the first root of the polynomial x^2 - 2.
When we use (set-option :pp-decimal true), it will display
(- 1.4142135623?)
The question mark is used to indicate the result is truncated.
Note that, the result is negative. However, it is indeed a solution for the problem you posted.
Since, you are looking for triangles, you should assert that the constants are all > 0.
BTW, you do not need the existential quantifier. We can simply use a constant c.
Here is an example (also available online at rise4fun):
(set-option :pp-decimal true)
(declare-const a Real)
(declare-const b Real)
(declare-const c Real)
(assert (= a 1.0))
(assert (= b 1.0))
(assert (> c 0))
(assert (= (+ (* a a) (* b b)) (* c c)))
(check-sat)
(get-model)
Here is another example that does not have a solution (also available online at rise4fun):
(set-option :pp-decimal true)
(declare-const a Real)
(declare-const b Real)
(declare-const c Real)
(assert (> c 0))
(assert (> a c))
(assert (= (+ (* a a) (* b b)) (* c c)))
(check-sat)
BTW, you should consider the Python interface for Z3. It is much more user friendly. The tutorial that I linked has examples in Kinematics. They also use nonlinear arithmetic to encode simple high-school physics problems.
Related
I want to solve this in the z3 solver with bit vector 48:
(declare-fun x () Int)
(declare-fun y () Int)
(assert (= *someNumber* (* x y)))
(assert (> x 1))
(assert (> y 1))
(check-sat)
(get-model)
(exit)
I'm trying to figure out how to use the arithmetic function however, it does not work out very well.
The problems with that (for me) are the correct Syntax of the functions && how to set the values in there.
(set-option :produce-models true)
(set-logic QF_BV)
;; Declaring all the variables
(declare-const a (_ BitVec 48))
(declare-const b (_ BitVec 48))
(declare-const c (_ BitVec 48))
;; Soft constraints to limit reuse
(assert (= c #xnumberInHex))
(assert-soft (not (= a b)))
(check-sat-using (then simplify solve-eqs bit-blast sat))
(simplify (= c (bvmul a b))
(simplify (bvugt a #b000000000001))
(simplify (bvugt b #b000000000001))
(check-sat)
(get-model)
Any help is much appreciated.
Syntax / how to write the correct bit vector there
Looks like you've got almost all the pieces in there, but perhaps not exactly getting the syntax right. Here's a complete encoding with c = 18:
(set-option :produce-models true)
(set-logic ALL)
;; Declaring all the variables
(declare-const a (_ BitVec 48))
(declare-const b (_ BitVec 48))
(declare-const c (_ BitVec 48))
(assert (= c #x000000000012)) ; 18 is 0x12 in hex
(assert (= c (bvmul a b)))
; don't allow overflow
(assert (bvumul_noovfl a b))
(assert (bvult #x000000000001 a))
(assert (bvult #x000000000001 b))
;; Soft constraints to limit reuse
(assert-soft (not (= a b)))
(check-sat)
(get-model)
Note the use of the ALL logic and the function bvumul_noovfl which detects unsigned bit-vector multiplication overflow. (This function is z3 specific, and is only available when you pick the logic to be ALL.) Since you're doing bit-vector arithmetic, it is subject to wrap-around, and I'm guessing this is something you'd like to avoid. By explicitly stating we do not want the multiplication of a and b to overflow, we're achieving that goal.
For this input, z3 says:
sat
(model
(define-fun b () (_ BitVec 48)
#x000000000009)
(define-fun a () (_ BitVec 48)
#x000000000002)
(define-fun c () (_ BitVec 48)
#x000000000012)
)
which correctly factors the number 18 (written here in hexadecimal as 12) into 2 and 9.
Note that multiplication is a hard problem. As you increase the bit-size (here you picked 48, but could be larger), or if the number c itself gets larger, the problem will become harder and harder for z3 to solve. This is, of course, not surprising: Factorization is a hard problem in general, and there's no magic here for z3 to correctly factor your input value without solving a huge set of internal equations, which increase exponentially in size as the bit-width increases.
But fear not: Bit-vector logic is complete: This means that z3 will always be able to factor, albeit slowly, assuming you do not run out of memory or patience first!
This is what I did now.
It might help others in the future:
(set-option :produce-models true)
(set-logic ALL)
;; Declaring all the variables
(declare-const a (_ BitVec 48))
(declare-const b (_ BitVec 48))
(declare-const c (_ BitVec 48))
(assert (= c #x00000000affe))
(assert (= c (bvmul a b)))
; don't allow overflow
(assert (= c (bvumul_noovfl a b)))
(assert (bvult #x000000000001 a))
(assert (bvult a c))
(assert (bvult #x000000000001 b))
(assert (bvult b c))
;; Soft constraints to limit reuse
(assert-soft (not (= a b)))
(check-sat)
(get-model)
I added two more asserts to make sure a or b does not exceed c (the input in hexadecimal)
in this example, I used "affe" that's 45054 in decimal.
it should work for bigger ones as well.
Output:
sat
(model
(define-fun b () (_ BitVec 48)
#x00000000138e)
(define-fun a () (_ BitVec 48)
#x000000000009)
(define-fun c () (_ BitVec 48)
#x00000000affe)
)
hex: 138e * 9 = affe
dec: 5006 * 9 = 45054
Hope this will help someone else in the future.
I'm trying to define in Z3 the parthood relation (called C in the code below) between pairs of sets (defined using array).
I wrote 3 asserts to define reflexivity, transitivity, and antisymmetry but Z3 returns "unknown" and I don't understand why.
(define-sort Set () (Array Int Bool))
(declare-rel C (Set Set))
; reflexivity
(assert (forall ((X Set)) (C X X)))
; transitive
(assert (forall ((X Set)(Y Set)(Z Set))
(=>
(and (C X Y) (C Y Z))
(C X Z)
)
))
; antisymmetric
(assert (forall ((X Set)(Y Set))
(=>
(and (C X Y) (C Y X))
(= X Y)
)
))
(check-sat)
I noticed that the unknown is returned only when the antisymmetry is considered with one of the other 2 asserts. If I only consider the antisymmetry property Z3 doesn't return unknown. The same if I consider reflexivity and transitivity without antisymmetry.
Quantifiers are inherently incomplete. So, it's not surprising that Z3 (or any other SMT solver) will return unknown when they are present. There are a few heuristics that solvers use for handling quantifiers, such as e-matching; but those will only apply when you have ground-terms around. Your formulation, having only quantified axioms, is unlikely to benefit from that.
For reasoning about quantifiers in general, an SMT solver is simply not the best choice; use a theorem prover (Isabelle, Lean, Coq, etc.) for that.
Here's a nice slide deck by Leonardo on the use of quantifiers in SMT solving: https://leodemoura.github.io/files/qsmt.pdf. It can help provide some further insight into the techniques and the difficulties associated.
I'm looking for ideas on how to encode mathematical equations into cnf-sat form, so that they can be solved by an open source SAT solver like MiniSat.
So, how do I convert something like:
3x + 4y - z = 14
-2x - 4z <= -6
x - 3y + z >= 15
into a propositional equation that can be solved by using SAT Solvers.
Any suggestions because I'm stumped??
I'm assuming you're looking for an integer solution to your equations since Integer Linear Programming is a known NP-hard problem, as is SAT. (Linear programming without the integer constraint is in P, of course.)
You could convert your equations to a SAT instance but your time would be more fruitfully spent learning how to use an SMT solver, which will let you express your equations much more naturally. As an example, using Microsoft's Z3 solver, your equations above could be solved with this simple program:
(declare-fun x () Int)
(declare-fun y () Int)
(declare-fun z () Int)
(assert (= (+ (* 3 x) (* 4 y) (- z)) 14))
(assert (<= (- (* (- 2) x) (* 4 z)) (- 6)))
(assert (>= (+ (- x (* (- 3) y)) z) 15))
(check-sat)
(get-model)
You can paste that program into an online Z3 sandbox and click the play button to see it solve the equations.
I am encoding sets as relations and operations over sets as universally quantified implications. I have a selection operator over sets that produces new sets by selecting elements satisfying a unary predicate p (eg: v<4, v>4, ..). Due to this operator, I have simple arithmetic predicates in my formulas. An example Z3 encoding of such a formula is given below -
(set-option :mbqi true)
(set-option :model-compact true)
;; Rmem and Rmem1 are sets of Int
(declare-fun Rmem (Int) Bool)
(declare-fun Rmem1 (Int) Bool)
(declare-const v Int)
(declare-const v1 Int)
(declare-const x Int)
;; Rmem = Rmem1 U {x}
(assert (forall ((n Int)) (= (Rmem n)(or (Rmem1 n) (= n x)))))
;; Select(m<v1) from Rmem1 = {}
(assert (forall ((m Int)) (= false (and (Rmem1 m) (< m v1)))))
(assert (or (< v x) (= v x)))
(assert (or (< v v) (= v v1)))
(assert (exists ((q Int)) (and (Rmem q) (< q v))))
(check-sat)
(get-model)
As expected, Z3 returns UNSAT for the above formula. However, my questions are -
Given that I can write my formula in prenex normal form, is it still in EPR class?
Are such formulas decidable? Is z3 a decision procedure for such formulas? How should I constrain my predicates such that the formulas are decidable?
Update - The aforementioned set of formulas can be expressed as conjunctive queries in relational algebra, but with inequality.
Your formula is in decidable fragment that is supported by Z3. Technically, the formula is not in EPR because you use atoms of the form x < c in quantifiers. The Z3 guide (Quantifiers section) describes many fragments that can be decided by Z3. Note that some of these fragments are very expensive (e.g., NEXPTIME-hard). So, Z3 may still fail to solve them in a reasonable amount of time, or run out of memory.
I am using the Z3 SMT solver by Microsoft, and I am trying to define constants of a custom sort. It seems like such constants are not unequal by default. Suppose you have the following program:
(declare-sort S 0)
(declare-const x S)
(declare-const y S)
(assert (= x y))
(check-sat)
This will give "sat", because it is of course perfectly possible that two constants of the same sort are equal. Since I am making model in which constants have to be different from each other, this means that I would need to add an axiom of the form
(assert (not (= x y)))
for every pair of constants of the same sort. I was wondering if there is some way to do this generic, so that each constant of a sort is unique by default.
You can use datatypes to encode enumeration types found in many programming languages. In the following example, the sort S has three elements and they are different from each other.
(declare-datatypes () ((S a b c)))
Here is a complete example: http://rise4fun.com/Z3/ncPc
(declare-datatypes () ((S a b c)))
(echo "a and b are different")
(simplify (= a b))
; x must be equal to a, b or c
(declare-const x S)
; since x != a, then it must be b or c
(assert (not (= x a)))
(check-sat)
(get-model)
; in the next check-sat x must be c
(assert (not (= x b)))
(check-sat)
(get-model)
Another possibility is to use distinct.
(assert (distinct a b c d e))