Theorem: Batteries.HashMap.Imp.expand_size
File: .lake/packages/batteries/Batteries/Data/HashMap/WF.lean

tactic: rw [expand, go]
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
⊢ (expand sz buckets).buckets.size = buckets.size
state_after: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
⊢ Nat.sum (List.map (fun x => x.toList.length) buckets.val.data) + (Buckets.mk (buckets.val.size * 2) ⋯).size =
    buckets.size

case hs
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
⊢ ∀ (j : Nat), j < 0 → buckets.val.data[j]?.getD AssocList.nil = AssocList.nil

tactic: rw [Buckets.mk_size]
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
⊢ Nat.sum (List.map (fun x => x.toList.length) buckets.val.data) + (Buckets.mk (buckets.val.size * 2) ⋯).size =
    buckets.size
state_after: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
⊢ Nat.sum (List.map (fun x => x.toList.length) buckets.val.data) + 0 = buckets.size

tactic: simp [Buckets.size]
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
⊢ Nat.sum (List.map (fun x => x.toList.length) buckets.val.data) + 0 = buckets.size
state_after: no goals

tactic: nofun
state_before: case hs
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
⊢ ∀ (j : Nat), j < 0 → buckets.val.data[j]?.getD AssocList.nil = AssocList.nil
state_after: no goals

tactic: unfold expand.go
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
⊢ (expand.go i source target).size = Nat.sum (List.map (fun x => x.toList.length) source.data) + target.size
state_after: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
⊢ (if h : i < source.size then
        let idx := ⟨i, h⟩;
        let es := source.get idx;
        let source := source.set idx AssocList.nil;
        let target := AssocList.foldl reinsertAux target es;
        expand.go (i + 1) source target
      else target).size =
    Nat.sum (List.map (fun x => x.toList.length) source.data) + target.size

tactic: split
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
⊢ (if h : i < source.size then
        let idx := ⟨i, h⟩;
        let es := source.get idx;
        let source := source.set idx AssocList.nil;
        let target := AssocList.foldl reinsertAux target es;
        expand.go (i + 1) source target
      else target).size =
    Nat.sum (List.map (fun x => x.toList.length) source.data) + target.size
state_after: case isTrue
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
h✝ : i < source.size
⊢ (let idx := ⟨i, h✝⟩;
      let es := source.get idx;
      let source := source.set idx AssocList.nil;
      let target := AssocList.foldl reinsertAux target es;
      expand.go (i + 1) source target).size =
    Nat.sum (List.map (fun x => x.toList.length) source.data) + target.size

case isFalse
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
h✝ : ¬i < source.size
⊢ target.size = Nat.sum (List.map (fun x => x.toList.length) source.data) + target.size

tactic: refine (go (i+1) _ _ fun j hj => ?a).trans ?b <;> simp
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
⊢ (let idx := ⟨i, H⟩;
      let es := source.get idx;
      let source := source.set idx AssocList.nil;
      let target := AssocList.foldl reinsertAux target es;
      expand.go (i + 1) source target).size =
    Nat.sum (List.map (fun x => x.toList.length) source.data) + target.size
state_after: case a
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
j : Nat
hj : j < i + 1
⊢ (source.data.set i AssocList.nil)[j]?.getD AssocList.nil = AssocList.nil

case b
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
⊢ Nat.sum (List.map (fun x => x.toList.length) (source.data.set i AssocList.nil)) +
      (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).size =
    Nat.sum (List.map (fun x => x.toList.length) source.data) + target.size

tactic: simp [List.getD_eq_getElem?, List.getElem?_set, Option.map_eq_map]
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
j : Nat
hj : j < i + 1
⊢ (source.data.set i AssocList.nil)[j]?.getD AssocList.nil = AssocList.nil
state_after: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
j : Nat
hj : j < i + 1
⊢ (if i = j then if i < source.size then some AssocList.nil else none else source.data[j]?).getD AssocList.nil =
    AssocList.nil

tactic: split
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
j : Nat
hj : j < i + 1
⊢ (if i = j then if i < source.size then some AssocList.nil else none else source.data[j]?).getD AssocList.nil =
    AssocList.nil
state_after: case isTrue
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
j : Nat
hj : j < i + 1
h✝ : i = j
⊢ (some AssocList.nil).getD AssocList.nil = AssocList.nil

case isFalse
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
j : Nat
hj : j < i + 1
h✝ : ¬i = j
⊢ source.data[j]?.getD AssocList.nil = AssocList.nil

tactic: cases source.data[j]? <;> rfl
state_before: case isTrue
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
j : Nat
hj : j < i + 1
h✝ : i = j
⊢ (some AssocList.nil).getD AssocList.nil = AssocList.nil
state_after: no goals

tactic: next H => exact hs _ (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ hj) (Ne.symm H))
state_before: case isFalse
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
j : Nat
hj : j < i + 1
h✝ : ¬i = j
⊢ source.data[j]?.getD AssocList.nil = AssocList.nil
state_after: no goals

tactic: exact hs _ (Nat.lt_of_le_of_ne (Nat.le_of_lt_succ hj) (Ne.symm H))
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H✝ : i < source.size
j : Nat
hj : j < i + 1
H : ¬i = j
⊢ source.data[j]?.getD AssocList.nil = AssocList.nil
state_after: no goals

tactic: case b =>
refine have ⟨l₁, l₂, h₁, _, eq⟩ := List.exists_of_set' H; eq ▸ ?_
rw [h₁]
simp only [Buckets.size_eq, List.map_append, List.map_cons, AssocList.toList,
  List.length_nil, Nat.sum_append, Nat.sum_cons, Nat.zero_add, Array.data_length]
rw [Nat.add_assoc, Nat.add_assoc, Nat.add_assoc]; congr 1
(conv => rhs; rw [Nat.add_left_comm]); congr 1
rw [← Array.getElem_eq_data_getElem]
have := @reinsertAux_size α β _; simp [Buckets.size] at this
induction source[i].toList generalizing target <;> simp [*, Nat.succ_add]; rfl
state_before: case b
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
⊢ Nat.sum (List.map (fun x => x.toList.length) (source.data.set i AssocList.nil)) +
      (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).size =
    Nat.sum (List.map (fun x => x.toList.length) source.data) + target.size
state_after: no goals

tactic: refine have ⟨l₁, l₂, h₁, _, eq⟩ := List.exists_of_set' H; eq ▸ ?_
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
⊢ Nat.sum (List.map (fun x => x.toList.length) (source.data.set i AssocList.nil)) +
      (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).size =
    Nat.sum (List.map (fun x => x.toList.length) source.data) + target.size
state_after: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum (List.map (fun x => x.toList.length) (l₁ ++ AssocList.nil :: l₂)) +
      (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).size =
    Nat.sum (List.map (fun x => x.toList.length) source.data) + target.size

tactic: rw [h₁]
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum (List.map (fun x => x.toList.length) (l₁ ++ AssocList.nil :: l₂)) +
      (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).size =
    Nat.sum (List.map (fun x => x.toList.length) source.data) + target.size
state_after: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum (List.map (fun x => x.toList.length) (l₁ ++ AssocList.nil :: l₂)) +
      (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).size =
    Nat.sum (List.map (fun x => x.toList.length) (l₁ ++ source.data[i] :: l₂)) + target.size

tactic: simp only [Buckets.size_eq, List.map_append, List.map_cons, AssocList.toList,
  List.length_nil, Nat.sum_append, Nat.sum_cons, Nat.zero_add, Array.data_length]
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum (List.map (fun x => x.toList.length) (l₁ ++ AssocList.nil :: l₂)) +
      (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).size =
    Nat.sum (List.map (fun x => x.toList.length) (l₁ ++ source.data[i] :: l₂)) + target.size
state_after: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum (List.map (fun x => x.toList.length) l₁) + Nat.sum (List.map (fun x => x.toList.length) l₂) +
      Nat.sum
        (List.map (fun x => x.toList.length)
          (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data) =
    Nat.sum (List.map (fun x => x.toList.length) l₁) +
        (source.data[i].toList.length + Nat.sum (List.map (fun x => x.toList.length) l₂)) +
      Nat.sum (List.map (fun x => x.toList.length) target.val.data)

tactic: rw [Nat.add_assoc, Nat.add_assoc, Nat.add_assoc]
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum (List.map (fun x => x.toList.length) l₁) + Nat.sum (List.map (fun x => x.toList.length) l₂) +
      Nat.sum
        (List.map (fun x => x.toList.length)
          (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data) =
    Nat.sum (List.map (fun x => x.toList.length) l₁) +
        (source.data[i].toList.length + Nat.sum (List.map (fun x => x.toList.length) l₂)) +
      Nat.sum (List.map (fun x => x.toList.length) target.val.data)
state_after: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum (List.map (fun x => x.toList.length) l₁) +
      (Nat.sum (List.map (fun x => x.toList.length) l₂) +
        Nat.sum
          (List.map (fun x => x.toList.length)
            (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data)) =
    Nat.sum (List.map (fun x => x.toList.length) l₁) +
      (source.data[i].toList.length +
        (Nat.sum (List.map (fun x => x.toList.length) l₂) +
          Nat.sum (List.map (fun x => x.toList.length) target.val.data)))

tactic: congr 1
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum (List.map (fun x => x.toList.length) l₁) +
      (Nat.sum (List.map (fun x => x.toList.length) l₂) +
        Nat.sum
          (List.map (fun x => x.toList.length)
            (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data)) =
    Nat.sum (List.map (fun x => x.toList.length) l₁) +
      (source.data[i].toList.length +
        (Nat.sum (List.map (fun x => x.toList.length) l₂) +
          Nat.sum (List.map (fun x => x.toList.length) target.val.data)))
state_after: case e_a
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum (List.map (fun x => x.toList.length) l₂) +
      Nat.sum
        (List.map (fun x => x.toList.length)
          (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data) =
    source.data[i].toList.length +
      (Nat.sum (List.map (fun x => x.toList.length) l₂) + Nat.sum (List.map (fun x => x.toList.length) target.val.data))

tactic: (conv => rhs; rw [Nat.add_left_comm])
state_before: case e_a
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum (List.map (fun x => x.toList.length) l₂) +
      Nat.sum
        (List.map (fun x => x.toList.length)
          (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data) =
    source.data[i].toList.length +
      (Nat.sum (List.map (fun x => x.toList.length) l₂) + Nat.sum (List.map (fun x => x.toList.length) target.val.data))
state_after: case e_a
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum (List.map (fun x => x.toList.length) l₂) +
      Nat.sum
        (List.map (fun x => x.toList.length)
          (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data) =
    Nat.sum (List.map (fun x => x.toList.length) l₂) +
      (source.data[i].toList.length + Nat.sum (List.map (fun x => x.toList.length) target.val.data))

tactic: congr 1
state_before: case e_a
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum (List.map (fun x => x.toList.length) l₂) +
      Nat.sum
        (List.map (fun x => x.toList.length)
          (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data) =
    Nat.sum (List.map (fun x => x.toList.length) l₂) +
      (source.data[i].toList.length + Nat.sum (List.map (fun x => x.toList.length) target.val.data))
state_after: case e_a.e_a
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum
      (List.map (fun x => x.toList.length)
        (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data) =
    source.data[i].toList.length + Nat.sum (List.map (fun x => x.toList.length) target.val.data)

tactic: rw [← Array.getElem_eq_data_getElem]
state_before: case e_a.e_a
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum
      (List.map (fun x => x.toList.length)
        (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data) =
    source.data[i].toList.length + Nat.sum (List.map (fun x => x.toList.length) target.val.data)
state_after: case e_a.e_a
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum
      (List.map (fun x => x.toList.length)
        (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data) =
    source[i].toList.length + Nat.sum (List.map (fun x => x.toList.length) target.val.data)

tactic: have := @reinsertAux_size α β _
state_before: case e_a.e_a
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum
      (List.map (fun x => x.toList.length)
        (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data) =
    source[i].toList.length + Nat.sum (List.map (fun x => x.toList.length) target.val.data)
state_after: case e_a.e_a
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
this : ∀ (data : Buckets α β) (a : α) (b : β), (reinsertAux data a b).size = data.size.succ
⊢ Nat.sum
      (List.map (fun x => x.toList.length)
        (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data) =
    source[i].toList.length + Nat.sum (List.map (fun x => x.toList.length) target.val.data)

tactic: simp [Buckets.size] at this
state_before: case e_a.e_a
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
this : ∀ (data : Buckets α β) (a : α) (b : β), (reinsertAux data a b).size = data.size.succ
⊢ Nat.sum
      (List.map (fun x => x.toList.length)
        (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data) =
    source[i].toList.length + Nat.sum (List.map (fun x => x.toList.length) target.val.data)
state_after: case e_a.e_a
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
this :
  ∀ (data : Buckets α β) (a : α) (b : β),
    Nat.sum (List.map (fun x => x.toList.length) (reinsertAux data a b).val.data) =
      Nat.sum (List.map (fun x => x.toList.length) data.val.data) + 1
⊢ Nat.sum
      (List.map (fun x => x.toList.length)
        (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data) =
    source[i].toList.length + Nat.sum (List.map (fun x => x.toList.length) target.val.data)

tactic: induction source[i].toList generalizing target <;> simp [*, Nat.succ_add]
state_before: case e_a.e_a
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
this :
  ∀ (data : Buckets α β) (a : α) (b : β),
    Nat.sum (List.map (fun x => x.toList.length) (reinsertAux data a b).val.data) =
      Nat.sum (List.map (fun x => x.toList.length) data.val.data) + 1
⊢ Nat.sum
      (List.map (fun x => x.toList.length)
        (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data) =
    source[i].toList.length + Nat.sum (List.map (fun x => x.toList.length) target.val.data)
state_after: case e_a.e_a.cons
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
this :
  ∀ (data : Buckets α β) (a : α) (b : β),
    Nat.sum (List.map (fun x => x.toList.length) (reinsertAux data a b).val.data) =
      Nat.sum (List.map (fun x => x.toList.length) data.val.data) + 1
head✝ : α × β
tail✝ : List (α × β)
tail_ih✝ :
  ∀ (target : Buckets α β),
    Nat.sum
        (List.map (fun x => x.toList.length)
          (List.foldl (fun d x => reinsertAux d x.fst x.snd) target tail✝).val.data) =
      tail✝.length + Nat.sum (List.map (fun x => x.toList.length) target.val.data)
target : Buckets α β
⊢ tail✝.length + (Nat.sum (List.map (fun x => x.toList.length) target.val.data) + 1) =
    tail✝.length + Nat.sum (List.map (fun x => x.toList.length) target.val.data) + 1

tactic: rfl
state_before: case e_a.e_a.cons
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
this :
  ∀ (data : Buckets α β) (a : α) (b : β),
    Nat.sum (List.map (fun x => x.toList.length) (reinsertAux data a b).val.data) =
      Nat.sum (List.map (fun x => x.toList.length) data.val.data) + 1
head✝ : α × β
tail✝ : List (α × β)
tail_ih✝ :
  ∀ (target : Buckets α β),
    Nat.sum
        (List.map (fun x => x.toList.length)
          (List.foldl (fun d x => reinsertAux d x.fst x.snd) target tail✝).val.data) =
      tail✝.length + Nat.sum (List.map (fun x => x.toList.length) target.val.data)
target : Buckets α β
⊢ tail✝.length + (Nat.sum (List.map (fun x => x.toList.length) target.val.data) + 1) =
    tail✝.length + Nat.sum (List.map (fun x => x.toList.length) target.val.data) + 1
state_after: no goals

tactic: conv => rhs; rw [Nat.add_left_comm]
state_before: case e_a
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum (List.map (fun x => x.toList.length) l₂) +
      Nat.sum
        (List.map (fun x => x.toList.length)
          (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data) =
    source.data[i].toList.length +
      (Nat.sum (List.map (fun x => x.toList.length) l₂) + Nat.sum (List.map (fun x => x.toList.length) target.val.data))
state_after: case e_a
α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : i < source.size
l₁ l₂ : List (AssocList α β)
h₁ : source.data = l₁ ++ source.data[i] :: l₂
left✝ : l₁.length = i
eq : source.data.set i AssocList.nil = l₁ ++ AssocList.nil :: l₂
⊢ Nat.sum (List.map (fun x => x.toList.length) l₂) +
      Nat.sum
        (List.map (fun x => x.toList.length)
          (List.foldl (fun d x => reinsertAux d x.fst x.snd) target source[i].toList).val.data) =
    Nat.sum (List.map (fun x => x.toList.length) l₂) +
      (source.data[i].toList.length + Nat.sum (List.map (fun x => x.toList.length) target.val.data))

tactic: rw [(_ : Nat.sum _ = 0), Nat.zero_add]
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : ¬i < source.size
⊢ target.size = Nat.sum (List.map (fun x => x.toList.length) source.data) + target.size
state_after: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : ¬i < source.size
⊢ Nat.sum (List.map (fun x => x.toList.length) source.data) = 0

tactic: rw [← (_ : source.data.map (fun _ => .nil) = source.data)]
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : ¬i < source.size
⊢ Nat.sum (List.map (fun x => x.toList.length) source.data) = 0
state_after: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : ¬i < source.size
⊢ Nat.sum (List.map (fun x => x.toList.length) (List.map (fun x => AssocList.nil) source.data)) = 0

α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : ¬i < source.size
⊢ List.map (fun x => AssocList.nil) source.data = source.data

tactic: refine List.ext_getElem (by simp) fun j h₁ h₂ => ?_
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : ¬i < source.size
⊢ List.map (fun x => AssocList.nil) source.data = source.data
state_after: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : ¬i < source.size
j : Nat
h₁ : j < (List.map (fun x => AssocList.nil) source.data).length
h₂ : j < source.data.length
⊢ (List.map (fun x => AssocList.nil) source.data)[j] = source.data[j]

tactic: simp only [List.getElem_map, Array.data_length]
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : ¬i < source.size
j : Nat
h₁ : j < (List.map (fun x => AssocList.nil) source.data).length
h₂ : j < source.data.length
⊢ (List.map (fun x => AssocList.nil) source.data)[j] = source.data[j]
state_after: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : ¬i < source.size
j : Nat
h₁ : j < (List.map (fun x => AssocList.nil) source.data).length
h₂ : j < source.data.length
⊢ AssocList.nil = source.data[j]

tactic: have := (hs j (Nat.lt_of_lt_of_le h₂ (Nat.not_lt.1 H))).symm
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : ¬i < source.size
j : Nat
h₁ : j < (List.map (fun x => AssocList.nil) source.data).length
h₂ : j < source.data.length
⊢ AssocList.nil = source.data[j]
state_after: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : ¬i < source.size
j : Nat
h₁ : j < (List.map (fun x => AssocList.nil) source.data).length
h₂ : j < source.data.length
this : AssocList.nil = source.data[j]?.getD AssocList.nil
⊢ AssocList.nil = source.data[j]

tactic: rwa [List.getElem?_eq_getElem] at this
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : ¬i < source.size
j : Nat
h₁ : j < (List.map (fun x => AssocList.nil) source.data).length
h₂ : j < source.data.length
this : AssocList.nil = source.data[j]?.getD AssocList.nil
⊢ AssocList.nil = source.data[j]
state_after: no goals

tactic: simp only [List.map_map]
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : ¬i < source.size
⊢ Nat.sum (List.map (fun x => x.toList.length) (List.map (fun x => AssocList.nil) source.data)) = 0
state_after: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : ¬i < source.size
⊢ Nat.sum (List.map ((fun x => x.toList.length) ∘ fun x => AssocList.nil) source.data) = 0

tactic: induction source.data <;> simp [*]
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : ¬i < source.size
⊢ Nat.sum (List.map ((fun x => x.toList.length) ∘ fun x => AssocList.nil) source.data) = 0
state_after: no goals

tactic: simp
state_before: α : Type u_1
β : Type u_2
sz : Nat
inst✝ : Hashable α
buckets : Buckets α β
i : Nat
source : Array (AssocList α β)
target : Buckets α β
hs : ∀ (j : Nat), j < i → source.data[j]?.getD AssocList.nil = AssocList.nil
H : ¬i < source.size
⊢ (List.map (fun x => AssocList.nil) source.data).length = source.data.length
state_after: no goals