use verus_builtin_macros::verus;
#[allow(unused_imports)]
use verus_builtin::*;
#[allow(unused_imports)]
use vstd::prelude::*;
#[allow(unused_imports)]
use crate::ext::Q;
#[allow(unused_imports)]
use crate::model::*;
#[allow(unused_imports)]
use crate::q::*;
#[allow(unused_imports)]
use crate::round::*;
#[allow(unused_imports)]
use crate::types::{Dir, Rat};
verus! {
pub proof fn lemma_exact_path_implies_magnitude_fits(n: int, d: int)
requires
d > 0,
exact_path(n, d),
ensures
magnitude_fits(n, d),
{
if n == 0 {
crate::model::lemma_max_mag_pow2();
assert(magnitude_fits(n, d)) by (nonlinear_arith)
requires
n == 0,
max_mag() > 0,
d > 0,
;
} else {
let g = gcd_int(n, d);
let rn = red_num(n, d);
let rd = red_den(n, d);
crate::round::lemma_reduce_exact(n, d);
crate::round::lemma_reduce_abs(n, d);
assert(abs_int(rn) <= max_mag());
assert(rd >= 1);
assert(abs_int(rn) * g <= max_mag() * g) by (nonlinear_arith)
requires
abs_int(rn) <= max_mag(),
g > 0,
;
assert(max_mag() * g <= max_mag() * (rd * g)) by (nonlinear_arith)
requires
rd >= 1,
g > 0,
max_mag() >= 0,
;
assert(abs_int(n) <= max_mag() * d) by (nonlinear_arith)
requires
abs_int(n) == abs_int(rn) * g,
d == rd * g,
abs_int(rn) * g <= max_mag() * g,
max_mag() * g <= max_mag() * (rd * g),
;
}
}
pub proof fn lemma_prod_d_pos(x: Rat, y: Rat)
requires
x.wf(),
y.wf(),
ensures
prod_d(x, y) > 0,
{
assert(prod_d(x, y) == x.d() * y.d());
assert(x.d() * y.d() > 0) by (nonlinear_arith)
requires
x.d() > 0,
y.d() > 0,
;
}
pub proof fn theorem_q_add_commutative(a: Q, b: Q)
requires
a.wf(),
b.wf(),
ensures
Q::spec_add(a, b) == Q::spec_add(b, a),
{
match (a, b) {
(Q::Number(x), Q::Number(y)) => {
assert(add_n(x, y) == add_n(y, x));
assert(prod_d(x, y) == prod_d(y, x)) by (nonlinear_arith);
},
_ => {},
}
}
pub proof fn theorem_q_mul_commutative(a: Q, b: Q)
requires
a.wf(),
b.wf(),
ensures
Q::spec_mul(a, b) == Q::spec_mul(b, a),
{
match (a, b) {
(Q::Number(x), Q::Number(y)) => {
assert(mul_n(x, y) == mul_n(y, x)) by (nonlinear_arith);
assert(prod_d(x, y) == prod_d(y, x)) by (nonlinear_arith);
},
_ => {},
}
}
pub proof fn theorem_q_add_associative_exact(a: Rat, b: Rat, c: Rat)
requires
a.wf(),
b.wf(),
c.wf(),
exact_path(add_n(a, b), prod_d(a, b)),
exact_path(add_n(b, c), prod_d(b, c)),
({
let ab = round_frac(add_n(a, b), prod_d(a, b), Dir::Nearest);
let bc = round_frac(add_n(b, c), prod_d(b, c), Dir::Nearest);
&&& exact_path(add_n(ab, c), prod_d(ab, c))
&&& exact_path(add_n(a, bc), prod_d(a, bc))
}),
ensures
({
let ab = round_frac(add_n(a, b), prod_d(a, b), Dir::Nearest);
let bc = round_frac(add_n(b, c), prod_d(b, c), Dir::Nearest);
Q::spec_add(Q::spec_add(Q::Number(a), Q::Number(b)), Q::Number(c)) == Q::spec_add(
Q::Number(a),
Q::spec_add(Q::Number(b), Q::Number(c)),
)
}),
{
crate::laws::theorem_add_associative_exact(a, b, c, Dir::Nearest);
lemma_prod_d_pos(a, b);
lemma_prod_d_pos(b, c);
lemma_exact_path_implies_magnitude_fits(add_n(a, b), prod_d(a, b));
lemma_exact_path_implies_magnitude_fits(add_n(b, c), prod_d(b, c));
let ab = round_frac(add_n(a, b), prod_d(a, b), Dir::Nearest);
let bc = round_frac(add_n(b, c), prod_d(b, c), Dir::Nearest);
crate::round::lemma_round_frac_wf(add_n(a, b), prod_d(a, b), Dir::Nearest);
crate::round::lemma_round_frac_wf(add_n(b, c), prod_d(b, c), Dir::Nearest);
lemma_prod_d_pos(ab, c);
lemma_prod_d_pos(a, bc);
lemma_exact_path_implies_magnitude_fits(add_n(ab, c), prod_d(ab, c));
lemma_exact_path_implies_magnitude_fits(add_n(a, bc), prod_d(a, bc));
let left = round_frac(add_n(ab, c), prod_d(ab, c), Dir::Nearest);
let right = round_frac(add_n(a, bc), prod_d(a, bc), Dir::Nearest);
crate::round::lemma_round_frac_wf(add_n(ab, c), prod_d(ab, c), Dir::Nearest);
crate::round::lemma_round_frac_wf(add_n(a, bc), prod_d(a, bc), Dir::Nearest);
crate::laws::lemma_canonical_eq(left, right);
}
pub proof fn theorem_q_mul_associative_exact(a: Rat, b: Rat, c: Rat)
requires
a.wf(),
b.wf(),
c.wf(),
exact_path(mul_n(a, b), prod_d(a, b)),
exact_path(mul_n(b, c), prod_d(b, c)),
({
let ab = round_frac(mul_n(a, b), prod_d(a, b), Dir::Nearest);
let bc = round_frac(mul_n(b, c), prod_d(b, c), Dir::Nearest);
&&& exact_path(mul_n(ab, c), prod_d(ab, c))
&&& exact_path(mul_n(a, bc), prod_d(a, bc))
}),
ensures
({
let ab = round_frac(mul_n(a, b), prod_d(a, b), Dir::Nearest);
let bc = round_frac(mul_n(b, c), prod_d(b, c), Dir::Nearest);
Q::spec_mul(Q::spec_mul(Q::Number(a), Q::Number(b)), Q::Number(c)) == Q::spec_mul(
Q::Number(a),
Q::spec_mul(Q::Number(b), Q::Number(c)),
)
}),
{
lemma_prod_d_pos(a, b);
lemma_prod_d_pos(b, c);
lemma_exact_path_implies_magnitude_fits(mul_n(a, b), prod_d(a, b));
lemma_exact_path_implies_magnitude_fits(mul_n(b, c), prod_d(b, c));
let ab = round_frac(mul_n(a, b), prod_d(a, b), Dir::Nearest);
let bc = round_frac(mul_n(b, c), prod_d(b, c), Dir::Nearest);
crate::round::lemma_round_frac_wf(mul_n(a, b), prod_d(a, b), Dir::Nearest);
crate::round::lemma_round_frac_wf(mul_n(b, c), prod_d(b, c), Dir::Nearest);
lemma_prod_d_pos(ab, c);
lemma_prod_d_pos(a, bc);
lemma_exact_path_implies_magnitude_fits(mul_n(ab, c), prod_d(ab, c));
lemma_exact_path_implies_magnitude_fits(mul_n(a, bc), prod_d(a, bc));
let left = round_frac(mul_n(ab, c), prod_d(ab, c), Dir::Nearest);
let right = round_frac(mul_n(a, bc), prod_d(a, bc), Dir::Nearest);
crate::round::lemma_round_frac_wf(mul_n(ab, c), prod_d(ab, c), Dir::Nearest);
crate::round::lemma_round_frac_wf(mul_n(a, bc), prod_d(a, bc), Dir::Nearest);
crate::laws::theorem_exact_path_is_exact(mul_n(a, b), prod_d(a, b), Dir::Nearest);
crate::laws::theorem_exact_path_is_exact(mul_n(b, c), prod_d(b, c), Dir::Nearest);
crate::laws::theorem_exact_path_is_exact(mul_n(ab, c), prod_d(ab, c), Dir::Nearest);
crate::laws::theorem_exact_path_is_exact(mul_n(a, bc), prod_d(a, bc), Dir::Nearest);
crate::laws::theorem_mul_associative_exact(a, b, c, ab, bc, left, right);
crate::laws::lemma_canonical_eq(left, right);
}
pub proof fn theorem_q_distributive_exact(a: Rat, b: Rat, c: Rat)
requires
a.wf(),
b.wf(),
c.wf(),
exact_path(add_n(b, c), prod_d(b, c)),
({
let bc = round_frac(add_n(b, c), prod_d(b, c), Dir::Nearest);
&&& exact_path(mul_n(a, bc), prod_d(a, bc))
}),
exact_path(mul_n(a, b), prod_d(a, b)),
exact_path(mul_n(a, c), prod_d(a, c)),
({
let ab = round_frac(mul_n(a, b), prod_d(a, b), Dir::Nearest);
let ac = round_frac(mul_n(a, c), prod_d(a, c), Dir::Nearest);
&&& exact_path(add_n(ab, ac), prod_d(ab, ac))
}),
ensures
({
let bc = round_frac(add_n(b, c), prod_d(b, c), Dir::Nearest);
let ab = round_frac(mul_n(a, b), prod_d(a, b), Dir::Nearest);
let ac = round_frac(mul_n(a, c), prod_d(a, c), Dir::Nearest);
Q::spec_mul(Q::Number(a), Q::spec_add(Q::Number(b), Q::Number(c))) == Q::spec_add(
Q::spec_mul(Q::Number(a), Q::Number(b)),
Q::spec_mul(Q::Number(a), Q::Number(c)),
)
}),
{
lemma_prod_d_pos(b, c);
lemma_exact_path_implies_magnitude_fits(add_n(b, c), prod_d(b, c));
let bc = round_frac(add_n(b, c), prod_d(b, c), Dir::Nearest);
crate::round::lemma_round_frac_wf(add_n(b, c), prod_d(b, c), Dir::Nearest);
lemma_prod_d_pos(a, bc);
lemma_prod_d_pos(a, b);
lemma_prod_d_pos(a, c);
lemma_exact_path_implies_magnitude_fits(mul_n(a, bc), prod_d(a, bc));
lemma_exact_path_implies_magnitude_fits(mul_n(a, b), prod_d(a, b));
lemma_exact_path_implies_magnitude_fits(mul_n(a, c), prod_d(a, c));
let ab = round_frac(mul_n(a, b), prod_d(a, b), Dir::Nearest);
let ac = round_frac(mul_n(a, c), prod_d(a, c), Dir::Nearest);
crate::round::lemma_round_frac_wf(mul_n(a, b), prod_d(a, b), Dir::Nearest);
crate::round::lemma_round_frac_wf(mul_n(a, c), prod_d(a, c), Dir::Nearest);
lemma_prod_d_pos(ab, ac);
lemma_exact_path_implies_magnitude_fits(add_n(ab, ac), prod_d(ab, ac));
let lhs = round_frac(mul_n(a, bc), prod_d(a, bc), Dir::Nearest);
let rhs = round_frac(add_n(ab, ac), prod_d(ab, ac), Dir::Nearest);
crate::round::lemma_round_frac_wf(mul_n(a, bc), prod_d(a, bc), Dir::Nearest);
crate::round::lemma_round_frac_wf(add_n(ab, ac), prod_d(ab, ac), Dir::Nearest);
crate::laws::theorem_exact_path_is_exact(add_n(b, c), prod_d(b, c), Dir::Nearest);
crate::laws::theorem_exact_path_is_exact(mul_n(a, bc), prod_d(a, bc), Dir::Nearest);
crate::laws::theorem_exact_path_is_exact(mul_n(a, b), prod_d(a, b), Dir::Nearest);
crate::laws::theorem_exact_path_is_exact(mul_n(a, c), prod_d(a, c), Dir::Nearest);
crate::laws::theorem_exact_path_is_exact(add_n(ab, ac), prod_d(ab, ac), Dir::Nearest);
crate::laws::theorem_distributive_exact(a, b, c, bc, lhs, ab, ac, rhs);
crate::laws::lemma_canonical_eq(lhs, rhs);
}
pub proof fn theorem_q_add_monotone_exact(a: Rat, b: Rat, c: Rat)
requires
a.wf(),
b.wf(),
c.wf(),
q_le(a, b),
exact_path(add_n(a, c), prod_d(a, c)),
exact_path(add_n(b, c), prod_d(b, c)),
ensures
({
let ac = round_frac(add_n(a, c), prod_d(a, c), Dir::Nearest);
let bc = round_frac(add_n(b, c), prod_d(b, c), Dir::Nearest);
&&& Q::spec_add(Q::Number(a), Q::Number(c)) == Q::Number(ac)
&&& Q::spec_add(Q::Number(b), Q::Number(c)) == Q::Number(bc)
&&& q_le(ac, bc)
}),
{
lemma_prod_d_pos(a, c);
lemma_prod_d_pos(b, c);
lemma_exact_path_implies_magnitude_fits(add_n(a, c), prod_d(a, c));
lemma_exact_path_implies_magnitude_fits(add_n(b, c), prod_d(b, c));
crate::laws::theorem_add_monotone_exact(a, b, c);
let ac = round_frac(add_n(a, c), prod_d(a, c), Dir::Nearest);
let bc = round_frac(add_n(b, c), prod_d(b, c), Dir::Nearest);
crate::laws::theorem_exact_path_is_exact(add_n(a, c), prod_d(a, c), Dir::Nearest);
crate::laws::theorem_exact_path_is_exact(add_n(b, c), prod_d(b, c), Dir::Nearest);
crate::interval::lemma_frac_chain_le(
ac.n(),
ac.d(),
add_n(a, c),
prod_d(a, c),
add_n(b, c),
prod_d(b, c),
bc.n(),
bc.d(),
);
}
}