Two-sided collars along a simple polygonal arc #
Schoenflies/CrosscutAtMostTwo.lean proves Lemma "At most two sides" assuming
Schoenflies.HasArcCollars: every compact piece of D ∩ P has a two-sided collar inside D.
This module discharges that hypothesis for a polygonal arc presented by its vertex list.
The route: a linear chain, not a cyclic one #
Schoenflies/Strip.lean builds the collar of blueprint Lemma 1.8 for a ClosedPolygon, whose
vertex family is indexed by ZMod (m + 3). The apparatus is redone here on a linear index —
route (A) of the three the blueprint's arc case admits. Closing the arc into a polygon (route
(B)) was rejected: it needs a return path from one end of the arc back to the other meeting the
arc only at its ends, and producing one is the two-sided collar of the arc all over again.
Two things change from the cyclic case, and both make the arc case easier.
- There are no sectors at the two extreme vertices. An edge block already stops short of
both of its endpoints by the trim
lam, so the collar of the whole chain of blocks is an open neighbourhood of the arc minus two small end caps — which is all that is wanted, because the compact pieceKsits at positive distance from the two endpoints of a crosscut (they are outsideDandKis inside). - The neighbourhood is open by construction. The collar of a closed polygon has to contain
the curve, so
StripData.nbhdis a union of open sets plus the carrier, andStripData.nbhd_eqis needed to see that it is open. Herenbhdis defined outright as the union of the vertex balls and the edge tubes; it contains the arc only away from its two ends, and there is nothing to prove.
What does not change is the germ argument at a corner: Plane.germs_split' is applied
exactly as in the cyclic case, with the incoming ray at vertex i + 1 written A.back i and
the outgoing one A.tang (i + 1).
The one thing left open #
PolyArc is a presentation: a simple polygonal arc given by its vertex list, exactly as
ClosedPolygon presents a simple closed polygonal curve. Everything is proved for a PolyArc,
and Schoenflies.polyArc_crosscut_at_most_two is Lemma "At most two sides" for one with no
hypothesis left standing at all. What is not proved is the converse presentation statement:
that a set which happens to be a simple polygonal arc is the carrier of some PolyArc. That is
the arc analogue of Schoenflies.exists_closedPolygon, which Schoenflies/Realization.lean
proves for a Jordan curve; it is normalisation, not geometry.
Schoenflies.hasArcCollars therefore carries it as the hypothesis
Schoenflies.IsPolyArcCarrier. See the note at the end of the file for the route.
The presentation is checked in both other directions, so neither the structure nor the
hypothesis is vacuous or accidentally false: Schoenflies.PolyArc.isArcBetween_carrier and
Schoenflies.PolyArc.isPolygonal_carrier say the carrier of a PolyArc is a simple polygonal
arc, and Schoenflies.isPolyArcCarrier_segment exhibits one.
Blueprint #
Schoenflies.PolyArc— a simple polygonal arc presented by its vertex list; the arc analogue ofSchoenflies.ClosedPolygon.Schoenflies.ArcStrip— the constants of blueprint Lemma 1.8 (b), as a structure: the cone radiusR, the trimlam, the half-widthrho, and the separations they satisfy. The arc analogue ofSchoenflies.StripData, with the two clauses that make the collar fit inside the prescribed region and clear of the two endpoints.Schoenflies.ArcStrip.nbhd,.sideL,.sideR— the collarNand its two tracksN_L,N_Rof Lemma 1.8 (b).Schoenflies.ArcStrip.nbhd_diff_carrier,.isConnected_sideL,.isConnected_sideR,.sideL_disjoint_sideR,.subset_closure_sideL,.subset_closure_sideR— the clauses of Lemma 1.8 (b).Schoenflies.exists_arcStrip— the constants exist. The arc analogue ofSchoenflies.exists_stripData_subset.Schoenflies.ArcStrip.collar,Schoenflies.PolyArc.exists_arcCollar,Schoenflies.PolyArc.hasArcCollars— Lemma 1.8 (b) itself, as the interfaceSchoenflies.ArcCollarthatSchoenflies/CrosscutAtMostTwo.leanconsumes.Schoenflies.PolyArc.isArcBetween_carrier,Schoenflies.PolyArc.isPolygonal_carrier— the carrier of aPolyArcis a simple polygonal arc between its two extreme vertices.Schoenflies.polyArc_crosscut_at_most_two,Schoenflies.polyArc_crosscut_components_exhaust— Lemma "At most two sides" for a polygonal arc presented by a vertex list, with no further assumptions.Schoenflies.hasArcCollars,Schoenflies.crosscut_at_most_two_of_polyArc,Schoenflies.crosscut_components_exhaust_of_polyArc— the same for a setPpresented bySchoenflies.IsPolyArcCarrier.Schoenflies.segmentPolyArc,Schoenflies.isPolyArcCarrier_segment— a straight crosscut as aPolyArc, which recoversSchoenflies.hasArcCollars_segmentas a special case.
Simple polygonal arcs #
A polygonal arc is presented by its vertex list v 0, …, v (n + 1); its edges are the n + 1
segments edge i = [v i, v (i + 1)] for i ≤ n, and its interior vertices — the ones that
carry a corner, and hence a sector of the collar — are v 1, …, v n.
The vertex function is indexed by all of ℕ and asked to be injective outright, rather than
injective on {0, …, n + 1}. Nothing past v (n + 1) is ever looked at except through
A.tang i and A.len i, which are only well behaved when v i ≠ v (i + 1); asking for global
injectivity buys that for free and removes an i ≤ n side condition from every lemma about the
edge frame. It costs a discharger nothing: a finite vertex list is padded to an injective
sequence by any tail of fresh points.
A simple polygonal arc, presented by its vertex list. The arc runs from vertex 0 to
vertex (n + 1) along the n + 1 edges [vertex i, vertex (i + 1)], i ≤ n.
- vertex_inj : Function.Injective self.vertex
The vertices are distinct.
- edges_meet (i : ℕ) : i ≤ n → ∀ j ≤ n, i ≠ j → segment ℝ (self.vertex i) (self.vertex (i + 1)) ∩ segment ℝ (self.vertex j) (self.vertex (j + 1)) ⊆ {self.vertex i, self.vertex (i + 1)}
Simplicity: an edge meets any other edge only at one of its own endpoints.
- corner (i : ℕ) : i < n → (self.vertex i - self.vertex (i + 1)).det (self.vertex (i + 2) - self.vertex (i + 1)) ≠ 0
No redundant vertex: the two edges at an interior vertex are not collinear. The two extreme vertices carry no condition, because the collar puts no sector there.
Instances For
The turned vector of a reversed direction #
The edge frame #
Every point is the point of some frame position, so the two coordinates identify it.
Edges as sets #
What simplicity gives #
Simplicity, second form. The trimmed core of an edge misses every other edge: the two
common points edges_meet allows are the endpoints, and the trim removes them.
The four germs at an interior vertex #
Plane.germs_split' applied at the interior vertex v (i + 1), whose incoming ray is
A.back i and whose outgoing ray is A.tang (i + 1). The smallness of the offset is left as a
hypothesis; the block versions supply it from the germ field of an ArcStrip.
The constants #
ArcStrip is the arc analogue of Schoenflies.StripData: the blueprint's "choose the blocks so
that consecutive ones overlap and nonadjacent closures are disjoint", with every constant named.
Three fields have no counterpart in the closed case, and they are what makes the collar a collar
of K inside D: ball_subset and tube_subset put every piece inside the prescribed open
set, and sep_ends keeps K clear of the two ends of the arc, where the collar has no pieces.
sep_ends is not a restriction in the intended application: the two endpoints of a crosscut lie
outside D and K lies inside, so the distance from K to either endpoint is positive and R
is chosen below it.
The constants of the collar of a compact piece K of the simple polygonal arc A, inside a
prescribed open set D.
- R : ℝ
The radius of the vertex sectors.
- lam : ℝ
The distance by which an edge block stops short of each endpoint of its edge.
- rho : ℝ
The half-width of an edge block.
The sectors reach past the ends of the blocks they have to overlap.
The blocks are nonempty, with room to spare at both ends.
A sector does not run past the far end of an incident edge.
Distinct vertices are
2Rapart, so distinct sectors are disjoint.- sep_vertex_edge (i : ℕ) : i ≤ n + 1 → ∀ j ≤ n, i ≠ j → i ≠ j + 1 → ∀ y ∈ A.edge j, 2 * self.R ≤ dist (A.vertex i) y
A vertex is
2Raway from every nonincident edge. - sep_trim_edge (i : ℕ) : i ≤ n → ∀ j ≤ n, j ≠ i → ∀ c ∈ Set.Icc self.lam (A.len i - self.lam), ∀ y ∈ A.edge j, 2 * self.rho ≤ dist (A.pt i c) y
The trimmed edge
iis2 * rhoaway from every other edge. - germ (i : ℕ) : i < n → self.rho * (1 + |inner ℝ (A.back i) (A.tang (i + 1))|) ≤ self.lam * |(A.back i).det (A.tang (i + 1))|
The vertex-matching threshold, at the interior vertices only.
The sector at an interior vertex is inside the prescribed open set.
- tube_subset (i : ℕ) : i ≤ n → ∀ c ∈ Set.Icc self.lam (A.len i - self.lam), Metric.ball (A.pt i c) self.rho ⊆ D
The block of an edge is inside the prescribed open set: a
rho-ball about a point of the trimmed core is. - subset_carrier : K ⊆ A.carrier
The compact piece is inside the arc…
…and clear of its two endpoints, where the collar has no pieces.
Instances For
The four families of blocks #
The k-th link of the left chain: the block of edge 0 to start with, and thereafter the
sector at vertex k glued to the block of edge k. Consecutive links overlap in the block of
the earlier edge, which is what makes the union connected.
Instances For
The collar: the union of the edge tubes and the balls about the interior vertices. Unlike the closed case it is not a neighbourhood of the whole arc — it stops short of the two endpoints — and it is manifestly open.
Equations
Instances For
The germ argument at an interior vertex #
Two shapes of bounded union #
Both tracks and the collar are unions over an initial segment of ℕ. These two rewrites are the
only interface to that indexing.
Nonadjacent blocks are disjoint #
Every step is one of the separation hypotheses of ArcStrip against one of the two containments
exists_foot and sectorL_subset_ball.
A tube stays out of the sectors at every vertex other than its edge's own two.
A sector misses every edge that is not incident to its vertex.
A sector misses the two edges incident to its vertex: their points lie on the two bounding rays, and the arcs are open.
The two tracks, as sets #
The collar minus the arc is exactly the two tracks #
A vertex ball minus the arc is covered by the two sectors at that vertex. A point of the
ball off the arc points in some direction from the vertex; that direction is either one of the
two incident rays — and then the point is on the incident edge, because R_le_len says the
sector does not run past the far end — or on one of the two arcs, and then the point is in the
corresponding sector.
Chaining a linear family #
The union of the left pieces is connected because consecutive pieces overlap. Unlike the cyclic
case there is no closing overlap to discard: the chain 0, 1, …, N is exactly the spanning tree
of the overlap graph.
A family of connected sets indexed by an initial segment of ℕ, in which every member meets
its successor, has connected union.
One positive offset below an accuracy, below a geometric bound, and small enough against a
germ threshold. This is the arc's replacement for the exists_common_bound of
Schoenflies/StripLocal.lean, which is private there.
The overlaps #
The blueprint's "consecutive edge and vertex blocks overlap in a nonempty labelled half-strip".
Both witnesses sit at across-coordinate rho / 2, at along-coordinate 3 lam / 2 from the
interior vertex in question.
The two tracks are connected #
The two tracks are disjoint #
Not a clause of Schoenflies.ArcCollar — the consumer does not need it — but it comes out of
the same four families times four families as in the cyclic case, and a later consumer will
want it.
The compact piece is inside the collar #
sep_ends is what makes this work: a point of K on the first edge is at least R from the
first vertex, so it is never in the gap the collar leaves at that end, and symmetrically at the
other end.
Both tracks approach every point of K #
A sector comes arbitrarily close to its vertex: shrink a point of it towards the vertex, which stays in the arc because an arc of directions is a cone.
Both tracks come arbitrarily close to every point of K. In the middle of an edge this
is the block; at an interior vertex it is exists_near_sectorL; in between it is the germ with
the progress held fixed and the offset shrunk below the corner's threshold. The two cases the
cyclic argument does not have — a point near an extreme vertex, where there is no sector —
are excluded by sep_ends.
Lemma 1.8 (b) #
The two-sided collar of the compact piece K along the arc, as the record
Schoenflies.ArcCollar that Schoenflies/CrosscutAtMostTwo.lean consumes. The construction is
exported, not existentially packaged: nbhd, sideL and sideR are definitions with an API
of their own, and Schoenflies.ArcStrip.sideL_disjoint_sideR and
Schoenflies.ArcStrip.isOpen_sideL are two clauses of Lemma 1.8 (b) that the record drops.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Choosing the constants #
The blueprint's own recipe, in the blueprint's order, with the two clauses about the prescribed open set folded in at the step where they can be met.
Rfrom the edge lengths, the pairwise vertex separations, the distance from each vertex to each nonincident edge, the openness ofDat each interior vertex, and the distance fromKto the two endpoints of the arc.lam := R / 5, which gives2 lam < Rand, throughR ≤ len i, also4 lam < len i.rhofrom the distance of each trimmed edge to every other edge, from the germ threshold at every interior vertex, and from the compact separation of each trimmed edge from the complement ofD. Step 3 is where "the collar is insideD" is really paid for: a trimmed core is a compact subset ofD, because the only points of the arc outsideDare its two endpoints and the trim removes them.
A point of a trimmed core is not the first vertex of the arc: on the first edge the trim keeps it away, and on any other edge simplicity does.
Step 1: the cone radius.
Step 3: the half-width.
Lemma 1.8 (b), the constants. A simple polygonal arc whose two endpoints lie outside the
region D and whose remaining points lie inside it carries an ArcStrip for every compact
piece K of D ∩ P.
Lemma 1.8 (b), and HasArcCollars #
Two-sided polygonal strips, the arc case. Every compact piece of the arc lying inside
the region has a two-sided collar there. The collar is ArcStrip.collar, a construction, not an
existential: Schoenflies.exists_arcStrip produces the constants and every part of the collar is
a definition with an API.
HasArcCollars for a polygonal arc. This is the hypothesis of
Schoenflies.crosscut_at_most_two, discharged.
Note that neither connectedness nor nontriviality of K is used: the collar exists for every
compact subset of D ∩ P.
P is a simple polygonal arc from a to b, presented by a vertex list. This is the
arc analogue of what Schoenflies.exists_closedPolygon proves for a Jordan curve, and it is the
one thing this module does not prove; see the note at the end of the file.
Equations
Instances For
HasArcCollars for a set presented as the carrier of a PolyArc. The conclusion is
literally the Schoenflies.HasArcCollars that Schoenflies/CrosscutAtMostTwo.lean carries as a
hypothesis, and the hypotheses are those of Schoenflies.crosscut_at_most_two together with the
presentation of P by a vertex list.
Lemma "At most two sides" for a polygonal arc presented by a vertex list.
Lemma "At most two sides", in the form the crosscut theorem consumes, for a polygonal arc presented by a vertex list.
The presentation is faithful: the carrier is a simple polygonal arc #
PolyArc is a presentation, so the interface owes a check in the other direction: that the
carrier of a PolyArc really is a simple polygonal arc between its two extreme vertices. Both
halves are an induction along the chain of edges, and the only input is simplicity: consecutive
edges meet exactly at the vertex they share, and nonconsecutive ones not at all.
With them, Lemma "At most two sides" for an arc presented by a vertex list has no hypothesis
left standing — Schoenflies.polyArc_crosscut_at_most_two.
The union of the first k + 1 edges is an arc from the first vertex to vertex (k + 1).
The carrier of a PolyArc is an arc between its two extreme vertices.
The carrier of a PolyArc is polygonal.
Lemma "At most two sides" for a polygonal arc presented by a vertex list, with nothing
left standing. The arc hypothesis and the polygonality hypothesis of
Schoenflies.crosscut_at_most_two are supplied by the presentation itself, and the collar
hypothesis by Schoenflies.PolyArc.hasArcCollars.
Lemma "At most two sides", in the form the crosscut theorem consumes, for a polygonal arc presented by a vertex list, with nothing left standing.
The presentation is not vacuous: a straight crosscut #
A nondegenerate segment is a PolyArc 0: one edge, no interior vertex, so both edges_meet and
corner are vacuous. The vertex function is padded past the segment by walking on in the same
direction, which keeps it injective — this is the padding convention the structure's docstring
describes, in its simplest instance. With it, Schoenflies.hasArcCollars_segment of
Schoenflies/CrosscutAtMostTwo.lean is a special case of Schoenflies.hasArcCollars, which
certifies that Schoenflies.IsPolyArcCarrier is satisfiable and that the whole apparatus above
is not vacuous.
The one-edge arc from a to b, with its vertex list padded injectively past b.
Equations
Instances For
A nondegenerate segment is presented by a vertex list.
What is still missing #
Exactly one thing: Schoenflies.IsPolyArcCarrier. Everything above is proved for an arc
presented by its vertex list, and Schoenflies.hasArcCollars therefore carries that
presentation as a hypothesis in place of the blueprint's set-level "P is a simple polygonal
arc" (IsArcBetween P a b together with IsPolygonal P).
The missing theorem is
theorem isPolyArcCarrier_of_isPolygonal {P : Set Plane} {a b : Plane}
(hP : IsArcBetween P a b) (hpoly : IsPolygonal P) (hab : a ≠ b) : IsPolyArcCarrier P a b
the arc analogue of Schoenflies.exists_closedPolygon, which Schoenflies/Realization.lean
proves for a Jordan curve. It is a normalisation statement, not geometry: it says a set that
happens to be both an arc and a finite union of segments can be cut into a chain. The route is
the one Schoenflies/Realization.lean takes in the closed case, and its three steps are:
Schoenflies.IsArcBetween.exists_poly_eqalready gives a vertex listvswithpoly vs = P,vs.head = a,vs.getLast = b. That list may backtrack: nothing yet says its vertices occur in order alongP.- Order them. Each segment
[vs i, vs (i+1)]is contained inPand is an arc between its ends, so bySchoenflies.IsArcBetween.eq_of_subsetit is the subarc ofPbetween the two parameters. The parameters of thevs i, sorted and deduplicated, therefore cut[0, 1]into intervals each of which is covered by one of those segments, and the subarc over each is a segment. That is the chain, withvertex_injandedges_meetimmediate from injectivity of the parametrisation. - Delete redundant vertices, i.e. merge two consecutive collinear edges into one. This is the
blueprint's own first sentence ("Delete redundant vertices at which two consecutive edges are
collinear") and is what
cornerneeds; the closed-curve analogue isSchoenflies.PrePolygon.exists_closedPolygon_of_prePolygon.
None of the three is formalised for an arc. The remaining results require no such interface.