|
| 1 | +require import AllCore Array Real RealExp List. |
| 2 | +(*---*) import RField. |
| 3 | +require import Distr DBool Xreal. |
| 4 | +(*---*) import Biased. |
| 5 | +require import StdOrder. |
| 6 | +(*---*) import RealOrder. |
| 7 | + |
| 8 | +lemma mul0z (x : int) : 0 * x = 0. |
| 9 | +proof. by smt(). qed. |
| 10 | + |
| 11 | +lemma neg0: -0 = 0. |
| 12 | +proof. by smt(). qed. |
| 13 | + |
| 14 | +lemma xle_rle: |
| 15 | + forall (x y : real), |
| 16 | + 0%r <= x <= y => x%xr <= y%xr. |
| 17 | +proof. by smt(). qed. |
| 18 | + |
| 19 | +lemma Ep_dbiased (p : real) (f : bool -> xreal) : |
| 20 | + 0%r <= p <= 1%r => Ep (dbiased p) f = p ** f true + (1%r - p) ** f false. |
| 21 | +proof. |
| 22 | +move => ?. |
| 23 | +rewrite (Ep_fin [true; false]) //. |
| 24 | ++ by case. |
| 25 | +by rewrite /BXA.big /predT /= !dbiased1E /= !clamp_id //. |
| 26 | +qed. |
| 27 | + |
| 28 | +(* uniformly sampling a 2-d boolean array of size n x m *) |
| 29 | +module M = { |
| 30 | + proc sample (n : int, m : int, a : bool array) : (bool array) = { |
| 31 | + var i, j : int; |
| 32 | + var b : bool; |
| 33 | + i <- 0; |
| 34 | + while (i < n) { |
| 35 | + j <- 0; |
| 36 | + while (j < m) { |
| 37 | + b <$ dbiased 0.5; |
| 38 | + a.[i * m + j] <- b; |
| 39 | + j <- j + 1; |
| 40 | + } |
| 41 | + i <- i + 1; |
| 42 | + } |
| 43 | + return a; |
| 44 | + } |
| 45 | +}. |
| 46 | + |
| 47 | +op outer_shape_pred (i n m : int) (a a' : bool array) = |
| 48 | + 0 <= i <= n |
| 49 | + /\ 0 <= m |
| 50 | + /\ size a = n * m |
| 51 | + /\ size a = size a'. |
| 52 | + |
| 53 | +op shape_pred (i j n m : int) (a a' : bool array) = |
| 54 | + 0 <= i < n |
| 55 | + /\ 0 <= j <= m |
| 56 | + /\ size a = n * m |
| 57 | + /\ size a = size a'. |
| 58 | + |
| 59 | +op row_eq_upto (i m : int) (a1 a2 : bool array) = |
| 60 | + forall (i' j' : int), |
| 61 | + 0 <= i' < i |
| 62 | + => 0 <= j' < m |
| 63 | + => a1.[i' * m + j'] = a2.[i' * m + j']. |
| 64 | + |
| 65 | +op cell_eq_upto (i j m : int) (a1 a2 : bool array) = |
| 66 | + forall (j' : int), |
| 67 | + 0 <= j' < j |
| 68 | + => a1.[i * m + j'] = a2.[i * m + j']. |
| 69 | + |
| 70 | +lemma row_eq_upto_increase (i m : int) (a1 a2 : bool array): |
| 71 | + 0 <= i |
| 72 | + => (row_eq_upto i m a1 a2 /\ cell_eq_upto i m m a1 a2 |
| 73 | + <=> row_eq_upto (i + 1) m a1 a2). |
| 74 | +proof. |
| 75 | +move => ? @/row_eq_upto @/cell_eq_upto; split. |
| 76 | +- move => ? i' j' *. |
| 77 | + by case: (i' < i) => /#. |
| 78 | +- move => ?; split. |
| 79 | + - move => i' j' ??. |
| 80 | + have ?: 0 <= i' < i + 1 by smt(). |
| 81 | + by smt(). |
| 82 | + - smt(). |
| 83 | +qed. |
| 84 | + |
| 85 | +lemma cell_eq_upto_false (i j' j m : int) (a1 a2 : bool array) : |
| 86 | + 0 <= j' < j |
| 87 | + => a1.[i * m + j'] <> a2.[i * m + j'] |
| 88 | + => cell_eq_upto i j m a1 a2 = false. |
| 89 | +proof. by smt(). qed. |
| 90 | + |
| 91 | +lemma cell_eq_upto_split (i j m : int) (a1 a2 : bool array) : |
| 92 | + 0 <= j < m |
| 93 | + => (cell_eq_upto i (j + 1) m a1 a2 |
| 94 | + <=> (cell_eq_upto i j m a1 a2 |
| 95 | + /\ a1.[i * m + j] = a2.[i * m + j]) |
| 96 | + ). |
| 97 | +proof. |
| 98 | +move => ? @/cell_eq_upto; split. |
| 99 | +- move => ?; split. |
| 100 | + - move => j' ?. |
| 101 | + have ?: 0 <= j' < j + 1 by smt(). |
| 102 | + by smt(). |
| 103 | + - by smt(). |
| 104 | +- move => ? j' ?. |
| 105 | + by case (j' < j) => /#. |
| 106 | +qed. |
| 107 | +
|
| 108 | +lemma row_eq_upto_unrelated_set (i m x : int) (v : bool) (a1 a2 : bool array): |
| 109 | + i * m <= x < size a1 |
| 110 | + => (row_eq_upto i m a1 a2 <=> row_eq_upto i m a1.[x <- v] a2). |
| 111 | +proof. |
| 112 | +move => ?. |
| 113 | +rewrite /row_eq_upto; split. |
| 114 | +- move => ? i' j' ??. |
| 115 | + rewrite get_set 1:/#. |
| 116 | + have -> /=: !(i' * m + j' = x) by smt(). |
| 117 | + by smt(). |
| 118 | +- move => ? i' j' ??. |
| 119 | + by rewrite (_: a1.[i' * m + j'] = a1.[x <- v].[i' * m + j']) 1:get_set /#. |
| 120 | +qed. |
| 121 | +
|
| 122 | +lemma cell_eq_upto_unrelated_set (i j m x : int) (v : bool) (a1 a2 : bool array) : |
| 123 | + 0 <= i /\ 0 <= j < m /\ i * m + j <= x < size a1 |
| 124 | + => (cell_eq_upto i j m a1 a2 <=> cell_eq_upto i j m a1.[x <- v] a2). |
| 125 | +proof. |
| 126 | +move => [#] ?????. |
| 127 | +rewrite /cell_eq_upto; split. |
| 128 | +- move => ? j' ?. |
| 129 | + rewrite get_set 1:/#. |
| 130 | + have -> /=: !(i * m + j' = x) by smt(). |
| 131 | + by smt(). |
| 132 | +- move => ? j' ?. |
| 133 | + by rewrite (_: a1.[i * m + j'] = a1.[x <- v].[i * m + j']) 1:get_set /#. |
| 134 | +qed. |
| 135 | + |
| 136 | +(* The probability of every possible boolean matrix of size n x m is no more than 2 ^ -(n * m) *) |
| 137 | +lemma L: |
| 138 | + forall (a0 : bool array), |
| 139 | + ehoare [M.sample : |
| 140 | + (0 <= arg.`1 |
| 141 | + /\ 0 <= arg.`2 |
| 142 | + /\ size arg.`3 = arg.`1 * arg.`2 |
| 143 | + /\ size arg.`3 = size a0) |
| 144 | + `|` (1%r / (2%r ^ (n * m)))%xr ==> (res = a0)%xr]. |
| 145 | +proof. |
| 146 | +move => a0. |
| 147 | +proc. |
| 148 | +while ((0 <= i <= n |
| 149 | + /\ 0 <= m |
| 150 | + /\ size a = n * m |
| 151 | + /\ size a0 = size a) |
| 152 | + `|` (2%r ^ ((-(n - i) * m)%r))%xr |
| 153 | + * (row_eq_upto i m a a0)%xr). |
| 154 | +(* !cond => inv => pos_f <= inv_f *) |
| 155 | ++ move => &hr. |
| 156 | + rewrite xle_cxr_r => *. (* Bug in EC: the precedent is lost when rewriting xle_cxr_r twice. *) |
| 157 | + rewrite xle_cxr_r => *. |
| 158 | + have ->: n{hr} - i{hr} = 0 by smt(). |
| 159 | + rewrite mul0z neg0 rpow0 mul1m_simpl. |
| 160 | + apply xle_rle; split => * ;1: by smt(). |
| 161 | + exact le_b2r. |
| 162 | +(* {cond /\ inv | inv_f} c {inv | inv_f} *) |
| 163 | ++ wp. |
| 164 | + while (( 0 <= i < n |
| 165 | + /\ 0 <= j <= m |
| 166 | + /\ size a = n * m |
| 167 | + /\ size a = size a0) |
| 168 | + `|` (2%r ^ ((-((n - i) * m - j))%r))%xr |
| 169 | + * (row_eq_upto i m a a0 /\ cell_eq_upto i j m a a0)%xr). |
| 170 | + (* !cond => inv => pos_f <= inv_f *) |
| 171 | + + move => &hr />. |
| 172 | + rewrite xle_cxr_r => *. |
| 173 | + rewrite xle_cxr_l => *. |
| 174 | + + by smt(). |
| 175 | + + rewrite (_: - (n{hr} - (i{hr} + 1)) * m{hr} |
| 176 | + = - ((n{hr} - i{hr}) * m{hr} - j{hr})) //= 1:/#. |
| 177 | + rewrite (_: j{hr} = m{hr}) 1:/#. |
| 178 | + rewrite -row_eq_upto_increase 1:/#. |
| 179 | + rewrite ler_eqVlt; left; reflexivity. |
| 180 | + (* {cond /\ inv | inv_f} c {inv | inv_f} *) |
| 181 | + + wp; skip. |
| 182 | + move => &hr. |
| 183 | + move => />. |
| 184 | + rewrite xle_cxr_r => [#] 5? Hsize *. |
| 185 | + rewrite Ep_dbiased /= 1:/#. |
| 186 | + rewrite (_: ((0 <= i{hr} < n{hr}) <=> true)) 1:/#. |
| 187 | + rewrite (_: ((0 <= j{hr} + 1 <= m{hr}) <=> true)) 1:/#. |
| 188 | + rewrite !size_set. |
| 189 | + rewrite (_: ((size a{hr} = n{hr} * m{hr}) <=> true)) 1:/#. |
| 190 | + rewrite (_: (size a{hr} = size a0) <=> true) /= 1:/#. |
| 191 | + rewrite !to_pos_pos 1,2,3,4,5:#smt:(rpow_gt0 b2r_ge0). |
| 192 | + rewrite !cell_eq_upto_split 1,2:/#. |
| 193 | + rewrite !get_set //=. |
| 194 | + - split; 1: by smt(). |
| 195 | + move => ?. |
| 196 | + by apply (IntOrder.ltr_le_trans ((n{hr} - 1) * m{hr} + m{hr})) => /#. |
| 197 | + - split; 1: by smt(). |
| 198 | + move => ?. |
| 199 | + by apply (IntOrder.ltr_le_trans ((n{hr} - 1) * m{hr} + m{hr})) => /#. |
| 200 | + case (a0.[i{hr} * m{hr} + j{hr}]) => Hcase /=. |
| 201 | + + rewrite -row_eq_upto_unrelated_set. |
| 202 | + - split; 1: by smt(). |
| 203 | + move => ?. |
| 204 | + by apply (IntOrder.ltr_le_trans ((n{hr} - 1) * m{hr} + m{hr})) => /#. |
| 205 | + rewrite -cell_eq_upto_unrelated_set. |
| 206 | + - do! split; 1,2,3: by smt(). |
| 207 | + move => ?. |
| 208 | + by apply (IntOrder.ltr_le_trans ((n{hr} - 1) * m{hr} + m{hr})) => /#. |
| 209 | + rewrite -{2} (rpow1 2%r) //. |
| 210 | + rewrite -rpowN //. |
| 211 | + by smt(rpowD). |
| 212 | + + rewrite /= -row_eq_upto_unrelated_set. |
| 213 | + - split; 1: by smt(). |
| 214 | + move => ?. |
| 215 | + by apply (IntOrder.ltr_le_trans ((n{hr} - 1) * m{hr} + m{hr})) => /#. |
| 216 | + rewrite -cell_eq_upto_unrelated_set. |
| 217 | + - do! split; 1,2,3: by smt(). |
| 218 | + move => ?. |
| 219 | + by apply (IntOrder.ltr_le_trans ((n{hr} - 1) * m{hr} + m{hr})) => /#. |
| 220 | + rewrite -{2} (rpow1 2%r) //. |
| 221 | + rewrite -rpowN //. |
| 222 | + by smt(rpowD). |
| 223 | + (* pre => inv *) |
| 224 | + + wp; skip. |
| 225 | + move => &hr />. |
| 226 | + rewrite xle_cxr_r => *. |
| 227 | + rewrite xle_cxr_l 1:/#. |
| 228 | + rewrite (_: cell_eq_upto i{hr} 0 m{hr} a{hr} a0 = true) //= 1:/#. |
| 229 | +wp. |
| 230 | +skip => /> &hr. |
| 231 | +rewrite xle_cxr_r => *. |
| 232 | +rewrite xle_cxr_l 1:/#. |
| 233 | +rewrite fromintN rpowN //= rpow_int //=. |
| 234 | +rewrite (_: row_eq_upto 0 m{hr} a{hr} a0 = true) //= 1:/#. |
| 235 | +qed. |
0 commit comments