#[allow(unused_imports)]
use super::super::prelude::*;
verus! {
use super::super::arithmetic::internals::mul_internals_nonlinear as MulINL;
use super::super::arithmetic::internals::mul_internals::*;
pub broadcast proof fn lemma_mul_is_mul_recursive(x: int, y: int)
ensures
#[trigger] (x * y) == mul_recursive(x, y),
{
if (x >= 0) {
lemma_mul_is_mul_pos(x, y);
assert(x * y == mul_pos(x, y));
assert((x * y) == mul_recursive(x, y));
} else {
lemma_mul_is_mul_pos(-x, y);
assert(x * y == -1 * (-x * y)) by { lemma_mul_is_associative(-1, -x, y) }; assert((x * y) == mul_recursive(x, y));
}
}
pub proof fn lemma_mul_is_mul_pos(x: int, y: int)
requires
x >= 0,
ensures
x * y == mul_pos(x, y),
{
reveal(mul_pos);
lemma_mul_induction_auto(x, |u: int| u >= 0 ==> u * y == mul_pos(u, y));
}
pub proof fn lemma_mul_basics(x: int)
ensures
0 * x == 0,
x * 0 == 0,
x * 1 == x,
1 * x == x,
{
}
pub broadcast proof fn lemma_mul_basics_1(x: int)
ensures
#[trigger] (0 * x) == 0,
{
}
pub broadcast proof fn lemma_mul_basics_2(x: int)
ensures
#[trigger] (x * 0) == 0,
{
}
pub broadcast proof fn lemma_mul_basics_3(x: int)
ensures
#[trigger] (x * 1) == x,
{
}
pub broadcast proof fn lemma_mul_basics_4(x: int)
ensures
#[trigger] (1 * x) == x,
{
}
pub broadcast group group_mul_basics {
lemma_mul_basics_1,
lemma_mul_basics_2,
lemma_mul_basics_3,
lemma_mul_basics_4,
}
pub broadcast proof fn lemma_mul_nonzero(x: int, y: int)
ensures
#[trigger] (x * y) != 0 <==> x != 0 && y != 0,
{
MulINL::lemma_mul_nonzero(x, y);
}
pub broadcast proof fn lemma_mul_by_zero_is_zero(x: int)
ensures
#![trigger x * 0]
#![trigger 0 * x]
x * 0 == 0 && 0 * x == 0,
{
assert forall|x: int| #![trigger x * 0] #![trigger 0 * x] x * 0 == 0 && 0 * x == 0 by {
lemma_mul_basics(x);
}
}
pub broadcast proof fn lemma_mul_is_associative(x: int, y: int, z: int)
ensures
#![trigger x * (y * z)]
#![trigger (x * y) * z]
x * (y * z) == (x * y) * z,
{
MulINL::lemma_mul_is_associative(x, y, z);
}
pub broadcast proof fn lemma_mul_is_commutative(x: int, y: int)
ensures
#[trigger] (x * y) == y * x,
{
}
pub broadcast proof fn lemma_mul_ordering(x: int, y: int)
requires
x != 0,
y != 0,
0 <= x * y,
ensures
#[trigger] (x * y) >= x && x * y >= y,
{
MulINL::lemma_mul_ordering(x, y);
}
pub broadcast proof fn lemma_mul_inequality(x: int, y: int, z: int)
requires
x <= y,
z >= 0,
ensures
#[trigger] (x * z) <= #[trigger] (y * z),
{
lemma_mul_induction_auto(z, |u: int| u >= 0 ==> x * u <= y * u);
}
pub broadcast proof fn lemma_mul_strict_inequality(x: int, y: int, z: int)
requires
x < y,
z > 0,
ensures
#[trigger] (x * z) < #[trigger] (y * z),
{
MulINL::lemma_mul_strict_inequality(x, y, z);
}
pub broadcast proof fn lemma_mul_upper_bound(x: int, xbound: int, y: int, ybound: int)
requires
x <= xbound,
y <= ybound,
0 <= x,
0 <= y,
ensures
#[trigger] (x * y) <= #[trigger] (xbound * ybound),
{
lemma_mul_inequality(x, xbound, y);
lemma_mul_inequality(y, ybound, xbound);
}
pub broadcast proof fn lemma_mul_strict_upper_bound(x: int, xbound: int, y: int, ybound: int)
requires
x < xbound,
y < ybound,
0 < x,
0 < y,
ensures
#[trigger] (x * y) <= #[trigger] ((xbound - 1) * (ybound - 1)),
{
lemma_mul_inequality(x, xbound - 1, y);
lemma_mul_inequality(y, ybound - 1, xbound - 1);
}
pub broadcast proof fn lemma_mul_left_inequality(x: int, y: int, z: int)
requires
0 < x,
ensures
y <= z ==> #[trigger] (x * y) <= #[trigger] (x * z),
y < z ==> x * y < x * z,
{
lemma_mul_induction_auto(x, |u: int| u > 0 ==> y <= z ==> u * y <= u * z);
lemma_mul_induction_auto(x, |u: int| u > 0 ==> y < z ==> u * y < u * z);
}
pub broadcast proof fn lemma_mul_equality_converse(m: int, x: int, y: int)
requires
m != 0,
#[trigger] (m * x) == #[trigger] (m * y),
ensures
x == y,
{
lemma_mul_induction_auto(m, |u| x > y && 0 < u ==> x * u > y * u);
lemma_mul_induction_auto(m, |u: int| x < y && 0 < u ==> x * u < y * u);
lemma_mul_induction_auto(m, |u: int| x > y && 0 > u ==> x * u < y * u);
lemma_mul_induction_auto(m, |u: int| x < y && 0 > u ==> x * u > y * u);
}
pub broadcast proof fn lemma_mul_inequality_converse(x: int, y: int, z: int)
requires
#[trigger] (x * z) <= #[trigger] (y * z),
z > 0,
ensures
x <= y,
{
lemma_mul_induction_auto(z, |u: int| x * u <= y * u && u > 0 ==> x <= y);
}
pub broadcast proof fn lemma_mul_strict_inequality_converse(x: int, y: int, z: int)
requires
#[trigger] (x * z) < #[trigger] (y * z),
z >= 0,
ensures
x < y,
{
lemma_mul_induction_auto(z, |u: int| x * u < y * u && u >= 0 ==> x < y);
}
pub broadcast proof fn lemma_mul_is_distributive_add(x: int, y: int, z: int)
ensures
#[trigger] (x * (y + z)) == x * y + x * z,
{
MulINL::lemma_mul_is_distributive_add(x, y, z);
}
pub broadcast proof fn lemma_mul_is_distributive_add_other_way(x: int, y: int, z: int)
ensures
#[trigger] ((y + z) * x) == y * x + z * x,
{
broadcast use group_mul_properties_internal;
}
pub broadcast proof fn lemma_mul_is_distributive_sub(x: int, y: int, z: int)
ensures
#[trigger] (x * (y - z)) == x * y - x * z,
{
broadcast use group_mul_properties_internal;
}
pub broadcast proof fn lemma_mul_is_distributive_sub_other_way(x: int, y: int, z: int)
ensures
#[trigger] ((y - z) * x) == y * x - z * x,
{
lemma_mul_is_distributive_sub(x, y, z);
lemma_mul_is_commutative(x, y - z);
lemma_mul_is_commutative(x, y);
lemma_mul_is_commutative(x, z);
}
pub broadcast group group_mul_is_distributive {
lemma_mul_is_distributive_add,
lemma_mul_is_distributive_add_other_way,
lemma_mul_is_distributive_sub,
lemma_mul_is_distributive_sub_other_way,
}
pub broadcast group group_mul_is_commutative_and_distributive {
lemma_mul_is_commutative,
group_mul_is_distributive,
}
proof fn lemma_mul_is_distributive(x: int, y: int, z: int)
ensures
x * (y + z) == x * y + x * z,
x * (y - z) == x * y - x * z,
(y + z) * x == y * x + z * x,
(y - z) * x == y * x - z * x,
x * (y + z) == (y + z) * x,
x * (y - z) == (y - z) * x,
x * y == y * x,
x * z == z * x,
{
broadcast use group_mul_is_commutative_and_distributive;
}
pub broadcast proof fn lemma_mul_strictly_positive(x: int, y: int)
ensures
(0 < x && 0 < y) ==> (0 < #[trigger] (x * y)),
{
MulINL::lemma_mul_strictly_positive(x, y);
}
pub broadcast proof fn lemma_mul_strictly_increases(x: int, y: int)
requires
1 < x,
0 < y,
ensures
y < #[trigger] (x * y),
{
lemma_mul_induction_auto(x, |u: int| 1 < u ==> y < u * y);
}
pub broadcast proof fn lemma_mul_increases(x: int, y: int)
requires
0 < x,
0 < y,
ensures
y <= #[trigger] (x * y),
{
lemma_mul_induction_auto(x, |u: int| 0 < u ==> y <= u * y);
}
pub broadcast proof fn lemma_mul_nonnegative(x: int, y: int)
requires
0 <= x,
0 <= y,
ensures
0 <= #[trigger] (x * y),
{
lemma_mul_induction_auto(x, |u: int| 0 <= u ==> 0 <= u * y);
}
pub broadcast proof fn lemma_mul_unary_negation(x: int, y: int)
ensures
#![trigger (-x) * y]
#![trigger x * (-y)]
(-x) * y == -(x * y) == x * (-y),
{
lemma_mul_induction_auto(x, |u: int| (-u) * y == -(u * y) == u * (-y));
}
pub broadcast proof fn lemma_mul_cancels_negatives(x: int, y: int)
ensures
#[trigger] (x * y) == (-x) * (-y),
{
lemma_mul_induction_auto(x, |u: int| (-u) * y == -(u * y) == u * (-y));
}
pub broadcast group group_mul_properties {
group_mul_basics,
lemma_mul_strict_inequality,
lemma_mul_inequality,
group_mul_is_commutative_and_distributive,
lemma_mul_is_associative,
lemma_mul_ordering,
lemma_mul_nonzero,
lemma_mul_nonnegative,
lemma_mul_strictly_increases,
lemma_mul_increases,
}
proof fn lemma_mul_properties_prove_mul_properties_auto()
ensures
forall|x: int, y: int| #[trigger] (x * y) == y * x,
forall|x: int| #![trigger x * 1] #![trigger 1 * x] x * 1 == 1 * x == x,
forall|x: int, y: int, z: int| x < y && z > 0 ==> #[trigger] (x * z) < #[trigger] (y * z),
forall|x: int, y: int, z: int|
x <= y && z >= 0 ==> #[trigger] (x * z) <= #[trigger] (y * z),
forall|x: int, y: int, z: int| #[trigger] (x * (y + z)) == x * y + x * z,
forall|x: int, y: int, z: int| #[trigger] (x * (y - z)) == x * y - x * z,
forall|x: int, y: int, z: int| #[trigger] ((y + z) * x) == y * x + z * x,
forall|x: int, y: int, z: int| #[trigger] ((y - z) * x) == y * x - z * x,
forall|x: int, y: int, z: int|
#![trigger x * (y * z)]
#![trigger (x * y) * z]
x * (y * z) == (x * y) * z,
forall|x: int, y: int| #[trigger] (x * y) != 0 <==> x != 0 && y != 0,
forall|x: int, y: int| 0 <= x && 0 <= y ==> 0 <= #[trigger] (x * y),
forall|x: int, y: int|
0 < x && 0 < y && 0 <= x * y ==> x <= #[trigger] (x * y) && y <= (x * y),
forall|x: int, y: int| (1 < x && 0 < y) ==> (y < #[trigger] (x * y)),
forall|x: int, y: int| (0 < x && 0 < y) ==> (y <= #[trigger] (x * y)),
forall|x: int, y: int| (0 < x && 0 < y) ==> (0 < #[trigger] (x * y)),
{
broadcast use group_mul_properties;
}
}