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