use crate::{env::{Env, IndDesc}, term::Term};
use super::ids::*;
use super::nat::{nat, nat_lit, nat_next};
use super::prop::eq_refl;
pub fn le(n: Term, m: Term) -> Term { Term::Ind(LE_ID, vec![n, m]) }
pub fn le_refl(n: Term) -> Term {
Term::Ctor(LE_ID, LE_REFL_IDX, vec![n.clone(), n])
}
pub fn le_step(n: Term, m: Term, h: Term) -> Term {
Term::Ctor(LE_ID, LE_STEP_IDX, vec![n, m, h])
}
pub fn declare_le(env: &mut Env) {
let id = LE_ID;
let refl_tel = Term::Ind(id, vec![Term::Var(1), Term::Var(1)]);
let step_tel = Term::Pi(
Box::new(Term::Ind(id, vec![Term::Var(1), Term::Var(0)])), Box::new(Term::Ind(id, vec![Term::Var(2), nat_next(Term::Var(1))])), );
env.insert(id, IndDesc {
arity: 2,
sort: 0,
param_tel: Term::Pi(
Box::new(nat()),
Box::new(Term::Pi(Box::new(nat()), Box::new(Term::Sort(0)))),
),
constructors: vec![refl_tel, step_tel],
});
}
pub fn le_of_lits(n: u64, m: u64) -> Term {
assert!(n <= m, "le_of_lits: {n} > {m}");
if n == m {
le_refl(nat_lit(n))
} else {
le_step(nat_lit(n), nat_lit(m - 1), le_of_lits(n, m - 1))
}
}
pub fn nat_div_ty() -> Term {
Term::Pi(Box::new(nat()), Box::new(Term::Pi(Box::new(nat()), Box::new(nat()))))
}
pub fn nat_div_axiom() -> Term {
nat_div_ty()
}
pub fn nat_min_le_right_ty() -> Term {
Term::Pi(
Box::new(nat()),
Box::new(Term::Pi(
Box::new(nat()),
Box::new(Term::Ind(LE_ID, vec![
Term::App(
Box::new(Term::App(
Box::new(Term::Var(2)), Box::new(Term::Var(1)), )),
Box::new(Term::Var(0)), ),
Term::Var(0), ])),
)),
)
}
pub fn nat_div_le_self_ty() -> Term {
Term::Pi(
Box::new(nat()),
Box::new(Term::Pi(
Box::new(nat()),
Box::new(Term::Ind(LE_ID, vec![
Term::App(
Box::new(Term::App(
Box::new(Term::Var(2)), Box::new(Term::Var(1)), )),
Box::new(Term::Var(0)), ),
Term::Var(1), ])),
)),
)
}
pub fn axiom_term(ty: Term) -> Term { ty.clone() }
pub fn le_type_pi() -> Term {
Term::Pi(
Box::new(nat()),
Box::new(Term::Pi(Box::new(nat()), Box::new(Term::Sort(0)))),
)
}
pub fn le_type_lam() -> Term {
Term::Lam(
Box::new(nat()),
Box::new(Term::Lam(
Box::new(nat()),
Box::new(Term::Ind(LE_ID, vec![Term::Var(1), Term::Var(0)])),
)),
)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::kernel::check;
fn ctx() -> crate::ctx::Ctx { vec![] }
#[test]
fn le_refl_type_checks() {
let env = crate::stdlib::std_env();
let proof = le_refl(nat_lit(3));
let ty = le(nat_lit(3), nat_lit(3));
assert_eq!(check(&env, &ctx(), &proof, &ty), Ok(()));
}
#[test]
fn le_step_type_checks() {
let env = crate::stdlib::std_env();
let h = le_refl(nat_lit(2));
let proof = le_step(nat_lit(2), nat_lit(2), h);
let ty = le(nat_lit(2), nat_lit(3));
assert_eq!(check(&env, &ctx(), &proof, &ty), Ok(()));
}
#[test]
fn le_of_lits_correct() {
let env = crate::stdlib::std_env();
let proof = le_of_lits(0, 5);
let ty = le(nat_lit(0), nat_lit(5));
assert_eq!(check(&env, &ctx(), &proof, &ty), Ok(()));
}
#[test]
fn le_of_lits_refl() {
let env = crate::stdlib::std_env();
let proof = le_of_lits(3, 3);
let ty = le(nat_lit(3), nat_lit(3));
assert_eq!(check(&env, &ctx(), &proof, &ty), Ok(()));
}
}