/-
Copyright (c) 2026 Terence Rokop. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Terence Rokop
-/modulepublicimportGeb.Mathlib.Data.PFunctor.Slice.Basic
W-types of slice polynomial functors (constructive core)
When dom = cod = I, a SlicePFunctor I I is a slice endofunctor
Type/I → Type/I. Its W-type (initial algebra) is obtained as a subtype of the
PFunctor W-type P.W: a tree is admitted when every node's children sit
over the direction-input indices prescribed by r, and it is indexed by the
q-assigned output index of its root shape.
The index (codomain-assignment) and the admissibility predicate
(domain-restriction) are not written by explicit recursion. The index of a
tree is the output index of its root, so it is not recursive at all; the
predicate is recursive, but is obtained from mathlib's non-dependent W-type
eliminator WType.elim, folding the index and the predicate together into
the structure WIndex via the algebra wIndexStep. Carrying the index
inside the fold is what lets the algebra state the direction-input-map
condition OverInput — the children's index family, as a function of
direction, equals rCurried a, the shape of SliceDomPFunctor.Compatible:
the plain Prop-valued fold discards the children, so the condition would
be inexpressible without either this
pairing or the dependent recursor.
The carrier W is the admissible trees, with structure map wIndex. Its
constructor mk and destructor dest are mutually inverse (W is a fixed
point of the slice endofunctor), and elim is the morphism into any slice
algebra over I. Only the existence half of the initial-algebra universal
property is established here — the carrier, its fixed-point structure
(mk/dest), and elim with its computation rule elim_mk and over-I law
comp_elim; uniqueness of elim is not formalized. The value of elim is
computed by a single non-dependent WType.elim (the fold elimData, with
algebra elimStep) into the carrier ElimData — each subtree's index, its
admissibility, and (given admissibility) its image value with the witness that
the value lies over the index, i.e. a slice morphism
(valid, const index) → (Y, p); carrying the value in the fold keeps elim's
computational layer independent of the dependent recursor: elim uses
WType.rec only in the proof elimData_valid, relating the fold's
admissibility component to WValid. A direct WType.rec definition of a
Type-valued datum (such as elim's value) would be noncomputable — the
code generator does not compile recursor applications — which the project's
constructive discipline forbids; a Prop-valued recursor definition such as
RecProp is exempt, its content being erased. All of this stays
Classical.choice-free.
The single index type is forced: the constraint compares a child's
codomain-index against the parent's domain-index, so it typechecks only when
dom = cod. That is the endofunctor condition an initial algebra requires.
Main definitions
SlicePFunctor.wIndexRoot — the index of a slice W-tree: the output index
of its root shape. Not recursive.
SlicePFunctor.WIndex / SlicePFunctor.wIndexStep / SlicePFunctor.wIndexValid
— the index-and-admissibility carrier, the algebra computing it, and the fold.
SlicePFunctor.ForAll / SlicePFunctor.AllValid / SlicePFunctor.OverInput /
SlicePFunctor.NodeValid are the direction-quantifier, the
all-children-admissible condition (ForAll of the children's valid), the
direction-input-map condition, and the node-admissibility predicate
combining the latter two.
SlicePFunctor.WValid — the domain-restriction predicate: the admissibility
component of wIndexValid.
SlicePFunctor.W — the carrier of the slice W-type: the admissible trees.
SlicePFunctor.wIndex — the slice W-type's structure map into I.
SlicePFunctor.W.mk / SlicePFunctor.W.dest — the constructor and
destructor of the slice W-type.
SlicePFunctor.W.ElimData / SlicePFunctor.W.elimStep /
SlicePFunctor.W.elimData — the elim carrier, algebra, and fold.
SlicePFunctor.W.elim — the morphism from the slice W-type into any slice
algebra over I.
SlicePFunctor.W.RecProp — the paramorphism from the slice W-type into
Prop: a predicate whose step sees each node and its child subtrees together
with the children's predicate values.
Main statements
SlicePFunctor.wIndexValid_index_eq_wIndexRoot — the index component of the
fold agrees with the non-recursive root index; one non-recursive case split.
SlicePFunctor.wValid_mk — admissibility unfolded one level.
SlicePFunctor.W.dest_mk / SlicePFunctor.W.mk_dest — mk and dest are
mutually inverse.
SlicePFunctor.W.wIndex_mk / SlicePFunctor.W.comp_elim — mk and elim
lie over I.
SlicePFunctor.W.elim_mk — the computation rule for elim: it is a morphism
of slice algebras.
SlicePFunctor.W.elimData_valid — the fold's admissibility component agrees
with WValid; a use of the dependent recursor WType.rec.
SlicePFunctor.W.induction — structural induction for the slice W-type, the wrapped
form of WType.rec on the admissibility subtype.
SlicePFunctor.W.recProp_mk — the one-level computation rule for RecProp.
Implementation notes
wIndexValid folds into the structure WIndex (index, valid) via
wIndexStep; a node's valid is NodeValid — AllValid (every child
admissible) and OverInput (the children's index family equal to rCurried a,
the Compatible shape). Its index component is the depth-1 root output
index, so wIndexValid_index_eq_wIndexRoot needs only cases. elim's
value is computed by elimData, a single non-dependent WType.elim with
algebra elimStep into
the structure ElimData (extending WIndex with a value function and an
over law, a slice morphism); within elim's construction the dependent
recursor is used only in the proof elimData_valid (a WType.rec application
showing the fold's admissibility component agrees with WValid). A direct
WType.recdefinition of a Type-valued datum (such as elim's value) would
be rejected by the code generator as noncomputable; a WType.rec application
in a proof, or a Prop-valued WType.rec definition such as RecProp, is
unproblematic. wIndexRoot, ForAll, AllValid, OverInput,
NodeValid, wIndexStep,
wIndexValid, WValid, W, wIndex, W.mk, W.dest, W.elimStep,
W.elimData, W.elim, and W.RecProp are @[expose] so a wrapper module and
the tests can unfold them across the module boundary.
The index of a slice W-tree: the q-assigned output index of its root
shape. Not recursive — it reads only the root node, via PFunctor.W.head.
@[`@[expose]` has no effect outside a `module` fileexpose]defwIndexRoot{I:TypeuI}(F:SlicePFunctor.{uA,uB,uI,uI}II):F.toPFunctor.W→I:=F.q∘PFunctor.W.head
The index and admissibility of a slice W-tree, the two components folded
together by wIndexValid.
The tree's index: the output index of its root shape.
Every direction satisfies the predicate P. Parallels OverInput, over
F.B a.
@[`@[expose]` has no effect outside a `module` fileexpose]defForAll{I:TypeuI}(F:SlicePFunctor.{uA,uB,uI,uI}II)(a:F.toPFunctor.A)(P:F.toPFunctor.Ba→Prop):Prop:=∀b,Pb
Every child of c is admissible: ForAll of the children's valid.
@[`@[expose]` has no effect outside a `module` fileexpose]defAllValid{I:TypeuI}(F:SlicePFunctor.{uA,uB,uI,uI}II)(a:F.toPFunctor.A)(c:F.toPFunctor.Ba→WIndexI):Prop:=F.ForAlla(WIndex.valid∘c)
The direction-input-map condition on a node's children: their index
family, as a function of direction, equals the direction-input map
rCurried a. Point-free — the shape of SliceDomPFunctor.Compatible for
the identity projection.
@[`@[expose]` has no effect outside a `module` fileexpose]defOverInput{I:TypeuI}(F:SlicePFunctor.{uA,uB,uI,uI}II)(a:F.toPFunctor.A)(idx:F.toPFunctor.Ba→I):Prop:=idx=F.rCurrieda
A node with shape a and children c is admissible when every child is
admissible (AllValid) and the children's index family lies over the
direction-input map (OverInput).
@[`@[expose]` has no effect outside a `module` fileexpose]defNodeValid{I:TypeuI}(F:SlicePFunctor.{uA,uB,uI,uI}II)(a:F.toPFunctor.A)(c:F.toPFunctor.Ba→WIndexI):Prop:=F.AllValidac∧F.OverInputa(WIndex.index∘c)
The algebra computing a node's index and admissibility from its children's:
the index is the q-assigned output index of the shape, and the node is
NodeValid.
@[`@[expose]` has no effect outside a `module` fileexpose]defwIndexStep{I:TypeuI}(F:SlicePFunctor.{uA,uB,uI,uI}II):F.toPFunctor.Obj(WIndexI)→WIndexI:=fun⟨a,c⟩↦{index:=F.qa,valid:=F.NodeValidac}
The index paired with admissibility: the F.toPFunctor-algebra morphism
into (WIndex I, wIndexStep) given by WType.elim.
@[`@[expose]` has no effect outside a `module` fileexpose]defwIndexValid{I:TypeuI}(F:SlicePFunctor.{uA,uB,uI,uI}II):F.toPFunctor.W→WIndexI:=WType.elim(WIndexI)F.wIndexStep
The domain-restriction predicate on slice W-trees: a tree is admitted when
every node's children sit over the direction-input indices prescribed by
r. The admissibility component of wIndexValid.
@[`@[expose]` has no effect outside a `module` fileexpose]defWValid{I:TypeuI}(F:SlicePFunctor.{uA,uB,uI,uI}II):F.toPFunctor.W→Prop:=WIndex.valid∘F.wIndexValid
The index component of wIndexValid agrees with the non-recursive root
index. A depth-1 fact: proved by a single non-recursive case split.
Admissibility unfolded one level: WType.mk a f is admitted exactly when
every child f b is admitted and the children's index family lies over the
direction-input map.
The carrier of the slice W-type: the admissible PFunctor W-trees.
@[`@[expose]` has no effect outside a `module` fileexpose]defW{I:TypeuI}(F:SlicePFunctor.{uA,uB,uI,uI}II):Type(maxuAuB):={w:F.toPFunctor.W//F.WValidw}
The slice W-type's structure map as an object of Type/I: the index of the
underlying tree.
@[`@[expose]` has no effect outside a `module` fileexpose]defwIndex{I:TypeuI}(F:SlicePFunctor.{uA,uB,uI,uI}II):F.W→I:=F.wIndexRoot∘Subtype.val
namespaceW
The constructor of the slice W-type: the slice endofunctor's value at
(W, wIndex) maps into W. The algebra structure map.
@[`@[expose]` has no effect outside a `module` fileexpose]defmk{I:TypeuI}{F:SlicePFunctor.{uA,uB,uI,uI}II}(x:F.toSliceDomPFunctor.ObjF.wIndex):F.W:=⟨WType.mkx.1.1(Subtype.val∘x.1.2),(F.wValid_mk__).mpr⟨funb↦(x.1.2b).property,funext((F.toSliceDomPFunctor.compatible_iffF.wIndexx.1.1x.1.2).mpx.2)⟩⟩
The destructor of the slice W-type: every admissible tree decomposes as a
shape together with a compatible family of admissible subtrees. Inverse to
mk.
@[`@[expose]` has no effect outside a `module` fileexpose]defdest{I:TypeuI}{F:SlicePFunctor.{uA,uB,uI,uI}II}(z:F.W):F.toSliceDomPFunctor.ObjF.wIndex:=matchzwith|⟨WType.mkaf,hw⟩=>⟨⟨a,funb↦⟨fb,((F.wValid_mkaf).mphw).1b⟩⟩,(F.toSliceDomPFunctor.compatible_iffF.wIndexa_).mprfunb↦congrFun((F.wValid_mkaf).mphw).2b⟩
The elim fold carrier: extends WIndex to a slice morphism
(valid, const index) → (Y, p) — a value function defined once the subtree is
admissible, together with the proof that it lies over the index.
The image value, available once the subtree is admissible.
The value lies over the index: p ∘ value is constant at index.
The slice-algebra step of the elim fold: index and admissibility
(NodeValid) as for wIndexStep, and a value function that, given a node's
admissibility, applies the target algebra g to the compatible family of its
children's values, with over recording that the result lies over the index.
@[`@[expose]` has no effect outside a `module` fileexpose]defelimStep{I:TypeuI}(F:SlicePFunctor.{uA,uB,uI,uI}II)(Y:TypeuY)(p:Y→I)(g:F.toSliceDomPFunctor.Objp→Y)(hg:p∘g=F.objp):F.toPFunctor.Obj(ElimDataYp)→ElimDataYp:=fun⟨a,c⟩↦{index:=F.qavalid:=F.NodeValida(ElimData.toWIndex∘c)value:=funhv↦g⟨⟨a,funb↦(cb).value(hv.1b)⟩,(F.toSliceDomPFunctor.compatible_iffpa_).mprfunb↦(congrFun(cb).over(hv.1b)).trans(congrFunhv.2b)⟩over:=funextfun_↦congrFunhg_}
The elim fold: the F.toPFunctor-algebra morphism into
(ElimData Y p, elimStep) given by WType.elim, a single non-dependent fold
with no explicit recursion.
@[`@[expose]` has no effect outside a `module` fileexpose]defelimData{I:TypeuI}(F:SlicePFunctor.{uA,uB,uI,uI}II)(Y:TypeuY)(p:Y→I)(g:F.toSliceDomPFunctor.Objp→Y)(hg:p∘g=F.objp):F.toPFunctor.W→ElimDataYp:=WType.elim(ElimDataYp)(elimStepFYpghg)
The index component of elimData is the root index.
The admissibility component of elimData agrees with WValid. An
inductive step: it applies the dependent recursor WType.rec (the initial
algebra's induction principle, consulting the hypothesis ih), unlike the
non-recursive cases/casesOn splits elsewhere. It is in a proof, where
non-computability is immaterial.
The eliminator of the slice W-type: the morphism into any slice algebra
(Y, p, g) over I. The existence half of initiality. The value is computed by
the non-dependent fold elimData; the tree's admissibility supplies the
argument to the fold's value function.
@[`@[expose]` has no effect outside a `module` fileexpose]defelim{I:TypeuI}(F:SlicePFunctor.{uA,uB,uI,uI}II)(Y:TypeuY)(p:Y→I)(g:F.toSliceDomPFunctor.Objp→Y)(hg:p∘g=F.objp):F.W→Y:=funz↦(elimDataFYpghgz.val).value((elimData_validFYpghgz.val).mprz.property)
elim lies over I: composing with the target structure map recovers
wIndex.
Structural induction for the slice W-type: a predicate holds of every
admissible tree once it holds of mk x whenever it holds of each child
x.1.2 b. The wrapped form of the dependent recursor WType.rec on the
admissibility subtype.
Paramorphism from the slice W-type into Prop: step sees the node x,
hence its child subtrees x.1.2 b, together with the children's predicate
values. The value is computed by WType.rec with a Prop motive, so no
noncomputable flag arises. @[expose] so the presheaf layer can unfold it.
@[`@[expose]` has no effect outside a `module` fileexpose]defRecProp{I:TypeuI}{F:SlicePFunctor.{uA,uB,uI,uI}II}(step:(x:F.toSliceDomPFunctor.ObjF.wIndex)→(F.toPFunctor.Bx.1.1→Prop)→Prop):F.W→Prop:=funz↦WType.rec(motive:=funw↦F.WValidw→Prop)(funafihhv↦step(dest⟨WType.mkaf,hv⟩)(funb↦ihb(((F.wValid_mkaf).mphv).1b)))z.1z.2
The one-level computation rule for RecProp: on mk x it applies step
to the node x and the family of child values. Definitional; stated for
downstream unfolding.