├── homework5 ├── 1.txt ├── 2.txt ├── __init__.py ├── __pycache__ │ ├── tac.cpython-37.pyc │ ├── calc.cpython-37.pyc │ └── counter.cpython-37.pyc ├── counter.py ├── README.md ├── exercise2.py ├── equiv.py ├── exercise1.py ├── compiler.py ├── calc.py └── tac.py ├── .DS_Store ├── homework7 ├── README.md ├── exercise5.py ├── exercise2.py ├── exercise6.py ├── exercise7.py ├── exercise1.py ├── exercise3.py ├── exercise4.py └── pointer.py ├── homework6 ├── .DS_Store ├── __pycache__ │ ├── tableau.cpython-37.pyc │ └── constraint.cpython-37.pyc ├── exercise.py ├── task_scheduling.py ├── constraint.py ├── pandas_exercise.py ├── 01knapsack.py ├── simplex.py ├── four_queen.py ├── README.md ├── seat_arrangement.py ├── tableau.py └── fourier_motzkin.py ├── homework8 ├── .DS_Store ├── __pycache__ │ ├── ast.cpython-37.pyc │ ├── concrete.cpython-37.pyc │ └── symbolic.cpython-37.pyc ├── README.md ├── printer.py ├── pymp.py ├── ast.py ├── concrete.py ├── concolic.py └── symbolic.py ├── homework9 ├── .DS_Store ├── __pycache__ │ ├── tac.cpython-37.pyc │ ├── prover.cpython-37.pyc │ ├── backward.cpython-37.pyc │ ├── compiler.cpython-37.pyc │ ├── imp_ast.cpython-37.pyc │ └── imp_ast.cpython-38.pyc ├── README.md ├── gen_prog.py ├── prover.py ├── compiler.py ├── large_prog.py ├── tac.py ├── backward.py ├── forward.py └── imp_ast.py ├── README.md ├── homework2 ├── exercise1.v ├── README.md ├── exercise2.v ├── exercise3.v ├── exercise7.v ├── challenge2.v ├── challenge1.v ├── exercise4.v ├── exercise6.v └── exercise5.v ├── homework1 └── README.md ├── homework4 ├── README.md ├── exercise3.v ├── exercise1.v ├── exercise9.v ├── exercise4.v ├── exercise11.v ├── exercise10.v ├── exercise5.v ├── exercise7.v ├── exercise12.v ├── exercise6.v ├── exercise8.v └── exercise2.v └── homework3 ├── README.md ├── exercise2.py ├── exercise3.py ├── dpll.py └── exercise1.py /homework5/1.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /homework5/2.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/.DS_Store -------------------------------------------------------------------------------- /homework7/README.md: -------------------------------------------------------------------------------- 1 | 地址:http://staff.ustc.edu.cn/~bjhua/courses/theory/2020/assignment/assign7/ 2 | -------------------------------------------------------------------------------- /homework6/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework6/.DS_Store -------------------------------------------------------------------------------- /homework8/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework8/.DS_Store -------------------------------------------------------------------------------- /homework9/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework9/.DS_Store -------------------------------------------------------------------------------- /homework5/__init__.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | lib_path = os.path.abspath(os.path.join('./')) 3 | sys.path.append(lib_path) 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 课程主页 2 | http://staff.ustc.edu.cn/~bjhua/courses/theory/2020/schedule.html 3 | 4 | ### description 5 | 复习时重新写的作业。 -------------------------------------------------------------------------------- /homework2/exercise1.v: -------------------------------------------------------------------------------- 1 | Theorem exercise1: forall P Q:Prop, 2 | P -> (Q -> P). 3 | Proof. 4 | intros. 5 | apply H. 6 | Qed. -------------------------------------------------------------------------------- /homework1/README.md: -------------------------------------------------------------------------------- 1 | 地址:http://staff.ustc.edu.cn/~bjhua/courses/theory/2020/assignment/assign1-software.html 2 | 3 | 下载几个软件:Coq, z3. -------------------------------------------------------------------------------- /homework2/README.md: -------------------------------------------------------------------------------- 1 | 地址:http://staff.ustc.edu.cn/~bjhua/courses/theory/2020/assignment/assign2/index.html 2 | 3 | 本次作业主要是用 Coq 来证明一些定理。 -------------------------------------------------------------------------------- /homework2/exercise2.v: -------------------------------------------------------------------------------- 1 | Theorem exercise2: forall P Q H:Prop, 2 | P -> (Q -> (H -> Q)). 3 | Proof. 4 | intros. 5 | apply H1. 6 | Qed. -------------------------------------------------------------------------------- /homework4/README.md: -------------------------------------------------------------------------------- 1 | 地址:http://staff.ustc.edu.cn/~bjhua/courses/theory/2020/assignment/assign4/index.html 2 | 3 | - Predicate logic:谓词逻辑 -------------------------------------------------------------------------------- /homework2/exercise3.v: -------------------------------------------------------------------------------- 1 | Theorem Exercise3: forall P Q: Prop, 2 | P/\Q ->P. 3 | Proof. 4 | intros. 5 | inversion H. 6 | apply H0. 7 | Qed. -------------------------------------------------------------------------------- /homework5/__pycache__/tac.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework5/__pycache__/tac.cpython-37.pyc -------------------------------------------------------------------------------- /homework8/__pycache__/ast.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework8/__pycache__/ast.cpython-37.pyc -------------------------------------------------------------------------------- /homework9/__pycache__/tac.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework9/__pycache__/tac.cpython-37.pyc -------------------------------------------------------------------------------- /homework5/__pycache__/calc.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework5/__pycache__/calc.cpython-37.pyc -------------------------------------------------------------------------------- /homework9/__pycache__/prover.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework9/__pycache__/prover.cpython-37.pyc -------------------------------------------------------------------------------- /homework5/__pycache__/counter.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework5/__pycache__/counter.cpython-37.pyc -------------------------------------------------------------------------------- /homework6/__pycache__/tableau.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework6/__pycache__/tableau.cpython-37.pyc -------------------------------------------------------------------------------- /homework8/__pycache__/concrete.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework8/__pycache__/concrete.cpython-37.pyc -------------------------------------------------------------------------------- /homework8/__pycache__/symbolic.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework8/__pycache__/symbolic.cpython-37.pyc -------------------------------------------------------------------------------- /homework9/__pycache__/backward.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework9/__pycache__/backward.cpython-37.pyc -------------------------------------------------------------------------------- /homework9/__pycache__/compiler.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework9/__pycache__/compiler.cpython-37.pyc -------------------------------------------------------------------------------- /homework9/__pycache__/imp_ast.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework9/__pycache__/imp_ast.cpython-37.pyc -------------------------------------------------------------------------------- /homework9/__pycache__/imp_ast.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework9/__pycache__/imp_ast.cpython-38.pyc -------------------------------------------------------------------------------- /homework6/__pycache__/constraint.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvanjoi/FMF-homework-2020spring/HEAD/homework6/__pycache__/constraint.cpython-37.pyc -------------------------------------------------------------------------------- /homework2/exercise7.v: -------------------------------------------------------------------------------- 1 | Theorem exercise7: forall P Q R:Prop, 2 | (P->(Q/\R))-> ((P->Q)/\(P->R)). 3 | Proof. 4 | intros. 5 | split. 6 | apply H. 7 | apply H. 8 | Qed. -------------------------------------------------------------------------------- /homework2/challenge2.v: -------------------------------------------------------------------------------- 1 | Theorem challenge2: forall P Q:Prop, 2 | (P -> Q) -> ( ~Q -> ~P). 3 | Proof. 4 | intros. 5 | unfold not. 6 | unfold not in H0. 7 | auto. 8 | Qed. -------------------------------------------------------------------------------- /homework2/challenge1.v: -------------------------------------------------------------------------------- 1 | Theorem challenge1: forall P Q R S T:Prop, 2 | ((P/\Q)/\R) /\ (S/\T) -> (Q /\ S). 3 | Proof. 4 | intros. 5 | split. 6 | apply H. 7 | apply H. 8 | Qed. -------------------------------------------------------------------------------- /homework4/exercise3.v: -------------------------------------------------------------------------------- 1 | Variables A B: Set. 2 | Variables P Q: A -> Prop. 3 | Theorem exercise3: 4 | (forall x:A, ~P x /\ Q x) -> (forall x:A, P x -> Q x). 5 | Proof. 6 | intros. 7 | apply H. 8 | Qed. -------------------------------------------------------------------------------- /homework5/counter.py: -------------------------------------------------------------------------------- 1 | # counter.py 2 | 3 | counter = 0 4 | 5 | 6 | def fresh_var(): 7 | global counter 8 | c = counter 9 | counter = counter + 1 10 | return 'x_'+(c.__str__()) 11 | -------------------------------------------------------------------------------- /homework2/exercise4.v: -------------------------------------------------------------------------------- 1 | Theorem exercise4: forall P Q R:Prop, 2 | (P /\ (Q /\ R)) -> ( (P /\ Q) /\ R). 3 | Proof. 4 | intros. 5 | inversion H. 6 | split. 7 | split. 8 | apply H0. 9 | apply H1. 10 | apply H. 11 | Qed. -------------------------------------------------------------------------------- /homework2/exercise6.v: -------------------------------------------------------------------------------- 1 | Theorem exercise6: forall P Q R:Prop, 2 | ((P->R)/\(Q->R))-> ((P/\Q)->R). 3 | Proof. 4 | intros. 5 | inversion H. 6 | inversion H0. 7 | apply H1 in H3. 8 | apply H2 in H4. 9 | apply H3. 10 | Qed. -------------------------------------------------------------------------------- /homework4/exercise1.v: -------------------------------------------------------------------------------- 1 | Theorem exercise1: forall P Q:Prop, 2 | ~(P \/ Q) -> ~P /\ ~Q. 3 | Proof. 4 | unfold not. 5 | intros. 6 | split. 7 | intros. 8 | apply H. 9 | left. 10 | apply H0. 11 | intros. 12 | apply H. 13 | right. 14 | apply H0. 15 | Qed. -------------------------------------------------------------------------------- /homework4/exercise9.v: -------------------------------------------------------------------------------- 1 | Variables A: Set. 2 | Variables P Q: A -> Prop. 3 | Theorem Exercise9: 4 | (exists x: A, ~P x ) -> ~(forall x:A, P x). 5 | Proof. 6 | intros. 7 | destruct H as [a p]. 8 | unfold not. 9 | intros. 10 | apply p in H. 11 | apply H. 12 | Qed. -------------------------------------------------------------------------------- /homework2/exercise5.v: -------------------------------------------------------------------------------- 1 | Theorem exercise5: forall P Q R:Prop, 2 | (P\/(Q\/R)) -> ((P\/Q)\/R). 3 | Proof. 4 | intros. 5 | inversion H. 6 | left. 7 | left. 8 | apply H0. 9 | inversion H0. 10 | left. 11 | right. 12 | apply H1. 13 | right. 14 | apply H1. 15 | Qed. -------------------------------------------------------------------------------- /homework4/exercise4.v: -------------------------------------------------------------------------------- 1 | Variables A: Set. 2 | Variables P Q: A -> Prop. 3 | Theorem Exercise4: 4 | (forall x: A, (P x -> Q x)) -> (forall x: A,~Q x) -> (forall x: A, ~P x). 5 | Proof. 6 | intros. 7 | intros H1. 8 | apply H in H1. 9 | apply H0 in H1. 10 | apply H1. 11 | Qed. -------------------------------------------------------------------------------- /homework4/exercise11.v: -------------------------------------------------------------------------------- 1 | Variables A: Set. 2 | Variables P Q: A -> Prop. 3 | Theorem Exercise11: 4 | (forall x: A, P x -> Q x) /\ (exists x:A, P x) -> exists x:A, Q x. 5 | Proof. 6 | intros. 7 | destruct H. 8 | destruct H0 as [a p]. 9 | exists a. 10 | apply H in p. 11 | apply p. 12 | Qed. -------------------------------------------------------------------------------- /homework7/exercise5.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | # Use I as an alias for IntSort() 4 | I = IntSort() 5 | # A is an array from integer to integer 6 | A = Array('A', I, I) 7 | x = Int('x') 8 | print(A[x]) 9 | print(Select(A, x)) 10 | print(Store(A, x, 10)) 11 | print(simplify(Select(Store(A, 2, x+1), 2))) 12 | -------------------------------------------------------------------------------- /homework5/README.md: -------------------------------------------------------------------------------- 1 | 地址:http://staff.ustc.edu.cn/~bjhua/courses/theory/2020/assignment/assign5/index.html 2 | 3 | partA 中的证明两个程序相等。 4 | 5 | partB 部分作业的目的是定义两套语法 calc 和 tac, 在 compiler 中可以将 calc 编译为 tac. 6 | 7 | 重点: 8 | - SSA: Static single assignment form, 即静态单赋值,这是一种中间表示形式,被称为单赋值的原因是每个名字在 SSA 中仅被赋值一次,同时尽在每个变量使用之前定义。 -------------------------------------------------------------------------------- /homework6/exercise.py: -------------------------------------------------------------------------------- 1 | from os import replace 2 | from z3 import * 3 | 4 | # exercise1 5 | x, y = Ints('x y') 6 | solve( 7 | x + y >= 2, 8 | 2*x - y >= 0, 9 | -x + 2*y >=1) 10 | 11 | # exercise2 12 | x, y = Reals('x y') 13 | solve( 14 | x + y >= 0.8, 15 | x + 5*y >= 0.2, 16 | x + 3*y <= 0) -------------------------------------------------------------------------------- /homework4/exercise10.v: -------------------------------------------------------------------------------- 1 | Variables A: Set. 2 | Variables P Q: A -> Prop. 3 | Theorem Exercise10: 4 | (forall x: A, P x -> ~Q x) -> ~(exists x:A, (P x /\ Q x)). 5 | Proof. 6 | intros. 7 | unfold not. 8 | intros. 9 | destruct H0 as [a p]. 10 | destruct p as [p1 p2]. 11 | apply H in p2. 12 | apply p2. 13 | apply p1. 14 | Qed. -------------------------------------------------------------------------------- /homework4/exercise5.v: -------------------------------------------------------------------------------- 1 | Variables A: Set. 2 | Variables P Q: A -> Prop. 3 | Theorem Exercise5: 4 | (forall x: A, (P x /\ Q x)) <-> (forall x: A, P x) /\ (forall x:A, Q x). 5 | Proof. 6 | split. 7 | intros. 8 | split. 9 | apply H. 10 | apply H. 11 | intros. 12 | inversion H. 13 | split. 14 | apply H0. 15 | apply H1. 16 | Qed. -------------------------------------------------------------------------------- /homework4/exercise7.v: -------------------------------------------------------------------------------- 1 | Variables A: Set. 2 | Variables P Q: A -> Prop. 3 | Theorem Exercise7: 4 | (exists x: A, (~P x /\ ~Q x)) -> (exists x:A, ~(P x /\ Q x)). 5 | Proof. 6 | intros. 7 | destruct H as [a p]. 8 | exists a. 9 | unfold not. 10 | intros. 11 | inversion p. 12 | inversion H. 13 | apply H0. 14 | apply H2. 15 | Qed. -------------------------------------------------------------------------------- /homework4/exercise12.v: -------------------------------------------------------------------------------- 1 | Variables A: Set. 2 | Variables P Q R: A -> Prop. 3 | Theorem Exercise12: 4 | (exists x: A, P x /\ Q x) /\ (forall x:A, P x -> R x) -> exists x:A, R x /\ Q x. 5 | Proof. 6 | intros. 7 | destruct H. 8 | destruct H as [a p]. 9 | exists a. 10 | destruct p. 11 | split. 12 | apply H0 in H. 13 | apply H. 14 | apply H1. 15 | Qed. -------------------------------------------------------------------------------- /homework4/exercise6.v: -------------------------------------------------------------------------------- 1 | Variables A: Set. 2 | Variables P Q: A -> Prop. 3 | Theorem Exercise6: 4 | (exists x: A, (~P x \/ Q x)) -> (exists x:A, ~(P x /\ ~Q x)). 5 | Proof. 6 | intros. 7 | destruct H as [a p]. 8 | exists a. 9 | unfold not. 10 | intros. 11 | inversion p. 12 | inversion H. 13 | apply H0. 14 | apply H1. 15 | inversion H. 16 | apply H2 in H0. 17 | apply H0. 18 | Qed. -------------------------------------------------------------------------------- /homework6/task_scheduling.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | # TODO: Challenge: Task Scheduling 4 | # Task Scheduling can be treated as a optimizing problem, too. 5 | 6 | # Modeling the problem: use "selected[i] = 1" means task i is selected. Otherwise "selected[i] = 0". 7 | # Modeling the constraint: use "selected[i] + selected[j] <= 1" to represent that task j overlaps with task i. 8 | # Goal: max() 9 | 10 | 11 | """Your code here""" -------------------------------------------------------------------------------- /homework9/README.md: -------------------------------------------------------------------------------- 1 | 地址:http://staff.ustc.edu.cn/~bjhua/courses/theory/2020/assignment/assign9/index.html 2 | 3 | - imp_ast.py: 相较于 homework8 中的 ast.py, 增加了几个结构和函数, 例如 ExpUni, exp_num_nodes. 4 | - prover.py: 转化为 z3 后验证 5 | 6 | #### backward 7 | - backward.py: 反向 8 | - gen_prog.py: 生成一个测试脚本 9 | - large_prog.py: gen_prog.py 生成的脚本 10 | 11 | #### forwoard 12 | - tac.py: 提供 Three Address Code 的结构。 13 | - compiler.py: 14 | - forward.py: -------------------------------------------------------------------------------- /homework8/README.md: -------------------------------------------------------------------------------- 1 | 地址:http://staff.ustc.edu.cn/~bjhua/courses/theory/2020/assignment/assign8/index.html 2 | 3 | 脚本说明: 4 | - ast.py: C-- 语言的语法树 5 | - printer.py: 用来检查 ast.py 写的是否正确 6 | - pymp.py: multiprocessing 的学习 7 | - concrete.py: 实现 concrete execution. 8 | - symbolic.py: 实现 symbolic execution. 9 | - concolic.py: 实现 concolic execution. 10 | 11 | ----------------- 12 | 13 | 重点: 14 | - Concrete execution: 15 | - big step: 16 | - samll step: 17 | - Symbolic execution: 18 | - Concolic execution: -------------------------------------------------------------------------------- /homework4/exercise8.v: -------------------------------------------------------------------------------- 1 | Variables A: Set. 2 | Variables P Q: A -> Prop. 3 | Theorem Exercise8: 4 | (exists x: A, (P x \/ Q x)) <-> (exists x:A, P x) \/ (exists x:A, Q x). 5 | Proof. 6 | split. 7 | intros. 8 | destruct H as [a p]. 9 | inversion p. 10 | left. 11 | exists a. 12 | apply H. 13 | right. 14 | exists a. 15 | apply H. 16 | intros. 17 | inversion H. 18 | destruct H0 as [a p]. 19 | exists a. 20 | left. 21 | apply p. 22 | destruct H0 as [a p]. 23 | exists a. 24 | right. 25 | apply p. 26 | Qed. -------------------------------------------------------------------------------- /homework4/exercise2.v: -------------------------------------------------------------------------------- 1 | Theorem exercise2: forall P Q R: Prop, 2 | P /\ (Q\/R) <-> (P/\Q) \/ (P/\R). 3 | Proof. 4 | split. 5 | intros. 6 | destruct H as [H1 H2]. 7 | inversion H2. 8 | left. 9 | split. 10 | apply H1. 11 | apply H. 12 | right. 13 | split. 14 | apply H1. 15 | apply H. 16 | intros. 17 | inversion H. 18 | split. 19 | inversion H0. 20 | apply H1. 21 | inversion H0. 22 | left. 23 | apply H2. 24 | split. 25 | inversion H0. 26 | apply H1. 27 | inversion H0. 28 | right. 29 | apply H2. 30 | Qed. 31 | -------------------------------------------------------------------------------- /homework7/exercise2.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | class Todo(Exception): 4 | pass 5 | 6 | x, y = BitVecs('x y', 32) 7 | 8 | # Given two bit vectors, to compute their average: 9 | def poc_of_overflow(x, y): 10 | solver = Solver() 11 | solver.add(x >=1, y == 4, x*y < 0) 12 | res = solver.check() 13 | if res == sat: 14 | print('found an poc for integer overflow: ', solver.model()) 15 | else: 16 | print('success!') 17 | # 536870912 * 4 = 2147483647 = 2**31 > 2**31 - 1 18 | if __name__ == '__main__': 19 | poc_of_overflow(x, y) -------------------------------------------------------------------------------- /homework7/exercise6.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | # Exercise 6: to prove Store(A, i, x)[i]>=x 4 | 5 | class Todo(Exception): 6 | pass 7 | 8 | # First we define some basic var types 9 | A = Array('A', IntSort(), IntSort()) 10 | x = Int('x') 11 | i = Int('i') 12 | 13 | # This function returns the above formulae: 14 | # Store(A, i, x)[i]>=x 15 | # Now you should fill in the definition of the above formulae: 16 | def gen_formulae(): 17 | """Fill your code here""" 18 | B = Store(A, i, x) 19 | return B 20 | 21 | def prove(P): 22 | solve(Not(Select(P,i) >= x)) 23 | 24 | if __name__ == '__main__': 25 | P = gen_formulae() 26 | prove(P) 27 | -------------------------------------------------------------------------------- /homework5/exercise2.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | # Before we presenting the EUF theory, we first introduce some Z3's 4 | # facilities to define terms and functions. 5 | 6 | ######################################## 7 | # Sort, term, formula 8 | 9 | # In Z3, we can define sorts, we can simply think them as sets. 10 | # This code: 11 | S = DeclareSort('S') 12 | f = Function('f', S, S) 13 | x1, x2, x3, x4, x5 = Consts('x1 x2 x3 x4 x5', S) 14 | solve(x1 == x2, x2 == x3, x4 == x5, x5 != x1, f(x1) != f(x3)) 15 | # what's Z3's output? And why that output? 16 | ''' 17 | no solution 18 | 因为 x1 和 x3 属于相等,在一个并查集中,因此 f(x1) != f(x3) 返回的结果为 False, 最终导致 no solution. 19 | ''' 20 | # 修改 21 | solve(x1 == x2, x2 == x3, x4 == x5, x5 != x1, f(x1) == f(x3)) 22 | 23 | -------------------------------------------------------------------------------- /homework3/README.md: -------------------------------------------------------------------------------- 1 | 地址:http://staff.ustc.edu.cn/~bjhua/courses/theory/2020/assignment/assign3/index.html 2 | 3 | SAT, z3 4 | 5 | 重点: 6 | - 输出所有满足 SAT 的 boolean 值:当得到一个结果时,否认这个结果(哪个 命题 值为 true 则将它取 Not), 再与原命题做 /\, 之后再检验可满足性。 7 | - valid(P) <==> unsat(~P), valid 意为 永真 8 | - dpll 算法:相较于枚举真值表(2^n)来检测可满足性,dpll 是一种更省时间的算法, 9 | ```cpp 10 | // 伪代码描述 11 | dpll( P){ 12 | if(P == T) { 13 | return sat; 14 | } else if (P == F) { 15 | return unsat; 16 | } 17 | 18 | unitProp(P); // unit prop and simplify P 19 | x = select_atomic(P) // choose an atomic prop 20 | if ( dpll( P[x] -> T)){ // splitiing 21 | return sat; 22 | } 23 | return dpll( P[x] -> F); 24 | } 25 | ``` 26 | - NNF: Negation normal form, 即否定范式,否定联结符的联结对象只是命题原子的公式 27 | - CNF: Conjunctive normal form, 即合取范式,若干个析取子句的合取 -------------------------------------------------------------------------------- /homework7/exercise7.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | # Exercise 7: Verify Store(A, i*i - i*i, x)[0]>=x 4 | 5 | class Todo(Exception): 6 | pass 7 | 8 | # We already discussed the problem 9 | # Store(A, i*i - i*i, x)[0]>=x 10 | # is undecidable because it contains non-linear arithmetic. 11 | # Now try to convert it into a Z3 formulae and investigate the output. 12 | # Whether it's "unknown" or not? 13 | # What's the reason? 14 | 15 | a = Array('a', IntSort(), IntSort()) 16 | x = Int('x') 17 | i = Int('i') 18 | 19 | def gen_formulae(): 20 | """Fill your code here""" 21 | b = Store(a, i * i - i * i, x) 22 | return b 23 | 24 | def prove(P): 25 | solve(Not(Select(P, 0) >= x)) 26 | 27 | if __name__ == '__main__': 28 | P = gen_formulae() 29 | prove(P) 30 | # It's print: no solution, not "unknown" 31 | # In my view, although i * i maybe exceed 2^31 - 1, but i * i equal i * i, so the result is not "unkonwn" -------------------------------------------------------------------------------- /homework5/equiv.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | class Todo(Exception): 4 | pass 5 | 6 | # program equivalence: 7 | # in the class, we present two implementation of the same algorithms, one 8 | # is: 9 | ''' 10 | int power3(int in){ 11 | int i, out_a; 12 | out_a = in; 13 | for(i = 0; i < 2; i++) 14 | out_a = out_a * in; 15 | return out_a; 16 | } 17 | ''' 18 | # and the other one is: 19 | ''' 20 | int power3_new(int in){ 21 | int out_b; 22 | out_b = (in*in)*in; 23 | return out_b; 24 | } 25 | 26 | ''' 27 | # and with EUF, we can prove that these two algorithm are equivalent, 28 | # that is: 29 | # P1/\P2 -> out_a==out_b 30 | 31 | # Please construct, manually, the propositions P1 and P2, and let Z3 32 | # prove the above implication. (Note that you don't need to generate 33 | # P1 or P2 automatically, just write down them manually.) 34 | # TODO: your code here: 35 | # P1 = ... 36 | # P2 = ... 37 | # solve(...) 38 | 39 | S = DeclareSort('S') 40 | f = Function('f', S,S, S) 41 | in_ = Const('in_', S) 42 | output_a_0, output_a_1, output_a_2, output_b = Consts('output_a_0 output_a_1 output_a_2 output_b', S) 43 | P1 = And( output_a_0 == in_, output_a_1 == f(output_a_0, in_), output_a_2 == f(output_a_1, in_)) 44 | P2 = output_b == f( f(in_,in_), in_) 45 | F = Implies( And(P1,P2), output_a_2 == output_b) 46 | solve(F) -------------------------------------------------------------------------------- /homework7/exercise1.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | 4 | class Todo(Exception): 5 | pass 6 | 7 | 8 | x, y = BitVecs('x y', 32) 9 | # Given two bit vectors, to compute their average: 10 | def int_average(x, y): 11 | ''' 12 | add your implementation here: 13 | pay attention: 14 | z3 中的 BitVec 是有符号的二进制数字 15 | for example: 16 | z = BitVec('z',2) 17 | solve(z == -1) # [z=3] 18 | solve(z == 1) # [z=1] 19 | 因此要使用 LShR, 逻辑右移 20 | ''' 21 | t = (x&y) + ((x^y)>>1) 22 | return t + (LShR(t,31) & (x^y)) 23 | 24 | 25 | # we've given this correct implementation for you, but this is a 26 | # special hack, you should not copy this code as your implementation. 27 | def int_average_correct(x, y): 28 | ex = SignExt(1, x) 29 | ey = SignExt(1, y) 30 | result_correct = (ex+ey)/2 31 | return Extract(31, 0, result_correct) 32 | 33 | 34 | if __name__ == '__main__': 35 | result1 = int_average(x, y) 36 | result2 = int_average_correct(x, y) 37 | solver = Solver() 38 | solver.add() 39 | res = solver.check(result1 != result2) 40 | if res == sat: 41 | print("Failed: your implementation is wrong!") 42 | m = solver.model() 43 | print('The counter example is: ', m) 44 | else: 45 | print('Exercise 1: Success!') -------------------------------------------------------------------------------- /homework8/printer.py: -------------------------------------------------------------------------------- 1 | from ast import * 2 | 3 | 4 | test_stms = [StmAssign('s', ExpNum(0)), 5 | StmAssign('i', ExpNum(0)), 6 | StmWhile(ExpBop(ExpVar('i'), ExpBop(ExpVar('n'), ExpNum(3), BOp.MIN), BOp.LE), 7 | [StmAssign('s', ExpBop(ExpVar('s'), ExpVar('i'), BOp.ADD)), 8 | StmAssign('i', ExpBop(ExpVar('i'), ExpNum(1), BOp.ADD)), 9 | StmIf(ExpBop(ExpVar('s'), ExpVar('i'), BOp.GT), 10 | [StmAssign("b", ExpBop(ExpVar('s'), ExpNum(1), BOp.MIN))], 11 | []) 12 | ]), 13 | StmIf(ExpBop(ExpVar('s'), ExpVar('i'), BOp.GT), 14 | [StmAssign("s", ExpBop(ExpVar('i'), ExpNum(1), BOp.MIN))], 15 | [StmAssign("s", ExpBop(ExpVar('i'), ExpNum(1), BOp.ADD))]) 16 | ] 17 | 18 | test_func = Function(name='printer_test', args=['n'], stms=test_stms, ret=ExpVar('s')) 19 | 20 | # your code should print like: 21 | # 22 | # printer_test(n){ 23 | # s = 0; 24 | # i = 0; 25 | # while(i <= (n - 3)){ 26 | # s = s + i; 27 | # i = i + 1; 28 | # if(s > i){ 29 | # b = s - 1; 30 | # } 31 | # } 32 | # if(s > i){ 33 | # s = i - 1; 34 | # } 35 | # else{ 36 | # s = i + 1; 37 | # } 38 | # return s; 39 | # } 40 | # 41 | print(test_func) 42 | -------------------------------------------------------------------------------- /homework6/constraint.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class Relation(Enum): 5 | GE = ">=" 6 | LE = "<=" 7 | 8 | 9 | class IllegalConstraintError(Exception): 10 | def __init__(self, constraint): 11 | self.constraint = constraint 12 | 13 | def __str__(self): 14 | return f"Illegal constraint: {self.constraint}" 15 | 16 | 17 | class Constraint: 18 | '''构建 Constraint 类 19 | coefficients 为一个 list, 下标为 i 的值为 x_i 的系数 20 | value 为右侧的值 21 | relation 为类型 >= or <= 22 | ''' 23 | def __init__(self, coefficients, value, relation=Relation.GE): 24 | ''' 25 | default: >= 26 | ''' 27 | self.coefficients = coefficients 28 | self.value = value 29 | self.relation = relation 30 | 31 | def __str__(self): 32 | coefficients_str = "" 33 | for idx, value in enumerate(self.coefficients): 34 | if idx == 0: 35 | coefficients_str += f"{value}*x{idx}" 36 | elif value > 0: 37 | coefficients_str += f" + {value}*x{idx}" 38 | elif value < 0: 39 | coefficients_str += f" - {abs(value)}*x{idx}" 40 | 41 | return f"{coefficients_str} {self.relation.value} {self.value}" 42 | 43 | 44 | if __name__ == '__main__': 45 | A = [Constraint([1, 1], 2), Constraint([2, -1], 0), Constraint([-1, 2], 1, Relation.LE)] 46 | for constr in A: 47 | print(constr) 48 | -------------------------------------------------------------------------------- /homework8/pymp.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import multiprocessing as mp 4 | from collections import namedtuple 5 | from datetime import datetime 6 | 7 | 8 | # a utility class to represent the code you should fill in. 9 | class Todo(Exception): 10 | pass 11 | 12 | 13 | Timer = namedtuple('Timer', ('pid', 'time')) 14 | 15 | 16 | def timer(interval, result): 17 | for i in range(5): 18 | time.sleep(interval) 19 | # TODO: Exercise 4 Code Here 20 | print( Timer(os.getpid(), time.time())) 21 | 22 | if __name__ == '__main__': 23 | # TODO: Exercise 4: Start two timers which record time with different 24 | # intervals, use Queue or SimpleQueue to gather the result. 25 | # 26 | # example output: 27 | # 28 | # Timer(pid=39834, time='2020-06-15 05:39:07.986') 29 | # Timer(pid=39835, time='2020-06-15 05:39:08.988') 30 | # Timer(pid=39834, time='2020-06-15 05:39:08.990') 31 | # Timer(pid=39834, time='2020-06-15 05:39:09.993') 32 | # Timer(pid=39835, time='2020-06-15 05:39:10.993') 33 | # Timer(pid=39834, time='2020-06-15 05:39:10.996') 34 | # Timer(pid=39834, time='2020-06-15 05:39:11.999') 35 | # Timer(pid=39835, time='2020-06-15 05:39:12.997') 36 | # Timer(pid=39835, time='2020-06-15 05:39:15.001') 37 | # Timer(pid=39835, time='2020-06-15 05:39:17.005') 38 | # 39 | p = mp.Process( target=timer, args=(1,'')) 40 | p.start() 41 | timer(1,'') 42 | p.join() -------------------------------------------------------------------------------- /homework6/pandas_exercise.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | # Here you have to do some exercises to familiarize yourself with pandas. 4 | # Especially some basic operations based on pd.Series and pd.DataFrame 5 | 6 | # TODO: Create a Series called `ser`: 7 | # x1 1.0 8 | # x2 -1.0 9 | # x3 2.0 10 | # Your code here 11 | ser = pd.Series([1.0, -1.0, 2.0],index=['x1','x2','x3']) 12 | 13 | # TODO: Create a DataFrame called `df`: 14 | # x0 x1 x2 15 | # s0 -1.1 0.8 -2.5 16 | # s1 -1.3 -1.0 -1.2 17 | # s2 1.7 1.8 2.1 18 | # s3 0.9 0.3 1.1 19 | 20 | # Your code here 21 | df = pd.DataFrame( 22 | [[-1.1, 0.8, -2.5], 23 | [-1.3, -1.0, -1.2], 24 | [-1.7, 1.8, -2.1], 25 | [-0.9, 0.3, 1.1],], 26 | index=['s0','s1','s2','s3'], 27 | columns=['x0','x1','x2'] 28 | ) 29 | 30 | 31 | # TODO: select `df` by column="x1": 32 | print( df['x1']) 33 | 34 | # TODO: select `df` by third row and first column: 35 | print(df.iloc[2,0]) 36 | 37 | # TODO: change `df`'s column's name x0 to y0: 38 | df = df.rename( columns={'x0':'y0'}) 39 | 40 | # TODO: select `df` where column's name start with x: 41 | print( df[df.columns[df.columns.str.startswith('x')]]) 42 | 43 | # TODO: change `ser`'s index to [y0,x1,x2]: 44 | ser.index = df.columns 45 | 46 | # TODO: change `df` where column y0 multiply -1.5: 47 | df['y0'] = df['y0'] * -1.5 48 | # TODO: calculate `df` dot `ser`: 49 | print(df.dot(ser)) 50 | 51 | # TODO: merge `ser` with the result of previous task: 52 | df.append(ser, ignore_index=True) 53 | -------------------------------------------------------------------------------- /homework6/01knapsack.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | 4 | # We've been talking a lot of the satisfying problem, but using 5 | # tools like Z3, we can also solve optimization problem. 6 | # the 0-1 knapsack problem is often solved by the dynamic 7 | # programming algorithm. But it's more natural and easier 8 | # to solve with the LA theory. 9 | # TODO: Exercise 6. 0-1 Knapsack problem. 10 | # There are n items, with specific weight 11 | # W = {w1, ..., wn} 12 | # and value: 13 | # V = {v1, ..., vn} 14 | # For a given knapsack of capacity C, to choose some items 15 | # such that: 16 | # wi+...+wk <= C 17 | # and max(vi+...+vk). 18 | # 19 | # Now consider below condition: 20 | # W = {4, 6, 2, 2, 5, 1} 21 | # V = {8, 10, 6, 3, 7, 2}, 22 | # C = 12 23 | # Solve it with Z3. 24 | 25 | W = [4, 6, 2, 2, 5, 1] 26 | V = [8, 10, 6, 3, 7, 2] 27 | C = 12 28 | # create an optimizer 29 | solver = Optimize() 30 | vars = [Int('var_%d' % i) for i in range(len(W))] 31 | weights = [] 32 | values = [] 33 | 34 | # Initialize weights and values 35 | for i in range(len(W)): 36 | weights.append( vars[i] * W[i]) 37 | values.append( vars[i] * V[i]) 38 | 39 | # Add constraint wi+...+wk <= C 40 | """your code here""" 41 | solver.add( [Or( vars[i] == 0, vars[i] == 1) for i in range(len(W))]) 42 | solver.add( Sum(weights) <= C) 43 | 44 | # Solve it via maximize 45 | solver.maximize(sum(values)) 46 | print(solver.check()) 47 | maxValue = 0 48 | m = solver.model() 49 | for i in range(len(W)): 50 | if m[vars[i]] == 1: 51 | print(W[i], ': ', V[i]) 52 | maxValue += V[i] 53 | 54 | print('max value: ', maxValue) 55 | 56 | -------------------------------------------------------------------------------- /homework7/exercise3.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | 4 | class Todo(Exception): 5 | pass 6 | 7 | x, y = BitVecs('x y', 32) 8 | 9 | # Given two bit vectors, computer their multiplication, return two value: 10 | # an overflow flag, and the result (after rounding). 11 | # For instance, for x=1, y=2, return (False, 2). 12 | # for x=0x80000000, y=2, return (True, 0) 13 | def mult_with_overflow(x, y): 14 | '''检查 x * y 是否溢出 15 | add your implementation here: 16 | ''' 17 | INT_MAX = 2**31-1 18 | if simplify(x >= 0) and simplify(y >= 0): 19 | if simplify((INT_MAX / x) < y): 20 | return True, 0 21 | else: 22 | return False, simplify(x * y) 23 | elif simplify(x<0) and simplify(y<0): 24 | if simplify((INT_MAX / x) > y): 25 | return True, 0 26 | else: 27 | return False, simplify(x * y) 28 | elif x * y == -2**32: 29 | return True, 0 30 | elif simplify(x < 0): 31 | return mult_with_overflow( simplify(x<<1>>1), y) 32 | else: 33 | return mult_with_overflow(x, simplify(y<<1>>1)) 34 | 35 | 36 | if __name__ == '__main__': 37 | # some unit tests 38 | x = BitVecVal(1, 32) 39 | y = BitVecVal(2, 32) 40 | of, res = mult_with_overflow(x, y) 41 | if not((not of) and res == 2): 42 | print("Wrong!") 43 | else: 44 | pass 45 | x = BitVecVal(0x80000000, 32) 46 | y = BitVecVal(2, 32) 47 | of, res = mult_with_overflow(x, y) 48 | # some unit tests 49 | if not (of and res == 0): 50 | print("Wrong!") 51 | else: 52 | pass 53 | 54 | -------------------------------------------------------------------------------- /homework9/gen_prog.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | def generate(n: int): 5 | f = open('large_prog.py', "w+") 6 | f.write("from imp_ast import *\n") 7 | f.write("import backward\n") 8 | f.write("\n") 9 | 10 | # the program 11 | f.write("fun_large_if = Function('large_if',\n\ 12 | ['x', 'y'],\n\ 13 | [\n") 14 | i = 0 15 | while i < n: 16 | f.write(" " * 12) 17 | f.write("StmIf(ExpBop(ExpVar('x'), ExpNum(") 18 | f.write(i.__str__()) 19 | f.write("), BOp.LT), [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(") 20 | f.write(i.__str__()) 21 | f.write("), BOp.ADD))], [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(") 22 | f.write((i+1).__str__()) 23 | f.write("), BOp.ADD))])") 24 | if i != n-1: 25 | f.write(', ') 26 | f.write('\n') 27 | i = i+1 28 | f.write(" " * 12) 29 | f.write("],\n") 30 | f.write(" " * 12) 31 | f.write("ExpVar('y'),\n") 32 | f.write(" " * 12) 33 | f.write("ExpBop(ExpVar('y'), ExpNum(0), BOp.GT),\n") 34 | f.write(" " * 12) 35 | f.write("ExpBop(ExpVar('y'), ExpNum(0), BOp.GT))\n") 36 | 37 | # diver 38 | f.write("\n\nif __name__ == '__main__':\n") 39 | f.write(" the_vc = backward.vc(fun_large_if)\n") 40 | f.write(" print(exp_num_nodes(the_vc))\n") 41 | f.write("\n") 42 | 43 | f.close() 44 | 45 | 46 | if __name__ == '__main__': 47 | start_time = time.time() 48 | num_ifs = sys.argv[1] 49 | generate(int(num_ifs)) 50 | end_time = time.time() 51 | print(end_time - start_time, 's') 52 | -------------------------------------------------------------------------------- /homework6/simplex.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import pandas as pd 4 | from pandas.testing import assert_series_equal 5 | 6 | from constraint import Constraint, IllegalConstraintError 7 | from tableau import Tableau 8 | 9 | 10 | def simplex(constraints): 11 | result = {} 12 | if not constraints: 13 | return result 14 | 15 | print("===>Solving Constraints:") 16 | basic_var_amount = len(constraints[0].coefficients) 17 | for constraint in constraints: 18 | if len(constraint.coefficients) != basic_var_amount: 19 | raise IllegalConstraintError(constraint) 20 | print(constraint) 21 | 22 | tab = Tableau(constraints) 23 | 24 | # TODO: finish the simplex algorithm 25 | # if there is no solution, return string "no solution" 26 | # if find a solution, return the result as dict: e.g {"x0": 1, "x1": 1} 27 | # feel free to change the code here or add new class but your code should pass the unittest 28 | 29 | # Your code here 30 | 31 | print(f"===>Solving result is: {result}") 32 | return result 33 | 34 | 35 | class TestSimplex(unittest.TestCase): 36 | 37 | def test_simplex_sat(self): 38 | case = [Constraint([1, 1], 2), Constraint([2, -1], 0), Constraint([-1, 2], 1)] 39 | result = simplex(case) 40 | assert_series_equal(pd.Series(result), pd.Series({"x0": 1.0, "x1": 1.0})) 41 | 42 | def test_simplex_unsat(self): 43 | case = [Constraint([-1, 1, 0], 0), Constraint([-1, 0, 1], 0), Constraint([1, -1, -2], 0), 44 | Constraint([0, 0, 1], 1)] 45 | result = simplex(case) 46 | self.assertEqual(result, "no solution") 47 | 48 | 49 | if __name__ == '__main__': 50 | unittest.main() 51 | -------------------------------------------------------------------------------- /homework6/four_queen.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | import numpy as np 3 | # TODO: Exercise 8 4 | # Here the basic requirement is to solve Four Queens Problem 5 | # But we also encourage you to try to implement a common method that can solve 6 | # N queens which N can be arbitrary value.(Here we do not consider N to be a huge 7 | # value). 8 | 9 | # Init our board with N = 4 10 | N = 8 11 | board = [[Int('i_{}_{}'.format(i, j))for i in range(N)] 12 | for j in range(N)] 13 | 14 | # TODO: Complete the remains. 15 | def queens_quiz(N, board): 16 | solver = Solver() 17 | # 只能是 0 或 1, 分别代表该位置 无皇后,有皇后 18 | solver.add( [Or(board[i][j] == 0, board[i][j] == 1) for i in range(N) for j in range(N)] ) 19 | # 行 20 | solver.add( [Sum( board[i]) == 1 for i in range(N) ]) 21 | # 列 22 | temp = [ list(i) for i in np.array(board).T] 23 | solver.add( [ Sum( temp[i]) == 1 for i in range(N)]) 24 | # 正对角线 25 | solver.add( [ Sum(i) <= 1 for i in [[board[i][0]] + [ board[i+j][j] for j in range(1,N) if i + j < N] for i in range(N)]] + [Sum(i) <= 1 for i in [[board[0][i]] + [ board[j][i+j] for j in range(1,N) if i + j < N] for i in range(N)]]) 26 | # 反对角线 27 | solver.add( [ Sum(i) <= 1 for i in [[board[0][i]] + [board[j][i-j] for j in range(1,N) if i - j >= 0] for i in range(N)]] + [Sum(i) <= 1 for i in [[board[i][N-1]] + [ board[i+j][N-1-j] for j in range( 1,N) if i + j < N and N - i - j >= 0] for i in range(N)]]) 28 | 29 | while solver.check() == sat: 30 | m = solver.model() 31 | block = [] 32 | for i in board: 33 | for j in i: 34 | if m[j] == 1: 35 | block.append(j == 1) 36 | print(block) 37 | solver.add(Not(And(block))) 38 | 39 | if __name__ == "__main__": 40 | queens_quiz(N,board) 41 | -------------------------------------------------------------------------------- /homework5/exercise1.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | # Before we presenting the EUF theory, we first introduce some Z3's 4 | # facilities to define terms and functions. 5 | 6 | ######################################## 7 | # Sort, term, formula 8 | 9 | # In Z3, we can define sorts, we can simply think them as sets. 10 | # This code: 11 | S = DeclareSort('S') 12 | 13 | # declares a new sort (although abstract) called S. 14 | # The sort can contain constants: 15 | e = Const('e', S) 16 | 17 | # Z3 has some builtin sort: 18 | # Bool, Int, Real, BitVec n, Array, Index, Elem, String, Seq S. 19 | # which can be used directly. 20 | 21 | # We can define functions: 22 | f = Function('f', S, S) 23 | g = Function('g', S, S, S) 24 | # this is a unary function from sort S to sort S. 25 | # we can solve the congruence rule: 26 | # e is a constant from S. 27 | 28 | # And e has some intrinsic property, for example, the reflexivity. 29 | # Hence, the following proposition is unsat: 30 | solve(e != e) 31 | solve(e == f(e)) 32 | solve(e == f(g(e, e))) 33 | 34 | 35 | # the example from the lecture: 36 | x1, x2, x3, x4, x5 = Consts('x1 x2 x3 x4 x5', S) 37 | solve(x1 == x2, x2 == x3, x4 == x5, x5 != x1, f(x1) != f(x3)) 38 | # with the result "no solutio n". 39 | 40 | # If we change the disequality to equality: 41 | solve(x1 == x2, x2 == x3, x4 == x5, x5 != x1, f(x1) == f(x3)) 42 | # this will give the following solution: 43 | ''' 44 | [x3 = S!val!1, 45 | x5 = S!val!0, 46 | x4 = S!val!0, 47 | x1 = S!val!1, 48 | x2 = S!val!1] 49 | ''' 50 | # note that S!val!0, S!val!1 are distinct values. 51 | 52 | # Let's study the translation validation we presented in the lecture: 53 | t1, t2, y1, y2, z = Consts('t1 t2 y1 y2 z', S) 54 | f = Function('f', S, S, S) 55 | g = Function('g', S, S, S) 56 | F1 = And(t1 == f(x1, y1), t2 == f(x2, y2), z == g(t1, t2)) 57 | F2 = And(z == g(f(x1, y1), f(x2, y2))) 58 | F = Implies(F1, F2) 59 | solve(Not(F)) 60 | solve(F) 61 | 62 | 63 | -------------------------------------------------------------------------------- /homework9/prover.py: -------------------------------------------------------------------------------- 1 | import z3 2 | import imp_ast 3 | 4 | 5 | class Todo(Exception): 6 | pass 7 | 8 | 9 | def vc_2_z3(vc: imp_ast.Exp): 10 | if isinstance(vc, imp_ast.ExpNum): 11 | return vc.num 12 | 13 | if isinstance(vc, imp_ast.ExpVar): 14 | return z3.Int(vc.var) 15 | 16 | # TODO: your Exercise 5 code here, convert the generated 17 | # vc to z3 constraints format, 18 | # also do not forget to deal with ExpUni, Z3 is often 19 | # able to handle formulas involving quantifiers. like: 20 | # ForAll([x, y], f(x, y) == 0) 21 | if isinstance(vc, imp_ast.ExpBop): 22 | left = vc_2_z3(vc.left) 23 | right = vc_2_z3(vc.right) 24 | 25 | if vc.bop == imp_ast.BOp.ADD: 26 | return left + right 27 | elif vc.bop == imp_ast.BOp.MIN: 28 | return left - right 29 | elif vc.bop == imp_ast.BOp.MUL: 30 | return left * right 31 | elif vc.bop == imp_ast.BOp.DIV: 32 | return left / right 33 | elif vc.bop == imp_ast.BOp.EQ: 34 | return left == right 35 | elif vc.bop == imp_ast.BOp.NE: 36 | return left != right 37 | elif vc.bop == imp_ast.BOp.GT: 38 | return left > right 39 | elif vc.bop == imp_ast.BOp.GE: 40 | return left >= right 41 | elif vc.bop == imp_ast.BOp.LT: 42 | return left < right 43 | elif vc.bop == imp_ast.BOp.LE: 44 | return left <= right 45 | elif vc.bop == imp_ast.BOp.IM: 46 | return z3.Implies( left, right) 47 | elif vc.bop == imp_ast.BOp.AND: 48 | return z3.And(left,right) 49 | elif vc.bop == imp_ast.BOp.OR: 50 | return z3.Or(left, right) 51 | if isinstance(vc, imp_ast.ExpNeg): 52 | return z3.Not( vc_2_z3( vc.exp)) 53 | if isinstance(vc, imp_ast.ExpUni): 54 | exp = vc_2_z3(vc.exp) 55 | return z3.ForAll(z3.Ints(list(vc.vars_set)), exp) 56 | 57 | 58 | def prove_vc(vc: imp_ast) -> bool: 59 | solver = z3.Solver() 60 | vc_z3 = vc_2_z3(vc) 61 | # debugging: 62 | print(vc_z3) 63 | solver.add(z3.Not(vc_z3)) 64 | res = solver.check() 65 | if res == z3.unsat: 66 | return True 67 | else: 68 | print(solver.model()) 69 | return False 70 | -------------------------------------------------------------------------------- /homework9/compiler.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | from typing import List 3 | import imp_ast 4 | import tac 5 | 6 | 7 | ############################################### 8 | # a counter 9 | counter = 0 10 | 11 | 12 | def counter_next(): 13 | global counter 14 | counter = counter + 1 15 | return f"L_{counter}" 16 | 17 | 18 | ############################################### 19 | # to compile one statement 20 | def compile_stm(s): 21 | if isinstance(s, imp_ast.StmAssign): 22 | result.append(tac.StmAssign(s.var, s.exp)) 23 | return 24 | if isinstance(s, imp_ast.StmIf): 25 | tb = counter_next() 26 | fb = counter_next() 27 | rb = counter_next() 28 | new_stm = tac.StmIf(s.exp, tb, fb, -1, -1) 29 | result.append(new_stm) 30 | result.append(tac.StmLabel(tb)) 31 | compile_stms(s.then_stms) 32 | result.append(tac.StmGoto(rb, -1)) 33 | result.append(tac.StmLabel(fb)) 34 | compile_stms(s.else_stms) 35 | result.append(tac.StmGoto(rb, -1)) 36 | result.append(tac.StmLabel(rb)) 37 | return 38 | if isinstance(s, imp_ast.StmWhile): 39 | entry = counter_next() 40 | tb = counter_next() 41 | rb = counter_next() 42 | result.append(tac.StmLabel(entry)) 43 | result.append(tac.StmInv(s.inv, s.modified_vars)) 44 | result.append(tac.StmIf(s.exp, tb, rb, -1, -1)) 45 | result.append(tac.StmLabel(tb)) 46 | compile_stms(s.stms) 47 | result.append(tac.StmGoto(entry, -1)) 48 | result.append(tac.StmLabel(rb)) 49 | return 50 | 51 | 52 | result = [] 53 | # to compile a list of statements: 54 | def compile_stms(stms: List[imp_ast.Stm]): 55 | for s in stms: 56 | compile_stm(s) 57 | 58 | 59 | ############################################### 60 | # to compile a function: 61 | def compile_fun(f: imp_ast.Function) -> tac.Function: 62 | global result 63 | result = [] 64 | compile_stms(f.stms) 65 | result.append(tac.StmReturn(f.ret)) 66 | return tac.Function(f.name, 67 | f.args, 68 | result, 69 | f.pre, 70 | f.post) 71 | 72 | 73 | if __name__ == '__main__': 74 | f = compile_fun(imp_ast.fun_foo) 75 | print(f) 76 | f = tac.assemble(f) 77 | print(f) 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /homework6/README.md: -------------------------------------------------------------------------------- 1 | 地址:http://staff.ustc.edu.cn/~bjhua/courses/theory/2020/assignment/assign6/index.html 2 | 3 | 本次作业结构看起来有些复杂,这里给出一些说明: 4 | 5 | ##### part1: 学习部分 6 | - exercise.py: 对应 Exercise1, Exercise2. 7 | - pandas_exercise.py: 对应 exercise5. 主要是用来学习 pandans 方便实现 simplex. 8 | 9 | ##### part2: 理论算法实现部分 10 | - constraint.py: 构建了 Constraint 类,详细说明可见该脚本下的注释 11 | - fourier_motzkin.py: fourizer——motzkin Variable Elimination 算法的实现 12 | - tableau.py: 对应 exercise6, 实现了 pivot 函数,该函数可以实现变量转化,可见 simplex 中的示例。 13 | - simplex.py: simplex 算法的实现,由于这个是 challenge, 咱们就不写了哈[doge] 14 | 15 | ##### part3: 应用 16 | 用 LA 解决以下问题: 17 | - seat_arrangement.py: 座位问题 18 | - 01knapsack.py: 0-1背包,最优化问题 19 | - four_queen.py: 四皇后 20 | 21 | -------------- 22 | 23 | 重点: 24 | - Guassian elimination: 即高斯消去 25 | ``` 26 | 对于方程组 27 | x + y = 0.8 28 | x - y = 0.2 29 | 另二式相加,得到 2x = 1, 30 | 进而得到 x = 0.5 31 | 再代入得到 y = 0.3 32 | ``` 33 | - Fourier-Motzkin Variable Elimination: 重复消去变量,直到获得 SAT 或 UNSAT. 该算法在实数范围内存在指数爆炸的问题,对于比较小的范围比较有实际价值。 34 | 35 | 1. 首先 normalize, 对于某个变量,最终形式为: 36 | ``` 37 | x_i + P_1(x) >= 0 38 | .... 39 | x_i + P_m(x) >= 0 40 | 41 | -x_i + Q_1(x) >= 0 42 | .... 43 | -x_i + Q_n(x) >= 0 44 | 45 | R(x) >= 0 46 | ``` 47 | 上式中,P(x), Q(x), R(x) 均不包含变量 x_i. 48 | 49 | 2. 消去 x_i 50 | ``` 51 | P_1(x) + Q_1(x) >= 0 52 | ... 53 | P_1(x) + Q_n(x) >= 0 54 | 55 | ... 56 | 57 | P_m(x) + Q_1(x) >= 0 58 | ... 59 | P_m(x) + Q_n(x) >= 0 60 | 61 | R(x) >= 0 62 | ``` 63 | 64 | 示例: 65 | ``` 66 | 方程组: 67 | x - y <= 0 68 | x - z <= 0 69 | -x + y + 2z <= 0 70 | -z <= -1 71 | 72 | 消去 x 后 73 | 2z <= 0 74 | y + z <= 0 75 | -z <= -1 76 | 77 | 再消去 z 78 | 0 <= -2 79 | y <= -1 80 | 81 | -> UNSAT 82 | ``` 83 | 84 | - Simplex: 85 | 86 | 示例: 87 | ``` 88 | 对于不等式: 89 | x + y >= 2 90 | 2x - y >= 0 91 | -x + 2y >= 1 92 | 93 | 1. 首先,将不等式转化为以下形式: 94 | x + y - s1 = 0 95 | 2x - y - s2 = 0 96 | -x + 2y -s3 = 0 97 | s1 >= 2 98 | s2 >= 0 99 | s3 >= 1 100 | 101 | 2. 初始时令 x = 0, y = 0, 得到 102 | s1 = 0 不满足 103 | s2 = 0 104 | s3 = 0 不满足 105 | 106 | 3. 首先修复 s1, 107 | s1 = x + y -> x = s1 - y 108 | s2 = 2x - y -> s2 = 2s1 - 3y 109 | s3 = -x + 2y -> s3 = -s1 + 3y 110 | 令 s1 = 2, y = 0 得到 111 | x = 2 112 | s2 = 4 113 | s3 = -2 不满足 114 | 115 | 4. 修复 s3 116 | s3 = -s1 + 3y -> y = s1/3 + s3/3 117 | x = s1 - y -> x = 2 * s1/3 - s3/3 118 | s2 = 2s1 - 3y -> s2 = s1 - s3 119 | 令 s1 = 2, s3 = 1 得到 120 | x = 1 121 | y = 1 122 | s2 = 1 123 | 124 | satisfied! 125 | ``` -------------------------------------------------------------------------------- /homework3/exercise2.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | 4 | class Todo(Exception): 5 | pass 6 | 7 | # In Exercise 1, we've learned how to use z3 to obtain the solutions that 8 | # satisfy a given proposition. 9 | # We must point out that the validity of Z3 is capable to prove 10 | # lies into the boundary of classical logic: 11 | 12 | 13 | # Besides "And", "Or" and "Not" constructors (functions), there 14 | # is some also the "Implies" and "Xor" constructors, which 15 | # can be used to construct propositions. For instance: 16 | # P->P 17 | P,Q,R = Bools('P Q R') 18 | F = Implies(P, P) 19 | 20 | # Now think of what we do in previous exercise about using Coq. If we 21 | # use Coq to prove P -> P, we will use tactic apply P. 22 | # Then P -> P is proved. 23 | # Now we use a different way, to prove it via z3. 24 | # This time we don't use z3 to obtain the solution for P->P, we just 25 | # try to find solution for its opposite, aka. Not(F): 26 | solve(Not(F)) 27 | 28 | # Z3 output the following: 29 | # "no solution" 30 | # which indicates that the proposition F is valid. 31 | 32 | # Then the following 33 | # double negation law: 34 | # ~~P -> P 35 | F = Implies(Not(Not(P)), P) 36 | solve(Not(F)) 37 | 38 | # TODO: Exercise 2-1 39 | # Now it's your turn, try to prove the exclusive middle law if also valid: 40 | # P \/ ~P 41 | '''Your code begin''' 42 | print( '\nexercise 2-1:') 43 | F = Or( P, Not( P)) 44 | solve(Not(F)) 45 | 46 | # TODO: Exercise 2-2 47 | # Prove the validity of the Pierce's law: 48 | # ((P->Q)->P)->P) 49 | # Todo: your code here: 50 | '''Your code begin''' 51 | print( '\nexercise 2-2:') 52 | F = Implies( Implies( Implies(P,Q),P), P) 53 | solve(Not(F)) 54 | 55 | 56 | # Note that the Pierce's law only holds in classical logic, but 57 | # not in constructive logic, for 58 | # interested readers, please refer to the background reading: 59 | # https://en.wikipedia.org/wiki/Peirce%27s_law 60 | 61 | 62 | # TODO: Exercise 2-3 63 | # In previous exercise about use Coq, we ever give you an challenge 64 | # (P -> Q) -> (~Q -> ~P). 65 | # Now try to prove it's valid via z3 66 | '''Your code begin''' 67 | print( '\nexercise 2-3:') 68 | F = Implies( Implies(P,Q), Implies( Not(Q), Not(P))) 69 | solve(Not(F)) 70 | 71 | # TODO: Exercise 2-4 72 | # Once more, try to prove that validity of : 73 | # (P -> Q /\ R) -> ((P -> Q) /\ (P -> R)) 74 | # Be carefully when you process the priority of operations cause 75 | # there is no intros. which can process it automatically for you 76 | # to use. 77 | '''Your code begin''' 78 | print( '\nexercise 2-4:') 79 | F = Implies( Implies( P, And( Q,R)), And( Implies( P,Q), Implies(P,R))) 80 | solve(Not(F)) 81 | 82 | 83 | # Well done, you complete Exercise 2, remember to save your code for handing in. -------------------------------------------------------------------------------- /homework9/large_prog.py: -------------------------------------------------------------------------------- 1 | from imp_ast import * 2 | import backward 3 | import time 4 | import prover 5 | fun_large_if = Function('large_if', 6 | ['x', 'y'], 7 | [ 8 | StmIf(ExpBop(ExpVar('x'), ExpNum(0), BOp.LT), [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(0), BOp.ADD))], [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(1), BOp.ADD))]), 9 | StmIf(ExpBop(ExpVar('x'), ExpNum(1), BOp.LT), [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(1), BOp.ADD))], [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(2), BOp.ADD))]), 10 | StmIf(ExpBop(ExpVar('x'), ExpNum(2), BOp.LT), [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(2), BOp.ADD))], [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(3), BOp.ADD))]), 11 | StmIf(ExpBop(ExpVar('x'), ExpNum(3), BOp.LT), [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(3), BOp.ADD))], [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(4), BOp.ADD))]), 12 | StmIf(ExpBop(ExpVar('x'), ExpNum(4), BOp.LT), [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(4), BOp.ADD))], [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(5), BOp.ADD))]), 13 | StmIf(ExpBop(ExpVar('x'), ExpNum(5), BOp.LT), [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(5), BOp.ADD))], [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(6), BOp.ADD))]), 14 | StmIf(ExpBop(ExpVar('x'), ExpNum(6), BOp.LT), [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(6), BOp.ADD))], [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(7), BOp.ADD))]), 15 | StmIf(ExpBop(ExpVar('x'), ExpNum(7), BOp.LT), [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(7), BOp.ADD))], [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(8), BOp.ADD))]), 16 | StmIf(ExpBop(ExpVar('x'), ExpNum(8), BOp.LT), [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(8), BOp.ADD))], [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(9), BOp.ADD))]), 17 | StmIf(ExpBop(ExpVar('x'), ExpNum(9), BOp.LT), [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(9), BOp.ADD))], [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(10), BOp.ADD))]) 18 | ], 19 | ExpVar('y'), 20 | ExpBop(ExpVar('y'), ExpNum(0), BOp.GT), 21 | ExpBop(ExpVar('y'), ExpNum(0), BOp.GT)) 22 | 23 | 24 | if __name__ == '__main__': 25 | print(fun_large_if) 26 | start_time = time.time() 27 | the_vc = backward.vc(fun_large_if) 28 | # print(the_vc) 29 | print(prover.prove_vc(the_vc)) 30 | end_time = time.time() 31 | print(end_time - start_time, 's') 32 | print(exp_num_nodes(the_vc)) 33 | 34 | 35 | ''' some questions. 36 | 1. How long does your code take to generate the VC? How to speed up this process? 37 | 当 num_ifs = 10 时生成的代码可以在很短时间完成,约 0.02s. 38 | 简单尝试了一下,但是当 num_ifs = 20 时,短时间内就无法生成了了。 39 | 话实在想不到加速的方法。 40 | 41 | 2. How large is the generated VC? How to shrink it? 42 | 可以使用三元表达式替换 if-else. 43 | 44 | 3. Is Z3 able to prove this VC? How long does Z3 take to finish the task? How to speed up? 45 | 是有解的 [x = -9, y = 1]. 但不是 validity. 46 | 解决 z3 prove num_ifs=10 时的 large_prop 约为 2s. 47 | 这里 pre 和 post 相同,可以考虑输入满足 pre 且能绕开所有 if-else 的变量。例如 [x= 10, y=1]. 48 | ''' -------------------------------------------------------------------------------- /homework7/exercise4.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | import time 3 | 4 | class Todo(Exception): 5 | pass 6 | 7 | x, y, z = BitVecs('x y z', 32) 8 | 9 | # We given an example for the special case of Fermat's Last Theorem when n==2, 10 | # that is, we ask Z3 to show that x*x+y*y=z*z does have solutions. 11 | def fermat_2(x, y, z): 12 | cons = [] 13 | cons.append(x&0xffffff00 == 0) 14 | cons.append(y&0xffffff00 == 0) 15 | cons.append(z&0xffffff00 == 0) 16 | cons.append(x!=0) 17 | cons.append(y!=0) 18 | cons.append(z!=0) 19 | cons.append(x*x+y*y == z*z) 20 | return cons 21 | 22 | 23 | # write a function for arbitrary n: 24 | def fermat(x, y, z, n): 25 | ''' 26 | add your implementation here: 27 | ''' 28 | cons = [] 29 | cons.append(x&0xffffff00 == 0) # I can't understand why the magic number is that. 30 | cons.append(y&0xffffff00 == 0) 31 | cons.append(z&0xffffff00 == 0) 32 | cons.append(x!=0) 33 | cons.append(y!=0) 34 | cons.append(z!=0) 35 | def mul(k,n): 36 | temp = 1 37 | for _ in range(n): 38 | temp *= k 39 | return temp 40 | 41 | cons.append(mul(x,n)+mul(y,n) == mul(z,n)) 42 | return cons 43 | 44 | 45 | a,b,c = Ints('a b c') 46 | def fermat_int(a, b, c, n): 47 | ''' 测试整数,用来回答ppt上的问题 48 | ''' 49 | cons = [] 50 | max_number = 511 51 | cons.append(a Function: 112 | # we first build a dict, mapping labels to their address 113 | label_dict = {} 114 | i = 0 115 | for s in f.stms: 116 | if isinstance(s, StmLabel): 117 | label_dict[s.label] = i 118 | i = i+1 119 | # debugging 120 | #print('label_dict=', label_dict) 121 | # rewrite the program to fix the address 122 | for s in f.stms: 123 | if isinstance(s, StmIf): 124 | s.true_address = label_dict[s.true_label] 125 | s.false_address = label_dict[s.false_label] 126 | if isinstance(s, StmGoto): 127 | s.address = label_dict[s.label] 128 | return f 129 | 130 | 131 | -------------------------------------------------------------------------------- /homework6/tableau.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import pandas as pd 4 | from pandas.testing import assert_frame_equal 5 | 6 | from constraint import Constraint 7 | 8 | 9 | class Tableau: 10 | def __init__(self, constraints): 11 | assert constraints, "constraints should not empty" 12 | 13 | col_size = len(constraints[0].coefficients) 14 | row_size = len(constraints) 15 | self.col_names = [f"x{i}" for i in range(col_size)] 16 | self.row_names = [f"s{i}" for i in range(row_size)] 17 | 18 | self.data = pd.DataFrame(data=[constraint.coefficients for constraint in constraints], 19 | columns=self.col_names, index=self.row_names, dtype="float64") 20 | 21 | def __str__(self): 22 | return repr(self.data) 23 | 24 | def pivot(self, row, col): 25 | # TODO: finish the pivot function of Tableau 26 | # 27 | # the pivot function will changes the tableau's data like: 28 | # 29 | # x0 x1 s0 x1 30 | # s0 1.0 1.0 pivot s0 and x0 x0 1.0 -1.0 31 | # s1 2.0 -1.0 ---------------------------------> s1 2.0 -3.0 32 | # s2 -1.0 2.0 s1 = x+y; --> x = s1-y; s2 -1.0 3.0 33 | # s2 = 2x-y = 2(s1-y)-y = 2s1 – 3y 34 | # s3 = -x+2y = -(s1-y)+2y = -s1+3y 35 | # 36 | # check the lecture's slides to understand how this happened. 37 | print(row, col) 38 | for i in self.data: 39 | # i = x0, x1, .... 40 | print(f'i = {i}\n',self.data) 41 | if i == col: 42 | self.data.loc[row, i] = 1 / self.data.loc[row, col] 43 | else: 44 | self.data.loc[row, i] /= -1 * self.data.loc[row, col] 45 | 46 | for i in self.data.index: 47 | # i = s0, s1, ... 48 | if i != row: 49 | for j in self.data.columns: 50 | print(f'i = {i},j = {j}\n',self.data) 51 | if j != col: 52 | self.data.loc[i, j] += self.data.loc[row, j] * self.data.loc[i, col] 53 | self.data.loc[i, col] *= self.data.loc[ row, col] 54 | 55 | # swap row and column's name 56 | self.data.rename(columns={col: row}, index={row: col}, inplace=True) 57 | 58 | 59 | class TestTableau(unittest.TestCase): 60 | 61 | def test_pivot_1(self): 62 | case = [Constraint([1, 1], 2), Constraint([2, -1], 0), Constraint([-1, 2], 1)] 63 | ''' 64 | x0 + x1 >= 2 65 | 2x0 - x1 >= 0 66 | -x0 + 2 * x1 >= 1 67 | || 68 | || 69 | \/ 70 | x0 + x1 - s0 = 0 71 | 2x0 - x1 - s1 = 0 72 | -x0 + 2 * x1 - s2 = 0 73 | s0 >= 2 74 | s1 >= 0 75 | s2 >= 1 76 | ''' 77 | tab = Tableau(case) 78 | tab.pivot("s0", "x0") 79 | assert_frame_equal(tab.data, pd.DataFrame(data=[[1.0, -1.0], [2.0, -3.0], [-1.0, 3.0]], 80 | index=["x0", "s1", "s2"], columns=["s0", "x1"])) 81 | tab.pivot("s2", "x1") 82 | assert_frame_equal(tab.data, pd.DataFrame(data=[[2.0/3.0, -1.0/3.0], [1.0, -1.0], [1.0/3.0, 1.0/3.0]], 83 | index=["x0", "s1", "x1"], columns=["s0", "s2"])) 84 | 85 | def test_pivot_2(self): 86 | case = [Constraint([-1, 1, 0], 0), Constraint([-1, 0, 1], 0), Constraint([1, -1, -2], 0), 87 | Constraint([0, 0, 1], 1)] 88 | tab = Tableau(case) 89 | tab.pivot("s3", "x2") 90 | assert_frame_equal(tab.data, pd.DataFrame(data=[[-1, 1, 0], [-1, 0, 1], [1, -1, -2], [0, 0, 1]], 91 | index=["s0", "s1", "s2", "x2"], columns=["x0", "x1", "s3"], 92 | dtype="float64")) 93 | tab.pivot("s2", "x0") 94 | assert_frame_equal(tab.data, pd.DataFrame(data=[[-1, 0, -2], [-1, -1, -1], [1, 1, 2], [0, 0, 1]], 95 | index=["s0", "s1", "x0", "x2"], columns=["s2", "x1", "s3"], 96 | dtype="float64")) 97 | 98 | 99 | if __name__ == '__main__': 100 | unittest.main() 101 | -------------------------------------------------------------------------------- /homework5/compiler.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | import counter 4 | import calc 5 | import tac 6 | 7 | 8 | class Todo(Exception): 9 | pass 10 | 11 | 12 | ############################################### 13 | # a compiler from Calc to Tac. 14 | 15 | # a map from variable to new variable: 16 | all_stms = [] 17 | 18 | 19 | def emit_stm(s): 20 | global all_stms 21 | all_stms.append(s) 22 | 23 | 24 | # invariant: compile an expression, return a variable 25 | def compile_exp(e): 26 | if isinstance(e, calc.ExpVar): 27 | return e.x 28 | if isinstance(e, calc.ExpAdd): 29 | var_left = compile_exp(e.left) 30 | var_right = compile_exp(e.right) 31 | new_var = counter.fresh_var() 32 | emit_stm(tac.StmAssignAdd(new_var, var_left, var_right)) 33 | return new_var 34 | # TODO: your code here: 35 | var_left = compile_exp(e.left) 36 | var_right = compile_exp(e.right) 37 | new_var = counter.fresh_var() 38 | if isinstance(e, calc.ExpSub): 39 | emit_stm( tac.StmAssignSub(new_var, var_left, var_right)) 40 | return new_var 41 | elif isinstance(e, calc.ExpMul): 42 | emit_stm( tac.StmAssignMul(new_var, var_left, var_right)) 43 | return new_var 44 | elif isinstance(e, calc.ExpDiv): 45 | emit_stm( tac.StmAssignDiv(new_var, var_left, var_right)) 46 | return new_var 47 | 48 | 49 | def compile_stm(s): 50 | if isinstance(s, calc.StmAssign): 51 | new_var = compile_exp(s.e) 52 | emit_stm(tac.StmAssignVar(s.x, new_var)) 53 | return 54 | 55 | 56 | # take a function 'f', convert it to SSA 57 | def compile_func0(f): 58 | global all_stms 59 | all_stms = [] 60 | if isinstance(f, calc.Function): 61 | # to compile each statement one by one: 62 | for s in f.stms: 63 | compile_stm(s) 64 | return tac.Function(f.name, f.args, all_stms, f.ret) 65 | 66 | 67 | def translation_validation(orig_f, result_f, orig_cons, result_cons): 68 | # TODO: for the compiler to be correct, you should prove this condition: 69 | # TODO: orig_cons /\ result_cons -> x1==x2 70 | # TODO: your code here: 71 | result1 = calc.ExpVar(orig_f.ret) 72 | result2 = calc.ExpVar(result_f.ret) 73 | 74 | solve( 75 | Implies( And( And(orig_cons), And(result_cons)), calc.gen_cons_exp(result1) == calc.gen_cons_exp(result2)) 76 | ) 77 | 78 | 79 | def compile_func(f): 80 | # print the original program: 81 | # calc.pp_func(f) 82 | # convert it to SSA: 83 | f_ssa = calc.to_ssa_func(f) 84 | '''f_ssa 85 | f(x1, x2, y1, y2, ){ 86 | x_0=((x1+y1)*(x2+y2)); 87 | return x_0; 88 | } 89 | ''' 90 | # generate constraints: 91 | cons_before = calc.gen_cons_func(f_ssa) 92 | '''cons_before 93 | [x_0 == f_mul(f_add(x1, y1), f_add(x2, y2))] 94 | ''' 95 | # compile the program: 96 | result_f = compile_func0(f_ssa) 97 | '''result_f 98 | f(x1, x2, y1, y2, ){ 99 | x_1=x1+y1; 100 | x_2=x2+y2; 101 | x_3=x_1*x_2; 102 | x_0=x_3; 103 | return x_0; 104 | } 105 | ''' 106 | # print the converted program 107 | # tac.pp_func(result_f) 108 | # convert the result program to SSA: 109 | result_f_ssa = tac.to_ssa_func(result_f) 110 | ''' 111 | f(x1, x2, y1, y2, ){ 112 | x_4=x1+y1; 113 | x_5=x2+y2; 114 | x_6=x_4*x_5; 115 | x_7=x_6; 116 | return x_7; 117 | } 118 | ''' 119 | # generate constraints on the target program: 120 | cons_after = tac.gen_cons_func(result_f_ssa) 121 | '''cons_after 122 | [x_4 == f_add(x1, y1), x_5 == f_add(x2, y2), x_6 == f_mul(x_4, x_5), x_7 == x_6] 123 | ''' 124 | # translation validation the compiler: 125 | translation_validation(f_ssa, result_f_ssa, cons_before, cons_after) 126 | return result_f_ssa 127 | 128 | 129 | if __name__ == '__main__': 130 | # a sample program: 131 | sample_f = calc.Function('f', 132 | ['x1', 'x2', 'y1', 'y2'], 133 | [calc.StmAssign('z', calc.ExpMul(calc.ExpAdd(calc.ExpVar('x1'), calc.ExpVar('y1')), 134 | calc.ExpAdd(calc.ExpVar('x2'), calc.ExpVar('y2'))))], 135 | 'z') 136 | ''' 137 | f(x1,x2,y1,y2){ 138 | z = (x1 + y1) * (x2+y2) 139 | return z 140 | } 141 | ''' 142 | compile_func(sample_f) 143 | -------------------------------------------------------------------------------- /homework8/ast.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | from typing import List 3 | 4 | # a utility class to represent the code you should fill in. 5 | class Todo(Exception): 6 | pass 7 | 8 | 9 | ######################################## 10 | # This bunch of code declare the syntax for the language C--, as we 11 | # discussed in the class: 12 | ''' 13 | bop ::= + | - | * | / | == | != | > | < | >= | <= 14 | E ::= n | x | E bop E 15 | S ::= skip 16 | | x=E 17 | | S;S 18 | | f(E1, …, En) 19 | | if(E, S, S) 20 | | while(E, S) 21 | F ::= f(x1, …, xn){S; return E;} 22 | ''' 23 | ################################## 24 | # bops 25 | 26 | 27 | class BOp(Enum): 28 | ADD = "+" 29 | MIN = "-" 30 | MUL = "*" 31 | DIV = "/" 32 | EQ = "==" 33 | NE = "!=" 34 | GT = ">" 35 | GE = ">=" 36 | LT = "<" 37 | LE = "<=" 38 | 39 | ########################################## 40 | # expressions 41 | 42 | 43 | class Exp: 44 | pass 45 | 46 | 47 | class ExpNum(Exp): 48 | def __init__(self, n: int): 49 | self.num = n 50 | 51 | def __str__(self): 52 | return f"{self.num}" 53 | 54 | 55 | class ExpVar(Exp): 56 | def __init__(self, var: str): 57 | self.var = var 58 | 59 | def __str__(self): 60 | return f"{self.var}" 61 | 62 | 63 | class ExpBop(Exp): 64 | def __init__(self, left: Exp, right: Exp, bop: BOp): 65 | self.left = left 66 | self.right = right 67 | self.bop = bop 68 | 69 | def __str__(self): 70 | if isinstance(self.left, ExpBop): 71 | left_str = f"({self.left})" 72 | else: 73 | left_str = f"{self.left}" 74 | 75 | if isinstance(self.right, ExpBop): 76 | right_str = f"({self.right})" 77 | else: 78 | right_str = f"{self.right}" 79 | 80 | return f"{left_str} {self.bop.value} {right_str}" 81 | 82 | 83 | ############################################### 84 | # statement 85 | 86 | 87 | class Stm: 88 | def __init__(self): 89 | self.level = 0 90 | 91 | def __repr__(self): 92 | return str(self) 93 | 94 | 95 | class StmAssign(Stm): 96 | def __init__(self, var: str, exp: Exp): 97 | super().__init__() 98 | self.var = var 99 | self.exp = exp 100 | 101 | def __str__(self): 102 | indent_space = self.level * "\t" 103 | return f"{indent_space}{self.var} = {self.exp};\n" 104 | 105 | 106 | class StmIf(Stm): 107 | def __init__(self, exp: Exp, then_stms: List[Stm], else_stms: List[Stm]): 108 | super().__init__() 109 | self.exp = exp 110 | self.then_stms = then_stms 111 | self.else_stms = else_stms 112 | 113 | def __str__(self): 114 | # TODO: Exercise 1 Code Here 115 | for stm in self.then_stms: 116 | stm.level = self.level + 1 117 | for stm in self.else_stms: 118 | stm.level = self.level + 1 119 | 120 | indent_space = self.level * "\t" 121 | 122 | then_stms_str = "".join([str(stm) for stm in self.then_stms]) 123 | else_stms_str = "".join([str(stm) for stm in self.else_stms]) 124 | 125 | res = (f"{indent_space}if({self.exp}){{\n" 126 | f"{then_stms_str}" 127 | f"{indent_space}}}\n") 128 | if len(else_stms_str): 129 | res += (f"{indent_space}else{{\n" 130 | f"{else_stms_str}" 131 | f"{indent_space}}}\n") 132 | 133 | return res 134 | 135 | 136 | class StmWhile(Stm): 137 | def __init__(self, exp: Exp, stms: List[Stm]): 138 | super().__init__() 139 | self.exp = exp 140 | self.stms = stms 141 | 142 | def __str__(self): 143 | # TODO: Exercise 1 Code Here 144 | for stm in self.stms: 145 | stm.level = self.level + 1 146 | indent_space = self.level * "\t" 147 | stms_str = "".join([str(stm) for stm in self.stms]) 148 | 149 | return (f"{indent_space}while({self.exp}){{\n" 150 | f"{stms_str}" 151 | f"{indent_space}}}\n") 152 | 153 | 154 | ############################################### 155 | # function 156 | class Function: 157 | def __init__(self, name: str, args: List[str], stms: List[Stm], ret: Exp): 158 | self.name = name 159 | self.args = args 160 | self.stms = stms 161 | self.ret = ret 162 | 163 | def __str__(self): 164 | arg_str = ",".join(self.args) 165 | for stm in self.stms: 166 | stm.level += 1 167 | 168 | stms_str = "".join([str(stm) for stm in self.stms]) 169 | 170 | return (f"{self.name}({arg_str}){{\n" 171 | f"{stms_str}" 172 | f"\treturn {self.ret};\n" 173 | f"}}\n") 174 | -------------------------------------------------------------------------------- /homework9/backward.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | from imp_ast import * 3 | import prover 4 | 5 | 6 | # a utility class to represent the code you should fill in. 7 | class Todo(Exception): 8 | pass 9 | 10 | 11 | def var_substitution(var: str, exp: Exp, post_cond: Exp): 12 | if isinstance(post_cond, ExpNum): 13 | return post_cond 14 | # TODO: your Exercise 4 code here, do the variable substitution 15 | # do not forget deal with ExpUni here 16 | elif isinstance(post_cond, ExpVar): 17 | if post_cond.var == var: 18 | return exp 19 | else: 20 | return post_cond 21 | elif isinstance(post_cond, ExpBop): 22 | return ExpBop( 23 | var_substitution(var, exp, post_cond.left), 24 | var_substitution(var, exp, post_cond.right), 25 | post_cond.bop) 26 | elif isinstance(post_cond, ExpNeg): 27 | return ExpNeg(var_substitution(var, exp, post_cond.exp)) 28 | elif isinstance(post_cond, ExpUni): 29 | if var in post_cond.vars_set: 30 | return post_cond 31 | return ExpUni(post_cond.vars_set, var_substitution(var, exp, post_cond.exp)) 32 | 33 | def vc_stms(stms: List[Stm], post_cond: Exp): 34 | for stm in reversed(stms): 35 | post_cond = vc_stm(stm, post_cond) 36 | 37 | return post_cond 38 | 39 | 40 | def vc_stm(stm: Stm, post_cond: Exp): 41 | if isinstance(stm, StmAssign): 42 | return var_substitution(stm.var, stm.exp, post_cond) 43 | 44 | # TODO: your Exercise 4 code here, generates verification conditions from statement 45 | # recall the rules: 46 | # 47 | # VC(x=e, P) = P[x↦e] 48 | # VC(if(e;s1;s2), P) = (e → VC(s1, P))∧(~e → VC(s2, P)) 49 | # VC(while I(e;s), P) = I ∧ (∀(x1 x2 ... xn).I → (e → VC(s, I) ∧ (~e → P))) 50 | elif isinstance(stm, StmIf): 51 | return ExpBop( 52 | ExpBop( stm.exp, vc_stms(stm.then_stms, post_cond), BOp.IM), 53 | ExpBop( ExpNeg(stm.exp), vc_stms(stm.else_stms, post_cond), BOp.IM), 54 | BOp.AND) 55 | 56 | elif isinstance(stm, StmWhile): 57 | return ExpBop( 58 | stm.inv, 59 | ExpUni( 60 | stm.modified_vars, 61 | ExpBop( 62 | stm.inv, 63 | ExpBop( 64 | ExpBop(stm.exp, vc_stms(stm.stms, stm.inv), BOp.IM), 65 | ExpBop(ExpNeg(stm.exp), post_cond, BOp.IM), 66 | BOp.AND), 67 | BOp.IM)), 68 | BOp.AND) 69 | 70 | ######################################## 71 | # This function will scan through a given function "f", generate and 72 | # return a verification condition: 73 | # VC(pre f(){S} post) = pre → VC(S, post) 74 | def vc(func: Function) -> Exp: 75 | post_cond = var_substitution("result", func.ret, func.post) 76 | return ExpBop(func.pre, vc_stms(func.stms, post_cond), BOp.IM) 77 | 78 | 79 | if __name__ == '__main__': 80 | # TODO: Exercise 4: perform verification condition generation, get the verification condition 81 | # 82 | # should print: 83 | # 84 | # (n <= 0) -> ((n <= 5) && ∀(n).((n <= 5) -> (((n < 5) -> ((n + 1) <= 5)) && (~(n < 5) -> (n == 5))))) 85 | # the number of nodes in VC: 15 86 | # 87 | # (n >= 0) -> (((0 <= (n + 1)) && ((2 * 0) == (0 * (0 - 1)))) && ∀(s,i).(((i <= (n + 1)) && ((2 * s) == 88 | # (i * (i - 1)))) -> (((i <= n) -> (((i + 1) <= (n + 1)) && ((2 * (s + i)) == ((i + 1) * ((i + 1) - 1))))) && 89 | # (~(i <= n) -> ((2 * s) == (n * (n + 1))))))) 90 | # the number of nodes in VC: 39 91 | # 92 | fill_in_modified_vars(fun_foo) 93 | '''fun_foo 94 | pre={n <= 0} 95 | foo(n){ 96 | inv={n <= 5} 97 | modified_vars={n} 98 | while(n < 5){ 99 | n = n + 1; 100 | } 101 | return n; 102 | } 103 | post={result == 5} 104 | ''' 105 | vc_foo = vc(fun_foo) 106 | print(vc_foo) 107 | print("the number of nodes in VC: ", exp_num_nodes(vc_foo)) 108 | 109 | fill_in_modified_vars(fun_sum) 110 | ''' fun_sum 111 | pre={n >= 0} 112 | sum(n){ 113 | s = 0; 114 | i = 0; 115 | inv={(i <= (n + 1)) && ((2 * s) == (i * (i - 1)))} 116 | modified_vars={i,s} 117 | while(i <= n){ 118 | s = s + i; 119 | i = i + 1; 120 | } 121 | return s; 122 | } 123 | post={(result * 2) == (n * (n + 1))} 124 | ''' 125 | vc_sum = vc(fun_sum) 126 | print(vc_sum) 127 | 128 | 129 | print("the number of nodes in VC: ", exp_num_nodes(vc_sum)) 130 | 131 | # TODO: Exercise 5: prove the generated vc with prove_vc(the_vc), you 132 | # need to complete the code in prover.py file 133 | # 134 | # should output: 135 | # 136 | # Implies(n <= 0, 137 | # And(n <= 5, 138 | # ForAll(n, 139 | # Implies(n <= 5, 140 | # And(Implies(n < 5, n + 1 <= 5), 141 | # Implies(Not(n < 5), n == 5)))))) 142 | # 143 | # Implies(n >= 0, 144 | # And(And(n + 1 >= 0, True), 145 | # ForAll([s, i], 146 | # Implies(And(i <= n + 1, 2*s == i*(i - 1)), 147 | # And(Implies(i <= n, 148 | # And(i + 1 <= n + 1, 149 | # 2*(s + i) == 150 | # (i + 1)*(i + 1 - 1))), 151 | # Implies(Not(i <= n), 152 | # 2*s == n*(n + 1))))))) 153 | # 154 | # True 155 | # True 156 | # 157 | print(prover.prove_vc(vc_foo)) 158 | print(prover.prove_vc(vc_sum)) -------------------------------------------------------------------------------- /homework3/exercise3.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | class Todo(Exception): 4 | pass 5 | 6 | # Applications of SAT via Z3 7 | 8 | # In the previous part we've discussed how to obtain solutions and prove 9 | # the validity for propositions. 10 | # In this part, we will try to use Z3 to solve some practical problems. 11 | # Hints: 12 | # You can reuse the all_set function that you've implemented in exercise 1 13 | # if you think necessary. 14 | 15 | 16 | def sat_all(props, f): 17 | """Get all solutions of given proposition set props that satisfy f 18 | 19 | Arguments: 20 | props {BoolRef} -- Proposition list 21 | f {Boolref} -- logical express that consist of props 22 | """ 23 | solver = Solver() 24 | solver.add(f) 25 | result = [] 26 | while solver.check() == sat: 27 | m = solver.model() 28 | result.append(m) 29 | block = [] 30 | for prop in props: 31 | if m.eval(prop, True): 32 | # TODO: Fill your code here 33 | '''Your code begin, replace the following line:''' 34 | new_prop = prop 35 | else: 36 | new_prop = Not(prop) 37 | block.append(new_prop) 38 | # TODO: Fill your code here 39 | '''Your code begin''' 40 | temp = True 41 | for prop in block: 42 | temp = And( temp, prop) 43 | new_prop = And( f, Not( temp)) 44 | solver.add(new_prop) 45 | print("the given proposition: ", f) 46 | print("the number of solutions: ", len(result)) 47 | 48 | def print_model(m): 49 | print(sorted([(d, m[d]) for d in m], key=lambda x: str(x[0]))) 50 | for m in result: 51 | print_model(m) 52 | 53 | 54 | # TODO: Exercise 3-1 55 | # Circuit Layout 56 | # Usually When EE-Engineers design a circuit layout, they will verify it to 57 | # make sure that the layout will not only output a single electrical level 58 | # since it's useless. 59 | # Now let's investigate the Circuit Layout we provide you. 60 | # According to the requirement, what we should do is to convert the circuit layout 61 | # into a proposition expression, let's say 'F', and try to obtains the solutions 62 | # for F and Not(F). 63 | # And then make sure that both F and Not(F) can be satisfied. 64 | # First we convert it into proposition 65 | def circuit_layout(): 66 | a, b, c, d = Bools('a b c d') 67 | # Todo: replace the following line with your own code: 68 | # (d /\ (a /\ b)) \/ (~c /\ a /\ b) 69 | F = Or( And( a,b,d), And( Not(c), a, b)) 70 | print('exercise 3-1:') 71 | sat_all([a,b,c,d], F) 72 | 73 | ########################################################### 74 | 75 | # TODO: Exercise 3-2 76 | # Seat Arrangement Problem 77 | # Alice, Bob, Carol take 3 seats. But they have some requirements: 78 | # 1. Alice can not sit near to Carol; 79 | # 2. Bob can not sit right to Alice. 80 | # Questions: 81 | # 1. Is there any solution? 82 | # 2. How many solutions in total? 83 | 84 | # Now let us investigate the problem 85 | 86 | 87 | def seat_arrangement(): 88 | solver = Solver() 89 | # 1. First we need to modeling the problem 90 | # Let say: 91 | # A_i means Alice takes seat Ai, 92 | # B_i means Bob takes seat Bi, 93 | # C_i means Carol takes seat Ci. 94 | # And since there are only 3 seats, so 1 <= i <= 3 95 | N_SEAT = 3 96 | a1, a2, a3 = Bools('a1 a2 a3') 97 | b1, b2, b3 = Bools('b1 b2 b3') 98 | c1, c2, c3 = Bools('c1 c2 c3') 99 | 100 | # alice must take a seat: 101 | alice_take_seat_1 = And(a1, Not(a2), Not(a3), Not(b1), Not(c1)) 102 | alice_take_seat_2 = And(a2, Not(a1), Not(a3), Not(b2), Not(c2)) 103 | alice_take_seat_3 = And(a3, Not(a1), Not(a2), Not(b3), Not(c3)) 104 | solver.add(Or(alice_take_seat_1, alice_take_seat_2, alice_take_seat_3)) 105 | 106 | # bob must take a seat: 107 | bob_take_seat_1 = And(b1, Not(b2), Not(b3), Not(a1), Not(a1)) 108 | bob_take_seat_2 = And(b2, Not(b1), Not(b3), Not(a2), Not(c2)) 109 | bob_take_seat_3 = And(b3, Not(b1), Not(b2), Not(a3), Not(c3)) 110 | solver.add(Or(bob_take_seat_1, bob_take_seat_2, bob_take_seat_3)) 111 | 112 | # carol must take a seat: 113 | carol_take_seat_1 = And(c1, Not(c2), Not(c3), Not(b1), Not(a1)) 114 | carol_take_seat_2 = And(c2, Not(c1), Not(c3), Not(b2), Not(a2)) 115 | carol_take_seat_3 = And(c3, Not(c1), Not(c2), Not(b3), Not(a3)) 116 | solver.add(Or(carol_take_seat_1, carol_take_seat_2, carol_take_seat_3)) 117 | 118 | # alice can not sit near to carol: 119 | alice_not_near_carol = And(Implies(a1, Not(c2)), Implies(a2, Not(Or(c1, c3))), Implies(a3, Not(c2))) 120 | solver.add(alice_not_near_carol) 121 | 122 | # 3. Bob can not sit right to Alice 123 | alice_not_near_carol = And(Implies(b2, Not(a1)), Implies(b3, Not(a2))) 124 | solver.add(alice_not_near_carol) 125 | 126 | # Hint: here only one solution is printed, you may change this to 127 | # print all the solutions to check your implementation. 128 | solver.check() 129 | model = solver.model() 130 | # print(model) 131 | # fancy printing 132 | if model.evaluate(a1): 133 | print("Alice ", end='') 134 | if model.evaluate(b1): 135 | print("Bob ", end='') 136 | if model.evaluate(c1): 137 | print("Carol ", end='') 138 | if model.evaluate(a2): 139 | print("Alice ", end='') 140 | if model.evaluate(b2): 141 | print("Bob ", end='') 142 | if model.evaluate(c2): 143 | print("Carol ", end='') 144 | if model.evaluate(a3): 145 | print("Alice", end='') 146 | if model.evaluate(b3): 147 | print("Bob", end='') 148 | if model.evaluate(c3): 149 | print("Carol", end='') 150 | 151 | 152 | if __name__ == '__main__': 153 | # circuit_layout should have 3 solutions for F and 13 solutions for Not(F) 154 | circuit_layout() 155 | # seat_arrangement should have 1 solution 156 | print('\nexercise 3-2:') 157 | seat_arrangement() -------------------------------------------------------------------------------- /homework8/concrete.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from dataclasses import dataclass 3 | from typing import List, Dict 4 | 5 | from ast import * 6 | 7 | 8 | # a concrete execution engine. 9 | 10 | # concrete execution memory model will store arguments and concrete values 11 | @dataclass 12 | class Memory: 13 | args: List[str] 14 | concrete_memory: Dict[str, int] 15 | 16 | def __str__(self): 17 | arg_str = ",".join(self.args) 18 | concrete_str = "\n".join([f"\t{var}: {value}" for var, value in self.concrete_memory.items()]) 19 | return (f"Arguments: {arg_str}\n" 20 | f"Concrete Values: \n" 21 | f"{concrete_str}\n") 22 | 23 | 24 | ##################### 25 | # concrete execution 26 | def interpret_exp(memory, exp): 27 | if isinstance(exp, ExpNum): 28 | return exp.num 29 | 30 | if isinstance(exp, ExpVar): 31 | # TODO: Exercise 2 Code Here 32 | # process ExpVar by reading the memory of variable x 33 | return memory.concrete_memory[exp.var] 34 | 35 | if isinstance(exp, ExpBop): 36 | # TODO: Exercise 2 Code Here 37 | # process ExpBop by the rules in the lecture note 38 | left = exp.left 39 | right = exp.right 40 | 41 | if isinstance(left, ExpBop): 42 | left = interpret_exp(memory, left) 43 | elif isinstance(left, ExpNum): 44 | left = left.num 45 | else: 46 | left = memory.concrete_memory[left.var] 47 | 48 | if isinstance(right, ExpBop): 49 | right = interpret_exp(memory, right) 50 | elif isinstance(right, ExpNum): 51 | right = right.num 52 | else: 53 | right = memory.concrete_memory[right.var] 54 | 55 | if exp.bop == BOp.ADD: 56 | return left + right 57 | elif exp.bop == BOp.MIN: 58 | return left - right 59 | elif exp.bop == BOp.MUL: 60 | return left * right 61 | elif exp.bop == BOp.DIV: 62 | return left / right 63 | elif exp.bop == BOp.EQ: 64 | return left == right 65 | elif exp.bop == BOp.NE: 66 | return left != right 67 | elif exp.bop == BOp.GT: 68 | return left > right 69 | elif exp.bop == BOp.GE: 70 | return left >= right 71 | elif exp.bop == BOp.LT: 72 | return left < right 73 | else: 74 | return left <= right 75 | 76 | def interpret_stm(memory, stm): 77 | if isinstance(stm, StmAssign): 78 | # TODO: Exercise 3 Code Here 79 | # process StmAssign by updating the memory 80 | memory.concrete_memory[stm.var] = interpret_exp(memory, stm.exp) 81 | 82 | elif isinstance(stm, StmIf): 83 | # TODO: Exercise 3 Code Here 84 | # process StmIf by the big-step rules 85 | if interpret_exp(memory, stm.exp): 86 | interpret_stms(memory, stm.then_stms) 87 | else: 88 | interpret_stms(memory, stm.else_stms) 89 | 90 | elif isinstance(stm, StmWhile): 91 | # TODO: Exercise 3 Code Here 92 | # process StmWhile by the big-step rules 93 | while interpret_exp(memory, stm.exp): 94 | interpret_stms(memory, stm.stms) 95 | 96 | return memory 97 | 98 | 99 | def interpret_stms(memory, stms): 100 | for stm in stms: 101 | interpret_stm(memory, stm) 102 | return memory 103 | 104 | 105 | def interpret_func(func, params): 106 | assert len(func.args) == len(params), "The number of parameters does not match" 107 | memory = Memory(func.args, dict(zip(func.args, params))) 108 | interpret_stms(memory, func.stms) 109 | 110 | return interpret_exp(memory, func.ret) 111 | 112 | 113 | ####################################### 114 | # test code 115 | func_sum = Function('sum', ['n'], 116 | [StmAssign('s', ExpNum(0)), 117 | StmAssign('i', ExpNum(0)), 118 | StmWhile(ExpBop(ExpVar('i'), ExpVar('n'), BOp.LE), 119 | [StmAssign('s', ExpBop(ExpVar('s'), ExpVar('i'), BOp.ADD)), 120 | StmAssign('i', ExpBop(ExpVar('i'), ExpNum(1), BOp.ADD)) 121 | ]) 122 | ], ExpVar('s')) 123 | 124 | func_max = Function("max", ["m", "n"], 125 | [StmAssign("c", ExpVar("m")), 126 | StmIf(ExpBop(ExpVar("n"), ExpVar("c"), BOp.GT), 127 | [StmAssign("c", ExpVar("n"))], 128 | []) 129 | ], ExpVar("c")) 130 | 131 | func_gcd = Function("gcd", ["m", "n"], 132 | [StmWhile(ExpBop(ExpVar("m"), ExpVar("n"), BOp.NE), 133 | [StmIf(ExpBop(ExpVar("m"), ExpVar("n"), BOp.GE), 134 | [StmAssign("m", ExpBop(ExpVar("m"), ExpVar("n"), BOp.MIN))], 135 | [StmAssign("n", ExpBop(ExpVar("n"), ExpVar("m"), BOp.MIN))]) 136 | ]) 137 | ], ExpVar("m")) 138 | 139 | 140 | class TestConcrete(unittest.TestCase): 141 | def test_interpret_exp(self): 142 | exp1 = ExpBop(ExpBop(ExpNum(3), ExpNum(2), BOp.ADD), 143 | ExpBop(ExpNum(3), ExpNum(2), BOp.MUL), 144 | BOp.GE) 145 | 146 | exp2 = ExpBop(ExpBop(ExpNum(10), ExpNum(2), BOp.DIV), 147 | ExpBop(ExpNum(8), ExpNum(2), BOp.MIN), 148 | BOp.NE) 149 | 150 | print(exp1) 151 | self.assertEqual(interpret_exp({}, exp1), False) 152 | 153 | print(exp2) 154 | self.assertEqual(interpret_exp({}, exp2), True) 155 | 156 | def test_interpret_func_sum(self): 157 | # print(func_sum) 158 | self.assertEqual(interpret_func(func_sum, [100]), 5050) 159 | 160 | def test_interpret_func_max(self): 161 | # print(func_max) 162 | self.assertEqual(interpret_func(func_max, [10, 20]), 20) 163 | 164 | def test_interpret_func_gcd(self): 165 | # print(func_gcd) 166 | self.assertEqual(interpret_func(func_gcd, [60, 48]), 12) 167 | 168 | 169 | if __name__ == '__main__': 170 | unittest.main() 171 | -------------------------------------------------------------------------------- /homework8/concolic.py: -------------------------------------------------------------------------------- 1 | import random 2 | from dataclasses import dataclass 3 | from typing import List, Dict 4 | 5 | from z3 import * 6 | from ast import * 7 | 8 | from symbolic import check_cond, neg_exp, symbolic_exp, f1 9 | from concrete import interpret_exp 10 | 11 | 12 | # a concolic execution engine. 13 | 14 | # concolic memory model will store arguments, concrete values, symbolic values 15 | # and path condition list 16 | @dataclass 17 | class Memory: 18 | args: List[str] 19 | concrete_memory: Dict[str, int] 20 | symbolic_memory: Dict[str, Exp] 21 | path_condition: List[Exp] 22 | 23 | def __str__(self): 24 | arg_str = ",".join(self.args) 25 | actual_str = ",".join([f"{var} = {value}" for var, value in self.concrete_memory.items()]) 26 | exp_str = "\n".join([f"\t{var} = {value}" for var, value in self.symbolic_memory.items()]) 27 | cond_str = ",".join([str(cond) for cond in self.path_condition]) 28 | return (f"Arguments: {arg_str}\n" 29 | f"Path Condition: {cond_str}\n" 30 | f"Actual Table: {actual_str}\n" 31 | f"Symbol Table: \n" 32 | f"{exp_str}\n") 33 | 34 | 35 | ##################### 36 | # concolic execution 37 | def concolic_stm(memory, stm): 38 | if isinstance(stm, StmAssign): 39 | # TODO: Exercise 8 Code Here 40 | # process StmAssign by updating both symbolic memory and concrete memory 41 | memory.concrete_memory[stm.var] = interpret_exp(memory, stm.exp) 42 | memory.symbolic_memory[stm.var] = interpret_exp(memory, stm.exp) 43 | 44 | 45 | elif isinstance(stm, StmIf): 46 | # TODO: Exercise 8 Code Here 47 | # process StmIf statement 48 | if interpret_exp(memory, stm.exp): 49 | memory.path_condition.append( symbolic_exp(memory, stm.exp)) 50 | memory = concolic_stms( memory, stm.then_stms) 51 | else: 52 | memory.path_condition.append(neg_exp(symbolic_exp(memory, stm.exp))) 53 | memory = concolic_stms(memory, stm.else_stms) 54 | 55 | elif isinstance(stm, StmWhile): 56 | # TODO: Exercise 9 Code Here 57 | # Executing the loop expression by concrete execution 58 | # to decide whether to continue.For the statements contained by 59 | # while-statement, do the concolic execution. 60 | if interpret_exp(memory, stm.exp): 61 | memory.path_condition.append( 62 | ExpBop( 63 | memory.symbolic_memory[stm.exp.left.var], 64 | memory.symbolic_memory[stm.exp.right.var], 65 | stm.exp.bop)) 66 | concolic_stms(memory, stm.stms) 67 | else: 68 | memory.path_condition.append( neg_exp(stm.exp)) 69 | 70 | return memory 71 | 72 | 73 | def concolic_stms(memory, stms): 74 | for stm in stms: 75 | concolic_stm(memory, stm) 76 | 77 | return memory 78 | 79 | 80 | def concolic_func(func, init_concrete): 81 | # init memory 82 | init_symbolic = dict(zip(func.args, [ExpVar(arg) for arg in func.args])) 83 | memory = Memory(func.args, init_concrete, init_symbolic, []) 84 | 85 | concolic_stms(memory, func.stms) 86 | return memory, interpret_exp(memory, func.ret) 87 | 88 | 89 | def concolic_executor(func, init_params, try_times): 90 | init_concrete = dict(zip(func.args, init_params)) 91 | print(f"First Try, Input Value: {init_concrete}") 92 | memory, _ = concolic_func(func, init_concrete.copy()) 93 | print(memory) 94 | 95 | # random select and negate one condition from previous result 96 | # and use z3 to generate a input to do next concolic execution 97 | for try_time in range(2, try_times+1, 1): 98 | random_idx = random.randrange(0, len(memory.path_condition)) 99 | memory.path_condition[random_idx] = neg_exp(memory.path_condition[random_idx]) 100 | ret, solver = check_cond(memory) 101 | 102 | if ret == sat: 103 | # use z3 result update new input values 104 | model = solver.model() 105 | for dec in model.decls(): 106 | if dec.name() in func.args: 107 | init_concrete[dec.name()] = model[dec].as_long() 108 | 109 | print(f"Try times: {try_time}, Input Value: {init_concrete}") 110 | memory, _ = concolic_func(func, init_concrete.copy()) 111 | print(memory) 112 | else: 113 | print(f"Try times: {try_time}, Path conditions got UNSAT/UNKNOWN from z3") 114 | print(f"Conditions try to Solve: {solver}\n") 115 | 116 | 117 | ##################### 118 | # test code 119 | func_loop = Function("loop", ["m", "n"], 120 | [StmWhile(ExpBop(ExpVar("m"), ExpVar("n"), BOp.LT), 121 | [StmIf(ExpBop(ExpVar("m"), ExpNum(0), BOp.GT), 122 | [StmAssign("m", ExpBop(ExpVar("m"), ExpNum(2), BOp.MUL))], 123 | [StmIf(ExpBop(ExpVar("m"), ExpNum(0), BOp.EQ), 124 | [StmAssign("m", ExpNum(1))], 125 | [StmAssign("m", ExpBop(ExpVar("m"), ExpNum(-1), BOp.MUL))])]) 126 | ]) 127 | ], ExpVar("m")) 128 | 129 | # example for challenge 130 | hard_stm_1 = ExpBop(ExpBop(ExpBop(ExpVar("y"), ExpVar("y"), BOp.MUL), ExpVar("x"), BOp.MUL), 131 | ExpBop(ExpVar("y"), ExpNum(23123), BOp.MUL), BOp.ADD) 132 | 133 | func_foo = Function("foo", ["x", "y"], 134 | [StmAssign("m", hard_stm_1), 135 | StmIf(ExpBop(ExpVar("m"), ExpVar("y"), BOp.LE), 136 | [StmAssign("s", ExpNum(1))], 137 | [StmAssign("s", ExpNum(2))]) 138 | ], ExpVar("s")) 139 | 140 | 141 | if __name__ == '__main__': 142 | # TODO: Exercise 8: Complete code in the function `concolic_stm` to 143 | # deal with `StmAssign` and `StmIf` statement, you need to maintain 144 | # both symbolic memory and concrete memory. Here you can 145 | # directly use the related functions in the `symbolic.py` and 146 | # `concrete.py` file 147 | # 148 | print(f1) 149 | 150 | # how many paths in `f1`? How many times it has executed to cover all paths? 151 | '''3 paths, and in result, we try 5 times''' 152 | concolic_executor(f1, [0, 0], 5) 153 | print('----------------------') 154 | 155 | # TODO: Exercise 9: Fill code in the function `concolic_stm` to 156 | # deal with `StmWhile` statement. what you need to do is execute the 157 | # loop expression by concrete execution to decide whether to continue, 158 | # and for the statements contained by while-statement, do the concolic 159 | # execution. Don't forget to add the loop judgment expression to the 160 | # path condition list. 161 | # 162 | print(func_loop) 163 | 164 | # how many paths it covers in `func_loop`? How many times it has executed? 165 | '''4 paths, min times is 4.''' 166 | concolic_executor(func_loop, [2, 31], 20) 167 | -------------------------------------------------------------------------------- /homework6/fourier_motzkin.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from constraint import Relation, Constraint, IllegalConstraintError 3 | from tableau import Tableau 4 | import numpy as np 5 | 6 | def fourier_motzkin(constraints): 7 | # Implement the Fourier Motzkin algorithm 8 | # 9 | # The key idea of Fourier Motzkin algorithm is to 10 | # repeatedly eliminate variables, until SAT or UNSAT is obtained. 11 | # The procedure can be summarized as: 12 | # 1) Select a variable xi, and change the constraints into normal form, 13 | # with m positive and n negative occurrences of xi: 14 | # 15 | # xi + P1(x) >= 0 16 | # ... 17 | # xi + Pm(x) >= 0 18 | # -xi + Q1(x) >= 0 19 | # ... 20 | # -xi + Qn(x) >= 0 21 | # R(x) >= 0 22 | # 23 | # 2) Eliminate xi. The previous m + n constraints will be replaced with 24 | # m * n new constraints. 25 | # 26 | # P1(x) + Q1(x) >= 0 27 | # ... 28 | # P1(x) + Qn(x) >= 0 29 | # P2(x) + Q1(x) >= 0 30 | # ... 31 | # P2(x) + Qn(x) >= 0 32 | # ... 33 | # Pm(x) + Qn(x) >= 0 34 | # R(x) >= 0 35 | # 36 | # 3) If there're multiple variables in a single constraint, repeat step 1) and 2). 37 | 38 | result = {} 39 | print("===>Solving Constraints:") 40 | if not constraints: 41 | return result 42 | 43 | basic_var_amount = len(constraints[0].coefficients) 44 | for constraint in constraints: 45 | if len(constraint.coefficients) != basic_var_amount: 46 | raise IllegalConstraintError(constraint) 47 | print(constraint) 48 | #print(f"constraint.coefficients = {constraint.coefficients[1]}---constraint.value = {constraint.value}-----constraint.relation = {constraint.relation}") 49 | 50 | # TODO: finish the fourier_motzkin algorithm 51 | # if there is no solution, return string "no solution" 52 | # if find a solution, return the result as dict: e.g {"x0": 1, "x1": 1} 53 | # feel free to change the code here or add new code but your code should pass the unittest 54 | 55 | # Your code here 56 | 57 | vals = [] 58 | #定义行列数,col为列数,row为行数 59 | lenrow = len(constraints) 60 | lencol = len(constraints[0].coefficients) + 1 61 | #将LE转换为GE,并且正规化 62 | for constraint in constraints: 63 | if constraint.relation == Relation.LE: 64 | for idx , coefficient in enumerate(constraint.coefficients): 65 | constraint.coefficients[idx] = coefficient * -1 66 | constraint.value = constraint.value * -1 67 | constraint.relation = Relation.GE 68 | if abs(constraint.coefficients[0]) != 1 : 69 | temp = abs(constraint.coefficients[0]) 70 | constraint.coefficients[0] /= temp 71 | constraint.coefficients[1] /= temp 72 | constraint.value /= temp 73 | vals.append(constraint.value) 74 | 75 | tab = Tableau(constraints) 76 | tab.data.insert(loc = len(tab.data.columns) , column = "val" , value = vals) 77 | #将data转化为numpy数组形式 78 | constraints_np = tab.data.values 79 | #print(constraints_np) 80 | 81 | first_op_col = 0 82 | flag = 0 83 | for j in range(lencol - 1): 84 | first_op_col = j 85 | for count in range(lenrow- 1): 86 | for i in range(lenrow): 87 | if constraints_np[count][j] * constraints_np[i][j] < 0: 88 | first_op_col = j 89 | count = lenrow 90 | j = lencol - 1 91 | flag = 1 92 | break 93 | if flag == 1: 94 | break 95 | if flag == 1 : 96 | break 97 | 98 | #print(f'first_op_col ={first_op_col}') 99 | 100 | #对first_op_col这一列进行消去 101 | privious_args = [] 102 | count_nega = 0 103 | count_post = 0 104 | row_nega = 0 105 | row_post = 0 106 | row_final = 0 107 | for i in range(lenrow): 108 | if constraints_np[i][first_op_col] > 0: 109 | count_post += 1 110 | row_post = i 111 | else: 112 | count_nega += 1 113 | row_nega = i 114 | if count_post > count_nega: 115 | row_final = row_nega 116 | else : 117 | row_final = row_post 118 | #print(f'row_final = {row_final}') 119 | 120 | #记录原始参数 121 | for i in range(lencol): 122 | privious_args.append(constraints_np[row_final][i]) 123 | 124 | #print(privious_args) 125 | #合并 126 | #print(constraints_np) 127 | #print('\n\n') 128 | for i in range(lenrow): 129 | if i == row_final: 130 | continue 131 | for j in range(lencol): 132 | constraints_np[i][j] += privious_args[j] 133 | #print(constraints_np) 134 | 135 | #说明只有两个x系数 136 | if lencol == 3: 137 | for i in range(lenrow) : 138 | if i == row_final: 139 | continue 140 | for j in range(lencol - 1): 141 | if j != first_op_col: 142 | constraints_np[i][2] /= constraints_np[i][j] 143 | constraints_np[i][j] /= constraints_np[i][j] 144 | print('\n\n') 145 | #print(constraints_np) 146 | 147 | ret = [0,0] 148 | ret_used = [0,0] 149 | ret_index = 0 150 | for i in range(lenrow): 151 | if(i == row_final): 152 | continue 153 | for j in range(lencol - 1): 154 | if j != first_op_col: 155 | if ret_used[j] == 1: 156 | #或者是其他不对的条件 157 | if constraints_np[i][2] != ret[j]: 158 | return "no solution" 159 | else: 160 | ret_used[j] = 1 161 | ret_index = j 162 | ret[j] = constraints_np[i][2] 163 | 164 | #print(privious_args) 165 | if first_op_col == 0: 166 | ret[first_op_col] = privious_args[2] - privious_args[1] * ret[ret_index] 167 | else : 168 | ret[first_op_col] = privious_args[2] - privious_args[0] * ret[ret_index] 169 | ret[first_op_col] /= privious_args[1] 170 | 171 | #print(ret) 172 | for i in range(len(ret)): 173 | result[f'x{i}'] = round(ret[i],1) 174 | 175 | print(f"===>Solving result is {result}") 176 | return result 177 | 178 | 179 | class TestFourierMotzkin(unittest.TestCase): 180 | 181 | def test_fourier_motzkin_sat(self): 182 | case = [Constraint([1, 1], 0.8), Constraint([1, -1], 0.2)] 183 | ''' 184 | x0 + x1 >= 0.8 185 | x0 - x1 >= 0.2 186 | ''' 187 | result = fourier_motzkin(case) 188 | self.assertDictEqual(result, {"x0": 0.5, "x1": 0.3}) 189 | 190 | def test_fourier_motzkin_unsat(self): 191 | case = [Constraint([1, 1], 0.8), Constraint([1, 5], 0.2), Constraint([1, 3], 0, relation=Relation.LE)] 192 | ''' 193 | x0 + x1 >= 0.8 194 | x0 + 5 * x1 >= 0.2 195 | x0 + 3 * x1 <= 0 196 | ''' 197 | result = fourier_motzkin(case) 198 | self.assertEqual(result, "no solution") 199 | 200 | 201 | if __name__ == '__main__': 202 | unittest.main() -------------------------------------------------------------------------------- /homework7/pointer.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod, ABC 2 | 3 | from z3 import * 4 | 5 | # uninterrupted functions 6 | S = Function("S", IntSort(), IntSort()) 7 | H = Function("H", IntSort(), IntSort()) 8 | 9 | class Todo(Exception): 10 | pass 11 | 12 | # Term 13 | class Term: 14 | @abstractmethod 15 | def to_z3(self): 16 | pass 17 | 18 | 19 | class TVar(Term): 20 | def __init__(self, name, var): 21 | self.name = name 22 | self.var = var 23 | 24 | def __str__(self): 25 | # TODO: Implement the printing of `x` 26 | return f"{self.var}" 27 | 28 | def to_z3(self): 29 | # ⟦x⟧ = H(S(x)) 30 | return H(S(self.var)) 31 | 32 | 33 | class TAdd(Term): 34 | def __init__(self, term, exp): 35 | self.term = term 36 | self.exp = exp 37 | 38 | def __str__(self): 39 | # TODO: Implement the printing of `T + E` 40 | return f'{self.term} + {self.exp}' 41 | 42 | def to_z3(self): 43 | # ⟦T + E⟧ = ⟦T⟧ + ⟦E⟧ 44 | return self.term.to_z3() + self.exp.to_z3() 45 | 46 | 47 | class TAddr(Term): 48 | def __init__(self, name, var): 49 | self.name = name 50 | self.var = var 51 | 52 | def __str__(self): 53 | # TODO: Implement the printing of `&x` 54 | return f'&{self.var}' 55 | 56 | 57 | def to_z3(self): 58 | return S(self.var) 59 | 60 | 61 | class TAddrStar(Term): 62 | def __init__(self, term): 63 | self.term = term 64 | 65 | def __str__(self): 66 | # TODO: Implement the printing of `&*T` 67 | return f'&*{self.term}' 68 | 69 | 70 | def to_z3(self): 71 | # ⟦&*T⟧ = ⟦T⟧ 72 | return self.term.to_z3() 73 | 74 | 75 | class TStar(Term): 76 | def __init__(self, term): 77 | self.term = term 78 | 79 | def __str__(self): 80 | # TODO: Implement the printing of `*T` 81 | return f'*{self.term}' 82 | 83 | def to_z3(self): 84 | # ⟦*T⟧ = H(⟦T⟧) 85 | return H(self.term.to_z3()) 86 | 87 | 88 | class TNull(Term): 89 | def __str__(self): 90 | pass 91 | 92 | def to_z3(self): 93 | # ⟦NULL⟧ = 0 94 | return 0 95 | 96 | 97 | # Expression 98 | class Expression: 99 | @abstractmethod 100 | def to_z3(self): 101 | pass 102 | 103 | 104 | class EVar(Expression): 105 | def __init__(self, name, var): 106 | self.name = name 107 | self.var = var 108 | 109 | def __str__(self): 110 | return self.name 111 | 112 | def to_z3(self): 113 | # TODO: Implement the translate procedure of `x` 114 | # [x] = H(S(x)) 115 | return H(S(self.var)) 116 | 117 | 118 | class EConst(Expression): 119 | def __init__(self, value): 120 | self.value = value 121 | 122 | def __str__(self): 123 | return f"{self.value}" 124 | 125 | def to_z3(self): 126 | # TODO: Implement the translate procedure of `n` 127 | # [n] = n 128 | return self.value 129 | 130 | 131 | class EAdd(Expression): 132 | def __init__(self, left, right): 133 | self.left = left 134 | self.right = right 135 | 136 | def __str__(self): 137 | return f"({self.left} + {self.right})" 138 | 139 | def to_z3(self): 140 | # TODO: Implement the translate procedure of `E + E` 141 | # [E + E] = [E] + [E] 142 | return self.left.to_z3() + self.right.to_z3() 143 | 144 | class EMinus(Expression): 145 | def __init__(self, left, right): 146 | self.left = left 147 | self.right = right 148 | 149 | def __str__(self): 150 | return f"({self.left} - {self.right})" 151 | 152 | def to_z3(self): 153 | # TODO: Implement the translate procedure of `E - E` 154 | # [E - E] = [E] - [E] 155 | return self.left.to_z3() - self.right.to_z3() 156 | 157 | 158 | class EStar(Expression): 159 | def __init__(self, term): 160 | self.term = term 161 | 162 | def __str__(self): 163 | return f"*{self.term}" 164 | 165 | def to_z3(self): 166 | # TODO: Implement the translate procedure of `*T` 167 | # [*T] = H(T) 168 | return H(self.term.to_z3()) 169 | 170 | 171 | # Relation 172 | class Relation: 173 | @abstractmethod 174 | def to_z3(self): 175 | pass 176 | 177 | 178 | class RTEq(Relation): 179 | def __init__(self, left, right): 180 | self.left = left 181 | self.right = right 182 | 183 | def __str__(self): 184 | return f"({self.left} = {self.right})" 185 | 186 | def to_z3(self): 187 | # TODO: Implement the translate procedure of `T = T` 188 | # [T = T] = [T] = [T] 189 | return self.left.to_z3() == self.right.to_z3() 190 | 191 | 192 | class RTLess(Relation): 193 | def __init__(self, left, right): 194 | self.left = left 195 | self.right = right 196 | 197 | def __str__(self): 198 | return f"({self.left} < {self.right})" 199 | 200 | def to_z3(self): 201 | # TODO: Implement the translate procedure of `T < T` 202 | # [T < T] = [T] < [T] 203 | return self.left.to_z3() < self.right.to_z3() 204 | 205 | 206 | class REEq(Relation): 207 | def __init__(self, left, right): 208 | self.left = left 209 | self.right = right 210 | 211 | def __str__(self): 212 | return f"({self.left} = {self.right})" 213 | 214 | def to_z3(self): 215 | # TODO: Implement the translate procedure of `E = E` 216 | # [E = E] = [E] = [E] 217 | return self.left.to_z3() == self.right.to_z3() 218 | 219 | 220 | class RELess(Relation): 221 | def __init__(self, left, right): 222 | self.left = left 223 | self.right = right 224 | 225 | def __str__(self): 226 | return f"({self.left} < {self.right})" 227 | 228 | def to_z3(self): 229 | # TODO: Implement the translate procedure of `E < E` 230 | # [E < E] = [E] < [E] 231 | return self.left.to_z3() < self.right.to_z3() 232 | 233 | 234 | # Proposition: 235 | class Proposition: 236 | @abstractmethod 237 | def to_z3(self): 238 | pass 239 | 240 | 241 | class P(Proposition): 242 | def __init__(self, rel): 243 | self.rel = rel 244 | 245 | def __str__(self): 246 | return f"{self.rel}" 247 | 248 | def to_z3(self): 249 | # TODO: Implement the translate procedure of `P` 250 | return self.rel 251 | 252 | 253 | class PNot(Proposition): 254 | def __init__(self, rel): 255 | self.rel = rel 256 | 257 | def __str__(self): 258 | return f"~{self.rel}" 259 | 260 | def to_z3(self): 261 | # TODO: Implement the translate procedure of `~ P` 262 | return Not(self.rel.to_z3()) 263 | 264 | class PAnd(Proposition): 265 | def __init__(self, left, right): 266 | self.left = left 267 | self.right = right 268 | 269 | def __str__(self): 270 | # TODO: Implement the printing of `P ∧ P` 271 | return f'({self.left} /\ {self.right})' 272 | 273 | def to_z3(self): 274 | # TODO: Implement the translate procedure of `P ∧ P` 275 | return And( self.left.to_z3(), self.right.to_z3()) 276 | 277 | 278 | def doit(): 279 | p = Int("p") 280 | a = Int("a") 281 | 282 | # TODO Exercise 8: try to complete pointer logic printing method by implement the missing `__str__` methods in 283 | # each class. 284 | p1 = PAnd(RTEq(TVar("p", p), TAddr("a", a)), REEq(EVar("a", a), EConst(1))) 285 | p2 = RTEq(TStar(TVar("p", p)), EConst(1)) 286 | 287 | # your code should print: ((p = &a) /\ (a = 1)) -> (*p = 1) 288 | print(f"{p1} -> {p2}") 289 | 290 | # TODO Exercise 9: finish the missing code in `to_z3()` methods, make it can translates pointer logic to z3's 291 | # constraints. `to_z3()` methods in the `Term` class are already finished. 292 | prop = Implies(p1.to_z3(), p2.to_z3()) 293 | 294 | # should print: Implies(And(H(S(p)) == S(a), H(S(a)) == 1), H(H(S(p))) == 1) 295 | print(prop) 296 | 297 | s = Solver() 298 | s.add(Not(prop)) 299 | 300 | # should print: unsat 301 | print(s.check()) 302 | 303 | 304 | if __name__ == '__main__': 305 | doit() 306 | -------------------------------------------------------------------------------- /homework9/forward.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Dict, Set, List 3 | 4 | from backward import var_substitution 5 | import imp_ast 6 | import compiler 7 | import tac 8 | import prover 9 | 10 | 11 | # a utility class to represent the code you should fill in. 12 | class Todo(Exception): 13 | pass 14 | 15 | 16 | # for debugging 17 | def print_rou(rou): 18 | rou_str = "\n".join([f"\t{var}: {value}" for var, value in rou.items()]) 19 | print(f"rou: \n" 20 | f"{rou_str}\n") 21 | 22 | 23 | # do the `rou(exp)` operation, transfer the expression by mapping variables to symbolic values 24 | # similar to `symbolic_exp` function in assignment 8 25 | def map_2_rou(exp: imp_ast.Exp, args: List[str], rou: Dict[str, imp_ast.Exp]) ->imp_ast.Exp: 26 | if isinstance(exp, imp_ast.ExpNum): 27 | return exp 28 | 29 | if isinstance(exp, imp_ast.ExpVar): 30 | rou_value = rou[exp.var] 31 | # avoid infinite recursion 32 | if exp.var in args: 33 | return rou_value 34 | else: 35 | return map_2_rou(rou_value, args, rou) 36 | 37 | if isinstance(exp, imp_ast.ExpBop): 38 | left = map_2_rou(exp.left, args, rou) 39 | right = map_2_rou(exp.right, args, rou) 40 | return imp_ast.ExpBop(left, right, exp.bop) 41 | 42 | if isinstance(exp, imp_ast.ExpNeg): 43 | return imp_ast.ExpNeg(map_2_rou(exp.exp, args, rou)) 44 | 45 | 46 | # get `rou_prime` by changing modified variables's mapping value in `rou` to a new ExpVar(var) 47 | # `rou_prime=rou[(x1,..,xn) |-> (y1,..,yn)]` where `(y1,y2 ... ,yn)` are new variables, 48 | # here we create `y` by adding `_prime` to original one's name. 49 | def get_rou_prime(modified_vars: Set[str], rou: Dict[str, imp_ast.Exp]): 50 | rou_prime = rou.copy() 51 | renamed_modified_vars = set() 52 | 53 | for var in modified_vars: 54 | new_name = var+"_prime" 55 | rou_prime[var] = imp_ast.ExpVar(new_name) 56 | renamed_modified_vars.add(new_name) 57 | 58 | return rou_prime, renamed_modified_vars 59 | 60 | 61 | ######################################## 62 | # starting from the code position "pc", walk the code forward, 63 | # maintaining the symbolic state (pc, rou, sigma), where: 64 | # pc is the program counter, pointing to the next instruction to be executed; 65 | # rou is the symbolic store, mapping variables to symbolic values; 66 | # sigma is the invariant set 67 | def vc(func: tac.Function, pc: int, rou: Dict[str, imp_ast.Exp], sigma: Set[int]) -> imp_ast.Exp: 68 | stm = func.stms[pc] 69 | 70 | if isinstance(stm, tac.StmLabel): 71 | pc += 1 72 | return vc(func, pc, rou, sigma) 73 | 74 | elif isinstance(stm, tac.StmGoto): 75 | return vc(func, stm.address, rou, sigma) 76 | 77 | # TODO: Exercise 9 code here: 78 | # recall the verification generation rules: 79 | # 80 | # VC(pc, rou, sigma) = VC(pc++, rou, sigma) pc->Label 81 | # VC(pc, rou, sigma) = VC(pc++, rou[x |-> rou(E)], sigma) pc->x=E 82 | # VC(pc, rou, sigma) = VC(Label, rou, sigma) pc->goto Label 83 | # 84 | # VC(pc, rou, sigma) = rou(E)->VC(L1,rou,sigma) /\ 85 | # ~rou(E)->VC(L2,rou,sigma) pc->if(E, L1, L2) 86 | # 87 | # VC(pc, rou, sigma) = rou(E) /\ 88 | # (∀(y1...yn).rou_prime(E)-> 89 | # VC(pc++, rou_prime, sigma.add(pc)) pc->inv E, pc not in sigma 90 | # where rou_prime = rou[(x1..xn)|->(y1..yn)] 91 | # (x1...xn) is modified variables 92 | # 93 | # VC(pc, rou, sigma) = rou(E) pc->inv E, pc in sigma 94 | # 95 | # VC(pc, rou, sigma) = rou(post["result" |-> E]) pc->return E 96 | elif isinstance(stm, tac.StmAssign): 97 | rou[stm.var] = map_2_rou(stm.exp, func.args, rou) 98 | pc += 1 99 | return vc(func, pc, rou, sigma) 100 | elif isinstance(stm, tac.StmIf): 101 | return imp_ast.ExpBop( 102 | imp_ast.ExpBop( stm.exp, vc(func, stm.true_address, rou, sigma), imp_ast.BOp.IM), 103 | imp_ast.ExpBop( imp_ast.ExpNeg(stm.exp), vc(func, stm.false_address, rou, sigma), imp_ast.BOp.IM), 104 | imp_ast.BOp.AND) 105 | elif isinstance(stm, tac.StmInv): 106 | if pc in sigma: 107 | return map_2_rou(stm.inv, func.args, rou) 108 | else: 109 | rou_prime, renamed_modified_vars = get_rou_prime(stm.modified_vars,rou) 110 | sigma.add(pc) 111 | pc += 1 112 | return imp_ast.ExpBop( 113 | map_2_rou(stm.inv, func.args, rou), 114 | imp_ast.ExpBop( 115 | imp_ast.ExpUni( 116 | renamed_modified_vars, 117 | map_2_rou(stm.inv, func.args, rou_prime)), 118 | vc( func, pc, rou_prime, sigma), 119 | imp_ast.BOp.IM), 120 | imp_ast.BOp.AND) 121 | elif isinstance(stm, tac.StmReturn): 122 | func.post = var_substitution("result", stm.e, func.post) 123 | return map_2_rou(func.post, func.args, rou) 124 | 125 | def vc_func(func: tac.Function) -> imp_ast.Exp: 126 | rou_init = dict(zip(func.args, [imp_ast.ExpVar(arg) for arg in func.args])) 127 | 128 | pre_cond = map_2_rou(func.pre, func.args, rou_init) 129 | vc_cond = vc(func, 0, rou_init, set()) 130 | 131 | # VC = 𝜌(pre) → vc(pc) 132 | return imp_ast.ExpBop(pre_cond, vc_cond, imp_ast.BOp.IM) 133 | 134 | 135 | if __name__ == '__main__': 136 | # fill the modified variables in StmInv 137 | imp_ast.fill_in_modified_vars(imp_ast.fun_foo) 138 | '''imp_ast.fun_foo 139 | pre={n <= 0} 140 | foo(n){ 141 | inv={n <= 5} 142 | modified_vars={n} 143 | while(n < 5){ 144 | n = n + 1; 145 | } 146 | return n; 147 | } 148 | post={result == 5} 149 | ''' 150 | # compile the source code to low-level code: 151 | f = compiler.compile_fun(imp_ast.fun_foo) 152 | print(f) 153 | ''' low-level code 154 | pre=n <= 0 155 | foo(n){ 156 | L_1: 157 | inv=n <= 5, modified_vars={'n'} 158 | if(n < 5, L_2, L_3, -1, -1) 159 | L_2: 160 | n = n + 1 161 | goto L_1, -1 162 | L_3: 163 | return n 164 | } 165 | post=result == 5 166 | ''' 167 | # convert the label address to physical address 168 | f = tac.assemble(f) 169 | print(f) 170 | '''f 171 | pre=n <= 0 172 | foo(n){ 173 | L_1: 174 | inv=n <= 5, modified_vars={'n'} 175 | if(n < 5, L_2, L_3, 3, 6) 176 | L_2: 177 | n = n + 1 178 | goto L_1, 0 179 | L_3: 180 | return n 181 | } 182 | post=result == 5 183 | ''' 184 | # generate verification conditions: 185 | the_vc = vc_func(f) 186 | 187 | # 188 | # TODO: Exercise 9: Finish this generator by filling missing code in the function vc() 189 | # You'll be using the symbolic execution idea from previous assignment. 190 | # 191 | # should print: 192 | # 193 | # (n <= 0) -> ((n <= 5) && 194 | # ∀(n_prime).((n_prime <= 5) -> (((n_prime < 5) -> ((n_prime + 1) <= 5)) && (~(n_prime < 5) -> (n_prime == 5))))) 195 | # the number of nodes in VC: 15 196 | # 197 | print(the_vc) 198 | print("the number of nodes in VC: ", imp_ast.exp_num_nodes(the_vc)) 199 | # 200 | # should print: 201 | # 202 | # Implies(n <= 0, 203 | # And(n <= 5, 204 | # ForAll(n_prime, 205 | # Implies(n_prime <= 5, 206 | # And(Implies(n_prime < 5, 207 | # n_prime + 1 <= 5), 208 | # Implies(Not(n_prime < 5), 209 | # n_prime == 5)))))) 210 | # 211 | # convert and send the generated "the_vc" to Z3 solver, 212 | # to prove or disprove it: 213 | # should print: 214 | # 215 | # 216 | # True 217 | # 218 | print(prover.prove_vc(the_vc)) 219 | 220 | -------------------------------------------------------------------------------- /homework3/dpll.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | # In this problem, you will implement the DPLL algorithm as discussed 4 | # in the class. 5 | 6 | # a utility class to represent the code you should fill in. 7 | class Todo(Exception): 8 | pass 9 | 10 | ######################################## 11 | # This bunch of code declare the syntax for the propositional logic, we 12 | # repeat here: 13 | ''' 14 | P ::= p 15 | | T 16 | | F 17 | | P /\ P 18 | | P \/ P 19 | | P -> P 20 | | ~P 21 | ''' 22 | 23 | 24 | class Prop: 25 | pass 26 | 27 | 28 | class PropVar(Prop): 29 | def __init__(self, var): 30 | self.var = var 31 | 32 | 33 | class PropTrue(Prop): 34 | def __init__(self): 35 | pass 36 | 37 | 38 | class PropFalse(Prop): 39 | def __init__(self): 40 | pass 41 | 42 | 43 | class PropAnd(Prop): 44 | def __init__(self, left, right): 45 | self.left = left 46 | self.right = right 47 | 48 | 49 | class PropOr(Prop): 50 | def __init__(self, left, right): 51 | self.left = left 52 | self.right = right 53 | 54 | 55 | class PropImplies(Prop): 56 | def __init__(self, left, right): 57 | self.left = left 58 | self.right = right 59 | 60 | 61 | class PropNot(Prop): 62 | def __init__(self, p): 63 | self.prop = p 64 | 65 | 66 | ##################### 67 | # We define pretty printing function. 68 | def left_paren(): 69 | print('(', sep='', end='') 70 | 71 | 72 | def right_paren(): 73 | print(')', sep='', end='') 74 | 75 | 76 | def pp(prop): 77 | if prop.__class__ == PropVar: 78 | print(prop.var, sep='', end='') 79 | return 80 | if prop.__class__ == PropTrue: 81 | print('True', sep='', end='') 82 | return 83 | if prop.__class__ == PropFalse: 84 | print('False', sep='', end='') 85 | return 86 | if prop.__class__ == PropAnd: 87 | left_paren() 88 | pp(prop.left) 89 | right_paren() 90 | print('/\\', sep='', end='') 91 | left_paren() 92 | pp(prop.right) 93 | right_paren() 94 | return 95 | if prop.__class__ == PropOr: 96 | left_paren() 97 | pp(prop.left) 98 | right_paren() 99 | print('\\/', sep='', end='') 100 | left_paren() 101 | pp(prop.right) 102 | right_paren() 103 | return 104 | if prop.__class__ == PropImplies: 105 | left_paren() 106 | pp(prop.left) 107 | right_paren() 108 | print('->', sep='', end='') 109 | left_paren() 110 | pp(prop.right) 111 | right_paren() 112 | return 113 | if prop.__class__ == PropNot: 114 | left_paren() 115 | print('~', sep='', end='') 116 | pp(prop.prop) 117 | right_paren() 118 | return 119 | 120 | 121 | # we can convert the above defined syntax into Z3's representation, so 122 | # that we can check it's validity easily: 123 | def toz3(prop): 124 | if prop.__class__ == PropVar: 125 | return Bool(prop.var) 126 | if prop.__class__ == PropImplies: 127 | return Implies(toz3(prop.left), toz3(prop.right)) 128 | # Todo: add your code to handle other cases: 129 | if prop.__class__ == PropTrue: 130 | return True 131 | if prop.__class__ == PropFalse: 132 | return False 133 | if prop.__class__ == PropAnd: 134 | return And( toz3(prop.left), toz3(prop.right)) 135 | if prop.__class__ == PropOr: 136 | return Or( toz3(prop.left), toz3(prop.right)) 137 | if prop.__class__ == PropNot: 138 | return Not( toz3(prop.prop)) 139 | 140 | 141 | ##################### 142 | # a sample test program: 143 | prop = PropImplies(PropVar('p'), PropImplies(PropVar('q'), PropVar('p'))) 144 | pp(prop) 145 | z3prop = toz3(prop) 146 | print('') 147 | print(z3prop) 148 | solver = Solver() 149 | solver.add(Not(z3prop)) 150 | print(solver.check()) 151 | 152 | ##################### 153 | # TODO: please implement the nnf(), cnf() and dpll() algorithm, as discussed 154 | # in the class. 155 | def nnf(prop): 156 | '''convert the prop into nnf 157 | ''' 158 | if prop.__class__ == PropImplies: 159 | return PropOr(PropNot(nnf( prop.left)), nnf( prop.right)) 160 | if prop.__class__ == PropNot: 161 | if prop.prop.__class__ == PropVar: 162 | return prop 163 | if prop.prop.__class__ == PropTrue: 164 | return PropFalse() 165 | if prop.prop.__class__ == PropFalse: 166 | return PropTrue() 167 | if prop.prop.__class__ == PropAnd: 168 | return PropOr(nnf(PropNot(prop.prop.left)), nnf(PropNot(prop.prop.right))) 169 | if prop.prop.__class__ == PropOr: 170 | return PropAnd(nnf(PropNot(prop.prop.left)), nnf(PropNot(prop.prop.right))) 171 | if prop.prop.__class__ == PropImplies: 172 | return PropOr(nnf(prop.prop.left), nnf(prop.prop.right)) 173 | if prop.prop.__class__ == PropNot: 174 | return nnf(prop.prop.prop) 175 | return prop 176 | 177 | 178 | def cnf(prop): 179 | '''convert the prop into cnf 180 | ''' 181 | if prop.__class__ == PropAnd: 182 | return PropAnd( cnf( prop.left), cnf(prop.right)) 183 | if prop.__class__ == PropOr: 184 | if prop.left.__class__ == PropAnd: 185 | return PropAnd(cnf(PropOr(prop.left.left, prop.right)), cnf(PropOr(prop.left.right, prop.right))) 186 | if prop.right.__class__ == PropAnd: 187 | return PropAnd(cnf(PropOr(prop.left, prop.right.left)), cnf(PropOr(prop.left, prop.right.right))) 188 | return PropOr(cnf(prop.left), cnf(prop.right)) 189 | return prop 190 | 191 | def replaceProp(prop, p, value): 192 | if prop.__class__ == PropVar: 193 | if prop.var == p.var: 194 | return value 195 | return prop 196 | if prop.__class__ == PropAnd or prop.__class__ == PropOr: 197 | prop.left = replaceProp(prop.left, p, value) 198 | prop.right = replaceProp(prop.right, p, value) 199 | if prop.__class__ == PropNot: 200 | prop.prop = replaceProp(prop.prop, p, value) 201 | return prop 202 | 203 | def unitProp(prop): 204 | if prop.__class__ == PropAnd: 205 | prop.left=unitProp(prop.left) 206 | prop.right=unitProp(prop.right) 207 | if prop.left.__class__ == PropTrue and prop.right.__class__ == PropTrue: 208 | return PropTrue() 209 | else: 210 | return PropFalse() 211 | if prop.__class__ == PropOr: 212 | prop.left=unitProp(prop.left) 213 | prop.right=unitProp(prop.right) 214 | if prop.left.__class__ == PropFalse and prop.right.__class__ == PropFalse: 215 | return PropFalse() 216 | else: 217 | return PropTrue() 218 | if prop.__class__ == PropNot: 219 | prop = PropNot(unitProp(prop.prop)) 220 | if prop.prop.__class__ == PropFalse: 221 | return PropTrue() 222 | elif prop.prop.__class__ == PropTrue: 223 | return PropFalse() 224 | return prop 225 | 226 | def select_automic(prop): 227 | if prop.__class__ == PropVar: 228 | return prop 229 | if prop.__class__ == PropAnd or prop.__class__ == PropOr: 230 | if select_automic(prop.left).__class__ != PropTrue and select_automic(prop.left).__class__ != PropFalse: 231 | return select_automic(prop.left) 232 | if select_automic(prop.right).__class__ != PropTrue and select_automic(prop.right).__class__ != PropFalse: 233 | return select_automic(prop.right) 234 | return unitProp(prop) 235 | if prop.__class__ == PropNot: 236 | return select_automic(prop.prop) 237 | return prop 238 | 239 | def dpll(prop): 240 | prop = unitProp(prop) 241 | 242 | if prop.__class__ == PropTrue: 243 | return True 244 | elif prop.__class__ == PropFalse: 245 | return False 246 | 247 | p = select_automic(prop) 248 | 249 | if dpll(replaceProp(prop, p, PropTrue())): 250 | return True 251 | return dpll(replaceProp(prop, p, PropFalse())) 252 | 253 | ##################### 254 | # Don't forget to write test cases to test your solution. 255 | # prop: p-> ( q -> p) 256 | # z3 formal: Implies(p, Implies(q, p)) 257 | # 该命题的否定为 unsat -> 该命题为 sat 258 | print(dpll(cnf(nnf(prop)))) 259 | -------------------------------------------------------------------------------- /homework5/calc.py: -------------------------------------------------------------------------------- 1 | # exercise4-6 2 | import counter 3 | from z3 import * 4 | class Todo(Exception): 5 | pass 6 | 7 | ################################## 8 | # The abstract syntax for the Calc language: 9 | class Exp: 10 | pass 11 | 12 | 13 | class ExpVar(Exp): 14 | def __init__(self, x): 15 | self.x = x 16 | 17 | 18 | class ExpAdd(Exp): 19 | def __init__(self, left, right): 20 | self.left = left 21 | self.right = right 22 | 23 | 24 | class ExpSub(Exp): 25 | def __init__(self, left, right): 26 | self.left = left 27 | self.right = right 28 | 29 | 30 | class ExpMul(Exp): 31 | def __init__(self, left, right): 32 | self.left = left 33 | self.right = right 34 | 35 | 36 | class ExpDiv(Exp): 37 | def __init__(self, left, right): 38 | self.left = left 39 | self.right = right 40 | 41 | 42 | # statement 43 | class Stm: 44 | pass 45 | 46 | 47 | class StmAssign(Stm): 48 | def __init__(self, x, e): 49 | self.x = x 50 | self.e = e 51 | 52 | 53 | # function: 54 | class Function: 55 | def __init__(self, name, args, stms, ret): 56 | self.name = name 57 | self.args = args 58 | self.stms = stms 59 | self.ret = ret 60 | 61 | 62 | # a pretty printer 63 | def print_str(s, sep='', end=''): 64 | print(s, sep=sep, end=end) 65 | 66 | 67 | def pp_exp(e): 68 | if isinstance(e, ExpVar): 69 | print_str(e.x) 70 | return 71 | if isinstance(e, ExpAdd): 72 | print_str('(') 73 | pp_exp(e.left) 74 | print_str('+') 75 | pp_exp(e.right) 76 | print_str(')') 77 | return 78 | if isinstance(e, ExpSub): 79 | print_str('(') 80 | pp_exp(e.left) 81 | print_str('-') 82 | pp_exp(e.right) 83 | print_str(')') 84 | return 85 | if isinstance(e, ExpMul): 86 | print_str('(') 87 | pp_exp(e.left) 88 | print_str('*') 89 | pp_exp(e.right) 90 | print_str(')') 91 | return 92 | if isinstance(e, ExpDiv): 93 | print_str('(') 94 | pp_exp(e.left) 95 | print_str('/') 96 | pp_exp(e.right) 97 | print_str(')') 98 | return 99 | 100 | 101 | def pp_stm(s): 102 | if isinstance(s, StmAssign): 103 | print_str(s.x) 104 | print_str('=') 105 | pp_exp(s.e) 106 | print_str(';\n') 107 | return 108 | 109 | 110 | def pp_func(f): 111 | if isinstance(f, Function): 112 | print_str(f.name) 113 | print_str('(') 114 | for x in f.args: 115 | print_str(x) 116 | print_str(', ') 117 | print_str('){\n') 118 | for s in f.stms: 119 | pp_stm(s) 120 | print_str('return ') 121 | print_str(f.ret) 122 | print(';\n}\n') 123 | 124 | 125 | ############################################### 126 | # Generate Z3 constraints: 127 | def gen_cons_exp(file, e): 128 | if isinstance(e, ExpVar): 129 | file.write(e.x) 130 | return 131 | if isinstance(e, ExpAdd): 132 | file.write('f_add(') 133 | gen_cons_exp(file, e.left) 134 | file.write(', ') 135 | gen_cons_exp(file, e.right) 136 | file.write(')') 137 | return 138 | if isinstance(e, ExpSub): 139 | file.write('f_sub(') 140 | gen_cons_exp(file, e.left) 141 | file.write(', ') 142 | gen_cons_exp(file, e.right) 143 | file.write(')') 144 | return 145 | if isinstance(e, ExpMul): 146 | file.write('f_mul(') 147 | gen_cons_exp(file, e.left) 148 | file.write(', ') 149 | gen_cons_exp(file, e.right) 150 | file.write(')') 151 | return 152 | if isinstance(e, ExpDiv): 153 | file.write('f_div(') 154 | gen_cons_exp(file, e.left) 155 | file.write(', ') 156 | gen_cons_exp(file, e.right) 157 | file.write(')') 158 | return 159 | 160 | 161 | def gen_cons_stm(file, s): 162 | if isinstance(s, StmAssign): 163 | file.write(s.x) 164 | file.write(' == ') 165 | gen_cons_exp(file, s.e) 166 | file.write(', ') 167 | return 168 | 169 | 170 | def gen_cons_func(file, f): 171 | if isinstance(f, Function): 172 | print_str(f.name) 173 | # collect all variables 174 | vars = set() 175 | for a in f.args: 176 | vars.add(a) 177 | for s in f.stms: 178 | if isinstance(s, StmAssign): 179 | vars.add(s.x) 180 | # the declarations 181 | file.write('S = DeclareSort(\'S\')\n') 182 | for x in vars: 183 | file.write(x) 184 | file.write(', ') 185 | file.write('junk = Consts(\'') 186 | for x in vars: 187 | file.write(x) 188 | file.write(' ') 189 | file.write('junk\', S)\n') 190 | file.write('f_add = Function(\'f_add\', S, S, S)\n') 191 | file.write('f_sub = Function(\'f_sub\', S, S, S)\n') 192 | file.write('f_mul = Function(\'f_mul\', S, S, S)\n') 193 | file.write('f_div = Function(\'f_div\', S, S, S)\n\n') 194 | file.write('F = And(') 195 | for s in f.stms: 196 | gen_cons_stm(file, s) 197 | file.write(' True)\n\n') 198 | 199 | 200 | def gen_cons_exp(e): 201 | if isinstance(e, ExpVar): 202 | return Const(e.x, DeclareSort('S')) 203 | if isinstance(e, ExpAdd): 204 | left = gen_cons_exp(e.left) 205 | right = gen_cons_exp(e.right) 206 | return z3.Function('f_add', 207 | DeclareSort('S'), 208 | DeclareSort('S'), 209 | DeclareSort('S')).__call__(left, right) 210 | if isinstance(e, ExpSub): 211 | left = gen_cons_exp(e.left) 212 | right = gen_cons_exp(e.right) 213 | return z3.Function('f_sub', 214 | DeclareSort('S'), 215 | DeclareSort('S'), 216 | DeclareSort('S')).__call__(left, right) 217 | if isinstance(e, ExpMul): 218 | left = gen_cons_exp(e.left) 219 | right = gen_cons_exp(e.right) 220 | return z3.Function('f_mul', 221 | DeclareSort('S'), 222 | DeclareSort('S'), 223 | DeclareSort('S')).__call__(left, right) 224 | if isinstance(e, ExpDiv): 225 | left = gen_cons_exp(e.left) 226 | right = gen_cons_exp(e.right) 227 | return z3.Function('f_div', 228 | DeclareSort('S'), 229 | DeclareSort('S'), 230 | DeclareSort('S')).__call__(left, right) 231 | 232 | 233 | def gen_cons_stm(s): 234 | if isinstance(s, StmAssign): 235 | new_exp = gen_cons_exp(s.e) 236 | return Const(s.x, DeclareSort('S')) == new_exp 237 | 238 | 239 | def gen_cons_func(f): 240 | cons = [] 241 | if isinstance(f, Function): 242 | for s in f.stms: 243 | new_cons = gen_cons_stm(s) 244 | cons.append(new_cons) 245 | return cons 246 | 247 | 248 | ############################################### 249 | # SSA conversion: 250 | 251 | # a map from variable to new variable: 252 | var_map = {} 253 | 254 | 255 | def to_ssa_exp(e): 256 | if isinstance(e, ExpVar): 257 | return ExpVar(var_map[e.x]) 258 | if isinstance(e, ExpAdd): 259 | new_left = to_ssa_exp(e.left) 260 | new_right = to_ssa_exp(e.right) 261 | return ExpAdd(new_left, new_right) 262 | if isinstance(e, ExpSub): 263 | new_left = to_ssa_exp(e.left) 264 | new_right = to_ssa_exp(e.right) 265 | return ExpSub(new_left, new_right) 266 | if isinstance(e, ExpMul): 267 | new_left = to_ssa_exp(e.left) 268 | new_right = to_ssa_exp(e.right) 269 | return ExpMul(new_left, new_right) 270 | if isinstance(e, ExpDiv): 271 | new_left = to_ssa_exp(e.left) 272 | new_right = to_ssa_exp(e.right) 273 | return ExpDiv(new_left, new_right) 274 | 275 | 276 | def to_ssa_stm(s): 277 | if isinstance(s, StmAssign): 278 | new_e = to_ssa_exp(s.e) 279 | new_var = counter.fresh_var() 280 | var_map[s.x] = new_var 281 | return StmAssign(new_var, new_e) 282 | 283 | 284 | # take a function 'f', convert it to SSA 285 | def to_ssa_func(f): 286 | if isinstance(f, Function): 287 | # first, put every argument into the map 288 | for arg in f.args: 289 | var_map[arg] = arg 290 | # to convert each statement one by one: 291 | new_stms = [] 292 | for s in f.stms: 293 | new_s = to_ssa_stm(s) 294 | new_stms.append(new_s) 295 | new_ret = var_map[f.ret] 296 | return Function(f.name, f.args, new_stms, new_ret) 297 | 298 | 299 | if __name__ == '__main__': 300 | # a sample program: 301 | sample_f = Function('f', 302 | ['x1', 'x2', 'y1', 'y2'], 303 | [StmAssign('z', ExpMul(ExpAdd(ExpVar('x1'), ExpVar('y1')), 304 | ExpAdd(ExpVar('x2'), ExpVar('y2'))))], 305 | 'z') 306 | # print the original program 307 | pp_func(sample_f) 308 | # convert it to SSA 309 | new_f = to_ssa_func(sample_f) 310 | # print the converted program 311 | pp_func(new_f) 312 | # generate Z3 constraints 313 | print( gen_cons_func(new_f)) 314 | -------------------------------------------------------------------------------- /homework3/exercise1.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | # Z3 is an SMT solver. In this lecture, we'll discuss 4 | # the basis usage of Z3 through some working example, the 5 | # primary goal is to introduce how to use Z3 to solve 6 | # the satisfiability problems we've discussed in the past 7 | # several lectures. 8 | # We must emphasize that Z3 is just one of the many such SMT 9 | # solvers, and by introducing Z3, we hope you will have a 10 | # general understanding of what such solvers look like, and 11 | # what they can do. 12 | class Todo(Exception): 13 | pass 14 | 15 | ######################################## 16 | # Basic propositional logic 17 | 18 | # In Z3, we can declare two propositions just as booleans, this 19 | # is rather natural, for propositions can have values true or false. 20 | # To declare two propositions P and Q: 21 | P = Bool('P') 22 | Q = Bool('Q') 23 | # or, we can use a more compact shorthand: 24 | P, Q = Bools('P Q') 25 | 26 | # We can build propositions by writing Lisp-style abstract 27 | # syntax trees, for example, the disjunction: 28 | # P \/ Q 29 | # can be encoded as the following AST: 30 | F = Or(P, Q) 31 | 32 | # Note that the connective '\/' is called 'Or' in Z3, we'll see 33 | # several other in the next. 34 | 35 | # The simplest usage for Z3 is to feed the proposition to Z3 36 | # directly, to check the satisfiability, this can be done by 37 | # calling the # 'solve()' function: 38 | solve(F) 39 | 40 | # Simply speaking, the "solve()" function will create an instance 41 | # of solver, check the satisfiability of the proposition, and 42 | # output a model in which that proposition is satisfiable. 43 | 44 | # For the above call, the Z3 will output something like this: 45 | # [P=True, Q=False] 46 | # which is a model with assignments to proposition P and Q that 47 | # makes the proposition F satisfiable. Obviously, this is just 48 | # one of several possible models. 49 | 50 | # Same as disjunction, the conjunction 51 | # P /\ ~Q 52 | # can be encoded as the following AST 53 | F = And(P, Not(Q)) 54 | 55 | # Note that we use Not(Q) to encode ~Q 56 | 57 | # Then we use solve to find a model that satisfy the proposition 58 | solve(F) 59 | 60 | 61 | ########################################################### 62 | # TODO: Exercise 1-1 63 | # Now you have know the basic usage of using z3 to find the solution that 64 | # will satisfy a proposition. 65 | # 66 | # Try to find solution that satisfies proposition 67 | # (P /\ Q) \/ R 68 | P, Q, R = Bools('P Q R') 69 | # TODO: replace the following line with: F = (P /\ Q) \/ R 70 | '''Fill your code here, replace the following line:''' 71 | print('\nExercise 1-1: (P /\ Q) \/ R') 72 | F = Or(And(P,Q),R) 73 | solve(F) 74 | 75 | 76 | # Try to find solution that satisfies proposition 77 | # P \/ (Q \/ R) 78 | P, Q, R = Bools('P Q R') 79 | # TODO: fill code to let 'F' can describe P \/ (Q \/ R) 80 | '''Fill your code here, replace the following line:''' 81 | print('\nExercise 1-1: P \/ (Q \/ R)') 82 | F = Or(P,Q,R) 83 | solve(F) 84 | 85 | 86 | ########################################################### 87 | # In Exercise 1-1 you've see the basic usage of z3 for describing propositions. 88 | # Like And, Or, Not. Also how to use the solve method to get the solution. 89 | 90 | # But keep in mind that not all propositions are satisfiable, consider: 91 | # F = P /\ ~P 92 | P = Bool('P') 93 | F = And(P, Not(P)) 94 | solve(F) 95 | 96 | # Z3 will output: 97 | # "no solution" 98 | # which indicates that the proposition F is not satisfiable, that 99 | # is, the proposition F cannot be true for any possible values 100 | # of P. 101 | 102 | 103 | # TODO: Exercise 1-2. 104 | # Consider proposition (P \/ Q) /\ (Q /\ R) /\ (P /\ ~R). Complete below code, 105 | # Z3 will show you that no solution can satisfy it. 106 | P, Q, R = Bools('P Q R') 107 | # TODO: fill your code here, replace the following line: 108 | print( '\nexerciese 1-2: (P \/ Q) /\ (Q /\ R) /\ (P /\ ~R).') 109 | F = And( Or(P,Q), And(Q,R), And( P, Not(R)) ) 110 | solve(F) 111 | 112 | 113 | # TODO: Exercise 1-3 114 | # Try to solve proposition 115 | # (P /\ ~S /\ R) /\ (R /\ ( ~P \/ (S /\ ~Q))) 116 | # TODO: fill your code here, replace the following line: 117 | P,S,R,Q = Bools('P S R Q') 118 | print( '\nexercise 1-3: (P /\ ~S /\ R) /\ (R /\ ( ~P \/ (S /\ ~Q)))') 119 | F = And( And( P, Not(S), R), And( R, Or( Not(P), And( S, Not(Q))))) 120 | solve(F) 121 | 122 | ########################################################### 123 | # You may notice that some problems in Exercise 1 has more than one solutions 124 | # that satisfy it, but the solve method only provider you 1 solution. 125 | # To Get another solution that can satisfy it. What you need to do is add 126 | # constraints to solver to get different solutions as below example. 127 | 128 | # Consider again our first example, in exercise 1: 129 | # P \/ Q 130 | # By default, Z3 only outputs the one row in 131 | # the truth table: 132 | """ 133 | P Q P\/Q 134 | t t t 135 | t f t 136 | f t t 137 | f f f 138 | """ 139 | # After all, we're asking Z3 about the satisfiability of the 140 | # proposition, so one row of evidence is enough. 141 | 142 | # What if we want Z3 to output all the assignment of propositions 143 | # that make the proposition satisfiable, not just the first one. For the 144 | # above example, we want the all first 3 rows. 145 | 146 | # Here is the trick: when we get an answer, we negate the 147 | # answer, make a conjunction 148 | # with the original proposition, then check the satisfiability 149 | # again. For the above example: 150 | P, Q = Bools('P Q') 151 | F = Or(P, Q) 152 | # Z3 outputs: 153 | # [P=True, Q=False] 154 | # we want to build this: 155 | F = And(F, Not(And(P, Not(Q)))) 156 | solve(F) 157 | # Z3 output this: 158 | # [P = False, Q = True] 159 | # continue the building process: 160 | F = And(F, Not(And(Not(P), Q))) 161 | solve(F) 162 | # Z3 output this: 163 | # [P = True, Q = True] 164 | # continue the building process: 165 | F = And(F, Not(And(P, Q))) 166 | solve(F) 167 | # Z3 output this: 168 | # "no solution" 169 | 170 | # In fact, what we Add to F can be treated as constraints, by add negation of 171 | # each solution given by solve method, we can get a new solution which is 172 | # different from solutions we get before. We doing this until no new solution 173 | # can be found, aka. "no solution" by solve, that means we get all solutions. 174 | 175 | 176 | # TODO: Exercise 1-4 177 | # Now you have know how to add constraint to solver to get different solutions 178 | # from z3. Try to get **all solutions** that satisfy the proposition in Exercise 1: 179 | # (P /\ Q) \/ R 180 | P, Q, R = Bools('P Q R') 181 | '''Your code begin, replace the following line:''' 182 | print('\nexercise 1-4:') 183 | F = Or( R, And( P,Q)) 184 | solve(F) 185 | F = And(F, Not( And(Not(R), P,Q))) 186 | solve(F) 187 | F = And(F, Not( And(R, P,Q))) 188 | solve(F) 189 | F = And(F, Not( And(R, Not(P),Not(Q)))) 190 | solve(F) 191 | F = And(F, Not( And(R, P,Not(Q)))) 192 | solve(F) 193 | F = And(F, Not( And(R, Not(P),Q))) 194 | solve(F) 195 | 196 | 197 | # We can automate the above process, for this, we should expose 198 | # more internal capability of Z3. Consider our first example again: 199 | # P /\ Q 200 | 201 | # To create a new SMT solver: 202 | solver = Solver() 203 | 204 | P, Q = Bools('P Q') 205 | F = Or(P, Q) 206 | # add the proposition F into the solver: 207 | solver.add(F) 208 | # you can add more propositions into the solver, and the solver 209 | # will try to check the conjunction of these propositions. 210 | 211 | # To check whether or not the current solver is satisfiable: 212 | print(solver.check()) 213 | # meanwhile, also store other results, say, the concrete values 214 | # for the propositions, etc.. 215 | 216 | # To get the model: 217 | print(solver.model()) 218 | # this is effective, only if the solver is "sat". To be specific, 219 | # the model contains all the values for propositions (a map): 220 | m = solver.model() 221 | print(m[P], m[Q]) 222 | 223 | # To wrap these together, we have this code: 224 | solver = Solver() 225 | # to add the proposition F again: 226 | P, Q = Bools('P Q') 227 | props = [P, Q] 228 | F = Or(P, Q) 229 | solver.add(F) 230 | print(solver.check()) 231 | print(solver.model()) 232 | 233 | 234 | # TODO: Exercise 1-5 235 | # Now it's your turn, let's wrap all these facility into a nice function: 236 | # Read and understand the code, then complete the lost part. 237 | 238 | print('\nexercise 1-5:') 239 | def sat_all(props, f): 240 | """Get all solutions of given proposition set props that satisfy f 241 | 242 | Arguments: 243 | props {BoolRef} -- Proposition list 244 | f {Boolref} -- logical express that consist of props 245 | """ 246 | solver = Solver() 247 | solver.add(f) 248 | result = [] 249 | while solver.check() == sat: 250 | m = solver.model() 251 | result.append(m) 252 | block = [] 253 | for prop in props: 254 | if m.eval(prop, True): 255 | # TODO: Fill your code here 256 | '''Your code begin, replace the following line:''' 257 | new_prop = prop 258 | else: 259 | new_prop = Not(prop) 260 | block.append(new_prop) 261 | # TODO: Fill your code here 262 | '''Your code begin''' 263 | temp = True 264 | for prop in block: 265 | temp = And( temp, prop) 266 | new_prop = And( f, Not( temp)) 267 | solver.add(new_prop) 268 | print("the given proposition: ", f) 269 | print("the number of solutions: ", len(result)) 270 | 271 | def print_model(m): 272 | print(sorted([(d, m[d]) for d in m], key=lambda x: str(x[0]))) 273 | for m in result: 274 | print_model(m) 275 | 276 | 277 | # If you complete the function. Try to use it for below props. 278 | sat_all([P, Q], Or(P, Q)) 279 | sat_all([P], Implies(P, P)) 280 | 281 | # Well done, you've complete exercise 1. Remember to save it for later hands in. -------------------------------------------------------------------------------- /homework8/symbolic.py: -------------------------------------------------------------------------------- 1 | import multiprocessing as mp 2 | from dataclasses import dataclass 3 | from typing import List, Dict 4 | 5 | from z3 import * 6 | from ast import * 7 | 8 | 9 | # a symbolic execution engine. 10 | 11 | # symbolic execution memory model will store arguments, symbolic values and path condition 12 | @dataclass 13 | class Memory: 14 | args: List[str] 15 | symbolic_memory: Dict[str, Exp] 16 | path_condition: List[Exp] 17 | 18 | def __str__(self): 19 | arg_str = ",".join(self.args) 20 | exp_str = "\n".join([f"\t{var} = {value}" for var, value in self.symbolic_memory.items()]) 21 | cond_str = ",".join([str(cond) for cond in self.path_condition]) 22 | return (f"Arguments: {arg_str}\n" 23 | f"Path Condition: {cond_str}\n" 24 | f"Symbol Memory: \n" 25 | f"{exp_str}\n") 26 | 27 | 28 | # negate the condition 29 | def neg_exp(exp): 30 | if exp.bop is BOp.EQ: 31 | return ExpBop(exp.left, exp.right, BOp.NE) 32 | if exp.bop is BOp.NE: 33 | return ExpBop(exp.left, exp.right, BOp.EQ) 34 | if exp.bop is BOp.GT: 35 | return ExpBop(exp.left, exp.right, BOp.LE) 36 | if exp.bop is BOp.GE: 37 | return ExpBop(exp.left, exp.right, BOp.LT) 38 | if exp.bop is BOp.LT: 39 | return ExpBop(exp.left, exp.right, BOp.GE) 40 | if exp.bop is BOp.LE: 41 | return ExpBop(exp.left, exp.right, BOp.GT) 42 | 43 | 44 | ##################### 45 | # compile AST expression to Z3 46 | def exp_2_z3(exp): 47 | if isinstance(exp, ExpNum): 48 | return exp.num 49 | if isinstance(exp, ExpVar): 50 | # TODO: Exercise 7 Code Here 51 | # transfer the ExpVar to z3 Int 52 | return Int( str(exp.var)) 53 | if isinstance(exp, ExpBop): 54 | # TODO: Exercise 7 Code Here 55 | # transfer the ExpBop 56 | if exp.bop == BOp.ADD: 57 | return (exp_2_z3(exp.left) + exp_2_z3(exp.right)) 58 | elif exp.bop == BOp.MIN: 59 | return (exp_2_z3(exp.left) - exp_2_z3(exp.right)) 60 | elif exp.bop == BOp.MUL: 61 | return (exp_2_z3(exp.left) * exp_2_z3(exp.right)) 62 | elif exp.bop == BOp.DIV: 63 | return (exp_2_z3(exp.left) / exp_2_z3(exp.right)) 64 | elif exp.bop == BOp.EQ: 65 | return (exp_2_z3(exp.left) == exp_2_z3(exp.right)) 66 | elif exp.bop == BOp.NE: 67 | return (exp_2_z3(exp.left) != exp_2_z3(exp.right)) 68 | elif exp.bop == BOp.GT: 69 | return (exp_2_z3(exp.left) > exp_2_z3(exp.right)) 70 | elif exp.bop == BOp.GE: 71 | return (exp_2_z3(exp.left) >= exp_2_z3(exp.right)) 72 | elif exp.bop == BOp.LT: 73 | return (exp_2_z3(exp.left) < exp_2_z3(exp.right)) 74 | elif exp.bop == BOp.LE: 75 | return (exp_2_z3(exp.left) <= exp_2_z3(exp.right)) 76 | 77 | # use Z3 to solve conditions 78 | def check_cond(memory, add_cond=None): 79 | solver = Solver() 80 | 81 | # add path condition 82 | for cond in memory.path_condition: 83 | solver.add(exp_2_z3(cond)) 84 | 85 | # add additional condition 86 | if add_cond: 87 | for cond in add_cond: 88 | solver.add(exp_2_z3(symbolic_exp(memory, cond))) 89 | 90 | check_result = solver.check() 91 | 92 | return check_result, solver 93 | 94 | 95 | ##################### 96 | # symbolic execution 97 | def symbolic_exp(memory, exp): 98 | if isinstance(exp, ExpNum): 99 | return exp 100 | 101 | if isinstance(exp, ExpVar): 102 | # TODO: Exercise 5 Code Here 103 | # transfer the ExpVar to Exp which only contains argument variables 104 | # and ExpNum 105 | var = memory.symbolic_memory[str(exp.var)] 106 | 107 | if isinstance(var, ExpVar): 108 | return ExpVar(var) 109 | elif isinstance(var, ExpNum): 110 | return symbolic_exp(memory,var) 111 | elif str(var.left) == str(exp) or str(var.right) == str(exp): 112 | ''' prevent stack overflow 113 | ''' 114 | return ExpBop(var.left, var.right, var.bop) 115 | return ExpBop(symbolic_exp(memory, var.left), symbolic_exp(memory, var.right),var.bop) 116 | 117 | if isinstance(exp, ExpBop): 118 | # TODO: Exercise 5 Code Here 119 | # transfer ExpBop's left and right expression recursive 120 | return ExpBop(symbolic_exp(memory, exp.left), symbolic_exp(memory, exp.right), exp.bop) 121 | 122 | 123 | def symbolic_stm(memory, stm, rest_stms, results): 124 | if isinstance(stm, StmAssign): 125 | # TODO: Exercise 6 Code Here 126 | # process StmAssign by updating symbolic memory 127 | memory.symbolic_memory[stm.var] = symbolic_exp(memory,stm.exp) 128 | symbolic_stms(memory, rest_stms, results) 129 | if isinstance(stm, StmIf): 130 | # TODO: Exercise 6 Code Here 131 | # process StmIf by forking two processes 132 | # one of them will symbolic execute then_stms and rest_stms 133 | # other one will symbolic execute else_stms and rest_stms 134 | # also, start them and wait them to join 135 | rest_stms_then = [ i for i in stm.then_stms] 136 | rest_stms_else = [ i for i in stm.else_stms] 137 | for i in rest_stms: 138 | rest_stms_then.append(i) 139 | rest_stms_else.append(i) 140 | p1 = mp.Process(target = symbolic_stms,args = (memory,rest_stms_then,results, stm.exp)) 141 | p2 = mp.Process(target = symbolic_stms,args = (memory,rest_stms_else,results, neg_exp(stm.exp))) 142 | p1.start() 143 | p2.start() 144 | p1.join() 145 | p2.join() 146 | 147 | 148 | def symbolic_stms(memory, stms, results, condition=None): 149 | if condition: 150 | memory.path_condition.append(symbolic_exp(memory, condition)) 151 | 152 | if not stms: 153 | results.put(memory) 154 | else: 155 | symbolic_stm(memory, stms[0], stms[1:], results) 156 | 157 | return results 158 | 159 | 160 | def symbolic_function(func): 161 | # init memory 162 | init_params = [ExpVar(arg) for arg in func.args] 163 | memory = Memory(func.args, dict(zip(func.args, init_params)), []) 164 | 165 | results = symbolic_stms(memory, func.stms, mp.SimpleQueue()) 166 | result_list = [] 167 | 168 | while not results.empty(): 169 | result = results.get() 170 | print(result) 171 | result_list.append(result) 172 | 173 | return result_list 174 | 175 | 176 | ############################### 177 | # test code 178 | f1 = Function('f2', ['a', "b"], 179 | [StmAssign('x', ExpNum(1)), 180 | StmAssign('y', ExpNum(0)), 181 | StmIf(ExpBop(ExpVar('a'), ExpNum(0), BOp.NE), 182 | [StmAssign('y', ExpBop(ExpVar('x'), ExpNum(3), BOp.ADD)), 183 | StmIf(ExpBop(ExpVar('b'), ExpNum(0), BOp.EQ), 184 | [StmAssign('x', ExpBop(ExpNum(2), ExpBop(ExpVar('a'), ExpVar('b'), BOp.ADD), BOp.MUL))], 185 | [])], 186 | []) 187 | ], ExpVar('x')) 188 | 189 | 190 | if __name__ == '__main__': 191 | 192 | example_memory = Memory(args=["a", "b", "c"], 193 | symbolic_memory={"a": ExpVar("a"), 194 | "b": ExpBop(ExpNum(42), ExpVar("a"), BOp.MIN), 195 | "c": ExpBop(ExpVar("c"), ExpNum(20), BOp.ADD), 196 | "m": ExpBop(ExpVar("b"), ExpNum(5), BOp.MUL), 197 | "n": ExpBop(ExpVar("c"), ExpNum(2), BOp.MUL)}, 198 | path_condition=[]) 199 | 200 | example_exp = ExpBop(ExpVar("m"), ExpVar("n"), BOp.EQ) 201 | 202 | # TODO: Exercise 5: Fill code in the function `symbolic_exp` 203 | # You should replace the variables in the expression according to the 204 | # symbolic memory. The result will be an expression only contains argument 205 | # variables(ExpVar("arg") and ExpNum. 206 | # 207 | # Exercise 5 Should output: 208 | # 209 | # [m == n] ===> [((42 - a) * 5) == ((c + 20) * 2)] 210 | # 211 | print(f"[{example_exp}] ===> [{symbolic_exp(example_memory, example_exp)}]\n") 212 | 213 | # TODO: Exercise 6: Fill code in the function `symbolic_stm` 214 | # Here you should deal with `StmAssign` and `StmIf`, the `StmAssign` 215 | # will update the symbolic memory; In the `StmIf` you should do the branch 216 | # splitting, recall how to use Python's multiprocessing in Exercise 4 217 | # 218 | # Should output(the order may different): 219 | # 220 | # Arguments: a,b 221 | # Path Condition: a == 0 222 | # Symbol Memory: 223 | # a = a 224 | # b = b 225 | # x = 1 226 | # y = 0 227 | # 228 | # Arguments: a,b 229 | # Path Condition: a != 0, b != 0 230 | # Symbol Memory: 231 | # a = a 232 | # b = b 233 | # x = 1 234 | # y = 1 + 3 235 | # 236 | # Arguments: a,b 237 | # Path Condition: a != 0, b == 0 238 | # Symbol Memory: 239 | # a = a 240 | # b = b 241 | # x = 2 * (a + b) 242 | # y = 1 + 3 243 | # 244 | print(f1) 245 | result_memories = symbolic_function(f1) 246 | 247 | # TODO: Exercise 7: Fill code in the function `exp_2_z3`. 248 | # make it can transfers the conditions(AST Node) to z3 constraints. 249 | # note that our program only contains integer number 250 | # 251 | # Should output: 252 | # 253 | # Conditions: [a != 0, b == 0, 2 * (a + b) - 4 == 0] 254 | # SAT Input: a = 2, b = 0 255 | # 256 | 257 | # additional condition need to check: x - y = 0 258 | check_conditions = [ExpBop(ExpBop(ExpVar('x'), ExpVar('y'), BOp.MIN), ExpNum(0), BOp.EQ)] 259 | 260 | for result_memory in result_memories: 261 | ret, s = check_cond(result_memory, check_conditions) 262 | if ret == sat: 263 | print(f"Conditions: {s}") 264 | print(f"SAT Input: {s.model()}") 265 | -------------------------------------------------------------------------------- /homework5/tac.py: -------------------------------------------------------------------------------- 1 | import counter 2 | from z3 import * 3 | 4 | 5 | class Todo(Exception): 6 | pass 7 | 8 | 9 | ################################## 10 | # The abstract syntax for the Tac (three address code) language: 11 | 12 | # statement 13 | class Stm: 14 | pass 15 | 16 | 17 | class StmAssignVar(Stm): 18 | def __init__(self, x, y): 19 | self.x = x 20 | self.y = y 21 | 22 | 23 | class StmAssignAdd(Stm): 24 | def __init__(self, x, y, z): 25 | self.x = x 26 | self.y = y 27 | self.z = z 28 | 29 | 30 | class StmAssignSub(Stm): 31 | def __init__(self, x, y, z): 32 | self.x = x 33 | self.y = y 34 | self.z = z 35 | 36 | 37 | class StmAssignMul(Stm): 38 | def __init__(self, x, y, z): 39 | self.x = x 40 | self.y = y 41 | self.z = z 42 | 43 | 44 | class StmAssignDiv(Stm): 45 | def __init__(self, x, y, z): 46 | self.x = x 47 | self.y = y 48 | self.z = z 49 | 50 | 51 | # function: 52 | class Function: 53 | def __init__(self, name, args, stms, ret): 54 | self.name = name 55 | self.args = args 56 | self.stms = stms 57 | self.ret = ret 58 | 59 | 60 | # a pretty printer 61 | def print_str(s, sep='', end=''): 62 | print(s, sep=sep, end=end) 63 | 64 | 65 | def pp_stm(s): 66 | # TODO: your code here: 67 | if isinstance( s, StmAssignVar): 68 | print_str(s.x) 69 | print_str('=') 70 | print_str(s.y) 71 | print_str(';\n') 72 | elif isinstance( s, StmAssignAdd): 73 | print_str(s.x) 74 | print_str('=') 75 | print_str(s.y) 76 | print_str('+') 77 | print_str(s.z) 78 | print_str(';\n') 79 | elif isinstance( s, StmAssignSub): 80 | print_str(s.x) 81 | print_str('=') 82 | print_str(s.y) 83 | print_str('-') 84 | print_str(s.z) 85 | print_str(';\n') 86 | elif isinstance( s, StmAssignMul): 87 | print_str(s.x) 88 | print_str('=') 89 | print_str(s.y) 90 | print_str('*') 91 | print_str(s.z) 92 | print_str(';\n') 93 | elif isinstance( s, StmAssignDiv): 94 | print_str(s.x) 95 | print_str('=') 96 | print_str(s.y) 97 | print_str('/') 98 | print_str(s.z) 99 | print_str(';\n') 100 | 101 | 102 | 103 | def pp_func(f): 104 | # TODO: your code here: 105 | if isinstance(f, Function): 106 | print_str(f.name) 107 | print_str('(') 108 | for x in f.args: 109 | print_str(x) 110 | print_str(', ') 111 | print_str('){\n') 112 | for s in f.stms: 113 | pp_stm(s) 114 | print_str('return ') 115 | print_str(f.ret) 116 | print(';\n}\n') 117 | 118 | 119 | ############################################### 120 | # Generate Z3 constraints: 121 | def gen_cons_stm(file, s): 122 | # TODO: your code here: 123 | if isinstance( s, StmAssignVar): 124 | file.write(s.x) 125 | file.write('=') 126 | file.write(s.y) 127 | elif isinstance( s, StmAssignAdd): 128 | file.write(s.x) 129 | file.write('=') 130 | file.write('f_add(') 131 | file.write(s.y) 132 | file.write(',') 133 | file.write(s.z) 134 | file.write(')') 135 | file.write(',') 136 | 137 | elif isinstance( s, StmAssignSub): 138 | file.write(s.x) 139 | file.write('=') 140 | file.write('f_sub(') 141 | file.write(s.y) 142 | file.write(',') 143 | file.write(s.z) 144 | file.write(')') 145 | file.write(',') 146 | elif isinstance( s, StmAssignMul): 147 | file.write(s.x) 148 | file.write('=') 149 | file.write('f_mul(') 150 | file.write(s.y) 151 | file.write(',') 152 | file.write(s.z) 153 | file.write(')') 154 | file.write(',') 155 | elif isinstance( s, StmAssignDiv): 156 | file.write(s.x) 157 | file.write('=') 158 | file.write('f_div(') 159 | file.write(s.y) 160 | file.write(',') 161 | file.write(s.z) 162 | file.write(')') 163 | file.write(',') 164 | 165 | 166 | def gen_cons_func(file, f): 167 | # TODO: your code here: 168 | if isinstance(f, Function): 169 | print_str(f.name) 170 | # collect all variables 171 | vars = set() 172 | for a in f.args: 173 | vars.add(a) 174 | for s in f.stms: 175 | vars.add(s.x) 176 | file.write('S = DeclareSort(\'S\')\n') 177 | for x in vars: 178 | file.write(x) 179 | file.write(', ') 180 | file.write('junk = Consts(\'') 181 | for x in vars: 182 | file.write(x) 183 | file.write(' ') 184 | file.write('junk\', S)\n') 185 | file.write('f_add = Function(\'f_add\', S, S, S)\n') 186 | file.write('f_sub = Function(\'f_sub\', S, S, S)\n') 187 | file.write('f_mul = Function(\'f_mul\', S, S, S)\n') 188 | file.write('f_div = Function(\'f_div\', S, S, S)\n\n') 189 | file.write('F = And(') 190 | for s in f.stms: 191 | gen_cons_stm(file, s) 192 | file.write(' True)\n\n') 193 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 194 | def gen_cons_stm(s): 195 | # TODO: your code here: 196 | if isinstance( s, StmAssignVar): 197 | return Const( s.x, DeclareSort('S')) == Const( s.y, DeclareSort('S')) 198 | left = Const(s.y, DeclareSort('S')) 199 | right = Const(s.z, DeclareSort('S')) 200 | if isinstance( s, StmAssignAdd): 201 | return Const( s.x, DeclareSort('S')) == z3.Function('f_add', 202 | DeclareSort('S'), 203 | DeclareSort('S'), 204 | DeclareSort('S')).__call__(left, right) 205 | elif isinstance( s, StmAssignSub): 206 | return Const( s.x, DeclareSort('S')) == z3.Function('f_sub', 207 | DeclareSort('S'), 208 | DeclareSort('S'), 209 | DeclareSort('S')).__call__(left, right) 210 | elif isinstance( s, StmAssignMul): 211 | return Const( s.x, DeclareSort('S')) == z3.Function('f_mul', 212 | DeclareSort('S'), 213 | DeclareSort('S'), 214 | DeclareSort('S')).__call__(left, right) 215 | elif isinstance( s, StmAssignDiv): 216 | return Const( s.x, DeclareSort('S')) == z3.Function('f_div', 217 | DeclareSort('S'), 218 | DeclareSort('S'), 219 | DeclareSort('S')).__call__(left, right) 220 | 221 | def gen_cons_func(f): 222 | # TODO: your code here: 223 | cons = [] 224 | if isinstance(f, Function): 225 | for s in f.stms: 226 | new_cons = gen_cons_stm(s) 227 | cons.append(new_cons) 228 | return cons 229 | ############################################### 230 | 231 | # SSA conversion: 232 | 233 | # a map from variable to new variable: 234 | var_map = {} 235 | 236 | 237 | def to_ssa_stm(s): 238 | # TODO: your code here: 239 | if isinstance( s, StmAssignVar): 240 | new_y = var_map[s.y] 241 | new_x = counter.fresh_var() 242 | var_map[s.x] = new_x 243 | return StmAssignVar(new_x, new_y) 244 | 245 | elif isinstance( s, StmAssignAdd): 246 | new_y = var_map[s.y] 247 | new_z = var_map[s.z] 248 | new_x = counter.fresh_var() 249 | var_map[s.x] = new_x 250 | return StmAssignAdd(new_x, new_y, new_z) 251 | 252 | elif isinstance( s, StmAssignSub): 253 | new_y = var_map[s.y] 254 | new_z = var_map[s.z] 255 | new_x = counter.fresh_var() 256 | var_map[s.x] = new_x 257 | return StmAssignSub(new_x, new_y, new_z) 258 | elif isinstance( s, StmAssignMul): 259 | new_y = var_map[s.y] 260 | new_z = var_map[s.z] 261 | new_x = counter.fresh_var() 262 | var_map[s.x] = new_x 263 | return StmAssignMul(new_x, new_y, new_z) 264 | elif isinstance( s, StmAssignDiv): 265 | new_y = var_map[s.y] 266 | new_z = var_map[s.z] 267 | new_x = counter.fresh_var() 268 | var_map[s.x] = new_x 269 | return StmAssignDiv(new_x, new_y, new_z) 270 | 271 | 272 | # take a function 'f', convert it to SSA 273 | def to_ssa_func(f): 274 | # TODO: your code here: 275 | if isinstance(f, Function): 276 | for arg in f.args: 277 | var_map[arg] = arg 278 | new_stms = [] 279 | for s in f.stms: 280 | new_s = to_ssa_stm(s) 281 | new_stms.append(new_s) 282 | new_ret = var_map[f.ret] 283 | return Function( f.name, f.args, new_stms, new_ret) 284 | 285 | 286 | if __name__ == '__main__': 287 | # a sample program: 288 | sample_f = Function('f', 289 | ['x1', 'x2', 'y1', 'y2'], 290 | [StmAssignAdd('t1', 'x1', 'y1'), 291 | StmAssignAdd('t2', 'x2', 'y2'), 292 | StmAssignMul('t3', 't1', 't2'), 293 | StmAssignVar('z', 't3')], 294 | 'z') 295 | ''' 296 | f(x1,x2,y1,y2) { 297 | t1 = x1 + y1 298 | t2 = x2 + y2 299 | t3 = t1 + t2 300 | z = t3 301 | return z 302 | } 303 | ''' 304 | # print the original program 305 | pp_func(sample_f) 306 | # convert it to SSA 307 | ssa_for_f = to_ssa_func(sample_f) 308 | # print the converted program 309 | pp_func(ssa_for_f) 310 | # generate Z3 constraints 311 | ''' 之前的可以存储到 1.txt 中的代码 312 | fp = open(os.getcwd() + '/homework5/1.txt', 'w+') 313 | gen_cons_func(fp,ssa_for_f) 314 | fp.close() 315 | ''' 316 | print(gen_cons_func(ssa_for_f)) 317 | -------------------------------------------------------------------------------- /homework9/imp_ast.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | from typing import List, Set 3 | 4 | # a utility class to represent the code you should fill in. 5 | class Todo(Exception): 6 | pass 7 | 8 | ######################################## 9 | # This bunch of code declare the syntax for the language C--, as we 10 | # discussed in the class. 11 | # but we add bop implication: ->, add: &&, or: || 12 | # and negation: ~, universal quantification: ∀ 13 | ''' 14 | bop ::= + | - | * | / | == | != | > | < | >= | <= | -> 15 | E ::= n | x | E bop E | ~E | ∀(x1, …, xn).E 16 | S ::= skip 17 | | x=E 18 | | S;S 19 | | f(E1, …, En) 20 | | if(E, S, S) 21 | | while(E, S) 22 | F ::= f(x1, …, xn){S; return E;} 23 | ''' 24 | 25 | 26 | ################################## 27 | # bops 28 | 29 | 30 | class BOp(Enum): 31 | ADD = "+" 32 | MIN = "-" 33 | MUL = "*" 34 | DIV = "/" 35 | EQ = "==" 36 | NE = "!=" 37 | GT = ">" 38 | GE = ">=" 39 | LT = "<" 40 | LE = "<=" 41 | IM = "->" 42 | AND = "&&" 43 | OR = "||" 44 | 45 | 46 | ########################################## 47 | # expressions 48 | 49 | 50 | class Exp: 51 | pass 52 | 53 | 54 | class ExpNum(Exp): 55 | def __init__(self, n: int): 56 | self.num = n 57 | 58 | def __str__(self): 59 | return f"{self.num}" 60 | 61 | 62 | class ExpVar(Exp): 63 | def __init__(self, var: str): 64 | self.var = var 65 | 66 | def __str__(self): 67 | return f"{self.var}" 68 | 69 | 70 | class ExpBop(Exp): 71 | def __init__(self, left: Exp, right: Exp, bop: BOp): 72 | self.left = left 73 | self.right = right 74 | self.bop = bop 75 | 76 | def __str__(self): 77 | if isinstance(self.left, ExpBop): 78 | left_str = f"({self.left})" 79 | else: 80 | left_str = f"{self.left}" 81 | 82 | if isinstance(self.right, ExpBop): 83 | right_str = f"({self.right})" 84 | else: 85 | right_str = f"{self.right}" 86 | 87 | return f"{left_str} {self.bop.value} {right_str}" 88 | 89 | 90 | class ExpNeg(Exp): 91 | def __init__(self, exp: Exp): 92 | self.exp = exp 93 | 94 | def __str__(self): 95 | return f"~({self.exp})" 96 | 97 | 98 | class ExpUni(Exp): 99 | def __init__(self, vars_set: Set[str], exp: Exp): 100 | self.vars_set = vars_set 101 | self.exp = exp 102 | 103 | def __str__(self): 104 | vars_str = ",".join(self.vars_set) 105 | return f"∀({vars_str}).({self.exp})" 106 | 107 | 108 | # given an expression "e", to calculate the number of nodes 109 | # in this expression. this number is useful to estimate 110 | # how large this expression is, and how much memory it will occupy. 111 | def exp_num_nodes(exp: Exp) -> int: 112 | if isinstance(exp, ExpNum): 113 | return 1 114 | elif isinstance(exp, ExpVar): 115 | return 1 116 | elif isinstance(exp, ExpBop): 117 | return exp_num_nodes(exp.left) + exp_num_nodes(exp.right) 118 | elif isinstance(exp, ExpNeg): 119 | return exp_num_nodes(exp.exp) 120 | elif isinstance(exp, ExpUni): 121 | return exp_num_nodes(exp.exp) 122 | 123 | ############################################### 124 | # statement 125 | class Stm: 126 | def __init__(self): 127 | self.level = 0 128 | 129 | def __repr__(self): 130 | return str(self) 131 | 132 | 133 | class StmAssign(Stm): 134 | def __init__(self, var: str, exp: Exp): 135 | super().__init__() 136 | self.var = var 137 | self.exp = exp 138 | 139 | def __str__(self): 140 | indent_space = self.level * "\t" 141 | return f"{indent_space}{self.var} = {self.exp};\n" 142 | 143 | 144 | class StmIf(Stm): 145 | def __init__(self, exp: Exp, then_stms: List[Stm], else_stms: List[Stm]): 146 | super().__init__() 147 | self.exp = exp 148 | self.then_stms = then_stms 149 | self.else_stms = else_stms 150 | 151 | def __str__(self): 152 | indent_space = self.level * "\t" 153 | 154 | for stm in self.then_stms: 155 | stm.level = self.level + 1 156 | 157 | for stm in self.else_stms: 158 | stm.level = self.level + 1 159 | 160 | then_stms_str = "".join([str(stm) for stm in self.then_stms]) 161 | else_stms_str = "".join([str(stm) for stm in self.else_stms]) 162 | 163 | then_str = (f"{indent_space}if({self.exp}){{\n" 164 | f"{then_stms_str}" 165 | f"{indent_space}}}\n") 166 | 167 | if self.else_stms: 168 | return (f"{then_str}" 169 | f"{indent_space}else{{\n" 170 | f"{else_stms_str}" 171 | f"{indent_space}}}\n") 172 | else: 173 | return then_str 174 | 175 | 176 | class StmWhile(Stm): 177 | def __init__(self, inv: Exp, modified_vars: Set[str], exp: Exp, stms: List[Stm]): 178 | super().__init__() 179 | self.inv = inv 180 | self.modified_vars = modified_vars 181 | self.exp = exp 182 | self.stms = stms 183 | 184 | def __str__(self): 185 | indent_space = self.level * "\t" 186 | for stm in self.stms: 187 | stm.level = self.level + 1 188 | 189 | stms_str = "".join([str(stm) for stm in self.stms]) 190 | modified_vars = ",".join(self.modified_vars) 191 | 192 | return (f"{indent_space}inv={{{self.inv}}}\n" 193 | f"{indent_space}modified_vars={{{modified_vars}}}\n" 194 | f"{indent_space}while({self.exp}){{\n" 195 | f"{stms_str}" 196 | f"{indent_space}}}\n") 197 | 198 | 199 | ############################################### 200 | # function 201 | class Function: 202 | def __init__(self, name: str, args: List[str], stms: List[Stm], ret: Exp, pre: Exp, post: Exp): 203 | self.name = name 204 | self.args = args 205 | self.stms = stms 206 | self.ret = ret 207 | self.pre = pre 208 | self.post = post 209 | 210 | def __str__(self): 211 | arg_str = ",".join(self.args) 212 | for stm in self.stms: 213 | stm.level += 1 214 | 215 | stms_str = "".join([str(stm) for stm in self.stms]) 216 | 217 | return (f"pre={{{self.pre}}}\n" 218 | f"{self.name}({arg_str}){{\n" 219 | f"{stms_str}" 220 | f"\treturn {self.ret};\n" 221 | f"}}\n" 222 | f"post={{{self.post}}}\n") 223 | 224 | 225 | # for a given function "f", this function crawl through this function, 226 | # for each while statement in the function, record the modified 227 | # vars on the while statement. Notice the nesting of loops. 228 | def fill_in_modified_vars(f: Function): 229 | '''标记处 循环内 改动的变量 230 | TODO 231 | 注意,每个 stmwhile 中都有带有一个 modified_vars 232 | ''' 233 | def is_modified_vars(stm): 234 | if isinstance(stm, StmAssign) and stm.var != stm.exp: 235 | return stm.var 236 | 237 | def loop_stms(stms): 238 | if isinstance(stms, StmAssign): 239 | return set(stms.var) 240 | elif isinstance(stms, StmWhile): 241 | for stm in stms.stms: 242 | if is_modified_vars(stm): 243 | stms.modified_vars.add(stm.var) 244 | elif isinstance(stm, StmWhile): 245 | stms.modified_vars |= loop_stms(stm) 246 | elif isinstance(stm, StmIf): 247 | for s in stm.then_stms: 248 | stms.modified_vars |= loop_stms(s) 249 | for s in stm.else_stms: 250 | stms.modified_vars |= loop_stms(s) 251 | elif isinstance(stms, StmIf): 252 | for stm in stms.then_stms: 253 | loop_stms(stm) 254 | for stm in stms.else_stms: 255 | loop_stms(stm) 256 | 257 | return set() 258 | return stms.modified_vars 259 | 260 | for stm in f.stms: 261 | loop_stms(stm) 262 | 263 | ##################### 264 | # test case 265 | ''' 266 | pre={n <= 0} 267 | foo(n){ 268 | inv={n <= 5} 269 | modified_vars={} 270 | while(n < 5){ 271 | n = n + 1; 272 | } 273 | return n; 274 | } 275 | post={result == 5} 276 | ''' 277 | fun_foo = Function('foo', 278 | ['n'], 279 | [StmWhile(ExpBop(ExpVar('n'), ExpNum(5), BOp.LE), 280 | set(), 281 | ExpBop(ExpVar('n'), ExpNum(5), BOp.LT), 282 | [StmAssign('n', ExpBop(ExpVar('n'), ExpNum(1), BOp.ADD))])], 283 | ExpVar('n'), 284 | ExpBop(ExpVar('n'), ExpNum(0), BOp.LE), 285 | ExpBop(ExpVar('result'), ExpNum(5), BOp.EQ)) 286 | 287 | 288 | ########## 289 | # test case for exercise 3 290 | fun_loop = Function("loop", 291 | ["m", "n"], 292 | [StmAssign('a', ExpNum(0)), 293 | StmAssign("b", ExpNum(0)), 294 | StmWhile(ExpBop(ExpVar('n'), ExpNum(0), BOp.GE), 295 | set(), 296 | ExpBop(ExpVar('m'), ExpNum(0), BOp.LE), 297 | [StmAssign('m', ExpBop(ExpVar('n'), ExpNum(1), BOp.MIN)), 298 | StmWhile(ExpBop(ExpVar('n'), ExpNum(0), BOp.GE), 299 | set(), 300 | ExpBop(ExpVar('n'), ExpNum(0), BOp.LE), 301 | [StmAssign('a', ExpBop(ExpVar('a'), ExpNum(1), BOp.ADD)), 302 | StmAssign('b', ExpBop(ExpVar('b'), ExpNum(2), BOp.ADD)) 303 | ]) 304 | ]), 305 | StmAssign("d", ExpNum(5)), 306 | StmIf(ExpBop(ExpVar('n'), ExpVar('m'), BOp.GE), 307 | [StmAssign("b", ExpBop(ExpVar('b'), ExpVar('a'), BOp.ADD))], 308 | [StmWhile(ExpBop(ExpVar('d'), ExpNum(0), BOp.GE), 309 | set(), 310 | ExpBop(ExpVar('d'), ExpNum(0), BOp.GT), 311 | [StmIf(ExpBop(ExpVar('d'), ExpVar('n'), BOp.GE), 312 | [StmAssign('a', ExpBop(ExpVar('a'), ExpVar('d'), BOp.ADD)), 313 | StmAssign('d', ExpBop(ExpVar('d'), ExpNum(1), BOp.MIN)) 314 | ], 315 | [StmAssign('b', ExpBop(ExpVar('b'), ExpVar('d'), BOp.MIN)), 316 | StmAssign('d', ExpBop(ExpVar('d'), ExpNum(2), BOp.MIN)) 317 | ]), 318 | ]) 319 | ]) 320 | ], 321 | ExpVar('a'), 322 | ExpBop(ExpVar('n'), ExpNum(0), BOp.LE), 323 | ExpBop(ExpVar('m'), ExpNum(0), BOp.GE),) 324 | 325 | 326 | ##################### 327 | # fill in the function "sum" below: 328 | # def __init__(self, name: str, args: List[str], stms: List[Stm], ret: Exp, pre: Exp, post: Exp): 329 | 330 | fun_sum = Function("sum", 331 | ['n'], 332 | [StmAssign('s', ExpNum(0)), 333 | StmAssign('i', ExpNum(0)), 334 | StmWhile(ExpBop(ExpBop( ExpVar('i'), ExpBop(ExpVar('n'),ExpNum(1),BOp.ADD), BOp.LE), 335 | ExpBop( 336 | ExpBop(ExpNum(2), ExpVar('s'), BOp.MUL), 337 | ExpBop(ExpVar('i'), ExpBop(ExpVar('i'),ExpNum(1),BOp.MIN) ,BOp.MUL), 338 | BOp.EQ), 339 | BOp.AND), 340 | set(), 341 | ExpBop(ExpVar('i'), ExpVar('n'), BOp.LE), 342 | [ 343 | StmAssign('s', ExpBop(ExpVar('s'),ExpVar('i') ,BOp.ADD)), 344 | StmAssign('i', ExpBop(ExpVar('i'),ExpNum(1) ,BOp.ADD)) 345 | ]), 346 | ], 347 | ExpVar('s'), 348 | ExpBop(ExpVar('n'), ExpNum(0), BOp.GE), 349 | ExpBop( ExpBop(ExpVar('result'), ExpNum(2), BOp.MUL) ,ExpBop(ExpVar('n'), ExpBop( ExpVar('n'), ExpNum(1), BOp.ADD), BOp.MUL), BOp.EQ)) 350 | 351 | 352 | if __name__ == '__main__': 353 | print(fun_foo) 354 | 355 | # TODO: Exercise 1: write down your definition for the above function "sum" 356 | # 357 | # should print: 358 | # 359 | # pre={n >= 0} 360 | # sum(n){ 361 | # s = 0; 362 | # i = 0; 363 | # inv={(i <= (n + 1)) && ((2 * s) == (i * (i - 1)))} 364 | # modified_vars={} 365 | # while(i <= n){ 366 | # s = s + i; 367 | # i = i + 1; 368 | # } 369 | # return s; 370 | # } 371 | # post={(2 * result) == (n * (n + 1))} 372 | # 373 | print(fun_sum) 374 | # TODO: Exercise 2: Complete function exp_num_nodes(), to count the number of nodes in a given expression. 375 | # 376 | # should print: 377 | # 378 | # post condition of sum(n) has 5 nodes 379 | # invariant in the while statement of sum(n) has 8 nodes 380 | # 381 | print(f"post condition of sum(n) has {exp_num_nodes(fun_sum.post)} nodes") 382 | print(f"invariant in the while statement of sum(n) has {exp_num_nodes(fun_sum.stms[2].inv)} nodes\n") 383 | 384 | # TODO: Exercise 3: Calculate the modified_var in any while statement by filling in the 385 | # function fill_in_modified_vars() module. Or you can modify the data structures to add new member 386 | # methods if you prefer OO-style. 387 | # 388 | # should print: 389 | # 390 | # first while statement's modified_vars is: {'a', 'm', 'b'} 391 | # second while statement's modified_vars is: {'a', 'b'}. 392 | # third while statement's modified_vars is: {'a', 'b', 'd'} 393 | # 394 | ''' fun_loop 395 | pre={n <= 0} 396 | loop(m,n){ 397 | a = 0; 398 | b = 0; 399 | inv={n >= 0} 400 | modified_vars={} 401 | while(m <= 0){ 402 | m = n - 1; 403 | inv={n >= 0} 404 | modified_vars={} 405 | while(n <= 0){ 406 | a = a + 1; 407 | b = b + 2; 408 | } 409 | } 410 | d = 5; 411 | if(n >= m){ 412 | b = b + a; 413 | } 414 | else{ 415 | inv={d >= 0} 416 | modified_vars={} 417 | while(d > 0){ 418 | if(d >= n){ 419 | a = a + d; 420 | d = d - 1; 421 | } 422 | else{ 423 | b = b - d; 424 | d = d - 2; 425 | } 426 | } 427 | } 428 | return a; 429 | } 430 | post={m >= 0} 431 | ''' 432 | fill_in_modified_vars(fun_loop) 433 | 434 | print(f"first while statement's modified_vars is: {fun_loop.stms[2].modified_vars}") 435 | print(f"second while statement's modified_vars is: {fun_loop.stms[2].stms[1].modified_vars}.") 436 | print(f"third while statement's modified_vars is: {fun_loop.stms[4].else_stms[0].modified_vars}") --------------------------------------------------------------------------------