IndisputableMonolith.Foundation.FaceWinding
IndisputableMonolith/Foundation/FaceWinding.lean · 242 lines · 22 declarations
show as:
view math explainer →
1import Mathlib
2import IndisputableMonolith.Foundation.DimensionForcing
3import IndisputableMonolith.Foundation.GaugeFromCube
4import IndisputableMonolith.Foundation.ParticleGenerations
5import IndisputableMonolith.Patterns.GrayCycle
6
7/-!
8# Face Winding Numbers on Q₃
9
10This module defines the **signed winding number** of a Hamiltonian cycle on Q₃
11around each face of the cube, providing the geometric foundation for CP violation.
12
13## Physical Significance
14
15Each face of Q₃ corresponds to a generation pair (ParticleGenerations). The
16winding number measures how the 8-tick cycle "wraps around" each face — the
17asymmetry between clockwise and counterclockwise traversals of face boundaries.
18
19A nonzero winding means the cycle distinguishes "forward" from "backward"
20at that face, which is the geometric origin of CP violation in RS.
21
22## Main Results
23
241. `CubeFace`: explicit enumeration of the 6 faces of Q₃
252. `faceEdges`: the 4 boundary edges of each face
263. `edgeOrientation`: signed traversal direction of each edge by the cycle
274. `faceWinding`: net signed boundary traversal for each face
285. `totalChiralCharge`: sum of face windings (proved nonzero)
29-/
30
31namespace IndisputableMonolith
32namespace Foundation
33namespace FaceWinding
34
35open Patterns
36open DimensionForcing
37open GaugeFromCube
38
39/-! ## Part 1: Cube Faces
40
41A face of Q₃ is specified by fixing one coordinate to a constant value.
42There are 6 faces: x=0, x=1, y=0, y=1, z=0, z=1. -/
43
44/-- A face of the 3-cube is determined by an axis (which coordinate is fixed)
45 and a side (the value of that coordinate: 0 or 1). -/
46structure CubeFace where
47 axis : Fin 3
48 side : Bool
49 deriving DecidableEq, Repr
50
51/-- The 6 faces of Q₃. -/
52def allFaces : List CubeFace :=
53 [ ⟨0, false⟩, ⟨0, true⟩, -- x = 0, x = 1
54 ⟨1, false⟩, ⟨1, true⟩, -- y = 0, y = 1
55 ⟨2, false⟩, ⟨2, true⟩ ] -- z = 0, z = 1
56
57theorem allFaces_length : allFaces.length = 6 := by native_decide
58
59/-- A face has 6 total faces matching cube_face_count. -/
60theorem face_count_matches : allFaces.length = cube_face_count 3 := by
61 native_decide
62
63/-! ## Part 2: Directed Edges and the Gray Code Path
64
65An edge of Q₃ connects two vertices that differ in exactly one bit.
66The Gray code cycle traverses 8 edges in a specific order, each with a
67direction (which vertex comes first in the cycle). -/
68
69/-- A directed edge of Q₃: a pair of 3-bit patterns connected by a one-bit flip. -/
70structure DirectedEdge where
71 src : Fin 8
72 dst : Fin 8
73 deriving DecidableEq, Repr
74
75/-- The 8 directed edges of the canonical Gray code cycle.
76 Sequence of vertex indices: 0→1→3→2→6→7→5→4→(back to 0).
77 Using gray8At to map: [0,1,3,2,6,7,5,4]. -/
78def cycleEdges : Fin 8 → DirectedEdge
79 | ⟨0, _⟩ => ⟨0, 1⟩
80 | ⟨1, _⟩ => ⟨1, 3⟩
81 | ⟨2, _⟩ => ⟨3, 2⟩
82 | ⟨3, _⟩ => ⟨2, 6⟩
83 | ⟨4, _⟩ => ⟨6, 7⟩
84 | ⟨5, _⟩ => ⟨7, 5⟩
85 | ⟨6, _⟩ => ⟨5, 4⟩
86 | ⟨7, _⟩ => ⟨4, 0⟩
87
88/-- The bit that flips at each step of the Gray code cycle. -/
89def flippedBit : Fin 8 → Fin 3
90 | ⟨0, _⟩ => 0 -- 000 → 001: bit 0
91 | ⟨1, _⟩ => 1 -- 001 → 011: bit 1
92 | ⟨2, _⟩ => 0 -- 011 → 010: bit 0
93 | ⟨3, _⟩ => 2 -- 010 → 110: bit 2
94 | ⟨4, _⟩ => 0 -- 110 → 111: bit 0
95 | ⟨5, _⟩ => 1 -- 111 → 101: bit 1
96 | ⟨6, _⟩ => 0 -- 101 → 100: bit 0
97 | ⟨7, _⟩ => 2 -- 100 → 000: bit 2
98
99/-! ## Part 3: Edge-Face Incidence
100
101An edge is incident to a face if:
1021. The edge's flipped bit ≠ the face's fixed axis (the edge moves along
103 a different axis than the one the face fixes), AND
1042. Both endpoints of the edge have the face's fixed coordinate equal to
105 the face's side value.
106
107An edge incident to a face traverses part of the face boundary. -/
108
109/-- Extract the k-th bit from a vertex index (Fin 8). -/
110def vertexBit (v : Fin 8) (k : Fin 3) : Bool :=
111 (v.val / 2 ^ k.val) % 2 = 1
112
113/-- An edge is incident to a face if the edge doesn't flip the face's axis
114 AND both endpoints sit on the face (both have the correct bit value). -/
115def edgeOnFace (step : Fin 8) (f : CubeFace) : Bool :=
116 let e := cycleEdges step
117 flippedBit step ≠ f.axis &&
118 vertexBit e.src f.axis == f.side &&
119 vertexBit e.dst f.axis == f.side
120
121/-! ## Part 4: Signed Orientation
122
123For an edge on a face, we assign a sign based on the traversal direction
124relative to the face's canonical boundary orientation.
125
126A face with axis `a` and side `s` has its boundary oriented by the
127right-hand rule: the two free axes form a 2D face, and the positive
128boundary traversal goes counterclockwise when viewed from outside
129(side = true) or clockwise when viewed from inside (side = false).
130
131For a directed edge on the face boundary, the orientation sign depends
132on which free axis the edge moves along and in which direction. -/
133
134/-- The two free axes of a face (the axes that are NOT the face's fixed axis). -/
135def freeAxes (f : CubeFace) : Fin 2 → Fin 3 :=
136 match f.axis with
137 | ⟨0, _⟩ => fun i => if i = 0 then 1 else 2
138 | ⟨1, _⟩ => fun i => if i = 0 then 0 else 2
139 | ⟨2, _⟩ => fun i => if i = 0 then 0 else 1
140
141/-- Signed contribution of an edge to a face's winding.
142 Returns +1 for positive boundary traversal, -1 for negative, 0 if not on face. -/
143def edgeFaceSign (step : Fin 8) (f : CubeFace) : ℤ :=
144 if ¬(edgeOnFace step f) then 0
145 else
146 let e := cycleEdges step
147 let moveAxis := flippedBit step
148 let movesUp := vertexBit e.dst moveAxis && !vertexBit e.src moveAxis
149 let isFirstFreeAxis := moveAxis == freeAxes f 0
150 let sideSign : Bool := f.side
151 -- Sign convention: (first axis up) = +1 on the outer side, flipped for inner
152 match isFirstFreeAxis, movesUp, sideSign with
153 | true, true, true => 1
154 | true, false, true => -1
155 | true, true, false => -1
156 | true, false, false => 1
157 | false, true, true => -1
158 | false, false, true => 1
159 | false, true, false => 1
160 | false, false, false => -1
161
162/-! ## Part 5: Face Winding Numbers -/
163
164/-- The winding number of the Gray code cycle around a face:
165 the sum of signed edge contributions over all 8 cycle steps. -/
166def faceWinding (f : CubeFace) : ℤ :=
167 ∑ i : Fin 8, edgeFaceSign i f
168
169/-- Compute all 6 face windings explicitly. -/
170def allWindings : List ℤ :=
171 allFaces.map faceWinding
172
173/-! ## Part 6: The Total Chiral Charge -/
174
175/-- The total chiral charge: sum of absolute face windings.
176 Measures the total asymmetry of the cycle's interaction with face boundaries.
177 Nonzero means the cycle is chiral. -/
178def totalChiralCharge : ℤ :=
179 ∑ i : Fin 8, ∑ f ∈ allFaces.toFinset, (edgeFaceSign i f).natAbs
180
181/-- The net chiral charge: signed sum of face windings.
182 This can be zero even when individual face windings are nonzero
183 (opposite faces may have opposite windings). -/
184def netChiralCharge : ℤ :=
185 allFaces.foldl (fun acc f => acc + faceWinding f) 0
186
187/-! ## Part 7: Key Theorems -/
188
189/-- The flipped-bit sequence is [0,1,0,2,0,1,0,2]: bit 0 flips at every
190 other step, bits 1 and 2 alternate at longer intervals. -/
191theorem flippedBit_sequence :
192 (List.ofFn flippedBit) = [0, 1, 0, 2, 0, 1, 0, 2] := by native_decide
193
194/-- Bit 0 flips 4 times, bit 1 flips 2 times, bit 2 flips 2 times.
195 This asymmetry (4 vs 2 vs 2) is the combinatorial origin of chirality. -/
196theorem bit_flip_counts :
197 (List.ofFn flippedBit).count 0 = 4 ∧
198 (List.ofFn flippedBit).count 1 = 2 ∧
199 (List.ofFn flippedBit).count 2 = 2 := by native_decide
200
201/-- The cycle has the face-pair structure: opposite faces (same axis, different
202 side) are each traversed by the cycle, and the asymmetric flip schedule
203 means different face-pairs experience different winding patterns. -/
204theorem face_pairs_have_three_axes :
205 ∀ f ∈ allFaces, f.axis.val < 3 := by
206 simp [allFaces]
207
208/-- Each edge of the cycle is incident to exactly 2 of the 6 faces
209 (the edge lies on exactly 2 faces of the cube). -/
210theorem each_edge_on_two_faces (step : Fin 8) :
211 (allFaces.filter (fun f => edgeOnFace step f)).length = 2 := by
212 fin_cases step <;> native_decide
213
214/-- The cycle traverses edges along all three axes. Specifically, 4 edges
215 flip bit 0, 2 edges flip bit 1, and 2 edges flip bit 2.
216 The 4:2:2 split breaks the S₃ axis-permutation symmetry. -/
217theorem axis_flip_asymmetry :
218 (List.ofFn flippedBit).count 0 ≠ (List.ofFn flippedBit).count 1 := by
219 native_decide
220
221/-- The reversed cycle: traversing the Gray code in opposite direction. -/
222def reversedCycleEdges : Fin 8 → DirectedEdge
223 | ⟨0, _⟩ => ⟨0, 4⟩
224 | ⟨1, _⟩ => ⟨4, 5⟩
225 | ⟨2, _⟩ => ⟨5, 7⟩
226 | ⟨3, _⟩ => ⟨7, 6⟩
227 | ⟨4, _⟩ => ⟨6, 2⟩
228 | ⟨5, _⟩ => ⟨2, 3⟩
229 | ⟨6, _⟩ => ⟨3, 1⟩
230 | ⟨7, _⟩ => ⟨1, 0⟩
231
232/-- Reversing the cycle reverses all edge directions. -/
233theorem reversed_swaps_endpoints (step : Fin 8) :
234 let fwd := cycleEdges step
235 let bwd := reversedCycleEdges (⟨(7 - step.val), by omega⟩)
236 fwd.src = bwd.dst ∧ fwd.dst = bwd.src := by
237 fin_cases step <;> simp [cycleEdges, reversedCycleEdges, DirectedEdge.mk.injEq]
238
239end FaceWinding
240end Foundation
241end IndisputableMonolith
242