l3lab/ntp-mathlib huggingface dataset:
theorem nodupKeys_dedupKeys (l : List (Sigma β)) : NodupKeys (dedupKeys l) := by
  dsimp [dedupKeys]
  generalize hl : nil = l'
  have : NodupKeys l' := by
    rw [← hl]
    

Proof state:
α : Type u
β : α → Type v
l✝ l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
l : List (Sigma β)
l' : List (Sigma β)
hl : [] = l'
⊢ NodupKeys []

Next tactic:
apply nodup_nil
theorem nodupKeys_dedupKeys (l : List (Sigma β)) : NodupKeys (dedupKeys l) := by
  dsimp [dedupKeys]
  generalize hl : nil = l'
  have : NodupKeys l' := by
    rw [← hl]
    apply nodup_nil
  

Proof state:
α : Type u
β : α → Type v
l✝ l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
l : List (Sigma β)
l' : List (Sigma β)
hl : [] = l'
this : NodupKeys l'
⊢ NodupKeys (foldr (fun x => kinsert x.fst x.snd) l' l)

Next tactic:
clear hl
theorem nodupKeys_dedupKeys (l : List (Sigma β)) : NodupKeys (dedupKeys l) := by
  dsimp [dedupKeys]
  generalize hl : nil = l'
  have : NodupKeys l' := by
    rw [← hl]
    apply nodup_nil
  clear hl
  

Proof state:
α : Type u
β : α → Type v
l✝ l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
l : List (Sigma β)
l' : List (Sigma β)
this : NodupKeys l'
⊢ NodupKeys (foldr (fun x => kinsert x.fst x.snd) l' l)

Next tactic:
induction' l with x xs l_ih
theorem nodupKeys_dedupKeys (l : List (Sigma β)) : NodupKeys (dedupKeys l) := by
  dsimp [dedupKeys]
  generalize hl : nil = l'
  have : NodupKeys l' := by
    rw [← hl]
    apply nodup_nil
  clear hl
  induction' l with x xs l_ih
  · 

Proof state:
case nil
α : Type u
β : α → Type v
l l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
l' : List (Sigma β)
this : NodupKeys l'
⊢ NodupKeys (foldr (fun x => kinsert x.fst x.snd) l' [])

Next tactic:
apply this
theorem nodupKeys_dedupKeys (l : List (Sigma β)) : NodupKeys (dedupKeys l) := by
  dsimp [dedupKeys]
  generalize hl : nil = l'
  have : NodupKeys l' := by
    rw [← hl]
    apply nodup_nil
  clear hl
  induction' l with x xs l_ih
  · apply this
  · 

Proof state:
case cons
α : Type u
β : α → Type v
l l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
l' : List (Sigma β)
this : NodupKeys l'
x : Sigma β
xs : List (Sigma β)
l_ih : NodupKeys (foldr (fun x => kinsert x.fst x.snd) l' xs)
⊢ NodupKeys (foldr (fun x => kinsert x.fst x.snd) l' (x :: xs))

Next tactic:
cases x
theorem nodupKeys_dedupKeys (l : List (Sigma β)) : NodupKeys (dedupKeys l) := by
  dsimp [dedupKeys]
  generalize hl : nil = l'
  have : NodupKeys l' := by
    rw [← hl]
    apply nodup_nil
  clear hl
  induction' l with x xs l_ih
  · apply this
  · cases x
    

Proof state:
case cons.mk
α : Type u
β : α → Type v
l l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
l' : List (Sigma β)
this : NodupKeys l'
xs : List (Sigma β)
l_ih : NodupKeys (foldr (fun x => kinsert x.fst x.snd) l' xs)
fst✝ : α
snd✝ : β fst✝
⊢ NodupKeys (foldr (fun x => kinsert x.fst x.snd) l' ({ fst := fst✝, snd := snd✝ } :: xs))

Next tactic:
simp only [foldr_cons, kinsert_def, nodupKeys_cons, ne_eq, not_true]
theorem nodupKeys_dedupKeys (l : List (Sigma β)) : NodupKeys (dedupKeys l) := by
  dsimp [dedupKeys]
  generalize hl : nil = l'
  have : NodupKeys l' := by
    rw [← hl]
    apply nodup_nil
  clear hl
  induction' l with x xs l_ih
  · apply this
  · cases x
    simp only [foldr_cons, kinsert_def, nodupKeys_cons, ne_eq, not_true]
    

Proof state:
case cons.mk
α : Type u
β : α → Type v
l l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
l' : List (Sigma β)
this : NodupKeys l'
xs : List (Sigma β)
l_ih : NodupKeys (foldr (fun x => kinsert x.fst x.snd) l' xs)
fst✝ : α
snd✝ : β fst✝
⊢ fst✝ ∉ keys (kerase fst✝ (foldr (fun x => kinsert x.fst x.snd) l' xs)) ∧
    NodupKeys (kerase fst✝ (foldr (fun x => kinsert x.fst x.snd) l' xs))

Next tactic:
constructor
theorem nodupKeys_dedupKeys (l : List (Sigma β)) : NodupKeys (dedupKeys l) := by
  dsimp [dedupKeys]
  generalize hl : nil = l'
  have : NodupKeys l' := by
    rw [← hl]
    apply nodup_nil
  clear hl
  induction' l with x xs l_ih
  · apply this
  · cases x
    simp only [foldr_cons, kinsert_def, nodupKeys_cons, ne_eq, not_true]
    constructor
    · 

Proof state:
case cons.mk.left
α : Type u
β : α → Type v
l l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
l' : List (Sigma β)
this : NodupKeys l'
xs : List (Sigma β)
l_ih : NodupKeys (foldr (fun x => kinsert x.fst x.snd) l' xs)
fst✝ : α
snd✝ : β fst✝
⊢ fst✝ ∉ keys (kerase fst✝ (foldr (fun x => kinsert x.fst x.snd) l' xs))

Next tactic:
simp [keys_kerase]
theorem nodupKeys_dedupKeys (l : List (Sigma β)) : NodupKeys (dedupKeys l) := by
  dsimp [dedupKeys]
  generalize hl : nil = l'
  have : NodupKeys l' := by
    rw [← hl]
    apply nodup_nil
  clear hl
  induction' l with x xs l_ih
  · apply this
  · cases x
    simp only [foldr_cons, kinsert_def, nodupKeys_cons, ne_eq, not_true]
    constructor
    · simp [keys_kerase]
      

Proof state:
case cons.mk.left
α : Type u
β : α → Type v
l l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
l' : List (Sigma β)
this : NodupKeys l'
xs : List (Sigma β)
l_ih : NodupKeys (foldr (fun x => kinsert x.fst x.snd) l' xs)
fst✝ : α
snd✝ : β fst✝
⊢ fst✝ ∉ List.erase (keys (foldr (fun x => kinsert x.fst x.snd) l' xs)) fst✝

Next tactic:
apply l_ih.not_mem_erase
theorem nodupKeys_dedupKeys (l : List (Sigma β)) : NodupKeys (dedupKeys l) := by
  dsimp [dedupKeys]
  generalize hl : nil = l'
  have : NodupKeys l' := by
    rw [← hl]
    apply nodup_nil
  clear hl
  induction' l with x xs l_ih
  · apply this
  · cases x
    simp only [foldr_cons, kinsert_def, nodupKeys_cons, ne_eq, not_true]
    constructor
    · simp [keys_kerase]
      apply l_ih.not_mem_erase
    · 

Proof state:
case cons.mk.right
α : Type u
β : α → Type v
l l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
l' : List (Sigma β)
this : NodupKeys l'
xs : List (Sigma β)
l_ih : NodupKeys (foldr (fun x => kinsert x.fst x.snd) l' xs)
fst✝ : α
snd✝ : β fst✝
⊢ NodupKeys (kerase fst✝ (foldr (fun x => kinsert x.fst x.snd) l' xs))

Next tactic:
exact l_ih.kerase _
theorem dlookup_dedupKeys (a : α) (l : List (Sigma β)) : dlookup a (dedupKeys l) = dlookup a l := by
  

Proof state:
α : Type u
β : α → Type v
l✝ l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
a : α
l : List (Sigma β)
⊢ dlookup a (dedupKeys l) = dlookup a l

Next tactic:
induction' l with l_hd _ l_ih
theorem dlookup_dedupKeys (a : α) (l : List (Sigma β)) : dlookup a (dedupKeys l) = dlookup a l := by
  induction' l with l_hd _ l_ih; 

Proof state:
case nil
α : Type u
β : α → Type v
l l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
a : α
⊢ dlookup a (dedupKeys []) = dlookup a []
case cons
α : Type u
β : α → Type v
l l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
a : α
l_hd : Sigma β
tail✝ : List (Sigma β)
l_ih : dlookup a (dedupKeys tail✝) = dlookup a tail✝
⊢ dlookup a (dedupKeys (l_hd :: tail✝)) = dlookup a (l_hd :: tail✝)

Next tactic:
rfl
theorem dlookup_dedupKeys (a : α) (l : List (Sigma β)) : dlookup a (dedupKeys l) = dlookup a l := by
  induction' l with l_hd _ l_ih; rfl
  

Proof state:
case cons
α : Type u
β : α → Type v
l l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
a : α
l_hd : Sigma β
tail✝ : List (Sigma β)
l_ih : dlookup a (dedupKeys tail✝) = dlookup a tail✝
⊢ dlookup a (dedupKeys (l_hd :: tail✝)) = dlookup a (l_hd :: tail✝)

Next tactic:
cases' l_hd with a' b
theorem dlookup_dedupKeys (a : α) (l : List (Sigma β)) : dlookup a (dedupKeys l) = dlookup a l := by
  induction' l with l_hd _ l_ih; rfl
  cases' l_hd with a' b
  

Proof state:
case cons.mk
α : Type u
β : α → Type v
l l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
a : α
tail✝ : List (Sigma β)
l_ih : dlookup a (dedupKeys tail✝) = dlookup a tail✝
a' : α
b : β a'
⊢ dlookup a (dedupKeys ({ fst := a', snd := b } :: tail✝)) = dlookup a ({ fst := a', snd := b } :: tail✝)

Next tactic:
by_cases h : a = a'
theorem dlookup_dedupKeys (a : α) (l : List (Sigma β)) : dlookup a (dedupKeys l) = dlookup a l := by
  induction' l with l_hd _ l_ih; rfl
  cases' l_hd with a' b
  by_cases h : a = a'
  · 

Proof state:
case pos
α : Type u
β : α → Type v
l l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
a : α
tail✝ : List (Sigma β)
l_ih : dlookup a (dedupKeys tail✝) = dlookup a tail✝
a' : α
b : β a'
h : a = a'
⊢ dlookup a (dedupKeys ({ fst := a', snd := b } :: tail✝)) = dlookup a ({ fst := a', snd := b } :: tail✝)

Next tactic:
subst a'
theorem dlookup_dedupKeys (a : α) (l : List (Sigma β)) : dlookup a (dedupKeys l) = dlookup a l := by
  induction' l with l_hd _ l_ih; rfl
  cases' l_hd with a' b
  by_cases h : a = a'
  · subst a'
    

Proof state:
case pos
α : Type u
β : α → Type v
l l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
a : α
tail✝ : List (Sigma β)
l_ih : dlookup a (dedupKeys tail✝) = dlookup a tail✝
b : β a
⊢ dlookup a (dedupKeys ({ fst := a, snd := b } :: tail✝)) = dlookup a ({ fst := a, snd := b } :: tail✝)

Next tactic:
rw [dedupKeys_cons, dlookup_kinsert, dlookup_cons_eq]
theorem dlookup_dedupKeys (a : α) (l : List (Sigma β)) : dlookup a (dedupKeys l) = dlookup a l := by
  induction' l with l_hd _ l_ih; rfl
  cases' l_hd with a' b
  by_cases h : a = a'
  · subst a'
    rw [dedupKeys_cons, dlookup_kinsert, dlookup_cons_eq]
  · 

Proof state:
case neg
α : Type u
β : α → Type v
l l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
a : α
tail✝ : List (Sigma β)
l_ih : dlookup a (dedupKeys tail✝) = dlookup a tail✝
a' : α
b : β a'
h : ¬a = a'
⊢ dlookup a (dedupKeys ({ fst := a', snd := b } :: tail✝)) = dlookup a ({ fst := a', snd := b } :: tail✝)

Next tactic:
rw [dedupKeys_cons, dlookup_kinsert_ne h, l_ih, dlookup_cons_ne]
theorem dlookup_dedupKeys (a : α) (l : List (Sigma β)) : dlookup a (dedupKeys l) = dlookup a l := by
  induction' l with l_hd _ l_ih; rfl
  cases' l_hd with a' b
  by_cases h : a = a'
  · subst a'
    rw [dedupKeys_cons, dlookup_kinsert, dlookup_cons_eq]
  · rw [dedupKeys_cons, dlookup_kinsert_ne h, l_ih, dlookup_cons_ne]
    

Proof state:
case neg.a
α : Type u
β : α → Type v
l l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
a : α
tail✝ : List (Sigma β)
l_ih : dlookup a (dedupKeys tail✝) = dlookup a tail✝
a' : α
b : β a'
h : ¬a = a'
⊢ a ≠ { fst := a', snd := b }.fst

Next tactic:
exact h
theorem sizeOf_dedupKeys {α} {β : α → Type*} [DecidableEq α] [SizeOf (Sigma β)]
    (xs : List (Sigma β)) : SizeOf.sizeOf (dedupKeys xs) ≤ SizeOf.sizeOf xs := by
  

Proof state:
α✝ : Type u
β✝ : α✝ → Type v
l l₁ l₂ : List (Sigma β✝)
inst✝² : DecidableEq α✝
α : Type u_2
β : α → Type u_1
inst✝¹ : DecidableEq α
inst✝ : SizeOf (Sigma β)
xs : List (Sigma β)
⊢ sizeOf (dedupKeys xs) ≤ sizeOf xs

Next tactic:
simp only [SizeOf.sizeOf, _sizeOf_1]
theorem sizeOf_dedupKeys {α} {β : α → Type*} [DecidableEq α] [SizeOf (Sigma β)]
    (xs : List (Sigma β)) : SizeOf.sizeOf (dedupKeys xs) ≤ SizeOf.sizeOf xs := by
  simp only [SizeOf.sizeOf, _sizeOf_1]
  

Proof state:
α✝ : Type u
β✝ : α✝ → Type v
l l₁ l₂ : List (Sigma β✝)
inst✝² : DecidableEq α✝
α : Type u_2
β : α → Type u_1
inst✝¹ : DecidableEq α
inst✝ : SizeOf (Sigma β)
xs : List (Sigma β)
⊢ rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) (dedupKeys xs) ≤
    rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) xs

Next tactic:
induction' xs with x xs
theorem sizeOf_dedupKeys {α} {β : α → Type*} [DecidableEq α] [SizeOf (Sigma β)]
    (xs : List (Sigma β)) : SizeOf.sizeOf (dedupKeys xs) ≤ SizeOf.sizeOf xs := by
  simp only [SizeOf.sizeOf, _sizeOf_1]
  induction' xs with x xs
  · 

Proof state:
case nil
α✝ : Type u
β✝ : α✝ → Type v
l l₁ l₂ : List (Sigma β✝)
inst✝² : DecidableEq α✝
α : Type u_2
β : α → Type u_1
inst✝¹ : DecidableEq α
inst✝ : SizeOf (Sigma β)
⊢ rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) (dedupKeys []) ≤
    rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) []

Next tactic:
simp [dedupKeys]
theorem sizeOf_dedupKeys {α} {β : α → Type*} [DecidableEq α] [SizeOf (Sigma β)]
    (xs : List (Sigma β)) : SizeOf.sizeOf (dedupKeys xs) ≤ SizeOf.sizeOf xs := by
  simp only [SizeOf.sizeOf, _sizeOf_1]
  induction' xs with x xs
  · simp [dedupKeys]
  · 

Proof state:
case cons
α✝ : Type u
β✝ : α✝ → Type v
l l₁ l₂ : List (Sigma β✝)
inst✝² : DecidableEq α✝
α : Type u_2
β : α → Type u_1
inst✝¹ : DecidableEq α
inst✝ : SizeOf (Sigma β)
x : Sigma β
xs : List (Sigma β)
tail_ih✝ :
  rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) (dedupKeys xs) ≤
    rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) xs
⊢ rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) (dedupKeys (x :: xs)) ≤
    rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) (x :: xs)

Next tactic:
simp only [dedupKeys_cons, kinsert_def, add_le_add_iff_left, Sigma.eta]
theorem sizeOf_dedupKeys {α} {β : α → Type*} [DecidableEq α] [SizeOf (Sigma β)]
    (xs : List (Sigma β)) : SizeOf.sizeOf (dedupKeys xs) ≤ SizeOf.sizeOf xs := by
  simp only [SizeOf.sizeOf, _sizeOf_1]
  induction' xs with x xs
  · simp [dedupKeys]
  · simp only [dedupKeys_cons, kinsert_def, add_le_add_iff_left, Sigma.eta]
    

Proof state:
case cons
α✝ : Type u
β✝ : α✝ → Type v
l l₁ l₂ : List (Sigma β✝)
inst✝² : DecidableEq α✝
α : Type u_2
β : α → Type u_1
inst✝¹ : DecidableEq α
inst✝ : SizeOf (Sigma β)
x : Sigma β
xs : List (Sigma β)
tail_ih✝ :
  rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) (dedupKeys xs) ≤
    rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) xs
⊢ rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) (kerase x.fst (dedupKeys xs)) ≤
    rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) xs

Next tactic:
trans
theorem sizeOf_dedupKeys {α} {β : α → Type*} [DecidableEq α] [SizeOf (Sigma β)]
    (xs : List (Sigma β)) : SizeOf.sizeOf (dedupKeys xs) ≤ SizeOf.sizeOf xs := by
  simp only [SizeOf.sizeOf, _sizeOf_1]
  induction' xs with x xs
  · simp [dedupKeys]
  · simp only [dedupKeys_cons, kinsert_def, add_le_add_iff_left, Sigma.eta]
    trans
    

Proof state:
α✝ : Type u
β✝ : α✝ → Type v
l l₁ l₂ : List (Sigma β✝)
inst✝² : DecidableEq α✝
α : Type u_2
β : α → Type u_1
inst✝¹ : DecidableEq α
inst✝ : SizeOf (Sigma β)
x : Sigma β
xs : List (Sigma β)
tail_ih✝ :
  rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) (dedupKeys xs) ≤
    rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) xs
⊢ rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) (kerase x.fst (dedupKeys xs)) ≤ ?m.274908
α✝ : Type u
β✝ : α✝ → Type v
l l₁ l₂ : List (Sigma β✝)
inst✝² : DecidableEq α✝
α : Type u_2
β : α → Type u_1
inst✝¹ : DecidableEq α
inst✝ : SizeOf (Sigma β)
x : Sigma β
xs : List (Sigma β)
tail_ih✝ :
  rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) (dedupKeys xs) ≤
    rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) xs
⊢ ?m.274908 ≤ rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) xs
α✝ : Type u
β✝ : α✝ → Type v
l l₁ l₂ : List (Sigma β✝)
inst✝² : DecidableEq α✝
α : Type u_2
β : α → Type u_1
inst✝¹ : DecidableEq α
inst✝ : SizeOf (Sigma β)
x : Sigma β
xs : List (Sigma β)
tail_ih✝ :
  rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) (dedupKeys xs) ≤
    rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) xs
⊢ ℕ

Next tactic:
apply sizeOf_kerase
theorem sizeOf_dedupKeys {α} {β : α → Type*} [DecidableEq α] [SizeOf (Sigma β)]
    (xs : List (Sigma β)) : SizeOf.sizeOf (dedupKeys xs) ≤ SizeOf.sizeOf xs := by
  simp only [SizeOf.sizeOf, _sizeOf_1]
  induction' xs with x xs
  · simp [dedupKeys]
  · simp only [dedupKeys_cons, kinsert_def, add_le_add_iff_left, Sigma.eta]
    trans
    apply sizeOf_kerase
    

Proof state:
α✝ : Type u
β✝ : α✝ → Type v
l l₁ l₂ : List (Sigma β✝)
inst✝² : DecidableEq α✝
α : Type u_2
β : α → Type u_1
inst✝¹ : DecidableEq α
inst✝ : SizeOf (Sigma β)
x : Sigma β
xs : List (Sigma β)
tail_ih✝ :
  rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) (dedupKeys xs) ≤
    rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) xs
⊢ sizeOf (dedupKeys xs) ≤ rec 1 (fun head tail tail_ih => 1 + sizeOf head + tail_ih) xs

Next tactic:
assumption
@[simp]
theorem kunion_nil : ∀ {l : List (Sigma β)}, kunion l [] = l
  | [] => rfl
  | _ :: l => by 

Proof state:
α : Type u
β : α → Type v
l✝ l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
head✝ : Sigma β
l : List (Sigma β)
⊢ kunion (head✝ :: l) [] = head✝ :: l

Next tactic:
rw [kunion, kerase_nil, kunion_nil]
@[simp]
theorem mem_keys_kunion {a} {l₁ l₂ : List (Sigma β)} :
    a ∈ (kunion l₁ l₂).keys ↔ a ∈ l₁.keys ∨ a ∈ l₂.keys := by
  

Proof state:
α : Type u
β : α → Type v
l l₁✝ l₂✝ : List (Sigma β)
inst✝ : DecidableEq α
a : α
l₁ l₂ : List (Sigma β)
⊢ a ∈ keys (kunion l₁ l₂) ↔ a ∈ keys l₁ ∨ a ∈ keys l₂

Next tactic:
induction l₁ generalizing l₂ with
  | nil => simp
  | cons s l₁ ih => by_cases h : a = s.1 <;> [simp [h]; simp [h, ih]]
@[simp]
theorem mem_keys_kunion {a} {l₁ l₂ : List (Sigma β)} :
    a ∈ (kunion l₁ l₂).keys ↔ a ∈ l₁.keys ∨ a ∈ l₂.keys := by
  induction l₁ generalizing l₂ with
  

Proof state:
case nil
α : Type u
β : α → Type v
l l₁ l₂✝ : List (Sigma β)
inst✝ : DecidableEq α
a : α
l₂ : List (Sigma β)
⊢ a ∈ keys (kunion [] l₂) ↔ a ∈ keys [] ∨ a ∈ keys l₂

Next tactic:
| nil => simp
@[simp]
theorem mem_keys_kunion {a} {l₁ l₂ : List (Sigma β)} :
    a ∈ (kunion l₁ l₂).keys ↔ a ∈ l₁.keys ∨ a ∈ l₂.keys := by
  induction l₁ generalizing l₂ with
  | nil => 

Proof state:
case nil
α : Type u
β : α → Type v
l l₁ l₂✝ : List (Sigma β)
inst✝ : DecidableEq α
a : α
l₂ : List (Sigma β)
⊢ a ∈ keys (kunion [] l₂) ↔ a ∈ keys [] ∨ a ∈ keys l₂

Next tactic:
simp
@[simp]
theorem mem_keys_kunion {a} {l₁ l₂ : List (Sigma β)} :
    a ∈ (kunion l₁ l₂).keys ↔ a ∈ l₁.keys ∨ a ∈ l₂.keys := by
  induction l₁ generalizing l₂ with
  | nil => simp
  

Proof state:
case cons
α : Type u
β : α → Type v
l l₁✝ l₂✝ : List (Sigma β)
inst✝ : DecidableEq α
a : α
s : Sigma β
l₁ : List (Sigma β)
ih : ∀ {l₂ : List (Sigma β)}, a ∈ keys (kunion l₁ l₂) ↔ a ∈ keys l₁ ∨ a ∈ keys l₂
l₂ : List (Sigma β)
⊢ a ∈ keys (kunion (s :: l₁) l₂) ↔ a ∈ keys (s :: l₁) ∨ a ∈ keys l₂

Next tactic:
| cons s l₁ ih => by_cases h : a = s.1 <;> [simp [h]; simp [h, ih]]
@[simp]
theorem mem_keys_kunion {a} {l₁ l₂ : List (Sigma β)} :
    a ∈ (kunion l₁ l₂).keys ↔ a ∈ l₁.keys ∨ a ∈ l₂.keys := by
  induction l₁ generalizing l₂ with
  | nil => simp
  | cons s l₁ ih => 

Proof state:
case cons
α : Type u
β : α → Type v
l l₁✝ l₂✝ : List (Sigma β)
inst✝ : DecidableEq α
a : α
s : Sigma β
l₁ : List (Sigma β)
ih : ∀ {l₂ : List (Sigma β)}, a ∈ keys (kunion l₁ l₂) ↔ a ∈ keys l₁ ∨ a ∈ keys l₂
l₂ : List (Sigma β)
⊢ a ∈ keys (kunion (s :: l₁) l₂) ↔ a ∈ keys (s :: l₁) ∨ a ∈ keys l₂

Next tactic:
by_cases h : a = s.1 <;> [simp [h]; simp [h, ih]]
@[simp]
theorem mem_keys_kunion {a} {l₁ l₂ : List (Sigma β)} :
    a ∈ (kunion l₁ l₂).keys ↔ a ∈ l₁.keys ∨ a ∈ l₂.keys := by
  induction l₁ generalizing l₂ with
  | nil => simp
  | cons s l₁ ih => 

Proof state:
case cons
α : Type u
β : α → Type v
l l₁✝ l₂✝ : List (Sigma β)
inst✝ : DecidableEq α
a : α
s : Sigma β
l₁ : List (Sigma β)
ih : ∀ {l₂ : List (Sigma β)}, a ∈ keys (kunion l₁ l₂) ↔ a ∈ keys l₁ ∨ a ∈ keys l₂
l₂ : List (Sigma β)
⊢ a ∈ keys (kunion (s :: l₁) l₂) ↔ a ∈ keys (s :: l₁) ∨ a ∈ keys l₂

Next tactic:
by_cases h : a = s.1
@[simp]
theorem mem_keys_kunion {a} {l₁ l₂ : List (Sigma β)} :
    a ∈ (kunion l₁ l₂).keys ↔ a ∈ l₁.keys ∨ a ∈ l₂.keys := by
  induction l₁ generalizing l₂ with
  | nil => simp
  | cons s l₁ ih => by_cases h : a = s.1 <;> [

Proof state:
case pos
α : Type u
β : α → Type v
l l₁✝ l₂✝ : List (Sigma β)
inst✝ : DecidableEq α
a : α
s : Sigma β
l₁ : List (Sigma β)
ih : ∀ {l₂ : List (Sigma β)}, a ∈ keys (kunion l₁ l₂) ↔ a ∈ keys l₁ ∨ a ∈ keys l₂
l₂ : List (Sigma β)
h : a = s.fst
⊢ a ∈ keys (kunion (s :: l₁) l₂) ↔ a ∈ keys (s :: l₁) ∨ a ∈ keys l₂

Next tactic:
simp [h]
@[simp]
theorem mem_keys_kunion {a} {l₁ l₂ : List (Sigma β)} :
    a ∈ (kunion l₁ l₂).keys ↔ a ∈ l₁.keys ∨ a ∈ l₂.keys := by
  induction l₁ generalizing l₂ with
  | nil => simp
  | cons s l₁ ih => by_cases h : a = s.1 <;> [simp [h]; 

Proof state:
case neg
α : Type u
β : α → Type v
l l₁✝ l₂✝ : List (Sigma β)
inst✝ : DecidableEq α
a : α
s : Sigma β
l₁ : List (Sigma β)
ih : ∀ {l₂ : List (Sigma β)}, a ∈ keys (kunion l₁ l₂) ↔ a ∈ keys l₁ ∨ a ∈ keys l₂
l₂ : List (Sigma β)
h : ¬a = s.fst
⊢ a ∈ keys (kunion (s :: l₁) l₂) ↔ a ∈ keys (s :: l₁) ∨ a ∈ keys l₂

Next tactic:
simp [h, ih]
@[simp]
theorem kunion_kerase {a} :
    ∀ {l₁ l₂ : List (Sigma β)}, kunion (kerase a l₁) (kerase a l₂) = kerase a (kunion l₁ l₂)
  | [], _ => rfl
  | s :: _, l => by 

Proof state:
α : Type u
β : α → Type v
l✝ l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
a : α
s : Sigma β
tail✝ : List (Sigma β)
l : List (Sigma β)
⊢ kunion (kerase a (s :: tail✝)) (kerase a l) = kerase a (kunion (s :: tail✝) l)

Next tactic:
by_cases h : a = s.1
@[simp]
theorem kunion_kerase {a} :
    ∀ {l₁ l₂ : List (Sigma β)}, kunion (kerase a l₁) (kerase a l₂) = kerase a (kunion l₁ l₂)
  | [], _ => rfl
  | s :: _, l => by by_cases h : a = s.1 <;> 

Proof state:
case pos
α : Type u
β : α → Type v
l✝ l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
a : α
s : Sigma β
tail✝ : List (Sigma β)
l : List (Sigma β)
h : a = s.fst
⊢ kunion (kerase a (s :: tail✝)) (kerase a l) = kerase a (kunion (s :: tail✝) l)

Next tactic:
simp [h, kerase_comm a s.1 l, kunion_kerase]
@[simp]
theorem kunion_kerase {a} :
    ∀ {l₁ l₂ : List (Sigma β)}, kunion (kerase a l₁) (kerase a l₂) = kerase a (kunion l₁ l₂)
  | [], _ => rfl
  | s :: _, l => by by_cases h : a = s.1 <;> 

Proof state:
case neg
α : Type u
β : α → Type v
l✝ l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
a : α
s : Sigma β
tail✝ : List (Sigma β)
l : List (Sigma β)
h : ¬a = s.fst
⊢ kunion (kerase a (s :: tail✝)) (kerase a l) = kerase a (kunion (s :: tail✝) l)

Next tactic:
simp [h, kerase_comm a s.1 l, kunion_kerase]
theorem NodupKeys.kunion (nd₁ : l₁.NodupKeys) (nd₂ : l₂.NodupKeys) : (kunion l₁ l₂).NodupKeys := by
  

Proof state:
α : Type u
β : α → Type v
l l₁ l₂ : List (Sigma β)
inst✝ : DecidableEq α
nd₁ : NodupKeys l₁
nd₂ : NodupKeys l₂
⊢ NodupKeys (List.kunion l₁ l₂)

Next tactic:
induction l₁ generalizing l₂ with
  | nil => simp only [nil_kunion, nd₂]
  | cons s l₁ ih =>
    simp? at nd₁ says simp only [nodupKeys_cons] at nd₁
    simp [not_or, nd₁.1, nd₂, ih nd₁.2 (nd₂.kerase s.1)]
theorem NodupKeys.kunion (nd₁ : l₁.NodupKeys) (nd₂ : l₂.NodupKeys) : (kunion l₁ l₂).NodupKeys := by
  induction l₁ generalizing l₂ with
  

Proof state:
case nil
α : Type u
β : α → Type v
l : List (Sigma β)
inst✝ : DecidableEq α
l₂ : List (Sigma β)
nd₁ : NodupKeys []
nd₂ : NodupKeys l₂
⊢ NodupKeys (List.kunion [] l₂)

Next tactic:
| nil => simp only [nil_kunion, nd₂]
theorem NodupKeys.kunion (nd₁ : l₁.NodupKeys) (nd₂ : l₂.NodupKeys) : (kunion l₁ l₂).NodupKeys := by
  induction l₁ generalizing l₂ with
  | nil => 

Proof state:
case nil
α : Type u
β : α → Type v
l : List (Sigma β)
inst✝ : DecidableEq α
l₂ : List (Sigma β)
nd₁ : NodupKeys []
nd₂ : NodupKeys l₂
⊢ NodupKeys (List.kunion [] l₂)

Next tactic:
simp only [nil_kunion, nd₂]
theorem NodupKeys.kunion (nd₁ : l₁.NodupKeys) (nd₂ : l₂.NodupKeys) : (kunion l₁ l₂).NodupKeys := by
  induction l₁ generalizing l₂ with
  | nil => simp only [nil_kunion, nd₂]
  

Proof state:
case cons
α : Type u
β : α → Type v
l : List (Sigma β)
inst✝ : DecidableEq α
s : Sigma β
l₁ : List (Sigma β)
ih : ∀ {l₂ : List (Sigma β)}, NodupKeys l₁ → NodupKeys l₂ → NodupKeys (List.kunion l₁ l₂)
l₂ : List (Sigma β)
nd₁ : NodupKeys (s :: l₁)
nd₂ : NodupKeys l₂
⊢ NodupKeys (List.kunion (s :: l₁) l₂)

Next tactic:
| cons s l₁ ih =>
    simp? at nd₁ says simp only [nodupKeys_cons] at nd₁
    simp [not_or, nd₁.1, nd₂, ih nd₁.2 (nd₂.kerase s.1)]
theorem NodupKeys.kunion (nd₁ : l₁.NodupKeys) (nd₂ : l₂.NodupKeys) : (kunion l₁ l₂).NodupKeys := by
  induction l₁ generalizing l₂ with
  | nil => simp only [nil_kunion, nd₂]
  | cons s l₁ ih =>
    

Proof state:
case cons
α : Type u
β : α → Type v
l : List (Sigma β)
inst✝ : DecidableEq α
s : Sigma β
l₁ : List (Sigma β)
ih : ∀ {l₂ : List (Sigma β)}, NodupKeys l₁ → NodupKeys l₂ → NodupKeys (List.kunion l₁ l₂)
l₂ : List (Sigma β)
nd₁ : NodupKeys (s :: l₁)
nd₂ : NodupKeys l₂
⊢ NodupKeys (List.kunion (s :: l₁) l₂)

Next tactic:
simp? at nd₁ says simp only [nodupKeys_cons] at nd₁