SMT2Lib slows after a non-negativity assert - z3

We're trying to build a solver for a weighted mean function. The code is written in SMT2Lib, and ran by CVC5 or Z3.
However, after adding an assert that indicates the non-negativity of the denominator, the code does not terminate. ("(assert (> tau0_max 0))")
Are there any alternatives to the parameters or the way we can declare the functions differently in order to approach this problem?
(Ints are not suitable to our problem. We'd like to use Rationals, but instead use Reals as they're offered by SMT2Lib).
(set-option :produce-assignments true)
(set-option :produce-models true)
(set-option :produce-proofs true)
(set-logic ALL)
;define data points x_0 x_1 x_2
(declare-fun x (Int) Real)
(declare-fun n () Int)
(define-fun sqr ((x Real)) Real (* x x))
(define-fun max ((x Real) (y Real)) Real (ite (> x y) x y))
;(define-fun c0 ((i Int)) Real 1.0)
(define-fun miu () Real (/ (+ (x 0) (+ (x 1) (+ (x 2) (+ (x 3) (+ (x 4) (+ (x 5) (+ (x 6) (+ (x 7) (+ (x 8) (+ (x 9) (x 10))))))))))) 11.0))
(define-fun miu_c0 () Real (/ (+ (x 0) (+ (x 1) (+ (x 2) (+ (x 3) (+ (x 4) (+ (x 5) (+ (x 6) (+ (x 7) (+ (x 8) (+ (x 9) (+ (x 10) (x 11)))))))))))) 12.0))
(define-fun tau0 ((i Int)) Real (sqr (- (x i) miu_c0)))
(define-fun tau0_max () Real (max (tau0 0) (max (tau0 1) (max (tau0 2) (max (tau0 3) (max (tau0 4) (max (tau0 5) (max (tau0 6) (max (tau0 7) (max (tau0 8) (max (tau0 9) (max (tau0 10) (tau0 11)))))))))))))
**(assert (> tau0_max 0))**
(define-fun c1 ((i Int)) Real (- 1.0 (/ (tau0 i) tau0_max)))
(define-fun miu_c1 () Real (/ (+ (* (c1 0) (x 0)) (+ (* (c1 1) (x 1)) (+ (* (c1 2) (x 2)) (+ (* (c1 3) (x 3)) (+ (* (c1 4) (x 4)) (+ (* (c1 5) (x 5)) (+ (* (c1 6) (x 6)) (+ (* (c1 7) (x 7)) (+ (* (c1 8) (x 8)) (+ (* (c1 9) (x 9)) (+ (* (c1 10) (x 10)) (* (c1 11) (x 11))))))))))))) 12.0))
(define-fun tau1 ((i Int)) Real (sqr (- (x i) miu_c1)))
(define-fun tau1_max () Real (max (tau1 0) (max (tau1 1) (max (tau1 2) (max (tau1 3) (max (tau1 4) (max (tau1 5) (max (tau1 6) (max (tau1 7) (max (tau1 8) (max (tau1 9) (max (tau1 10) (tau1 11)))))))))))))
(define-fun c2 ((i Int)) Real (* (c1 i) (- 1.0 (/ (tau1 i) tau1_max))))
(assert (= (c2 0) 1.0))
(check-sat)
(get-model)

Related

Why does Z3 keeps a variable at the same value even if it is specified not to do that

I am encountering a problem in Z3 for which I can't seem to find where it originates from and how to fix it. My goal that for a given certain iteration (for-loop) that is composed of an if-then-else statement at each step; is it possible to achieve a given value k after the loop has finished. This is done without knowing the structure of if. In other words, i need to check every possible mapping of the function (true or false) for each step. More precisely in smt2 format:
(declare-fun a(Int) Int)
(declare-fun b(Int) Int)
(assert (= 1 (a 0)))
(assert (= 1 (b 0)))
(assert (xor (and ( = (a 1) (+ (a 0) (* 2 (b 0)))) (= (b 1) (+ 1 (b 0)))) (and (= (b 1) (+ (a 0) (b 0))) (= (a 1) (+ (b 0) 1)))))
(assert (xor (and ( = (a 2) (+ (a 1) (* 2 (b 1)))) (= (b 2) (+ 2 (b 1)))) (and (= (b 2) (+ (a 1) (b 1))) (= (a 2) (+ (b 1) 2)))))
(assert (xor (and ( = (a 3) (+ (a 2) (* 2 (b 2)))) (= (b 3) (+ 3 (b 2)))) (and (= (b 3) (+ (a 2) (b 2))) (= (a 3) (+ (b 2) 3)))))
(assert (xor (and ( = (a 4) (+ (a 3) (* 2 (b 3)))) (= (b 4) (+ 4 (b 3)))) (and (= (b 4) (+ (a 3) (b 3))) (= (a 4) (+ (b 3) 4)))))
(assert (xor (and ( = (a 5) (+ (a 4) (* 2 (b 4)))) (= (b 5) (+ 5 (b 4)))) (and (= (b 5) (+ (a 4) (b 4))) (= (a 5) (+ (b 4) 5)))))
(assert (xor (and ( = (a 6) (+ (a 5) (* 2 (b 5)))) (= (b 6) (+ 6 (b 5)))) (and (= (b 6) (+ (a 5) (b 5))) (= (a 6) (+ (b 5) 6)))))
(assert (xor (and ( = (a 7) (+ (a 6) (* 2 (b 6)))) (= (b 7) (+ 7 (b 6)))) (and (= (b 7) (+ (a 6) (b 6))) (= (a 7) (+ (b 6) 7)))))
(assert (xor (and ( = (a 8) (+ (a 7) (* 2 (b 7)))) (= (b 8) (+ 8 (b 7)))) (and (= (b 8) (+ (a 7) (b 7))) (= (a 8) (+ (b 7) 8)))))
(assert (xor (and ( = (a 9) (+ (a 8) (* 2 (b 8)))) (= (b 9) (+ 9 (b 8)))) (and (= (b 9) (+ (a 8) (b 8))) (= (a 9) (+ (b 8) 9)))))
(assert (xor (and ( = (a 10) (+ (a 9) (* 2 (b 9)))) (= (b 10) (+ 10 (b 9)))) (and (= (b 10) (+ (a 9) (b 9))) (= (a 10) (+ (b 9) 10)))))
(assert (= (b 10) 461))
(check-sat)
(get-model)
The xor operator is used to check if the statement for then holds or the statement in else holds, but not both. So the the variable a or b is bounded to follow only one valid path. Somehow the values sometimes don't seem to obey this rule or they do not change, and I am unable to tell why is this happening. As for example take this output for a, for the step 2 and 3 the value doesn't change, which should not be possible:
(define-fun a ((x!0 Int)) Int
(ite (= x!0 0) 1
(ite (= x!0 1) 3
(ite (= x!0 2) 7 <--- should not be possible but keeps happening
(ite (= x!0 3) 7 <---
(ite (= x!0 4) 29
[...]
I don't know if i either am encountering a bug or my logic involved in the solution for this problem is flawed. I tried to use Bounded Model Checking. I would appreciate any help!
Issue: the problem is either in your understanding of how the loop should behave, or in the encoding of the formula implementing the logic of the loop. Since you didn't provide the original pseudo-code, I cannot guess any further.
Let's take this:
(assert (xor
(and
(= (a 1) (+ (a 0) (* 2 (b 0))))
(= (b 1) (+ 1 (b 0)))
)
(and
(= (b 1) (+ (a 0) (b 0)))
(= (a 1) (+ (b 0) 1))
)
)
)
The expression that is being unrolled is:
( -- #then-branch
a' := a + 2 * b
/\
b' := K + b
)
xor
( -- #else-branch
a' = K + b
/\
b' = a + b
)
where K depends on the current iteration, starting with 1.
Q: is the solution provided by the SMT solver feasible? YES!
(the portion you have shared with us..)
a_0 := 1
b_0 := 1
-- execute #then-branch (K = 1)
a_1 := a_0 + 2 * b_0 = 1 + 2 * 1 = 3
b_1 := K + b_0 = 1 + 1 = 2
-- execute #then-branch (K = 2)
a_2 := a_1 + 2 * b_1 = 3 + 2 * 2 = 7
b_2 := K + b_1 = 2 + 2 = 4
-- execute #else-branch (K = 3)
a_3 := K + b_2 = 3 + 4 = 7
b_3 := a_2 + b_2 = 7 + 4 = 11
-- execute #then-branch (K = 4)
a_4 := a_3 + 2 * b_3 = 7 + 2 * 11 = 29
b_4 := K + b_3 = 4 + 11 = 15
...

function with quantifier in Z3

I have a problem with quantifier.
Let a(0) = 0, and a(n+1) would be either a(n)+1 or a(n)+2 based on the value of x(n). We may expect that for any kind of x(.) and for all n, a(n) <= n*2.
Here is the code for Z3:
(declare-fun a (Int) Int)
(declare-fun x (Int) Int)
(declare-fun N () Int)
(assert (forall
((n Int))
(=> (>= n 0)
(= (a (+ n 1))
(ite (> (x n) 0)
(+ (a n) 1)
(+ (a n) 2)
)
)
)
))
(assert (= (a 0) 0))
(assert (> (a N) (+ N N)))
(check-sat)
(get-model)
I hope Z3 could return "unsat", while it always "timeout".
I wonder if Z3 could handle this kind of quantifier, and if somebody could give some advice.
Thanks.
The formula is SAT, for N < 0, the graph of a is underspecified.
But the default quantifier instantiation engine can't determine this. You can take advantage of that you are defining a recursive function to enforce a different engine.
;(declare-fun a (Int) Int)
(declare-fun x (Int) Int)
(declare-fun y (Int) Int)
(declare-fun N () Int)
(define-fun-rec a ((n Int)) Int
(if (> n 0) (if (> (x (- n 1)) 0) (+ (a (- n 1)) 1) (+ (a (- n 1)) 2)) (y n)))
(assert (= (a 0) 0))
(assert (> (a N) (+ N N)))
(check-sat)
(get-model)
As Malte writes, there is no support for induction on such formulas so don't expect Z3 to produce induction proofs. It does find inductive invariants on a class of Horn clause formulas, but it requires a transformation to cast arbitrary formulas into this format.
Thanks, Malte and Nikolaj.
The variable N should be bounded:
(assert (> N 0))
(assert (< N 10000))
I replace
(assert (> (a N) (+ N N)))
with
(assert (and
(not (> (a N) (+ N N)))
(> (a (+ N 1)) (+ (+ N 1) (+ N 1)))
))
and it works for both definition of a(n).
Does this a kind of inductive proof as you mentioned?
Here are the two blocks of code, and both of them return "unsat":
(declare-fun a (Int) Int)
(declare-fun x (Int) Int)
(declare-fun N () Int)
(assert (forall
((n Int))
(=> (>= n 0)
(= (a (+ n 1))
(ite (> (x n) 0)
(+ (a n) 1)
(+ (a n) 2)
)
))
))
(assert (= (a 0) 0))
(assert (> N 0))
(assert (< N 10000))
;(assert (> (a N) (+ N N)))
(assert (and
(not (> (a N) (+ N N)))
(> (a (+ N 1)) (+ (+ N 1) (+ N 1)))
))
(check-sat)
;(get-model)
and
(declare-fun x (Int) Int)
(declare-fun y (Int) Int)
(declare-fun N () Int)
(define-fun-rec a ((n Int)) Int
(if (> n 0)
(if (> (x (- n 1)) 0) (+ (a (- n 1)) 1) (+ (a (- n 1)) 2)) (y n)))
(assert (= (a 0) 0))
(assert (> N 0))
(assert (< N 10000))
;(assert (> (a N) (+ N N)))
(assert (and
(not (> (a N) (+ N N)))
(> (a (+ N 1)) (+ (+ N 1) (+ N 1)))
))
(check-sat)
;(get-model)

z3 and z3PY giving different results

When I tried following in z3, I got result timeout
(set-option :smt.mbqi true)
(declare-fun R(Int) Int)
(declare-fun Q(Int) Int)
(declare-var X Int)
(declare-var Y Int)
(declare-const k Int)
(assert (>= X 0))
(assert (> Y 0))
(assert (forall ((n Int)) (=> (= n 0) (= (Q n) 0))))
(assert (forall ((n Int)) (=> (= n 0) (= (R n) X))))
(assert (forall ((n Int)) (=> (> n 0) (= (R (+ n 1) ) (+ (R n) (* 2 Y))))))
(assert (forall ((n Int)) (=> (> n 0) (= (Q (+ n 1) ) (- (Q n) 2)))))
(assert (forall ((n Int)) (=> (> n 0) (= X (+ (* (Q n) Y) (R n))))))
(assert (forall ((n Int)) (= X (+ (* (Q n) Y) (R n)))))
(assert (= X (+ (* (Q k) Y) (R k))))
(assert (not (= (* X 2) (+ (* (Q (+ k 1)) Y) (R (+ k 1))))))
(check-sat)
Same when I tried in z3py using following code, I got result unsat which is wrong
from z3 import *
x=Int('x')
y=Int('y')
k=Int('k')
n1=Int('n1')
r=Function('r',IntSort(),IntSort())
q=Function('q',IntSort(),IntSort())
s=Solver()
s.add(x>=0)
s.add(y>0)
s.add(ForAll(n1,Implies(n1==0,r(0)==x)))
s.add(ForAll(n1,Implies(n1==0,q(0)==0)))
s.add(ForAll(n1,Implies(n1>0,r(n1+1)==r(n1)-(2*y))))
s.add(ForAll(n1,Implies(n1>0,q(n1+1)==q(n1)+(2))))
s.add(x==q(k)*y+r(k))
s.add(not(2*x==q(k+1)*y+r(k+1)))
if sat==s.check():
print s.check()
print s.model()
else :
print s.check()
Looking forward to Suggestions.
My suggestion is to use replace the built-in not operator by the Z3 function called Not, e.g.
not(2*x==q(k+1)*y+r(k+1))
is simplified to False by Python before Z3 gets to see it, while
Not(2*x==q(k+1)*y+r(k+1))
has the desired meaning.

Find the largest palindrome made from the product of two 5-digit numbers using Z3-SMTLIB

We look for a number of the form efghiihgfe which is the product of two numbers of the form 999ab and 99qcd.
We use the following code
(declare-const a Int)
(declare-const b Int)
(declare-const c Int)
(declare-const d Int)
(declare-const e Int)
(declare-const f Int)
(declare-const g Int)
(declare-const h Int)
(declare-const i Int)
(declare-const p Int)
(declare-const q Int)
(assert (and (>= a 0) (<= a 9)))
(assert (and (>= b 0) (<= b 9)))
(assert (and (>= c 0) (<= c 9)))
(assert (and (>= d 0) (<= d 9)))
(assert (and (>= e 0) (<= e 9)))
(assert (and (>= f 0) (<= f 9)))
(assert (and (>= g 0) (<= g 9)))
(assert (and (>= h 0) (<= h 9)))
(assert (and (>= i 0) (<= i 9)))
(assert (and (>= p 0) (<= p 9)))
(assert (and (>= q 0) (<= q 9)))
(assert (= (* (+ 99900 (* 10 a) b ) (+ 99000 (* 100 q) (* 10 c) d ))
(+ (* (^ 10 9) e) (* (^ 10 8) f) (* (^ 10 7) g) (* (^ 10 6) h) (* (^ 10 5) i)
(* (^ 10 4) i) (* 1000 h ) (* 100 g) (* 10 f) e) ) )
(check-sat)
(get-model)
(eval (+ (* (^ 10 9) e) (* (^ 10 8) f) (* (^ 10 7) g) (* (^ 10 6) h) (* (^ 10 5) i)
(* (^ 10 4) i) (* 1000 h ) (* 100 g) (* 10 f) e))
and the output is
(model
(define-fun q () Int
6)
(define-fun p () Int
0)
(define-fun i () Int
0)
(define-fun h () Int
6)
(define-fun g () Int
6)
(define-fun f () Int
9)
(define-fun e () Int
9)
(define-fun d () Int
1)
(define-fun c () Int
8)
(define-fun b () Int
9)
(define-fun a () Int
7)
)
9966006699
To verify that 9966006699 is the maxim we run the code
(declare-const a Int)
(declare-const b Int)
(declare-const c Int)
(declare-const d Int)
(declare-const e Int)
(declare-const f Int)
(declare-const g Int)
(declare-const h Int)
(declare-const i Int)
(declare-const p Int)
(declare-const q Int)
(assert (and (>= a 0) (<= a 9)))
(assert (and (>= b 0) (<= b 9)))
(assert (and (>= c 0) (<= c 9)))
(assert (and (>= d 0) (<= d 9)))
(assert (and (>= e 0) (<= e 9)))
(assert (and (>= f 0) (<= f 9)))
(assert (and (>= g 0) (<= g 9)))
(assert (and (>= h 0) (<= h 9)))
(assert (and (>= i 0) (<= i 9)))
(assert (and (>= p 0) (<= p 9)))
(assert (and (>= q 0) (<= q 9)))
(assert (= (* (+ 99900 (* 10 a) b ) (+ 99000 (* 100 q) (* 10 c) d ))
(+ (* (^ 10 9) e) (* (^ 10 8) f) (* (^ 10 7) g) (* (^ 10 6) h) (* (^ 10 5) i)
(* (^ 10 4) i) (* 1000 h ) (* 100 g) (* 10 f) e) ) )
(assert (> (+ (* (^ 10 9) e) (* (^ 10 8) f) (* (^ 10 7) g) (* (^ 10 6) h) (* (^ 10 5) i)
(* (^ 10 4) i) (* 1000 h ) (* 100 g) (* 10 f) e) 9966006699 ))
(check-sat)
and the output is
unsat
Please let me know if there is a more efficient program with Z3 to solve the problem.
Thank you, maybe use bit-vectors to force using finite domains instead of ILP.

Simplifying z3 expression using C++ API

I have such an expression
z3::expr expr = (exists ((flag Bool))
(exists ((w Int))
(exists ((i Int))
(exists ((counter Int))
(and (= i (+ x y z))
flag
(not (= i 0))
(= i counter)
(not (= w counter))
(>= i 1)
(= w 0)))))))
I use C++ API to do quantifier elimination and simplification.
z3::goal g(ctx);
g.add(expr);
z3::apply_result result = (qe & simplify & propagate_ineqs)(g);
I have defined the tactics.
I want to get such result:
(or (>= (+ x y z) 1 )
(<= (+ x y z) -1 ))
but I get this output which is appropriate for my application:
(let ((a!1 (or (<= (+ (* (- 1) x)
(* (- 1) y)
(* (- 1) z))
(- 1))
(<= (+ x y z) (- 1)))))
(and (or (<= (+ x y z) (- 1))
(>= (+ x y z) 1))
a!1
(>= (+ x y z) 1)))
what tactics should I use to make it work as I want?
I solved the issue by setting these options in the context, before defining the goal:
ctx.set(":pp-min-alias-size", 1000000);
ctx.set(":pp-max-depth", 1000000);
it didn't simplify as I wanted, but removed the "let"s and that's better than nothing!

Resources