use std::collections::BTreeSet;
use logicaffeine_kernel::prelude::StandardLibrary;
use logicaffeine_kernel::{infer_type, Context, Term};
use logicaffeine_proof::certifier::{certify, CertificationContext};
use logicaffeine_proof::polycalc::{partition_of_unity, pou_as_product, pou_atom};
use logicaffeine_proof::{DerivationTree, InferenceRule, ProofExpr, ProofTerm};
fn g(n: &str) -> Term {
Term::Global(n.to_string())
}
fn kvar(n: &str) -> Term {
Term::Var(n.to_string())
}
fn app(f: Term, x: Term) -> Term {
Term::App(Box::new(f), Box::new(x))
}
fn pi(param: &str, ty: Term, body: Term) -> Term {
Term::Pi { param: param.to_string(), param_type: Box::new(ty), body_type: Box::new(body) }
}
fn nat() -> Term {
g("Nat")
}
fn entity() -> Term {
g("Entity")
}
fn keq(a: Term, b: Term) -> Term {
app(app(app(g("Eq"), entity()), a), b)
}
fn kpou(n: Term) -> Term {
app(g("PoU"), n)
}
fn krmul(a: Term, b: Term) -> Term {
app(app(g("rmul"), a), b)
}
fn ksucc(n: Term) -> Term {
app(g("Succ"), n)
}
fn id(a: ProofTerm, b: ProofTerm) -> ProofExpr {
ProofExpr::Identity(a, b)
}
fn ppou(n: ProofTerm) -> ProofTerm {
ProofTerm::Function("PoU".to_string(), vec![n])
}
fn prmul(a: ProofTerm, b: ProofTerm) -> ProofTerm {
ProofTerm::Function("rmul".to_string(), vec![a, b])
}
fn psucc(n: ProofTerm) -> ProofTerm {
ProofTerm::Function("Succ".to_string(), vec![n])
}
fn pk() -> ProofTerm {
ProofTerm::Variable("k".to_string())
}
fn pone() -> ProofTerm {
ProofTerm::Constant("one".to_string())
}
fn patom() -> ProofTerm {
ProofTerm::Constant("atom".to_string())
}
fn pzero() -> ProofTerm {
ProofTerm::Constant("Zero".to_string())
}
fn forall(v: &str, body: ProofExpr) -> ProofExpr {
ProofExpr::ForAll { variable: v.to_string(), body: Box::new(body) }
}
fn named(name: &str) -> DerivationTree {
DerivationTree::leaf(ProofExpr::Atom(name.to_string()), InferenceRule::PremiseMatch)
}
fn one_poly() -> BTreeSet<u64> {
[0u64].into_iter().collect()
}
fn theory_context() -> Context {
let mut ctx = Context::new();
StandardLibrary::register(&mut ctx);
ctx.add_declaration("one", entity());
ctx.add_declaration("atom", entity());
ctx.add_declaration("rmul", pi("_", entity(), pi("_", entity(), entity())));
ctx.add_declaration("PoU", pi("_", nat(), entity()));
ctx.add_declaration("def_zero", keq(kpou(g("Zero")), g("one")));
ctx.add_declaration(
"def_succ",
pi("j", nat(), keq(kpou(ksucc(kvar("j"))), krmul(kpou(kvar("j")), g("atom")))),
);
ctx.add_declaration(
"ring_step",
pi("j", nat(), keq(krmul(kpou(kvar("j")), g("atom")), kpou(kvar("j")))),
);
ctx
}
#[test]
fn full_kernel_integration_derives_no_finite_randomness_for_all_n() {
assert_eq!(partition_of_unity(0), one_poly(), "model ⊨ def_zero: PoU(0) = 1");
for v in 0..8 {
assert_eq!(pou_atom(v), one_poly(), "model ⊨ ring_step: atom (=(1+x)+x) is the identity 1");
}
for n in 0..12 {
assert_eq!(partition_of_unity(n + 1), partition_of_unity(n), "model ⊨ recurrence: PoU(n+1) = PoU(n)·atom = PoU(n)");
assert_eq!(partition_of_unity(n), pou_as_product(n), "the factorization the axioms abstract");
}
let ctx = theory_context();
let ui_succ = DerivationTree::new(
id(ppou(psucc(pk())), prmul(ppou(pk()), patom())),
InferenceRule::UniversalInst("k".to_string()),
vec![named("def_succ")],
);
let ui_ring = DerivationTree::new(
id(prmul(ppou(pk()), patom()), ppou(pk())),
InferenceRule::UniversalInst("k".to_string()),
vec![named("ring_step")],
);
let step_eq = DerivationTree::new(
id(ppou(psucc(pk())), ppou(pk())),
InferenceRule::EqualityTransitivity,
vec![ui_succ, ui_ring],
);
let ih = DerivationTree::leaf(id(ppou(pk()), pone()), InferenceRule::PremiseMatch);
let step = DerivationTree::new(
id(ppou(psucc(pk())), pone()),
InferenceRule::EqualityTransitivity,
vec![step_eq, ih],
);
let tree = DerivationTree::new(
forall("n", id(ppou(ProofTerm::Variable("n".to_string())), pone())),
InferenceRule::StructuralInduction {
variable: "n".to_string(),
ind_type: "Nat".to_string(),
step_var: "k".to_string(),
},
vec![named("def_zero"), step],
);
let cert_ctx = CertificationContext::new(&ctx);
let term = certify(&tree, &cert_ctx).expect("the ∀n induction certifies to a Fix/Match term");
let inferred =
infer_type(&ctx, &term).expect("the certified induction term must type-check in the kernel");
assert!(
matches!(inferred, Term::Pi { .. }),
"expected ∀n:Nat. Eq Entity (PoU n) one, got {inferred}"
);
}
#[test]
fn skipping_the_ring_axiom_fails_the_kernel_type_check() {
let ctx = theory_context();
let ui_succ = DerivationTree::new(
id(ppou(psucc(pk())), prmul(ppou(pk()), patom())),
InferenceRule::UniversalInst("k".to_string()),
vec![named("def_succ")],
);
let ih = DerivationTree::leaf(id(ppou(pk()), pone()), InferenceRule::PremiseMatch);
let broken_step = DerivationTree::new(
id(ppou(psucc(pk())), pone()),
InferenceRule::EqualityTransitivity,
vec![ui_succ, ih],
);
let tree = DerivationTree::new(
forall("n", id(ppou(ProofTerm::Variable("n".to_string())), pone())),
InferenceRule::StructuralInduction {
variable: "n".to_string(),
ind_type: "Nat".to_string(),
step_var: "k".to_string(),
},
vec![named("def_zero"), broken_step],
);
let cert_ctx = CertificationContext::new(&ctx);
let verified = matches!(
certify(&tree, &cert_ctx).and_then(|term| infer_type(&ctx, &term)),
Ok(Term::Pi { .. })
);
assert!(!verified, "a step that skips ring_step must NOT yield a kernel-checked ∀n theorem");
}