/- Topolei.Cubical.EvalTest ======================== Roundtrip tests for the evaluator (cells-spec §13 Phase 1 Week 2 test: "eval roundtrip for simple terms"). Each test uses the axiom equations from `Eval.lean` to reduce an evaluation call to a normal form and check the expected value. These tests exercise: · free variables produce `nvar` neutrals, · identity lambda β-reduces correctly, · const-function β-reduces correctly (ignoring argument), · nested applications compose, · path abstractions close over their environment, · path applications β-reduce via `substDim`, · transport / composition terms produce the expected neutrals. -/ import CubicalTransport.Eval -- ── Free variable ─────────────────────────────────────────────────────────── /-- A free variable evaluates to a `nvar` neutral. -/ theorem eval_free_var (x : String) : eval .nil (.var x) = .vneu (.nvar x) := by rw [eval_var]; rfl -- ── Identity β-redex ──────────────────────────────────────────────────────── /-- `(λx. x) y` β-reduces to the value of `y`. With `y` free in the env, the result is `vneu (nvar "y")`. -/ theorem eval_identity_beta : eval .nil (.app (.lam "x" (.var "x")) (.var "y")) = .vneu (.nvar "y") := by rw [eval_app, eval_lam, eval_var] -- state: vApp (.vlam .nil "x" (.var "x")) ((CEnv.nil.lookup "y").getD _) = _ have hlookup : (CEnv.nil.lookup "y").getD (.vneu (.nvar "y")) = .vneu (.nvar "y") := rfl rw [hlookup, vApp_vlam, eval_var] -- state: ((CEnv.nil.extend "x" (vneu (nvar "y"))).lookup "x").getD _ = _ simp [CEnv.extend] -- ── Constant function ─────────────────────────────────────────────────────── /-- `(λx. z) y` β-reduces to the free variable `z`. -/ theorem eval_const_fun_beta : eval .nil (.app (.lam "x" (.var "z")) (.var "y")) = .vneu (.nvar "z") := by rw [eval_app, eval_lam, eval_var] have : (CEnv.nil.lookup "y").getD (.vneu (.nvar "y")) = .vneu (.nvar "y") := rfl rw [this, vApp_vlam, eval_var] -- After extend: lookup "z" in [("x", vneu "y")] → none → default simp [CEnv.extend, CEnv.lookup] -- ── Nested application ────────────────────────────────────────────────────── /-- `((λx. λy. x) a) b` β-reduces to `a` (K combinator applied). -/ theorem eval_K_combinator : eval .nil (.app (.app (.lam "x" (.lam "y" (.var "x"))) (.var "a")) (.var "b")) = .vneu (.nvar "a") := by rw [eval_app, eval_app, eval_lam, eval_var] have ha : (CEnv.nil.lookup "a").getD (.vneu (.nvar "a")) = .vneu (.nvar "a") := rfl rw [ha, vApp_vlam, eval_lam, eval_var] have hb : (CEnv.nil.lookup "b").getD (.vneu (.nvar "b")) = .vneu (.nvar "b") := rfl rw [hb, vApp_vlam, eval_var] -- env is now [("y", vneu "b"), ("x", vneu "a")]; lookup "x" finds "a". simp [CEnv.extend, CEnv.lookup] -- ── Stuck application ────────────────────────────────────────────────────── /-- Applying a free variable to another yields a stuck `napp` neutral. -/ theorem eval_stuck_app : eval .nil (.app (.var "f") (.var "x")) = .vneu (.napp (.nvar "f") (.vneu (.nvar "x"))) := by rw [eval_app, eval_var, eval_var] have hf : (CEnv.nil.lookup "f").getD (.vneu (.nvar "f")) = .vneu (.nvar "f") := rfl have hx : (CEnv.nil.lookup "x").getD (.vneu (.nvar "x")) = .vneu (.nvar "x") := rfl rw [hf, hx, vApp_vneu] -- ── Dimension abstraction and application ────────────────────────────────── /-- Path abstraction captures its environment as a `vplam`. -/ theorem eval_plam_closure (i : DimVar) (body : CTerm) : eval .nil (.plam i body) = .vplam .nil i body := eval_plam _ _ _ /-- Path application β-reduces via `CTerm.substDim`. -/ theorem eval_papp_beta (i : DimVar) (body : CTerm) (r : DimExpr) : eval .nil (.papp (.plam i body) r) = eval .nil (body.substDim i r) := by rw [eval_papp, eval_plam, vPApp_vplam] -- ── Transport and composition produce expected neutrals ──────────────────── -- ── Week 3: transport along refl = id ───────────────────────────────────── /-- T1 at eval level: transport under a `.top` face reduces to its argument. (This is the spec's Week 3 test "transport along refl = id".) -/ theorem eval_transp_top_id (i : DimVar) (A : CType) (x : String) : eval .nil (.transp i A .top (.var x)) = .vneu (.nvar x) := by rw [eval_transp_top, eval_var]; rfl /-- T2 at eval level: transport along a syntactically constant line reduces to its argument. For `A = .univ`, this holds for any `φ` — via `eval_transp_top` when `φ = .top` and via `eval_transp_const` otherwise. -/ theorem eval_transp_const_univ (i : DimVar) (φ : FaceFormula) (x : String) : eval .nil (.transp i .univ φ (.var x)) = .vneu (.nvar x) := by by_cases hφ : φ = .top · subst hφ; rw [eval_transp_top, eval_var]; rfl · rw [eval_transp_const _ _ _ _ _ hφ (rfl : CType.dimAbsent i .univ = true), eval_var]; rfl /-- T2 also discharges for `pi` when neither side mentions the binder. -/ theorem eval_transp_const_pi (i : DimVar) (φ : FaceFormula) (x : String) : eval .nil (.transp i (.pi .univ .univ) φ (.var x)) = .vneu (.nvar x) := by have h : CType.dimAbsent i (.pi .univ .univ) = true := rfl by_cases hφ : φ = .top · subst hφ; rw [eval_transp_top, eval_var]; rfl · rw [eval_transp_const _ _ _ _ _ hφ h, eval_var]; rfl /-- Transport at a free-variable argument under a stuck face and non-constant non-pi non-path non-glue line produces a neutral `ntransp`. The Π, Path, and Glue cases are handled by `eval_transp_pi` / `eval_transp_path` / the Glue-specific axioms in `Glue.lean`. -/ theorem eval_transp_neu (i : DimVar) (A : CType) (φ : FaceFormula) (x : String) (hφ : φ ≠ .top) (hA : CType.dimAbsent i A = false) (h_not_pi : ∀ domA codA, A ≠ .pi domA codA) (h_not_path : ∀ A₀ a b, A ≠ .path A₀ a b) (h_not_glue : ∀ φG T f fInv sec ret coh Ai, A ≠ .glue φG T f fInv sec ret coh Ai) : eval .nil (.transp i A φ (.var x)) = .vneu (.ntransp i A φ (.vneu (.nvar x))) := by rw [eval_transp_stuck _ _ _ _ _ hφ hA h_not_pi h_not_path h_not_glue, eval_var] rfl -- ── Π-case with constant domain, varying codomain ──────────────────────────── -- -- Concrete setup: codomain varies in dimension `i` but domain is `.univ` -- (constant). -- Body: `pi univ (path univ (var "a") (papp (var "p") (dim-var i)))`. private def i_dim : DimVar := ⟨"i"⟩ private def codAtype : CType := .path .univ (.var "a") (.papp (.var "p") (DimExpr.var i_dim)) private theorem codAtype_varies : CType.dimAbsent i_dim codAtype = false := by decide private theorem pi_univ_codA_varies : CType.dimAbsent i_dim (.pi .univ codAtype) = false := by decide /-- vTransp along `pi .univ codAtype` produces a `vTranspFun` closure carrying both the (constant) domain and the (varying) codomain. -/ theorem eval_transp_pi_const_dom_example (φ : FaceFormula) (hφ : φ ≠ .top) (f : String) : eval .nil (.transp i_dim (.pi .univ codAtype) φ (.var f)) = .vTranspFun i_dim .univ codAtype φ (.vneu (.nvar f)) := by rw [eval_transp_pi _ _ _ _ _ _ hφ pi_univ_codA_varies, eval_var] rfl /-- The CCHM Π β-rule at the value level, const-domain subcase. The inner `vTranspInv` reduces to identity by `vTranspInv_const` (since `.univ` is absent from `i_dim`), and the outer `vTransp` on the varying codomain stalls into a neutral. -/ theorem vApp_vTranspFun_const_dom_reduces (φ : FaceFormula) (hφ : φ ≠ .top) (f y : String) : vApp (.vTranspFun i_dim .univ codAtype φ (.vneu (.nvar f))) (.vneu (.nvar y)) = .vneu (.ntransp i_dim codAtype φ (.vneu (.napp (.nvar f) (.vneu (.nvar y))))) := by -- CCHM Π β-rule rw [vApp_vTranspFun] -- Inverse transport through constant domain `.univ` is identity rw [vTranspInv_const i_dim .univ φ _ (rfl : CType.dimAbsent i_dim .univ = true)] -- Apply `f` (a neutral) to `y` (a neutral) — stuck `napp` rw [vApp_vneu] -- Forward transport through the varying codomain — stuck neutral rw [vTransp_stuck _ _ _ _ hφ codAtype_varies (by intro _ _ h; nomatch h)] -- ── Π-case with varying domain, varying codomain ───────────────────────────── -- -- Concrete setup: BOTH domain and codomain vary in `i` — the full CCHM case -- where inverse transport is non-trivial. -- Body: `pi (path univ (var "a0") (papp (var "p") (dim-var i))) -- (path univ (var "b0") (papp (var "q") (dim-var i)))`. private def domAtype : CType := .path .univ (.var "a0") (.papp (.var "p") (DimExpr.var i_dim)) private def codBtype : CType := .path .univ (.var "b0") (.papp (.var "q") (DimExpr.var i_dim)) private theorem domAtype_varies : CType.dimAbsent i_dim domAtype = false := by decide private theorem codBtype_varies : CType.dimAbsent i_dim codBtype = false := by decide private theorem pi_varying_all : CType.dimAbsent i_dim (.pi domAtype codBtype) = false := by decide /-- vTransp along a pi with both sides varying still produces a unified `vTranspFun` — no special-case logic needed at the line level. -/ theorem eval_transp_pi_varying_dom (φ : FaceFormula) (hφ : φ ≠ .top) (f : String) : eval .nil (.transp i_dim (.pi domAtype codBtype) φ (.var f)) = .vTranspFun i_dim domAtype codBtype φ (.vneu (.nvar f)) := by rw [eval_transp_pi _ _ _ _ _ _ hφ pi_varying_all, eval_var] rfl /-- The reversed domain line also varies in `i_dim`. Reversing substitutes `i := inv i` in the right-endpoint `DimExpr.var i_dim`, producing `DimExpr.inv (DimExpr.var i_dim)`, which still mentions `i_dim`. -/ private theorem domAtype_reversed_varies : CType.dimAbsent i_dim (domAtype.substDimExpr i_dim (.inv (.var i_dim))) = false := by decide /-- Full CCHM Π β-rule in the **varying-domain** case. Applying a `vTranspFun i_dim domAtype codBtype φ f` to `y`: 1. inverse-transports `y` through `domAtype` → stuck (`ntransp i_dim (domAtype[i := inv i]) φ y`), 2. applies `f` to the stuck result → stuck `napp`, 3. forward-transports through `codBtype` → stuck `ntransp`. All three stalls cascade through the axiom equations without incident. -/ theorem vApp_vTranspFun_varying_dom_reduces (φ : FaceFormula) (hφ : φ ≠ .top) (f y : String) : vApp (.vTranspFun i_dim domAtype codBtype φ (.vneu (.nvar f))) (.vneu (.nvar y)) = .vneu (.ntransp i_dim codBtype φ (.vneu (.napp (.nvar f) (.vneu (.ntransp i_dim (domAtype.substDimExpr i_dim (.inv (.var i_dim))) φ (.vneu (.nvar y))))))) := by -- CCHM Π β-rule. rw [vApp_vTranspFun] -- Inverse transport unfolds to forward transport along the reversed line. unfold vTranspInv -- The reversed domAtype still varies in i_dim, so vTransp stalls. rw [vTransp_stuck _ _ _ _ hφ domAtype_reversed_varies (by intro _ _ h; nomatch h)] -- Apply the (neutral) f to the (now-neutral) argument → stuck `napp`. rw [vApp_vneu] -- Forward transport through the varying codomain → stuck `ntransp`. rw [vTransp_stuck _ _ _ _ hφ codBtype_varies (by intro _ _ h; nomatch h)] -- ── Heterogeneous composition: C1, C2, const-line, and stuck ──────────────── /-- **C1 at eval level**: `comp` under a `.top` face reduces to its system body substituted at the `.one` endpoint. Concrete exercise: with `u = .var "body"` (a free variable with no dim dependence) and `A = .univ`, the substitution is a no-op and the result is `vneu (nvar "body")`. -/ theorem eval_comp_top_example (i : DimVar) (t : String) : eval .nil (.comp i .univ .top (.var "body") (.var t)) = .vneu (.nvar "body") := by rw [eval_comp_top] -- (var "body").substDim i .one = var "body" (var case is trivial) simp only [CTerm.substDim] rw [eval_var] rfl /-- C1 at eval level, with a body that actually uses the line's dim var. The substitution replaces the dim, but here `papp (var "p") i` becomes `papp (var "p") .one`, which evaluates via `vPApp` on a neutral. -/ theorem eval_comp_top_dim_subst (i : DimVar) (t : String) : eval .nil (.comp i .univ .top (.papp (.var "p") (.var i)) (.var t)) = .vneu (.npapp (.nvar "p") .one) := by rw [eval_comp_top] -- Reduce `(papp (var "p") (var i)).substDim i .one`: -- substDim on papp = papp (t.substDim ..) (DimExpr.subst ..) -- var "p" unchanged; DimExpr.subst i .one (var i) collapses via if_true. simp only [CTerm.substDim, DimExpr.subst, if_true] rw [eval_papp, eval_var] have hp : (CEnv.nil.lookup "p").getD (.vneu (.nvar "p")) = .vneu (.nvar "p") := rfl rw [hp, vPApp_vneu] /-- **C2 at eval level**: `comp` under a `.bot` face reduces to `transp` under `.bot`. When the line `A` is constant (here `.univ`), T2 then reduces the transport to identity. -/ theorem eval_comp_bot_univ (i : DimVar) (u t : String) : eval .nil (.comp i .univ .bot (.var u) (.var t)) = .vneu (.nvar t) := by rw [eval_comp_bot] -- eval (transp i .univ .bot (var t)) rw [eval_transp_const _ _ _ _ _ (by intro h; nomatch h) (rfl : CType.dimAbsent i .univ = true), eval_var] rfl /-- **Constant-line comp = hcomp**: when `A` is constant in `i`, het comp reduces to plain homogeneous composition. The tube becomes `.plam i u` (a `vplam` closure). When the whole thing is then evaluated at `.top` face, hcomp's top-case fires and `vPApp`s the tube at `.one`. Verify end-to-end with a free-variable system body `u = .var "body"` (no dim dependence): the chain is comp (top) → substDim i .one → eval "body" → nvar "body". -/ theorem eval_comp_const_line (i : DimVar) (φ : FaceFormula) (hφ₁ : φ ≠ .top) (hφ₂ : φ ≠ .bot) (t : String) : eval .nil (.comp i .univ φ (.var "body") (.var t)) = .vneu (.nhcomp .univ φ (.vplam .nil i (.var "body")) (.vneu (.nvar t))) := by rw [eval_comp_const _ _ _ _ _ _ hφ₁ hφ₂ (rfl : CType.dimAbsent i .univ = true)] rw [eval_plam, eval_var] have : (CEnv.nil.lookup t).getD (.vneu (.nvar t)) = .vneu (.nvar t) := rfl rw [this] -- `vHCompValue .univ φ (vplam nil i (var "body")) (vneu (nvar t))` -- → stuck, since .univ is not .pi. exact vHCompValue_stuck _ _ _ _ hφ₁ (by intro _ _ h; nomatch h) /-- Stuck comp: free variables, non-constant non-pi line, non-top non-bot face. -/ theorem eval_comp_neu (i : DimVar) (A : CType) (φ : FaceFormula) (u t : String) (hφ₁ : φ ≠ .top) (hφ₂ : φ ≠ .bot) (hA : CType.dimAbsent i A = false) (h_not_pi : ∀ domA codA, A ≠ .pi domA codA) : eval .nil (.comp i A φ (.var u) (.var t)) = .vneu (.ncomp i A φ (.vneu (.nvar u)) (.vneu (.nvar t))) := by rw [eval_comp_stuck _ _ _ _ _ _ hφ₁ hφ₂ hA h_not_pi, eval_var, eval_var] have hu : (CEnv.nil.lookup u).getD (.vneu (.nvar u)) = .vneu (.nvar u) := rfl have ht : (CEnv.nil.lookup t).getD (.vneu (.nvar t)) = .vneu (.nvar t) := rfl rw [hu, ht] -- ── Π hcomp: CCHM β-rule with pointwise reduction ────────────────────────── /-- **Π hcomp β-rule at `.top`**: `hcomp (pi A B) .top tube base` is `vPApp tube .one` by `vHCompValue_top` — the tube covers the whole cube, so the composition's result is just the tube at `1`. Demonstrate with a vplam tube: `tube = vplam .nil j (var "u_body")`. The result is `eval .nil ((var "u_body").substDim j .one) = vneu (nvar "u_body")`. -/ theorem vHCompValue_top_reduces (j : DimVar) (base : CVal) : vHCompValue (.pi .univ .univ) .top (.vplam .nil j (.var "u_body")) base = .vneu (.nvar "u_body") := by rw [vHCompValue_top, vPApp_vplam] -- (var "u_body").substDim j .one = var "u_body" (no dim usage) simp only [CTerm.substDim] rw [eval_var] rfl /-- **Π hcomp β-rule** at a non-top face, with concrete structure. Apply `hcomp (pi .univ .univ) φ tube base` to `y` where: · tube = `.vneu (.nvar "tube")` (a free variable), · base = `.vneu (.nvar "base_fn")` (a free function), · y = `.vneu (.nvar "y")`. Expected reduction chain: 1. `vHCompValue_pi` produces `vHCompFun .univ φ tube base`. 2. `vApp_vHCompFun` unfolds to `vHCompValue .univ φ (.vTubeApp tube y) (vApp base y)`. 3. `vApp_vneu` reduces `vApp base y` to `napp (nvar "base_fn") y`. 4. `vHCompValue_stuck` on `.univ` produces the final neutral `nhcomp`. -/ theorem vApp_vHCompFun_reduces (φ : FaceFormula) (hφ : φ ≠ .top) : vApp (.vHCompFun .univ φ (.vneu (.nvar "tube")) (.vneu (.nvar "base_fn"))) (.vneu (.nvar "y")) = .vneu (.nhcomp .univ φ (.vTubeApp (.vneu (.nvar "tube")) (.vneu (.nvar "y"))) (.vneu (.napp (.nvar "base_fn") (.vneu (.nvar "y"))))) := by rw [vApp_vHCompFun, vApp_vneu, vHCompValue_stuck _ _ _ _ hφ (by intro _ _ h; nomatch h)] /-- **vTubeApp reduction**: `(λj. (tube @ j) arg) @ r = (tube @ r) arg`. Exercised with a vplam tube: `tube = vplam .nil j (var "u_body")`. The chain: 1. `vPApp_vTubeApp` unfolds to `vApp (vPApp tube r) arg`. 2. `vPApp_vplam` reduces the inner `vPApp` to `eval .nil ("u_body"[j := r])`. 3. The body doesn't mention j, so the substDim is identity. 4. `eval_var` looks up "u_body" → `nvar "u_body"`. 5. `vApp_vneu` produces `napp (nvar "u_body") arg`. -/ theorem vPApp_vTubeApp_reduces (j : DimVar) (r : DimExpr) : vPApp (.vTubeApp (.vplam .nil j (.var "u_body")) (.vneu (.nvar "arg"))) r = .vneu (.napp (.nvar "u_body") (.vneu (.nvar "arg"))) := by rw [vPApp_vTubeApp, vPApp_vplam] -- substDim j r (var "u_body") = var "u_body" (no dim dep) simp only [CTerm.substDim] rw [eval_var] have hlook : (CEnv.nil.lookup "u_body").getD (.vneu (.nvar "u_body")) = .vneu (.nvar "u_body") := rfl rw [hlook, vApp_vneu] -- ── Path transport: CCHM endpoint reductions ───────────────────────────────── -- -- Concrete path-transport setup. A varying path line -- `path A₀(i) a(i) b(i)` -- where A₀ = .univ (so it doesn't vary), -- a = .var "a_line" (free variable; here conservatively no i-dep, -- but could have), -- b = .papp (.var "b_pt") (DimExpr.var i_dim) — uses i_dim -- The right endpoint `b` mentions `i_dim`, so the whole path line varies. private def pathLine_a : CTerm := .var "a_line" private def pathLine_b : CTerm := .papp (.var "b_pt") (DimExpr.var i_dim) private def pathLineA : CType := .path .univ pathLine_a pathLine_b private theorem pathLineA_varies : CType.dimAbsent i_dim pathLineA = false := by decide /-- Transport along a varying path line produces a `vPathTransp` closure storing the path term (as a CTerm, not a value). -/ theorem eval_transp_path_example (φ : FaceFormula) (hφ : φ ≠ .top) (p : String) : eval .nil (.transp i_dim pathLineA φ (.var p)) = .vPathTransp .nil i_dim .univ pathLine_a pathLine_b φ (.var p) := by show eval .nil (.transp i_dim (.path .univ pathLine_a pathLine_b) φ (.var p)) = _ rw [eval_transp_path _ _ _ _ _ _ _ hφ pathLineA_varies] /-- **Path transport at the `.zero` endpoint**: CCHM's `(j=0)` clause fires, yielding the line's left endpoint at `i=1` — here `.var "a_line"` (which has no `i`-dep, so its `substDim i .one` is itself). -/ theorem vPApp_vPathTransp_zero_reduces (φ : FaceFormula) (p : CTerm) : vPApp (.vPathTransp .nil i_dim .univ pathLine_a pathLine_b φ p) .zero = .vneu (.nvar "a_line") := by rw [vPApp_vPathTransp_zero] -- pathLine_a.substDim i_dim .one = pathLine_a (no dim dep; var case) show eval .nil (CTerm.substDim i_dim .one (.var "a_line")) = _ simp only [CTerm.substDim] rw [eval_var]; rfl /-- **Path transport at the `.one` endpoint**: CCHM's `(j=1)` clause fires, yielding the line's right endpoint at `i=1`. Here `pathLine_b` mentions `i_dim`, so its `substDim i_dim .one` replaces the dim variable with `.one`, producing `papp (var "b_pt") .one`. Evaluation then gives `npapp (nvar "b_pt") .one`. -/ theorem vPApp_vPathTransp_one_reduces (φ : FaceFormula) (p : CTerm) : vPApp (.vPathTransp .nil i_dim .univ pathLine_a pathLine_b φ p) .one = .vneu (.npapp (.nvar "b_pt") .one) := by rw [vPApp_vPathTransp_one] -- pathLine_b.substDim i_dim .one = papp (var "b_pt") (DimExpr.subst i_dim .one (DimExpr.var i_dim)) -- = papp (var "b_pt") .one simp only [pathLine_b, CTerm.substDim, DimExpr.subst, if_true] rw [eval_papp, eval_var] have hb : (CEnv.nil.lookup "b_pt").getD (.vneu (.nvar "b_pt")) = .vneu (.nvar "b_pt") := rfl rw [hb, vPApp_vneu] /-- When the path line is fully constant (all of A₀, a, b absent from i), transport reduces via T2 at eval level (arm 2), returning the base unchanged — no `vPathTransp` produced. -/ theorem eval_transp_constant_path (i : DimVar) (φ : FaceFormula) (p : String) : eval .nil (.transp i (.path .univ (.var "a0") (.var "b0")) φ (.var p)) = .vneu (.nvar p) := by have hA : CType.dimAbsent i (.path .univ (.var "a0") (.var "b0")) = true := rfl by_cases hφ : φ = .top · subst hφ; rw [eval_transp_top, eval_var]; rfl · rw [eval_transp_const _ _ _ _ _ hφ hA, eval_var] rfl -- ── Multi-clause comp reductions ─────────────────────────────────────────────── /-- **Empty multi-clause comp reduces to plain transport.** A `compN` with no clauses has no system — nothing to override, so the result is just transport of the base. Demonstrated with `A = .univ` where transport is identity (via T2). -/ theorem eval_compN_empty (i : DimVar) (t : String) : eval .nil (.compN i .univ [] (.var t)) = .vneu (.nvar t) := by rw [eval_compN, vCompNAtTerm_def] -- find? on [] is none; filter on [] is []; [] arm → transport simp only [List.find?, List.filter] -- Now: eval .nil (.transp i .univ .bot (.var t)) rw [eval_transp_const _ _ _ _ _ (by intro h; nomatch h) (rfl : CType.dimAbsent i .univ = true), eval_var] rfl /-- **compN with a `.top`-faced clause fires on that clause**, returning the clause's body substituted at `i := .one`. This is the CCHM full-system rule lifted to multi-clause. -/ theorem eval_compN_top_fires (i : DimVar) (u t : String) : eval .nil (.compN i .univ [(.top, .var u)] (.var t)) = .vneu (.nvar u) := by rw [eval_compN, vCompNAtTerm_def] -- find? matches the (.top, _) head immediately. simp only [List.find?] -- Goal: eval .nil ((var u).substDim i .one) = vneu (nvar u) simp only [CTerm.substDim] rw [eval_var]; rfl /-- **compN where a `.top` clause is NOT at the head but later**: the scanning `find?` still picks it up. Exercised with clauses `[(φ, _), (.top, u)]` for some non-top `φ`. -/ theorem eval_compN_top_later (i : DimVar) (u t : String) (k : DimVar) : eval .nil (.compN i .univ [(.eq0 k, .var "dummy"), (.top, .var u)] (.var t)) = .vneu (.nvar u) := by rw [eval_compN, vCompNAtTerm_def] -- find? skips (.eq0 k, _), hits (.top, _) simp only [List.find?] simp only [CTerm.substDim] rw [eval_var]; rfl -- ── Path transport at a composite endpoint (inv .zero = .one) ──────────────── -- -- Demonstrates the key correctness property: even when the applied dim -- expression isn't literally `.zero` or `.one`, if it *evaluates to* an -- endpoint (e.g. `.inv .zero = 1`), the multi-clause `dimExprEq1` helper -- detects this and fires the corresponding clause. /-- **Path transport at `inv .zero`** (= 1 semantically) fires the (j=1) clause of the CCHM multi-clause system, yielding `b(1)`. Exercises: · `FaceFormula.dimExprEq0 (inv .zero) = dimExprEq1 .zero = .bot` · `FaceFormula.dimExprEq1 (inv .zero) = dimExprEq0 .zero = .top` So the compN system becomes `[(φ, _), (.bot, a), (.top, b)]` and `vCompNAtTerm`'s `find?` picks the third clause. -/ theorem vPApp_vPathTransp_inv_zero (φ : FaceFormula) (hφ : φ ≠ .top) (hφbot : φ ≠ .bot) (p : CTerm) : vPApp (.vPathTransp .nil i_dim .univ pathLine_a pathLine_b φ p) (.inv .zero) = .vneu (.npapp (.nvar "b_pt") .one) := by rw [vPApp_vPathTransp_general _ _ _ _ _ _ _ _ (by intro h; nomatch h) (by intro h; nomatch h)] -- After: vCompNAtTerm .nil i_dim .univ -- [(φ, p@(inv 0)), (dimExprEq0 (inv 0), a), (dimExprEq1 (inv 0), b)] -- (p@(inv 0)) rw [vCompNAtTerm_def] -- Reduce the dimExprEq0/dimExprEq1 at inv .zero: -- dimExprEq0 (inv .zero) = dimExprEq1 .zero = .bot -- dimExprEq1 (inv .zero) = dimExprEq0 .zero = .top simp only [FaceFormula.dimExprEq0, FaceFormula.dimExprEq1] -- Now `find?` scans [(φ, _), (.bot, _), (.top, _)]. It skips φ (non-top -- by hφ), skips .bot (non-top), hits .top. -- The `match φ with .top => ... | _ => ...` on the head first clause -- reduces to `| _ => false` since φ ≠ .top. have _hφtop_eq : (match φ with | .top => true | _ => false) = false := by cases φ <;> first | rfl | exact absurd rfl hφ simp only [List.find?] -- Now `find?` on [(.bot, a), (.top, b)]: skip .bot, match .top. -- Continue reducing: show eval .nil (pathLine_b.substDim i_dim .one) = _ simp only [pathLine_b, CTerm.substDim, DimExpr.subst, if_true] rw [eval_papp, eval_var] have hb : (CEnv.nil.lookup "b_pt").getD (.vneu (.nvar "b_pt")) = .vneu (.nvar "b_pt") := rfl rw [hb, vPApp_vneu] -- ── Heterogeneous Π composition ───────────────────────────────────────────── /-- **Hetero Π comp produces a `vCompFun`**: evaluating `comp^i (pi A B) φ u t` when the pi line genuinely varies packages everything into a closure that runs the CCHM β-rule on application. -/ theorem eval_comp_pi_example (u_name t_name : String) (φ : FaceFormula) (hφ₁ : φ ≠ .top) (hφ₂ : φ ≠ .bot) : eval .nil (.comp i_dim (.pi domAtype codBtype) φ (.var u_name) (.var t_name)) = .vCompFun .nil i_dim domAtype codBtype φ (.var u_name) (.var t_name) := by rw [eval_comp_pi _ _ _ _ _ _ _ hφ₁ hφ₂ pi_varying_all] /-- **Const-domain hetero Π comp β degenerate case**: when `domA = .univ` (const in i), the fill `y_at_i` and `y_at_0` both reduce to `y` (via `vTransp_const`). The inner comp becomes just `comp^i codB φ (u y) (t y)`. -/ theorem vApp_vCompFun_const_dom_example (u_name t_name y_name : String) (φ : FaceFormula) : vApp (.vCompFun .nil i_dim .univ codBtype φ (.var u_name) (.var t_name)) (.vneu (.nvar y_name)) = eval (CEnv.nil.extend "$y" (.vneu (.nvar y_name))) (.comp i_dim codBtype φ (.app (.var u_name) (.transp ⟨"$fj"⟩ ((CType.univ).substDimExpr i_dim (.join (.inv (.var ⟨"$fj"⟩)) (.var i_dim))) φ (.var "$y"))) (.app (.var t_name) (.transp ⟨"$fj"⟩ ((CType.univ).substDimExpr i_dim (.inv (.var ⟨"$fj"⟩))) φ (.var "$y")))) := by rw [vApp_vCompFun] /-- **Varying-domain hetero Π comp β** also fires, producing the CCHM fill-based inner comp term. Uses `domAtype` (genuinely varying in i). -/ theorem vApp_vCompFun_varying_dom_fires (u_name t_name y_name : String) (φ : FaceFormula) : vApp (.vCompFun .nil i_dim domAtype codBtype φ (.var u_name) (.var t_name)) (.vneu (.nvar y_name)) = eval (CEnv.nil.extend "$y" (.vneu (.nvar y_name))) (.comp i_dim codBtype φ (.app (.var u_name) (.transp ⟨"$fj"⟩ (domAtype.substDimExpr i_dim (.join (.inv (.var ⟨"$fj"⟩)) (.var i_dim))) φ (.var "$y"))) (.app (.var t_name) (.transp ⟨"$fj"⟩ (domAtype.substDimExpr i_dim (.inv (.var ⟨"$fj"⟩))) φ (.var "$y")))) := by rw [vApp_vCompFun] /-- **Spot-check of the fill's endpoint correctness** at the CType level: `domAtype.substDimExpr i_dim (.join (.inv (.var fj)) (.var i_dim))` is NOT equal to `domAtype` (genuine substitution happens), confirming the fill construction is non-trivial. -/ example : domAtype.substDimExpr i_dim (.join (.inv (.var ⟨"$fj"⟩)) (.var i_dim)) = .path .univ (.var "a0") (.papp (.var "p") (.join (.inv (.var ⟨"$fj"⟩)) (.var i_dim))) := by simp only [domAtype, CType.substDimExpr, CTerm.substDim, DimExpr.subst] rfl