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

后端 未结 2 1284
不知归路
不知归路 2021-01-24 09:00

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.

相关标签:
2条回答
  • 2021-01-24 09:30

    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).

    0 讨论(0)
  • 2021-01-24 09:52

    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.

    0 讨论(0)
提交回复
热议问题