Skip to main content

vstd/arithmetic/
div_mod.rs

1//! This file contains proofs related to integer division (`/`) and
2//! remainder aka mod (`%`). These are part of the math standard library.
3//!
4//! It's based on the following file from the Dafny math standard
5//! library:
6//! `Source/DafnyStandardLibraries/src/Std/Arithmetic/DivMod.dfy`.
7//! That file has the following copyright notice:
8//! /*******************************************************************************
9//! * Original: Copyright (c) Microsoft Corporation *
10//! SPDX-License-Identifier: MIT * * Modifications and Extensions:
11//! Copyright by the contributors to the Dafny Project *
12//! SPDX-License-Identifier: MIT
13//! *******************************************************************************/
14use super::super::calc_macro::*;
15#[allow(unused_imports)]
16use super::super::prelude::*;
17
18verus! {
19
20#[verifier::inline]
21pub open spec fn rust_div(a: int, b: int) -> int
22    recommends
23        b != 0,
24{
25    if a == 0 {
26        0
27    } else if a > 0 {
28        a / b
29    } else {
30        -((-a) / b)
31    }
32}
33
34#[verifier::inline]
35pub open spec fn rust_rem(a: int, b: int) -> int
36    recommends
37        b != 0,
38{
39    if a == 0 {
40        0
41    } else if a > 0 {
42        a % b
43    } else {
44        -((-a) % b)
45    }
46}
47
48#[allow(unused_imports)]
49#[cfg(verus_keep_ghost)]
50use super::super::arithmetic::internals::div_internals::{
51    div_recursive,
52    lemma_div_induction_auto,
53    div_auto,
54    div_pos,
55    lemma_div_auto,
56};
57use super::super::arithmetic::internals::div_internals_nonlinear as DivINL;
58#[cfg(verus_keep_ghost)]
59use super::super::arithmetic::internals::mod_internals::{
60    lemma_div_add_denominator,
61    lemma_mod_auto,
62    mod_recursive,
63};
64use super::super::arithmetic::internals::mod_internals_nonlinear as ModINL;
65#[cfg(verus_keep_ghost)]
66use super::internals::mul_internals::{
67    group_mul_properties_internal,
68    lemma_mul_induction,
69    lemma_mul_induction_auto,
70};
71#[cfg(verus_keep_ghost)]
72use super::super::arithmetic::internals::general_internals::{is_le};
73#[cfg(verus_keep_ghost)]
74use super::super::math::{add as add1, sub as sub1, div as div1};
75use super::super::arithmetic::mul::*;
76
77/*****************************************************************************
78* Division
79*****************************************************************************/
80
81/// Proof that, for the case of `x / d`, division using `/` is
82/// equivalent to a recursive definition of division.
83pub broadcast proof fn lemma_div_is_div_recursive(x: int, d: int)
84    requires
85        0 < d,
86    ensures
87        div_recursive(x, d) == #[trigger] (x / d),
88{
89    reveal(div_recursive);
90    reveal(div_pos);
91    lemma_div_induction_auto(d, x, |u: int| div_recursive(u, d) == u / d);
92}
93
94/// Proof that the quotient of an integer divided by itself is 1,
95/// specifically that `d / d == 1`.
96pub proof fn lemma_div_by_self(d: int)
97    requires
98        d != 0,
99    ensures
100        d / d == 1,
101{
102    DivINL::lemma_div_by_self(d);
103}
104
105/// Proof that 0 divided by a nonzero integer is 0, specifically `0 / d == 0`.
106pub proof fn lemma_div_of0(d: int)
107    requires
108        d != 0,
109    ensures
110        0 as int / d == 0,
111{
112    DivINL::lemma_div_of0(d);
113}
114
115/// Proof establishing basic properties of division using `x`: 0
116/// divided by `x` is 0; `x` divided by 1 is itself; and `x` divided
117/// by itself is 1.
118pub proof fn lemma_div_basics(x: int)
119    ensures
120        x != 0 as int ==> 0 as int / x == 0,
121        x / 1 == x,
122        x != 0 ==> x / x == 1,
123{
124    if (x != 0) {
125        lemma_div_by_self(x);
126        lemma_div_of0(x);
127    }
128}
129
130/// Proof for basic property that 0 divided by `x` is 0.
131pub broadcast proof fn lemma_div_basics_1(x: int)
132    ensures
133        x != 0 as int ==> #[trigger] (0int / x) == 0,
134{
135    lemma_div_basics(x);
136}
137
138/// Proof for basic property that `x` divided by 1 is `x`.
139pub broadcast proof fn lemma_div_basics_2(x: int)
140    ensures
141        #[trigger] (x / 1) == x,
142{
143    lemma_div_basics(x);
144}
145
146/// Proof for basic property that `x` divided by `x` is 1.
147pub broadcast proof fn lemma_div_basics_3(x: int)
148    ensures
149        x != 0 ==> #[trigger] (x / x) == 1,
150{
151    lemma_div_basics(x);
152}
153
154/// Proof that dividing any non-negative integer by a positive integer is non-zero.
155pub broadcast proof fn lemma_div_basics_4(x: int, y: int)
156    ensures
157        x >= 0 && y > 0 ==> #[trigger] (x / y) >= 0,
158{
159}
160
161/// Proof that the quotient produced by dividing any non-negative integer `x`
162/// by a positive integer `y` is at most `x`.
163pub broadcast proof fn lemma_div_basics_5(x: int, y: int)
164    ensures
165        x >= 0 && y > 0 ==> #[trigger] (x / y) <= x,
166{
167    assert forall|x: int, y: int| x >= 0 && y > 0 implies 0 <= #[trigger] (x / y) <= x by {
168        lemma_div_pos_is_pos(x, y);
169        lemma_div_is_ordered_by_denominator(x, 1, y);
170    };
171}
172
173pub broadcast group group_div_basics {
174    lemma_div_basics_1,
175    lemma_div_basics_2,
176    lemma_div_basics_3,
177    lemma_div_basics_4,
178    lemma_div_basics_5,
179}
180
181/// Proof that if a dividend is a whole number, the divisor is a
182/// natural number, and their quotient is 0, then the dividend is
183/// smaller than the divisor.
184pub broadcast proof fn lemma_small_div_converse(x: int, d: int)
185    ensures
186        0 <= x && 0 < d && #[trigger] (x / d) == 0 ==> x < d,
187{
188    assert forall|x: int, d: int| 0 <= x && 0 < d && #[trigger] (x / d) == 0 implies x < d by {
189        lemma_div_induction_auto(d, x, |u: int| 0 <= u && 0 < d && u / d == 0 ==> u < d);
190    }
191}
192
193/// Proof that division of a positive integer by a positive integer
194/// less than or equal to it is nonzero. Specifically,
195/// given that `x >= d`, we can conclude that `x / d > 0`.
196pub proof fn lemma_div_non_zero(x: int, d: int)
197    requires
198        x >= d > 0,
199    ensures
200        #[trigger] (x / d) > 0,
201{
202    broadcast use lemma_div_pos_is_pos;
203
204    if x / d == 0 {
205        broadcast use lemma_small_div_converse;
206
207    }
208}
209
210/// Proof that given two fractions with the same numerator, the order
211/// of the fractions is determined by the denominators. However, if
212/// the numerator is 0, the fractions are equal regardless of the
213/// denominators' values. Specifically, given that `1 <= y <= z`, we
214/// know `x / y >= x / z`.
215pub broadcast proof fn lemma_div_is_ordered_by_denominator(x: int, y: int, z: int)
216    requires
217        0 <= x,
218        1 <= y <= z,
219    ensures
220        #[trigger] (x / y) >= #[trigger] (x / z),
221    decreases x,
222{
223    reveal(div_recursive);
224    reveal(div_pos);
225    broadcast use lemma_div_is_div_recursive;
226
227    assert(forall|u: int, d: int|
228        #![trigger div_recursive(u, d)]
229        #![trigger div1(u, d)]
230        d > 0 ==> div_recursive(u, d) == div1(u, d));
231    if (x < z) {
232        lemma_div_is_ordered(0, x, y);
233    } else {
234        lemma_div_is_ordered(x - z, x - y, y);
235        lemma_div_is_ordered_by_denominator(x - z, y, z);
236    }
237}
238
239/// Proof that a number gets strictly smaller when divided by a number
240/// greater than one. Specifically, `x / d < x`.
241pub broadcast proof fn lemma_div_is_strictly_smaller(x: int, d: int)
242    requires
243        0 < x,
244        1 < d,
245    ensures
246        #[trigger] (x / d) < x,
247    decreases x,
248{
249    lemma_div_induction_auto(d, x, |u: int| 0 < u ==> u / d < u);
250}
251
252/// Proof that, given `r == a % d + b % d - (a + b) % d`, `r` can also
253/// be expressed as `d * ((a + b) / d) - d * (a / d) - d * (b / d)`.
254pub broadcast proof fn lemma_dividing_sums(a: int, b: int, d: int, r: int)
255    requires
256        0 < d,
257        r == a % d + b % d - (a + b) % d,
258    ensures
259        #![trigger (d * ((a + b) / d) - r), (d * (a / d) + d * (b / d))]
260        d * ((a + b) / d) - r == d * (a / d) + d * (b / d),
261{
262    ModINL::lemma_fundamental_div_mod(a + b, d);
263    ModINL::lemma_fundamental_div_mod(a, d);
264    ModINL::lemma_fundamental_div_mod(b, d);
265}
266
267/// Proof that dividing a whole number by a natural number will result
268/// in a quotient that is greater than or equal to 0. Specifically,
269/// `x / d >= 0`.
270pub broadcast proof fn lemma_div_pos_is_pos(x: int, d: int)
271    requires
272        0 <= x,
273        0 < d,
274    ensures
275        0 <= #[trigger] (x / d),
276{
277    lemma_div_auto(d);
278    assert(div_auto(d));
279    let f = |u: int| 0 <= u ==> u / d >= 0;
280    assert forall|i: int| #[trigger] is_le(0, i) && f(i) implies f(i + d) by {
281        assert(i / d >= 0);
282    };
283    lemma_div_induction_auto(d, x, |u: int| 0 <= u ==> u / d >= 0);
284}
285
286/// Proof that dividing a number then adding 1 gives the same result
287/// as adding the divisor and then doing the division. Specifically,
288/// `1 + (x / d)` is equal to `(d + x) / d`.
289pub broadcast proof fn lemma_div_plus_one(x: int, d: int)
290    requires
291        0 < d,
292    ensures
293        #![trigger (1 + x / d), ((d + x) / d)]
294        1 + x / d == (d + x) / d,
295{
296    lemma_div_auto(d);
297}
298
299/// Proof that dividing a number then subtracting 1 gives the same result
300/// as subtracting the divisor and then doing the division. Specifically,
301/// `-1 + (x / d)` is equal to `(-d + x) / d`.
302pub broadcast proof fn lemma_div_minus_one(x: int, d: int)
303    requires
304        0 < d,
305    ensures
306        #![trigger (-1 + x / d), ((-d + x) / d)]
307        -1 + x / d == (-d + x) / d,
308{
309    lemma_div_auto(d);
310}
311
312/// Proof that dividing any non-negative integer less than `d` by `d`
313/// produces a quotient of 0.
314pub proof fn lemma_basic_div_specific_divisor(d: int)
315    requires
316        0 < d,
317    ensures
318        forall|x: int| 0 <= x < d ==> #[trigger] (x / d) == 0,
319{
320    lemma_div_auto(d);
321}
322
323/// Proof that dividing any non-negative integer by a larger integer
324/// produces a quotient of 0.
325pub broadcast proof fn lemma_basic_div(x: int, d: int)
326    requires
327        0 <= x < d,
328    ensures
329        #[trigger] (x / d) == 0,
330{
331    lemma_basic_div_specific_divisor(d);
332}
333
334/// Proof that numerical order is preserved when dividing two seperate
335/// integers by a common positive divisor. Specifically, given that
336/// `z > 0` and `x <= y`, we know `x / z <= y / z`.
337pub broadcast proof fn lemma_div_is_ordered(x: int, y: int, z: int)
338    requires
339        x <= y,
340        0 < z,
341    ensures
342        #[trigger] (x / z) <= #[trigger] (y / z),
343{
344    lemma_div_auto(z);
345    let f = |xy: int| xy <= 0 ==> (xy + y) / z <= y / z;
346    assert forall|i: int| #[trigger] is_le(i + 1, z) && f(i) implies f(i - z) by {
347        if (i - z <= 0) {
348            assert(f(i));
349            assert(i <= 0 ==> (i + y) / z <= y / z);
350            if (i > 0) {
351                assert(z > 0);
352                assert(i <= z);
353                assert(((i + y) - z) / z <= y / z);
354            } else {
355                assert((i + y) / z <= y / z);
356            }
357            assert((i - z + y) / z <= y / z);
358        }
359    };
360    lemma_div_induction_auto(z, x - y, |xy: int| xy <= 0 ==> (xy + y) / z <= y / z);
361}
362
363/// Proof that dividing an integer by 2 or more results in a quotient
364/// that is smaller than the original dividend. Specifically, `x / d < x`.
365pub broadcast proof fn lemma_div_decreases(x: int, d: int)
366    requires
367        0 < x,
368        1 < d,
369    ensures
370        #[trigger] (x / d) < x,
371{
372    lemma_div_induction_auto(d, x, |u: int| 0 < u ==> u / d < u);
373}
374
375/// Proof that dividing an integer by 1 or more results in a quotient
376/// that is less than or equal to the original dividend. Specifically,
377/// `x / d <= x`.
378pub broadcast proof fn lemma_div_nonincreasing(x: int, d: int)
379    requires
380        0 <= x,
381        0 < d,
382    ensures
383        #[trigger] (x / d) <= x,
384{
385    lemma_div_induction_auto(d, x, |u: int| 0 <= u ==> u / d <= u);
386}
387
388/// Proof that a natural number x divided by a larger natural number
389/// gives a remainder equal to x. Specifically, because `x < m`, we
390/// know `x % m == x`.
391pub proof fn lemma_small_mod(x: nat, m: nat)
392    requires
393        x < m,
394        0 < m,
395    ensures
396        x % m == x,
397{
398    ModINL::lemma_small_mod(x, m);
399}
400
401/// The remainder of a nonnegative integer `x` divided by the product of two positive integers
402/// `y` and `z` is equivalent to dividing `x` by `y`, dividing the quotient by `z`, multiplying
403/// the remainder by `y`, and then adding the product to the remainder of `x` divided by `y`.
404/// In mathematical terms, `(x % (y * z)) == y * ((x / y) % z) + x % y`.
405pub broadcast proof fn lemma_breakdown(x: int, y: int, z: int)
406    requires
407        0 <= x,
408        0 < y,
409        0 < z,
410    ensures
411        #![trigger y * z, x % (y * z), y * ((x / y) % z) + x % y]
412        0 < y * z,
413        (x % (y * z)) == y * ((x / y) % z) + x % y,
414{
415    broadcast use lemma_mul_strictly_positive;
416
417    lemma_div_pos_is_pos(x, y);
418    calc! {
419        (<)
420        (y * (x / y)) % (y * z) + (x % y) % (y * z); (<=) {
421            lemma_part_bound1(x, y, z);
422        }
423        y * (z - 1) + (x % y) % (y * z); (<) {
424            lemma_part_bound2(x, y, z);
425        }
426        y * (z - 1) + y; (==) {
427            broadcast use group_mul_basics;
428
429        }
430        y * (z - 1) + y * 1; (==) {
431            broadcast use group_mul_is_distributive;
432
433        }
434        y * (z - 1 + 1); (==) {}
435        y * z;
436    }
437    calc! {
438        (==)
439        x % (y * z); {
440            ModINL::lemma_fundamental_div_mod(x, y);
441        }
442        (y * (x / y) + x % y) % (y * z); {
443            broadcast use group_mod_properties;
444
445            assert(0 <= x % y);
446            lemma_mul_nonnegative(y, x / y);
447            assert((y * (x / y)) % (y * z) + (x % y) % (y * z) < y * z);
448            lemma_mod_adds(y * (x / y), x % y, y * z);
449        }
450        (y * (x / y)) % (y * z) + (x % y) % (y * z); {
451            broadcast use {group_mod_properties, lemma_mul_is_commutative};
452
453            lemma_mul_increases(z, y);
454            // comparison op can't be chained in calc!
455            // assert forall is also not avaialable in calc!
456            assert((x % y) < y && y <= (y * z));
457            lemma_small_mod((x % y) as nat, (y * z) as nat);
458            assert((x % y) % (y * z) == x % y);
459        }
460        (y * (x / y)) % (y * z) + x % y; {
461            lemma_truncate_middle(x / y, y, z);
462        }
463        y * ((x / y) % z) + x % y;
464    }
465}
466
467/// Proof that the difference between a nonnegative integer `x` and a
468/// positive integer `d` must be strictly less than the quotient of
469/// `x` divided by `d` and then multiplied by `d`.
470pub broadcast proof fn lemma_remainder_upper(x: int, d: int)
471    requires
472        0 <= x,
473        0 < d,
474    ensures
475        #![trigger (x - d), (x / d * d)]
476        x - d < x / d * d,
477{
478    broadcast use group_mul_properties_internal;
479
480    lemma_div_induction_auto(d, x, |u: int| 0 <= u ==> u - d < u / d * d);
481}
482
483/// Proof that the division of a nonnegative integer `x` by a positive
484/// integer `d` multiplied by `d` is less than or equal to the value
485/// of `x`.
486pub broadcast proof fn lemma_remainder_lower(x: int, d: int)
487    requires
488        0 <= x,
489        0 < d,
490    ensures
491        x >= #[trigger] (x / d * d),
492{
493    broadcast use group_mul_properties_internal;
494
495    lemma_div_induction_auto(d, x, |u: int| 0 <= u ==> u >= u / d * d);
496}
497
498/// Proof that the difference between a nonnegative integer `x` and
499/// the division of `x` by a positive integer `d` multiplied by `d` is
500/// lower bounded (inclusively) by 0 and upper bounded (exclusively)
501/// by `d`.
502pub broadcast proof fn lemma_remainder(x: int, d: int)
503    requires
504        0 <= x,
505        0 < d,
506    ensures
507        0 <= #[trigger] (x - (x / d * d)) < d,
508{
509    broadcast use group_mul_properties_internal;
510
511    lemma_div_induction_auto(d, x, |u: int| 0 <= u - u / d * d < d);
512}
513
514/// Proof of the fundamental theorem of division and modulo, namely
515/// that `x` can be expressed as `d` times the quotient `x / d` plus
516/// the remainder `x % d`.
517pub broadcast proof fn lemma_fundamental_div_mod(x: int, d: int)
518    requires
519        d != 0,
520    ensures
521        x == #[trigger] (d * (x / d) + (x % d)),
522{
523    assert(x == d * (x / d) + (x % d)) by {
524        ModINL::lemma_fundamental_div_mod(x, d);
525    }
526}
527
528/// Proof that dividing `x` by `c * d` is equivalent to first dividing
529/// `x` by `c` and then dividing the result by `d`.
530pub broadcast proof fn lemma_div_denominator(x: int, c: int, d: int)
531    requires
532        0 <= x,
533        0 < c,
534        0 < d,
535    ensures
536        c * d != 0,
537        #[trigger] ((x / c) / d) == x / (c * d),
538{
539    lemma_mul_strictly_positive(c, d);
540    let r = x % (c as int * d as int);
541    lemma_div_pos_is_pos(r, c as int);
542    if (r / c as int >= d) {
543        ModINL::lemma_fundamental_div_mod(r, c as int);
544        lemma_mul_inequality(d as int, r / c as int, c as int);
545        lemma_mul_is_commutative(d, c);
546    }
547    assert(r / (c as int) < d);
548    lemma_fundamental_div_mod_converse(r / c, d, 0, r / c);
549    assert((r / c as int) % d as int == r / c as int);
550    lemma_fundamental_div_mod(r, c);
551    assert(c * (r / c) + r % c == r);
552    assert(c * ((r / c as int) % d as int) + r % c as int == r);
553    let k = x / (c as int * d as int);
554    lemma_fundamental_div_mod(x, c * d);
555    assert(x == (c * d) * (x / (c * d)) + x % (c * d));
556    assert(r == x - (c * d) * (x / (c * d)));
557    assert(r == x - (c * d) * k);
558    calc! {
559        (==)
560        c * ((x / c) % d) + x % c; {
561            broadcast use lemma_mul_is_commutative;
562
563            lemma_mod_multiples_vanish(-k, x / c, d);
564        }
565        c * ((x / c + (-k) * d) % d) + x % c; {
566            lemma_hoist_over_denominator(x, (-k) * d, c as nat);
567        }
568        c * (((x + (((-k) * d) * c)) / c) % d) + x % c; {
569            lemma_mul_is_associative(-k, d, c);
570        }
571        c * (((x + ((-k) * (d * c))) / c) % d) + x % c; {
572            lemma_mul_unary_negation(k, d * c);
573        }
574        c * (((x + (-(k * (d * c)))) / c) % d) + x % c; {
575            lemma_mul_is_associative(k, d, c);
576        }
577        c * (((x + (-(k * d * c))) / c) % d) + x % c; {}
578        c * (((x - k * d * c) / c) % d) + x % c; {
579            broadcast use {lemma_mul_is_associative, lemma_mul_is_commutative};
580
581        }
582        c * ((r / c) % d) + x % c; {}
583        c * (r / c) + x % c; {
584            lemma_fundamental_div_mod(r, c);
585            assert(r == c * (r / c) + r % c);
586            lemma_mod_mod(x, c, d);
587            assert(r % c == x % c);
588        }
589        r; {
590            broadcast use {group_mod_properties, lemma_mod_is_mod_recursive};
591
592        }
593        r % (c * d); {}
594        (x - (c * d) * k) % (c * d); {
595            lemma_mul_unary_negation(c * d, k);
596        }
597        (x + (c * d) * (-k)) % (c * d); {
598            lemma_mod_multiples_vanish(-k, x, c * d);
599        }
600        x % (c * d);
601    }
602    assert(c * (x / c) + x % c - r == c * (x / c) - c * ((x / c) % d) ==> x - r == c * (x / c) - c
603        * ((x / c) % d)) by {
604        lemma_fundamental_div_mod(x, c);
605    };
606    assert(c * (x / c) + x % c - r == c * (x / c) - c * ((x / c) % d));
607    assert(x - r == c * (x / c) - c * ((x / c) % d));
608    assert((x / c) / d == x / (c * d)) by {
609        lemma_fundamental_div_mod(x / c, d);
610        assert(d * ((x / c) / d) == x / c - ((x / c) % d));
611        lemma_fundamental_div_mod(x, c * d);
612        assert(x == (c * d) * (x / (c * d)) + (x % (c * d)));
613        lemma_mul_is_distributive_sub(c, x / c, (x / c) % d);
614        assert(c * (d * ((x / c) / d)) == c * (x / c) - c * ((x / c) % d));
615        lemma_mul_is_associative(c, d, (x / c) / d);
616        assert((c * d) * ((x / c) / d) == c * (x / c) - c * ((x / c) % d));
617        assert((c * d) * ((x / c) / d) == x - r);
618        assert((c * d) * ((x / c) / d) == (c * d) * (x / (c * d)));
619        lemma_mul_equality_converse(c * d, (x / c) / d, x / (c * d));
620    }
621    assert(c * d != 0) by {
622        assert(0 < c * d);
623    }
624    assert(c * d != 0);  // work around https://github.com/Z3Prover/z3/issues/8057
625}
626
627/// Proof that multiplying an integer by a fraction is equivalent to
628/// multiplying the fraction's numerator by the integer. Specifically,
629/// `x * (y / z) == (x * y) / z`.
630pub broadcast proof fn lemma_mul_hoist_inequality(x: int, y: int, z: int)
631    requires
632        0 <= x,
633        0 < z,
634    ensures
635        #![trigger (x * (y / z)), ((x * y) / z)]
636        x * (y / z) <= (x * y) / z,
637{
638    calc! {
639        (==)
640        (x * y) / z; (==) {
641            lemma_fundamental_div_mod(y, z);
642        }
643        (x * (z * (y / z) + y % z)) / z; (==) {
644            broadcast use group_mul_is_distributive;
645
646        }
647        (x * (z * (y / z)) + x * (y % z)) / z;
648    }
649    assert((x * (z * (y / z)) + x * (y % z)) / z >= x * (y / z)) by {
650        broadcast use {group_mod_properties, lemma_mul_is_associative, lemma_mul_is_commutative};
651
652        lemma_mul_nonnegative(x, y % z);
653        lemma_div_is_ordered(x * (z * (y / z)), x * (z * (y / z)) + x * (y % z), z);
654        lemma_div_multiples_vanish(x * (y / z), z);
655    };
656}
657
658/// Proof that for a positive integer `d`, if `a - a % d` is less than
659/// or equal to `b` and `b` is less than `a + d - a % d`, then the
660/// quotient of `a` divided by `d` is equivalent to the quotient of
661/// `b` divided by `d`.
662///
663/// In other words, if `a` and `b` occur between the same two
664/// multiples of `d`, then their quotient with `d` is equivalent.
665pub broadcast proof fn lemma_indistinguishable_quotients(a: int, b: int, d: int)
666    requires
667        0 < d,
668        0 <= a - a % d <= b < a + d - a % d,
669    ensures
670        #![trigger (a / d), (b / d)]
671        a / d == b / d,
672{
673    lemma_div_induction_auto(
674        d,
675        a - b,
676        |ab: int|
677            {
678                let u = ab + b;
679                0 <= u - u % d <= b < u + d - u % d ==> u / d == b / d
680            },
681    );
682}
683
684/// Proof that common factors from the dividend and divisor of a
685/// modulus operation can be factored out. Specifically,
686/// `(b * x) % (b * c) == b * (x % c)`.
687pub proof fn lemma_truncate_middle(x: int, b: int, c: int)
688    requires
689        0 <= x,
690        0 < b,
691        0 < c,
692    ensures
693        #![trigger (b * (x % c))]
694        0 < b * c,
695        (b * x) % (b * c) == b * (x % c),
696{
697    broadcast use {lemma_mul_strictly_positive, lemma_mul_nonnegative};
698
699    calc! {
700        (==)
701        b * x; {
702            ModINL::lemma_fundamental_div_mod(b * x, b * c);
703        }
704        (b * c) * ((b * x) / (b * c)) + (b * x) % (b * c); {
705            lemma_div_denominator(b * x, b, c);
706        }
707        (b * c) * (((b * x) / b) / c) + (b * x) % (b * c); {
708            broadcast use lemma_mul_is_commutative;
709
710            lemma_div_by_multiple(x, b);
711        }
712        (b * c) * (x / c) + (b * x) % (b * c);
713    }
714    assert(b * x == (b * c) * (x / c) + b * (x % c)) by {
715        ModINL::lemma_fundamental_div_mod(x, c);
716        broadcast use {group_mul_is_distributive, lemma_mul_is_associative};
717
718    };
719}
720
721/// Proof that multiplying the numerator and denominator by an integer
722/// does not change the quotient. Specifically,
723/// `a / d == (x * a) / (x * d)`.
724pub broadcast proof fn lemma_div_multiples_vanish_quotient(x: int, a: int, d: int)
725    requires
726        0 < x,
727        0 <= a,
728        0 < d,
729    ensures
730        #![trigger a / d, x * a, x * d]
731        0 < x * d,
732        a / d == (x * a) / (x * d),
733{
734    lemma_mul_strictly_positive(x, d);
735    calc! {
736        (==)
737        (x * a) / (x * d); {
738            lemma_mul_nonnegative(x, a);
739            lemma_div_denominator(x * a, x, d);
740        }
741        ((x * a) / x) / d; {
742            lemma_div_multiples_vanish(a, x);
743        }
744        a / d;
745    }
746}
747
748/// Proof that, since `a % d == 0` and `0 <= r < d`, we can conclude
749/// `a == d * (a + r) / d`.
750#[verifier::spinoff_prover]
751pub broadcast proof fn lemma_round_down(a: int, r: int, d: int)
752    requires
753        0 < d,
754        a % d == 0,
755        0 <= r < d,
756    ensures
757        #![trigger (d * ((a + r) / d))]
758        a == d * ((a + r) / d),
759{
760    broadcast use group_mul_properties_internal;
761
762    lemma_div_induction_auto(d, a, |u: int| u % d == 0 ==> u == d * ((u + r) / d));
763}
764
765/// Proof that, since `0 <= b < d`, we have `(d * x + b) / d == x`.
766pub broadcast proof fn lemma_div_multiples_vanish_fancy(x: int, b: int, d: int)
767    requires
768        0 < d,
769        0 <= b < d,
770    ensures
771        #![trigger (d * x + b) / d]
772        (d * x + b) / d == x,
773{
774    let f = |u: int| (d * u + b) / d == u;
775    assert(f(0)) by {
776        lemma_div_auto(d);
777    }
778    assert forall|i: int| i >= 0 && #[trigger] f(i) implies #[trigger] f(add1(i, 1)) by {
779        assert(d * (i + 1) + b == d * i + b + d) by {
780            assert(d * (i + 1) == d * i + d) by {
781                lemma_mul_is_distributive_add(d, i, 1);
782                lemma_mul_basics(d);
783            }
784        }
785        super::internals::div_internals::lemma_div_basics(d);
786    }
787    assert forall|i: int| i <= 0 && #[trigger] f(i) implies #[trigger] f(sub1(i, 1)) by {
788        assert(d * (i - 1) + b == d * i + b - d) by {
789            assert(d * (i - 1) == d * i - d) by {
790                lemma_mul_is_distributive_sub(d, i, 1);
791                lemma_mul_basics(d);
792            }
793        }
794        super::internals::div_internals::lemma_div_basics(d);
795    }
796    broadcast use group_mul_properties_internal;
797
798    lemma_mul_induction(f);
799    assert(f(x));
800}
801
802/// Proof that multiplying an integer by a common numerator and
803/// denominator results in the original integer. Specifically,
804/// `(d * x) / d == x`.
805pub broadcast proof fn lemma_div_multiples_vanish(x: int, d: int)
806    requires
807        0 < d,
808    ensures
809        #![trigger (d * x) / d]
810        (d * x) / d == x,
811{
812    lemma_div_multiples_vanish_fancy(x, 0, d);
813}
814
815/// Proof that multiplying a whole number by a common numerator and
816/// denominator results in the original integer. Specifically,
817/// `(b * d) / d == b`.
818pub broadcast proof fn lemma_div_by_multiple(b: int, d: int)
819    requires
820        0 <= b,
821        0 < d,
822    ensures
823        #![trigger ((b * d) / d)]
824        (b * d) / d == b,
825{
826    lemma_div_multiples_vanish(b, d);
827    broadcast use group_mul_properties_internal;
828
829}
830
831/// Proof that a dividend that is a positive multiple of a divisor
832/// will always yield a greater quotient than a smaller dividend.
833/// Specifically, `x / z < y / z` because `y == m * z` and `x < y`.
834pub broadcast proof fn lemma_div_by_multiple_is_strongly_ordered(x: int, y: int, m: int, z: int)
835    requires
836        x < y,
837        y == m * z,
838        0 < z,
839    ensures
840        #![trigger x / z, m * z, y / z]
841        x / z < y / z,
842{
843    lemma_mod_multiples_basic(m, z);
844    lemma_div_induction_auto(
845        z,
846        y - x,
847        |yx: int|
848            {
849                let u = yx + x;
850                x < u && u % z == 0 ==> x / z < u / z
851            },
852    );
853}
854
855/// Proof that if an integer is less than or equal to the product of
856/// two other integers, then the quotient with one of them will be
857/// less than or equal to the other of them. Specifically, because
858/// `a <= b * c`, we know `a / b <= c`.
859pub broadcast proof fn lemma_multiply_divide_le(a: int, b: int, c: int)
860    requires
861        0 < b,
862        a <= b * c,
863    ensures
864        #![trigger a / b, b * c]
865        a / b <= c,
866{
867    lemma_mod_multiples_basic(c, b);
868    let f = |i: int| 0 <= i && (i + a) % b == 0 ==> a / b <= (i + a) / b;
869    lemma_div_induction_auto(b, b * c - a, f);
870    lemma_div_multiples_vanish(c, b);
871}
872
873/// Proof that if an integer is less than the product of two other
874/// integers, then the quotient with one of them will be less than the
875/// other. Specifically, because `a < b * c`, we know `a / b < c`.
876pub broadcast proof fn lemma_multiply_divide_lt(a: int, b: int, c: int)
877    requires
878        0 < b,
879        a < b * c,
880    ensures
881        #![trigger a / b, b * c]
882        a / b < c,
883{
884    assert(((b * c - a) + a) % b == 0 ==> a / b < ((b * c - a) + a) / b) by {
885        let f = |i: int| 0 < i && (i + a) % b == 0 ==> a / b < (i + a) / b;
886        lemma_div_induction_auto(b, b * c - a, f);
887    }
888    assert(b * c == c * b) by {
889        lemma_mul_is_commutative(b, c);
890    }
891    assert((b * c) % b == 0) by {
892        lemma_mod_multiples_basic(c, b);
893    }
894    assert((b * c) / b == c) by {
895        lemma_div_multiples_vanish(c, b);
896    }
897}
898
899/// Proof that adding an integer to a fraction is equivalent to adding
900/// that integer times the denominator to the numerator. Specifically,
901/// `x / d + j == (x + j * d) / d`.
902pub broadcast proof fn lemma_hoist_over_denominator(x: int, j: int, d: nat)
903    requires
904        0 < d,
905    ensures
906        #![trigger x / d as int + j]
907        x / d as int + j == (x + j * d) / d as int,
908{
909    let dd = d as int;
910    let q = x / dd;
911    let r = x % dd;
912    assert(x == dd * q + r) by {
913        lemma_fundamental_div_mod(x, dd);
914    }
915    assert(j * dd == dd * j) by {
916        lemma_mul_is_commutative(j, dd);
917    }
918    assert(x + j * dd == dd * (q + j) + r) by {
919        lemma_mul_is_distributive_add(dd, q, j);
920    }
921    assert((x + j * dd) / dd == q + j) by {
922        lemma_fundamental_div_mod_converse(x + j * d, dd, q + j, r);
923    }
924}
925
926/// Proof that, for nonnegative integer `a` and positive integers `b` and `c`,
927/// the remainder of `b * (a / b)` divided by `b * c` is less than or equal to `b * (c - 1)`.
928/// This accounts for the rounding down that occurs in integer division.
929pub broadcast proof fn lemma_part_bound1(a: int, b: int, c: int)
930    requires
931        0 <= a,
932        0 < b,
933        0 < c,
934    ensures
935        #![trigger (b * (a / b) % (b * c))]
936        0 < b * c,
937        (b * (a / b) % (b * c)) <= b * (c - 1),
938{
939    lemma_mul_strictly_positive(b, a / b);
940    lemma_mul_strictly_positive(b, c);
941    lemma_mul_strictly_positive(b, c - 1);
942    calc! {
943        (==)
944        b * (a / b) % (b * c); {
945            ModINL::lemma_fundamental_div_mod(b * (a / b), b * c);
946        }
947        b * (a / b) - (b * c) * ((b * (a / b)) / (b * c)); {
948            broadcast use lemma_mul_is_associative;
949
950        }
951        b * (a / b) - b * (c * ((b * (a / b)) / (b * c))); {
952            broadcast use group_mul_is_distributive;
953
954        }
955        b * ((a / b) - (c * ((b * (a / b)) / (b * c))));
956    }
957    assert(b * (a / b) % (b * c) <= b * (c - 1)) by {
958        broadcast use {lemma_mul_is_commutative, lemma_mul_inequality};
959
960    };
961}
962
963/*******************************************************************************
964* Modulus
965*******************************************************************************/
966
967/// Proof that computing the modulus using `%` is equivalent to
968/// computing it with a recursive definition of modulus. Specifically,
969/// `x % m` is equivalent in that way.
970pub broadcast proof fn lemma_mod_is_mod_recursive(x: int, m: int)
971    requires
972        m > 0,
973    ensures
974        mod_recursive(x, m) == #[trigger] (x % m),
975    decreases
976            (if x < 0 {
977                -x + m
978            } else {
979                x
980            }),
981{
982    reveal(mod_recursive);
983    if x < 0 {
984        calc! {
985            (==)
986            mod_recursive(x, m); {}
987            mod_recursive(x + m, m); {
988                lemma_mod_is_mod_recursive(x + m, m);
989            }
990            (x + m) % m; {
991                lemma_add_mod_noop(x, m, m);
992            }
993            ((x % m) + (m % m)) % m; {
994                broadcast use {lemma_mod_self_0, lemma_mod_twice};
995
996            }
997            (x % m) % m; {
998                broadcast use {lemma_mod_self_0, lemma_mod_twice};
999
1000            }
1001            x % m;
1002        }
1003    } else if x < m {
1004        lemma_small_mod(x as nat, m as nat);
1005    } else {
1006        calc! {
1007            (==)
1008            mod_recursive(x, m); {}
1009            mod_recursive(x - m, m); {
1010                lemma_mod_is_mod_recursive(x - m, m);
1011            }
1012            (x - m) % m; {
1013                lemma_sub_mod_noop(x, m, m);
1014            }
1015            ((x % m) - (m % m)) % m; {
1016                broadcast use {lemma_mod_self_0, lemma_mod_twice};
1017
1018            }
1019            (x % m) % m; {
1020                broadcast use {lemma_mod_self_0, lemma_mod_twice};
1021
1022            }
1023            x % m;
1024        }
1025    }
1026}
1027
1028/// Proof that any integer divided by itself produces a remainder of 0.
1029pub broadcast proof fn lemma_mod_self_0(m: int)
1030    requires
1031        m > 0,
1032    ensures
1033        #[trigger] (m % m) == 0,
1034{
1035    lemma_mod_auto(m);
1036}
1037
1038/// Proof that performing `(x % m) % m` gives the same result as simply perfoming `x % m`.
1039pub broadcast proof fn lemma_mod_twice(x: int, m: int)
1040    requires
1041        m > 0,
1042    ensures
1043        #[trigger] ((x % m) % m) == x % m,
1044{
1045    lemma_mod_auto(m);
1046}
1047
1048pub broadcast group group_mod_basics {
1049    lemma_mod_self_0,
1050    lemma_mod_twice,
1051}
1052
1053/// Proof that the remainder of any division will be less than the divisor's value.
1054pub broadcast proof fn lemma_mod_division_less_than_divisor(x: int, m: int)
1055    requires
1056        m > 0,
1057    ensures
1058        0 <= #[trigger] (x % m) < m,
1059{
1060    lemma_mod_auto(m);
1061}
1062
1063pub broadcast group group_mod_properties {
1064    group_mod_basics,
1065    lemma_mod_division_less_than_divisor,
1066}
1067
1068/// Proof that when natural number `x` is divided by natural number
1069/// `m`, the remainder will be less than or equal to `x`.
1070pub broadcast proof fn lemma_mod_decreases(x: nat, m: nat)
1071    requires
1072        0 < m,
1073    ensures
1074        #[trigger] (x % m) <= x,
1075{
1076    lemma_mod_auto(m as int);
1077}
1078
1079/// Proof that if `x % m` is zero and `x` is positive, then `x >= m`.
1080pub broadcast proof fn lemma_mod_is_zero(x: nat, m: nat)
1081    requires
1082        x > 0 && m > 0,
1083        #[trigger] (x % m) == 0,
1084    ensures
1085        x >= m,
1086{
1087    if (x < m) {
1088        lemma_small_mod(x, m);
1089    }
1090}
1091
1092/// Proof that multiplying by a number then dividing by that same
1093/// number produces a remainder of 0. Specifically, `(x * m) % m == 0`.
1094#[verifier::spinoff_prover]
1095pub broadcast proof fn lemma_mod_multiples_basic(x: int, m: int)
1096    requires
1097        m > 0,
1098    ensures
1099        #[trigger] ((x * m) % m) == 0,
1100{
1101    lemma_mod_auto(m);
1102    broadcast use group_mul_properties_internal;
1103
1104    let f = |u: int| (u * m) % m == 0;
1105    lemma_mul_induction(f);
1106    assert(f(x));
1107}
1108
1109/// Proof that adding the divisor to the dividend doesn't change the
1110/// remainder. Specifically, `(m + b) % m == b % m`.
1111pub broadcast proof fn lemma_mod_add_multiples_vanish(b: int, m: int)
1112    requires
1113        0 < m,
1114    ensures
1115        (m + b) % m == #[trigger] (b % m),
1116{
1117    lemma_mod_auto(m);
1118}
1119
1120/// Proof that subtracting the divisor from the dividend doesn't
1121/// change the remainder. Specifically, `(-m + b) % m == b % m`.
1122pub broadcast proof fn lemma_mod_sub_multiples_vanish(b: int, m: int)
1123    requires
1124        0 < m,
1125    ensures
1126        (-m + b) % m == #[trigger] (b % m),
1127{
1128    lemma_mod_auto(m);
1129}
1130
1131/// Proof that adding any multiple of the divisor to the dividend will produce the
1132/// same remainder. In other words, `(m * a + b) % m == b % m`.
1133#[verifier::spinoff_prover]
1134pub broadcast proof fn lemma_mod_multiples_vanish(a: int, b: int, m: int)
1135    requires
1136        0 < m,
1137    ensures
1138        #[trigger] ((m * a + b) % m) == b % m,
1139    decreases
1140            (if a > 0 {
1141                a
1142            } else {
1143                -a
1144            }),
1145{
1146    lemma_mod_auto(m);
1147    broadcast use group_mul_properties_internal;
1148
1149    let f = |u: int| (m * u + b) % m == b % m;
1150    lemma_mul_induction(f);
1151    assert(f(a));
1152}
1153
1154/// Proof that modulo distributes over subtraction if the subtracted value is
1155/// less than or equal to the modulo of the number it's being subtracted from.
1156/// Specifically, because `0 <= s <= x % d`, we can conclude that
1157/// `x % d - s % d == (x - s) % d`.
1158pub broadcast proof fn lemma_mod_subtraction(x: nat, s: nat, d: nat)
1159    requires
1160        0 < d,
1161        0 <= s <= x % d,
1162    ensures
1163        #![trigger ((x - s) % d as int)]
1164        x % d - s % d == (x - s) % d as int,
1165{
1166    lemma_mod_auto(d as int);
1167}
1168
1169/// Proof that modulo distributes over addition, provided you do an
1170/// extra modulo after adding the remainders. Specifically,
1171/// `((x % m) + (y % m)) % m == (x + y) % m`.
1172pub broadcast proof fn lemma_add_mod_noop(x: int, y: int, m: int)
1173    requires
1174        0 < m,
1175    ensures
1176        #![trigger (x + y) % m]
1177        ((x % m) + (y % m)) % m == (x + y) % m,
1178{
1179    lemma_mod_auto(m);
1180}
1181
1182/// Proof that describes an expanded and succinct version of modulus
1183/// operator in relation to addition. Specifically,
1184/// `(x + (y % m)) % m == (x + y) % m`.
1185pub broadcast proof fn lemma_add_mod_noop_right(x: int, y: int, m: int)
1186    requires
1187        0 < m,
1188    ensures
1189        #![trigger (x + y) % m]
1190        (x + (y % m)) % m == (x + y) % m,
1191{
1192    lemma_mod_auto(m);
1193}
1194
1195/// Proof that modulo distributes over subtraction provided you do an
1196/// extra modulo operation after subtracting the remainders.
1197/// Specifically, `((x % m) - (y % m)) % m == (x - y) % m`.
1198pub broadcast proof fn lemma_sub_mod_noop(x: int, y: int, m: int)
1199    requires
1200        0 < m,
1201    ensures
1202        #![trigger (x - y) % m]
1203        ((x % m) - (y % m)) % m == (x - y) % m,
1204{
1205    lemma_mod_auto(m);
1206}
1207
1208/// Proof that describes an expanded and succinct version of modulus
1209/// operator in relation to subtraction. Specifically,
1210/// `(x - (y % m)) % m == (x - y) % m`.
1211pub broadcast proof fn lemma_sub_mod_noop_right(x: int, y: int, m: int)
1212    requires
1213        0 < m,
1214    ensures
1215        #![trigger ((x - y) % m)]
1216        (x - (y % m)) % m == (x - y) % m,
1217{
1218    lemma_mod_auto(m);
1219}
1220
1221/// Proof of two properties of the sum of two remainders with the same dividend:
1222/// 1) `a % d + b % d == (a + b) % d + d * ((a % d + b % d) / d)`.
1223/// 2) `(a % d + b % d) < d ==> a % d + b % d == (a + b) % d`.
1224pub broadcast proof fn lemma_mod_adds(a: int, b: int, d: int)
1225    requires
1226        0 < d,
1227    ensures
1228        #![trigger ((a + b) % d)]
1229        a % d + b % d == (a + b) % d + d * ((a % d + b % d) / d),
1230        (a % d + b % d) < d ==> a % d + b % d == (a + b) % d,
1231{
1232    broadcast use group_mul_properties_internal;
1233
1234    lemma_div_auto(d);
1235}
1236
1237/// Proof that the remainder when dividing integer `x` by positive
1238/// integer `d` is equivalent to the remainder of `x * (1 - d)` by
1239/// `d`.
1240#[verifier::spinoff_prover]
1241pub proof fn lemma_mod_neg_neg(x: int, d: int)
1242    requires
1243        0 < d,
1244    ensures
1245        x % d == (x * (1 - d)) % d,
1246{
1247    broadcast use group_mul_properties_internal;
1248
1249    assert((x - x * d) % d == x % d) by {
1250        let f = |i: int| (x - i * d) % d == x % d;
1251        assert(f(0) && (forall|i: int| i >= 0 && #[trigger] f(i) ==> #[trigger] f(add1(i, 1))) && (
1252        forall|i: int| i <= 0 && #[trigger] f(i) ==> #[trigger] f(sub1(i, 1)))) by {
1253            lemma_mod_auto(d);
1254        };
1255        lemma_mul_induction(f);
1256        assert(f(x));
1257    }
1258
1259}
1260
1261/// This proof isn't exported from this module. It's just used in
1262/// the proof of [`lemma_fundamental_div_mod_converse`].
1263proof fn lemma_fundamental_div_mod_converse_helper_1(u: int, d: int, r: int)
1264    requires
1265        d != 0,
1266        0 <= r < d,
1267    ensures
1268        u == (u * d + r) / d,
1269    decreases
1270            if u >= 0 {
1271                u
1272            } else {
1273                -u
1274            },
1275{
1276    if u < 0 {
1277        lemma_fundamental_div_mod_converse_helper_1(u + 1, d, r);
1278        lemma_div_add_denominator(d, u * d + r);
1279        lemma_mul_is_distributive_add_other_way(d, u + 1, -1);
1280        assert(u == (u * d + r) / d);
1281    } else if u == 0 {
1282        DivINL::lemma_small_div();
1283        assert(u == 0 ==> u * d == 0) by (nonlinear_arith);
1284        assert(u == (u * d + r) / d);
1285    } else {
1286        lemma_fundamental_div_mod_converse_helper_1(u - 1, d, r);
1287        lemma_div_add_denominator(d, (u - 1) * d + r);
1288        lemma_mul_is_distributive_add_other_way(d, u - 1, 1);
1289        assert(u * d + r == (u - 1) * d + r + d);
1290        assert(u == (u * d + r) / d);
1291    }
1292}
1293
1294/// This proof isn't exported from this module. It's just used in
1295/// the proof of [`lemma_fundamental_div_mod_converse`].
1296proof fn lemma_fundamental_div_mod_converse_helper_2(u: int, d: int, r: int)
1297    requires
1298        d != 0,
1299        0 <= r < d,
1300    ensures
1301        r == (u * d + r) % d,
1302    decreases
1303            if u >= 0 {
1304                u
1305            } else {
1306                -u
1307            },
1308{
1309    if u < 0 {
1310        lemma_fundamental_div_mod_converse_helper_2(u + 1, d, r);
1311        lemma_mod_add_multiples_vanish(u * d + r, d);
1312        lemma_mul_is_distributive_add_other_way(d, u + 1, -1);
1313        assert(u * d == (u + 1) * d + (-1) * d);
1314        assert(u * d + r == (u + 1) * d + r - d);
1315        assert(r == (u * d + r) % d);
1316    } else if u == 0 {
1317        assert(u == 0 ==> u * d == 0) by (nonlinear_arith);
1318        if d > 0 {
1319            lemma_small_mod(r as nat, d as nat);
1320        } else {
1321            lemma_small_mod(r as nat, (-d) as nat);
1322        }
1323        assert(r == (u * d + r) % d);
1324    } else {
1325        lemma_fundamental_div_mod_converse_helper_2(u - 1, d, r);
1326        lemma_mod_add_multiples_vanish((u - 1) * d + r, d);
1327        lemma_mul_is_distributive_add_other_way(d, u - 1, 1);
1328        assert(u * d + r == (u - 1) * d + r + d);
1329        assert(r == (u * d + r) % d);
1330    }
1331}
1332
1333/// Proof of the converse of the fundamental property of division and modulo.
1334/// Specifically, if we know `0 <= r < d` and `x == q * d + r`, then we
1335/// know that `r` is the remainder `x % d`.
1336pub broadcast proof fn lemma_fundamental_div_mod_converse_mod(x: int, d: int, q: int, r: int)
1337    requires
1338        d != 0,
1339        0 <= r < d,
1340        x == #[trigger] (q * d + r),
1341    ensures
1342        r == #[trigger] (x % d),
1343{
1344    lemma_fundamental_div_mod_converse_helper_1(q, d, r);
1345    assert(q == (q * d + r) / d);
1346    lemma_fundamental_div_mod_converse_helper_2(q, d, r);
1347}
1348
1349/// Proof of the converse of the fundamental property of division and modulo.
1350/// Specifically, if we know `0 <= r < d` and `x == q * d + r`, then we
1351/// know that `q` is the quotient `x / d`.
1352pub broadcast proof fn lemma_fundamental_div_mod_converse_div(x: int, d: int, q: int, r: int)
1353    requires
1354        d != 0,
1355        0 <= r < d,
1356        x == #[trigger] (q * d + r),
1357    ensures
1358        q == #[trigger] (x / d),
1359{
1360    lemma_fundamental_div_mod_converse_helper_1(q, d, r);
1361    assert(q == (q * d + r) / d);
1362    lemma_fundamental_div_mod_converse_helper_2(q, d, r);
1363}
1364
1365/// Proof of the converse of the fundamental property of division and modulo.
1366/// Specifically, if we know `0 <= r < d` and `x == q * d + r`, then we
1367/// know that `q` is the quotient `x / d` and `r` is the remainder `x % d`.
1368pub proof fn lemma_fundamental_div_mod_converse(x: int, d: int, q: int, r: int)
1369    requires
1370        d != 0,
1371        0 <= r < d,
1372        x == q * d + r,
1373    ensures
1374        r == x % d,
1375        q == x / d,
1376{
1377    lemma_fundamental_div_mod_converse_mod(x, d, q, r);
1378    lemma_fundamental_div_mod_converse_div(x, d, q, r);
1379}
1380
1381pub broadcast group group_fundamental_div_mod_converse {
1382    lemma_fundamental_div_mod_converse_mod,
1383    lemma_fundamental_div_mod_converse_div,
1384}
1385
1386/// Proof that the remainder, when natural number `x` is divided by
1387/// positive integer `m`, is less than `m`.
1388pub broadcast proof fn lemma_mod_pos_bound(x: int, m: int)
1389    requires
1390        0 <= x,
1391        0 < m,
1392    ensures
1393        0 <= #[trigger] (x % m) < m,
1394{
1395    lemma_mod_auto(m);
1396}
1397
1398/// Proof that when integer `x` is divided by positive integer `m`,
1399/// the remainder is nonegative and less than `m`.
1400pub broadcast proof fn lemma_mod_bound(x: int, m: int)
1401    requires
1402        0 < m,
1403    ensures
1404        0 <= #[trigger] (x % m) < m,
1405{
1406    ModINL::lemma_mod_range(x, m);
1407}
1408
1409/// Proof that the remainder when `x * y` is divided by `m` is
1410/// equivalent to the remainder when `(x % m) * y` is divided by `m`.
1411pub broadcast proof fn lemma_mul_mod_noop_left(x: int, y: int, m: int)
1412    requires
1413        0 < m,
1414    ensures
1415        (x % m) * y % m == #[trigger] (x * y % m),
1416{
1417    lemma_mod_auto(m);
1418    lemma_mul_induction_auto(y, |u: int| (x % m) * u % m == x * u % m);
1419}
1420
1421/// Proof that the remainder when `x * y` is divided by `m` is
1422/// equivalent to the remainder when `x * (y % m)` is divided by `m`.
1423pub broadcast proof fn lemma_mul_mod_noop_right(x: int, y: int, m: int)
1424    requires
1425        0 < m,
1426    ensures
1427        x * (y % m) % m == #[trigger] ((x * y) % m),
1428{
1429    lemma_mod_auto(m);
1430    lemma_mul_induction_auto(x, |u: int| u * (y % m) % m == (u * y) % m);
1431}
1432
1433/// Proof of various properties about modulo equivalence with respect
1434/// to multiplication, specifically various expressions that `(x * y)
1435/// % m` is equivalent to.
1436pub broadcast proof fn lemma_mul_mod_noop_general(x: int, y: int, m: int)
1437    requires
1438        0 < m,
1439    ensures
1440        ((x % m) * y) % m == (x * y) % m,
1441        (x * (y % m)) % m == (x * y) % m,
1442        ((x % m) * (y % m)) % m == #[trigger] ((x * y) % m),
1443{
1444    lemma_mul_mod_noop_left(x, y, m);
1445    lemma_mul_mod_noop_right(x, y, m);
1446    lemma_mul_mod_noop_right(x % m, y, m);
1447}
1448
1449/// Proof that modulo distributes over multiplication, provided you do
1450/// an extra modulo operation after multiplying the remainders. Specifically,
1451/// `(x % m) * (y % m) % m == (x * y) % m`.
1452pub broadcast proof fn lemma_mul_mod_noop(x: int, y: int, m: int)
1453    requires
1454        0 < m,
1455    ensures
1456        (x % m) * (y % m) % m == #[trigger] ((x * y) % m),
1457{
1458    lemma_mul_mod_noop_general(x, y, m);
1459}
1460
1461/// Proof that `x` and `y` are congruent modulo `m` if and only if `x
1462/// - y` is congruent to 0 modulo `m`. In other words, `x % m == y % m
1463/// <==> (x - y) % m == 0`.
1464///
1465/// Note: The Dafny standard library uses the triggers `x % m, y % m`
1466/// for the broadcasted forall quantifier. But this can lead to a trigger loop,
1467/// so we don't do that here.
1468pub broadcast proof fn lemma_mod_equivalence(x: int, y: int, m: int)
1469    requires
1470        0 < m,
1471    ensures
1472        #![trigger (x - y) % m]
1473        x % m == y % m <==> (x - y) % m == 0,
1474{
1475    lemma_mod_auto(m);
1476}
1477
1478/// This function says that `x` is congruent to `y` modulo `m` if and
1479/// only if their difference `x - y` is congruent to 0 modulo `m`.
1480pub open spec fn is_mod_equivalent(x: int, y: int, m: int) -> bool
1481    recommends
1482        m > 0,
1483{
1484    x % m == y % m <==> (x - y) % m == 0
1485}
1486
1487/// Proof that if `is_mod_equivalent` holds for `x`, `y`, and `m`,
1488/// then it holds for `x * z`, `y * z`, and `m`.
1489pub broadcast proof fn lemma_mod_mul_equivalent(x: int, y: int, z: int, m: int)
1490    requires
1491        m > 0,
1492        is_mod_equivalent(x, y, m),
1493    ensures
1494        #[trigger] is_mod_equivalent(x * z, y * z, m),
1495{
1496    lemma_mul_mod_noop_left(x, z, m);
1497    lemma_mul_mod_noop_left(y, z, m);
1498    lemma_mod_equivalence(x, y, m);
1499    lemma_mod_equivalence(x * z, y * z, m);
1500}
1501
1502/// Proof that multiplying the divisor by a positive number can't
1503/// decrease the remainder. Specifically, because `k > 0`, we have
1504/// `x % d <= x % (d * k)`.
1505pub broadcast proof fn lemma_mod_ordering(x: int, k: int, d: int)
1506    requires
1507        1 < d,
1508        0 < k,
1509    ensures
1510        0 < d * k,
1511        x % d <= #[trigger] (x % (d * k)),
1512{
1513    lemma_mul_strictly_increases(d, k);
1514    calc! {
1515        (==)
1516        x % d + d * (x / d); {
1517            lemma_fundamental_div_mod(x, d);
1518        }
1519        x; {
1520            lemma_fundamental_div_mod(x, d * k);
1521        }
1522        x % (d * k) + (d * k) * (x / (d * k)); {
1523            broadcast use lemma_mul_is_associative;
1524
1525        }
1526        x % (d * k) + d * (k * (x / (d * k)));
1527    }
1528    calc! {
1529        (==)
1530        x % d; {
1531            broadcast use group_mod_properties;
1532
1533        }
1534        (x % d) % d; {
1535            lemma_mod_multiples_vanish(x / d - k * (x / (d * k)), x % d, d);
1536        }
1537        (x % d + d * (x / d - k * (x / (d * k)))) % d; {
1538            broadcast use lemma_mul_is_distributive_sub;
1539
1540        }
1541        (x % d + d * (x / d) - d * (k * (x / (d * k)))) % d; {}
1542        (x % (d * k)) % d;
1543    }
1544    assert((x % (d * k)) % d <= x % (d * k)) by {
1545        broadcast use group_mod_properties;
1546
1547        lemma_mod_decreases((x % (d * k)) as nat, d as nat);
1548    };
1549}
1550
1551/// Proof that the remainder when `x` is divided by `a * b`, taken
1552/// modulo `a`, is equivalent to `x` modulo `a`. That is,
1553/// `(x % (a * b)) % a == x % a`.
1554pub broadcast proof fn lemma_mod_mod(x: int, a: int, b: int)
1555    requires
1556        0 < a,
1557        0 < b,
1558    ensures
1559        #![trigger (x % (a * b)) % a, x % a]
1560        0 < a * b,
1561        (x % (a * b)) % a == x % a,
1562{
1563    broadcast use lemma_mul_strictly_positive;
1564
1565    calc! {
1566        (==)
1567        x; {
1568            lemma_fundamental_div_mod(x, a * b);
1569        }
1570        (a * b) * (x / (a * b)) + x % (a * b); {
1571            broadcast use lemma_mul_is_associative;
1572
1573        }
1574        a * (b * (x / (a * b))) + x % (a * b); {
1575            lemma_fundamental_div_mod(x % (a * b), a);
1576        }
1577        a * (b * (x / (a * b))) + a * (x % (a * b) / a) + (x % (a * b)) % a; {
1578            broadcast use group_mul_is_distributive;
1579
1580        }
1581        a * (b * (x / (a * b)) + x % (a * b) / a) + (x % (a * b)) % a;
1582    }
1583    broadcast use {group_mod_properties, lemma_mul_is_commutative};
1584
1585    lemma_fundamental_div_mod_converse(
1586        x,
1587        a,
1588        b * (x / (a * b)) + x % (a * b) / a,
1589        (x % (a * b)) % a,
1590    );
1591}
1592
1593/// Proof that `(x % y) % (y * z) < y`.
1594pub broadcast proof fn lemma_part_bound2(x: int, y: int, z: int)
1595    requires
1596        0 <= x,
1597        0 < y,
1598        0 < z,
1599    ensures
1600        y * z > 0,
1601        #[trigger] (x % y) % #[trigger] (y * z) < y,
1602{
1603    broadcast use {
1604        lemma_mul_strictly_positive,
1605        group_mod_properties,
1606        lemma_mul_is_commutative,
1607        lemma_mul_increases,
1608    };
1609
1610    assert(x % y < y);
1611    assert(y <= y * z);
1612    assert(0 <= x % y < y * z);
1613    lemma_small_mod((x % y) as nat, (y * z) as nat);
1614    assert((x % y) % (y * z) == x % y);
1615}
1616
1617/// Proof of the validity of an expanded form of the modulus operation.
1618/// Specifically, `x % (y * z) == y * ((x / y) % z) + x % y`.
1619pub broadcast proof fn lemma_mod_breakdown(x: int, y: int, z: int)
1620    requires
1621        0 <= x,
1622        0 < y,
1623        0 < z,
1624    ensures
1625        #![trigger x % (y * z)]
1626        y * z > 0,
1627        x % (y * z) == y * ((x / y) % z) + x % y,
1628{
1629    broadcast use lemma_mul_strictly_positive;
1630
1631    lemma_div_pos_is_pos(x, y);
1632    assert(0 <= x / y);
1633    assert((y * (x / y)) % (y * z) + (x % y) % (y * z) < y * z) by {
1634        lemma_part_bound1(x, y, z);
1635        lemma_part_bound2(x, y, z);
1636        broadcast use {group_mul_basics, group_mul_is_distributive};
1637
1638    };
1639    calc! {
1640        (==)
1641        x % (y * z); {
1642            lemma_fundamental_div_mod(x, y);
1643        }
1644        (y * (x / y) + x % y) % (y * z); {
1645            broadcast use group_mod_properties;
1646
1647            assert(0 <= x % y);
1648            lemma_mul_nonnegative(y, x / y);
1649            assert((y * (x / y)) % (y * z) + (x % y) % (y * z) < y * z);
1650            lemma_mod_adds(y * (x / y), x % y, y * z);
1651        }
1652        (y * (x / y)) % (y * z) + (x % y) % (y * z); {
1653            broadcast use {group_mod_properties, lemma_mul_is_commutative};
1654
1655            lemma_mul_increases(z, y);
1656            assert(x % y < y && y <= y * z);
1657            lemma_small_mod((x % y) as nat, (y * z) as nat);
1658            assert((x % y) % (y * z) == x % y);
1659        }
1660        (y * (x / y)) % (y * z) + x % y; {
1661            lemma_truncate_middle(x / y, y, z);
1662        }
1663        y * ((x / y) % z) + x % y;
1664    }
1665}
1666
1667} // verus!