/- Copyright (c) 2024 Judith Ludwig, Christian Merten. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Judith Ludwig, Christian Merten -/ import BruhatTits.Graph.GroupAction /-! # Proof that the Bruhat-Tits graph is a tree Let `R` be a discrete valuation ring and `K` its fraction field. In this file we show that the Bruhat-Tits graph associated to `R` is acyclic (i.e. without loops) and conclude that it is a tree. The connectedness was already shown in `BruhatTits.Graph.Graph` (see `BruhatTits.BTGraph_connected`). The strategy for proving acyclicity is as follows: - Show that every trail (i.e. a walk that has no self-intersections in the interior, but possibly at the ends) can be transformed into a standard walk by the action of `GL₂(K)`. Here a standard walk is a walk that is represented by a standard sequence of lattices (see `List.IsStandard`). - The length of a standard walk is the distance (in the sense of `inv`) of the endpoints, so by the first point, this also holds for every trail. - In particular, the second point holds for a circle at `x`, but a circle always has length at least `3 > 0 = inv x x`, so no circles exist. -/ namespace BruhatTits variable {K : Type*} [Field K] variable {R : Subring K} [IsDiscreteValuationRing R] [IsFractionRing R K] section Action /-- Any walk is representable by a chain of lattices. If the walk is a trail, the chain is simple (see `BruhatTits.exists_repr_isSimpleChain_of_isTrail`). -/ lemma _root_.SimpleGraph.Walk.exists_repr_isChain {x y : Vertices R} (p : BTgraph.Walk x y) : ∃ (l : List (Lattice R)), l.IsChain ∧ l.map (fun L ↦ ⟦L⟧) = p.support := by induction' p using SimpleGraph.Walk.rec with x x y z hadj p ih · refine Quotient.inductionOn' x (fun L ↦ ?_) refine ⟨[L], singleton_isChain L, by simp⟩ · obtain ⟨l, hchain, hl⟩ := ih have lnenil : l ≠ [] := by rintro rfl apply p.support_ne_nil simpa using hl.symm match l with | (L :: l) => have hLy : ⟦L⟧ = y := by rw [p.support_eq_cons] at hl simp only [List.map_cons, List.cons.injEq] at hl exact hl.left subst hLy obtain ⟨M, rfl, hstd⟩ := exists_repr_isStandardNeighbour_of_isNeighbour L x hadj.symm refine ⟨M :: L :: l, ?_, ?_⟩ · exact cons_isChain_of hchain hstd · simpa /-- A non-empty chain of lattices defines a walk on the Bruhat-Tits graph. -/ def chainToWalk (l : List (Lattice R)) (hl : l ≠ []) (hc : l.IsChain) : BTgraph.Walk ⟦l.head hl⟧ ⟦l.getLast hl⟧ := match l with | [L] => SimpleGraph.Walk.nil' ⟦L⟧ | L₁ :: L₂ :: l => have p : BTgraph.Adj ⟦L₁⟧ ⟦L₂⟧ := by apply isNeighbour_of_isStandardNeighbour have := hc.isStandardNeighbour simp only [List.chain'_cons] at this exact this.left let q : BTgraph.Walk ⟦L₂⟧ ⟦(L₁ :: L₂ :: l).getLast hl⟧ := chainToWalk (L₂ :: l) (by simp) (isChain_of_cons_isChain (List.cons_ne_nil L₂ l) hc) q.cons p lemma isSimpleChain_of_isTrail_aux {x y : Vertices R} (p : BTgraph.Walk x y) (hp : p.IsTrail) (l : List (Lattice R)) (hl : l.map (fun L ↦ ⟦L⟧) = p.support) : (List.zipWith₃ (fun L₁ _ L₃ ↦ ¬ Lattice.IsSimilar R L₁ L₃) l l.tail l.tail.tail).Forall id := by match p, l with | .nil, [L] => simp [List.zipWith₃] | .cons _ .nil, [_, _] => simp [List.zipWith₃] | .cons adj (.cons adj' .nil), [M, L, Q] => simp only [List.map_cons, List.map_nil, SimpleGraph.Walk.support_cons, SimpleGraph.Walk.support_nil, List.cons.injEq, and_true] at hl simp only [List.tail_cons, List.zipWith₃, List.forall_cons, id_eq, List.Forall, and_true] intro h have : (⟦M⟧ : Vertices R) = ⟦Q⟧ := by simpa simp only [SimpleGraph.Walk.cons_isTrail_iff, SimpleGraph.Walk.IsTrail.nil, SimpleGraph.Walk.edges_nil, List.not_mem_nil, not_false_eq_true, and_self, SimpleGraph.Walk.edges_cons, List.mem_singleton, Sym2.eq, Sym2.rel_iff', Prod.mk.injEq, Prod.swap_prod_mk, and_true, not_or, not_and, true_and] at hp apply hp.right rw [← hl.left, ← hl.right.right] exact this | .cons adj (.cons adj' <| .cons adj'' q), (L₁ :: L₂ :: L₃ :: l) => simp only [List.map_cons, SimpleGraph.Walk.support_cons, List.cons.injEq] at hl simp only [SimpleGraph.Walk.cons_isTrail_iff, SimpleGraph.Walk.edges_cons, List.mem_cons, Sym2.eq, Sym2.rel_iff', Prod.mk.injEq, Prod.swap_prod_mk, and_true, not_or, not_and] at hp simp only [List.tail_cons, List.zipWith₃, List.forall_cons, id_eq] refine ⟨?_, ?_⟩ · intro h have h1 := hl.left subst h1 have h2 := hl.right.left subst h2 have h3 := hl.right.right.left subst h3 have h' : (⟦L₁⟧ : Vertices R) = ⟦L₃⟧ := by apply Quotient.sound exact h tauto · apply isSimpleChain_of_isTrail_aux (.cons adj' <| .cons adj'' q) · simp tauto · simp tauto /-- If `p` is a trail in the Bruhat-Tits graph, it is representable by a simple chain of lattices. -/ lemma exists_repr_isSimpleChain_of_isTrail {x y : Vertices R} (p : BTgraph.Walk x y) (hp : p.IsTrail) : ∃ (l : List (Lattice R)), l.IsSimpleChain ∧ l.map (fun L ↦ ⟦L⟧) = p.support := by obtain ⟨l, hl, heq⟩ := p.exists_repr_isChain refine ⟨l, ⟨hl, ?_⟩, heq⟩ apply isSimpleChain_of_isTrail_aux p hp _ heq /-- A walk on the Bruhat-Tits graph is a standard walk, if there exists a sequence of representing lattices `(Lᵢ)` with `pᵢ = ⟦Lᵢ⟧` such that the sequence `(Lᵢ)` is a standard sequence (see `List.IsStandard`). -/ def _root_.SimpleGraph.Walk.IsStandard {x y : Vertices R} (p : BTgraph.Walk x y) : Prop := ∃ (l : List (Lattice R)), l.map (fun L ↦ ⟦L⟧) = p.support ∧ l.IsStandard lemma isStandard_of_list_isStandard {x y : Vertices R} {p : BTgraph.Walk x y} (l : List (Lattice R)) (hleq : l.map (fun L ↦ ⟦L⟧) = p.support) (hl : l.IsStandard) : p.IsStandard := by use l /-- If `p` is a standard walk from `x` to `y`, the length of `p` is the distance `inv x y`. -/ lemma length_eq_inv_of_isStandard {x y : Vertices R} {p : BTgraph.Walk x y} (h : p.IsStandard) : p.length = inv x y := by obtain ⟨l, hleq, hl⟩ := h have hlen := length_eq_dist_add_one_of_isStandard hl have : p.support.length = dist (l.head hl.ne_nil) (l.getLast hl.ne_nil) + 1 := by rw [← hleq] simpa simp only [SimpleGraph.Walk.length_support, add_left_inj] at this have : x = ⟦l.head hl.ne_nil⟧ := by match l with | L :: l => rw [p.support_eq_cons, List.map_cons, List.cons.injEq] at hleq simpa using hleq.left.symm subst this have : y = ⟦l.getLast hl.ne_nil⟧ := by apply_fun List.reverse at hleq rw [← p.support_reverse, p.reverse.support_eq_cons] at hleq rw [← List.getLast_map (f := fun L ↦ ⟦L⟧), List.getLast_eq_head_reverse] simp_rw [hleq] · rfl · simpa using List.ne_nil_of_length_eq_add_one hlen subst this assumption /-- Given two vertices and a trail `p` from `x` to `y`, there exists a `g : GL₂(K)` such that `g • p` is a standard walk. -/ lemma exists_map_isStandard {x y : Vertices R} {p : BTgraph.Walk x y} (hp : p.IsTrail) : ∃ (g : GL (Fin 2) K), (p.map (g.toGraphIso (R := R))).IsStandard (R := R) := by obtain ⟨l, hlsimple, heq⟩ := exists_repr_isSimpleChain_of_isTrail p hp obtain ⟨g, hg⟩ := exists_trafo_to_isStandard l hlsimple use g refine isStandard_of_list_isStandard (g • l) ?_ hg simp only [List.smul_lattice_def, List.map_map, RelEmbedding.coe_toRelHom, RelIso.coe_toRelEmbedding, SimpleGraph.Walk.support_map] show List.map (fun L ↦ ⟦g • L⟧) l = _ simp_rw [← smulGL_mk, ← Vertices.smul_def] show List.map ((fun x : Vertices R ↦ g • x) ∘ (fun L ↦ ⟦L⟧)) l = _ rw [List.comp_map, heq] rfl end Action section Acyclic /-- The length of a trail is equal to the distance of the endpoints. -/ lemma length_eq_inv {x y : Vertices R} {p : BTgraph.Walk x y} (hp : p.IsTrail) : p.length = inv x y := by -- transform chain to standard one by a graph isomorphism, then apply the result for -- standard walks obtain ⟨g, hg⟩ := exists_map_isStandard hp have : (p.map (g.toGraphIso (R := R)).toHom).length = inv (g • x) (g • y) := length_eq_inv_of_isStandard hg simpa using this /-- The graph-theoretic distance agrees with our constructed `inv` function. -/ lemma dist_BTgraph_eq_inv : (BTgraph (R := R)).dist = inv := by ext x y obtain ⟨p, hp, hlen⟩ := (BTgraph_connected (R := R)).exists_path_of_dist x y rw [← hlen, length_eq_inv hp.isTrail] /-- The Bruhat-Tits graph has no loops, i.e. it is acyclic. -/ lemma BTgraph_isAcyclic : (BTgraph (R := R)).IsAcyclic := by -- suppose `c` is a circle intro x c h -- then `c` is a trail, but the length of such a chain is the distance -- of the endpoints, which yields a contradiction have : c.length = inv x x := length_eq_inv h.isCircuit.isTrail rw [inv_self] at this have : 3 ≤ 0 := by rw [← this] exact SimpleGraph.Walk.IsCycle.three_le_length h contradiction end Acyclic /-- The Bruhat-Tits graph is a tree. -/ theorem BTtree : SimpleGraph.IsTree (BTgraph (R := R)) where isConnected := BTgraph_connected IsAcyclic := BTgraph_isAcyclic