-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathZ3Driver.py
165 lines (147 loc) · 4.71 KB
/
Z3Driver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
from z3 import *
from Specs import *
from VCs import *
''' The function [spec_vars_ae] identifies all free
variables in an arithmetic expression and gathers
them in a set. '''
def spec_vars_ae(e):
match e:
case AEVar():
return set([e.name()])
case AEVal():
return set()
case AEPow():
e1 = spec_vars_ae(e.base())
e2 = spec_vars_ae(e.exp())
return e1.union(e2)
case AEPlus() | AEMinus() | AEMult():
e1 = spec_vars_ae(e.left())
e2 = spec_vars_ae(e.right())
return e1.union(e2)
''' The function [spec_vars] identifies all free
variables in a specification and gathers
them in a set. '''
def spec_vars(e):
match e:
case SVal():
return set()
case SNeg():
return spec_vars(e.value())
case SAnd() | SOr() | SImp():
e1 = spec_vars(e.left())
e2 = spec_vars(e.right())
return e1.union(e2)
case SLeq() | SLt() | SEq() | SGeq() | SGt():
e1 = spec_vars_ae(e.left())
e2 = spec_vars_ae(e.right())
return e1.union(e2)
''' The function [ae2z3] transforms an arithmetic expression
built using the [AExpr] class hierarchy into the
corresponding format accepted by the Z3 theorem
prover. '''
def ae2z3(e,vars):
match e:
case AEVal():
return IntVal(e.value())
case AEVar():
return vars[e.name()]
case AEPow():
l = ae2z3(e.base(),vars)
r = ae2z3(e.exp(),vars)
return (l**r)
case AEPlus():
l = ae2z3(e.left(),vars)
r = ae2z3(e.right(),vars)
return (l + r)
case AEMinus():
l = ae2z3(e.left(),vars)
r = ae2z3(e.right(),vars)
return (l - r)
case AEMult():
l = ae2z3(e.left(),vars)
r = ae2z3(e.right(),vars)
return (l * r)
''' The function [spec2z3] transforms a specification
built using the [Spec] class hierarchy into the
corresponding format accepted by the Z3 theorem
prover. '''
def spec2z3(e,vars):
if isinstance(e,SVal):
return BoolVal(e.value())
elif isinstance(e,SNeg):
l = spec2z3(e.value(),vars)
return Not(l)
elif isinstance(e,SAnd):
l = spec2z3(e.left(),vars)
r = spec2z3(e.right(),vars)
return And([l,r])
elif isinstance(e,SOr):
l = spec2z3(e.left(),vars)
r = spec2z3(e.right(),vars)
return Or([l,r])
elif isinstance(e,SImp):
l = spec2z3(e.left(),vars)
r = spec2z3(e.right(),vars)
return Implies(l,r)
elif isinstance(e,SEq):
l = ae2z3(e.left(),vars)
r = ae2z3(e.right(),vars)
return (l == r)
elif isinstance(e,SLt):
l = ae2z3(e.left(),vars)
r = ae2z3(e.right(),vars)
return (l < r)
elif isinstance(e,SLeq):
l = ae2z3(e.left(),vars)
r = ae2z3(e.right(),vars)
return (l <= r)
elif isinstance(e,SGt):
l = ae2z3(e.left(),vars)
r = ae2z3(e.right(),vars)
return (l > r)
elif isinstance(e,SGeq):
l = ae2z3(e.left(),vars)
r = ae2z3(e.right(),vars)
return (l >= r)
''' The function [prove_vcs] creates a solver instance
in Z3, pushes all the verification conditions passed
as arguments, negates them, and asks Z3 to provide a
model that satisfies them. ** Note ** to prove that the
specifications are valid (an thus the program is correct)
the answer of Z3 must be [unsat], that is, there exists no
valuation to variables that makes the negation of the
formulas true; hence the formulas themselves must be theorems,
i.e., they are always true.'''
def prove_vcs(vcs,vars):
s = Solver()
for vc in vcs:
# We negate each of the formulae so that if Z3 says unsat
# then we know it is a theorem.
s.add(Not(spec2z3(vc,vars)))
return s.check()
def prove_correct_VC(pre,c,post):
# Generate the proof obligations
vcs = VC(pre,c,post)
# Collect the variables in the specifications
# in order to generate references to variables
# in Z3
s = set()
for x in vcs:
s = s.union(spec_vars(x))
vars = dict()
for i in s:
vars[i] = Int(i)
return prove_vcs(vcs,vars)
def prove_correct_VCG(pre,c,post):
# Generate the proof obligations
vcs = VCG(pre,c,post)
# Collect the variables in the specifications
# in order to generate references to variables
# in Z3
s = set()
for x in vcs:
s = s.union(spec_vars(x))
vars = dict()
for i in s:
vars[i] = Int(i)
return prove_vcs(vcs,vars)