1use super::super::calc_macro::*;
15#[allow(unused_imports)]
16use super::super::prelude::*;
17
18verus! {
19
20pub open spec fn rust_div(a: int, b: int) -> int
21 recommends
22 b != 0,
23{
24 if a == 0 {
25 0
26 } else if a > 0 {
27 a / b
28 } else {
29 -((-a) / b)
30 }
31}
32
33pub open spec fn rust_rem(a: int, b: int) -> int
34 recommends
35 b != 0,
36{
37 if a == 0 {
38 0
39 } else if a > 0 {
40 a % b
41 } else {
42 -((-a) % b)
43 }
44}
45
46#[allow(unused_imports)]
47#[cfg(verus_keep_ghost)]
48use super::super::arithmetic::internals::div_internals::{
49 div_recursive,
50 lemma_div_induction_auto,
51 div_auto,
52 div_pos,
53 lemma_div_auto,
54};
55use super::super::arithmetic::internals::div_internals_nonlinear as DivINL;
56#[cfg(verus_keep_ghost)]
57use super::super::arithmetic::internals::mod_internals::{
58 lemma_div_add_denominator,
59 lemma_mod_auto,
60 mod_recursive,
61};
62use super::super::arithmetic::internals::mod_internals_nonlinear as ModINL;
63#[cfg(verus_keep_ghost)]
64use super::internals::mul_internals::{
65 group_mul_properties_internal,
66 lemma_mul_induction,
67 lemma_mul_induction_auto,
68};
69#[cfg(verus_keep_ghost)]
70use super::super::arithmetic::internals::general_internals::{is_le};
71#[cfg(verus_keep_ghost)]
72use super::super::math::{add as add1, sub as sub1, div as div1};
73use super::super::arithmetic::mul::*;
74
75pub broadcast proof fn lemma_div_is_div_recursive(x: int, d: int)
82 requires
83 0 < d,
84 ensures
85 div_recursive(x, d) == #[trigger] (x / d),
86{
87 reveal(div_recursive);
88 reveal(div_pos);
89 lemma_div_induction_auto(d, x, |u: int| div_recursive(u, d) == u / d);
90}
91
92pub proof fn lemma_div_by_self(d: int)
95 requires
96 d != 0,
97 ensures
98 d / d == 1,
99{
100 DivINL::lemma_div_by_self(d);
101}
102
103pub proof fn lemma_div_of0(d: int)
105 requires
106 d != 0,
107 ensures
108 0 as int / d == 0,
109{
110 DivINL::lemma_div_of0(d);
111}
112
113pub proof fn lemma_div_basics(x: int)
117 ensures
118 x != 0 as int ==> 0 as int / x == 0,
119 x / 1 == x,
120 x != 0 ==> x / x == 1,
121{
122 if (x != 0) {
123 lemma_div_by_self(x);
124 lemma_div_of0(x);
125 }
126}
127
128pub broadcast proof fn lemma_div_basics_1(x: int)
130 ensures
131 x != 0 as int ==> #[trigger] (0int / x) == 0,
132{
133 lemma_div_basics(x);
134}
135
136pub broadcast proof fn lemma_div_basics_2(x: int)
138 ensures
139 #[trigger] (x / 1) == x,
140{
141 lemma_div_basics(x);
142}
143
144pub broadcast proof fn lemma_div_basics_3(x: int)
146 ensures
147 x != 0 ==> #[trigger] (x / x) == 1,
148{
149 lemma_div_basics(x);
150}
151
152pub broadcast proof fn lemma_div_basics_4(x: int, y: int)
154 ensures
155 x >= 0 && y > 0 ==> #[trigger] (x / y) >= 0,
156{
157}
158
159pub broadcast proof fn lemma_div_basics_5(x: int, y: int)
162 ensures
163 x >= 0 && y > 0 ==> #[trigger] (x / y) <= x,
164{
165 assert forall|x: int, y: int| x >= 0 && y > 0 implies 0 <= #[trigger] (x / y) <= x by {
166 lemma_div_pos_is_pos(x, y);
167 lemma_div_is_ordered_by_denominator(x, 1, y);
168 };
169}
170
171pub broadcast group group_div_basics {
172 lemma_div_basics_1,
173 lemma_div_basics_2,
174 lemma_div_basics_3,
175 lemma_div_basics_4,
176 lemma_div_basics_5,
177}
178
179pub broadcast proof fn lemma_small_div_converse(x: int, d: int)
183 ensures
184 0 <= x && 0 < d && #[trigger] (x / d) == 0 ==> x < d,
185{
186 assert forall|x: int, d: int| 0 <= x && 0 < d && #[trigger] (x / d) == 0 implies x < d by {
187 lemma_div_induction_auto(d, x, |u: int| 0 <= u && 0 < d && u / d == 0 ==> u < d);
188 }
189}
190
191pub proof fn lemma_div_non_zero(x: int, d: int)
195 requires
196 x >= d > 0,
197 ensures
198 #[trigger] (x / d) > 0,
199{
200 broadcast use lemma_div_pos_is_pos;
201
202 if x / d == 0 {
203 broadcast use lemma_small_div_converse;
204
205 }
206}
207
208pub broadcast proof fn lemma_div_is_ordered_by_denominator(x: int, y: int, z: int)
214 requires
215 0 <= x,
216 1 <= y <= z,
217 ensures
218 #[trigger] (x / y) >= #[trigger] (x / z),
219 decreases x,
220{
221 reveal(div_recursive);
222 reveal(div_pos);
223 broadcast use lemma_div_is_div_recursive;
224
225 assert(forall|u: int, d: int|
226 #![trigger div_recursive(u, d)]
227 #![trigger div1(u, d)]
228 d > 0 ==> div_recursive(u, d) == div1(u, d));
229 if (x < z) {
230 lemma_div_is_ordered(0, x, y);
231 } else {
232 lemma_div_is_ordered(x - z, x - y, y);
233 lemma_div_is_ordered_by_denominator(x - z, y, z);
234 }
235}
236
237pub broadcast proof fn lemma_div_is_strictly_smaller(x: int, d: int)
240 requires
241 0 < x,
242 1 < d,
243 ensures
244 #[trigger] (x / d) < x,
245 decreases x,
246{
247 lemma_div_induction_auto(d, x, |u: int| 0 < u ==> u / d < u);
248}
249
250pub broadcast proof fn lemma_dividing_sums(a: int, b: int, d: int, r: int)
253 requires
254 0 < d,
255 r == a % d + b % d - (a + b) % d,
256 ensures
257 #![trigger (d * ((a + b) / d) - r), (d * (a / d) + d * (b / d))]
258 d * ((a + b) / d) - r == d * (a / d) + d * (b / d),
259{
260 ModINL::lemma_fundamental_div_mod(a + b, d);
261 ModINL::lemma_fundamental_div_mod(a, d);
262 ModINL::lemma_fundamental_div_mod(b, d);
263}
264
265pub broadcast proof fn lemma_div_pos_is_pos(x: int, d: int)
269 requires
270 0 <= x,
271 0 < d,
272 ensures
273 0 <= #[trigger] (x / d),
274{
275 lemma_div_auto(d);
276 assert(div_auto(d));
277 let f = |u: int| 0 <= u ==> u / d >= 0;
278 assert forall|i: int| #[trigger] is_le(0, i) && f(i) implies f(i + d) by {
279 assert(i / d >= 0);
280 };
281 lemma_div_induction_auto(d, x, |u: int| 0 <= u ==> u / d >= 0);
282}
283
284pub broadcast proof fn lemma_div_plus_one(x: int, d: int)
288 requires
289 0 < d,
290 ensures
291 #![trigger (1 + x / d), ((d + x) / d)]
292 1 + x / d == (d + x) / d,
293{
294 lemma_div_auto(d);
295}
296
297pub broadcast proof fn lemma_div_minus_one(x: int, d: int)
301 requires
302 0 < d,
303 ensures
304 #![trigger (-1 + x / d), ((-d + x) / d)]
305 -1 + x / d == (-d + x) / d,
306{
307 lemma_div_auto(d);
308}
309
310pub proof fn lemma_basic_div_specific_divisor(d: int)
313 requires
314 0 < d,
315 ensures
316 forall|x: int| 0 <= x < d ==> #[trigger] (x / d) == 0,
317{
318 lemma_div_auto(d);
319}
320
321pub broadcast proof fn lemma_basic_div(x: int, d: int)
324 requires
325 0 <= x < d,
326 ensures
327 #[trigger] (x / d) == 0,
328{
329 lemma_basic_div_specific_divisor(d);
330}
331
332pub broadcast proof fn lemma_div_is_ordered(x: int, y: int, z: int)
336 requires
337 x <= y,
338 0 < z,
339 ensures
340 #[trigger] (x / z) <= #[trigger] (y / z),
341{
342 lemma_div_auto(z);
343 let f = |xy: int| xy <= 0 ==> (xy + y) / z <= y / z;
344 assert forall|i: int| #[trigger] is_le(i + 1, z) && f(i) implies f(i - z) by {
345 if (i - z <= 0) {
346 assert(f(i));
347 assert(i <= 0 ==> (i + y) / z <= y / z);
348 if (i > 0) {
349 assert(z > 0);
350 assert(i <= z);
351 assert(((i + y) - z) / z <= y / z);
352 } else {
353 assert((i + y) / z <= y / z);
354 }
355 assert((i - z + y) / z <= y / z);
356 }
357 };
358 lemma_div_induction_auto(z, x - y, |xy: int| xy <= 0 ==> (xy + y) / z <= y / z);
359}
360
361pub broadcast proof fn lemma_div_decreases(x: int, d: int)
364 requires
365 0 < x,
366 1 < d,
367 ensures
368 #[trigger] (x / d) < x,
369{
370 lemma_div_induction_auto(d, x, |u: int| 0 < u ==> u / d < u);
371}
372
373pub broadcast proof fn lemma_div_nonincreasing(x: int, d: int)
377 requires
378 0 <= x,
379 0 < d,
380 ensures
381 #[trigger] (x / d) <= x,
382{
383 lemma_div_induction_auto(d, x, |u: int| 0 <= u ==> u / d <= u);
384}
385
386pub proof fn lemma_small_mod(x: nat, m: nat)
390 requires
391 x < m,
392 0 < m,
393 ensures
394 x % m == x,
395{
396 ModINL::lemma_small_mod(x, m);
397}
398
399pub broadcast proof fn lemma_breakdown(x: int, y: int, z: int)
404 requires
405 0 <= x,
406 0 < y,
407 0 < z,
408 ensures
409 #![trigger y * z, x % (y * z), y * ((x / y) % z) + x % y]
410 0 < y * z,
411 (x % (y * z)) == y * ((x / y) % z) + x % y,
412{
413 broadcast use lemma_mul_strictly_positive;
414
415 lemma_div_pos_is_pos(x, y);
416 calc! {
417 (<)
418 (y * (x / y)) % (y * z) + (x % y) % (y * z); (<=) {
419 lemma_part_bound1(x, y, z);
420 }
421 y * (z - 1) + (x % y) % (y * z); (<) {
422 lemma_part_bound2(x, y, z);
423 }
424 y * (z - 1) + y; (==) {
425 broadcast use group_mul_basics;
426
427 }
428 y * (z - 1) + y * 1; (==) {
429 broadcast use group_mul_is_distributive;
430
431 }
432 y * (z - 1 + 1); (==) {}
433 y * z;
434 }
435 calc! {
436 (==)
437 x % (y * z); {
438 ModINL::lemma_fundamental_div_mod(x, y);
439 }
440 (y * (x / y) + x % y) % (y * z); {
441 broadcast use group_mod_properties;
442
443 assert(0 <= x % y);
444 lemma_mul_nonnegative(y, x / y);
445 assert((y * (x / y)) % (y * z) + (x % y) % (y * z) < y * z);
446 lemma_mod_adds(y * (x / y), x % y, y * z);
447 }
448 (y * (x / y)) % (y * z) + (x % y) % (y * z); {
449 broadcast use {group_mod_properties, lemma_mul_is_commutative};
450
451 lemma_mul_increases(z, y);
452 assert((x % y) < y && y <= (y * z));
455 lemma_small_mod((x % y) as nat, (y * z) as nat);
456 assert((x % y) % (y * z) == x % y);
457 }
458 (y * (x / y)) % (y * z) + x % y; {
459 lemma_truncate_middle(x / y, y, z);
460 }
461 y * ((x / y) % z) + x % y;
462 }
463}
464
465pub broadcast proof fn lemma_remainder_upper(x: int, d: int)
469 requires
470 0 <= x,
471 0 < d,
472 ensures
473 #![trigger (x - d), (x / d * d)]
474 x - d < x / d * d,
475{
476 broadcast use group_mul_properties_internal;
477
478 lemma_div_induction_auto(d, x, |u: int| 0 <= u ==> u - d < u / d * d);
479}
480
481pub broadcast proof fn lemma_remainder_lower(x: int, d: int)
485 requires
486 0 <= x,
487 0 < d,
488 ensures
489 x >= #[trigger] (x / d * d),
490{
491 broadcast use group_mul_properties_internal;
492
493 lemma_div_induction_auto(d, x, |u: int| 0 <= u ==> u >= u / d * d);
494}
495
496pub broadcast proof fn lemma_remainder(x: int, d: int)
501 requires
502 0 <= x,
503 0 < d,
504 ensures
505 0 <= #[trigger] (x - (x / d * d)) < d,
506{
507 broadcast use group_mul_properties_internal;
508
509 lemma_div_induction_auto(d, x, |u: int| 0 <= u - u / d * d < d);
510}
511
512pub broadcast proof fn lemma_fundamental_div_mod(x: int, d: int)
516 requires
517 d != 0,
518 ensures
519 x == #[trigger] (d * (x / d) + (x % d)),
520{
521 assert(x == d * (x / d) + (x % d)) by {
522 ModINL::lemma_fundamental_div_mod(x, d);
523 }
524}
525
526pub broadcast proof fn lemma_div_denominator(x: int, c: int, d: int)
529 requires
530 0 <= x,
531 0 < c,
532 0 < d,
533 ensures
534 c * d != 0,
535 #[trigger] ((x / c) / d) == x / (c * d),
536{
537 lemma_mul_strictly_positive(c, d);
538 let r = x % (c as int * d as int);
539 lemma_div_pos_is_pos(r, c as int);
540 if (r / c as int >= d) {
541 ModINL::lemma_fundamental_div_mod(r, c as int);
542 lemma_mul_inequality(d as int, r / c as int, c as int);
543 lemma_mul_is_commutative(d, c);
544 }
545 assert(r / (c as int) < d);
546 lemma_fundamental_div_mod_converse(r / c, d, 0, r / c);
547 assert((r / c as int) % d as int == r / c as int);
548 lemma_fundamental_div_mod(r, c);
549 assert(c * (r / c) + r % c == r);
550 assert(c * ((r / c as int) % d as int) + r % c as int == r);
551 let k = x / (c as int * d as int);
552 lemma_fundamental_div_mod(x, c * d);
553 assert(x == (c * d) * (x / (c * d)) + x % (c * d));
554 assert(r == x - (c * d) * (x / (c * d)));
555 assert(r == x - (c * d) * k);
556 calc! {
557 (==)
558 c * ((x / c) % d) + x % c; {
559 broadcast use lemma_mul_is_commutative;
560
561 lemma_mod_multiples_vanish(-k, x / c, d);
562 }
563 c * ((x / c + (-k) * d) % d) + x % c; {
564 lemma_hoist_over_denominator(x, (-k) * d, c as nat);
565 }
566 c * (((x + (((-k) * d) * c)) / c) % d) + x % c; {
567 lemma_mul_is_associative(-k, d, c);
568 }
569 c * (((x + ((-k) * (d * c))) / c) % d) + x % c; {
570 lemma_mul_unary_negation(k, d * c);
571 }
572 c * (((x + (-(k * (d * c)))) / c) % d) + x % c; {
573 lemma_mul_is_associative(k, d, c);
574 }
575 c * (((x + (-(k * d * c))) / c) % d) + x % c; {}
576 c * (((x - k * d * c) / c) % d) + x % c; {
577 broadcast use {lemma_mul_is_associative, lemma_mul_is_commutative};
578
579 }
580 c * ((r / c) % d) + x % c; {}
581 c * (r / c) + x % c; {
582 lemma_fundamental_div_mod(r, c);
583 assert(r == c * (r / c) + r % c);
584 lemma_mod_mod(x, c, d);
585 assert(r % c == x % c);
586 }
587 r; {
588 broadcast use {group_mod_properties, lemma_mod_is_mod_recursive};
589
590 }
591 r % (c * d); {}
592 (x - (c * d) * k) % (c * d); {
593 lemma_mul_unary_negation(c * d, k);
594 }
595 (x + (c * d) * (-k)) % (c * d); {
596 lemma_mod_multiples_vanish(-k, x, c * d);
597 }
598 x % (c * d);
599 }
600 assert(c * (x / c) + x % c - r == c * (x / c) - c * ((x / c) % d) ==> x - r == c * (x / c) - c
601 * ((x / c) % d)) by {
602 lemma_fundamental_div_mod(x, c);
603 };
604 assert(c * (x / c) + x % c - r == c * (x / c) - c * ((x / c) % d));
605 assert(x - r == c * (x / c) - c * ((x / c) % d));
606 assert((x / c) / d == x / (c * d)) by {
607 lemma_fundamental_div_mod(x / c, d);
608 assert(d * ((x / c) / d) == x / c - ((x / c) % d));
609 lemma_fundamental_div_mod(x, c * d);
610 assert(x == (c * d) * (x / (c * d)) + (x % (c * d)));
611 lemma_mul_is_distributive_sub(c, x / c, (x / c) % d);
612 assert(c * (d * ((x / c) / d)) == c * (x / c) - c * ((x / c) % d));
613 lemma_mul_is_associative(c, d, (x / c) / d);
614 assert((c * d) * ((x / c) / d) == c * (x / c) - c * ((x / c) % d));
615 assert((c * d) * ((x / c) / d) == x - r);
616 assert((c * d) * ((x / c) / d) == (c * d) * (x / (c * d)));
617 lemma_mul_equality_converse(c * d, (x / c) / d, x / (c * d));
618 }
619 assert(c * d != 0) by {
620 assert(0 < c * d);
621 }
622 assert(c * d != 0); }
624
625pub broadcast proof fn lemma_mul_hoist_inequality(x: int, y: int, z: int)
629 requires
630 0 <= x,
631 0 < z,
632 ensures
633 #![trigger (x * (y / z)), ((x * y) / z)]
634 x * (y / z) <= (x * y) / z,
635{
636 calc! {
637 (==)
638 (x * y) / z; (==) {
639 lemma_fundamental_div_mod(y, z);
640 }
641 (x * (z * (y / z) + y % z)) / z; (==) {
642 broadcast use group_mul_is_distributive;
643
644 }
645 (x * (z * (y / z)) + x * (y % z)) / z;
646 }
647 assert((x * (z * (y / z)) + x * (y % z)) / z >= x * (y / z)) by {
648 broadcast use {group_mod_properties, lemma_mul_is_associative, lemma_mul_is_commutative};
649
650 lemma_mul_nonnegative(x, y % z);
651 lemma_div_is_ordered(x * (z * (y / z)), x * (z * (y / z)) + x * (y % z), z);
652 lemma_div_multiples_vanish(x * (y / z), z);
653 };
654}
655
656pub broadcast proof fn lemma_indistinguishable_quotients(a: int, b: int, d: int)
664 requires
665 0 < d,
666 0 <= a - a % d <= b < a + d - a % d,
667 ensures
668 #![trigger (a / d), (b / d)]
669 a / d == b / d,
670{
671 lemma_div_induction_auto(
672 d,
673 a - b,
674 |ab: int|
675 {
676 let u = ab + b;
677 0 <= u - u % d <= b < u + d - u % d ==> u / d == b / d
678 },
679 );
680}
681
682pub proof fn lemma_truncate_middle(x: int, b: int, c: int)
686 requires
687 0 <= x,
688 0 < b,
689 0 < c,
690 ensures
691 #![trigger (b * (x % c))]
692 0 < b * c,
693 (b * x) % (b * c) == b * (x % c),
694{
695 broadcast use {lemma_mul_strictly_positive, lemma_mul_nonnegative};
696
697 calc! {
698 (==)
699 b * x; {
700 ModINL::lemma_fundamental_div_mod(b * x, b * c);
701 }
702 (b * c) * ((b * x) / (b * c)) + (b * x) % (b * c); {
703 lemma_div_denominator(b * x, b, c);
704 }
705 (b * c) * (((b * x) / b) / c) + (b * x) % (b * c); {
706 broadcast use lemma_mul_is_commutative;
707
708 lemma_div_by_multiple(x, b);
709 }
710 (b * c) * (x / c) + (b * x) % (b * c);
711 }
712 assert(b * x == (b * c) * (x / c) + b * (x % c)) by {
713 ModINL::lemma_fundamental_div_mod(x, c);
714 broadcast use {group_mul_is_distributive, lemma_mul_is_associative};
715
716 };
717}
718
719pub broadcast proof fn lemma_div_multiples_vanish_quotient(x: int, a: int, d: int)
723 requires
724 0 < x,
725 0 <= a,
726 0 < d,
727 ensures
728 #![trigger a / d, x * a, x * d]
729 0 < x * d,
730 a / d == (x * a) / (x * d),
731{
732 lemma_mul_strictly_positive(x, d);
733 calc! {
734 (==)
735 (x * a) / (x * d); {
736 lemma_mul_nonnegative(x, a);
737 lemma_div_denominator(x * a, x, d);
738 }
739 ((x * a) / x) / d; {
740 lemma_div_multiples_vanish(a, x);
741 }
742 a / d;
743 }
744}
745
746pub broadcast proof fn lemma_round_down(a: int, r: int, d: int)
749 requires
750 0 < d,
751 a % d == 0,
752 0 <= r < d,
753 ensures
754 #![trigger (d * ((a + r) / d))]
755 a == d * ((a + r) / d),
756{
757 broadcast use group_mul_properties_internal;
758
759 lemma_div_induction_auto(d, a, |u: int| u % d == 0 ==> u == d * ((u + r) / d));
760}
761
762pub broadcast proof fn lemma_div_multiples_vanish_fancy(x: int, b: int, d: int)
764 requires
765 0 < d,
766 0 <= b < d,
767 ensures
768 #![trigger (d * x + b) / d]
769 (d * x + b) / d == x,
770{
771 let f = |u: int| (d * u + b) / d == u;
772 assert(f(0)) by {
773 lemma_div_auto(d);
774 }
775 assert forall|i: int| i >= 0 && #[trigger] f(i) implies #[trigger] f(add1(i, 1)) by {
776 assert(d * (i + 1) + b == d * i + b + d) by {
777 assert(d * (i + 1) == d * i + d) by {
778 lemma_mul_is_distributive_add(d, i, 1);
779 lemma_mul_basics(d);
780 }
781 }
782 super::internals::div_internals::lemma_div_basics(d);
783 }
784 assert forall|i: int| i <= 0 && #[trigger] f(i) implies #[trigger] f(sub1(i, 1)) by {
785 assert(d * (i - 1) + b == d * i + b - d) by {
786 assert(d * (i - 1) == d * i - d) by {
787 lemma_mul_is_distributive_sub(d, i, 1);
788 lemma_mul_basics(d);
789 }
790 }
791 super::internals::div_internals::lemma_div_basics(d);
792 }
793 broadcast use group_mul_properties_internal;
794
795 lemma_mul_induction(f);
796 assert(f(x));
797}
798
799pub broadcast proof fn lemma_div_multiples_vanish(x: int, d: int)
803 requires
804 0 < d,
805 ensures
806 #![trigger (d * x) / d]
807 (d * x) / d == x,
808{
809 lemma_div_multiples_vanish_fancy(x, 0, d);
810}
811
812pub broadcast proof fn lemma_div_by_multiple(b: int, d: int)
816 requires
817 0 <= b,
818 0 < d,
819 ensures
820 #![trigger ((b * d) / d)]
821 (b * d) / d == b,
822{
823 lemma_div_multiples_vanish(b, d);
824 broadcast use group_mul_properties_internal;
825
826}
827
828pub broadcast proof fn lemma_div_by_multiple_is_strongly_ordered(x: int, y: int, m: int, z: int)
832 requires
833 x < y,
834 y == m * z,
835 0 < z,
836 ensures
837 #![trigger x / z, m * z, y / z]
838 x / z < y / z,
839{
840 lemma_mod_multiples_basic(m, z);
841 lemma_div_induction_auto(
842 z,
843 y - x,
844 |yx: int|
845 {
846 let u = yx + x;
847 x < u && u % z == 0 ==> x / z < u / z
848 },
849 );
850}
851
852pub broadcast proof fn lemma_multiply_divide_le(a: int, b: int, c: int)
857 requires
858 0 < b,
859 a <= b * c,
860 ensures
861 #![trigger a / b, b * c]
862 a / b <= c,
863{
864 lemma_mod_multiples_basic(c, b);
865 let f = |i: int| 0 <= i && (i + a) % b == 0 ==> a / b <= (i + a) / b;
866 lemma_div_induction_auto(b, b * c - a, f);
867 lemma_div_multiples_vanish(c, b);
868}
869
870pub broadcast proof fn lemma_multiply_divide_lt(a: int, b: int, c: int)
874 requires
875 0 < b,
876 a < b * c,
877 ensures
878 #![trigger a / b, b * c]
879 a / b < c,
880{
881 assert(((b * c - a) + a) % b == 0 ==> a / b < ((b * c - a) + a) / b) by {
882 let f = |i: int| 0 < i && (i + a) % b == 0 ==> a / b < (i + a) / b;
883 lemma_div_induction_auto(b, b * c - a, f);
884 }
885 assert(b * c == c * b) by {
886 lemma_mul_is_commutative(b, c);
887 }
888 assert((b * c) % b == 0) by {
889 lemma_mod_multiples_basic(c, b);
890 }
891 assert((b * c) / b == c) by {
892 lemma_div_multiples_vanish(c, b);
893 }
894}
895
896pub broadcast proof fn lemma_hoist_over_denominator(x: int, j: int, d: nat)
900 requires
901 0 < d,
902 ensures
903 #![trigger x / d as int + j]
904 x / d as int + j == (x + j * d) / d as int,
905{
906 let dd = d as int;
907 let q = x / dd;
908 let r = x % dd;
909 assert(x == dd * q + r) by {
910 lemma_fundamental_div_mod(x, dd);
911 }
912 assert(j * dd == dd * j) by {
913 lemma_mul_is_commutative(j, dd);
914 }
915 assert(x + j * dd == dd * (q + j) + r) by {
916 lemma_mul_is_distributive_add(dd, q, j);
917 }
918 assert((x + j * dd) / dd == q + j) by {
919 lemma_fundamental_div_mod_converse(x + j * d, dd, q + j, r);
920 }
921}
922
923pub broadcast proof fn lemma_part_bound1(a: int, b: int, c: int)
927 requires
928 0 <= a,
929 0 < b,
930 0 < c,
931 ensures
932 #![trigger (b * (a / b) % (b * c))]
933 0 < b * c,
934 (b * (a / b) % (b * c)) <= b * (c - 1),
935{
936 lemma_mul_strictly_positive(b, a / b);
937 lemma_mul_strictly_positive(b, c);
938 lemma_mul_strictly_positive(b, c - 1);
939 calc! {
940 (==)
941 b * (a / b) % (b * c); {
942 ModINL::lemma_fundamental_div_mod(b * (a / b), b * c);
943 }
944 b * (a / b) - (b * c) * ((b * (a / b)) / (b * c)); {
945 broadcast use lemma_mul_is_associative;
946
947 }
948 b * (a / b) - b * (c * ((b * (a / b)) / (b * c))); {
949 broadcast use group_mul_is_distributive;
950
951 }
952 b * ((a / b) - (c * ((b * (a / b)) / (b * c))));
953 }
954 assert(b * (a / b) % (b * c) <= b * (c - 1)) by {
955 broadcast use {lemma_mul_is_commutative, lemma_mul_inequality};
956
957 };
958}
959
960pub broadcast proof fn lemma_mod_is_mod_recursive(x: int, m: int)
968 requires
969 m > 0,
970 ensures
971 mod_recursive(x, m) == #[trigger] (x % m),
972 decreases
973 (if x < 0 {
974 -x + m
975 } else {
976 x
977 }),
978{
979 reveal(mod_recursive);
980 if x < 0 {
981 calc! {
982 (==)
983 mod_recursive(x, m); {}
984 mod_recursive(x + m, m); {
985 lemma_mod_is_mod_recursive(x + m, m);
986 }
987 (x + m) % m; {
988 lemma_add_mod_noop(x, m, m);
989 }
990 ((x % m) + (m % m)) % m; {
991 broadcast use {lemma_mod_self_0, lemma_mod_twice};
992
993 }
994 (x % m) % m; {
995 broadcast use {lemma_mod_self_0, lemma_mod_twice};
996
997 }
998 x % m;
999 }
1000 } else if x < m {
1001 lemma_small_mod(x as nat, m as nat);
1002 } else {
1003 calc! {
1004 (==)
1005 mod_recursive(x, m); {}
1006 mod_recursive(x - m, m); {
1007 lemma_mod_is_mod_recursive(x - m, m);
1008 }
1009 (x - m) % m; {
1010 lemma_sub_mod_noop(x, m, m);
1011 }
1012 ((x % m) - (m % m)) % m; {
1013 broadcast use {lemma_mod_self_0, lemma_mod_twice};
1014
1015 }
1016 (x % m) % m; {
1017 broadcast use {lemma_mod_self_0, lemma_mod_twice};
1018
1019 }
1020 x % m;
1021 }
1022 }
1023}
1024
1025pub broadcast proof fn lemma_mod_self_0(m: int)
1027 requires
1028 m > 0,
1029 ensures
1030 #[trigger] (m % m) == 0,
1031{
1032 lemma_mod_auto(m);
1033}
1034
1035pub broadcast proof fn lemma_mod_twice(x: int, m: int)
1037 requires
1038 m > 0,
1039 ensures
1040 #[trigger] ((x % m) % m) == x % m,
1041{
1042 lemma_mod_auto(m);
1043}
1044
1045pub broadcast group group_mod_basics {
1046 lemma_mod_self_0,
1047 lemma_mod_twice,
1048}
1049
1050pub broadcast proof fn lemma_mod_division_less_than_divisor(x: int, m: int)
1052 requires
1053 m > 0,
1054 ensures
1055 0 <= #[trigger] (x % m) < m,
1056{
1057 lemma_mod_auto(m);
1058}
1059
1060pub broadcast group group_mod_properties {
1061 group_mod_basics,
1062 lemma_mod_division_less_than_divisor,
1063}
1064
1065pub broadcast proof fn lemma_mod_decreases(x: nat, m: nat)
1068 requires
1069 0 < m,
1070 ensures
1071 #[trigger] (x % m) <= x,
1072{
1073 lemma_mod_auto(m as int);
1074}
1075
1076pub broadcast proof fn lemma_mod_is_zero(x: nat, m: nat)
1078 requires
1079 x > 0 && m > 0,
1080 #[trigger] (x % m) == 0,
1081 ensures
1082 x >= m,
1083{
1084 if (x < m) {
1085 lemma_small_mod(x, m);
1086 }
1087}
1088
1089#[verifier::spinoff_prover]
1092pub broadcast proof fn lemma_mod_multiples_basic(x: int, m: int)
1093 requires
1094 m > 0,
1095 ensures
1096 #[trigger] ((x * m) % m) == 0,
1097{
1098 lemma_mod_auto(m);
1099 broadcast use group_mul_properties_internal;
1100
1101 let f = |u: int| (u * m) % m == 0;
1102 lemma_mul_induction(f);
1103 assert(f(x));
1104}
1105
1106pub broadcast proof fn lemma_mod_add_multiples_vanish(b: int, m: int)
1109 requires
1110 0 < m,
1111 ensures
1112 (m + b) % m == #[trigger] (b % m),
1113{
1114 lemma_mod_auto(m);
1115}
1116
1117pub broadcast proof fn lemma_mod_sub_multiples_vanish(b: int, m: int)
1120 requires
1121 0 < m,
1122 ensures
1123 (-m + b) % m == #[trigger] (b % m),
1124{
1125 lemma_mod_auto(m);
1126}
1127
1128#[verifier::spinoff_prover]
1131pub broadcast proof fn lemma_mod_multiples_vanish(a: int, b: int, m: int)
1132 requires
1133 0 < m,
1134 ensures
1135 #[trigger] ((m * a + b) % m) == b % m,
1136 decreases
1137 (if a > 0 {
1138 a
1139 } else {
1140 -a
1141 }),
1142{
1143 lemma_mod_auto(m);
1144 broadcast use group_mul_properties_internal;
1145
1146 let f = |u: int| (m * u + b) % m == b % m;
1147 lemma_mul_induction(f);
1148 assert(f(a));
1149}
1150
1151pub broadcast proof fn lemma_mod_subtraction(x: nat, s: nat, d: nat)
1156 requires
1157 0 < d,
1158 0 <= s <= x % d,
1159 ensures
1160 #![trigger ((x - s) % d as int)]
1161 x % d - s % d == (x - s) % d as int,
1162{
1163 lemma_mod_auto(d as int);
1164}
1165
1166pub broadcast proof fn lemma_add_mod_noop(x: int, y: int, m: int)
1170 requires
1171 0 < m,
1172 ensures
1173 #![trigger (x + y) % m]
1174 ((x % m) + (y % m)) % m == (x + y) % m,
1175{
1176 lemma_mod_auto(m);
1177}
1178
1179pub broadcast proof fn lemma_add_mod_noop_right(x: int, y: int, m: int)
1183 requires
1184 0 < m,
1185 ensures
1186 #![trigger (x + y) % m]
1187 (x + (y % m)) % m == (x + y) % m,
1188{
1189 lemma_mod_auto(m);
1190}
1191
1192pub broadcast proof fn lemma_sub_mod_noop(x: int, y: int, m: int)
1196 requires
1197 0 < m,
1198 ensures
1199 #![trigger (x - y) % m]
1200 ((x % m) - (y % m)) % m == (x - y) % m,
1201{
1202 lemma_mod_auto(m);
1203}
1204
1205pub broadcast proof fn lemma_sub_mod_noop_right(x: int, y: int, m: int)
1209 requires
1210 0 < m,
1211 ensures
1212 #![trigger ((x - y) % m)]
1213 (x - (y % m)) % m == (x - y) % m,
1214{
1215 lemma_mod_auto(m);
1216}
1217
1218pub broadcast proof fn lemma_mod_adds(a: int, b: int, d: int)
1222 requires
1223 0 < d,
1224 ensures
1225 #![trigger ((a + b) % d)]
1226 a % d + b % d == (a + b) % d + d * ((a % d + b % d) / d),
1227 (a % d + b % d) < d ==> a % d + b % d == (a + b) % d,
1228{
1229 broadcast use group_mul_properties_internal;
1230
1231 lemma_div_auto(d);
1232}
1233
1234#[verifier::spinoff_prover]
1238pub proof fn lemma_mod_neg_neg(x: int, d: int)
1239 requires
1240 0 < d,
1241 ensures
1242 x % d == (x * (1 - d)) % d,
1243{
1244 broadcast use group_mul_properties_internal;
1245
1246 assert((x - x * d) % d == x % d) by {
1247 let f = |i: int| (x - i * d) % d == x % d;
1248 assert(f(0) && (forall|i: int| i >= 0 && #[trigger] f(i) ==> #[trigger] f(add1(i, 1))) && (
1249 forall|i: int| i <= 0 && #[trigger] f(i) ==> #[trigger] f(sub1(i, 1)))) by {
1250 lemma_mod_auto(d);
1251 };
1252 lemma_mul_induction(f);
1253 assert(f(x));
1254 }
1255
1256}
1257
1258proof fn lemma_fundamental_div_mod_converse_helper_1(u: int, d: int, r: int)
1261 requires
1262 d != 0,
1263 0 <= r < d,
1264 ensures
1265 u == (u * d + r) / d,
1266 decreases
1267 if u >= 0 {
1268 u
1269 } else {
1270 -u
1271 },
1272{
1273 if u < 0 {
1274 lemma_fundamental_div_mod_converse_helper_1(u + 1, d, r);
1275 lemma_div_add_denominator(d, u * d + r);
1276 lemma_mul_is_distributive_add_other_way(d, u + 1, -1);
1277 assert(u == (u * d + r) / d);
1278 } else if u == 0 {
1279 DivINL::lemma_small_div();
1280 assert(u == 0 ==> u * d == 0) by (nonlinear_arith);
1281 assert(u == (u * d + r) / d);
1282 } else {
1283 lemma_fundamental_div_mod_converse_helper_1(u - 1, d, r);
1284 lemma_div_add_denominator(d, (u - 1) * d + r);
1285 lemma_mul_is_distributive_add_other_way(d, u - 1, 1);
1286 assert(u * d + r == (u - 1) * d + r + d);
1287 assert(u == (u * d + r) / d);
1288 }
1289}
1290
1291proof fn lemma_fundamental_div_mod_converse_helper_2(u: int, d: int, r: int)
1294 requires
1295 d != 0,
1296 0 <= r < d,
1297 ensures
1298 r == (u * d + r) % d,
1299 decreases
1300 if u >= 0 {
1301 u
1302 } else {
1303 -u
1304 },
1305{
1306 if u < 0 {
1307 lemma_fundamental_div_mod_converse_helper_2(u + 1, d, r);
1308 lemma_mod_add_multiples_vanish(u * d + r, d);
1309 lemma_mul_is_distributive_add_other_way(d, u + 1, -1);
1310 assert(u * d == (u + 1) * d + (-1) * d);
1311 assert(u * d + r == (u + 1) * d + r - d);
1312 assert(r == (u * d + r) % d);
1313 } else if u == 0 {
1314 assert(u == 0 ==> u * d == 0) by (nonlinear_arith);
1315 if d > 0 {
1316 lemma_small_mod(r as nat, d as nat);
1317 } else {
1318 lemma_small_mod(r as nat, (-d) as nat);
1319 }
1320 assert(r == (u * d + r) % d);
1321 } else {
1322 lemma_fundamental_div_mod_converse_helper_2(u - 1, d, r);
1323 lemma_mod_add_multiples_vanish((u - 1) * d + r, d);
1324 lemma_mul_is_distributive_add_other_way(d, u - 1, 1);
1325 assert(u * d + r == (u - 1) * d + r + d);
1326 assert(r == (u * d + r) % d);
1327 }
1328}
1329
1330pub broadcast proof fn lemma_fundamental_div_mod_converse_mod(x: int, d: int, q: int, r: int)
1334 requires
1335 d != 0,
1336 0 <= r < d,
1337 x == #[trigger] (q * d + r),
1338 ensures
1339 r == #[trigger] (x % d),
1340{
1341 lemma_fundamental_div_mod_converse_helper_1(q, d, r);
1342 assert(q == (q * d + r) / d);
1343 lemma_fundamental_div_mod_converse_helper_2(q, d, r);
1344}
1345
1346pub broadcast proof fn lemma_fundamental_div_mod_converse_div(x: int, d: int, q: int, r: int)
1350 requires
1351 d != 0,
1352 0 <= r < d,
1353 x == #[trigger] (q * d + r),
1354 ensures
1355 q == #[trigger] (x / d),
1356{
1357 lemma_fundamental_div_mod_converse_helper_1(q, d, r);
1358 assert(q == (q * d + r) / d);
1359 lemma_fundamental_div_mod_converse_helper_2(q, d, r);
1360}
1361
1362pub proof fn lemma_fundamental_div_mod_converse(x: int, d: int, q: int, r: int)
1366 requires
1367 d != 0,
1368 0 <= r < d,
1369 x == q * d + r,
1370 ensures
1371 r == x % d,
1372 q == x / d,
1373{
1374 lemma_fundamental_div_mod_converse_mod(x, d, q, r);
1375 lemma_fundamental_div_mod_converse_div(x, d, q, r);
1376}
1377
1378pub broadcast group group_fundamental_div_mod_converse {
1379 lemma_fundamental_div_mod_converse_mod,
1380 lemma_fundamental_div_mod_converse_div,
1381}
1382
1383pub broadcast proof fn lemma_mod_pos_bound(x: int, m: int)
1386 requires
1387 0 <= x,
1388 0 < m,
1389 ensures
1390 0 <= #[trigger] (x % m) < m,
1391{
1392 lemma_mod_auto(m);
1393}
1394
1395pub broadcast proof fn lemma_mod_bound(x: int, m: int)
1398 requires
1399 0 < m,
1400 ensures
1401 0 <= #[trigger] (x % m) < m,
1402{
1403 ModINL::lemma_mod_range(x, m);
1404}
1405
1406pub broadcast proof fn lemma_mul_mod_noop_left(x: int, y: int, m: int)
1409 requires
1410 0 < m,
1411 ensures
1412 (x % m) * y % m == #[trigger] (x * y % m),
1413{
1414 lemma_mod_auto(m);
1415 lemma_mul_induction_auto(y, |u: int| (x % m) * u % m == x * u % m);
1416}
1417
1418pub broadcast proof fn lemma_mul_mod_noop_right(x: int, y: int, m: int)
1421 requires
1422 0 < m,
1423 ensures
1424 x * (y % m) % m == #[trigger] ((x * y) % m),
1425{
1426 lemma_mod_auto(m);
1427 lemma_mul_induction_auto(x, |u: int| u * (y % m) % m == (u * y) % m);
1428}
1429
1430pub broadcast proof fn lemma_mul_mod_noop_general(x: int, y: int, m: int)
1434 requires
1435 0 < m,
1436 ensures
1437 ((x % m) * y) % m == (x * y) % m,
1438 (x * (y % m)) % m == (x * y) % m,
1439 ((x % m) * (y % m)) % m == #[trigger] ((x * y) % m),
1440{
1441 lemma_mul_mod_noop_left(x, y, m);
1442 lemma_mul_mod_noop_right(x, y, m);
1443 lemma_mul_mod_noop_right(x % m, y, m);
1444}
1445
1446pub broadcast proof fn lemma_mul_mod_noop(x: int, y: int, m: int)
1450 requires
1451 0 < m,
1452 ensures
1453 (x % m) * (y % m) % m == #[trigger] ((x * y) % m),
1454{
1455 lemma_mul_mod_noop_general(x, y, m);
1456}
1457
1458pub broadcast proof fn lemma_mod_equivalence(x: int, y: int, m: int)
1466 requires
1467 0 < m,
1468 ensures
1469 #![trigger (x - y) % m]
1470 x % m == y % m <==> (x - y) % m == 0,
1471{
1472 lemma_mod_auto(m);
1473}
1474
1475pub open spec fn is_mod_equivalent(x: int, y: int, m: int) -> bool
1478 recommends
1479 m > 0,
1480{
1481 x % m == y % m <==> (x - y) % m == 0
1482}
1483
1484pub broadcast proof fn lemma_mod_mul_equivalent(x: int, y: int, z: int, m: int)
1487 requires
1488 m > 0,
1489 is_mod_equivalent(x, y, m),
1490 ensures
1491 #[trigger] is_mod_equivalent(x * z, y * z, m),
1492{
1493 lemma_mul_mod_noop_left(x, z, m);
1494 lemma_mul_mod_noop_left(y, z, m);
1495 lemma_mod_equivalence(x, y, m);
1496 lemma_mod_equivalence(x * z, y * z, m);
1497}
1498
1499pub broadcast proof fn lemma_mod_ordering(x: int, k: int, d: int)
1503 requires
1504 1 < d,
1505 0 < k,
1506 ensures
1507 0 < d * k,
1508 x % d <= #[trigger] (x % (d * k)),
1509{
1510 lemma_mul_strictly_increases(d, k);
1511 calc! {
1512 (==)
1513 x % d + d * (x / d); {
1514 lemma_fundamental_div_mod(x, d);
1515 }
1516 x; {
1517 lemma_fundamental_div_mod(x, d * k);
1518 }
1519 x % (d * k) + (d * k) * (x / (d * k)); {
1520 broadcast use lemma_mul_is_associative;
1521
1522 }
1523 x % (d * k) + d * (k * (x / (d * k)));
1524 }
1525 calc! {
1526 (==)
1527 x % d; {
1528 broadcast use group_mod_properties;
1529
1530 }
1531 (x % d) % d; {
1532 lemma_mod_multiples_vanish(x / d - k * (x / (d * k)), x % d, d);
1533 }
1534 (x % d + d * (x / d - k * (x / (d * k)))) % d; {
1535 broadcast use lemma_mul_is_distributive_sub;
1536
1537 }
1538 (x % d + d * (x / d) - d * (k * (x / (d * k)))) % d; {}
1539 (x % (d * k)) % d;
1540 }
1541 assert((x % (d * k)) % d <= x % (d * k)) by {
1542 broadcast use group_mod_properties;
1543
1544 lemma_mod_decreases((x % (d * k)) as nat, d as nat);
1545 };
1546}
1547
1548pub broadcast proof fn lemma_mod_mod(x: int, a: int, b: int)
1552 requires
1553 0 < a,
1554 0 < b,
1555 ensures
1556 #![trigger (x % (a * b)) % a, x % a]
1557 0 < a * b,
1558 (x % (a * b)) % a == x % a,
1559{
1560 broadcast use lemma_mul_strictly_positive;
1561
1562 calc! {
1563 (==)
1564 x; {
1565 lemma_fundamental_div_mod(x, a * b);
1566 }
1567 (a * b) * (x / (a * b)) + x % (a * b); {
1568 broadcast use lemma_mul_is_associative;
1569
1570 }
1571 a * (b * (x / (a * b))) + x % (a * b); {
1572 lemma_fundamental_div_mod(x % (a * b), a);
1573 }
1574 a * (b * (x / (a * b))) + a * (x % (a * b) / a) + (x % (a * b)) % a; {
1575 broadcast use group_mul_is_distributive;
1576
1577 }
1578 a * (b * (x / (a * b)) + x % (a * b) / a) + (x % (a * b)) % a;
1579 }
1580 broadcast use {group_mod_properties, lemma_mul_is_commutative};
1581
1582 lemma_fundamental_div_mod_converse(
1583 x,
1584 a,
1585 b * (x / (a * b)) + x % (a * b) / a,
1586 (x % (a * b)) % a,
1587 );
1588}
1589
1590pub broadcast proof fn lemma_part_bound2(x: int, y: int, z: int)
1592 requires
1593 0 <= x,
1594 0 < y,
1595 0 < z,
1596 ensures
1597 y * z > 0,
1598 #[trigger] (x % y) % #[trigger] (y * z) < y,
1599{
1600 broadcast use {
1601 lemma_mul_strictly_positive,
1602 group_mod_properties,
1603 lemma_mul_is_commutative,
1604 lemma_mul_increases,
1605 };
1606
1607 assert(x % y < y);
1608 assert(y <= y * z);
1609 assert(0 <= x % y < y * z);
1610 lemma_small_mod((x % y) as nat, (y * z) as nat);
1611 assert((x % y) % (y * z) == x % y);
1612}
1613
1614pub broadcast proof fn lemma_mod_breakdown(x: int, y: int, z: int)
1617 requires
1618 0 <= x,
1619 0 < y,
1620 0 < z,
1621 ensures
1622 #![trigger x % (y * z)]
1623 y * z > 0,
1624 x % (y * z) == y * ((x / y) % z) + x % y,
1625{
1626 broadcast use lemma_mul_strictly_positive;
1627
1628 lemma_div_pos_is_pos(x, y);
1629 assert(0 <= x / y);
1630 assert((y * (x / y)) % (y * z) + (x % y) % (y * z) < y * z) by {
1631 lemma_part_bound1(x, y, z);
1632 lemma_part_bound2(x, y, z);
1633 broadcast use {group_mul_basics, group_mul_is_distributive};
1634
1635 };
1636 calc! {
1637 (==)
1638 x % (y * z); {
1639 lemma_fundamental_div_mod(x, y);
1640 }
1641 (y * (x / y) + x % y) % (y * z); {
1642 broadcast use group_mod_properties;
1643
1644 assert(0 <= x % y);
1645 lemma_mul_nonnegative(y, x / y);
1646 assert((y * (x / y)) % (y * z) + (x % y) % (y * z) < y * z);
1647 lemma_mod_adds(y * (x / y), x % y, y * z);
1648 }
1649 (y * (x / y)) % (y * z) + (x % y) % (y * z); {
1650 broadcast use {group_mod_properties, lemma_mul_is_commutative};
1651
1652 lemma_mul_increases(z, y);
1653 assert(x % y < y && y <= y * z);
1654 lemma_small_mod((x % y) as nat, (y * z) as nat);
1655 assert((x % y) % (y * z) == x % y);
1656 }
1657 (y * (x / y)) % (y * z) + x % y; {
1658 lemma_truncate_middle(x / y, y, z);
1659 }
1660 y * ((x / y) % z) + x % y;
1661 }
1662}
1663
1664}