l3lab/ntp-mathlib huggingface dataset:
theorem mk_mem_sym2 {xs : List α} {a b : α} (ha : a ∈ xs) (hb : b ∈ xs) :
    ⟦(a, b)⟧ ∈ xs.sym2 := by
  induction xs with
  | nil => simp at ha
  | cons x xs ih =>
    rw [mem_sym2_cons_iff]
    rw [mem_cons] at ha hb
    obtain (rfl | ha) := ha <;> obtain (rfl | hb) := hb
    · left; rfl
    · right; left; use b
    · right; left; rw [Sym2.eq_swap]; use a
    · 

Proof state:
case cons.inr.inr
α : Type u_1
a b x : α
xs : List α
ih : a ∈ xs → b ∈ xs → ⟦(a, b)⟧ ∈ List.sym2 xs
ha : a ∈ xs
hb : b ∈ xs
⊢ ⟦(a, b)⟧ = ⟦(x, x)⟧ ∨ (∃ y ∈ xs, ⟦(a, b)⟧ = ⟦(x, y)⟧) ∨ ⟦(a, b)⟧ ∈ List.sym2 xs

Next tactic:
right
theorem mk_mem_sym2 {xs : List α} {a b : α} (ha : a ∈ xs) (hb : b ∈ xs) :
    ⟦(a, b)⟧ ∈ xs.sym2 := by
  induction xs with
  | nil => simp at ha
  | cons x xs ih =>
    rw [mem_sym2_cons_iff]
    rw [mem_cons] at ha hb
    obtain (rfl | ha) := ha <;> obtain (rfl | hb) := hb
    · left; rfl
    · right; left; use b
    · right; left; rw [Sym2.eq_swap]; use a
    · right; 

Proof state:
case cons.inr.inr.h
α : Type u_1
a b x : α
xs : List α
ih : a ∈ xs → b ∈ xs → ⟦(a, b)⟧ ∈ List.sym2 xs
ha : a ∈ xs
hb : b ∈ xs
⊢ (∃ y ∈ xs, ⟦(a, b)⟧ = ⟦(x, y)⟧) ∨ ⟦(a, b)⟧ ∈ List.sym2 xs

Next tactic:
right
theorem mk_mem_sym2 {xs : List α} {a b : α} (ha : a ∈ xs) (hb : b ∈ xs) :
    ⟦(a, b)⟧ ∈ xs.sym2 := by
  induction xs with
  | nil => simp at ha
  | cons x xs ih =>
    rw [mem_sym2_cons_iff]
    rw [mem_cons] at ha hb
    obtain (rfl | ha) := ha <;> obtain (rfl | hb) := hb
    · left; rfl
    · right; left; use b
    · right; left; rw [Sym2.eq_swap]; use a
    · right; right; 

Proof state:
case cons.inr.inr.h.h
α : Type u_1
a b x : α
xs : List α
ih : a ∈ xs → b ∈ xs → ⟦(a, b)⟧ ∈ List.sym2 xs
ha : a ∈ xs
hb : b ∈ xs
⊢ ⟦(a, b)⟧ ∈ List.sym2 xs

Next tactic:
exact ih ha hb
theorem mk_mem_sym2_iff {xs : List α} {a b : α} :
    ⟦(a, b)⟧ ∈ xs.sym2 ↔ a ∈ xs ∧ b ∈ xs := by
  

Proof state:
α : Type u_1
xs : List α
a b : α
⊢ ⟦(a, b)⟧ ∈ List.sym2 xs ↔ a ∈ xs ∧ b ∈ xs

Next tactic:
constructor
theorem mk_mem_sym2_iff {xs : List α} {a b : α} :
    ⟦(a, b)⟧ ∈ xs.sym2 ↔ a ∈ xs ∧ b ∈ xs := by
  constructor
  · 

Proof state:
case mp
α : Type u_1
xs : List α
a b : α
⊢ ⟦(a, b)⟧ ∈ List.sym2 xs → a ∈ xs ∧ b ∈ xs

Next tactic:
intro h
theorem mk_mem_sym2_iff {xs : List α} {a b : α} :
    ⟦(a, b)⟧ ∈ xs.sym2 ↔ a ∈ xs ∧ b ∈ xs := by
  constructor
  · intro h
    

Proof state:
case mp
α : Type u_1
xs : List α
a b : α
h : ⟦(a, b)⟧ ∈ List.sym2 xs
⊢ a ∈ xs ∧ b ∈ xs

Next tactic:
exact ⟨left_mem_of_mk_mem_sym2 h, right_mem_of_mk_mem_sym2 h⟩
theorem mk_mem_sym2_iff {xs : List α} {a b : α} :
    ⟦(a, b)⟧ ∈ xs.sym2 ↔ a ∈ xs ∧ b ∈ xs := by
  constructor
  · intro h
    exact ⟨left_mem_of_mk_mem_sym2 h, right_mem_of_mk_mem_sym2 h⟩
  · 

Proof state:
case mpr
α : Type u_1
xs : List α
a b : α
⊢ a ∈ xs ∧ b ∈ xs → ⟦(a, b)⟧ ∈ List.sym2 xs

Next tactic:
rintro ⟨ha, hb⟩
theorem mk_mem_sym2_iff {xs : List α} {a b : α} :
    ⟦(a, b)⟧ ∈ xs.sym2 ↔ a ∈ xs ∧ b ∈ xs := by
  constructor
  · intro h
    exact ⟨left_mem_of_mk_mem_sym2 h, right_mem_of_mk_mem_sym2 h⟩
  · rintro ⟨ha, hb⟩
    

Proof state:
case mpr.intro
α : Type u_1
xs : List α
a b : α
ha : a ∈ xs
hb : b ∈ xs
⊢ ⟦(a, b)⟧ ∈ List.sym2 xs

Next tactic:
exact mk_mem_sym2 ha hb
theorem mem_sym2_iff {xs : List α} {z : Sym2 α} :
    z ∈ xs.sym2 ↔ ∀ y ∈ z, y ∈ xs := by
  

Proof state:
α : Type u_1
xs : List α
z : Sym2 α
⊢ z ∈ List.sym2 xs ↔ ∀ y ∈ z, y ∈ xs

Next tactic:
refine z.ind (fun a b => ?_)
theorem mem_sym2_iff {xs : List α} {z : Sym2 α} :
    z ∈ xs.sym2 ↔ ∀ y ∈ z, y ∈ xs := by
  refine z.ind (fun a b => ?_)
  

Proof state:
α : Type u_1
xs : List α
z : Sym2 α
a b : α
⊢ ⟦(a, b)⟧ ∈ List.sym2 xs ↔ ∀ y ∈ ⟦(a, b)⟧, y ∈ xs

Next tactic:
simp [mk_mem_sym2_iff]
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  

Proof state:
α : Type u_1
xs : List α
h : Nodup xs
⊢ Nodup (List.sym2 xs)

Next tactic:
induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> simp [left_mem_of_mk_mem_sym2 hz'] at h
    case notmem =>
      intro h'
      simp only [h.1, mem_map, Sym2.eq_iff, true_and, or_self, exists_eq_right] at h'
    case inj =>
      intro a b
      simp only [Sym2.eq_iff, true_and]
      rintro (rfl | ⟨rfl, rfl⟩) <;> rfl
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  

Proof state:
case nil
α : Type u_1
h : Nodup []
⊢ Nodup (List.sym2 [])

Next tactic:
| nil => simp only [List.sym2, nodup_nil]
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => 

Proof state:
case nil
α : Type u_1
h : Nodup []
⊢ Nodup (List.sym2 [])

Next tactic:
simp only [List.sym2, nodup_nil]
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  

Proof state:
case cons
α : Type u_1
x : α
xs : List α
ih : Nodup xs → Nodup (List.sym2 xs)
h : Nodup (x :: xs)
⊢ Nodup (List.sym2 (x :: xs))

Next tactic:
| cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> simp [left_mem_of_mk_mem_sym2 hz'] at h
    case notmem =>
      intro h'
      simp only [h.1, mem_map, Sym2.eq_iff, true_and, or_self, exists_eq_right] at h'
    case inj =>
      intro a b
      simp only [Sym2.eq_iff, true_and]
      rintro (rfl | ⟨rfl, rfl⟩) <;> rfl
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    

Proof state:
case cons
α : Type u_1
x : α
xs : List α
ih : Nodup xs → Nodup (List.sym2 xs)
h : Nodup (x :: xs)
⊢ Nodup (List.sym2 (x :: xs))

Next tactic:
rw [List.sym2]
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    

Proof state:
case cons
α : Type u_1
x : α
xs : List α
ih : Nodup xs → Nodup (List.sym2 xs)
h : Nodup (x :: xs)
⊢ Nodup (map (fun y => ⟦(x, y)⟧) (x :: xs) ++ List.sym2 xs)

Next tactic:
specialize ih h.of_cons
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    

Proof state:
case cons
α : Type u_1
x : α
xs : List α
h : Nodup (x :: xs)
ih : Nodup (List.sym2 xs)
⊢ Nodup (map (fun y => ⟦(x, y)⟧) (x :: xs) ++ List.sym2 xs)

Next tactic:
rw [nodup_cons] at h
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    

Proof state:
case cons
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
⊢ Nodup (map (fun y => ⟦(x, y)⟧) (x :: xs) ++ List.sym2 xs)

Next tactic:
refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    

Proof state:
case notmem
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
⊢ (fun y => ⟦(x, y)⟧) x ∉ map (fun y => ⟦(x, y)⟧) xs
case inj
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
⊢ Function.Injective fun y => ⟦(x, y)⟧
case disj
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
⊢ Disjoint (map (fun y => ⟦(x, y)⟧) (x :: xs)) (List.sym2 xs)

Next tactic:
case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> simp [left_mem_of_mk_mem_sym2 hz'] at h
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    

Proof state:
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
⊢ Disjoint (map (fun y => ⟦(x, y)⟧) (x :: xs)) (List.sym2 xs)

Next tactic:
case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> simp [left_mem_of_mk_mem_sym2 hz'] at h
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      

Proof state:
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
⊢ Disjoint (map (fun y => ⟦(x, y)⟧) (x :: xs)) (List.sym2 xs)

Next tactic:
intro z hz hz'
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      

Proof state:
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
z : Sym2 α
hz : z ∈ map (fun y => ⟦(x, y)⟧) (x :: xs)
hz' : z ∈ List.sym2 xs
⊢ False

Next tactic:
simp only [mem_cons, mem_map] at hz
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      

Proof state:
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
z : Sym2 α
hz' : z ∈ List.sym2 xs
hz : ∃ a, (a = x ∨ a ∈ xs) ∧ ⟦(x, a)⟧ = z
⊢ False

Next tactic:
obtain ⟨_, (rfl | _), rfl⟩ := hz
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> 

Proof state:
case intro.intro.inl
α : Type u_1
xs : List α
ih : Nodup (List.sym2 xs)
w✝ : α
h : w✝ ∉ xs ∧ Nodup xs
hz' : ⟦(w✝, w✝)⟧ ∈ List.sym2 xs
⊢ False

Next tactic:
simp [left_mem_of_mk_mem_sym2 hz'] at h
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> 

Proof state:
case intro.intro.inr
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
w✝ : α
h✝ : w✝ ∈ xs
hz' : ⟦(x, w✝)⟧ ∈ List.sym2 xs
⊢ False

Next tactic:
simp [left_mem_of_mk_mem_sym2 hz'] at h
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> simp [left_mem_of_mk_mem_sym2 hz'] at h
    

Proof state:
case notmem
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
⊢ (fun y => ⟦(x, y)⟧) x ∉ map (fun y => ⟦(x, y)⟧) xs
case inj
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
⊢ Function.Injective fun y => ⟦(x, y)⟧

Next tactic:
case notmem =>
      intro h'
      simp only [h.1, mem_map, Sym2.eq_iff, true_and, or_self, exists_eq_right] at h'
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> simp [left_mem_of_mk_mem_sym2 hz'] at h
    

Proof state:
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
⊢ (fun y => ⟦(x, y)⟧) x ∉ map (fun y => ⟦(x, y)⟧) xs

Next tactic:
case notmem =>
      intro h'
      simp only [h.1, mem_map, Sym2.eq_iff, true_and, or_self, exists_eq_right] at h'
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> simp [left_mem_of_mk_mem_sym2 hz'] at h
    case notmem =>
      

Proof state:
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
⊢ (fun y => ⟦(x, y)⟧) x ∉ map (fun y => ⟦(x, y)⟧) xs

Next tactic:
intro h'
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> simp [left_mem_of_mk_mem_sym2 hz'] at h
    case notmem =>
      intro h'
      

Proof state:
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
h' : (fun y => ⟦(x, y)⟧) x ∈ map (fun y => ⟦(x, y)⟧) xs
⊢ False

Next tactic:
simp only [h.1, mem_map, Sym2.eq_iff, true_and, or_self, exists_eq_right] at h'
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> simp [left_mem_of_mk_mem_sym2 hz'] at h
    case notmem =>
      intro h'
      simp only [h.1, mem_map, Sym2.eq_iff, true_and, or_self, exists_eq_right] at h'
    

Proof state:
case inj
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
⊢ Function.Injective fun y => ⟦(x, y)⟧

Next tactic:
case inj =>
      intro a b
      simp only [Sym2.eq_iff, true_and]
      rintro (rfl | ⟨rfl, rfl⟩) <;> rfl
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> simp [left_mem_of_mk_mem_sym2 hz'] at h
    case notmem =>
      intro h'
      simp only [h.1, mem_map, Sym2.eq_iff, true_and, or_self, exists_eq_right] at h'
    

Proof state:
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
⊢ Function.Injective fun y => ⟦(x, y)⟧

Next tactic:
case inj =>
      intro a b
      simp only [Sym2.eq_iff, true_and]
      rintro (rfl | ⟨rfl, rfl⟩) <;> rfl
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> simp [left_mem_of_mk_mem_sym2 hz'] at h
    case notmem =>
      intro h'
      simp only [h.1, mem_map, Sym2.eq_iff, true_and, or_self, exists_eq_right] at h'
    case inj =>
      

Proof state:
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
⊢ Function.Injective fun y => ⟦(x, y)⟧

Next tactic:
intro a b
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> simp [left_mem_of_mk_mem_sym2 hz'] at h
    case notmem =>
      intro h'
      simp only [h.1, mem_map, Sym2.eq_iff, true_and, or_self, exists_eq_right] at h'
    case inj =>
      intro a b
      

Proof state:
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
a b : α
⊢ (fun y => ⟦(x, y)⟧) a = (fun y => ⟦(x, y)⟧) b → a = b

Next tactic:
simp only [Sym2.eq_iff, true_and]
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> simp [left_mem_of_mk_mem_sym2 hz'] at h
    case notmem =>
      intro h'
      simp only [h.1, mem_map, Sym2.eq_iff, true_and, or_self, exists_eq_right] at h'
    case inj =>
      intro a b
      simp only [Sym2.eq_iff, true_and]
      

Proof state:
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
a b : α
⊢ a = b ∨ x = b ∧ a = x → a = b

Next tactic:
rintro (rfl | ⟨rfl, rfl⟩)
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> simp [left_mem_of_mk_mem_sym2 hz'] at h
    case notmem =>
      intro h'
      simp only [h.1, mem_map, Sym2.eq_iff, true_and, or_self, exists_eq_right] at h'
    case inj =>
      intro a b
      simp only [Sym2.eq_iff, true_and]
      rintro (rfl | ⟨rfl, rfl⟩) <;> 

Proof state:
case inl
α : Type u_1
x : α
xs : List α
h : x ∉ xs ∧ Nodup xs
ih : Nodup (List.sym2 xs)
a : α
⊢ a = a

Next tactic:
rfl
protected theorem Nodup.sym2 {xs : List α} (h : xs.Nodup) : xs.sym2.Nodup := by
  induction xs with
  | nil => simp only [List.sym2, nodup_nil]
  | cons x xs ih =>
    rw [List.sym2]
    specialize ih h.of_cons
    rw [nodup_cons] at h
    refine Nodup.append (Nodup.cons ?notmem (h.2.map ?inj)) ih ?disj
    case disj =>
      intro z hz hz'
      simp only [mem_cons, mem_map] at hz
      obtain ⟨_, (rfl | _), rfl⟩ := hz
        <;> simp [left_mem_of_mk_mem_sym2 hz'] at h
    case notmem =>
      intro h'
      simp only [h.1, mem_map, Sym2.eq_iff, true_and, or_self, exists_eq_right] at h'
    case inj =>
      intro a b
      simp only [Sym2.eq_iff, true_and]
      rintro (rfl | ⟨rfl, rfl⟩) <;> 

Proof state:
case inr.intro
α : Type u_1
xs : List α
ih : Nodup (List.sym2 xs)
a : α
h : a ∉ xs ∧ Nodup xs
⊢ a = a

Next tactic:
rfl
protected theorem Perm.sym2 {xs ys : List α} (h : xs ~ ys) :
    xs.sym2 ~ ys.sym2 := by
  

Proof state:
α : Type u_1
xs ys : List α
h : xs ~ ys
⊢ List.sym2 xs ~ List.sym2 ys

Next tactic:
induction h with
  | nil => rfl
  | cons x h ih =>
    simp only [List.sym2, map_cons, cons_append, perm_cons]
    exact (h.map _).append ih
  | swap x y xs =>
    simp only [List.sym2, map_cons, cons_append]
    conv => enter [1,2,1]; rw [Sym2.eq_swap]
    -- Explicit permutation to speed up simps that follow.
    refine Perm.trans (Perm.swap ..) (Perm.trans (Perm.cons _ ?_) (Perm.swap ..))
    simp only [← Multiset.coe_eq_coe, ← Multiset.cons_coe,
      ← Multiset.coe_add, ← Multiset.singleton_add]
    simp only [add_assoc, add_left_comm]
  | trans _ _ ih1 ih2 => exact ih1.trans ih2
protected theorem Perm.sym2 {xs ys : List α} (h : xs ~ ys) :
    xs.sym2 ~ ys.sym2 := by
  induction h with
  

Proof state:
case nil
α : Type u_1
xs ys : List α
⊢ List.sym2 [] ~ List.sym2 []

Next tactic:
| nil => rfl
protected theorem Perm.sym2 {xs ys : List α} (h : xs ~ ys) :
    xs.sym2 ~ ys.sym2 := by
  induction h with
  | nil => 

Proof state:
case nil
α : Type u_1
xs ys : List α
⊢ List.sym2 [] ~ List.sym2 []

Next tactic:
rfl
protected theorem Perm.sym2 {xs ys : List α} (h : xs ~ ys) :
    xs.sym2 ~ ys.sym2 := by
  induction h with
  | nil => rfl
  

Proof state:
case cons
α : Type u_1
xs ys : List α
x : α
l₁✝ l₂✝ : List α
h : l₁✝ ~ l₂✝
ih : List.sym2 l₁✝ ~ List.sym2 l₂✝
⊢ List.sym2 (x :: l₁✝) ~ List.sym2 (x :: l₂✝)

Next tactic:
| cons x h ih =>
    simp only [List.sym2, map_cons, cons_append, perm_cons]
    exact (h.map _).append ih
protected theorem Perm.sym2 {xs ys : List α} (h : xs ~ ys) :
    xs.sym2 ~ ys.sym2 := by
  induction h with
  | nil => rfl
  | cons x h ih =>
    

Proof state:
case cons
α : Type u_1
xs ys : List α
x : α
l₁✝ l₂✝ : List α
h : l₁✝ ~ l₂✝
ih : List.sym2 l₁✝ ~ List.sym2 l₂✝
⊢ List.sym2 (x :: l₁✝) ~ List.sym2 (x :: l₂✝)

Next tactic:
simp only [List.sym2, map_cons, cons_append, perm_cons]
protected theorem Perm.sym2 {xs ys : List α} (h : xs ~ ys) :
    xs.sym2 ~ ys.sym2 := by
  induction h with
  | nil => rfl
  | cons x h ih =>
    simp only [List.sym2, map_cons, cons_append, perm_cons]
    

Proof state:
case cons
α : Type u_1
xs ys : List α
x : α
l₁✝ l₂✝ : List α
h : l₁✝ ~ l₂✝
ih : List.sym2 l₁✝ ~ List.sym2 l₂✝
⊢ List.map (fun y => ⟦(x, y)⟧) l₁✝ ++ List.sym2 l₁✝ ~ List.map (fun y => ⟦(x, y)⟧) l₂✝ ++ List.sym2 l₂✝

Next tactic:
exact (h.map _).append ih
protected theorem Perm.sym2 {xs ys : List α} (h : xs ~ ys) :
    xs.sym2 ~ ys.sym2 := by
  induction h with
  | nil => rfl
  | cons x h ih =>
    simp only [List.sym2, map_cons, cons_append, perm_cons]
    exact (h.map _).append ih
  

Proof state:
case swap
α : Type u_1
xs✝ ys : List α
x y : α
xs : List α
⊢ List.sym2 (y :: x :: xs) ~ List.sym2 (x :: y :: xs)

Next tactic:
| swap x y xs =>
    simp only [List.sym2, map_cons, cons_append]
    conv => enter [1,2,1]; rw [Sym2.eq_swap]
    -- Explicit permutation to speed up simps that follow.
    refine Perm.trans (Perm.swap ..) (Perm.trans (Perm.cons _ ?_) (Perm.swap ..))
    simp only [← Multiset.coe_eq_coe, ← Multiset.cons_coe,
      ← Multiset.coe_add, ← Multiset.singleton_add]
    simp only [add_assoc, add_left_comm]