cubical-transport-hott-lean4/CubicalTransport/DecEq.lean
Maximus Gorog 271b47102e
Some checks are pending
Lean Action CI / build (push) Waiting to run
QUESTIONS Levels 1.5 + 2: full DecidableEq + simp routing
Lands the foundational DecidableEq machinery and the @[simp]-
based question-form routing in one go (per project discipline:
no shortcuts, no compat shims).

CubicalTransport/DecEq.lean (new, ~290 lines):
- Mutual decEq for the 5-way AST block (CType, CTerm, CTypeArg,
  CtorSpec, CTypeSchema) plus list/clause/branch helpers
  (decEqListCType, decEqListCTerm, decEqListCTypeArg,
  decEqListCtorSpec, decEqClauses, decEqBranches).
- Returns Decidable (a = b) directly; uses OR-patterns for
  cross-constructor mismatches, discharged uniformly via cases.
- Five DecidableEq instances declared post-block.
- Lean 4 deriving doesn't support mutual inductives; manual
  decEq is the canonical approach.

CubicalTransport/Interval.lean: deriving DecidableEq on DimExpr.
CubicalTransport/Face.lean: deriving DecidableEq on FaceFormula.

CubicalTransport/Question.lean:
- All 11 classifier Decidable instances now land:
    IsConstLine, IsFullFace, IsEmptyFace, IsTransport,
    IsIntervalLine, IsUnivLine — direct from DecidableEq.
    IsPathLine, IsPiLine, IsSigmaLine, IsGlueLine, IsIndLine —
    via match h : q.body with on the head constructor +
    existential-witness reconstruction in the isTrue arm.
- @[simp] tags on ask_of_full_face / ask_of_empty_face /
  ask_of_const_line / ask_of_transport_full_face — the Level 2
  routing through CompQ.Equiv.
- Three example proofs at end of file demonstrating that the
  simp-set composes (full-face C1, empty-face C2, transport-
  shaped interval-line reduction).

CubicalTransport/FFITest.lean: 6 new classifier-decidability
smoke tests (IsFullFace, IsTransport×2, IsPiLine, IsIntervalLine).
Test count: 84 → 89 passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 00:34:14 -06:00

399 lines
22 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
CubicalTransport.DecEq
======================
Decidable equality for the 5-way mutual block (`CType`, `CTerm`,
`CTypeArg`, `CtorSpec`, `CTypeSchema`) plus the list/pair helper
shapes that appear inside it.
Lean 4's `deriving instance DecidableEq` does not currently support
mutual inductives — has to be written manually. The mutual `decEq`
block returns `Decidable (a = b)` directly; instances are then
declared post-hoc.
Imports `CubicalTransport.Syntax` and depends on the `DecidableEq`
instances for `DimVar`, `DimExpr`, and `FaceFormula` (added in
`Interval.lean` / `Face.lean`).
Used by `CubicalTransport.Question` for syntactic-classifier
decidability (`IsFullFace`, `IsEmptyFace`, `IsIntervalLine`,
`IsUnivLine`, `IsTransport`, `IsPathLine`, …). Cells-spec /
paideia downstream consumers also benefit (they want to compare
AST nodes when normalising / dispatching).
-/
import CubicalTransport.Syntax
namespace CubicalTransport.DecEq
-- ── Mutual decEq block ──────────────────────────────────────────────────────
-- Every Decidable (a = b) on the 5 AST types and their list/pair
-- helpers lives here. The block is structurally recursive on the AST
-- subterms and uses Lean's automatic recognition of OR-patterns to
-- collapse cross-constructor mismatches into a single `isFalse` arm.
mutual
def CType.decEq : (a b : CType) → Decidable (a = b)
| .univ, .univ => isTrue rfl
| .pi A B, .pi A' B' =>
match CType.decEq A A', CType.decEq B B' with
| isTrue hA, isTrue hB => isTrue (by rw [hA, hB])
| isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
| .path A a b, .path A' a' b' =>
match CType.decEq A A', CTerm.decEq a a', CTerm.decEq b b' with
| isTrue hA, isTrue ha, isTrue hb => isTrue (by rw [hA, ha, hb])
| isFalse h, _, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
| .sigma A B, .sigma A' B' =>
match CType.decEq A A', CType.decEq B B' with
| isTrue hA, isTrue hB => isTrue (by rw [hA, hB])
| isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
| .glue ψ T f fInv s r c A, .glue ψ' T' f' fInv' s' r' c' A' =>
if hψ : ψ = ψ' then
match CType.decEq T T', CTerm.decEq f f', CTerm.decEq fInv fInv',
CTerm.decEq s s', CTerm.decEq r r', CTerm.decEq c c',
CType.decEq A A' with
| isTrue hT, isTrue hf, isTrue hfI, isTrue hs, isTrue hr, isTrue hc, isTrue hA =>
isTrue (by rw [hψ, hT, hf, hfI, hs, hr, hc, hA])
| isFalse h, _, _, _, _, _, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h, _, _, _, _, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, _, isFalse h, _, _, _, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, _, _, isFalse h, _, _, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, _, _, _, isFalse h, _, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, _, _, _, _, isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, _, _, _, _, _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
else
isFalse (fun heq => hψ (by cases heq; rfl))
| .ind S ps, .ind S' ps' =>
match CTypeSchema.decEq S S', decEqListCType ps ps' with
| isTrue hS, isTrue hp => isTrue (by rw [hS, hp])
| isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
| .interval, .interval => isTrue rfl
-- Cross-constructor mismatches. Each row enumerates the (a, b)
-- shapes where the head constructors differ; `cases heq` discharges
-- because the eliminator treats them as inhabited-but-equal-only-
-- between-same-constructor.
| .univ, .pi _ _ | .univ, .path _ _ _ | .univ, .sigma _ _
| .univ, .glue _ _ _ _ _ _ _ _ | .univ, .ind _ _ | .univ, .interval
| .pi _ _, .univ | .pi _ _, .path _ _ _ | .pi _ _, .sigma _ _
| .pi _ _, .glue _ _ _ _ _ _ _ _ | .pi _ _, .ind _ _ | .pi _ _, .interval
| .path _ _ _, .univ | .path _ _ _, .pi _ _ | .path _ _ _, .sigma _ _
| .path _ _ _, .glue _ _ _ _ _ _ _ _ | .path _ _ _, .ind _ _ | .path _ _ _, .interval
| .sigma _ _, .univ | .sigma _ _, .pi _ _ | .sigma _ _, .path _ _ _
| .sigma _ _, .glue _ _ _ _ _ _ _ _ | .sigma _ _, .ind _ _ | .sigma _ _, .interval
| .glue _ _ _ _ _ _ _ _, .univ | .glue _ _ _ _ _ _ _ _, .pi _ _
| .glue _ _ _ _ _ _ _ _, .path _ _ _ | .glue _ _ _ _ _ _ _ _, .sigma _ _
| .glue _ _ _ _ _ _ _ _, .ind _ _ | .glue _ _ _ _ _ _ _ _, .interval
| .ind _ _, .univ | .ind _ _, .pi _ _ | .ind _ _, .path _ _ _
| .ind _ _, .sigma _ _ | .ind _ _, .glue _ _ _ _ _ _ _ _ | .ind _ _, .interval
| .interval, .univ | .interval, .pi _ _ | .interval, .path _ _ _
| .interval, .sigma _ _ | .interval, .glue _ _ _ _ _ _ _ _ | .interval, .ind _ _ =>
isFalse (fun heq => by cases heq)
def CTerm.decEq : (a b : CTerm) → Decidable (a = b)
| .var x, .var y =>
if h : x = y then isTrue (by rw [h]) else isFalse (fun heq => h (by cases heq; rfl))
| .lam x t, .lam y u =>
if hx : x = y then
match CTerm.decEq t u with
| isTrue ht => isTrue (by rw [hx, ht])
| isFalse h => isFalse (fun heq => h (by cases heq; rfl))
else
isFalse (fun heq => hx (by cases heq; rfl))
| .app f a, .app f' a' =>
match CTerm.decEq f f', CTerm.decEq a a' with
| isTrue hf, isTrue ha => isTrue (by rw [hf, ha])
| isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
| .plam i t, .plam j u =>
if hi : i = j then
match CTerm.decEq t u with
| isTrue ht => isTrue (by rw [hi, ht])
| isFalse h => isFalse (fun heq => h (by cases heq; rfl))
else
isFalse (fun heq => hi (by cases heq; rfl))
| .papp t r, .papp u s =>
if hr : r = s then
match CTerm.decEq t u with
| isTrue ht => isTrue (by rw [hr, ht])
| isFalse h => isFalse (fun heq => h (by cases heq; rfl))
else
isFalse (fun heq => hr (by cases heq; rfl))
| .transp i A φ t, .transp j B ψ u =>
if hi : i = j then if hφ : φ = ψ then
match CType.decEq A B, CTerm.decEq t u with
| isTrue hA, isTrue ht => isTrue (by rw [hi, hA, hφ, ht])
| isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
else isFalse (fun heq => hφ (by cases heq; rfl))
else isFalse (fun heq => hi (by cases heq; rfl))
| .comp i A φ u t, .comp j B ψ u' t' =>
if hi : i = j then if hφ : φ = ψ then
match CType.decEq A B, CTerm.decEq u u', CTerm.decEq t t' with
| isTrue hA, isTrue hu, isTrue ht => isTrue (by rw [hi, hA, hφ, hu, ht])
| isFalse h, _, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
else isFalse (fun heq => hφ (by cases heq; rfl))
else isFalse (fun heq => hi (by cases heq; rfl))
| .compN i A cs t, .compN j B cs' t' =>
if hi : i = j then
match CType.decEq A B, decEqClauses cs cs', CTerm.decEq t t' with
| isTrue hA, isTrue hc, isTrue ht => isTrue (by rw [hi, hA, hc, ht])
| isFalse h, _, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
else isFalse (fun heq => hi (by cases heq; rfl))
| .glueIn φ t a, .glueIn ψ u b =>
if hφ : φ = ψ then
match CTerm.decEq t u, CTerm.decEq a b with
| isTrue ht, isTrue ha => isTrue (by rw [hφ, ht, ha])
| isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
else isFalse (fun heq => hφ (by cases heq; rfl))
| .unglue φ f g, .unglue ψ f' g' =>
if hφ : φ = ψ then
match CTerm.decEq f f', CTerm.decEq g g' with
| isTrue hf, isTrue hg => isTrue (by rw [hφ, hf, hg])
| isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
else isFalse (fun heq => hφ (by cases heq; rfl))
| .pair a b, .pair a' b' =>
match CTerm.decEq a a', CTerm.decEq b b' with
| isTrue ha, isTrue hb => isTrue (by rw [ha, hb])
| isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
| .fst t, .fst u =>
match CTerm.decEq t u with
| isTrue ht => isTrue (by rw [ht])
| isFalse h => isFalse (fun heq => h (by cases heq; rfl))
| .snd t, .snd u =>
match CTerm.decEq t u with
| isTrue ht => isTrue (by rw [ht])
| isFalse h => isFalse (fun heq => h (by cases heq; rfl))
| .dimExpr r, .dimExpr s =>
if h : r = s then isTrue (by rw [h]) else isFalse (fun heq => h (by cases heq; rfl))
| .ctor S c ps as, .ctor S' c' ps' as' =>
if hc : c = c' then
match CTypeSchema.decEq S S', decEqListCType ps ps', decEqListCTerm as as' with
| isTrue hS, isTrue hp, isTrue ha => isTrue (by rw [hS, hc, hp, ha])
| isFalse h, _, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
else isFalse (fun heq => hc (by cases heq; rfl))
| .indElim S ps m bs t, .indElim S' ps' m' bs' t' =>
match CTypeSchema.decEq S S', decEqListCType ps ps',
CTerm.decEq m m', decEqBranches bs bs', CTerm.decEq t t' with
| isTrue hS, isTrue hp, isTrue hm, isTrue hb, isTrue ht =>
isTrue (by rw [hS, hp, hm, hb, ht])
| isFalse h, _, _, _, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h, _, _, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, _, isFalse h, _, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, _, _, isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, _, _, _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
-- Cross-constructor mismatches. Lean discharges via `cases heq`.
| .var _, .lam _ _ | .var _, .app _ _ | .var _, .plam _ _ | .var _, .papp _ _
| .var _, .transp _ _ _ _ | .var _, .comp _ _ _ _ _ | .var _, .compN _ _ _ _
| .var _, .glueIn _ _ _ | .var _, .unglue _ _ _ | .var _, .pair _ _
| .var _, .fst _ | .var _, .snd _ | .var _, .dimExpr _ | .var _, .ctor _ _ _ _
| .var _, .indElim _ _ _ _ _
| .lam _ _, .var _ | .lam _ _, .app _ _ | .lam _ _, .plam _ _ | .lam _ _, .papp _ _
| .lam _ _, .transp _ _ _ _ | .lam _ _, .comp _ _ _ _ _ | .lam _ _, .compN _ _ _ _
| .lam _ _, .glueIn _ _ _ | .lam _ _, .unglue _ _ _ | .lam _ _, .pair _ _
| .lam _ _, .fst _ | .lam _ _, .snd _ | .lam _ _, .dimExpr _ | .lam _ _, .ctor _ _ _ _
| .lam _ _, .indElim _ _ _ _ _
| .app _ _, .var _ | .app _ _, .lam _ _ | .app _ _, .plam _ _ | .app _ _, .papp _ _
| .app _ _, .transp _ _ _ _ | .app _ _, .comp _ _ _ _ _ | .app _ _, .compN _ _ _ _
| .app _ _, .glueIn _ _ _ | .app _ _, .unglue _ _ _ | .app _ _, .pair _ _
| .app _ _, .fst _ | .app _ _, .snd _ | .app _ _, .dimExpr _ | .app _ _, .ctor _ _ _ _
| .app _ _, .indElim _ _ _ _ _
| .plam _ _, .var _ | .plam _ _, .lam _ _ | .plam _ _, .app _ _ | .plam _ _, .papp _ _
| .plam _ _, .transp _ _ _ _ | .plam _ _, .comp _ _ _ _ _ | .plam _ _, .compN _ _ _ _
| .plam _ _, .glueIn _ _ _ | .plam _ _, .unglue _ _ _ | .plam _ _, .pair _ _
| .plam _ _, .fst _ | .plam _ _, .snd _ | .plam _ _, .dimExpr _ | .plam _ _, .ctor _ _ _ _
| .plam _ _, .indElim _ _ _ _ _
| .papp _ _, .var _ | .papp _ _, .lam _ _ | .papp _ _, .app _ _ | .papp _ _, .plam _ _
| .papp _ _, .transp _ _ _ _ | .papp _ _, .comp _ _ _ _ _ | .papp _ _, .compN _ _ _ _
| .papp _ _, .glueIn _ _ _ | .papp _ _, .unglue _ _ _ | .papp _ _, .pair _ _
| .papp _ _, .fst _ | .papp _ _, .snd _ | .papp _ _, .dimExpr _ | .papp _ _, .ctor _ _ _ _
| .papp _ _, .indElim _ _ _ _ _
| .transp _ _ _ _, .var _ | .transp _ _ _ _, .lam _ _ | .transp _ _ _ _, .app _ _
| .transp _ _ _ _, .plam _ _ | .transp _ _ _ _, .papp _ _ | .transp _ _ _ _, .comp _ _ _ _ _
| .transp _ _ _ _, .compN _ _ _ _ | .transp _ _ _ _, .glueIn _ _ _
| .transp _ _ _ _, .unglue _ _ _ | .transp _ _ _ _, .pair _ _ | .transp _ _ _ _, .fst _
| .transp _ _ _ _, .snd _ | .transp _ _ _ _, .dimExpr _ | .transp _ _ _ _, .ctor _ _ _ _
| .transp _ _ _ _, .indElim _ _ _ _ _
| .comp _ _ _ _ _, .var _ | .comp _ _ _ _ _, .lam _ _ | .comp _ _ _ _ _, .app _ _
| .comp _ _ _ _ _, .plam _ _ | .comp _ _ _ _ _, .papp _ _ | .comp _ _ _ _ _, .transp _ _ _ _
| .comp _ _ _ _ _, .compN _ _ _ _ | .comp _ _ _ _ _, .glueIn _ _ _
| .comp _ _ _ _ _, .unglue _ _ _ | .comp _ _ _ _ _, .pair _ _
| .comp _ _ _ _ _, .fst _ | .comp _ _ _ _ _, .snd _ | .comp _ _ _ _ _, .dimExpr _
| .comp _ _ _ _ _, .ctor _ _ _ _ | .comp _ _ _ _ _, .indElim _ _ _ _ _
| .compN _ _ _ _, .var _ | .compN _ _ _ _, .lam _ _ | .compN _ _ _ _, .app _ _
| .compN _ _ _ _, .plam _ _ | .compN _ _ _ _, .papp _ _ | .compN _ _ _ _, .transp _ _ _ _
| .compN _ _ _ _, .comp _ _ _ _ _ | .compN _ _ _ _, .glueIn _ _ _
| .compN _ _ _ _, .unglue _ _ _ | .compN _ _ _ _, .pair _ _ | .compN _ _ _ _, .fst _
| .compN _ _ _ _, .snd _ | .compN _ _ _ _, .dimExpr _ | .compN _ _ _ _, .ctor _ _ _ _
| .compN _ _ _ _, .indElim _ _ _ _ _
| .glueIn _ _ _, .var _ | .glueIn _ _ _, .lam _ _ | .glueIn _ _ _, .app _ _
| .glueIn _ _ _, .plam _ _ | .glueIn _ _ _, .papp _ _ | .glueIn _ _ _, .transp _ _ _ _
| .glueIn _ _ _, .comp _ _ _ _ _ | .glueIn _ _ _, .compN _ _ _ _
| .glueIn _ _ _, .unglue _ _ _ | .glueIn _ _ _, .pair _ _ | .glueIn _ _ _, .fst _
| .glueIn _ _ _, .snd _ | .glueIn _ _ _, .dimExpr _ | .glueIn _ _ _, .ctor _ _ _ _
| .glueIn _ _ _, .indElim _ _ _ _ _
| .unglue _ _ _, .var _ | .unglue _ _ _, .lam _ _ | .unglue _ _ _, .app _ _
| .unglue _ _ _, .plam _ _ | .unglue _ _ _, .papp _ _ | .unglue _ _ _, .transp _ _ _ _
| .unglue _ _ _, .comp _ _ _ _ _ | .unglue _ _ _, .compN _ _ _ _
| .unglue _ _ _, .glueIn _ _ _ | .unglue _ _ _, .pair _ _ | .unglue _ _ _, .fst _
| .unglue _ _ _, .snd _ | .unglue _ _ _, .dimExpr _ | .unglue _ _ _, .ctor _ _ _ _
| .unglue _ _ _, .indElim _ _ _ _ _
| .pair _ _, .var _ | .pair _ _, .lam _ _ | .pair _ _, .app _ _ | .pair _ _, .plam _ _
| .pair _ _, .papp _ _ | .pair _ _, .transp _ _ _ _ | .pair _ _, .comp _ _ _ _ _
| .pair _ _, .compN _ _ _ _ | .pair _ _, .glueIn _ _ _ | .pair _ _, .unglue _ _ _
| .pair _ _, .fst _ | .pair _ _, .snd _ | .pair _ _, .dimExpr _ | .pair _ _, .ctor _ _ _ _
| .pair _ _, .indElim _ _ _ _ _
| .fst _, .var _ | .fst _, .lam _ _ | .fst _, .app _ _ | .fst _, .plam _ _
| .fst _, .papp _ _ | .fst _, .transp _ _ _ _ | .fst _, .comp _ _ _ _ _
| .fst _, .compN _ _ _ _ | .fst _, .glueIn _ _ _ | .fst _, .unglue _ _ _
| .fst _, .pair _ _ | .fst _, .snd _ | .fst _, .dimExpr _ | .fst _, .ctor _ _ _ _
| .fst _, .indElim _ _ _ _ _
| .snd _, .var _ | .snd _, .lam _ _ | .snd _, .app _ _ | .snd _, .plam _ _
| .snd _, .papp _ _ | .snd _, .transp _ _ _ _ | .snd _, .comp _ _ _ _ _
| .snd _, .compN _ _ _ _ | .snd _, .glueIn _ _ _ | .snd _, .unglue _ _ _
| .snd _, .pair _ _ | .snd _, .fst _ | .snd _, .dimExpr _ | .snd _, .ctor _ _ _ _
| .snd _, .indElim _ _ _ _ _
| .dimExpr _, .var _ | .dimExpr _, .lam _ _ | .dimExpr _, .app _ _
| .dimExpr _, .plam _ _ | .dimExpr _, .papp _ _ | .dimExpr _, .transp _ _ _ _
| .dimExpr _, .comp _ _ _ _ _ | .dimExpr _, .compN _ _ _ _
| .dimExpr _, .glueIn _ _ _ | .dimExpr _, .unglue _ _ _ | .dimExpr _, .pair _ _
| .dimExpr _, .fst _ | .dimExpr _, .snd _ | .dimExpr _, .ctor _ _ _ _
| .dimExpr _, .indElim _ _ _ _ _
| .ctor _ _ _ _, .var _ | .ctor _ _ _ _, .lam _ _ | .ctor _ _ _ _, .app _ _
| .ctor _ _ _ _, .plam _ _ | .ctor _ _ _ _, .papp _ _ | .ctor _ _ _ _, .transp _ _ _ _
| .ctor _ _ _ _, .comp _ _ _ _ _ | .ctor _ _ _ _, .compN _ _ _ _
| .ctor _ _ _ _, .glueIn _ _ _ | .ctor _ _ _ _, .unglue _ _ _ | .ctor _ _ _ _, .pair _ _
| .ctor _ _ _ _, .fst _ | .ctor _ _ _ _, .snd _ | .ctor _ _ _ _, .dimExpr _
| .ctor _ _ _ _, .indElim _ _ _ _ _
| .indElim _ _ _ _ _, .var _ | .indElim _ _ _ _ _, .lam _ _ | .indElim _ _ _ _ _, .app _ _
| .indElim _ _ _ _ _, .plam _ _ | .indElim _ _ _ _ _, .papp _ _
| .indElim _ _ _ _ _, .transp _ _ _ _ | .indElim _ _ _ _ _, .comp _ _ _ _ _
| .indElim _ _ _ _ _, .compN _ _ _ _ | .indElim _ _ _ _ _, .glueIn _ _ _
| .indElim _ _ _ _ _, .unglue _ _ _ | .indElim _ _ _ _ _, .pair _ _
| .indElim _ _ _ _ _, .fst _ | .indElim _ _ _ _ _, .snd _ | .indElim _ _ _ _ _, .dimExpr _
| .indElim _ _ _ _ _, .ctor _ _ _ _ =>
isFalse (fun heq => by cases heq)
def CTypeArg.decEq : (a b : CTypeArg) → Decidable (a = b)
| .type A, .type B =>
match CType.decEq A B with
| isTrue h => isTrue (by rw [h])
| isFalse h => isFalse (fun heq => h (by cases heq; rfl))
| .param i, .param j =>
if h : i = j then isTrue (by rw [h]) else isFalse (fun heq => h (by cases heq; rfl))
| .self, .self => isTrue rfl
| .dim, .dim => isTrue rfl
| .type _, .param _ | .type _, .self | .type _, .dim
| .param _, .type _ | .param _, .self | .param _, .dim
| .self, .type _ | .self, .param _ | .self, .dim
| .dim, .type _ | .dim, .param _ | .dim, .self =>
isFalse (fun heq => by cases heq)
def CtorSpec.decEq : (a b : CtorSpec) → Decidable (a = b)
| .mk n as bs, .mk n' as' bs' =>
if hn : n = n' then
match decEqListCTypeArg as as', decEqClauses bs bs' with
| isTrue ha, isTrue hb => isTrue (by rw [hn, ha, hb])
| isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
else isFalse (fun heq => hn (by cases heq; rfl))
def CTypeSchema.decEq : (a b : CTypeSchema) → Decidable (a = b)
| .mk n np cs, .mk n' np' cs' =>
if hn : n = n' then if hnp : np = np' then
match decEqListCtorSpec cs cs' with
| isTrue hc => isTrue (by rw [hn, hnp, hc])
| isFalse h => isFalse (fun heq => h (by cases heq; rfl))
else isFalse (fun heq => hnp (by cases heq; rfl))
else isFalse (fun heq => hn (by cases heq; rfl))
-- ── List / clause / branch helpers ──────────────────────────────────────────
def decEqListCType : (xs ys : List CType) → Decidable (xs = ys)
| [], [] => isTrue rfl
| [], _ :: _ => isFalse (fun heq => by cases heq)
| _ :: _, [] => isFalse (fun heq => by cases heq)
| x :: xs, y :: ys =>
match CType.decEq x y, decEqListCType xs ys with
| isTrue hx, isTrue hxs => isTrue (by rw [hx, hxs])
| isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
def decEqListCTerm : (xs ys : List CTerm) → Decidable (xs = ys)
| [], [] => isTrue rfl
| [], _ :: _ => isFalse (fun heq => by cases heq)
| _ :: _, [] => isFalse (fun heq => by cases heq)
| x :: xs, y :: ys =>
match CTerm.decEq x y, decEqListCTerm xs ys with
| isTrue hx, isTrue hxs => isTrue (by rw [hx, hxs])
| isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
def decEqListCTypeArg : (xs ys : List CTypeArg) → Decidable (xs = ys)
| [], [] => isTrue rfl
| [], _ :: _ => isFalse (fun heq => by cases heq)
| _ :: _, [] => isFalse (fun heq => by cases heq)
| x :: xs, y :: ys =>
match CTypeArg.decEq x y, decEqListCTypeArg xs ys with
| isTrue hx, isTrue hxs => isTrue (by rw [hx, hxs])
| isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
def decEqListCtorSpec : (xs ys : List CtorSpec) → Decidable (xs = ys)
| [], [] => isTrue rfl
| [], _ :: _ => isFalse (fun heq => by cases heq)
| _ :: _, [] => isFalse (fun heq => by cases heq)
| x :: xs, y :: ys =>
match CtorSpec.decEq x y, decEqListCtorSpec xs ys with
| isTrue hx, isTrue hxs => isTrue (by rw [hx, hxs])
| isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
def decEqClauses : (xs ys : List (FaceFormula × CTerm)) → Decidable (xs = ys)
| [], [] => isTrue rfl
| [], _ :: _ => isFalse (fun heq => by cases heq)
| _ :: _, [] => isFalse (fun heq => by cases heq)
| (φ, t) :: xs, (ψ, u) :: ys =>
if hφ : φ = ψ then
match CTerm.decEq t u, decEqClauses xs ys with
| isTrue ht, isTrue hxs => isTrue (by rw [hφ, ht, hxs])
| isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
else isFalse (fun heq => hφ (by cases heq; rfl))
def decEqBranches : (xs ys : List (String × CTerm)) → Decidable (xs = ys)
| [], [] => isTrue rfl
| [], _ :: _ => isFalse (fun heq => by cases heq)
| _ :: _, [] => isFalse (fun heq => by cases heq)
| (n, t) :: xs, (n', u) :: ys =>
if hn : n = n' then
match CTerm.decEq t u, decEqBranches xs ys with
| isTrue ht, isTrue hxs => isTrue (by rw [hn, ht, hxs])
| isFalse h, _ => isFalse (fun heq => h (by cases heq; rfl))
| _, isFalse h => isFalse (fun heq => h (by cases heq; rfl))
else isFalse (fun heq => hn (by cases heq; rfl))
end
-- ── Instance declarations ───────────────────────────────────────────────────
instance : DecidableEq CType := CType.decEq
instance : DecidableEq CTerm := CTerm.decEq
instance : DecidableEq CTypeArg := CTypeArg.decEq
instance : DecidableEq CtorSpec := CtorSpec.decEq
instance : DecidableEq CTypeSchema := CTypeSchema.decEq
end CubicalTransport.DecEq