Realizing a 2-cell split #
Schoenflies/CellulationInvariants.lean proves the step theorems of the second elementary
operation: given a realization R' of S.splitFace d standing in the relation
SplitData.IsCrosscutSplit to a realization R of S, the two invariants of
lem:cellulation-invariants propagate. Nothing built such an R'. This module does.
Blueprint #
def:generated-structure, operation 2 — the 2-cell split whose realization is constructed here.lem:cellulation-invariants(i), (vii) — the invariants thatSplitData.IsCrosscutSplit.isCellDecomposition_and_isFaceJordanderives from the output of this module.thm:general-crosscut(Schoenflies.crosscut_theorem) — what turns the constructed ear into the two new open 2-cells; it is applied insideIsCrosscutSplit.isRefinement, and this module supplies its hypotheses.
What is constructed #
Schoenflies.CellStructure.SplitData.EarCrosscut— the geometric input: an assignment of points to the ear's vertices and of parametrizations to the ear's edges, drawing the ear as a polygonal crosscut of the realized open 2-cell.Schoenflies.CellStructure.SplitData.realize— the realization ofS.splitFace dbuilt fromRand such an ear. It is adefwith lemmas, not an existential:splitPos,splitDrawing,splitCellare its three components, each with its own reduction lemmas (splitCell_face₁,splitCell_of_mem_cells,splitCell_earVertex,splitCell_earEdge, …), andrealize_pos/realize_drawing/realize_cellconnect them to the record.Schoenflies.CellStructure.SplitData.isCrosscutSplit_realize— the constructed realization stands in the relationIsCrosscutSplittoR. Composed withIsCrosscutSplit.isCellDecomposition_and_isFaceJordanthis is the full induction step.
What is assumed, and who discharges it #
realize itself asks only for EarCrosscut, whose six fields — pos_source, pos_target,
injOn, isDrawing, subset_face, polygonal — say that the ear is drawn as a simple
polygonal arc from R.pos d.source to R.pos d.target whose interior lies in the open 2-cell,
plus the seventh, disjoint_skeleton, which is a fact about R alone and is discharged by
Realization.disjoint_cell_skeletonSet from assertion (i). A producer that starts from
Schoenflies.exists_crosscut_of_polyAccessible — a polygonal arc inside the face with both
ends on its boundary — and cuts that arc into the ear's edges has all seven in hand.
isCrosscutSplit_realize asks in addition only for R.IsCellDecomposition D and
R.IsFaceJordan.
It used to ask for a third thing — that the two boundary paths of the split 2-cell share nothing
but their two ends — because SplitData did not imply it: its field paths_disjoint forbade
the two paths a common edge but said nothing about a common interior vertex, and with a
common interior vertex the two realized paths meet in a third point, so the IsCutPair clause
of IsCrosscutSplit is false. That gap has since been closed at the source: SplitData now
carries paths_meet and derives paths_disjoint from it. What follows is the record of a
condition that
producer of the SplitData chooses them (as the two arcs of one boundary cycle) and so can
supply it. If a later wave prefers it as a field of SplitData, that is the right place for it.
The general lemmas this needed #
Three facts about drawings and paths had no home on main and are proved here in the root
Graph namespace. If a second consumer appears they belong in Schoenflies/Graph/:
Graph.IsPath.map,Graph.walkVertices_map,Graph.IsPathGraph.map— a path pushes forward along an injective relabelling of the vertices.Graph.IsWalk.mapwas already onmain(inSchoenflies/CombinatorialInvariance.lean); the path version needs the injectivity, because the freshness clause is a non-membership.Graph.IsDrawing.isArcBetween_walkPointSet— the point set of a drawn path is a simple arc between its two ends. This is the workhorse: it is what makes the realized ear an arc (soIsCrosscutapplies) and what makes each realized boundary path an arc (soIsCutPairapplies). The induction is onGraph.IsPath, and the freshness clause of a path is exactly what rules out the returning point that would breakIsArcBetween.concatenate.
Pushing a path forward along a relabelling #
A path pushes forward along an injective relabelling. Unlike Graph.IsWalk.map this
needs the injectivity: the freshness clause is a non-membership, and only an injective map
reflects it.
The point set of a drawn path #
Graph.pointSet reads the vertex set and the edge set of a graph. Along a walk both are read
off the list instead, and that is the form the induction below runs on.
The point set a walk occupies: the vertices it visits together with the arcs of its
edges. For a path graph this is the whole of Graph.pointSet (walkPointSet_eq_pointSet).
Equations
- H.walkPointSet drw u W = H.walkVertices u W ∪ ⋃ e ∈ {e : β | e ∈ W}, Graph.edgeArc drw e
Instances For
Peeling the first step off a walk peels its arc off the point set. The vertex the step departs from is an end of that arc, which is why nothing is left behind.
The point set of a drawn path is a simple arc between its two ends.
The two pieces glued at each step are the arc of the first edge and the point set of the rest
of the path, and IsArcBetween.concatenate asks that they meet only at the vertex between
them. That is precisely the freshness clause of Graph.IsPath: the vertex the path departs
from is not among those the rest of it visits, and every point the first arc shares with the
rest of the drawing is a vertex the rest visits — a vertex by vertex_mem_edgeArc if it is
one of the rest's vertices, and by edge_inter if it lies on one of the rest's arcs.
What a realization does to a walk #
Two facts about an existing realization, both of the shape "the realized cells of a piece of the skeleton occupy the point set that piece of the drawing occupies". They are what let the crosscut theorem, which speaks of point sets, be fed from the cell structure, which speaks of cells.
The realized cells of a path occupy the point set the drawn path occupies. The two differ only in the endpoints an open 1-cell drops, and those are the points of the 0-cells the walk visits.
The drawn skeleton is covered by the open cells of dimension 0 and 1.
An open 2-cell misses the drawn skeleton. Immediate from the disjointness clause of assertion (i): the skeleton is covered by cells of lower dimension.
The ear, drawn #
SplitData fixes the abstract ear: a path graph d.ear glued to the skeleton at
d.source and d.target. Drawing it means choosing a point for each of its vertices and a
parametrization for each of its edges. EarCrosscut is the bundle of conditions under which
that drawing is a polygonal crosscut of the realized open 2-cell R.cell d.face.
The cells strictly below the split 2-cell are the cells of its two boundary paths.
This is SplitData.sub_face read as a set identity; with assertion (i) it identifies the
frontier of the old open 2-cell with the two realized boundary paths.
The point set the drawn ear occupies: the crosscut P of thm:general-crosscut.
Instances For
The geometric input of one 2-cell split. A position for each vertex of the abstract
ear and a parametrization for each of its edges, drawing the ear as a polygonal crosscut of
the realized open 2-cell R.cell d.face.
Every clause is a statement about the ear's own drawing, and every one of them is what the
finite-transfer module has in hand when it produces a crosscut from
Schoenflies.exists_crosscut_of_polyAccessible: it starts from a simple polygonal arc P
inside the face with its two ends on the boundary, and cuts P into the ear's edges.
The ear starts where the old 0-cell
d.sourcesits.…and ends where
d.targetsits.Distinct vertices of the ear are drawn at distinct points.
The ear is drawn as a plane graph.
Every point of the drawn ear but its two ends is inside the old open 2-cell.
- disjoint_skeleton : Disjoint (R.cell d.face) R.skeletonSet
The old open 2-cell misses the old drawn skeleton. This is a property of
Ralone, not of the ear; it is carried here so that the construction below depends on no ambient domain.Realization.disjoint_cell_skeletonSetdischarges it from assertion (i). - polygonal : IsPolygonal (d.earSet earPos earDraw)
The drawn ear is polygonal.
Instances For
On the two ends — the only vertices the ear shares with the old skeleton — the ear's positions agree with the old ones.
An interior vertex of the ear is drawn strictly inside the old open 2-cell.
The drawn ear meets the old skeleton exactly in its two ends. The interior of the ear is inside the open 2-cell, and an open 2-cell misses the drawn skeleton.
An ear edge's arc meets the ear's vertices exactly at its own two ends, so dropping all of the ear's vertices from it is the same as dropping its own two ends. This is what makes the definition of the new open 1-cells independent of a choice of orientation.
The realization built from a drawn ear #
Where the split puts each 0-cell: the ear's vertices go where the ear's drawing puts them, everything else stays. On the ear's two ends the two prescriptions agree.
Instances For
How the split draws each 1-cell.
Instances For
The point set of each open cell after the split: the two new 2-cells are the two sides of the crosscut, the ear's vertices and edges are their points and their open arcs, and every surviving cell keeps its old point set.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The skeleton of the split structure, drawn: the old drawn skeleton with the drawn ear glued on.
The old drawn skeleton with the drawn ear glued on is a plane graph. The three clauses
of Graph.IsDrawing all reduce, on a mixed pair, to the same fact: the ear meets the old
drawing only at its two ends, because its interior lies in an open 2-cell and an open 2-cell
misses the drawn skeleton.
The frontier of the old open 2-cell is the union of its two realized boundary paths.
SplitData.sub_face says which cells lie below the split 2-cell, and assertion (i) turns the
union of those open cells into the topological frontier.
A realized boundary path is a simple arc between the ear's two ends.
The two boundary paths cut the old 2-cell's boundary curve in two.
This is where SplitData.paths_meet is spent, and it is the only place: paths_disjoint alone
forbids the two paths a common edge but not a common interior vertex, and with a common
interior vertex the two realized paths meet in more than the two cut points. See the module
docstring.
The drawn ear is a path graph in the plane.
The drawn ear is a simple arc between the two old 0-cells it is glued to.
The drawn ear is a crosscut of the old Jordan face.
The closure of an ear edge's open arc is the closed arc.
The realization #
The realization of a 2-cell split.
The old realization R, a drawing of the ear as a polygonal crosscut of the old open 2-cell,
and assertion (i) at the old stage produce a realization of S.splitFace d:
- the ear's interior 0-cells go where the ear's drawing puts them, and its 1-cells to their open arcs;
- the two new 2-cells go to the two sides of the crosscut,
inside (Bᵢ ∪ P); - every surviving cell keeps its old point set.
This is the object the whole split step of lem:cellulation-invariants was missing:
SplitData.isCrosscutSplit_realize puts it in the relation IsCrosscutSplit to R, and
IsCrosscutSplit.isCellDecomposition_and_isFaceJordan then propagates both invariants.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The realized ear is the drawn ear. The open cells of the ear together with the two old 0-cells at its ends occupy exactly the crosscut.
The open cells the ear creates are the crosscut minus its two endpoints.
The constructed realization is a crosscut split of the old one — every clause of
SplitData.IsCrosscutSplit, discharged.
Composed with IsCrosscutSplit.isCellDecomposition_and_isFaceJordan this is the whole
induction step of lem:cellulation-invariants over the second elementary operation.
The induction step of lem:cellulation-invariants over the second elementary operation,
end to end. From a realization of S satisfying assertions (i) and (vii) and a drawing of
the ear as a polygonal crosscut, a realization of S.splitFace d satisfying (i) and (vii),
refining it along SplitData.parent.