|
| 1 | +/- |
| 2 | +Copyright (c) 2023 Bhavik Mehta, Rishi Mehta, Linus Sommer. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: Bhavik Mehta, Rishi Mehta, Linus Sommer |
| 5 | +-/ |
| 6 | +import Mathlib.Algebra.Order.Ring.Nat |
| 7 | +import Mathlib.Combinatorics.SimpleGraph.Connectivity |
| 8 | + |
| 9 | +/-! |
| 10 | +# Hamiltonian Graphs |
| 11 | +
|
| 12 | +In this file we introduce hamiltonian paths, cycles and graphs. |
| 13 | +
|
| 14 | +## Main definitions |
| 15 | +
|
| 16 | +- `SimpleGraph.Walk.IsHamiltonian`: Predicate for a walk to be hamiltonian. |
| 17 | +- `SimpleGraph.Walk.IsHamiltonianCycle`: Predicate for a walk to be a hamiltonian cycle. |
| 18 | +- `SimpleGraph.IsHamiltonian`: Predicate for a graph to be hamiltonian. |
| 19 | +-/ |
| 20 | + |
| 21 | +open Finset Function |
| 22 | +open scoped BigOperators |
| 23 | + |
| 24 | +namespace SimpleGraph |
| 25 | +variable {α β : Type*} [Fintype α] [Fintype β] [DecidableEq α] [DecidableEq β] {G : SimpleGraph α} |
| 26 | + {a b : α} {p : G.Walk a b} |
| 27 | + |
| 28 | +namespace Walk |
| 29 | + |
| 30 | +/-- A hamiltonian path is a walk `p` that visits every vertex exactly once. Note that while |
| 31 | +this definition doesn't contain that `p` is a path, `p.isPath` gives that. -/ |
| 32 | +def IsHamiltonian (p : G.Walk a b) : Prop := ∀ a, p.support.count a = 1 |
| 33 | + |
| 34 | +lemma IsHamiltonian.map {H : SimpleGraph β} (f : G →g H) (hf : Bijective f) (hp : p.IsHamiltonian) : |
| 35 | + (p.map f).IsHamiltonian := by |
| 36 | + simp [IsHamiltonian, hf.surjective.forall, hf.injective, hp _] |
| 37 | + |
| 38 | +/-- A hamiltonian path visits every vertex. -/ |
| 39 | +@[simp] lemma IsHamiltonian.mem_support (hp : p.IsHamiltonian) (c : α) : c ∈ p.support := by |
| 40 | + simp only [← List.count_pos_iff_mem, hp _, Nat.zero_lt_one] |
| 41 | + |
| 42 | +/-- The support of a hamiltonian walk is the entire vertex set. -/ |
| 43 | +lemma IsHamiltonian.support_toFinset (hp : p.IsHamiltonian) : p.support.toFinset = Finset.univ := by |
| 44 | + simp [eq_univ_iff_forall, hp] |
| 45 | + |
| 46 | +/-- The length of a hamiltonian path is one less than the number of vertices of the graph. -/ |
| 47 | +lemma IsHamiltonian.length_eq (hp : p.IsHamiltonian) : p.length = Fintype.card α - 1 := |
| 48 | + eq_tsub_of_add_eq $ by |
| 49 | + rw [← length_support, ← List.sum_toFinset_count_eq_length, Finset.sum_congr rfl fun _ _ ↦ hp _, |
| 50 | + ← card_eq_sum_ones, hp.support_toFinset, card_univ] |
| 51 | + |
| 52 | +/-- Hamiltonian paths are paths. -/ |
| 53 | +lemma IsHamiltonian.isPath (hp : p.IsHamiltonian) : p.IsPath := |
| 54 | + IsPath.mk' <| List.nodup_iff_count_le_one.2 <| (le_of_eq <| hp ·) |
| 55 | + |
| 56 | +/-- A path whose support contains every vertex is hamiltonian. -/ |
| 57 | +lemma IsPath.isHamiltonian_of_mem (hp : p.IsPath) (hp' : ∀ w, w ∈ p.support) : |
| 58 | + p.IsHamiltonian := fun _ ↦ |
| 59 | + le_antisymm (List.nodup_iff_count_le_one.1 hp.support_nodup _) (List.count_pos_iff_mem.2 (hp' _)) |
| 60 | + |
| 61 | +lemma IsPath.isHamiltonian_iff (hp : p.IsPath) : p.IsHamiltonian ↔ ∀ w, w ∈ p.support := |
| 62 | + ⟨(·.mem_support), hp.isHamiltonian_of_mem⟩ |
| 63 | + |
| 64 | +/-- A hamiltonian cycle is a cycle that visits every vertex once. -/ |
| 65 | +structure IsHamiltonianCycle (p : G.Walk a a) extends p.IsCycle : Prop := |
| 66 | + isHamiltonian_tail : (p.tail toIsCycle.not_nil).IsHamiltonian |
| 67 | + |
| 68 | +variable {p : G.Walk a a} |
| 69 | + |
| 70 | +lemma IsHamiltonianCycle.isCycle (hp : p.IsHamiltonianCycle) : p.IsCycle := |
| 71 | + hp.toIsCycle |
| 72 | + |
| 73 | +lemma IsHamiltonianCycle.map {H : SimpleGraph β} (f : G →g H) (hf : Bijective f) |
| 74 | + (hp : p.IsHamiltonianCycle) : (p.map f).IsHamiltonianCycle where |
| 75 | + toIsCycle := hp.isCycle.map hf.injective |
| 76 | + isHamiltonian_tail := by |
| 77 | + simp [IsHamiltonian, support_tail, hf.surjective.forall, List.count_tail, hf.injective] |
| 78 | + intro x |
| 79 | + rcases p with (_ | ⟨y, p⟩) |
| 80 | + · cases hp.ne_nil rfl |
| 81 | + simp only [support_cons, List.count_cons, List.map_cons, List.head_cons, hf.injective.eq_iff, |
| 82 | + add_tsub_cancel_right] |
| 83 | + exact hp.isHamiltonian_tail _ |
| 84 | + |
| 85 | +lemma isHamiltonianCycle_isCycle_and_isHamiltonian_tail : |
| 86 | + p.IsHamiltonianCycle ↔ ∃ h : p.IsCycle, (p.tail h.not_nil).IsHamiltonian := |
| 87 | + ⟨fun ⟨h, h'⟩ ↦ ⟨h, h'⟩, fun ⟨h, h'⟩ ↦ ⟨h, h'⟩⟩ |
| 88 | + |
| 89 | +lemma isHamiltonianCycle_iff_isCycle_and_support_count_tail_eq_one : |
| 90 | + p.IsHamiltonianCycle ↔ p.IsCycle ∧ ∀ a, (support p).tail.count a = 1 := by |
| 91 | + simp only [isHamiltonianCycle_isCycle_and_isHamiltonian_tail , IsHamiltonian, support_tail, |
| 92 | + exists_prop] |
| 93 | + |
| 94 | +/-- A hamiltonian cycle visits every vertex. -/ |
| 95 | +lemma IsHamiltonianCycle.mem_support (hp : p.IsHamiltonianCycle) (b : α) : |
| 96 | + b ∈ p.support := List.mem_of_mem_tail <| support_tail p _ ▸ hp.isHamiltonian_tail.mem_support _ |
| 97 | + |
| 98 | +/-- The length of a hamiltonian cycle is the number of vertices. -/ |
| 99 | +lemma IsHamiltonianCycle.length_eq (hp : p.IsHamiltonianCycle) : |
| 100 | + p.length = Fintype.card α := by |
| 101 | + rw [← length_tail_add_one hp.not_nil, hp.isHamiltonian_tail.length_eq, Nat.sub_add_cancel] |
| 102 | + rw [Nat.succ_le, Fintype.card_pos_iff] |
| 103 | + exact ⟨a⟩ |
| 104 | + |
| 105 | +lemma IsHamiltonianCycle.count_support_self (hp : p.IsHamiltonianCycle) : |
| 106 | + p.support.count a = 2 := by |
| 107 | + rw [support_eq_cons, List.count_cons_self, ← support_tail, hp.isHamiltonian_tail] |
| 108 | + |
| 109 | +lemma IsHamiltonianCycle.support_count_of_ne (hp : p.IsHamiltonianCycle) (h : a ≠ b) : |
| 110 | + p.support.count b = 1 := by |
| 111 | + rw [← cons_support_tail p, List.count_cons_of_ne h.symm, hp.isHamiltonian_tail] |
| 112 | + |
| 113 | +end Walk |
| 114 | + |
| 115 | +/-- A hamiltonian graph is a graph that contains a hamiltonian cycle. |
| 116 | +
|
| 117 | +By convention, the singleton graph is considered to be hamiltonian. -/ |
| 118 | +def IsHamiltonian (G : SimpleGraph α) : Prop := |
| 119 | + Fintype.card α ≠ 1 → ∃ a, ∃ p : G.Walk a a, p.IsHamiltonianCycle |
| 120 | + |
| 121 | +lemma IsHamiltonian.mono {H : SimpleGraph α} (hGH : G ≤ H) (hG : G.IsHamiltonian) : |
| 122 | + H.IsHamiltonian := |
| 123 | + fun hα ↦ let ⟨_, p, hp⟩ := hG hα; ⟨_, p.map $ .ofLE hGH, hp.map _ bijective_id⟩ |
| 124 | + |
| 125 | +lemma IsHamiltonian.connected (hG : G.IsHamiltonian) : G.Connected where |
| 126 | + preconnected a b := by |
| 127 | + obtain rfl | hab := eq_or_ne a b |
| 128 | + · rfl |
| 129 | + have : Nontrivial α := ⟨a, b, hab⟩ |
| 130 | + obtain ⟨_, p, hp⟩ := hG Fintype.one_lt_card.ne' |
| 131 | + have a_mem := hp.mem_support a |
| 132 | + have b_mem := hp.mem_support b |
| 133 | + exact ((p.takeUntil a a_mem).reverse.append $ p.takeUntil b b_mem).reachable |
| 134 | + nonempty := not_isEmpty_iff.1 fun _ ↦ by simpa using hG $ by simp [@Fintype.card_eq_zero] |
| 135 | + |
| 136 | +end SimpleGraph |
0 commit comments