├── 2PC ├── 2PC.ivy ├── config_2PC.txt └── inst.txt ├── README.md ├── chain ├── chain.ivy ├── config_chain.txt └── inst.txt ├── chord ├── chord.ivy ├── config_chord.txt └── inst.txt ├── dependencies.sh ├── distributed_lock ├── config_distributed_lock.txt ├── distributed_lock.ivy └── inst.txt ├── leader ├── config_leader.txt ├── inst.txt ├── leader.ivy └── main.cpp ├── lock_server ├── config_lock_server.txt ├── inst.txt └── lock_server.ivy ├── main.cpp ├── main.py ├── remove.py ├── switch ├── config_switch.txt ├── inst.txt └── switch.ivy ├── test.sh └── translate.py /2PC/2PC.ivy: -------------------------------------------------------------------------------- 1 | #lang ivy1.7 2 | 3 | ################################################################################ 4 | # 5 | # Types, relations and functions describing state of the network 6 | # 7 | ################################################################################ 8 | 9 | type node 10 | 11 | # epochs are totally ordered with a least element called zero 12 | relation vote_yes(N: node) 13 | relation vote_no(N: node) 14 | relation alive(N: node) 15 | relation go_commit(N: node) 16 | relation go_abort(N: node) 17 | relation decide_commit(N: node) 18 | relation decide_abort(N: node) 19 | 20 | individual abort_flag: bool 21 | 22 | ################################################################################ 23 | # 24 | # Protocol description 25 | # 26 | ################################################################################ 27 | 28 | after init { 29 | vote_yes(N) := false; 30 | vote_no(N) := false; 31 | alive(N) := true; 32 | go_commit(N) := false; 33 | go_abort(N) := false; 34 | decide_commit(N) := false; 35 | decide_abort(N) := false; 36 | abort_flag := false; 37 | } 38 | 39 | action vote1(n: node) = { 40 | require alive(n); 41 | require ~vote_no(n); 42 | require ~decide_commit(n); 43 | require ~decide_abort(n); 44 | vote_yes(n) := true; 45 | } 46 | 47 | action vote2(n: node) = { 48 | require alive(n); 49 | require ~vote_yes(n); 50 | require ~decide_commit(n); 51 | require ~decide_abort(n); 52 | vote_no(n) := true; 53 | abort_flag := true; 54 | decide_abort(n) := true; 55 | } 56 | 57 | action fail(n: node) = { 58 | require alive(n); 59 | alive(n) := false; 60 | abort_flag := true; 61 | } 62 | 63 | action go1 = { 64 | require ~go_commit(N); 65 | require ~go_abort(N); 66 | require vote_yes(N); 67 | go_commit(N) := true; 68 | } 69 | 70 | action go2 = { 71 | require ~go_commit(N); 72 | require ~go_abort(N); 73 | require exists N. vote_no(N) | ~alive(N); 74 | go_abort(N) := true; 75 | } 76 | 77 | action commit(n: node) = { 78 | require alive(n); 79 | require go_commit(n); 80 | decide_commit(n) := true; 81 | } 82 | 83 | action abort(n: node) = { 84 | require alive(n); 85 | require go_abort(n); 86 | decide_abort(n) := true; 87 | } 88 | 89 | export vote1 90 | export vote2 91 | export fail 92 | export go1 93 | export go2 94 | export commit 95 | export abort 96 | 97 | # the safety property 98 | invariant [1000000] (decide_commit(N) -> ~decide_abort(N2)) & (decide_commit(N) -> vote_yes(N2)) & (decide_abort(N) -> abort_flag) 99 | -------------------------------------------------------------------------------- /2PC/config_2PC.txt: -------------------------------------------------------------------------------- 1 | 7 2 | 1 bool vote_yes N 3 | 1 bool vote_no N 4 | 1 bool alive N 5 | 1 bool go_commit N 6 | 1 bool go_abort N 7 | 1 bool decide_commit N 8 | 1 bool decide_abort N 9 | 10 | 0 11 | 12 | 0 13 | -------------------------------------------------------------------------------- /2PC/inst.txt: -------------------------------------------------------------------------------- 1 | 1 2 | node=10 3 | 4 | 0 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # I4 2 | I4 is an automated inductive invariant generator for distributed protocols. 3 | 4 | ## Dependency 5 | [Ivy](http://microsoft.github.io/ivy/install.html), [Averroes](https://github.com/aman-goel/avr/tree/distributed)(distributed branch). 6 | 7 | Run script `bash dependencies.sh` to automatically install Ivy and Averroes. 8 | 9 | If you want to run Ivy locally, you need to add it to `PYTHONPATH`. (This is a step in installing Z3.) 10 | ``` 11 | export PYTHONPATH=/usr/local/lib/python2.7/site-packages:$PYTHONPATH 12 | ``` 13 | 14 | ## How to run 15 | 1. Start with a protocol, run `translate.py` in python2 to generate a finite instance in vmt format. Specify each sort's amount for the desired model size. 16 | ``` 17 | python translate.py lock_server/lock_server.ivy client=2 server=1 > tmp.vmt 18 | ``` 19 | This will produce a finite instance that is just enough to generate inductive invariants for the generate case for `lock_server.ivy`. 20 | 21 | 2. Use [Averroes](https://github.com/aman-goel/avr/tree/distributed) to generate invariants for the finite instance. 22 | ``` 23 | cd avr 24 | python avr.py --vmt ../tmp.vmt -e 4 25 | ``` 26 | * When [Averroes](https://github.com/aman-goel/avr/tree/distributed) finds a counter example, the finite instance is buggy and it requires a manual fix to the protocol. 27 | * Otherwise, `output/work_test/inv.txt` for the finite instance is generated. 28 | * Some detailed information can be found in `output/work_test/test.result`. `scalls` shows the total number of SMT calls; `time-dist-inv-induct-check` shows the percentage of total time spent in minimizing the inductive invariant; `time` shows the total time for finding and minimizing the inductive invariant. 29 | 30 | 3. Remove redundant information in `inv.txt`. 31 | ``` 32 | python remove.py avr/output/work_lock_server/inv.txt > inv.txt 33 | ``` 34 | 35 | 4. Compile `main.cpp`. 36 | ``` 37 | g++ main.cpp -o main -std=c++11 38 | ``` 39 | `main` verifies whether the generated invariant is the inductive invariant of the (possibly infinite) protocol. 40 | `main` requires following as input: the protocol `$MODEL_NAME$.ivy`, an invariant file (inv.txt) that is generated in the previous step, and an associated config file. 41 | 42 | ### config file 43 | * config file is usually named after `config_$MODEL_NAME$.txt`. 44 | * A config file has 3 parts. Each part starts with an integer that specifies the number of variables/constants each part defines, followed by a newline. 45 | * Each definition takes a newline. 46 | * The first part lists all the relations and functions (variables). 47 | Format: number of inputs, type of return value, name of relation/function \[, type of input1\][, type of input2, ...], Each separated by a space. 48 | E.g. 49 | ``` 50 | 2 boolean le TYPE1 TYPE1 51 | 1 TYPE1 some_relation TYPE2 52 | ``` 53 | * The second part lists all individuals that are named after zero, first, org, if showing up in `$MODEL_NAME$.ivy`. 54 | Format: type of individual, name of an individual in **uppercase**, `=`, the number '0'. Each separated by a space. 55 | E.g. 56 | ``` 57 | TYPE1 first = 0 58 | TYPE1 org = 0 59 | ``` 60 | If one wishes to assign different values or to use more variable names, modify the 61 | * The third part is not used now, thus it contains only the number 0. 62 | 63 | Now we can run main: `./main model_file invariant_file config_file [invariant_prefix]`. For example: 64 | ``` 65 | ./main lock_server/lock_server inv.txt lock_server/config_lock_server.txt 66 | ``` 67 | and the output is `$model_file$_inv.ivy`. It may or may not pass `ivy_check $MODEL_NAME$_inv.ivy`; if it does not, go back to step 1 and increase the model size. 68 | 69 | Check `log.txt` for more information. 70 | 71 | 5. `bash test.sh` runs all models and generates all `$model_file$_inv.ivy`. 72 | -------------------------------------------------------------------------------- /chain/chain.ivy: -------------------------------------------------------------------------------- 1 | #lang ivy1.7 2 | 3 | ################################################################################ 4 | # 5 | # A module for axiomatizing a total order 6 | # 7 | ################################################################################ 8 | module total_order(r) = { 9 | axiom r(X,X) # Reflexivity 10 | axiom r(X, Y) & r(Y, Z) -> r(X, Z) # Transitivity 11 | axiom r(X, Y) & r(Y, X) -> X = Y # Anti-symmetry 12 | axiom r(X, Y) | r(Y, X) # Totality 13 | } 14 | 15 | ################################################################################ 16 | # 17 | # Modules for lone and injective relations 18 | # 19 | ################################################################################ 20 | module lone(f) = { 21 | axiom (f(X, Y1) & f(X, Y2)) -> Y1 = Y2 22 | } 23 | module injective(f) = { 24 | axiom (f(X1, Y) & f(X2, Y)) -> X1 = X2 25 | } 26 | 27 | ################################################################################ 28 | # 29 | # Types, relations and functions describing state of the system 30 | # 31 | ################################################################################ 32 | 33 | type transaction 34 | type node 35 | type key 36 | type operation 37 | 38 | # a total order on the transaction timestamps 39 | relation le(X:transaction, Y:transaction) # le(X,Y) means X is before Y 40 | instantiate total_order(le) 41 | 42 | # transaction zero is a special transaction, before every transaction, 43 | # and it reads and writes to all keys 44 | individual zero:transaction 45 | axiom [here] le(zero, X) 46 | 47 | # Each operation reads and writes one key 48 | relation op_reads_key(Op: operation, K: key) # OP reads k 49 | #instantiate lone(op_reads_key) 50 | axiom (op_reads_key(X, Y1) & op_reads_key(X, Y2)) -> Y1 = Y2 51 | 52 | relation op_writes_key(Op : operation, K: key) # OP writes k 53 | #instantiate lone(op_writes_key) 54 | axiom (op_writes_key(X, Y1) & op_writes_key(X, Y2)) -> Y1 = Y2 55 | 56 | # Do not read and write the same key. 57 | axiom op_reads_key(Op, K1) & op_writes_key(Op, K2) -> K1 ~= K2 58 | 59 | # The operation in each node 60 | relation op_node(Op: operation, N : node) # The node on which an operation is applied 61 | #instantiate lone(op_node) 62 | axiom (op_node(X, Y1) & op_node(X, Y2)) -> Y1 = Y2 63 | 64 | relation node_for_key(K: key, N : node) # Key is at node n 65 | #instantiate lone(node_for_key) 66 | axiom (node_for_key(X, Y1) & node_for_key(X, Y2)) -> Y1 = Y2 67 | axiom op_reads_key(Op, K) & node_for_key(K, N1) & op_node(Op, N2) -> N1 = N2 #Operations must be local 68 | axiom op_writes_key(Op, K) & node_for_key(K, N1) & op_node(Op, N2) -> N1 = N2 #Operations must be local 69 | 70 | # The relation between operations and transactions and an order on operations 71 | 72 | relation op_in_tx(Tx : transaction, Op: operation) # An operation of transaction is op 73 | 74 | # Each op is in a single Tx. 75 | instantiate injective(op_in_tx) 76 | 77 | relation oporder(X:operation, Y:operation) 78 | axiom oporder(X, X) # Reflexive 79 | axiom oporder(X, Y) & oporder(Y, Z) -> oporder(X, Z) # Transitive 80 | axiom oporder(X, Y) & oporder(Y, X) -> X = Y # Anti-symmetric 81 | axiom (op_in_tx(T, X) & op_in_tx(T, Y)) -> (oporder(X, Y) | oporder(Y, X)) # total for operations in the same transaction 82 | axiom (op_in_tx(T, X) & (oporder(X, Y) | oporder(Y, X))) -> op_in_tx(T, Y) # op_in_tx is closed under the order 83 | 84 | # different operations in the same transaction are in different nodes 85 | axiom op_in_tx(T, O1) & op_in_tx(T, O2) & O1 ~= O2 & op_node(O1, N1) & op_node(O2, N2) -> N1 ~= N2 86 | 87 | relation precommit_tx(Tx : transaction, N: node) # Is transaction tx precommitted at n 88 | relation abort_tx(Tx : transaction) 89 | relation commit_tx(Tx: transaction) # Is tx committed 90 | relation depends_tx(Tx: transaction, K: key, Tr : transaction) #Flow values between commited transactions 91 | 92 | relation read_tx(Tx: transaction, K: key) 93 | relation write_tx(Tx: transaction, K: key) 94 | 95 | after init { 96 | precommit_tx(T, N) := T = zero; 97 | abort_tx(T) := false; 98 | commit_tx(T) := T = zero; 99 | depends_tx(T1, K, T2) := (T1 = zero & T2 = zero); 100 | read_tx(Tx, K) := Tx = zero; 101 | write_tx(Tx, K) := Tx = zero; 102 | } 103 | 104 | action do_abort(tx: transaction, op: operation, n: node, kw: key, kr: key, luwkw: transaction, lurkw: transaction, luwkr: transaction, lcwkr: transaction) = { 105 | require op_in_tx(tx, op); # Grab an operation 106 | require ~abort_tx(tx) & ~commit_tx(tx); # Ensures that the transaction is not already aborted or committed 107 | 108 | require (oporder(X, op) & X ~= op & op_node(X, N)) -> precommit_tx(tx, N); 109 | # Ensures that the previous operation was successfully precommitted 110 | require op_node(op, n) ; # Assume operation is in node n 111 | require ~precommit_tx(tx, n); 112 | require ~op_writes_key(op, K) | op_writes_key(op, kw); 113 | require op_writes_key(op, kw) -> node_for_key(kw, n); 114 | 115 | require ~op_reads_key(op, K) | op_reads_key(op, kr); 116 | require op_reads_key(op, kr) -> node_for_key(kr, n); 117 | 118 | # instantiate get_last_write(kw, luwkw); # Write fails because of any future read or write. 119 | # instantiate get_last_read (kw, lurkw); 120 | require write_tx(luwkw, kw) & (~abort_tx(luwkw)) & (write_tx(T, kw) -> (le(T, luwkw) | abort_tx(T))); 121 | require exists HT. depends_tx(lurkw, kw, HT) & (~abort_tx(lurkw)) & (read_tx(T, kw) -> le(T, lurkw) | abort_tx(T)); 122 | 123 | # instantiate get_previous_write(kr, luwkr, tx); # Read fails because of uncommited previous reads or writes 124 | # instantiate get_previous_committed_write(kr, lcwkr, tx); 125 | require write_tx(luwkr, kr) & le(luwkr, tx) & (~abort_tx(luwkr)) & (write_tx(T, kr) -> (le(T, luwkr) | le(tx, T) | abort_tx(T))); 126 | require commit_tx(lcwkr) & write_tx(lcwkr, kr) & le(lcwkr, tx) & ((commit_tx(T) & write_tx(T, kr)) -> (le(T, lcwkr) | le(tx, T))); 127 | 128 | # if ((op_writes_key(op, kw) & 129 | # (le(tx, luwkw) | le(tx, lurkw))) | 130 | # (op_reads_key(op, kr) & 131 | # luwkr ~= lcwkr & 132 | # le(luwkr, tx))) 133 | require (op_writes_key(op, kw) & (le(tx, luwkw) | le(tx, lurkw))) | (op_reads_key(op, kr) & luwkr ~= lcwkr & le(luwkr, tx)); 134 | 135 | abort_tx(tx) := true; 136 | } 137 | 138 | action do_progress(tx: transaction, op: operation, n: node, kw: key, kr: key, luwkw: transaction, lurkw: transaction, luwkr: transaction, lcwkr: transaction) = { 139 | require op_in_tx(tx, op); # Grab an operation 140 | require ~abort_tx(tx) & ~commit_tx(tx); # Ensures that the transaction is not already aborted or committed 141 | 142 | require (oporder(X, op) & X ~= op & op_node(X, N)) -> precommit_tx(tx, N); 143 | # Ensures that the previous operation was successfully precommitted 144 | require op_node(op, n) ; # Assume operation is in node n 145 | require ~precommit_tx(tx, n); 146 | require ~op_writes_key(op, K) | op_writes_key(op, kw); 147 | require op_writes_key(op, kw) -> node_for_key(kw, n); 148 | 149 | require ~op_reads_key(op, K) | op_reads_key(op, kr); 150 | require op_reads_key(op, kr) -> node_for_key(kr, n); 151 | 152 | # instantiate get_last_write(kw, luwkw); # Write fails because of any future read or write. 153 | # instantiate get_last_read (kw, lurkw); 154 | require write_tx(luwkw, kw) & (~abort_tx(luwkw)) & (write_tx(T, kw) -> (le(T, luwkw) | abort_tx(T))); 155 | require exists HT. depends_tx(lurkw, kw, HT) & (~abort_tx(lurkw)) & (read_tx(T, kw) -> le(T, lurkw) | abort_tx(T)); 156 | 157 | # instantiate get_previous_write(kr, luwkr, tx); # Read fails because of uncommited previous reads or writes 158 | # instantiate get_previous_committed_write(kr, lcwkr, tx); 159 | require write_tx(luwkr, kr) & le(luwkr, tx) & (~abort_tx(luwkr)) & (write_tx(T, kr) -> (le(T, luwkr) | le(tx, T) | abort_tx(T))); 160 | require commit_tx(lcwkr) & write_tx(lcwkr, kr) & le(lcwkr, tx) & ((commit_tx(T) & write_tx(T, kr)) -> (le(T, lcwkr) | le(tx, T))); 161 | 162 | # if ((op_writes_key(op, kw) & 163 | # (le(tx, luwkw) | le(tx, lurkw))) | 164 | # (op_reads_key(op, kr) & 165 | # luwkr ~= lcwkr & 166 | # le(luwkr, tx))) 167 | require ~((op_writes_key(op, kw) & (le(tx, luwkw) | le(tx, lurkw))) | (op_reads_key(op, kr) & luwkr ~= lcwkr & le(luwkr, tx))); 168 | 169 | if (op_writes_key(op, kw)) { 170 | write_tx(tx, kw) := true; 171 | }; 172 | if (op_reads_key(op, kr)) { 173 | depends_tx(tx, kr, lcwkr) := true; 174 | read_tx(tx, kr) := true; 175 | }; 176 | precommit_tx(tx, n) := true; 177 | if (forall O. (oporder(op, O) -> O = op)) { 178 | commit_tx(tx) := true; 179 | }; 180 | } 181 | 182 | export do_progress 183 | export do_abort 184 | 185 | # Safety: Linearizability 186 | invariant [1000000] (~(TX1 ~= TX2 & 187 | commit_tx(TX1) & 188 | commit_tx(TX2) & 189 | le(TX1,TX2) & # TX1 was before TX2 190 | write_tx(TX1, K) & # TX1 wrote K 191 | depends_tx(TX2, K, T3) & # TX2 read K 192 | ~le(TX1, T3))) 193 | & ((commit_tx(T) & op_in_tx(T, O) & op_node(O, N)) -> precommit_tx(T, N)) # Safety: Atomicity 194 | 195 | -------------------------------------------------------------------------------- /chain/config_chain.txt: -------------------------------------------------------------------------------- 1 | 13 2 | 2 bool le TR TR 3 | 2 bool op_reads_key OP K 4 | 2 bool op_writes_key OP K 5 | 2 bool op_node OP N 6 | 2 bool node_for_key K N 7 | 2 bool op_in_tx TR OP 8 | 2 bool oporder OP OP 9 | 2 bool precommit_tx TR N 10 | 1 bool abort_tx TR 11 | 1 bool commit_tx TR 12 | 3 bool depends_tx TR K TR 13 | 2 bool read_tx TR K 14 | 2 bool write_tx TR K 15 | 16 | 0 17 | 18 | 0 19 | -------------------------------------------------------------------------------- /chain/inst.txt: -------------------------------------------------------------------------------- 1 | 4 2 | transaction=3 3 | operation=3 4 | key=1 5 | node=2 6 | 7 | 0 8 | -------------------------------------------------------------------------------- /chord/chord.ivy: -------------------------------------------------------------------------------- 1 | #lang ivy1.7 2 | 3 | module ring_topology(carrier) = { 4 | relation btw(X:carrier,Y:carrier, Z:carrier) # Y is on the acyclic path from X to Z 5 | 6 | # Axiom defining the btw relation - note it's not reflexive 7 | # not needed: axiom btw(X,Y,Z) -> X ~= Y & X ~= Z & Y ~= Z # anti-reflexive 8 | axiom btw(W, X, Y) & btw(W, Y, Z) -> btw(W, X, Z) # transitive 9 | axiom btw(W, X, Y) -> ~btw(W, Y, X) # acyclic 10 | axiom btw(W, X, Y) | btw(W, Y, X) | W=X | X=Y # total 11 | axiom (btw(X, Y, Z) & X ~= Z) -> btw(Y, Z, X) # cyclic permutations 12 | } 13 | 14 | #module nodeopology(t) = { 15 | # relation btw(X:t,Y:t,Z:t) 16 | 17 | # axiom btw(W, Y, Z) & btw(W, X, Y) -> btw(X, Y, Z) 18 | # property btw(W, X, Z) & btw(X, Y, Z) -> btw(W, X, Y) 19 | # property btw(W, X, Z) & btw(X, Y, Z) -> btw(W, Y, Z) 20 | # property btw(W, Y, Z) & btw(W, X, Y) -> btw(W, X, Z) 21 | # property W = X | btw(W, X, W) 22 | # property ~btw(X, X, Y) 23 | # property ~btw(X, Y, Y) 24 | # property btw(X,Y,Z) | Y = Z | btw(X,Z,Y) 25 | # property btw(X,Y,Z) | Y = X | btw(Y,X,Z) 26 | #} 27 | 28 | type node 29 | 30 | instantiate ring : ring_topology(node) 31 | 32 | relation a(X : node) # active set 33 | relation s1(X : node, Y : node) # first successor 34 | relation in_s1(X : node) 35 | relation s2(X : node, Y : node) # second successor 36 | relation in_s2(X : node) 37 | relation p(X : node, Y : node) # predecessor 38 | 39 | individual org : node 40 | individual other : node 41 | axiom other ~= org 42 | 43 | relation reach(X: node) 44 | relation error(X: node) 45 | 46 | after init { 47 | a(X) := X = org | X = other; 48 | s1(X, Y) := (X = org & Y = other) | (X = other & Y = org); 49 | in_s1(X) := X = org | X = other; 50 | s2(X, Y) := false; 51 | in_s2(X) := false; 52 | p(X, Y) := (X = org & Y = other) | (X = other & Y = org); 53 | reach(X) := X = org; 54 | error(X) := false; 55 | } 56 | 57 | action join(x : node, y : node) = { 58 | require ~a(x); 59 | require a(y); 60 | # require ~(a(Z) & ring.btw(x, Z, y)); 61 | require ~ring.btw(x, org, y); 62 | # assume in_s1(x) -> exists Y. s1(x, Y); 63 | # assume in_s2(x) -> exists Y. s2(x, Y); 64 | a(x) := true; 65 | s1(x, Y) := y = Y; 66 | in_s1(x) := true; 67 | s2(x, Y) := false; 68 | in_s2(x) := false; 69 | p(x, Y) := false; 70 | } 71 | 72 | action stabilize(x : node, y : node, z : node) = { 73 | require a(x); 74 | require s1(x, y); 75 | require a(y); 76 | require p(y, z); 77 | # assume a(z); 78 | require ring.btw(x, z, y); 79 | # assume in_s1(x) -> exists Y. s1(x, Y); 80 | # assume in_s2(x) -> exists Y. s2(x, Y); 81 | s1(x, Z) := Z = z; 82 | in_s1(x) := true; 83 | s2(x, Y) := Y = y; 84 | in_s2(x) := true; 85 | } 86 | 87 | action notify(x : node, y : node, z : node) = { 88 | require a(x); 89 | require s1(x, y); 90 | require a(y); 91 | require p(y, z) | ~p(y, X); 92 | require ring.btw(z, x, y); 93 | p(y, X) := X = x; 94 | } 95 | 96 | action inherit(x : node, y : node, z : node) = { 97 | require a(x); 98 | require s1(x, y); 99 | require a(y); 100 | require s1(y, z); 101 | # assume in_s2(x) -> exists Y. s2(x, Y); 102 | s2(x, Z) := Z = z; 103 | in_s2(x) := true; 104 | } 105 | 106 | action remove(x : node, y : node, z : node) = { 107 | require a(x); 108 | require s1(x, y); 109 | require ~a(y); 110 | require s2(x, z); 111 | # assume in_s1(x) -> exists Y. s1(x, Y); 112 | # assume in_s2(x) -> exists Y. s2(x, Y); 113 | s1(x, Z) := Z = z; 114 | in_s1(x) := true; 115 | s2(x, Y) := false; 116 | in_s2(x) := false; 117 | } 118 | 119 | action fail(x : node) = { 120 | require a(x); 121 | require x ~= org; # assume origin node cannot fail 122 | # assume the last active successor of any does not fail 123 | require (s1(Y, x)) -> in_s2(Y); 124 | require (s1(Y, x) & s2(Y, Z)) -> a(Z); 125 | require (s1(X, Y) & s2(X, x)) -> (Y ~= x & a(Y)); 126 | # assume in_s1(x) -> exists Y. s1(x, Y); 127 | # assume in_s2(x) -> exists Y. s2(x, Y); 128 | a(x) := false; 129 | p(x, Y) := false; 130 | s1(x, Y) := false; 131 | in_s1(x) := false; 132 | s2(x, Y) := false; 133 | in_s2(x) := false; 134 | # assume (~s1(X, Y) | a(Y) | in_s2(X)); 135 | # assume (~s1(X, Y) | a(Y) | ~s2(X, Z) | a(Z)); 136 | } 137 | 138 | action reach_org(x : node, y : node, z : node) = { 139 | require (s1(x, y) & a(y) & reach(y)) | (s1(x, y) & ~a(y) & s2(x, z) & a(z) & reach(z)); 140 | reach(x) := true; 141 | } 142 | 143 | action remove_org(x : node, y : node, z : node) = { 144 | require x ~= org; 145 | require s1(x, y); 146 | require (~a(y) | ~reach(y)); 147 | require ~a(y) -> (~s2(x, Z) | s2(x, z)); 148 | require (~a(y) & s2(x, z)) -> (~a(z) | ~reach(z)); 149 | # require (s1(x, y) & a(y) & ~reach(y)) | (s1(x, y) & ~a(y) & s2(x, z) & (a(z) & ~reach(z))); 150 | reach(x) := false; 151 | } 152 | 153 | action test(x : node) = { 154 | require (s1(X, Y) & a(Y) & reach(Y)) -> reach(X); 155 | require (s1(X, Y) & ~a(Y) & s2(X, Z) & a(Z) & reach(Z)) -> reach(X); 156 | require (ring.btw(x, Y, org) & a(Y)) -> reach(Y); 157 | require a(x); 158 | require ~reach(x); 159 | require in_s1(x) -> exists Y. s1(x, Y); 160 | require in_s2(x) -> exists Y. s2(x, Y); 161 | error(x) := true; 162 | } 163 | 164 | export join 165 | export stabilize 166 | export inherit 167 | export remove 168 | export notify 169 | export reach_org 170 | export remove_org 171 | export fail 172 | export test 173 | 174 | invariant [1000000] ~error(N) 175 | -------------------------------------------------------------------------------- /chord/config_chord.txt: -------------------------------------------------------------------------------- 1 | 9 2 | 3 bool ring.btw NODE NODE NODE 3 | 1 bool a NODE 4 | 2 bool s1 NODE NODE 5 | 1 bool in_s1 NODE 6 | 2 bool s2 NODE NODE 7 | 1 bool in_s2 NODE 8 | 2 bool p NODE NODE 9 | 1 bool reach NODE 10 | 1 bool error NODE 11 | 12 | 1 13 | NODE org = 0 14 | 15 | 0 16 | -------------------------------------------------------------------------------- /chord/inst.txt: -------------------------------------------------------------------------------- 1 | 1 2 | node=4 3 | 4 | 1 5 | node_org=node0 6 | -------------------------------------------------------------------------------- /dependencies.sh: -------------------------------------------------------------------------------- 1 | apt-get update 2 | apt-get install python 3 | apt-get install python-pip 4 | apt-get install g++ 5 | 6 | echo "Building Z3" 7 | wget https://github.com/Z3Prover/z3/archive/z3-4.6.0.tar.gz 8 | tar xzf z3-4.6.0.tar.gz 9 | pushd . 10 | cd z3-z3-4.6.0/ 11 | python scripts/mk_make.py --prefix=/usr/local --python --pypkgdir=/usr/local/lib/python2.7/site-packages 12 | cd build 13 | make -j 4 14 | sudo make install 15 | export LD_LIBRARY_PATH=/usr/local/lib: 16 | export PYTHONPATH=/usr/local/lib/python2.7/site-packages:$PYTHONPATH 17 | popd 18 | 19 | echo "Building Ivy" 20 | sudo apt-get install python-ply python-pygraphviz 21 | sudo pip install ply pygraphviz tarjan 22 | sudo apt-get install python-tk tix 23 | git clone https://github.com/GLaDOS-Michigan/ivy.git 24 | pushd . 25 | cd ivy 26 | sudo python setup.py install 27 | popd 28 | 29 | echo "Building AVR" 30 | git clone https://github.com/GLaDOS-Michigan/avr.git 31 | pushd . 32 | cd avr 33 | git checkout distributed 34 | sudo apt-get install clang 35 | sudo apt-get install tcl8.6-dev 36 | sudo apt-get install libreadline-dev 37 | sudo apt-get install flex bison 38 | bash build.sh 39 | popd 40 | -------------------------------------------------------------------------------- /distributed_lock/config_distributed_lock.txt: -------------------------------------------------------------------------------- 1 | 5 2 | 1 EPOCH ep NODE 3 | 1 boolean held NODE 4 | 2 boolean transfer EPOCH NODE 5 | 2 boolean locked EPOCH NODE 6 | 2 boolean le EPOCH EPOCH 7 | 8 | 1 9 | EPOCH zero = 0 10 | 11 | 0 12 | -------------------------------------------------------------------------------- /distributed_lock/distributed_lock.ivy: -------------------------------------------------------------------------------- 1 | #lang ivy1.7 2 | 3 | # 4 | # An Ivy model of the toy lock example from https://github.com/Microsoft/Ironclad/blob/master/ironfleet/src/Dafny/Distributed/Protocol/Lock/Node.i.dfy 5 | # 6 | # For a description of the protocol, see the IronFleet paper 7 | # (https://www.microsoft.com/en-us/research/wp-content/uploads/2015/10/ironfleet.pdf), 8 | # Figure 4 9 | # 10 | 11 | # A total order helper module 12 | module total_order(r) = { 13 | axiom r(X,X) # Reflexivity 14 | axiom r(X, Y) & r(Y, Z) -> r(X, Z) # Transitivity 15 | axiom r(X, Y) & r(Y, X) -> X = Y # Anti-symmetry 16 | axiom r(X, Y) | r(Y, X) # Totality 17 | } 18 | 19 | ################################################################################ 20 | # 21 | # Types, relations and functions describing state of the network 22 | # 23 | ################################################################################ 24 | 25 | type node 26 | type epoch 27 | 28 | # epochs are totally ordered with a least element called zero 29 | relation le(X:epoch, Y:epoch) 30 | instantiate total_order(le) 31 | individual zero:epoch 32 | axiom le(zero, X) 33 | #individual maxint:epoch 34 | #axiom le(X, maxint) 35 | function ep(N:node) : epoch # ep(n) is the current epoch of node n 36 | 37 | relation held(N:node) # held(n) is true iff the lock is currently held by node n 38 | 39 | # transfer messages 40 | relation transfer(E:epoch, N:node) # the node is the message destination 41 | 42 | # locked messages 43 | relation locked(E:epoch, N:node) # the node is the message source 44 | 45 | ################################################################################ 46 | # 47 | # Protocol description 48 | # 49 | ################################################################################ 50 | individual first:node 51 | individual e:epoch 52 | axiom e ~= zero 53 | #axiom E ~= zero -> le(e, E) 54 | after init { 55 | # initially exactly one node holds the lock, and everyone has epoch zero 56 | held(X) := X=first; 57 | ep(N) := e if N = first else zero; 58 | transfer(E, N) := false; 59 | locked(E, N) := false; 60 | } 61 | 62 | action grant(n1:node, n2:node, e:epoch) = { 63 | # release the lock and send a transfer message 64 | require held(n1); 65 | require ~le(e, ep(n1)); # jump to some strictly higher epoch 66 | transfer(e, n2) := true; 67 | held(n1) := false; 68 | } 69 | 70 | action accept(n:node, e:epoch) = { 71 | # receive a transfer message and take the lock, sending a locked message 72 | require transfer(e,n); 73 | if ~le(e, ep(n)) { 74 | held(n) := true; 75 | ep(n) := e; 76 | locked(e, n) := true; 77 | }; 78 | } 79 | 80 | export grant 81 | export accept 82 | 83 | # the safety property 84 | invariant [1000000] locked(E, N1) & locked(E, N2) -> N1 = N2 85 | -------------------------------------------------------------------------------- /distributed_lock/inst.txt: -------------------------------------------------------------------------------- 1 | 2 2 | node=2 3 | epoch=4 4 | 5 | 0 6 | -------------------------------------------------------------------------------- /leader/config_leader.txt: -------------------------------------------------------------------------------- 1 | 5 2 | 3 bool ring.btw N N N 3 | 2 bool le ID ID 4 | 1 ID idn N 5 | 1 bool leader N 6 | 2 bool pending ID N 7 | 8 | 0 9 | 10 | 0 11 | -------------------------------------------------------------------------------- /leader/inst.txt: -------------------------------------------------------------------------------- 1 | 2 2 | node=3 3 | id=3 4 | 5 | 3 6 | node0_idn=id0 7 | node1_idn=id1 8 | node2_idn=id2 9 | -------------------------------------------------------------------------------- /leader/leader.ivy: -------------------------------------------------------------------------------- 1 | #lang ivy1.7 2 | 3 | ################################################################################ 4 | # 5 | # A module for axiomatizing a total order 6 | # 7 | ################################################################################ 8 | 9 | module total_order(r) = { 10 | axiom r(X,X) # Reflexivity 11 | axiom r(X, Y) & r(Y, Z) -> r(X, Z) # Transitivity 12 | axiom r(X, Y) & r(Y, X) -> X = Y # Anti-symmetry 13 | axiom r(X, Y) | r(Y, X) # Totality 14 | } 15 | 16 | 17 | ################################################################################ 18 | # 19 | # Module describing a ring topology. 20 | # 21 | # The module includes an anti-reflexive ternary btw relation. 22 | # 23 | # The module also includes get_next and get_prev actions. 24 | # 25 | # In this module, the ring topology is arbitrary and fixed. 26 | # 27 | ################################################################################ 28 | 29 | module ring_topology(carrier) = { 30 | 31 | relation btw(X:carrier,Y:carrier, Z:carrier) # Y is on the acyclic path from X to Z 32 | 33 | # Axiom defining the btw relation - note it's not reflexive 34 | # not needed: axiom btw(X,Y,Z) -> X ~= Y & X ~= Z & Y ~= Z # anti-reflexive 35 | axiom btw(W,X,Y) & btw(W,Y,Z) -> btw(W,X,Z) # transitive 36 | axiom btw(W,X,Y) -> ~btw(W,Y,X) # acyclic 37 | axiom btw(W,X,Y) | btw(W,Y,X) | W=X | W=Y | X=Y # total 38 | axiom btw(X,Y,Z) -> btw(Y,Z,X) # cyclic permutations 39 | 40 | # action get_next(x:carrier) returns (y:carrier) = { 41 | # assume x ~= y & ((Z ~= x & Z ~= y) -> btw(x,y,Z)) 42 | # } 43 | 44 | # action get_prev(y:carrier) returns (x:carrier) = { 45 | # assume y ~= x & ((Z ~= y & Z ~= x) -> btw(y,x,Z)) 46 | # } 47 | 48 | } 49 | 50 | 51 | ################################################################################ 52 | # 53 | # Types, relations and functions describing state of the network 54 | # 55 | ################################################################################ 56 | 57 | type node 58 | type id 59 | 60 | # A ring topology of nodes 61 | instantiate ring : ring_topology(node) 62 | 63 | # A total order on ids 64 | relation le(X:id, Y:id) 65 | instantiate total_order(le) 66 | 67 | # A function relating a node to its id 68 | function idn(X:node) : id 69 | axiom idn(X) = idn(Y) -> X = Y # the idn function is injective 70 | 71 | # A relation that keeps track of nodes that think they are the leader 72 | relation leader(N:node) 73 | 74 | # A relation for pending messages, a message is just an id 75 | relation pending(V:id, N:node) # The identity V is pending at node N 76 | 77 | ################################################################################ 78 | # 79 | # Protocol description 80 | # 81 | # Two action: send and receive 82 | # 83 | ################################################################################ 84 | 85 | after init { 86 | leader(N) := false; 87 | pending(V,N) := false; 88 | } 89 | 90 | action send(n: node, n1: node) = { 91 | # send my own id to the next node 92 | require n ~= n1 & ((Z ~= n & Z ~= n1) -> ring.btw(n, n1, Z)); 93 | pending(idn(n), n1) := true; 94 | } 95 | 96 | action become_leader(n: node) = { 97 | require pending(idn(n), n); 98 | leader(n) := true; 99 | } 100 | 101 | action receive(n: node, m: id, n1: node) = { 102 | require pending(m, n); 103 | require n ~= n1 & ((Z ~= n & Z ~= n1) -> ring.btw(n, n1, Z)); 104 | # require m ~= idn(n); 105 | if le(idn(n), m) { 106 | pending(m, n1) := true; 107 | }; 108 | } 109 | 110 | #action receive(n:node, m:id) = { 111 | # # receive a message from the right neighbor 112 | # assume pending(m, n); 113 | # pending(m, n) := *; # abstract the number of pending messages 114 | # if m = idn(n) { # Found a leader 115 | # leader(n) := true; 116 | # } else { 117 | # if le(idn(n), m) { # pass message to next node 118 | # var s := ring.get_next(n); 119 | # pending(m, s) := true; 120 | # } # otherwise drop the message... 121 | # } 122 | #} 123 | 124 | export send 125 | export receive 126 | export become_leader 127 | 128 | # The safety property: 129 | invariant [1000000] forall X: node, Y:node. leader(X) & leader(Y) -> X = Y # at most one leader 130 | -------------------------------------------------------------------------------- /leader/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | //#define DEBUG 10 | 11 | using std::make_pair; 12 | using std::pair; 13 | using std::string; 14 | using std::map; 15 | using std::vector; 16 | using std::set; 17 | using std::to_string; 18 | map var_to_id; 19 | map > > const_types; 20 | 21 | const int sizeN = 10000; 22 | const int N1 = 1000; 23 | const int N3 = 1000; 24 | int n = 0, n1, n2, n3; 25 | int len[sizeN]; 26 | int try_level[sizeN]; 27 | int arg[sizeN]; 28 | char relation[sizeN][1000]; 29 | char arg_type[N3][100][100]; 30 | 31 | char invs[sizeN][1000]; 32 | string results[sizeN], prefix[sizeN]; 33 | set > vars[sizeN]; 34 | int max_level; 35 | 36 | char type[10000][10000], var[10000][10000], specifies[N1][100][100]; 37 | char t[10000], name[10000]; 38 | 39 | int value; 40 | string model_name; 41 | 42 | struct comp{ 43 | bool operator()(const vector &a, const vector &b) const { 44 | if (a.size() < b.size()) return true; 45 | if (a.size() > b.size()) return false; 46 | for (int i = 0; i < a.size(); i++) { 47 | fprintf(stderr, "comp: %d %d\n", a[i], b[i]); 48 | if (a[i] < b[i]) return true; 49 | if (a[i] > b[i]) return false; 50 | } 51 | return false; 52 | } 53 | }; 54 | 55 | set> rela[1000]; 56 | 57 | void read_invariants(FILE *fi) { 58 | while (fgets(invs[n++], 1000, fi)) { 59 | int l = 0; 60 | for (int i = 0; invs[n-1][i]; i++) 61 | if (invs[n-1][i] != '\\') { 62 | if (invs[n-1][i] != '\t' && invs[n-1][i] != '&' && invs[n-1][i] != '\n') 63 | if (invs[n-1][i] == '\'') { 64 | while (invs[n-1][l - 1] != ' ') l--; 65 | i++; 66 | } else invs[n-1][l++] = invs[n-1][i]; 67 | } 68 | if (!l) n--; 69 | else invs[n-1][l] = 0; 70 | } 71 | n--; 72 | } 73 | 74 | void read_config(FILE *config) { 75 | fscanf(config, "%d\n", &n1); 76 | for (int i = 0; i < n1; i++) { 77 | fscanf(config, "%d %s %s", &len[i], type[i], var[i]); 78 | var_to_id[string(var[i])] = i; 79 | for (int j = 0; j < len[i]; j++) 80 | fscanf(config, "%s", specifies[i][j]); 81 | fscanf(config, "\n"); 82 | } 83 | fscanf(config, "%d\n", &n2); 84 | for (int i = 0; i < n2; i++) { 85 | fscanf(config, "%s %s = %d", t, name, &value); 86 | const_types[string(t)].push_back(make_pair(string(name), value)); 87 | } 88 | fscanf(config, "%d\n", &n3); 89 | max_level = 1<<(n2 + n3); 90 | for (int i = 0; i < n3; i++) { 91 | fscanf(config, "%d %s", &arg[i], relation[i]); 92 | for (int j = 0; j < arg[i]; j++) { 93 | fscanf(config, "%s", arg_type[i][j]); 94 | } 95 | int j; 96 | fscanf(config, "%d", &j); 97 | while (j--) { 98 | vector vec; 99 | int x; 100 | for (int k = 0; k < arg[i]; k++) { 101 | fscanf(config, "%d", &x); 102 | vec.push_back(x); 103 | } 104 | rela[i].insert(vec); 105 | } 106 | } 107 | } 108 | 109 | void print() { 110 | FILE *ivy = fopen((model_name + ".ivy").c_str(), "r"); 111 | FILE *out = fopen((model_name + "_inv.ivy").c_str(), "w"); 112 | char st[100000]; 113 | while (fgets(st, 100000, ivy)) fprintf(out, "%s", st); 114 | fputs("", out); 115 | for (int i = 0; i < n; i++) { 116 | if (prefix[i].length()){ 117 | fprintf(out, "invariant [%d] (%s) -> (%s)\n", i, prefix[i].c_str(), results[i].c_str()); 118 | } else { 119 | fprintf(out, "invariant [%d] %s\n", i, results[i].c_str()); 120 | } 121 | } 122 | fclose(ivy); 123 | fclose(out); 124 | } 125 | 126 | void check_input() { 127 | for (int i = 0; i < n; i++) printf("%s\n", invs[i]); 128 | puts(""); 129 | for (auto it = var_to_id.begin(); it != var_to_id.end(); it++) { 130 | printf("%s:", it->first.c_str()); 131 | for (int i = 0; i < len[it->second]; i++) printf(" %s", specifies[it->second][i]); 132 | puts(""); 133 | } 134 | puts(""); 135 | for (auto it = const_types.begin(); it != const_types.end(); it++) 136 | for (auto it2 = it->second.begin(); it2 != it->second.end(); it2++) { 137 | printf("%s %s = %d\n", it->first.c_str(), it2->first.c_str(), it2->second); 138 | } 139 | puts(""); 140 | for (int i = 0; i < n3; i++) { 141 | printf("%s(%s", relation[i], arg_type[i][0]); 142 | for (int j = 1; j < arg[i]; j++) printf(", %s", arg_type[i][j]); 143 | puts(")"); 144 | for (auto &it : rela[i]) { 145 | for (auto &j : it) printf("%d ", j); 146 | puts(""); 147 | } 148 | puts(""); 149 | } 150 | puts("done"); 151 | } 152 | 153 | string get_constant(string var, int value, set > &vars) { 154 | #ifdef DEBUG 155 | printf("variable: %s value: %d\n", var.c_str(), value); 156 | #endif 157 | // string t = type[var_to_id[var]]; 158 | // for (auto it = const_types[t].begin(); it != const_types[t].end(); it++) { 159 | // if (it->second == value) return it->first; 160 | // } 161 | // fprintf(stderr, "???"); 162 | // throw "?"; 163 | // return "!!!!!!!!!!"; 164 | pair variable = make_pair(var, value); 165 | vars.insert(variable); 166 | return var + std::to_string(value); 167 | } 168 | 169 | string translate(char *st, set > &vars) { 170 | char *pos = strchr(st, '_'); 171 | if (pos) { 172 | while (pos[1] < '0' || pos[1] > '9') 173 | pos = strchr(pos + 1, '_'); 174 | *pos = 0; 175 | string result(st); 176 | int id = var_to_id[result]; 177 | for (int i = 0; i < len[id]; i++) { 178 | pos++; 179 | char *next = strchr(pos, '_'); 180 | if (next) *next = 0; 181 | if (i != 0) result += ", " + get_constant(string(specifies[id][i]), atoi(pos), vars); 182 | else result += "(" + get_constant(string(specifies[id][i]), atoi(pos), vars); 183 | pos = next; 184 | } 185 | result += ")"; 186 | return result; 187 | } else { 188 | string type = ""; 189 | for (; *st < '0' || *st > '9'; st++) 190 | type += string(1, *st); 191 | int val = atoi(st); 192 | vars.insert(make_pair(type, val)); 193 | return type + std::to_string(val); 194 | } 195 | } 196 | 197 | bool check(vector &vec, set > &rela) { 198 | int i; 199 | for (auto &it : rela) { 200 | for (i = 0; i < vec.size(); i++) { 201 | if (vec[i] != it[i]) break; 202 | } 203 | if (i == vec.size()) { 204 | // for (auto i : it) printf("%d ", i); 205 | // puts(""); 206 | // for (int i = 0; i < vec.size(); i++) printf("%d ", vec[i]); 207 | // puts(""); 208 | return true; 209 | } 210 | } 211 | return false; 212 | } 213 | 214 | 215 | string search(int x, int i, vector vec, const set > &vars) { 216 | if (x == arg[i]) { 217 | if (check(vec, rela[i])) { 218 | string st = string(relation[i]) + "(" +arg_type[i][0] + to_string(vec[0]); 219 | for (int j = 1; j < arg[i]; j++) 220 | st += string(", ") + arg_type[i][j] + to_string(vec[j]); 221 | st += ") & "; 222 | return st; 223 | } else return ""; 224 | } 225 | string st; 226 | for (auto it = vars.begin(); it != vars.end(); it++) { 227 | if (it->first == string(arg_type[i][x])) { 228 | vec.push_back(it->second); 229 | st += search(x + 1, i, vec, vars); 230 | vec.pop_back(); 231 | } 232 | } 233 | return st; 234 | } 235 | 236 | void refine(int x) { 237 | try_level[x] = try_level[x] * 2 + 1; 238 | if (try_level[x] < 0) try_level[x] = 0; 239 | if (try_level[x] >= max_level) 240 | { 241 | printf("No refinement for %d!\n", x); 242 | prefix[x] = "false"; 243 | return; 244 | } 245 | string st; 246 | /* if (try_level[x]) { 247 | for (auto it1 = vars[x].begin(); it1 != vars[x].end(); it1++) 248 | for (auto it2 = it1; it2 != vars[x].end(); it2++) { 249 | if (it1->first == it2->first && it1->first == "EPOCH") { 250 | if (it1->second < it2->second) { 251 | st += "le(" + it1->first + std::to_string(it1->second) + ", " + it2->first + std::to_string(it2->second) + ") & "; 252 | } else if (it1->second > it2->second) { 253 | st += "le(" + it2->first + std::to_string(it2->second) + ", " + it1->first + std::to_string(it1->second) + ") & "; 254 | } 255 | } 256 | } 257 | }*/ 258 | auto it1 = const_types.begin(); 259 | auto it2 = it1->second.begin(); 260 | int j = try_level[x]; 261 | for (int i = 0; i < n2; i++) { 262 | if ((1 << i) & j) { 263 | for (auto & it3 : vars[x]) { 264 | if (it3.first == it1->first) { 265 | if (it3.second == it2->second) 266 | st += it3.first + std::to_string(it2->second) + " = " + it2->first + " & "; 267 | else st += it3.first + std::to_string(it3.second) + " ~= " + it2->first + " & "; 268 | } 269 | } 270 | } 271 | it2++; 272 | if (it2 == it1->second.end()) { 273 | it1++; 274 | it2 = it1->second.begin(); 275 | } 276 | } 277 | j = j >> n2; 278 | for (int i = 0; i < n2; i++) { 279 | if ((1 << i) & j) { 280 | st += search(0, i, vector(), vars[x]); 281 | } 282 | } 283 | if (st.size()) st.replace(st.rfind(" & "), 3, ""); 284 | prefix[x] = st; 285 | // printf("%s\n", st.c_str()); 286 | } 287 | 288 | void init() { 289 | for (int i = 0; i < n; i++) { 290 | char st1[100], st2[100], *pos = invs[i]; 291 | string result; 292 | while (*pos) { 293 | 294 | #ifdef DEBUG 295 | printf("now: %s\n", pos); 296 | #endif 297 | 298 | if (*pos == '!' || *pos == '(' || *pos == ')' || *pos == ' ') { 299 | if (*pos == '!') result += '~'; 300 | else result += *pos; 301 | pos++; 302 | } 303 | else { 304 | if (sscanf(pos, "%s %s", st1, st2) != 2 || (strcmp(st2, "==") && strcmp(st2, "!=") && strcmp(st2, "<="))) { 305 | #ifdef DEBUG 306 | printf("%s %s\n", st1, st2); 307 | #endif 308 | pos += strlen(st1); 309 | int cnt = 0; 310 | char *tmp = st1; 311 | while ((tmp = strchr(++tmp, ')'))) cnt++; 312 | if (strchr(st1, ')')) *strchr(st1, ')') = 0; 313 | result += translate(st1, vars[i]); 314 | while (cnt--) result += ')'; 315 | result += " && "; 316 | } else { 317 | #ifdef DEBUG 318 | printf("%s %s\n", st1, st2); 319 | #endif 320 | pos += strlen(st1) + strlen(st2) + 2; 321 | //printf("rest: %s\n", pos); 322 | if (strcmp(st2, "==") == 0) st2[1] = 0; 323 | else if (strcmp(st2, "!=") == 0) st2[0] = '~'; 324 | 325 | if (strcmp(st2, "<=") == 0) { 326 | result += "le(" + translate(st1, vars[i]) + ", "; 327 | } else { 328 | result += "(" + translate(st1, vars[i]) + " " + st2 + " "; 329 | } 330 | char *tmp = strchr(pos, ')'); 331 | *tmp = ' '; 332 | sscanf(pos, "%s", st2); 333 | pos += strlen(st2); 334 | //printf("new: %s\n", pos); 335 | if (st2[0] >= '0' && st2[0] <= '9') result += get_constant(type[var_to_id[st1]], atoi(st2), vars[i]) + ")) && "; 336 | else result += translate(st2, vars[i]) + ")) && "; 337 | } 338 | } 339 | } 340 | result.replace(result.rfind("&&"), 2, ""); 341 | while (result.find(" ") != string::npos) result.replace(result.find(" "), 2, " "); 342 | while (result.find(") )") != string::npos) result.replace(result.find(") )"), 3, "))"); 343 | while (result.find("&&") != string::npos) result.replace(result.find("&&"), 2, "&"); 344 | 345 | string distinct = "idn(N0) = ID0 & idn(N1) = ID1 & idn(N2) = ID2 & "; 346 | for (auto it1 = vars[i].begin(); it1 != vars[i].end(); it1++) { 347 | for (auto it2 = it1; it2 != vars[i].end(); it2++) { 348 | if (it1->first == it2->first && it1->second != it2->second) { 349 | distinct += it1->first + std::to_string(it1->second) + " ~= " + it2->first + std::to_string(it2->second) + " & "; 350 | } 351 | } 352 | } 353 | if (distinct.length()) { 354 | distinct.replace(distinct.rfind(" & "), 3, ""); 355 | results[i] = "(" + distinct + ") -> " + result; 356 | } 357 | else results[i] = result; 358 | try_level[i] = max_level / 2 - 1; refine(i); 359 | } 360 | } 361 | 362 | bool v[100000]; 363 | bool verify() { 364 | system(("ivy_check " + model_name + "_inv.ivy > log.txt").c_str()); 365 | FILE *in = fopen("log.txt", "r"); 366 | char st[100000]; 367 | int line, id; 368 | bool flag = false; 369 | char str[100000]; 370 | memset(v, 0, sizeof(v)); 371 | while (fgets(st, 100000, in)) { 372 | if (strstr(st, "FAIL")) { 373 | sscanf(st, "%s line %d: %d", str, &line, &id); 374 | printf("%s line %d: %d\n", str, line, id); 375 | if (id == 1000000) exit(-1); 376 | if (!v[id]) { 377 | v[id] = true; 378 | refine(id); 379 | } 380 | flag = true; 381 | } 382 | } 383 | fclose(in); 384 | if (!flag) fprintf(stderr, "succeed!\n"); 385 | return flag; 386 | } 387 | int main(int argc, char *argv[]) { 388 | if (argc < 3) { 389 | fprintf(stderr, "./main [model_name] [invariant_file]\n"); 390 | return 0; 391 | } 392 | model_name = argv[1]; 393 | 394 | read_invariants(fopen(argv[2], "r")); 395 | read_config(fopen(("config_" + model_name + ".txt").c_str(), "r")); 396 | 397 | check_input(); 398 | 399 | init(); 400 | // printf("vars[435]\n"); 401 | // for (auto it : vars[435]) { 402 | // printf("%s %d\n", it.first.c_str(), it.second); 403 | // } 404 | int cnt = 0; 405 | do { 406 | fprintf(stderr, "iteration %d\n\n", ++cnt); 407 | print(); 408 | // if (cnt == 3) { 409 | // // refine(9); 410 | // // refine(10); 411 | // // refine(26); 412 | // // refine(27); 413 | // print(); 414 | // break; 415 | // } 416 | } while (verify()); 417 | for (int i = 0; i < n; i++) 418 | fprintf(stderr, "%d: %d\n", i, try_level[i]); 419 | return 0; 420 | } 421 | -------------------------------------------------------------------------------- /lock_server/config_lock_server.txt: -------------------------------------------------------------------------------- 1 | 2 2 | 2 bool link C S 3 | 1 bool semaphore S 4 | 5 | 0 6 | 7 | 0 8 | -------------------------------------------------------------------------------- /lock_server/inst.txt: -------------------------------------------------------------------------------- 1 | 2 2 | client=2 3 | server=1 4 | 5 | 0 6 | -------------------------------------------------------------------------------- /lock_server/lock_server.ivy: -------------------------------------------------------------------------------- 1 | #lang ivy1.7 2 | 3 | type client 4 | type server 5 | 6 | relation link(X:client, Y:server) 7 | relation semaphore(X:server) 8 | 9 | after init { 10 | semaphore(W) := true; 11 | link(X,Y) := false 12 | } 13 | 14 | action connect(x:client,y:server) = { 15 | require semaphore(y); 16 | link(x,y) := true; 17 | semaphore(y) := false 18 | } 19 | 20 | action disconnect(x:client,y:server) = { 21 | require link(x,y); 22 | link(x,y) := false; 23 | semaphore(y) := true 24 | } 25 | 26 | export connect 27 | export disconnect 28 | 29 | invariant [1000000] link(C1, S) & link(C2, S) -> C1 = C2 30 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | //#define DEBUG 10 | 11 | using std::make_pair; 12 | using std::pair; 13 | using std::string; 14 | using std::map; 15 | using std::vector; 16 | using std::set; 17 | using std::to_string; 18 | map var_to_id; 19 | map > > const_types; 20 | 21 | const int sizeN = 10000; 22 | const int N1 = 1000; 23 | const int N3 = 1000; 24 | int n = 0, n1, n2, n3; 25 | int len[sizeN]; 26 | int try_level[sizeN]; 27 | int arg[sizeN]; 28 | char relation[sizeN][1000]; 29 | char arg_type[N3][100][100]; 30 | 31 | char invs[sizeN][1000]; 32 | string results[sizeN], prefix[sizeN]; 33 | set > vars[sizeN]; 34 | int max_level; 35 | 36 | char type[10000][10000], var[10000][10000], specifies[N1][100][100]; 37 | char t[10000], name[10000]; 38 | 39 | int value; 40 | string model_name; 41 | string inv_prefix; 42 | 43 | struct comp{ 44 | bool operator()(const vector &a, const vector &b) const { 45 | if (a.size() < b.size()) return true; 46 | if (a.size() > b.size()) return false; 47 | for (int i = 0; i < a.size(); i++) { 48 | fprintf(stderr, "comp: %d %d\n", a[i], b[i]); 49 | if (a[i] < b[i]) return true; 50 | if (a[i] > b[i]) return false; 51 | } 52 | return false; 53 | } 54 | }; 55 | 56 | set> rela[1000]; 57 | 58 | void read_invariants(FILE *fi) { 59 | while (fgets(invs[n++], 1000, fi)) { 60 | int l = 0; 61 | for (int i = 0; invs[n-1][i]; i++) 62 | if (invs[n-1][i] != '\\') { 63 | if (invs[n-1][i] != '\t' && invs[n-1][i] != '&' && invs[n-1][i] != '\n') 64 | if (invs[n-1][i] == '\'') { 65 | while (invs[n-1][l - 1] != ' ') l--; 66 | i++; 67 | } else invs[n-1][l++] = invs[n-1][i]; 68 | } 69 | invs[n-1][l] = 0; 70 | if (!l || invs[n-1][0] == '[' || (invs[n-1][0] == '(' && invs[n-1][3] == ':') || invs[n-1][0] == 'p') n--; 71 | 72 | } 73 | n--; 74 | } 75 | 76 | void read_config(FILE *config) { 77 | fscanf(config, "%d\n", &n1); 78 | for (int i = 0; i < n1; i++) { 79 | fscanf(config, "%d %s %s", &len[i], type[i], var[i]); 80 | var_to_id[string(var[i])] = i; 81 | for (int j = 0; j < len[i]; j++) 82 | fscanf(config, "%s", specifies[i][j]); 83 | fscanf(config, "\n"); 84 | } 85 | fscanf(config, "%d\n", &n2); 86 | for (int i = 0; i < n2; i++) { 87 | fscanf(config, "%s %s = %d", t, name, &value); 88 | const_types[string(t)].push_back(make_pair(string(name), value)); 89 | } 90 | fscanf(config, "%d\n", &n3); 91 | max_level = 1<<(n2 + n3); 92 | for (int i = 0; i < n3; i++) { 93 | fscanf(config, "%d %s", &arg[i], relation[i]); 94 | for (int j = 0; j < arg[i]; j++) { 95 | fscanf(config, "%s", arg_type[i][j]); 96 | } 97 | int j; 98 | fscanf(config, "%d", &j); 99 | while (j--) { 100 | vector vec; 101 | int x; 102 | for (int k = 0; k < arg[i]; k++) { 103 | fscanf(config, "%d", &x); 104 | vec.push_back(x); 105 | } 106 | rela[i].insert(vec); 107 | } 108 | } 109 | } 110 | 111 | void print() { 112 | FILE *ivy = fopen((model_name + ".ivy").c_str(), "r"); 113 | FILE *out = fopen((model_name + "_inv.ivy").c_str(), "w"); 114 | char st[100000]; 115 | while (fgets(st, 100000, ivy)) fprintf(out, "%s", st); 116 | fputs("", out); 117 | for (int i = 0; i < n; i++) { 118 | if (prefix[i].length()){ 119 | fprintf(out, "invariant [%d] (%s) -> (%s)\n", i, prefix[i].c_str(), results[i].c_str()); 120 | } else { 121 | fprintf(out, "invariant [%d] %s\n", i, results[i].c_str()); 122 | } 123 | } 124 | fclose(ivy); 125 | fclose(out); 126 | } 127 | 128 | void check_input() { 129 | for (int i = 0; i < n; i++) printf("%s\n", invs[i]); 130 | puts(""); 131 | for (auto it = var_to_id.begin(); it != var_to_id.end(); it++) { 132 | printf("%s:", it->first.c_str()); 133 | for (int i = 0; i < len[it->second]; i++) printf(" %s", specifies[it->second][i]); 134 | puts(""); 135 | } 136 | puts(""); 137 | for (auto it = const_types.begin(); it != const_types.end(); it++) 138 | for (auto it2 = it->second.begin(); it2 != it->second.end(); it2++) { 139 | printf("%s %s = %d\n", it->first.c_str(), it2->first.c_str(), it2->second); 140 | } 141 | puts(""); 142 | for (int i = 0; i < n3; i++) { 143 | printf("%s(%s", relation[i], arg_type[i][0]); 144 | for (int j = 1; j < arg[i]; j++) printf(", %s", arg_type[i][j]); 145 | puts(")"); 146 | for (auto &it : rela[i]) { 147 | for (auto &j : it) printf("%d ", j); 148 | puts(""); 149 | } 150 | puts(""); 151 | } 152 | puts("done"); 153 | } 154 | 155 | string get_constant(string var, int value, set > &vars) { 156 | #ifdef DEBUG 157 | printf("variable: %s value: %d\n", var.c_str(), value); 158 | #endif 159 | // string t = type[var_to_id[var]]; 160 | // for (auto it = const_types[t].begin(); it != const_types[t].end(); it++) { 161 | // if (it->second == value) return it->first; 162 | // } 163 | // fprintf(stderr, "???"); 164 | // throw "?"; 165 | // return "!!!!!!!!!!"; 166 | pair variable = make_pair(var, value); 167 | vars.insert(variable); 168 | return var + std::to_string(value); 169 | } 170 | 171 | string translate(char *st, set > &vars) { 172 | char *pos = strchr(st, '_'); 173 | if (pos) { 174 | while (pos[1] < '0' || pos[1] > '9') { 175 | pos = strchr(pos + 1, '_'); 176 | if (!pos) return st; 177 | } 178 | *pos = 0; 179 | string result(st); 180 | int id = var_to_id[result]; 181 | for (int i = 0; i < len[id]; i++) { 182 | pos++; 183 | char *next = strchr(pos, '_'); 184 | if (next) *next = 0; 185 | if (i != 0) result += ", " + get_constant(string(specifies[id][i]), atoi(pos), vars); 186 | else result += "(" + get_constant(string(specifies[id][i]), atoi(pos), vars); 187 | pos = next; 188 | } 189 | result += ")"; 190 | return result; 191 | } else { 192 | string type = ""; 193 | for (; *st < '0' || *st > '9'; st++) 194 | type += string(1, *st); 195 | int val = atoi(st); 196 | vars.insert(make_pair(type, val)); 197 | return type + std::to_string(val); 198 | } 199 | } 200 | 201 | bool check(vector &vec, set > &rela) { 202 | int i; 203 | for (auto &it : rela) { 204 | for (i = 0; i < vec.size(); i++) { 205 | if (vec[i] != it[i]) break; 206 | } 207 | if (i == vec.size()) { 208 | // for (auto i : it) printf("%d ", i); 209 | // puts(""); 210 | // for (int i = 0; i < vec.size(); i++) printf("%d ", vec[i]); 211 | // puts(""); 212 | return true; 213 | } 214 | } 215 | return false; 216 | } 217 | 218 | 219 | string search(int x, int i, vector vec, const set > &vars) { 220 | if (x == arg[i]) { 221 | if (check(vec, rela[i])) { 222 | string st = string(relation[i]) + "(" +arg_type[i][0] + to_string(vec[0]); 223 | for (int j = 1; j < arg[i]; j++) 224 | st += string(", ") + arg_type[i][j] + to_string(vec[j]); 225 | st += ") & "; 226 | return st; 227 | } else return ""; 228 | } 229 | string st; 230 | for (auto it = vars.begin(); it != vars.end(); it++) { 231 | if (it->first == string(arg_type[i][x])) { 232 | vec.push_back(it->second); 233 | st += search(x + 1, i, vec, vars); 234 | vec.pop_back(); 235 | } 236 | } 237 | return st; 238 | } 239 | 240 | void refine(int x) { 241 | try_level[x] = try_level[x] * 2 + 1; 242 | if (try_level[x] < 0) try_level[x] = 0; 243 | if (try_level[x] >= max_level) 244 | { 245 | // printf("No refinement for %d!\n", x); 246 | prefix[x] = "false"; 247 | return; 248 | } 249 | string st; 250 | /* if (try_level[x]) { 251 | for (auto it1 = vars[x].begin(); it1 != vars[x].end(); it1++) 252 | for (auto it2 = it1; it2 != vars[x].end(); it2++) { 253 | if (it1->first == it2->first && it1->first == "EPOCH") { 254 | if (it1->second < it2->second) { 255 | st += "le(" + it1->first + std::to_string(it1->second) + ", " + it2->first + std::to_string(it2->second) + ") & "; 256 | } else if (it1->second > it2->second) { 257 | st += "le(" + it2->first + std::to_string(it2->second) + ", " + it1->first + std::to_string(it1->second) + ") & "; 258 | } 259 | } 260 | } 261 | }*/ 262 | auto it1 = const_types.begin(); 263 | auto it2 = it1->second.begin(); 264 | int j = try_level[x]; 265 | for (int i = 0; i < n2; i++) { 266 | if ((1 << i) & j) { 267 | for (auto & it3 : vars[x]) { 268 | if (it3.first == it1->first) { 269 | if (it3.second == it2->second) 270 | st += it3.first + std::to_string(it2->second) + " = " + it2->first + " & "; 271 | else st += it3.first + std::to_string(it3.second) + " ~= " + it2->first + " & "; 272 | } 273 | } 274 | } 275 | it2++; 276 | if (it2 == it1->second.end()) { 277 | it1++; 278 | it2 = it1->second.begin(); 279 | } 280 | } 281 | j = j >> n2; 282 | for (int i = 0; i < n2; i++) { 283 | if ((1 << i) & j) { 284 | st += search(0, i, vector(), vars[x]); 285 | } 286 | } 287 | if (st.size()) st.replace(st.rfind(" & "), 3, ""); 288 | prefix[x] = st; 289 | // printf("%s\n", st.c_str()); 290 | } 291 | 292 | void init() { 293 | for (int i = 0; i < n; i++) { 294 | char st1[100], st2[100], *pos = invs[i]; 295 | string result; 296 | while (*pos) { 297 | 298 | #ifdef DEBUG 299 | printf("now: %s\n", pos); 300 | #endif 301 | 302 | if (*pos == '!' || *pos == '(' || *pos == ')' || *pos == ' ') { 303 | if (*pos == '!') result += '~'; 304 | else result += *pos; 305 | pos++; 306 | } 307 | else { 308 | if (sscanf(pos, "%s %s", st1, st2) != 2 || (strcmp(st2, "==") && strcmp(st2, "!=") && strcmp(st2, "<="))) { 309 | #ifdef DEBUG 310 | printf("%s %s\n", st1, st2); 311 | #endif 312 | pos += strlen(st1); 313 | int cnt = 0; 314 | char *tmp = st1; 315 | while ((tmp = strchr(++tmp, ')'))) cnt++; 316 | if (strchr(st1, ')')) *strchr(st1, ')') = 0; 317 | result += translate(st1, vars[i]); 318 | while (cnt--) result += ')'; 319 | result += " && "; 320 | } else { 321 | #ifdef DEBUG 322 | printf("%s %s\n", st1, st2); 323 | #endif 324 | pos += strlen(st1) + strlen(st2) + 2; 325 | //printf("rest: %s\n", pos); 326 | if (strcmp(st2, "==") == 0) st2[1] = 0; 327 | else if (strcmp(st2, "!=") == 0) st2[0] = '~'; 328 | 329 | if (strcmp(st2, "<=") == 0) { 330 | result += "le(" + translate(st1, vars[i]) + ", "; 331 | } else { 332 | result += "(" + translate(st1, vars[i]) + " " + st2 + " "; 333 | } 334 | char *tmp = strchr(pos, ')'); 335 | *tmp = ' '; 336 | sscanf(pos, "%s", st2); 337 | pos += strlen(st2); 338 | //printf("new: %s\n", pos); 339 | if (st2[0] >= '0' && st2[0] <= '9') result += get_constant(type[var_to_id[st1]], atoi(st2), vars[i]) + ")) && "; 340 | else result += translate(st2, vars[i]) + ")) && "; 341 | } 342 | } 343 | } 344 | result.replace(result.rfind("&&"), 2, ""); 345 | while (result.find(" ") != string::npos) result.replace(result.find(" "), 2, " "); 346 | while (result.find(") )") != string::npos) result.replace(result.find(") )"), 3, "))"); 347 | while (result.find("&&") != string::npos) result.replace(result.find("&&"), 2, "&"); 348 | 349 | string distinct; 350 | if (inv_prefix.size() == 0) { 351 | distinct = ""; 352 | } else { 353 | distinct = inv_prefix; 354 | } 355 | for (auto it1 = vars[i].begin(); it1 != vars[i].end(); it1++) { 356 | for (auto it2 = it1; it2 != vars[i].end(); it2++) { 357 | if (it1->first == it2->first && it1->second != it2->second) { 358 | distinct += it1->first + std::to_string(it1->second) + " ~= " + it2->first + std::to_string(it2->second) + " & "; 359 | } 360 | } 361 | } 362 | if (distinct.length()) { 363 | distinct.replace(distinct.rfind(" & "), 3, ""); 364 | results[i] = "(" + distinct + ") -> " + result; 365 | } 366 | else results[i] = result; 367 | try_level[i] = max_level / 2 - 1; refine(i); 368 | } 369 | } 370 | 371 | bool v[100000]; 372 | bool verify() { 373 | system(("ivy_check " + model_name + "_inv.ivy > log.txt").c_str()); 374 | FILE *in = fopen("log.txt", "r"); 375 | char st[100000]; 376 | int line, id; 377 | bool flag = false; 378 | bool succeed = false; 379 | char str[100000]; 380 | memset(v, 0, sizeof(v)); 381 | while (fgets(st, 100000, in)) { 382 | if (strstr(st, "FAIL")) { 383 | sscanf(st, "%s line %d: %d", str, &line, &id); 384 | //printf("%s line %d: %d\n", str, line, id); 385 | if (id == 1000000) { 386 | fprintf(stderr, "failed!\n"); 387 | exit(-1); 388 | } 389 | if (!v[id]) { 390 | v[id] = true; 391 | refine(id); 392 | } 393 | flag = true; 394 | } 395 | if (strcmp(st, "OK\n") == 0) { 396 | succeed = true; 397 | } 398 | } 399 | fclose(in); 400 | if (!flag) fprintf(stderr, succeed ? "succeed!\n" : "error!\n"); 401 | return flag; 402 | } 403 | int main(int argc, char *argv[]) { 404 | if (argc < 4) { 405 | fprintf(stderr, "./main model_file invariant_file config_file [invariant_prefix]\n"); 406 | return 0; 407 | } 408 | model_name = argv[1]; 409 | 410 | read_invariants(fopen(argv[2], "r")); 411 | read_config(fopen(argv[3], "r")); 412 | 413 | if (argc == 5) { 414 | inv_prefix = argv[4]; 415 | } 416 | 417 | //check_input(); 418 | 419 | init(); 420 | int cnt = 0; 421 | do { 422 | fprintf(stderr, "\niteration %d\n", ++cnt); 423 | print(); 424 | } while (verify()); 425 | return 0; 426 | } 427 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import subprocess 3 | import os 4 | from collections import defaultdict 5 | from copy import copy 6 | from itertools import permutations 7 | 8 | numbers = set() 9 | replace = {'!': '~', '&&': '&', '==': '='} 10 | nameprefix = 'v' 11 | 12 | for i in range(10): 13 | numbers.add(str(i)) 14 | 15 | def add_var(var, dic): 16 | l = len(var) 17 | while var[l - 1] in numbers and l > 0: 18 | l = l - 1 19 | if l == len(var) or l == 0: 20 | return var 21 | var = var.upper() 22 | if var not in dic[var[:l]]: 23 | dic[var[:l]].append(var) 24 | return '%s:%s'%(var, var[:l].lower()) 25 | 26 | def parse_var(st, used, config): 27 | # print 'parsing', st 28 | if st[0] == '_': 29 | st = st[1:] 30 | st = st.split('_') 31 | while len(st) > 1 and st[-2][-1] not in numbers: 32 | st[-2] = "%s_%s" % (st[-2], st[-1]) 33 | st.pop() 34 | 35 | ret = st[-1] 36 | if ret != '<': 37 | if len(st) > 1: 38 | ret += '(' 39 | else: 40 | # This is a constant. I need to remove its type in the beginning. 41 | l = -1 42 | for k in config.sorts: 43 | if ret.startswith(config.sorts[k].lower() + '_'): 44 | l = max(l, len(config.sorts[k])) 45 | assert '_' not in ret or l > 0, ret 46 | ret = ret[l + 1:] 47 | ret = add_var(ret, used) 48 | i = len(st) - 2 49 | while i >= 0: 50 | if i > 0: 51 | ret += add_var(st[i], used) + ', ' 52 | else: 53 | ret += add_var(st[i], used) + ')' 54 | i = i - 1 55 | # print ret 56 | return ret 57 | else: 58 | return "%s < %s" % (add_var(st[1], used), add_var(st[0], used)) 59 | 60 | def parse(st, used, config): 61 | ret = '' 62 | l = 0 63 | while l < len(st): 64 | if st[l] == '?': 65 | print ret 66 | print st 67 | exit() 68 | if st[l] in ['(', ')', '~', ' ', '&', '=']: 69 | ret += st[l] 70 | l = l + 1 71 | elif st[l] == '\t': 72 | l = l + 1 73 | else: 74 | r = l + 1 75 | while r < len(st) and st[r] not in ['(', ')', '~', ' ']: 76 | r = r + 1 77 | ret += parse_var(st[l:r], used, config) 78 | l = r 79 | return ret 80 | 81 | def comp(dic1, dic2): 82 | for k in dic1: 83 | if k not in dic2: 84 | return False 85 | for v in dic1[k]: 86 | if v not in dic2[k]: 87 | return False 88 | return True 89 | 90 | def update(dic1, dic2): 91 | for k in dic2: 92 | if k not in dic1: 93 | dic1[k] = dic2[k] 94 | else: 95 | dic1[k] = list(set(dic1[k] + dic2[k])) 96 | 97 | class Config(): 98 | def __init__(self, fi): 99 | self.module = fi.readline().replace('\n', '') 100 | self.isolate = fi.readline().replace('\n', '').split('=') 101 | if 'isolate' == self.isolate[0]: 102 | self.isolate = self.isolate[1] 103 | assert fi.readline() == '\n' 104 | else: 105 | self.isolate = '' 106 | self.read_relations(fi) 107 | assert fi.readline() == '\n' 108 | self.read_sorts(fi) 109 | assert fi.readline() == '\n' 110 | self.read_prefix(fi) 111 | # assert fi.readline() == '\n' 112 | # self.read_insts(fi) 113 | 114 | def read_relations(self, fi): 115 | n = eval(fi.readline()) 116 | self.relations = set() 117 | self.values = {} 118 | self.paras = {} 119 | for i in range(n): 120 | st = fi.readline().split() 121 | self.relations.add(st[2]) 122 | self.values[st[2]] = st[1] 123 | self.paras[st[2]] = st[3:] 124 | 125 | def read_sorts(self, fi): 126 | n = eval(fi.readline()) 127 | self.sorts = {} 128 | for i in range(n): 129 | st = fi.readline().split() 130 | self.sorts["%s'd" % st[1]] = st[0] 131 | 132 | def read_prefix(self, fi): 133 | n = eval(fi.readline()) 134 | self.prefix = {} 135 | for i in range(n): 136 | st = fi.readline()[:-1].split('=') 137 | used = defaultdict(list) 138 | if (len(st) > 1): 139 | ret = "%s=%s" % (parse_var(st[0], used, self), parse_var(st[1], used, self)) 140 | else: 141 | ret = "%s" % (parse_var(st[0], self.used, self)) 142 | self.prefix[ret] = used 143 | # print self.prefix 144 | 145 | class Invariant(): 146 | def __init__(self, fi, config): 147 | self.invs = [] # list of generalized invariants 148 | self.vars = [] # list of dict (vartype, list of varname in this type). 149 | self.symmetry = set() # set of generalized invariants after applying symmetry. To remove the same invariant after quantifier. 150 | self.config = config 151 | for st in fi: 152 | if st != '\n' and st.find('sz:') == -1 and st.find('property') == -1: 153 | assert 'fml_' not in st and 'loc_' not in st 154 | st = st.replace('\n', '') 155 | self.parse(st, self.config) 156 | for i in range(len(self.invs)): 157 | prefix = [] 158 | for p in config.prefix: 159 | prefix.append(p) 160 | if '(' not in p: 161 | update(self.vars[i], config.prefix[p]) 162 | # if comp(config.prefix[p], self.vars[i]): 163 | # prefix.append(p) 164 | for t in self.vars[i]: 165 | for l in range(1, len(self.vars[i][t])): 166 | for r in range(l): 167 | prefix.append("%s ~= %s" % (self.vars[i][t][r], self.vars[i][t][l])) 168 | if prefix: 169 | self.invs[i] = "(%s) -> (%s)" % (' & '.join(prefix), self.invs[i]) 170 | 171 | def __str__(self): 172 | ret = 'private {\n' 173 | for i in range(len(self.invs)): 174 | ret += "invariant [%s%d] %s\n" % (nameprefix, i, self.invs[i]) 175 | ret += '}\n' 176 | return ret 177 | 178 | def parse(self, st, config): 179 | var = defaultdict(list) 180 | st = st.replace('___', '_') 181 | if config.isolate: 182 | st = st.replace('%s.' % (config.isolate), '') 183 | if st.endswith('&&'): 184 | st = st[:-2] 185 | for k in config.sorts: 186 | st = st.replace(k, config.sorts[k]) 187 | for k in replace: 188 | st = st.replace(k, replace[k]) 189 | result = parse(st, var, config) 190 | if self.check_symmetry(result, var): 191 | self.invs.append(result) 192 | self.vars.append(var) 193 | 194 | def check_symmetry(self, result, var): 195 | return True 196 | rep = [result] 197 | for typ in var: 198 | l = len(var[typ]) 199 | newl = [] 200 | for perm in permutations(range(l)): 201 | tmp = list(rep) 202 | # print 'before:', tmp 203 | for org, v in zip(var[typ], perm): 204 | if not any(org in self.config.prefix[p][typ] for p in self.config.prefix): 205 | # print 'replace %s %s_%d' % (org, typ, v) 206 | tmp = map(lambda x: x.replace(org, '%s_%d' % (typ, v)), tmp) 207 | # print 'after:', tmp 208 | newl.extend(tmp) 209 | rep = newl 210 | # print '\n'.join(rep) 211 | # assert len(set(rep)) == len(rep) 212 | for s in rep: 213 | if s in self.symmetry: 214 | return False 215 | self.symmetry = self.symmetry.union(rep) 216 | return True 217 | 218 | def remove(self, i): 219 | self.invs[i] = 'false -> (%s)' % self.invs[i] 220 | 221 | def check(inv, config): 222 | fi = open('%s_%s.bak' % (config.module, config.isolate), 'r') 223 | fo = open('%s_%s.ivy' % (config.module, config.isolate), 'w') 224 | flag = True 225 | for st in fi: 226 | if 'invariant' in st and flag: 227 | fo.write(str(inv)) 228 | flag = False 229 | fo.write(st) 230 | fo.close() 231 | fi.close() 232 | global cnt 233 | if cnt < 1: 234 | fi = open('log.txt', 'r') 235 | else: 236 | if config.isolate: 237 | output = subprocess.Popen("ivy_check isolate=%s %s_system.ivy | tee log.txt " % (config.isolate, config.module), shell=True, stdout=subprocess.PIPE) 238 | else: 239 | output = subprocess.Popen("ivy_check %s_.ivy | tee log.txt " % (config.module), shell=True, stdout=subprocess.PIPE) 240 | fi = iter(output.stdout.readline, '') 241 | 242 | for st in fi: 243 | if any(p in st for p in ['Initialization', '(internal)']): 244 | print 'starting' + st, 245 | if 'FAIL' in st and 'line' in st: 246 | print st, 247 | if config.isolate: 248 | st = st.replace('%s.%s' % (config.isolate, nameprefix), '') 249 | else: 250 | st = st.replace(': %s' % (nameprefix), ': ') 251 | p = st.find('line') 252 | p += st[p:].find(':') + 2 253 | r = st[p:].find(' ') 254 | fail = eval(st[p:p + r]) 255 | if fail >= 1000000: 256 | print 'safety failed' 257 | exit() 258 | inv.remove(fail) 259 | if st == 'OK\n': 260 | return True 261 | return False 262 | 263 | if __name__ == '__main__': 264 | if len(sys.argv) != 3: 265 | print 'python main.py config inv_file' 266 | exit() 267 | config = Config(open(sys.argv[1], 'r')) 268 | inv = Invariant(open(sys.argv[2], 'r'), config) 269 | if not os.path.isfile('%s_%s.bak' % (config.module, config.isolate)): 270 | if config.isolate: 271 | os.system('cp %s_%s.ivy %s_%s.bak' % (config.module, config.isolate, config.module, config.isolate)) 272 | else: 273 | os.system('cp %s.ivy %s_%s.bak' % (config.module, config.module, config.isolate)) 274 | global cnt 275 | cnt = 1 276 | while not check(inv, config): 277 | print cnt, 'done' 278 | cnt += 1 279 | if cnt > 10: 280 | exit() 281 | print 'Success!' 282 | -------------------------------------------------------------------------------- /remove.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | if __name__ == '__main__': 4 | fi = open(sys.argv[1], 'r') 5 | flag = False 6 | for i in fi: 7 | if flag: 8 | if len(i) >= 11 and i[:11] == 'Assumptions': 9 | exit() 10 | print i, 11 | if len(i) >= 9 and i[:9] == 'Minimized': 12 | flag = True 13 | 14 | if flag: exit() 15 | 16 | fi = open(sys.argv[1], 'r') 17 | for i in fi: 18 | if flag: 19 | if len(i) >= 11 and i[:11] == 'Assumptions': 20 | exit() 21 | if 'fml_' not in i and 'loc_' not in i and '[1]' not in i: 22 | print i, 23 | if len(i) >= 9 and i[:9] == 'Inductive': 24 | flag = True 25 | -------------------------------------------------------------------------------- /switch/config_switch.txt: -------------------------------------------------------------------------------- 1 | 6 2 | 3 bool pending P N N 3 | 1 N src P 4 | 1 N dst P 5 | 2 bool link N N 6 | 2 bool route_dom N N 7 | 3 bool route_tc N N N 8 | 9 | 0 10 | 11 | 0 12 | -------------------------------------------------------------------------------- /switch/inst.txt: -------------------------------------------------------------------------------- 1 | 2 2 | node=3 3 | packet=1 4 | 5 | 0 6 | -------------------------------------------------------------------------------- /switch/switch.ivy: -------------------------------------------------------------------------------- 1 | #lang ivy1.7 2 | 3 | ################################################################################ 4 | # 5 | # Module describing an acyclic partial function. The function is built by 6 | # calling the "set" action. This has preconditions that enforce the required 7 | # invariants. The function can be accessed using "dom" to query if an element is 8 | # in the domain of the function, and "get" to get its value. The "get" action 9 | # has a precondition that the given element must be in the domain. 10 | # 11 | # Because of the invariant that the relation re construct by "set" is an acyclic 12 | # partial function, we can represent it by its transitive closure "tc", while 13 | # remainin in EPR. 14 | # 15 | ################################################################################ 16 | 17 | #module acyclic_partial_function(carrier) = { 18 | # relation dom(X:carrier) # domain of the function 19 | # relation tc(X:carrier,Y:carrier) # transitive closure of the function 20 | 21 | # Conjectures that ensure that tc really describes the transitive closure 22 | # of an acyclic partial function. 23 | # These invariants for part of the safety property. 24 | # invariant tc(X,X) # Reflexivity 25 | # invariant tc(X, Y) & tc(Y, Z) -> tc(X, Z) # Transitivity 26 | # invariant tc(X, Y) & tc(Y, X) -> X = Y # Anti-symmetry 27 | # invariant tc(X, Y) & tc(X, Z) -> (tc(Y, Z) | tc(Z, Y)) # Semi-linearity 28 | 29 | # init ~dom(X) & (tc(X,Y) <-> X = Y) #initially empty 30 | 31 | # action set(x:carrier,y:carrier) = { 32 | # dom(x) := true; 33 | # tc(X, Y) := tc(X, Y) | (tc(X, x) & tc(y, Y)) 34 | # } 35 | 36 | # action get(x:carrier) returns (y:carrier) = { 37 | # assume tc(x,y) & x ~= y & ((tc(x, Z) & x ~= Z) -> tc(y, Z)) 38 | # } 39 | #} 40 | 41 | ################################################################################ 42 | # 43 | # Types, relations and functions describing state of the network 44 | # 45 | ################################################################################ 46 | 47 | type packet 48 | type node 49 | 50 | relation pending(P:packet, S:node, T:node) # relation for pending packets 51 | function src(P:packet) : node # function src : packet -> node 52 | function dst(P:packet) : node # function dst : packet -> node 53 | relation link(S:node, T:node) # relation for network topology 54 | 55 | relation route_dom(N: node, X: node) 56 | relation route_tc(N: node, X: node, Y: node) 57 | #instantiate route(N:node) : acyclic_partial_function(node) # routing tables 58 | 59 | axiom ~link(X, X) # no self-loops in links 60 | axiom ~link(X, Y) | link(Y, X) # symmetric links 61 | 62 | # The initial state of the network (empty) 63 | after init { 64 | route_dom(N, X) := false; 65 | route_tc(N, X, Y) := X = Y; 66 | pending(P, S, T) := false; 67 | } 68 | # init ~pending(P,S,T) 69 | 70 | ################################################################################ 71 | # 72 | # Protocol description 73 | # 74 | # Two action: new_packet and receive 75 | # 76 | ################################################################################ 77 | 78 | action new_packet(p: packet) = { 79 | # Create a new packet, by adding it to pending from the src to itself 80 | pending(p, src(p), src(p)) := true 81 | } 82 | 83 | action flood(p: packet, sw0: node, sw1: node, sw2: node) = { 84 | require pending(p, sw0, sw1); 85 | require ~route_dom(dst(p), sw1); 86 | if (~route_dom(src(p), sw1) & src(p) ~= sw1) { 87 | # dom(x) := true; 88 | # tc(X, Y) := tc(X, Y) | (tc(X, x) & tc(y, Y)) 89 | route_dom(src(p), sw1) := true; 90 | route_tc(src(p), X, Y) := route_tc(src(p), X, Y) | (route_tc(src(p), X, sw1) & route_tc(src(p), sw0, Y)); 91 | }; 92 | if dst(p) ~= sw1 { 93 | pending(p, sw1, Y) := link(sw1, Y) & Y ~= sw0; 94 | }; 95 | } 96 | 97 | action route(p: packet, sw0: node, sw1: node, sw2: node) = { 98 | require pending(p, sw0, sw1); 99 | require route_dom(dst(p), sw1); 100 | require route_tc(dst(p), sw1, sw2) & sw1 ~= sw2 & ((route_tc(dst(p), sw1, Z) & sw1 ~= Z) -> route_tc(dst(p), sw2, Z)); 101 | if (~route_dom(src(p), sw1) & src(p) ~= sw1) { 102 | # dom(x) := true; 103 | # tc(X, Y) := tc(X, Y) | (tc(X, x) & tc(y, Y)) 104 | route_dom(src(p), sw1) := true; 105 | route_tc(src(p), X, Y) := route_tc(src(p), X, Y) | (route_tc(src(p), X, sw1) & route_tc(src(p), sw0, Y)); 106 | }; 107 | if dst(p) ~= sw1 { 108 | pending(p, sw1, sw2) := true; 109 | } 110 | } 111 | 112 | #action receive = { 113 | # local p:packet, sw0:node, sw1:node, sw2:node { 114 | # receive a pending packet from sw0 to sw1 and process it 115 | 116 | ######################################## 117 | # The action's guard. 118 | # assume pending(p, sw0, sw1); 119 | 120 | ######################################## 121 | # Abstract the number of times that the same packet recieved 122 | # pending(p, sw0, sw1) := *; 123 | 124 | ######################################## 125 | # learn: if no route from receiving switch back to source... 126 | # if (~route(src(p)).dom(sw1) & src(p) ~= sw1) { 127 | # call route(src(p)).set(sw1, sw0) # create new route from sw1 to sw0 128 | # }; 129 | 130 | ######################################## 131 | # forward the packet if destination is not self 132 | # if dst(p) ~= sw1 { 133 | # if ~route(dst(p)).dom(sw1) { # if no route from sw1 to to dst(p)... 134 | # pending(p, sw1, Y) := link(sw1, Y) & Y ~= sw0 # flood 135 | # } else { 136 | # sw2 := route(dst(p)).get(sw1); # get the routing table entry 137 | # pending(p, sw1, sw2) := true # route the packet there 138 | # } 139 | # } 140 | # } 141 | #} 142 | 143 | export new_packet 144 | export flood 145 | export route 146 | 147 | # The safety property is given by the invariants of the 148 | # acyclic_partial_function module, that state that the routing tables 149 | # do not create cycles. 150 | 151 | invariant [1000000] route_tc(N, X, X) & (route_tc(N, X, Y) & route_tc(N, Y, Z) -> route_tc(N, X, Z)) & (route_tc(N, X, Y) & route_tc(N, Y, X) -> X = Y) & (route_tc(N, X, Y) & route_tc(N, X, Z) -> (route_tc(N, Y, Z) | route_tc(N, Z, Y))) 152 | 153 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | # export PYTHONPATH=ivy/ivy/:$PYTHONPATH 2 | export LD_LIBRARY_PATH=/usr/local/lib: 3 | export PYTHONPATH=/usr/local/lib/python2.7/site-packages:$PYTHONPATH 4 | 5 | cp translate.py ivy/ivy 6 | 7 | echo 'lock server' 8 | pushd . 9 | cd ivy/ivy 10 | python translate.py ../../lock_server/lock_server.ivy client=2 server=1 > ../../tmp.vmt 11 | popd 12 | pushd . 13 | cd avr 14 | python avr.py --vmt ../tmp.vmt -e 4 15 | popd 16 | python remove.py avr/output/work_test/inv.txt > inv.txt 17 | time ./main lock_server/lock_server inv.txt lock_server/config_lock_server.txt 18 | echo 'lock server done!' 19 | echo '' 20 | 21 | echo 'leader election' 22 | pushd . 23 | cd ivy/ivy 24 | python translate.py ../../leader/leader.ivy node=3 id=3 > ../../tmp.vmt 25 | popd 26 | pushd . 27 | cd avr 28 | python avr.py --vmt ../tmp.vmt -e 4 29 | popd 30 | python remove.py avr/output/work_test/inv.txt > inv.txt 31 | time ./main leader/leader inv.txt leader/config_leader.txt "idn(N0) = ID0 & idn(N1) = ID1 & idn(N2) = ID2 & " 32 | echo 'leader election done!' 33 | echo '' 34 | 35 | echo 'distributed lock' 36 | pushd . 37 | cd ivy/ivy 38 | python translate.py ../../distributed_lock/distributed_lock.ivy node=2 epoch=4 > ../../tmp.vmt 39 | popd 40 | pushd . 41 | cd avr 42 | python avr.py --vmt ../tmp.vmt -e 4 43 | popd 44 | python remove.py avr/output/work_test/inv.txt > inv.txt 45 | time ./main distributed_lock/distributed_lock inv.txt distributed_lock/config_distributed_lock.txt 46 | echo 'distributed lock done!' 47 | echo '' 48 | 49 | echo 'chord ring' 50 | pushd . 51 | cd ivy/ivy 52 | python translate.py ../../chord/chord.ivy node=4 > ../../tmp.vmt 53 | popd 54 | pushd . 55 | cd avr 56 | python avr.py --vmt ../tmp.vmt -e 4 57 | popd 58 | python remove.py avr/output/work_test/inv.txt > inv.txt 59 | time ./main chord/chord inv.txt chord/config_chord.txt 60 | echo 'chord ring done!' 61 | echo '' 62 | 63 | echo 'learning switch' 64 | pushd . 65 | cd ivy/ivy 66 | python translate.py ../../switch/switch.ivy node=3 packet=1 > ../../tmp.vmt 67 | popd 68 | pushd . 69 | cd avr 70 | python avr.py --vmt ../tmp.vmt -e 4 71 | popd 72 | python remove.py avr/output/work_test/inv.txt > inv.txt 73 | time ./main switch/switch inv.txt switch/config_switch.txt 74 | echo 'learning switch done!' 75 | echo '' 76 | 77 | echo 'database chain replication' 78 | pushd . 79 | cd ivy/ivy 80 | python translate.py ../../chain/chain.ivy transaction=3 operation=3 key=1 node=2 > ../../tmp.vmt 81 | popd 82 | pushd . 83 | cd avr 84 | python avr.py --vmt ../tmp.vmt -e 4 85 | popd 86 | python remove.py avr/output/work_test/inv.txt > inv.txt 87 | time ./main chain/chain inv.txt chain/config_chain.txt 88 | echo 'database chain replication done!' 89 | echo '' 90 | 91 | echo 'two phase commit' 92 | pushd . 93 | cd ivy/ivy 94 | python translate.py ../../2PC/2PC.ivy node=6 > ../../tmp.vmt 95 | popd 96 | pushd . 97 | cd avr 98 | python avr.py --vmt ../tmp.vmt -e 4 99 | popd 100 | python remove.py avr/output/work_test/inv.txt > inv.txt 101 | time ./main 2PC/2PC inv.txt 2PC/config_2PC.txt 102 | echo 'two phase commit done!' 103 | echo '' 104 | -------------------------------------------------------------------------------- /translate.py: -------------------------------------------------------------------------------- 1 | # Haojun Ma(mahaojun@umich.edu) 2 | 3 | import ivy_init 4 | #import ivy_interp as itp 5 | import ivy_actions as act 6 | import ivy_utils as utl 7 | #import ivy_logic_utils as lut 8 | #import ivy_logic as lg 9 | import ivy_utils as iu 10 | import ivy_module as im 11 | #import ivy_alpha 12 | #import ivy_art 13 | #import ivy_interp 14 | #import ivy_compiler 15 | #import ivy_isolate 16 | import ivy_ast 17 | #import ivy_theory as ith 18 | #import ivy_transrel as itr 19 | #import ivy_solver as islv 20 | #import ivy_fragment as ifc 21 | from ivy_compiler import read_module 22 | import sys 23 | import math 24 | 25 | def usage(): 26 | print "usage: \n {} file.ivy".format(sys.argv[0]) 27 | sys.exit(1) 28 | 29 | def f_ConstantSort(x): 30 | assert isinstance(x, ivy_ast.ConstantSort) 31 | return ' is just a sort' 32 | 33 | def f_Variable(x): 34 | assert isinstance(x, ivy_ast.Variable) 35 | assert x.args == [] 36 | return x.rep + ':' + x.sort 37 | 38 | def f_Atom(x): 39 | assert isinstance(x, ivy_ast.Atom) 40 | ret = x.rep 41 | if x.args: 42 | ret += '(' + ', '.join([astdict[type(i)](i) for i in x.args]) + ')' 43 | return ret 44 | 45 | def inst_Assign(x, modefies): 46 | assert isinstance(x, act.AssignAction) 47 | assert len(x.args) == 2 48 | assert isinstance(x.args[0], ivy_ast.App) 49 | ret = [] 50 | name = x.args[0].rep 51 | # val = astdict[type(x.args[1])](x.args[1], dict()) 52 | modefies.add(name) 53 | instlist = [(name, ['(= bv_true bv_true)'], dict())] 54 | args = map(lambda x: astdict[type(x)](x, dict()), x.args[0].args) 55 | if name in constants: 56 | for c, a in zip(constants[name], args): 57 | newlist = [] 58 | for i in range(instance[c]): 59 | for l in instlist: 60 | newdic = dict(l[2]) 61 | if a.isupper(): 62 | newdic[a] = (c, i) 63 | newlist.append(('%s_%d' % (l[0], i), l[1], newdic)) 64 | else: 65 | newlist.append(('%s_%d' % (l[0], i), l[1] + ['(= %s %s%d)' % (a, c, i)], newdic)) 66 | instlist = newlist 67 | 68 | for inst in instlist: 69 | ret.append('(update_%s %s_next %s (and %s) %s)' % (name, inst[0], inst[0], ' '.join(inst[1]), astdict[type(x.args[1])](x.args[1], inst[2]))) 70 | else: 71 | ret.append('(= %s_next %s)' % (name, astdict[type(x.args[1])](x.args[1], dict()))) 72 | return ret 73 | 74 | def inst_copy(name): 75 | assert name in constants 76 | instlist = [name] 77 | for c in constants[name]: 78 | newlist = [] 79 | for i in range(instance[c]): 80 | newlist += map(lambda st: '%s_%d' % (st, i), instlist) 81 | instlist = newlist 82 | return map(lambda st: '(= %s %s_next)' % (st, st), instlist) 83 | 84 | def f_AssignAction(x, modefies): 85 | ret = inst_Assign(x, modefies) 86 | return '(and %s)' % ' '.join(ret) 87 | 88 | def f_RequiresAction(x, modefies): 89 | assert isinstance(x, act.RequiresAction) 90 | assert len(x.args) == 1 91 | # print 'assert', type(x.args[0]) 92 | # f_Atom(x.args[0]) 93 | return instantiate(x.args[0]) 94 | 95 | def f_Implies(x): 96 | assert isinstance(x, ivy_ast.Implies) 97 | assert len(x.args) == 2 98 | return astdict[type(x.args[0])](x.args[0]) + ' -> ' + astdict[type(x.args[1])](x.args[1]) 99 | 100 | def f_LabeledFormula(x): 101 | assert isinstance(x, ivy_ast.LabeledFormula) 102 | assert len(x.args) == 2 103 | # print type(x.formula) 104 | return '[' + x.name + '] ' + astdict[type(x.formula)](x.formula) 105 | 106 | def f_Sequence(x, modefies): 107 | assert isinstance(x, act.Sequence) 108 | return '(and ' + ' '.join([actiondict[type(i)](i, modefies) for i in x.args]) + ')' 109 | 110 | def declare_paras(prefix, paras): 111 | for para in paras: 112 | para.rep = para.rep.replace(':', '_') 113 | return '\n'.join(map(lambda para: '(declare-fun %s_%s () %s_type)' % (prefix, para.rep, para.sort), paras)) 114 | 115 | def f_ActionDef(x): 116 | assert isinstance(x, ivy_ast.ActionDef) 117 | assert len(x.args) == 2 118 | # print len(x.args), type(x.args[0]), type(x.args[1]) 119 | # print len(x.args[1].args) 120 | # print type(x.args[0]), type(x.formal_params), type(x.formal_returns) 121 | # for param in x.formal_params: 122 | # print type(param) 123 | # if x.formal_params: 124 | # print type(x.formal_params[0]) 125 | modefies[x.args[0].rep] = set() 126 | para = ' '.join(map(lambda para: "(%s %s_type)" % (para.rep, para.sort), x.formal_params)) 127 | lemma = ' '.join(map(lambda para: "(is_%s %s)" % (para.sort, para.rep), x.formal_params)) 128 | return "\n(define-fun %s_fun (%s) Bool (and %s %s))" % (x.args[0].rep, para, lemma, actiondict[type(x.args[1])](x.args[1], modefies[x.args[0].rep])) 129 | 130 | def f_IfAction(x, modefies): 131 | assert isinstance(x, act.IfAction) 132 | cond = instantiate(x.args[0]) 133 | thens = x.args[1].args 134 | ret = [] 135 | if len(x.args) > 3: 136 | elses = x.args[2].args 137 | else: 138 | elses = [] 139 | for c1 in thens: 140 | assert isinstance(c1, act.AssignAction) 141 | name = c1.args[0].rep 142 | th = inst_Assign(c1, modefies) 143 | el = inst_copy(name) 144 | for c2 in elses: 145 | if c2.args[0].rep == name: 146 | el = inst_Assign(c2, modefies) 147 | break 148 | ret.append('(and %s)' % (' '.join(map(lambda x: '(ite %s %s %s)' % (cond, x[0], x[1]), zip(th, el))))) 149 | for c2 in elses: 150 | assert isinstance(c1, act.AssignAction) 151 | name = c2.args[0].rep 152 | flag = True 153 | el = inst_Assign(c2, modefies) 154 | for c1 in thens: 155 | if c1.args[0].rep == name: 156 | flag = False 157 | break 158 | if flag: 159 | ret.append('(and %s)' % (' '.join(map(lambda x: '(ite %s %s %s)' % (cond, x[0], x[1]), zip(inst_copy(name), el))))) 160 | return '(and %s)' % ' '.join(ret) 161 | 162 | def f_ActionDecl(x): 163 | assert isinstance(x, ivy_ast.ActionDecl) 164 | assert len(x.args) == 1 165 | assert x.attributes == () 166 | return f_ActionDef(x.args[0]).replace(':', '_') 167 | 168 | def f_MixinDecl(x): 169 | assert isinstance(x, ivy_ast.MixinDecl) 170 | return '''I don't know what's MixinDecl''' 171 | 172 | def f_TypeDef(x): 173 | assert isinstance(x, ivy_ast.TypeDef) 174 | assert len(x.args) == 2 175 | return f_Atom(x.args[0]) 176 | 177 | def f_TypeDecl(x): 178 | assert isinstance(x, ivy_ast.TypeDecl) 179 | assert x.attributes == () 180 | assert len(x.args) == 1 181 | return f_TypeDef(x.args[0]) 182 | 183 | def f_ConstantDecl(x): 184 | assert isinstance(x, ivy_ast.ConstantDecl) 185 | assert len(x.args) == 1 186 | assert x.attributes == () 187 | return 'individual ' + f_Atom(x.args[0]) 188 | 189 | def f_ExportDef(x): 190 | #not dealing with scope 191 | assert isinstance(x, ivy_ast.ExportDef) 192 | assert len(x.args) == 2 193 | return f_Atom(x.args[0]) 194 | 195 | def f_ExportDecl(x): 196 | assert isinstance(x, ivy_ast.ExportDecl) 197 | assert len(x.args) == 1 198 | assert x.attributes == () 199 | return 'export ' + f_ExportDef(x.args[0]) 200 | 201 | def f_ConjectureDecl(x): 202 | assert isinstance(x, ivy_ast.ConjectureDecl) 203 | assert x.attributes == () 204 | assert len(x.args) == 1 205 | return 'assert ' + f_LabeledFormula(x.args[0]) 206 | 207 | #astdict[ivy_ast.App] = f_App 208 | #astdict[ivy_ast.Atom] = f_Atom 209 | #astdict[ivy_ast.Variable] = f_Variable 210 | #astdict[ivy_ast.MixinDecl] = f_MixinDecl 211 | #astdict[ivy_ast.TypeDecl] = f_TypeDecl 212 | #astdict[ivy_ast.ConstantDecl] = f_ConstantDecl 213 | #astdict[ivy_ast.ExportDecl] = f_ExportDecl 214 | #astdict[ivy_ast.ConjectureDecl] = f_ConjectureDecl 215 | #astdict[ivy_ast.Forall] = f_Forall 216 | #astdict[ivy_ast.Implies] = f_Implies 217 | 218 | actiondict = dict() 219 | actiondict[act.AssignAction] = f_AssignAction 220 | actiondict[act.RequiresAction] = f_RequiresAction 221 | actiondict[act.IfAction] = f_IfAction 222 | actiondict[act.Sequence] = f_Sequence 223 | 224 | constants = dict() 225 | modefies = dict() 226 | #def argsmap(args): 227 | # ret = '' 228 | # print type(args[0]) 229 | # for item in map(lambda x: astdict[type(x)](x), args): 230 | # ret = reduce(lambda x, y: x + y, map(lambda st: [st + ' (= ' + it + ' bv_true)' for it in item], ret)) 231 | # return ret 232 | 233 | def make_type(x, paratype): 234 | assert isinstance(x, ivy_ast.Atom) 235 | if hasattr(x,'sort'): 236 | ret = x.sort + '_type' 237 | else: 238 | ret = 'bool_type' 239 | names = [x.rep] 240 | for para in x.args: 241 | newnames = [] 242 | for i in range(instance[para.sort]): 243 | newnames += map(lambda st: '%s_%d' % (st, i), names) 244 | names = newnames 245 | paratype.append(para.sort) 246 | for name in names: 247 | print '''(declare-fun %s () %s)\n(declare-fun %s_next () %s)\n(define-fun .%s () %s (! %s :next %s_next))''' % (name, ret, name, ret, name, ret, name, name) 248 | if ret != 'bool_type': 249 | lemmas.append('(is_%s %s)' % (x.sort, name)) 250 | print '''(define-fun update_%s ((newv %s) (prev %s) (cond Bool) (val %s)) Bool (= newv (ite cond val prev)))''' % (x.rep, ret, ret, ret) 251 | # print '''(define-fun copy_%s ((newv %s) (prev %s)) Bool (= prev newv))''' % (x.rep, ret, ret) 252 | 253 | def type_infer(x): 254 | foralldict = dict() 255 | existdict = dict() 256 | if isinstance(x, ivy_ast.Atom) or isinstance(x, ivy_ast.App): 257 | if x.rep == '=': 258 | for arg in x.args: 259 | retdict1, retdict2 = type_infer(arg) 260 | foralldict.update(retdict1) 261 | existdict.update(retdict2) 262 | return foralldict, existdict 263 | name = x.rep 264 | if name not in constants: 265 | return foralldict, existdict 266 | for i in range(len(constants[name])): 267 | if isinstance(x.args[i], ivy_ast.Variable) or isinstance(x.args[i], ivy_ast.App): 268 | if x.args[i].rep[0].isupper(): 269 | if x.args[i].rep not in foralldict and x.args[i].rep not in existdict: 270 | foralldict[x.args[i].rep] = constants[name][i] 271 | x.args[i].sort = constants[name][i] 272 | else: 273 | print type(x.args[i]), 'is not finished' 274 | else: 275 | for arg in x.args: 276 | retdict1, retdict2 = type_infer(arg) 277 | foralldict.update(retdict1) 278 | existdict.update(retdict2) 279 | if isinstance(x, ivy_ast.Exists): 280 | for var in x.bounds: 281 | if var.rep in foralldict: 282 | existdict[var.rep] = foralldict[var.rep] 283 | del foralldict[var.rep] 284 | return foralldict, existdict 285 | 286 | def instantiate_And(x, dic): 287 | assert isinstance(x, ivy_ast.And) 288 | # print 'and', type(x.args), x.args, dir(x.args) 289 | if len(x.args) == 0: 290 | return 'bv_true' 291 | else: 292 | return '(ite (and ' + ' '.join(map(lambda arg: '(= %s bv_true)' % astdict[type(arg)](arg, dic), x.args)) + ') bv_true bv_false)' 293 | 294 | def instantiate_Or(x, dic): 295 | assert isinstance(x, ivy_ast.Or) 296 | # print 'or', type(x.args), x.args, dir(x.args) 297 | if len(x.args) == 0: 298 | return 'bv_false' 299 | else: 300 | return '(ite (or ' + ' '.join(map(lambda arg: '(= %s bv_true)' % astdict[type(arg)](arg, dic), x.args)) + ') bv_true bv_false)' 301 | 302 | def instantiate_Not(x, dic): 303 | assert isinstance(x, ivy_ast.Not) 304 | return '(ite (= %s bv_true) bv_false bv_true)' % astdict[type(x.args[0])](x.args[0], dic) 305 | 306 | def instantiate_Variable(x, dic): 307 | assert isinstance(x, ivy_ast.Variable) 308 | if x.rep in dic: 309 | return '%s%d' % (dic[x.rep][0], dic[x.rep][1]) 310 | else: 311 | return x.rep 312 | 313 | def instantiate_Atom(x, dic): 314 | assert isinstance(x, ivy_ast.Atom) 315 | name = x.rep 316 | if name == '=': 317 | # print "I don't know why they use Atom for euqal" 318 | return '(ite (= ' + ' '.join(map(lambda arg: astdict[type(arg)](arg, dic), x.args)) + ') bv_true bv_false)' 319 | # if name == 'le': 320 | # return '(ite (bvule %s %s) bv_true bv_false)' % (astdict[type(x.args[0])](x.args[0], dic), astdict[type(x.args[1])](x.args[1], dic)) 321 | # return '(ite (<= %s %s) bv_true bv_false)' % (astdict[type(x.args[0])](x.args[0], dic), astdict[type(x.args[1])](x.args[1], dic)) 322 | if name not in constants: 323 | return name 324 | args = [[]] 325 | for i in range(len(constants[name])): 326 | if x.args[i].rep in dic: 327 | args = map(lambda a: a + [(None, dic[x.args[i].rep][1])], args) 328 | else: 329 | newargs = [] 330 | st = astdict[type(x.args[i])](x.args[i], dic) 331 | for j in range(instance[constants[name][i]]): 332 | newargs += map(lambda x: x + [(st, j)], args) 333 | args = newargs 334 | ret = '' 335 | for arg in args: 336 | st = x.rep 337 | cond = [] 338 | for i in range(len(constants[name])): 339 | st = '%s_%d' % (st, arg[i][1]) 340 | if arg[i][0]: 341 | cond.append('(= %s %s%d)' % (arg[i][0], constants[name][i], arg[i][1])) 342 | if cond: 343 | if arg != args[-1]: 344 | ret = '%s(ite (and %s) %s ' % (ret, ' '.join(cond), st) 345 | else: 346 | ret = '%s%s' % (ret, st) + ')' * (len(args) - 1) 347 | else: 348 | ret = st 349 | return ret 350 | 351 | def instantiate_App(x, dic): 352 | assert isinstance(x, ivy_ast.App) 353 | name = x.rep 354 | ret = name 355 | if name == '=': 356 | print "I don't know why they use App for euqal" 357 | if name not in constants: 358 | return name 359 | args = [[]] 360 | for i in range(len(constants[name])): 361 | if x.args[i].rep in dic: 362 | args = map(lambda a: a + [(None, dic[x.args[i].rep][1])], args) 363 | else: 364 | newargs = [] 365 | st = astdict[type(x.args[i])](x.args[i], dic) 366 | for j in range(instance[constants[name][i]]): 367 | newargs += map(lambda x: x + [(st, j)], args) 368 | args = newargs 369 | ret = '' 370 | for arg in args: 371 | st = x.rep 372 | cond = [] 373 | for i in range(len(constants[name])): 374 | st = '%s_%d' % (st, arg[i][1]) 375 | if arg[i][0]: 376 | cond.append('(= %s %s%d)' % (arg[i][0], constants[name][i], arg[i][1])) 377 | if cond: 378 | if arg != args[-1]: 379 | ret = '%s(ite (and %s) %s ' % (ret, ' '.join(cond), st) 380 | else: 381 | ret = '%s%s' % (ret, st) + ')' * (len(args) - 1) 382 | else: 383 | ret = st 384 | return ret 385 | 386 | def instantiate_Assign(x, dic): 387 | assert isinstance(x, act.AssignAction) 388 | return '(ite (= %s %s) bv_true bv_false)' % (instantiate_App(x.args[0], dic), astdict[type(x.args[1])](x.args[1], dic)) 389 | 390 | def same_assign(x, y, st): 391 | assert isinstance(x, act.AssignAction) 392 | assert isinstance(y, act.AssignAction) 393 | return st != '' and x.args[0].rep == y.args[0].rep 394 | 395 | def instantiate_Implies(x, dic): 396 | assert isinstance(x, ivy_ast.Implies) 397 | return '(ite (=> (= %s bv_true) (= %s bv_true)) bv_true bv_false)' % (astdict[type(x.args[0])](x.args[0], dic), astdict[type(x.args[1])](x.args[1], dic)) 398 | 399 | def instantiate_Forall(x, dic): 400 | assert isinstance(x, ivy_ast.Forall) 401 | return astdict[type(x.args[0])](x.args[0], dic) 402 | 403 | def instantiate_Exists(x, dic): 404 | assert isinstance(x, ivy_ast.Exists) 405 | return astdict[type(x.args[0])](x.args[0], dic) 406 | 407 | class conditionalexp(ivy_ast.Formula): 408 | def __repr__(self): 409 | return repr(self.args[0]) + '?' + repr(self.args[1]) + ':' + repr(self.args[2]) 410 | 411 | def instantiate_conditionalexp(x, dic): 412 | assert isinstance(x, conditionalexp) 413 | return '(ite (= %s bv_true) (ite (= %s %s) bv_true bv_false) (ite (= %s %s) bv_true bv_false))' % (astdict[type(x.args[0])](x.args[0], dic), astdict[type(x.args[1])](x.args[1], dic), astdict[type(x.args[2])](x.args[2], dic), astdict[type(x.args[1])](x.args[1], dic), astdict[type(x.args[3])](x.args[3], dic)) 414 | 415 | def instantiate_Ite(x, dic): 416 | assert isinstance(x, ivy_ast.Ite) 417 | return '(ite (= %s bv_true) %s %s)' % (astdict[type(x.args[0])](x.args[0], dic), astdict[type(x.args[1])](x.args[1], dic), astdict[type(x.args[2])](x.args[2], dic)) 418 | 419 | astdict = dict() 420 | #astdict[ivy_ast.ActionDecl] = f_ActionDecl 421 | astdict[ivy_ast.And] = instantiate_And 422 | astdict[ivy_ast.Or] = instantiate_Or 423 | astdict[ivy_ast.Not] = instantiate_Not 424 | astdict[ivy_ast.Variable] = instantiate_Variable 425 | astdict[ivy_ast.App] = instantiate_App 426 | astdict[ivy_ast.Atom] = instantiate_Atom 427 | astdict[ivy_ast.Implies] = instantiate_Implies 428 | astdict[ivy_ast.Exists] = instantiate_Exists 429 | astdict[ivy_ast.Forall] = instantiate_Forall 430 | astdict[ivy_ast.Ite] = instantiate_Ite 431 | astdict[act.AssignAction] = instantiate_Assign 432 | astdict[conditionalexp] = instantiate_conditionalexp 433 | 434 | def instantiate(x): 435 | foralldict, existdict = type_infer(x) 436 | foralllist = [dict()] 437 | existlist = [dict()] 438 | for var, typ in foralldict.iteritems(): 439 | newlist = [] 440 | for d in foralllist: 441 | for i in range(instance[typ]): 442 | dd = dict(d) 443 | dd[var] = (typ, i) 444 | newlist.append(dd) 445 | foralllist = newlist 446 | for var, typ in existdict.iteritems(): 447 | newlist = [] 448 | for d in existlist: 449 | for i in range(instance[typ]): 450 | dd = dict(d) 451 | dd[var] = (typ, i) 452 | newlist.append(dd) 453 | existlist = newlist 454 | # print len(dictlist) 455 | ret = [] 456 | for d1 in foralllist: 457 | st = '(or' 458 | for d2 in existlist: 459 | dd = dict(d1) 460 | dd.update(d2) 461 | st += ' (= %s bv_true)' % (astdict[type(x)](x, dd)) 462 | ret.append(st + ')') 463 | # print ret 464 | return '(and ' + ' '.join(ret) + ')' 465 | 466 | 467 | def change(x, y): 468 | x = conditionalexp(ivy_ast.Atom('=', x.args[0].args[0], y.args[0].args[0]), x.args[0], y.args[1], x.args[1]) 469 | return instantiate(x) 470 | 471 | def generate_trans(actions): 472 | act = '' 473 | fun = '' 474 | for action in actions: 475 | name = action.args[0].rep 476 | if len(action.formal_params) > 0: 477 | fun += '(=> (= action %s) (and (%s_fun %s)' % (name, name, ' '.join(map(lambda para: '%s_%s' % (name, para.rep), action.formal_params))) 478 | else: 479 | fun += '(=> (= action %s) (and %s_fun' % (name, name) 480 | 481 | for cons in constants: 482 | if cons not in modefies[name]: 483 | fun += ' ' + ' '.join(inst_copy(cons)) 484 | fun += ')) ' 485 | 486 | fun += '(=> (not (or %s)) (and %s))' % (' '.join(map(lambda action: '(= action %s)' % (action.args[0].rep), actions)), ' '.join(map(lambda const: ' '.join(inst_copy(const)), constants.keys()))) 487 | return '(define-fun .trans () Bool (! (and %s %s %s) :trans true))\n' % (act, fun, ' '.join(lemmas)) 488 | 489 | typelength = set([0, 1]) 490 | 491 | def translate(decls): 492 | print ''' 493 | (set-info :source |Haojun Ma (mahaojun@umich.edu)|) 494 | 495 | ; Typecast bit to bool 496 | (define-sort bool_type () (_ BitVec 1)) 497 | (define-fun bv_false () bool_type (_ bv0 1)) 498 | (define-fun bv_true () bool_type (_ bv1 1)) 499 | (define-fun is_bool ((x bool_type)) Bool (or (= x bv_true) (= x bv_false))) 500 | ''' 501 | 502 | print '''; Define and enumerate transition system parameters''' 503 | for decl in decls.decls: 504 | if type(decl) == ivy_ast.TypeDecl: 505 | name = f_TypeDecl(decl) 506 | # if name == 'epoch' or name == 'round': 507 | # print '''(define-sort %s_type () Int)''' % (name) 508 | # for i in range(instance[name]): 509 | # print '''(define-fun %s%d () %s_type %d)''' % (name, i, name, i) 510 | # print '''(declare-fun %s%d_next () %s_type)''' % (name, i, name) 511 | # print '''(define-fun .%s%d () %s_type (! %s%d :next %s%d_next))''' % (name, i, name, name, i, name, i) 512 | # else: 513 | if True: 514 | l = math.ceil(math.log(instance[name], 2)) 515 | while l in typelength: 516 | l += 1 517 | typelength.add(l) 518 | print '''(define-sort %s_type () (_ BitVec %d))''' % (name, l) 519 | for i in range(instance[name]): 520 | print '''(define-fun %s%d () %s_type (_ bv%d %d))''' % (name, i, name, i, l) 521 | # print '''(declare-fun %s%d () %s_type)''' % (name, i, name) 522 | # print '''(declare-fun %s%d_next () %s_type)''' % (name, i, name) 523 | # print '''(define-fun .%s%d () %s_type (! %s%d :next %s%d_next))''' % (name, i, name, name, i, name, i) 524 | print '''(define-fun is_%s ((%s %s_type)) Bool (or %s))''' % (name, name, name, ' '.join(map(lambda i: '(= %s %s%d)' % (name, name, i), range(instance[name])))) 525 | # distinct = '' 526 | # for i in range(instance[name]): 527 | # for j in range(i): 528 | # distinct += ' (= %s%d %s%d)' % (name, j, name, i) 529 | # print '''(define-fun lemma_%s () Bool (and %s (not (or%s))))''' % (name, ' '.join(map(lambda i: '(= %s%d %s%d_next)' % (name, i, name, i), range(instance[name]))), distinct) 530 | # lemmas.append('lemma_%s' % name) 531 | 532 | print '''\n; Declare transition system states''' 533 | for decl in decls.decls: 534 | if type(decl) == ivy_ast.ConstantDecl: 535 | if isinstance(decl.args[0], ivy_ast.Atom): 536 | name = decl.args[0].rep 537 | constants[name] = [] 538 | make_type(decl.args[0], constants[name]) 539 | else: 540 | cons = decl.args[0] 541 | print '''(declare-fun %s () %s_type)''' % (cons.rep, cons.sort) 542 | print '''(declare-fun %s_next () %s_type)''' % (cons.rep, cons.sort) 543 | print '''(define-fun .%s () %s_type (! %s :next %s_next))''' % (cons.rep, cons.sort, cons.rep, cons.rep) 544 | lemmas.append('(is_%s %s)' % (cons.sort, cons.rep)) 545 | lemmas.append('(= %s_next %s)' % (cons.rep, cons.rep)) 546 | if 'transaction' not in instance: 547 | if cons.rep == 'zero' or cons.rep == 'org': 548 | lemmas.append('(= %s %s%d)' % (cons.rep, cons.sort, 0)) 549 | # if cons.rep == 'e': 550 | # pass 551 | # lemmas.append('(= %s %s%d)' % (cons.rep, cons.sort, 1)) 552 | # elif cons.rep == 'maxint': 553 | # pass 554 | # lemmas.append('(= %s %s%d)' % (cons.rep, cons.sort, instance[cons.sort] - 1)) 555 | # elif cons.rep == 'other': 556 | # pass 557 | # else: 558 | # lemmas.append('(= %s %s%d)' % (cons.rep, cons.sort, 0)) 559 | elif type(decl) == ivy_ast.AxiomDecl: 560 | print '''(define-fun axiom_%s () Bool %s)''' % (decl.args[0].name, instantiate(decl.args[0].formula)) 561 | lemmas.append('axiom_%s' % decl.args[0].name) 562 | 563 | for decl in decls.decls: 564 | if type(decl) == ivy_ast.ActionDecl: 565 | if f_Atom(decl.args[0].args[0]).startswith('init'): 566 | print '''\n; Initial state''' 567 | inits = [] 568 | for i, arg in enumerate(decl.args[0].args[1].args): 569 | inits.append(instantiate(arg)) 570 | for j in range(i): 571 | if same_assign(arg, decl.args[0].args[1].args[j], inits[j]): 572 | inits[j] = change(decl.args[0].args[1].args[j], arg) 573 | inits[i] = '' 574 | print '''(define-fun .init () Bool (! (and %s) :init true))''' % (' '.join(inits)) 575 | else: 576 | print f_ActionDecl(decl) 577 | print 578 | 579 | if 'epoch' in instance: 580 | pass 581 | # for i in range(instance['epoch']): 582 | # for j in range(instance['epoch']): 583 | # lemmas.append('(= le_%d_%d bv_%s)' % (i, j, 'true' if i <= j else 'false')) 584 | elif 'round' in instance: 585 | for i in range(instance['round']): 586 | for j in range(instance['round']): 587 | lemmas.append('(= le_%d_%d bv_%s)' % (i, j, 'true' if i <= j else 'false')) 588 | # for i in range(instance['acceptor']): 589 | # for j in range(instance['quorum']): 590 | # lemmas.append('(= member_%d_%d bv_%s)' % (i, j, 'true' if i != j else 'false')) 591 | elif 'term' in instance: 592 | for i in range(instance['term']): 593 | for j in range(instance['term']): 594 | lemmas.append('(= le_%d_%d bv_%s)' % (i, j, 'true' if i <= j else 'false')) 595 | for i in range(instance['node']): 596 | for j in range(instance['quorum']): 597 | lemmas.append('(= member_%d_%d bv_%s)' % (i, j, 'true' if i != j else 'false')) 598 | elif 'id' in instance: 599 | for i in range(instance['node']): 600 | lemmas.append('(= idn_%d id%d)' % (i, i)) 601 | 602 | 603 | actions = [] 604 | for decl in decls.decls: 605 | if type(decl) == ivy_ast.ExportDecl: 606 | for d in decls.decls: 607 | if type(d) == ivy_ast.ActionDecl and d.args[0].args[0].rep == decl.args[0].args[0].rep: 608 | actions.append(d.args[0]) 609 | l = math.ceil(math.log(len(actions) + 1, 2)) 610 | while l in typelength: 611 | l += 1 612 | print '''; Declare actions''' 613 | print '''(define-sort action_type () (_ BitVec %d))''' % l 614 | print '\n'.join(map(lambda i: '(define-fun %s() action_type (_ bv%d %d))' % (actions[i].args[0].rep, i, l), range(len(actions)))) 615 | print '''\n; Transition relation''' 616 | print '''(declare-fun action () action_type)''' 617 | for action in actions: 618 | print declare_paras(action.args[0].rep, action.formal_params) 619 | 620 | print generate_trans(actions) 621 | 622 | for decl in decls.decls: 623 | if type(decl) == ivy_ast.ConjectureDecl: 624 | print '''(define-fun .prop () Bool (! (and %s) :invar-property 0))''' % (instantiate(decl.args[0].formula)) 625 | 626 | instance = dict() 627 | lemmas = [] 628 | 629 | def main(): 630 | ivy_init.read_params() 631 | if not sys.argv[1].endswith('ivy'): 632 | usage() 633 | for i in range(2, len(sys.argv)): 634 | st = sys.argv[i].split('=') 635 | instance[st[0]] = eval(st[1]) 636 | 637 | with im.Module(): 638 | with utl.ErrorPrinter(): 639 | with iu.SourceFile(sys.argv[1]): 640 | decls = read_module(ivy_init.open_read(sys.argv[1])) 641 | translate(decls) 642 | 643 | if __name__ == "__main__": 644 | main() 645 | 646 | --------------------------------------------------------------------------------