|
| 1 | +======================================================================== |
| 2 | +Tactic: ``asyncwhile`` Tactic |
| 3 | +======================================================================== |
| 4 | + |
| 5 | +The ``asyncwhile`` tactic applies to probabilistic relational Hoare Logic |
| 6 | +goals where the programs contains a ``while`` loop. |
| 7 | +Unlike the ``while`` tactic, the ``asyncwhile`` tactic allows to reason |
| 8 | +on loop which are not in lockstep. |
| 9 | + |
| 10 | +------------------------------------------------------------------------ |
| 11 | +Syntax |
| 12 | +------------------------------------------------------------------------ |
| 13 | + |
| 14 | +The general form of the tactic is: |
| 15 | + |
| 16 | +.. admonition:: Syntax |
| 17 | + |
| 18 | + ``async while [f1,k1] [f2,k2] (L1) (L2) : (I)`` |
| 19 | + |
| 20 | +Here: |
| 21 | + |
| 22 | +- ``L1`` and ``L2`` are the left and right condition to control if we |
| 23 | + consider the lockstep case, or the oneside case, |
| 24 | +- ``k1`` and ``k2`` are natural number |
| 25 | +- ``f1`` and ``f2`` are the unrolling condition, initial by the parameter |
| 26 | + ``k1`` and ``k2``. |
| 27 | + |
| 28 | +Concretely, the tactic implements the following rulee:: |
| 29 | + |
| 30 | + I => (b1 <=> b2 /\ (!L1 /\ !L2 => f1 k1 /\ f2 k2)) \/ (L1 /\ b1) \/ (L2 /\ b2) |
| 31 | + equiv[while b1 {c1} ~ while {b2} c2: I /\ b1 <=> b2 /\ !L1 /\ !L2 /\ f1 k1 /\ f2 k2 ==> I] |
| 32 | + equiv[while b1 {c1} ~ skip: I /\ b1 /\ L1 /\ ==> I] |
| 33 | + equiv[skip ~ while b2 {c2}: I /\ b2 /\ L2 /\ ==> I] |
| 34 | + (Pre => I) /\ (I /\ !b1 /\ !b2 => Post) |
| 35 | + ------------------------------------------------------------------------------------------- |
| 36 | + equiv[while b1 {c1} ~ while {b2} c2: Pre ==> Post] |
| 37 | + |
| 38 | +The following example shows ``asynctwhile`` on a prhl goal. The program |
| 39 | +increments ``x`` until it reaches ``10``. |
| 40 | + |
| 41 | +.. ecproof:: |
| 42 | + |
| 43 | + require import AllCore. |
| 44 | + |
| 45 | + module M = { |
| 46 | + proc up_to_10(x : int) : int = { |
| 47 | + while (x < 10) { |
| 48 | + x <- x + 1; |
| 49 | + } |
| 50 | + return x; |
| 51 | + } |
| 52 | + proc up_to_10_by_2(x : int) : int = { |
| 53 | + while (x < 10) { |
| 54 | + x <- x + 1; |
| 55 | + if ( x < 10) x <- x + 1; |
| 56 | + } |
| 57 | + return x; |
| 58 | + } |
| 59 | + |
| 60 | + }. |
| 61 | + |
| 62 | + lemma asynctwhile_example : |
| 63 | + equiv[M.up_to_10 ~ M.up_to_10_by_2 : ={x} ==> ={res}]. |
| 64 | + proof. |
| 65 | + proc. |
| 66 | + async while |
| 67 | + [ (fun r => x <= r + 1), (x{1} ) ] |
| 68 | + [ (fun r => x <= r ), (x{2} ) ] |
| 69 | + (!(x{1} < 10)) (!(x{2} < 10)) |
| 70 | + : |
| 71 | + (x{1} = x{2}) => //=. |
| 72 | + + move=> &1 &2. smt. |
| 73 | + + move => v1 v2 //=. |
| 74 | + unroll {1} 1. |
| 75 | + unroll {1} 2. |
| 76 | + unroll {2} 1. |
| 77 | + rcondt {1} 1. auto. |
| 78 | + rcondt {2} 1. auto. |
| 79 | + sp 1 1. |
| 80 | + if. smt. |
| 81 | + sp 1 1. |
| 82 | + while (!(x{1} < 10 /\ (x{1} < 10 /\ (x{1} <= v1 + 1))) /\ |
| 83 | + !(x{2} < 10 /\ (x{2} < 10 /\ (x{2} <= v2 ))) /\ ={x}); auto; smt. |
| 84 | + while (!(x{1} < 10 /\ (x{1} < 10 /\ (x{1} <= v1 + 1))) /\ |
| 85 | + !(x{2} < 10 /\ (x{2} < 10 /\ (x{2} <= v2 ))) /\ ={x}); auto; smt. |
| 86 | + + move => &2. exfalso=> &1 ?. smt. |
| 87 | + + move => &1. exfalso=> &2 ?. smt. |
| 88 | + + exfalso. smt. |
| 89 | + + exfalso. smt. |
| 90 | + qed. |
0 commit comments