PYTHON] Z3 Examples

노션으로 옮김·2020년 5월 22일
1

uitility

목록 보기
15/18
post-thumbnail

다음의 가이드를 참고하는 글이다.

https://ericpony.github.io/z3py-tutorial/guide-examples.htm


Basic

Quadratic Equation

이차 방정식의 해를 구한다.

x = Int('x')
y = Int('y')
solve(x > 2, y < 10, x + 2*y == 7)

결과

root@ubuntu:/work/exploits/z3# python b1.py
[y = 0, x = 7]

Simplify

수식을 간단히 표현하는 기능이다.

x = Int('x')
y = Int('y')
print simplify(x + y + 2*x + 3)
print simplify(x < y + x + 2)
print simplify(And(x + 1 >= 3, x**2 + x**2 + y**2 + 2 >= 5))

결과

root@ubuntu:/work/exploits/z3# python b2.py
3 + 3*x + y
Not(y <= -2)
And(x >= 2, 2*x**2 + y**2 >= 3)

set_option

set_option()은 모든 표현식과 수식의 표현방식을 설정할 수 있다.
html_mode 옵션은 html 엔티티 형식으로 출력할건지를 결정한다.

x = Int('x')
y = Int('y')
print x**2 + y**2 >= 1
set_option(html_mode=True)
print x**2 + y**2 >= 1

결과

root@ubuntu:/work/exploits/z3# python b3.py
x**2 + y**2 >= 1
x<sup>2</sup> + y<sup>2</sup> &ge; 1

다음은 소수점 30개까지 출력하는 예제다.

>>> x = Real('x')
>>> y = Real('y')
>>> solve(x**2+y**2==3, x**3==2)
[x = 1.2599210498?, y = -1.1885280594?]
>>> set_option(precision=30)
>>> solve(x**2+y**2==3, x**3==2)
[x = 1.259921049894873164767210607278?, y = -1.188528059421316533710369365015?]

Traversing Expression

z3로 수식을 만들면, 각 요소를 접근할 수 있는 함수를 제공해준다.

x = Int('x')
y = Int('y')
n = x + y >= 3
print "num args: ", n.num_args()
print "children: ", n.children()
print "1st child:", n.arg(0)
print "2nd child:", n.arg(1)
print "operator: ", n.decl()
print "op name:  ", n.decl().name()

결과

root@ubuntu:/work/exploits/z3# python b4.py
num args:  2
children:  [x + y, 3]
1st child: x + y
2nd child: 3
operator:  >=
op name:   >=

Power Operator

근을 구할 수 있다.

x = Real('x')
y = Real('y')
solve(x**2 + y**2 > 3, x**3 + y < 5)
solve(x**2 == 4)

결과

root@ubuntu:/work/exploits/z3# python b5.py 
[x = 1/8, y = 2]
[x = 2]

Fractional

분수는 Q(분자, 분모)로 나타낼 수 있다.
또한 RealVal()로 상수를 표현해 분수를 만들 수 있다.

print 1/3
print RealVal(1)/3
print Q(1,3)
print '---------------'
x = Real('x')
print x + 1/3
print x + Q(1,3)
print x + "1/3"
print x + 0.25

결과

root@ubuntu:/work/exploits/z3# python b7.py 
0
1/3
1/3
---------------
x + 0
x + 1/3
x + 1/3
x + 1/4

Rational to Decimal

유리수를 10진수 표현으로 출력

x = Real('x')
solve(3*x == 1)

set_option(rational_to_decimal=True)
solve(3*x == 1)

결과

root@ubuntu:/work/exploits/z3# python b8.py 
[x = 1/3]
[x = 0.3333333333?]

Boolean

Boolean도 마찬가지로 답을 구할 수 있다.

p = Bool('p')
q = Bool('q')
r = Bool('r')
solve(p == Not(r), Or(Not(q), r))

결과

root@ubuntu:/work/exploits/z3# python bool.py
[r = False, q = False, p = True]

또한 그냥 상수값 True, False를 사용할 수도 있다.

p = Bool('p')
q = Bool('q')
print And(p, q, True)
print simplify(And(p, q, True))
print simplify(And(p, False))

결과

root@ubuntu:/work/exploits/z3# python bool2.py
And(p, q, True)
And(p, q)
False

논리 연산자를 Solve에 사용할 수도 있다.

p = Bool('p')
x = Real('x')
solve(Or(x < 5, x > 10), Or(p, x**2 == 2), Not(p))

결과

root@ubuntu:/work/exploits/z3# python bool4.py 
[x = -1.4142135623?, p = False]

Solver

solve() 대신 사용할 수 있다.
Solver()로 객체를 생성한 후에 add로 수식을 추가하는 방식이다.

t('x')
y = Int('y')

s = Solver()
print s

s.add(x > 10, y == x + 2)
print s
print "Solving constraints in the solver s ..."
print s.check()

print "Create a new scope..."
s.push()
s.add(y < 11)
print s
print "Solving updated set of constraints..."
print s.check()

print "Restoring state..."
s.pop()
print s
print "Solving restored set of constraints..."
print s.check()

push()는 현재 상태를 저장하는 것이고, pop()은 저장했던 상태를 복구한다.

check()Solver()의 해가 존재하는지 확인하는 것이다. 존재할 경우 sat, 아닐 경우 unsat 이다.

해결할 수 없을 때는 unknown이다. 예를 들어 다음처럼 다항식이 아닌 조건을 전달했을 때

x = Real('x')
s = Solver()
s.add(2**x == 3)
print s.check()

위 코드의 실행으로 unknown이 출력될 것이다.

Traversal - assert

Solver.assertions()으로 수식 단위로 접근할 수 있다.

x = Real('x')
y = Real('y')
s = Solver()
s.add(x > 1, y > 1, Or(x + y > 3, x - y < 2))
print "asserted constraints..."
for c in s.assertions():
    print c

print s.check()
print "statistics for the last check method..."
print s.statistics()
# Traversing statistics
for k, v in s.statistics():
    print "%s : %s" % (k, v)

결과

root@ubuntu:/work/exploits/z3# python tra.py 
asserted constraints...
x > 1
y > 1
Or(x + y > 3, x - y < 2)
sat
statistics for the last check method...
(:arith-iterations    1
 :arith-lower         1
 :arith-make-feasible 3
 :arith-max-columns   4
 :arith-max-rows      2
 :arith-pivots        1
 :arith-rows          4
 :arith-upper         3
 :decisions           2
 :final-checks        1
 :max-memory          2.38
 :memory              2.19
 :mk-bool-var         10
 :num-allocs          456090
 :rlimit-count        213)
mk bool var : 1
decisions : 2
final checks : 1
mk bool var : 5
arith-lower : 1
arith-upper : 3
arith-rows : 4
arith-iterations : 1
arith-pivots : 1
arith-make-feasible : 3
arith-max-columns : 4
arith-max-rows : 2
mk bool var : 1
mk bool var : 1
mk bool var : 1
mk bool var : 1
num allocs : 456090
rlimit count : 213
max memory : 2.38
memory : 2.19
root@ubuntu:/work/exploit

Model

Model은 해의 집합(?)을 말하는 것 같다.

We say the solution is a model for the set of asserted constraints.

어쨌든 model()을 이용해 각 solution에 접근할 수 있다.

x, y, z = Reals('x y z')
s = Solver()
s.add(x > 1, y > 1, x + y > 3, z - x < 10)
print s.check()

m = s.model()
print "x = %s" % m[x]

print "traversing model..."
for d in m.decls():
    print "%s = %s" % (d.name(), m[d])

결과

root@ubuntu:/work/exploits/z3# python pp.py
sat
x = 3/2
traversing model...
z = 0
y = 2
x = 3/2

0개의 댓글