#[cfg(verus_keep_ghost)]
use super::super::super::math::{add as add1, sub as sub1};
use super::super::super::prelude::*;
verus! {
pub open spec fn is_le(x: int, y: int) -> bool {
x <= y
}
proof fn lemma_induction_helper_pos(n: int, f: spec_fn(int) -> bool, x: int)
requires
x >= 0,
n > 0,
forall|i: int| 0 <= i < n ==> #[trigger] f(i),
forall|i: int| i >= 0 && #[trigger] f(i) ==> #[trigger] f(add1(i, n)),
forall|i: int| i < n && #[trigger] f(i) ==> #[trigger] f(sub1(i, n)),
ensures
f(x),
decreases x,
{
if (x >= n) {
assert(x - n < x);
lemma_induction_helper_pos(n, f, x - n);
assert(f(add1(x - n, n)));
assert(f((x - n) + n));
}
}
proof fn lemma_induction_helper_neg(n: int, f: spec_fn(int) -> bool, x: int)
requires
x < 0,
n > 0,
forall|i: int| 0 <= i < n ==> #[trigger] f(i),
forall|i: int| i >= 0 && #[trigger] f(i) ==> #[trigger] f(add1(i, n)),
forall|i: int| i < n && #[trigger] f(i) ==> #[trigger] f(sub1(i, n)),
ensures
f(x),
decreases -x,
{
if (-x <= n) {
lemma_induction_helper_pos(n, f, x + n);
assert(f(sub1(x + n, n)));
assert(f((x + n) - n));
} else {
lemma_induction_helper_neg(n, f, x + n);
assert(f(sub1(x + n, n)));
assert(f((x + n) - n));
}
}
pub proof fn lemma_induction_helper(n: int, f: spec_fn(int) -> bool, x: int)
requires
n > 0,
forall|i: int| 0 <= i < n ==> #[trigger] f(i),
forall|i: int| i >= 0 && #[trigger] f(i) ==> #[trigger] f(add1(i, n)),
forall|i: int| i < n && #[trigger] f(i) ==> #[trigger] f(sub1(i, n)),
ensures
f(x),
{
if (x >= 0) {
lemma_induction_helper_pos(n, f, x);
} else {
lemma_induction_helper_neg(n, f, x);
}
}
}