l3lab/ntp-mathlib huggingface dataset:
/-- An induction principle for `Cycle`. Use as `induction s using Cycle.induction_on`. -/
@[elab_as_elim]
theorem induction_on {C : Cycle α → Prop} (s : Cycle α) (H0 : C nil)
    (HI : ∀ (a) (l : List α), C ↑l → C ↑(a :: l)) : C s :=
  Quotient.inductionOn' s fun l => by
    refine List.recOn l ?_ ?_ <;> simp
    

Proof state:
case refine_1
α : Type u_1
C : Cycle α → Prop
s : Cycle α
H0 : C nil
HI : ∀ (a : α) (l : List α), C ↑l → C ↑(a :: l)
l : List α
⊢ C nil
case refine_2
α : Type u_1
C : Cycle α → Prop
s : Cycle α
H0 : C nil
HI : ∀ (a : α) (l : List α), C ↑l → C ↑(a :: l)
l : List α
⊢ ∀ (head : α) (tail : List α), C ↑tail → C ↑(head :: tail)

Next tactic:
assumption'
@[simp]
theorem reverse_reverse (s : Cycle α) : s.reverse.reverse = s :=
  Quot.inductionOn s fun _ => by 

Proof state:
α : Type u_1
s : Cycle α
x✝ : List α
⊢ reverse (reverse (Quot.mk Setoid.r x✝)) = Quot.mk Setoid.r x✝

Next tactic:
simp
@[simp]
theorem subsingleton_reverse_iff {s : Cycle α} : s.reverse.Subsingleton ↔ s.Subsingleton := by
  

Proof state:
α : Type u_1
s : Cycle α
⊢ Subsingleton (reverse s) ↔ Subsingleton s

Next tactic:
simp [length_subsingleton_iff]
theorem Subsingleton.congr {s : Cycle α} (h : Subsingleton s) :
    ∀ ⦃x⦄ (_hx : x ∈ s) ⦃y⦄ (_hy : y ∈ s), x = y := by
  

Proof state:
α : Type u_1
s : Cycle α
h : Subsingleton s
⊢ ∀ ⦃x : α⦄, x ∈ s → ∀ ⦃y : α⦄, y ∈ s → x = y

Next tactic:
induction' s using Quot.inductionOn with l
theorem Subsingleton.congr {s : Cycle α} (h : Subsingleton s) :
    ∀ ⦃x⦄ (_hx : x ∈ s) ⦃y⦄ (_hy : y ∈ s), x = y := by
  induction' s using Quot.inductionOn with l
  

Proof state:
case h
α : Type u_1
l : List α
h : Subsingleton (Quot.mk Setoid.r l)
⊢ ∀ ⦃x : α⦄, x ∈ Quot.mk Setoid.r l → ∀ ⦃y : α⦄, y ∈ Quot.mk Setoid.r l → x = y

Next tactic:
simp only [length_subsingleton_iff, length_coe, mk_eq_coe, le_iff_lt_or_eq, Nat.lt_add_one_iff,
    length_eq_zero, length_eq_one, Nat.not_lt_zero, false_or_iff] at h
theorem Subsingleton.congr {s : Cycle α} (h : Subsingleton s) :
    ∀ ⦃x⦄ (_hx : x ∈ s) ⦃y⦄ (_hy : y ∈ s), x = y := by
  induction' s using Quot.inductionOn with l
  simp only [length_subsingleton_iff, length_coe, mk_eq_coe, le_iff_lt_or_eq, Nat.lt_add_one_iff,
    length_eq_zero, length_eq_one, Nat.not_lt_zero, false_or_iff] at h
  

Proof state:
case h
α : Type u_1
l : List α
h : l = [] ∨ ∃ a, l = [a]
⊢ ∀ ⦃x : α⦄, x ∈ Quot.mk Setoid.r l → ∀ ⦃y : α⦄, y ∈ Quot.mk Setoid.r l → x = y

Next tactic:
rcases h with (rfl | ⟨z, rfl⟩)
theorem Subsingleton.congr {s : Cycle α} (h : Subsingleton s) :
    ∀ ⦃x⦄ (_hx : x ∈ s) ⦃y⦄ (_hy : y ∈ s), x = y := by
  induction' s using Quot.inductionOn with l
  simp only [length_subsingleton_iff, length_coe, mk_eq_coe, le_iff_lt_or_eq, Nat.lt_add_one_iff,
    length_eq_zero, length_eq_one, Nat.not_lt_zero, false_or_iff] at h
  rcases h with (rfl | ⟨z, rfl⟩) <;> 

Proof state:
case h.inl
α : Type u_1
⊢ ∀ ⦃x : α⦄, x ∈ Quot.mk Setoid.r [] → ∀ ⦃y : α⦄, y ∈ Quot.mk Setoid.r [] → x = y

Next tactic:
simp
theorem Subsingleton.congr {s : Cycle α} (h : Subsingleton s) :
    ∀ ⦃x⦄ (_hx : x ∈ s) ⦃y⦄ (_hy : y ∈ s), x = y := by
  induction' s using Quot.inductionOn with l
  simp only [length_subsingleton_iff, length_coe, mk_eq_coe, le_iff_lt_or_eq, Nat.lt_add_one_iff,
    length_eq_zero, length_eq_one, Nat.not_lt_zero, false_or_iff] at h
  rcases h with (rfl | ⟨z, rfl⟩) <;> 

Proof state:
case h.inr.intro
α : Type u_1
z : α
⊢ ∀ ⦃x : α⦄, x ∈ Quot.mk Setoid.r [z] → ∀ ⦃y : α⦄, y ∈ Quot.mk Setoid.r [z] → x = y

Next tactic:
simp
@[simp]
theorem nontrivial_coe_nodup_iff {l : List α} (hl : l.Nodup) :
    Nontrivial (l : Cycle α) ↔ 2 ≤ l.length := by
  

Proof state:
α : Type u_1
l : List α
hl : Nodup l
⊢ Nontrivial ↑l ↔ 2 ≤ List.length l

Next tactic:
rw [Nontrivial]
@[simp]
theorem nontrivial_coe_nodup_iff {l : List α} (hl : l.Nodup) :
    Nontrivial (l : Cycle α) ↔ 2 ≤ l.length := by
  rw [Nontrivial]
  

Proof state:
α : Type u_1
l : List α
hl : Nodup l
⊢ (∃ x y, x ≠ y ∧ x ∈ ↑l ∧ y ∈ ↑l) ↔ 2 ≤ List.length l

Next tactic:
rcases l with (_ | ⟨hd, _ | ⟨hd', tl⟩⟩)
@[simp]
theorem nontrivial_coe_nodup_iff {l : List α} (hl : l.Nodup) :
    Nontrivial (l : Cycle α) ↔ 2 ≤ l.length := by
  rw [Nontrivial]
  rcases l with (_ | ⟨hd, _ | ⟨hd', tl⟩⟩)
  · 

Proof state:
case nil
α : Type u_1
hl : Nodup []
⊢ (∃ x y, x ≠ y ∧ x ∈ ↑[] ∧ y ∈ ↑[]) ↔ 2 ≤ List.length []

Next tactic:
simp
@[simp]
theorem nontrivial_coe_nodup_iff {l : List α} (hl : l.Nodup) :
    Nontrivial (l : Cycle α) ↔ 2 ≤ l.length := by
  rw [Nontrivial]
  rcases l with (_ | ⟨hd, _ | ⟨hd', tl⟩⟩)
  · simp
  · 

Proof state:
case cons.nil
α : Type u_1
hd : α
hl : Nodup [hd]
⊢ (∃ x y, x ≠ y ∧ x ∈ ↑[hd] ∧ y ∈ ↑[hd]) ↔ 2 ≤ List.length [hd]

Next tactic:
simp
@[simp]
theorem nontrivial_coe_nodup_iff {l : List α} (hl : l.Nodup) :
    Nontrivial (l : Cycle α) ↔ 2 ≤ l.length := by
  rw [Nontrivial]
  rcases l with (_ | ⟨hd, _ | ⟨hd', tl⟩⟩)
  · simp
  · simp
  · 

Proof state:
case cons.cons
α : Type u_1
hd hd' : α
tl : List α
hl : Nodup (hd :: hd' :: tl)
⊢ (∃ x y, x ≠ y ∧ x ∈ ↑(hd :: hd' :: tl) ∧ y ∈ ↑(hd :: hd' :: tl)) ↔ 2 ≤ List.length (hd :: hd' :: tl)

Next tactic:
simp only [mem_cons, exists_prop, mem_coe_iff, List.length, Ne.def, Nat.succ_le_succ_iff,
      zero_le, iff_true_iff]
@[simp]
theorem nontrivial_coe_nodup_iff {l : List α} (hl : l.Nodup) :
    Nontrivial (l : Cycle α) ↔ 2 ≤ l.length := by
  rw [Nontrivial]
  rcases l with (_ | ⟨hd, _ | ⟨hd', tl⟩⟩)
  · simp
  · simp
  · simp only [mem_cons, exists_prop, mem_coe_iff, List.length, Ne.def, Nat.succ_le_succ_iff,
      zero_le, iff_true_iff]
    

Proof state:
case cons.cons
α : Type u_1
hd hd' : α
tl : List α
hl : Nodup (hd :: hd' :: tl)
⊢ ∃ x y, ¬x = y ∧ (x = hd ∨ x = hd' ∨ x ∈ tl) ∧ (y = hd ∨ y = hd' ∨ y ∈ tl)

Next tactic:
refine' ⟨hd, hd', _, by simp⟩
@[simp]
theorem nontrivial_coe_nodup_iff {l : List α} (hl : l.Nodup) :
    Nontrivial (l : Cycle α) ↔ 2 ≤ l.length := by
  rw [Nontrivial]
  rcases l with (_ | ⟨hd, _ | ⟨hd', tl⟩⟩)
  · simp
  · simp
  · simp only [mem_cons, exists_prop, mem_coe_iff, List.length, Ne.def, Nat.succ_le_succ_iff,
      zero_le, iff_true_iff]
    refine' ⟨hd, hd', _, by 

Proof state:
α : Type u_1
hd hd' : α
tl : List α
hl : Nodup (hd :: hd' :: tl)
⊢ (hd = hd ∨ hd = hd' ∨ hd ∈ tl) ∧ (hd' = hd ∨ hd' = hd' ∨ hd' ∈ tl)

Next tactic:
simp
@[simp]
theorem nontrivial_coe_nodup_iff {l : List α} (hl : l.Nodup) :
    Nontrivial (l : Cycle α) ↔ 2 ≤ l.length := by
  rw [Nontrivial]
  rcases l with (_ | ⟨hd, _ | ⟨hd', tl⟩⟩)
  · simp
  · simp
  · simp only [mem_cons, exists_prop, mem_coe_iff, List.length, Ne.def, Nat.succ_le_succ_iff,
      zero_le, iff_true_iff]
    refine' ⟨hd, hd', _, by simp⟩
    

Proof state:
case cons.cons
α : Type u_1
hd hd' : α
tl : List α
hl : Nodup (hd :: hd' :: tl)
⊢ ¬hd = hd'

Next tactic:
simp only [not_or, mem_cons, nodup_cons] at hl
@[simp]
theorem nontrivial_coe_nodup_iff {l : List α} (hl : l.Nodup) :
    Nontrivial (l : Cycle α) ↔ 2 ≤ l.length := by
  rw [Nontrivial]
  rcases l with (_ | ⟨hd, _ | ⟨hd', tl⟩⟩)
  · simp
  · simp
  · simp only [mem_cons, exists_prop, mem_coe_iff, List.length, Ne.def, Nat.succ_le_succ_iff,
      zero_le, iff_true_iff]
    refine' ⟨hd, hd', _, by simp⟩
    simp only [not_or, mem_cons, nodup_cons] at hl
    

Proof state:
case cons.cons
α : Type u_1
hd hd' : α
tl : List α
hl : (¬hd = hd' ∧ hd ∉ tl) ∧ hd' ∉ tl ∧ Nodup tl
⊢ ¬hd = hd'

Next tactic:
exact hl.left.left
@[simp]
theorem nontrivial_reverse_iff {s : Cycle α} : s.reverse.Nontrivial ↔ s.Nontrivial := by
  

Proof state:
α : Type u_1
s : Cycle α
⊢ Nontrivial (reverse s) ↔ Nontrivial s

Next tactic:
simp [Nontrivial]
theorem length_nontrivial {s : Cycle α} (h : Nontrivial s) : 2 ≤ length s := by
  

Proof state:
α : Type u_1
s : Cycle α
h : Nontrivial s
⊢ 2 ≤ length s

Next tactic:
obtain ⟨x, y, hxy, hx, hy⟩ := h
theorem length_nontrivial {s : Cycle α} (h : Nontrivial s) : 2 ≤ length s := by
  obtain ⟨x, y, hxy, hx, hy⟩ := h
  

Proof state:
case intro.intro.intro.intro
α : Type u_1
s : Cycle α
x y : α
hxy : x ≠ y
hx : x ∈ s
hy : y ∈ s
⊢ 2 ≤ length s

Next tactic:
induction' s using Quot.inductionOn with l
theorem length_nontrivial {s : Cycle α} (h : Nontrivial s) : 2 ≤ length s := by
  obtain ⟨x, y, hxy, hx, hy⟩ := h
  induction' s using Quot.inductionOn with l
  

Proof state:
case intro.intro.intro.intro.h
α : Type u_1
x y : α
hxy : x ≠ y
l : List α
hx : x ∈ Quot.mk Setoid.r l
hy : y ∈ Quot.mk Setoid.r l
⊢ 2 ≤ length (Quot.mk Setoid.r l)

Next tactic:
rcases l with (_ | ⟨hd, _ | ⟨hd', tl⟩⟩)
theorem length_nontrivial {s : Cycle α} (h : Nontrivial s) : 2 ≤ length s := by
  obtain ⟨x, y, hxy, hx, hy⟩ := h
  induction' s using Quot.inductionOn with l
  rcases l with (_ | ⟨hd, _ | ⟨hd', tl⟩⟩)
  · 

Proof state:
case intro.intro.intro.intro.h.nil
α : Type u_1
x y : α
hxy : x ≠ y
hx : x ∈ Quot.mk Setoid.r []
hy : y ∈ Quot.mk Setoid.r []
⊢ 2 ≤ length (Quot.mk Setoid.r [])

Next tactic:
simp at hx
theorem length_nontrivial {s : Cycle α} (h : Nontrivial s) : 2 ≤ length s := by
  obtain ⟨x, y, hxy, hx, hy⟩ := h
  induction' s using Quot.inductionOn with l
  rcases l with (_ | ⟨hd, _ | ⟨hd', tl⟩⟩)
  · simp at hx
  · 

Proof state:
case intro.intro.intro.intro.h.cons.nil
α : Type u_1
x y : α
hxy : x ≠ y
hd : α
hx : x ∈ Quot.mk Setoid.r [hd]
hy : y ∈ Quot.mk Setoid.r [hd]
⊢ 2 ≤ length (Quot.mk Setoid.r [hd])

Next tactic:
simp only [mem_coe_iff, mk_eq_coe, mem_singleton] at hx hy
theorem length_nontrivial {s : Cycle α} (h : Nontrivial s) : 2 ≤ length s := by
  obtain ⟨x, y, hxy, hx, hy⟩ := h
  induction' s using Quot.inductionOn with l
  rcases l with (_ | ⟨hd, _ | ⟨hd', tl⟩⟩)
  · simp at hx
  · simp only [mem_coe_iff, mk_eq_coe, mem_singleton] at hx hy
    

Proof state:
case intro.intro.intro.intro.h.cons.nil
α : Type u_1
x y : α
hxy : x ≠ y
hd : α
hx : x = hd
hy : y = hd
⊢ 2 ≤ length (Quot.mk Setoid.r [hd])

Next tactic:
simp [hx, hy] at hxy
theorem length_nontrivial {s : Cycle α} (h : Nontrivial s) : 2 ≤ length s := by
  obtain ⟨x, y, hxy, hx, hy⟩ := h
  induction' s using Quot.inductionOn with l
  rcases l with (_ | ⟨hd, _ | ⟨hd', tl⟩⟩)
  · simp at hx
  · simp only [mem_coe_iff, mk_eq_coe, mem_singleton] at hx hy
    simp [hx, hy] at hxy
  · 

Proof state:
case intro.intro.intro.intro.h.cons.cons
α : Type u_1
x y : α
hxy : x ≠ y
hd hd' : α
tl : List α
hx : x ∈ Quot.mk Setoid.r (hd :: hd' :: tl)
hy : y ∈ Quot.mk Setoid.r (hd :: hd' :: tl)
⊢ 2 ≤ length (Quot.mk Setoid.r (hd :: hd' :: tl))

Next tactic:
simp [Nat.succ_le_succ_iff]
theorem Subsingleton.nodup {s : Cycle α} (h : Subsingleton s) : Nodup s := by
  

Proof state:
α : Type u_1
s : Cycle α
h : Subsingleton s
⊢ Nodup s

Next tactic:
induction' s using Quot.inductionOn with l
theorem Subsingleton.nodup {s : Cycle α} (h : Subsingleton s) : Nodup s := by
  induction' s using Quot.inductionOn with l
  

Proof state:
case h
α : Type u_1
l : List α
h : Subsingleton (Quot.mk Setoid.r l)
⊢ Nodup (Quot.mk Setoid.r l)

Next tactic:
cases' l with hd tl
theorem Subsingleton.nodup {s : Cycle α} (h : Subsingleton s) : Nodup s := by
  induction' s using Quot.inductionOn with l
  cases' l with hd tl
  · 

Proof state:
case h.nil
α : Type u_1
h : Subsingleton (Quot.mk Setoid.r [])
⊢ Nodup (Quot.mk Setoid.r [])

Next tactic:
simp
theorem Subsingleton.nodup {s : Cycle α} (h : Subsingleton s) : Nodup s := by
  induction' s using Quot.inductionOn with l
  cases' l with hd tl
  · simp
  · 

Proof state:
case h.cons
α : Type u_1
hd : α
tl : List α
h : Subsingleton (Quot.mk Setoid.r (hd :: tl))
⊢ Nodup (Quot.mk Setoid.r (hd :: tl))

Next tactic:
have : tl = [] := by simpa [Subsingleton, length_eq_zero, Nat.succ_le_succ_iff] using h
theorem Subsingleton.nodup {s : Cycle α} (h : Subsingleton s) : Nodup s := by
  induction' s using Quot.inductionOn with l
  cases' l with hd tl
  · simp
  · have : tl = [] := by 

Proof state:
α : Type u_1
hd : α
tl : List α
h : Subsingleton (Quot.mk Setoid.r (hd :: tl))
⊢ tl = []

Next tactic:
simpa [Subsingleton, length_eq_zero, Nat.succ_le_succ_iff] using h
theorem Subsingleton.nodup {s : Cycle α} (h : Subsingleton s) : Nodup s := by
  induction' s using Quot.inductionOn with l
  cases' l with hd tl
  · simp
  · have : tl = [] := by simpa [Subsingleton, length_eq_zero, Nat.succ_le_succ_iff] using h
    

Proof state:
case h.cons
α : Type u_1
hd : α
tl : List α
h : Subsingleton (Quot.mk Setoid.r (hd :: tl))
this : tl = []
⊢ Nodup (Quot.mk Setoid.r (hd :: tl))

Next tactic:
simp [this]
theorem Nodup.nontrivial_iff {s : Cycle α} (h : Nodup s) : Nontrivial s ↔ ¬Subsingleton s := by
  

Proof state:
α : Type u_1
s : Cycle α
h : Nodup s
⊢ Nontrivial s ↔ ¬Subsingleton s

Next tactic:
rw [length_subsingleton_iff]
theorem Nodup.nontrivial_iff {s : Cycle α} (h : Nodup s) : Nontrivial s ↔ ¬Subsingleton s := by
  rw [length_subsingleton_iff]
  

Proof state:
α : Type u_1
s : Cycle α
h : Nodup s
⊢ Nontrivial s ↔ ¬length s ≤ 1

Next tactic:
induction s using Quotient.inductionOn'
theorem Nodup.nontrivial_iff {s : Cycle α} (h : Nodup s) : Nontrivial s ↔ ¬Subsingleton s := by
  rw [length_subsingleton_iff]
  induction s using Quotient.inductionOn'
  

Proof state:
case h
α : Type u_1
a✝ : List α
h : Nodup (Quotient.mk'' a✝)
⊢ Nontrivial (Quotient.mk'' a✝) ↔ ¬length (Quotient.mk'' a✝) ≤ 1

Next tactic:
simp only [mk''_eq_coe, nodup_coe_iff] at h
theorem Nodup.nontrivial_iff {s : Cycle α} (h : Nodup s) : Nontrivial s ↔ ¬Subsingleton s := by
  rw [length_subsingleton_iff]
  induction s using Quotient.inductionOn'
  simp only [mk''_eq_coe, nodup_coe_iff] at h
  

Proof state:
case h
α : Type u_1
a✝ : List α
h : List.Nodup a✝
⊢ Nontrivial (Quotient.mk'' a✝) ↔ ¬length (Quotient.mk'' a✝) ≤ 1

Next tactic:
simp [h, Nat.succ_le_iff]
@[simp]
theorem card_toMultiset (s : Cycle α) : Multiset.card s.toMultiset = s.length :=
  Quotient.inductionOn' s (by 

Proof state:
α : Type u_1
s : Cycle α
⊢ ∀ (a : List α), Multiset.card (toMultiset (Quotient.mk'' a)) = length (Quotient.mk'' a)

Next tactic:
simp
@[simp]
theorem toMultiset_eq_nil {s : Cycle α} : s.toMultiset = 0 ↔ s = Cycle.nil :=
  Quotient.inductionOn' s (by 

Proof state:
α : Type u_1
s : Cycle α
⊢ ∀ (a : List α), toMultiset (Quotient.mk'' a) = 0 ↔ Quotient.mk'' a = nil

Next tactic:
simp
@[simp]
theorem map_eq_nil {β : Type*} (f : α → β) (s : Cycle α) : map f s = nil ↔ s = nil :=
  Quotient.inductionOn' s (by 

Proof state:
α : Type u_1
β : Type u_2
f : α → β
s : Cycle α
⊢ ∀ (a : List α), map f (Quotient.mk'' a) = nil ↔ Quotient.mk'' a = nil

Next tactic:
simp
@[simp]
theorem mem_map {β : Type*} {f : α → β} {b : β} {s : Cycle α} :
    b ∈ s.map f ↔ ∃ a, a ∈ s ∧ f a = b :=
  Quotient.inductionOn' s (by 

Proof state:
α : Type u_1
β : Type u_2
f : α → β
b : β
s : Cycle α
⊢ ∀ (a : List α), b ∈ map f (Quotient.mk'' a) ↔ ∃ a_1 ∈ Quotient.mk'' a, f a_1 = b

Next tactic:
simp
/-- The `Multiset` of lists that can make the cycle. -/
def lists (s : Cycle α) : Multiset (List α) :=
  Quotient.liftOn' s (fun l => (l.cyclicPermutations : Multiset (List α))) fun l₁ l₂ h => by
    

Proof state:
α : Type u_1
s : Cycle α
l₁ l₂ : List α
h : Setoid.r l₁ l₂
⊢ (fun l => ↑(cyclicPermutations l)) l₁ = (fun l => ↑(cyclicPermutations l)) l₂

Next tactic:
simpa using h.cyclicPermutations.perm
@[simp]
theorem mem_lists_iff_coe_eq {s : Cycle α} {l : List α} : l ∈ s.lists ↔ (l : Cycle α) = s :=
  Quotient.inductionOn' s fun l => by
    

Proof state:
α : Type u_1
s : Cycle α
l✝ l : List α
⊢ l✝ ∈ lists (Quotient.mk'' l) ↔ ↑l✝ = Quotient.mk'' l

Next tactic:
rw [lists, Quotient.liftOn'_mk'']
@[simp]
theorem mem_lists_iff_coe_eq {s : Cycle α} {l : List α} : l ∈ s.lists ↔ (l : Cycle α) = s :=
  Quotient.inductionOn' s fun l => by
    rw [lists, Quotient.liftOn'_mk'']
    

Proof state:
α : Type u_1
s : Cycle α
l✝ l : List α
⊢ l✝ ∈ ↑(cyclicPermutations l) ↔ ↑l✝ = Quotient.mk'' l

Next tactic:
simp
@[simp]
theorem lists_nil : lists (@nil α) = [([] : List α)] := by
  

Proof state:
α : Type u_1
⊢ lists nil = ↑[[]]

Next tactic:
rw [nil, lists_coe, cyclicPermutations_nil]
/-- Auxiliary decidability algorithm for lists that contain at least two unique elements.
-/
def decidableNontrivialCoe : ∀ l : List α, Decidable (Nontrivial (l : Cycle α))
  | [] => isFalse (by 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
⊢ ¬Nontrivial ↑[]

Next tactic:
simp [Nontrivial]
/-- Auxiliary decidability algorithm for lists that contain at least two unique elements.
-/
def decidableNontrivialCoe : ∀ l : List α, Decidable (Nontrivial (l : Cycle α))
  | [] => isFalse (by simp [Nontrivial])
  | [x] => isFalse (by 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
x : α
⊢ ¬Nontrivial ↑[x]

Next tactic:
simp [Nontrivial]
/-- Auxiliary decidability algorithm for lists that contain at least two unique elements.
-/
def decidableNontrivialCoe : ∀ l : List α, Decidable (Nontrivial (l : Cycle α))
  | [] => isFalse (by simp [Nontrivial])
  | [x] => isFalse (by simp [Nontrivial])
  | x :: y :: l =>
    if h : x = y then
      @decidable_of_iff' _ (Nontrivial (x :: l : Cycle α)) (by 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
x y : α
l : List α
h : x = y
⊢ Nontrivial ↑(x :: y :: l) ↔ Nontrivial ↑(x :: l)

Next tactic:
simp [h, Nontrivial]
/-- Auxiliary decidability algorithm for lists that contain at least two unique elements.
-/
def decidableNontrivialCoe : ∀ l : List α, Decidable (Nontrivial (l : Cycle α))
  | [] => isFalse (by simp [Nontrivial])
  | [x] => isFalse (by simp [Nontrivial])
  | x :: y :: l =>
    if h : x = y then
      @decidable_of_iff' _ (Nontrivial (x :: l : Cycle α)) (by simp [h, Nontrivial])
        (decidableNontrivialCoe (x :: l))
    else isTrue ⟨x, y, h, by 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
x y : α
l : List α
h : ¬x = y
⊢ x ∈ ↑(x :: y :: l)

Next tactic:
simp
/-- Auxiliary decidability algorithm for lists that contain at least two unique elements.
-/
def decidableNontrivialCoe : ∀ l : List α, Decidable (Nontrivial (l : Cycle α))
  | [] => isFalse (by simp [Nontrivial])
  | [x] => isFalse (by simp [Nontrivial])
  | x :: y :: l =>
    if h : x = y then
      @decidable_of_iff' _ (Nontrivial (x :: l : Cycle α)) (by simp [h, Nontrivial])
        (decidableNontrivialCoe (x :: l))
    else isTrue ⟨x, y, h, by simp, by 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
x y : α
l : List α
h : ¬x = y
⊢ y ∈ ↑(x :: y :: l)

Next tactic:
simp
instance fintypeNodupCycle [Fintype α] : Fintype { s : Cycle α // s.Nodup } :=
  Fintype.ofSurjective (fun l : { l : List α // l.Nodup } => ⟨l.val, by 

Proof state:
α : Type u_1
inst✝¹ : DecidableEq α
inst✝ : Fintype α
l : { l // List.Nodup l }
⊢ Nodup ↑↑l

Next tactic:
simpa using l.prop
instance fintypeNodupCycle [Fintype α] : Fintype { s : Cycle α // s.Nodup } :=
  Fintype.ofSurjective (fun l : { l : List α // l.Nodup } => ⟨l.val, by simpa using l.prop⟩)
    fun ⟨s, hs⟩ => by
    

Proof state:
α : Type u_1
inst✝¹ : DecidableEq α
inst✝ : Fintype α
x✝ : { s // Nodup s }
s : Cycle α
hs : Nodup s
⊢ ∃ a, (fun l => { val := ↑↑l, property := (_ : Nodup ↑↑l) }) a = { val := s, property := hs }

Next tactic:
induction' s using Quotient.inductionOn' with s hs
instance fintypeNodupCycle [Fintype α] : Fintype { s : Cycle α // s.Nodup } :=
  Fintype.ofSurjective (fun l : { l : List α // l.Nodup } => ⟨l.val, by simpa using l.prop⟩)
    fun ⟨s, hs⟩ => by
    induction' s using Quotient.inductionOn' with s hs
    

Proof state:
case h
α : Type u_1
inst✝¹ : DecidableEq α
inst✝ : Fintype α
x✝ : { s // Nodup s }
s : List α
hs : Nodup (Quotient.mk'' s)
⊢ ∃ a, (fun l => { val := ↑↑l, property := (_ : Nodup ↑↑l) }) a = { val := Quotient.mk'' s, property := hs }

Next tactic:
exact ⟨⟨s, hs⟩, by simp⟩
instance fintypeNodupCycle [Fintype α] : Fintype { s : Cycle α // s.Nodup } :=
  Fintype.ofSurjective (fun l : { l : List α // l.Nodup } => ⟨l.val, by simpa using l.prop⟩)
    fun ⟨s, hs⟩ => by
    induction' s using Quotient.inductionOn' with s hs
    exact ⟨⟨s, hs⟩, by 

Proof state:
α : Type u_1
inst✝¹ : DecidableEq α
inst✝ : Fintype α
x✝ : { s // Nodup s }
s : List α
hs : Nodup (Quotient.mk'' s)
⊢ (fun l => { val := ↑↑l, property := (_ : Nodup ↑↑l) }) { val := s, property := hs } =
    { val := Quotient.mk'' s, property := hs }

Next tactic:
simp
instance fintypeNodupNontrivialCycle [Fintype α] :
    Fintype { s : Cycle α // s.Nodup ∧ s.Nontrivial } :=
  Fintype.subtype
    (((Finset.univ : Finset { s : Cycle α // s.Nodup }).map (Function.Embedding.subtype _)).filter
      Cycle.Nontrivial)
    (by 

Proof state:
α : Type u_1
inst✝¹ : DecidableEq α
inst✝ : Fintype α
⊢ ∀ (x : Cycle α),
    x ∈ Finset.filter Nontrivial (Finset.map (Function.Embedding.subtype fun s => Nodup s) Finset.univ) ↔
      Nodup x ∧ Nontrivial x

Next tactic:
simp
@[simp]
theorem toFinset_eq_nil {s : Cycle α} : s.toFinset = ∅ ↔ s = Cycle.nil :=
  Quotient.inductionOn' s (by 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
s : Cycle α
⊢ ∀ (a : List α), toFinset (Quotient.mk'' a) = ∅ ↔ Quotient.mk'' a = nil

Next tactic:
simp
/-- Given a `s : Cycle α` such that `Nodup s`, retrieve the next element after `x ∈ s`. -/
nonrec def next : ∀ (s : Cycle α) (_hs : Nodup s) (x : α) (_hx : x ∈ s), α := fun s =>
  Quot.hrecOn (motive := fun (s : Cycle α) => ∀ (_hs : Cycle.Nodup s) (x : α) (_hx : x ∈ s), α) s
  (fun l _hn x hx => next l x hx) fun l₁ l₂ h =>
    Function.hfunext (propext h.nodup_iff) fun h₁ h₂ _he =>
      Function.hfunext rfl fun x y hxy =>
        Function.hfunext (propext (by 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
s : Cycle α
l₁ l₂ : List α
h : Setoid.r l₁ l₂
h₁ : Nodup (Quot.mk Setoid.r l₁)
h₂ : Nodup (Quot.mk Setoid.r l₂)
_he : HEq h₁ h₂
x y : α
hxy : HEq x y
⊢ x ∈ Quot.mk Setoid.r l₁ ↔ y ∈ Quot.mk Setoid.r l₂

Next tactic:
rw [eq_of_heq hxy]
/-- Given a `s : Cycle α` such that `Nodup s`, retrieve the next element after `x ∈ s`. -/
nonrec def next : ∀ (s : Cycle α) (_hs : Nodup s) (x : α) (_hx : x ∈ s), α := fun s =>
  Quot.hrecOn (motive := fun (s : Cycle α) => ∀ (_hs : Cycle.Nodup s) (x : α) (_hx : x ∈ s), α) s
  (fun l _hn x hx => next l x hx) fun l₁ l₂ h =>
    Function.hfunext (propext h.nodup_iff) fun h₁ h₂ _he =>
      Function.hfunext rfl fun x y hxy =>
        Function.hfunext (propext (by rw [eq_of_heq hxy]; 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
s : Cycle α
l₁ l₂ : List α
h : Setoid.r l₁ l₂
h₁ : Nodup (Quot.mk Setoid.r l₁)
h₂ : Nodup (Quot.mk Setoid.r l₂)
_he : HEq h₁ h₂
x y : α
hxy : HEq x y
⊢ y ∈ Quot.mk Setoid.r l₁ ↔ y ∈ Quot.mk Setoid.r l₂

Next tactic:
simpa [eq_of_heq hxy] using h.mem_iff
/-- Given a `s : Cycle α` such that `Nodup s`, retrieve the next element after `x ∈ s`. -/
nonrec def next : ∀ (s : Cycle α) (_hs : Nodup s) (x : α) (_hx : x ∈ s), α := fun s =>
  Quot.hrecOn (motive := fun (s : Cycle α) => ∀ (_hs : Cycle.Nodup s) (x : α) (_hx : x ∈ s), α) s
  (fun l _hn x hx => next l x hx) fun l₁ l₂ h =>
    Function.hfunext (propext h.nodup_iff) fun h₁ h₂ _he =>
      Function.hfunext rfl fun x y hxy =>
        Function.hfunext (propext (by rw [eq_of_heq hxy]; simpa [eq_of_heq hxy] using h.mem_iff))
  fun hm hm' he' => heq_of_eq
    (by 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
s : Cycle α
l₁ l₂ : List α
h : Setoid.r l₁ l₂
h₁ : Nodup (Quot.mk Setoid.r l₁)
h₂ : Nodup (Quot.mk Setoid.r l₂)
_he : HEq h₁ h₂
x y : α
hxy : HEq x y
hm : x ∈ Quot.mk Setoid.r l₁
hm' : y ∈ Quot.mk Setoid.r l₂
he' : HEq hm hm'
⊢ (fun l _hn x hx => List.next l x hx) l₁ h₁ x hm = (fun l _hn x hx => List.next l x hx) l₂ h₂ y hm'

Next tactic:
rw [heq_iff_eq] at hxy
/-- Given a `s : Cycle α` such that `Nodup s`, retrieve the next element after `x ∈ s`. -/
nonrec def next : ∀ (s : Cycle α) (_hs : Nodup s) (x : α) (_hx : x ∈ s), α := fun s =>
  Quot.hrecOn (motive := fun (s : Cycle α) => ∀ (_hs : Cycle.Nodup s) (x : α) (_hx : x ∈ s), α) s
  (fun l _hn x hx => next l x hx) fun l₁ l₂ h =>
    Function.hfunext (propext h.nodup_iff) fun h₁ h₂ _he =>
      Function.hfunext rfl fun x y hxy =>
        Function.hfunext (propext (by rw [eq_of_heq hxy]; simpa [eq_of_heq hxy] using h.mem_iff))
  fun hm hm' he' => heq_of_eq
    (by rw [heq_iff_eq] at hxy; 

Proof state:
α : Type u_1
inst✝ : DecidableEq α
s : Cycle α
l₁ l₂ : List α
h : Setoid.r l₁ l₂
h₁ : Nodup (Quot.mk Setoid.r l₁)
h₂ : Nodup (Quot.mk Setoid.r l₂)
_he : HEq h₁ h₂
x y : α
hxy : x = y
hm : x ∈ Quot.mk Setoid.r l₁
hm' : y ∈ Quot.mk Setoid.r l₂
he' : HEq hm hm'
⊢ (fun l _hn x hx => List.next l x hx) l₁ h₁ x hm = (fun l _hn x hx => List.next l x hx) l₂ h₂ y hm'

Next tactic:
subst x