
다음의 가이드를 참고하는 글이다.
이차 방정식의 해를 구한다.
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]
수식을 간단히 표현하는 기능이다.
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()은 모든 표현식과 수식의 표현방식을 설정할 수 있다.
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> ≥ 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?]
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: >=
근을 구할 수 있다.
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]
분수는 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
유리수를 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도 마찬가지로 답을 구할 수 있다.
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]
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이 출력될 것이다.
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은 해의 집합(?)을 말하는 것 같다.
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