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
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
75/*****************************************************************************
76* Division
77*****************************************************************************/
78
79/// Proof that, for the case of `x / d`, division using `/` is
80/// equivalent to a recursive definition of division.
81pub 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
92/// Proof that the quotient of an integer divided by itself is 1,
93/// specifically that `d / d == 1`.
94pub 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
103/// Proof that 0 divided by a nonzero integer is 0, specifically `0 / d == 0`.
104pub 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
113/// Proof establishing basic properties of division using `x`: 0
114/// divided by `x` is 0; `x` divided by 1 is itself; and `x` divided
115/// by itself is 1.
116pub 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
128/// Proof for basic property that 0 divided by `x` is 0.
129pub 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
136/// Proof for basic property that `x` divided by 1 is `x`.
137pub broadcast proof fn lemma_div_basics_2(x: int)
138    ensures
139        #[trigger] (x / 1) == x,
140{
141    lemma_div_basics(x);
142}
143
144/// Proof for basic property that `x` divided by `x` is 1.
145pub 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
152/// Proof that dividing any non-negative integer by a positive integer is non-zero.
153pub 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
159/// Proof that the quotient produced by dividing any non-negative integer `x`
160/// by a positive integer `y` is at most `x`.
161pub 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
179/// Proof that if a dividend is a whole number, the divisor is a
180/// natural number, and their quotient is 0, then the dividend is
181/// smaller than the divisor.
182pub 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
191/// Proof that division of a positive integer by a positive integer
192/// less than or equal to it is nonzero. Specifically,
193/// given that `x >= d`, we can conclude that `x / d > 0`.
194pub 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
208/// Proof that given two fractions with the same numerator, the order
209/// of the fractions is determined by the denominators. However, if
210/// the numerator is 0, the fractions are equal regardless of the
211/// denominators' values. Specifically, given that `1 <= y <= z`, we
212/// know `x / y >= x / z`.
213pub 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
237/// Proof that a number gets strictly smaller when divided by a number
238/// greater than one. Specifically, `x / d < x`.
239pub 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
250/// Proof that, given `r == a % d + b % d - (a + b) % d`, `r` can also
251/// be expressed as `d * ((a + b) / d) - d * (a / d) - d * (b / d)`.
252pub 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
265/// Proof that dividing a whole number by a natural number will result
266/// in a quotient that is greater than or equal to 0. Specifically,
267/// `x / d >= 0`.
268pub 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
284/// Proof that dividing a number then adding 1 gives the same result
285/// as adding the divisor and then doing the division. Specifically,
286/// `1 + (x / d)` is equal to `(d + x) / d`.
287pub 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
297/// Proof that dividing a number then subtracting 1 gives the same result
298/// as subtracting the divisor and then doing the division. Specifically,
299/// `-1 + (x / d)` is equal to `(-d + x) / d`.
300pub 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
310/// Proof that dividing any non-negative integer less than `d` by `d`
311/// produces a quotient of 0.
312pub 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
321/// Proof that dividing any non-negative integer by a larger integer
322/// produces a quotient of 0.
323pub 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
332/// Proof that numerical order is preserved when dividing two seperate
333/// integers by a common positive divisor. Specifically, given that
334/// `z > 0` and `x <= y`, we know `x / z <= y / z`.
335pub 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
361/// Proof that dividing an integer by 2 or more results in a quotient
362/// that is smaller than the original dividend. Specifically, `x / d < x`.
363pub 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
373/// Proof that dividing an integer by 1 or more results in a quotient
374/// that is less than or equal to the original dividend. Specifically,
375/// `x / d <= x`.
376pub 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
386/// Proof that a natural number x divided by a larger natural number
387/// gives a remainder equal to x. Specifically, because `x < m`, we
388/// know `x % m == x`.
389pub 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
399/// The remainder of a nonnegative integer `x` divided by the product of two positive integers
400/// `y` and `z` is equivalent to dividing `x` by `y`, dividing the quotient by `z`, multiplying
401/// the remainder by `y`, and then adding the product to the remainder of `x` divided by `y`.
402/// In mathematical terms, `(x % (y * z)) == y * ((x / y) % z) + x % y`.
403pub 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            // comparison op can't be chained in calc!
453            // assert forall is also not avaialable in calc!
454            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
465/// Proof that the difference between a nonnegative integer `x` and a
466/// positive integer `d` must be strictly less than the quotient of
467/// `x` divided by `d` and then multiplied by `d`.
468pub 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
481/// Proof that the division of a nonnegative integer `x` by a positive
482/// integer `d` multiplied by `d` is less than or equal to the value
483/// of `x`.
484pub 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
496/// Proof that the difference between a nonnegative integer `x` and
497/// the division of `x` by a positive integer `d` multiplied by `d` is
498/// lower bounded (inclusively) by 0 and upper bounded (exclusively)
499/// by `d`.
500pub 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
512/// Proof of the fundamental theorem of division and modulo, namely
513/// that `x` can be expressed as `d` times the quotient `x / d` plus
514/// the remainder `x % d`.
515pub 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
526/// Proof that dividing `x` by `c * d` is equivalent to first dividing
527/// `x` by `c` and then dividing the result by `d`.
528pub 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);  // work around https://github.com/Z3Prover/z3/issues/8057
623}
624
625/// Proof that multiplying an integer by a fraction is equivalent to
626/// multiplying the fraction's numerator by the integer. Specifically,
627/// `x * (y / z) == (x * y) / z`.
628pub 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
656/// Proof that for a positive integer `d`, if `a - a % d` is less than
657/// or equal to `b` and `b` is less than `a + d - a % d`, then the
658/// quotient of `a` divided by `d` is equivalent to the quotient of
659/// `b` divided by `d`.
660///
661/// In other words, if `a` and `b` occur between the same two
662/// multiples of `d`, then their quotient with `d` is equivalent.
663pub 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
682/// Proof that common factors from the dividend and divisor of a
683/// modulus operation can be factored out. Specifically,
684/// `(b * x) % (b * c) == b * (x % c)`.
685pub 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
719/// Proof that multiplying the numerator and denominator by an integer
720/// does not change the quotient. Specifically,
721/// `a / d == (x * a) / (x * d)`.
722pub 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
746/// Proof that, since `a % d == 0` and `0 <= r < d`, we can conclude
747/// `a == d * (a + r) / d`.
748pub 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
762/// Proof that, since `0 <= b < d`, we have `(d * x + b) / d == x`.
763pub 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
799/// Proof that multiplying an integer by a common numerator and
800/// denominator results in the original integer. Specifically,
801/// `(d * x) / d == x`.
802pub 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
812/// Proof that multiplying a whole number by a common numerator and
813/// denominator results in the original integer. Specifically,
814/// `(b * d) / d == b`.
815pub 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
828/// Proof that a dividend that is a positive multiple of a divisor
829/// will always yield a greater quotient than a smaller dividend.
830/// Specifically, `x / z < y / z` because `y == m * z` and `x < y`.
831pub 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
852/// Proof that if an integer is less than or equal to the product of
853/// two other integers, then the quotient with one of them will be
854/// less than or equal to the other of them. Specifically, because
855/// `a <= b * c`, we know `a / b <= c`.
856pub 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
870/// Proof that if an integer is less than the product of two other
871/// integers, then the quotient with one of them will be less than the
872/// other. Specifically, because `a < b * c`, we know `a / b < c`.
873pub 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
896/// Proof that adding an integer to a fraction is equivalent to adding
897/// that integer times the denominator to the numerator. Specifically,
898/// `x / d + j == (x + j * d) / d`.
899pub 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
923/// Proof that, for nonnegative integer `a` and positive integers `b` and `c`,
924/// the remainder of `b * (a / b)` divided by `b * c` is less than or equal to `b * (c - 1)`.
925/// This accounts for the rounding down that occurs in integer division.
926pub 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
960/*******************************************************************************
961* Modulus
962*******************************************************************************/
963
964/// Proof that computing the modulus using `%` is equivalent to
965/// computing it with a recursive definition of modulus. Specifically,
966/// `x % m` is equivalent in that way.
967pub 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
1025/// Proof that any integer divided by itself produces a remainder of 0.
1026pub 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
1035/// Proof that performing `(x % m) % m` gives the same result as simply perfoming `x % m`.
1036pub 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
1050/// Proof that the remainder of any division will be less than the divisor's value.
1051pub 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
1065/// Proof that when natural number `x` is divided by natural number
1066/// `m`, the remainder will be less than or equal to `x`.
1067pub 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
1076/// Proof that if `x % m` is zero and `x` is positive, then `x >= m`.
1077pub 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/// Proof that multiplying by a number then dividing by that same
1090/// number produces a remainder of 0. Specifically, `(x * m) % m == 0`.
1091#[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
1106/// Proof that adding the divisor to the dividend doesn't change the
1107/// remainder. Specifically, `(m + b) % m == b % m`.
1108pub 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
1117/// Proof that subtracting the divisor from the dividend doesn't
1118/// change the remainder. Specifically, `(-m + b) % m == b % m`.
1119pub 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/// Proof that adding any multiple of the divisor to the dividend will produce the
1129/// same remainder. In other words, `(m * a + b) % m == b % m`.
1130#[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
1151/// Proof that modulo distributes over subtraction if the subtracted value is
1152/// less than or equal to the modulo of the number it's being subtracted from.
1153/// Specifically, because `0 <= s <= x % d`, we can conclude that
1154/// `x % d - s % d == (x - s) % d`.
1155pub 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
1166/// Proof that modulo distributes over addition, provided you do an
1167/// extra modulo after adding the remainders. Specifically,
1168/// `((x % m) + (y % m)) % m == (x + y) % m`.
1169pub 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
1179/// Proof that describes an expanded and succinct version of modulus
1180/// operator in relation to addition. Specifically,
1181/// `(x + (y % m)) % m == (x + y) % m`.
1182pub 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
1192/// Proof that modulo distributes over subtraction provided you do an
1193/// extra modulo operation after subtracting the remainders.
1194/// Specifically, `((x % m) - (y % m)) % m == (x - y) % m`.
1195pub 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
1205/// Proof that describes an expanded and succinct version of modulus
1206/// operator in relation to subtraction. Specifically,
1207/// `(x - (y % m)) % m == (x - y) % m`.
1208pub 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
1218/// Proof of two properties of the sum of two remainders with the same dividend:
1219/// 1) `a % d + b % d == (a + b) % d + d * ((a % d + b % d) / d)`.
1220/// 2) `(a % d + b % d) < d ==> a % d + b % d == (a + b) % d`.
1221pub 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/// Proof that the remainder when dividing integer `x` by positive
1235/// integer `d` is equivalent to the remainder of `x * (1 - d)` by
1236/// `d`.
1237#[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
1258/// This proof isn't exported from this module. It's just used in
1259/// the proof of [`lemma_fundamental_div_mod_converse`].
1260proof 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
1291/// This proof isn't exported from this module. It's just used in
1292/// the proof of [`lemma_fundamental_div_mod_converse`].
1293proof 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
1330/// Proof of the converse of the fundamental property of division and modulo.
1331/// Specifically, if we know `0 <= r < d` and `x == q * d + r`, then we
1332/// know that `r` is the remainder `x % d`.
1333pub 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
1346/// Proof of the converse of the fundamental property of division and modulo.
1347/// Specifically, if we know `0 <= r < d` and `x == q * d + r`, then we
1348/// know that `q` is the quotient `x / d`.
1349pub 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
1362/// Proof of the converse of the fundamental property of division and modulo.
1363/// Specifically, if we know `0 <= r < d` and `x == q * d + r`, then we
1364/// know that `q` is the quotient `x / d` and `r` is the remainder `x % d`.
1365pub 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
1383/// Proof that the remainder, when natural number `x` is divided by
1384/// positive integer `m`, is less than `m`.
1385pub 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
1395/// Proof that when integer `x` is divided by positive integer `m`,
1396/// the remainder is nonegative and less than `m`.
1397pub 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
1406/// Proof that the remainder when `x * y` is divided by `m` is
1407/// equivalent to the remainder when `(x % m) * y` is divided by `m`.
1408pub 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
1418/// Proof that the remainder when `x * y` is divided by `m` is
1419/// equivalent to the remainder when `x * (y % m)` is divided by `m`.
1420pub 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
1430/// Proof of various properties about modulo equivalence with respect
1431/// to multiplication, specifically various expressions that `(x * y)
1432/// % m` is equivalent to.
1433pub 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
1446/// Proof that modulo distributes over multiplication, provided you do
1447/// an extra modulo operation after multiplying the remainders. Specifically,
1448/// `(x % m) * (y % m) % m == (x * y) % m`.
1449pub 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
1458/// Proof that `x` and `y` are congruent modulo `m` if and only if `x
1459/// - y` is congruent to 0 modulo `m`. In other words, `x % m == y % m
1460/// <==> (x - y) % m == 0`.
1461///
1462/// Note: The Dafny standard library uses the triggers `x % m, y % m`
1463/// for the broadcasted forall quantifier. But this can lead to a trigger loop,
1464/// so we don't do that here.
1465pub 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
1475/// This function says that `x` is congruent to `y` modulo `m` if and
1476/// only if their difference `x - y` is congruent to 0 modulo `m`.
1477pub 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
1484/// Proof that if `is_mod_equivalent` holds for `x`, `y`, and `m`,
1485/// then it holds for `x * z`, `y * z`, and `m`.
1486pub 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
1499/// Proof that multiplying the divisor by a positive number can't
1500/// decrease the remainder. Specifically, because `k > 0`, we have
1501/// `x % d <= x % (d * k)`.
1502pub 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
1548/// Proof that the remainder when `x` is divided by `a * b`, taken
1549/// modulo `a`, is equivalent to `x` modulo `a`. That is,
1550/// `(x % (a * b)) % a == x % a`.
1551pub 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
1590/// Proof that `(x % y) % (y * z) < y`.
1591pub 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
1614/// Proof of the validity of an expanded form of the modulus operation.
1615/// Specifically, `x % (y * z) == y * ((x / y) % z) + x % y`.
1616pub 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} // verus!