Use Z3 and SMT-LIB to define sqrt function with a real number

蹲街弑〆低调 提交于 2019-12-20 04:38:06

问题


How I can write sqrt function in smt-libv2 format.

Note: To get a maximum of two values, i found a useful link here: Use Z3 and SMT-LIB to get a maximum of two values.


回答1:


Suppose that your formula is quantifier free, then you can define square-roots implicitly by introducing fresh variables and adding constraints. For example you can write:

  (define-fun is_sqrt ((x Real) (y Real)) Bool (= y (* x x)))

Then 'x' is a square root of 'y'; and if you just want the non-negative square roots, then:

  (define-fun is_sqrt ((x Real) (y Real)) Bool (and (>= x 0) (= y (* x x))))

For every occurrence in your assertion where you have a square root, introduce a fresh variable and plug the fresh variable into that place. Then add the assertion

   (assert (is_sqrt fresh-variable sub-term))

Z3 also provides a built-in operator for lifting terms into a power. You can use this to get a square root. So to write the square root of 'x', you can write the term:

   (^ x 0.5)

The inference using powers in Z3 is somewhat limited, so it really depends on what your formula says whether this formulation will be handled in the same way as the relational encoding.




回答2:


If you don't actually need a function, then the simplest way to define y as the square-root of x is to assert that y * y = x, i.e.:

; This will cause Z3 to return a decimal answer instead of a root-obj
(set-option :pp.decimal true)

; Option 1: inverse of multiplication. This works fine if you don't actually
; need to define a custom function. This will find y = 1.414... or y = -1.414...
(declare-fun y () Real)
(assert (= 2.0 (* y y)))

; Do this if you want to find the positive root y = 1.414...
(assert (>= y 0.0))

(check-sat)
(get-value (y))
(reset)

Another way I tried using uninterpreted functions is like this:

; Option 2: uninterpreted functions. Unfortunately Z3 seems to always return
; 'unknown' when sqrt is defined this way. Here we ignore the possibility that
; x < 0.0; fixing this doesn't help the situation, though.
(declare-fun sqrt (Real) Real)
(assert (forall ((x Real)) (= x (* (sqrt x) (sqrt x)))))
(declare-fun y () Real)
(assert (= y (sqrt 2.0)))
(check-sat)
(reset)

Finally, by far the easiest if you're using Z3 is to use the built-in power operator as suggested by Nikolaj. You can a function based around that idea:

; Option 3: built-in power operator. This is not standard SMT-LIB, but works
; well with Z3.
(define-fun sqrt ((x Real)) Real (^ x 0.5))
(declare-fun y () Real)
(assert (= y (sqrt 2.0)))
(check-sat)
(get-value (y))
(reset)

Nikolaj's idea of defining a function is_sqrt is also an interesting idea and has the advantage that it is quantifier-free, so it will work with nlsat (the most powerful nonlinear solver in Z3).



来源:https://stackoverflow.com/questions/30328888/use-z3-and-smt-lib-to-define-sqrt-function-with-a-real-number

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!