vstd/arithmetic/internals/
div_internals.rs1#[allow(unused_imports)]
15use super::super::super::prelude::*;
16
17verus! {
18
19#[cfg(verus_keep_ghost)]
20use super::super::super::arithmetic::internals::general_internals::is_le;
21#[cfg(verus_keep_ghost)]
22use super::super::super::arithmetic::internals::mod_internals::{
23 lemma_mod_induction_forall,
24 lemma_mod_induction_forall2,
25 mod_auto,
26 lemma_mod_auto,
27 lemma_mod_basics,
28};
29use super::super::super::arithmetic::internals::mod_internals_nonlinear;
30#[cfg(verus_keep_ghost)]
31#[cfg(verus_keep_ghost)]
32use super::super::super::arithmetic::internals::div_internals_nonlinear;
33#[cfg(verus_keep_ghost)]
34use super::super::super::math::{add as add1, sub as sub1};
35
36#[verifier::opaque]
39pub open spec fn div_pos(x: int, d: int) -> int
40 recommends
41 d > 0,
42 decreases
43 (if x < 0 {
44 d - x
45 } else {
46 x
47 }),
48 when d > 0
49{
50 if x < 0 {
51 -1 + div_pos(x + d, d)
52 } else if x < d {
53 0
54 } else {
55 1 + div_pos(x - d, d)
56 }
57}
58
59#[verifier::opaque]
63pub open spec fn div_recursive(x: int, d: int) -> int
64 recommends
65 d != 0,
66{
67 if d > 0 {
69 div_pos(x, d)
70 } else {
71 -1 * div_pos(x, -1 * d)
72 }
73}
74
75pub proof fn lemma_div_basics(n: int)
78 requires
79 n > 0,
80 ensures
81 (n / n) == 1 && -((-n) / n) == 1,
82 forall|x: int| 0 <= x < n <==> #[trigger] (x / n) == 0,
83 forall|x: int| #[trigger] ((x + n) / n) == x / n + 1,
84 forall|x: int| #[trigger] ((x - n) / n) == x / n - 1,
85{
86 lemma_mod_auto(n);
87 lemma_mod_basics(n);
88 div_internals_nonlinear::lemma_small_div();
89 div_internals_nonlinear::lemma_div_by_self(n);
90 assert forall|x: int| #[trigger] (x / n) == 0 implies 0 <= x < n by {
91 mod_internals_nonlinear::lemma_fundamental_div_mod(x, n);
92 }
93}
94
95pub open spec fn div_auto_plus(n: int) -> bool {
100 forall|x: int, y: int|
101 #![trigger ((x + y) / n)]
102 {
103 let z = (x % n) + (y % n);
104 ((0 <= z < n && ((x + y) / n) == x / n + y / n) || (n <= z < n + n && ((x + y) / n) == x
105 / n + y / n + 1))
106 }
107}
108
109pub open spec fn div_auto_minus(n: int) -> bool {
114 forall|x: int, y: int|
115 #![trigger ((x - y) / n)]
116 {
117 let z = (x % n) - (y % n);
118 ((0 <= z < n && ((x - y) / n) == x / n - y / n) || (-n <= z < 0 && ((x - y) / n) == x
119 / n - y / n - 1))
120 }
121}
122
123pub open spec fn div_auto(n: int) -> bool
128 recommends
129 n > 0,
130{
131 &&& mod_auto(n)
132 &&& (n / n == -((-n) / n) == 1)
133 &&& forall|x: int| 0 <= x < n <==> #[trigger] (x / n) == 0
134 &&& div_auto_plus(n)
135 &&& div_auto_minus(n)
136}
137
138proof fn lemma_div_auto_plus(n: int)
141 requires
142 n > 0,
143 ensures
144 div_auto_plus(n),
145{
146 lemma_mod_auto(n);
147 lemma_div_basics(n);
148 assert forall|x: int, y: int|
149 {
150 let z = (x % n) + (y % n);
151 ((0 <= z < n && #[trigger] ((x + y) / n) == x / n + y / n) || (n <= z < n + n && ((x
152 + y) / n) == x / n + y / n + 1))
153 } by {
154 let f = |xx: int, yy: int|
155 {
156 let z = (xx % n) + (yy % n);
157 ((0 <= z < n && ((xx + yy) / n) == xx / n + yy / n) || (n <= z < 2 * n && ((xx + yy)
158 / n) == xx / n + yy / n + 1))
159 };
160 assert forall|i: int, j: int|
161 {
162 &&& (j >= 0 && #[trigger] f(i, j) ==> f(i, add1(j, n)))
166 &&& (i < n && f(i, j) ==> f(i - n, j))
167 &&& (j < n && f(i, j) ==> f(i, j - n))
168 &&& (i >= 0 && f(i, j) ==> f(i + n, j))
169 } by {
170 assert(((i + n) + j) / n == ((i + j) + n) / n);
171 assert((i + (j + n)) / n == ((i + j) + n) / n);
172 assert(((i - n) + j) / n == ((i + j) - n) / n);
173 assert((i + (j - n)) / n == ((i + j) - n) / n);
174 }
175 assert forall|i: int, j: int| 0 <= i < n && 0 <= j < n implies #[trigger] f(i, j) by {
176 assert(((i + n) + j) / n == ((i + j) + n) / n);
177 assert((i + (j + n)) / n == ((i + j) + n) / n);
178 assert(((i - n) + j) / n == ((i + j) - n) / n);
179 assert((i + (j - n)) / n == ((i + j) - n) / n);
180 }
181 lemma_mod_induction_forall2(n, f);
182 assert(f(x, y));
183 }
184}
185
186#[verifier::spinoff_prover]
189proof fn lemma_div_auto_minus(n: int)
190 requires
191 n > 0,
192 ensures
193 div_auto_minus(n),
194{
195 lemma_mod_auto(n);
196 lemma_div_basics(n);
197 assert forall|x: int, y: int|
198 {
199 let z = (x % n) - (y % n);
200 ((0 <= z < n && #[trigger] ((x - y) / n) == x / n - y / n) || (-n <= z < 0 && ((x - y)
201 / n) == x / n - y / n - 1))
202 } by {
203 let f = |xx: int, yy: int|
204 {
205 let z = (xx % n) - (yy % n);
206 ((0 <= z < n && ((xx - yy) / n) == xx / n - yy / n) || (-n <= z < 0 && (xx - yy) / n
207 == xx / n - yy / n - 1))
208 };
209 assert forall|i: int, j: int|
210 {
211 &&& (j >= 0 && #[trigger] f(i, j) ==> f(i, add1(j, n)))
212 &&& (i < n && f(i, j) ==> f(sub1(i, n), j))
213 &&& (j < n && f(i, j) ==> f(i, sub1(j, n)))
214 &&& (i >= 0 && f(i, j) ==> f(add1(i, n), j))
215 } by {
216 assert(((i + n) - j) / n == ((i - j) + n) / n);
217 assert((i - (j - n)) / n == ((i - j) + n) / n);
218 assert(((i - n) - j) / n == ((i - j) - n) / n);
219 assert((i - (j + n)) / n == ((i - j) - n) / n);
220 }
221 assert forall|i: int, j: int| 0 <= i < n && 0 <= j < n implies #[trigger] f(i, j) by {
222 assert(((i + n) - j) / n == ((i - j) + n) / n);
223 assert((i - (j - n)) / n == ((i - j) + n) / n);
224 assert(((i - n) - j) / n == ((i - j) - n) / n);
225 assert((i - (j + n)) / n == ((i - j) - n) / n);
226 }
227 lemma_mod_induction_forall2(n, f);
228 assert(f(x, y));
229 }
230}
231
232pub proof fn lemma_div_auto(n: int)
235 requires
236 n > 0,
237 ensures
238 div_auto(n),
239{
240 lemma_mod_auto(n);
241 lemma_div_basics(n);
242 assert forall|x: int| 0 <= x < n <==> #[trigger] (x / n) == 0 by {
243 lemma_div_basics(n);
244 }
245 assert((0 + n) / n == 1);
246 assert((0 - n) / n == -1);
247 lemma_div_auto_plus(n);
248 lemma_div_auto_minus(n);
249}
250
251pub proof fn lemma_div_induction_auto(n: int, x: int, f: spec_fn(int) -> bool)
279 requires
280 n > 0,
281 div_auto(n) ==> {
282 &&& (forall|i: int| #[trigger] is_le(0, i) && i < n ==> f(i))
283 &&& (forall|i: int| #[trigger] is_le(0, i) && f(i) ==> f(i + n))
284 &&& (forall|i: int| #[trigger] is_le(i + 1, n) && f(i) ==> f(i - n))
285 },
286 ensures
287 div_auto(n),
288 f(x),
289{
290 lemma_div_auto(n);
291 assert(forall|i: int| is_le(0, i) && i < n ==> f(i));
292 assert(forall|i: int| is_le(0, i) && #[trigger] f(i) ==> #[trigger] f(add1(i, n)));
293 assert(forall|i: int| is_le(i + 1, n) && #[trigger] f(i) ==> #[trigger] f(sub1(i, n)));
294 assert forall|i: int| 0 <= i < n implies #[trigger] f(i) by {
295 assert(f(i)) by {
296 assert(forall|i: int| is_le(0, i) && i < n ==> f(i));
297 assert(is_le(0, i) && i < n);
298 };
299 };
300 lemma_mod_induction_forall(n, f);
301 assert(f(x));
302}
303
304pub proof fn lemma_div_induction_auto_forall(n: int, f: spec_fn(int) -> bool)
329 requires
330 n > 0,
331 div_auto(n) ==> {
332 &&& (forall|i: int| #[trigger] is_le(0, i) && i < n ==> f(i))
333 &&& (forall|i: int| #[trigger] is_le(0, i) && f(i) ==> f(i + n))
334 &&& (forall|i: int| #[trigger] is_le(i + 1, n) && f(i) ==> f(i - n))
335 },
336 ensures
337 div_auto(n),
338 forall|i| #[trigger] f(i),
339{
340 assert(div_auto(n)) by {
341 lemma_div_induction_auto(n, 0, f);
342 }
343 assert forall|i| #[trigger] f(i) by {
344 lemma_div_induction_auto(n, i, f);
345 }
346}
347
348}