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

tactic: have H1 (l n acc) : filterMap.go f acc l n =
    (((g₁ l).reverse ++ acc.toList).toAssocList, ⟨n.1 + (g₁ l).length⟩) := by
  induction l generalizing n acc with simp only [filterMap.go, AssocList.toList,
    List.filterMap_nil, List.reverse_nil, List.nil_append, AssocList.toList_toAssocList,
    List.length_nil, Nat.add_zero, List.filterMap_cons, g₁, *]
  | cons a b l => match f a b with
    | none => rfl
    | some c =>
      simp only [Option.map_some', List.reverse_cons, List.append_assoc, List.singleton_append,
        List.length_cons, Nat.succ_eq_add_one, Prod.mk.injEq, true_and]
      rw [Nat.add_right_comm]
      rfl
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
⊢ (Imp.filterMap f m).WF
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
⊢ (Imp.filterMap f m).WF

tactic: let g l := (g₁ l).reverse.toAssocList
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
⊢ (Imp.filterMap f m).WF
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
⊢ (Imp.filterMap f m).WF

tactic: let M := StateT (ULift Nat) Id
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
⊢ (Imp.filterMap f m).WF
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type ?u.73056 → Type ?u.73056 := StateT (ULift Nat) Id
⊢ (Imp.filterMap f m).WF

tactic: suffices ∀ bk sz (h : 0 < bk.length),
  m.buckets.val.mapM (m := M) (filterMap.go f .nil) ⟨0⟩ = (⟨bk⟩, ⟨sz⟩) →
  WF ⟨sz, ⟨bk⟩, h⟩ from this _ _ _ rfl
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
⊢ (Imp.filterMap f m).WF
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
⊢ ∀ (bk : List (AssocList α γ)) (sz : Nat) (h : 0 < bk.length),
    Array.mapM (filterMap.go f AssocList.nil) m.buckets.val { down := 0 } = ({ data := bk }, { down := sz }) →
      { size := sz, buckets := ⟨{ data := bk }, h⟩ }.WF

tactic: simp only [Array.mapM_eq_mapM_data, bind, StateT.bind, H2, List.map_map, Nat.zero_add, g]
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
⊢ ∀ (bk : List (AssocList α γ)) (sz : Nat) (h : 0 < bk.length),
    Array.mapM (filterMap.go f AssocList.nil) m.buckets.val { down := 0 } = ({ data := bk }, { down := sz }) →
      { size := sz, buckets := ⟨{ data := bk }, h⟩ }.WF
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
⊢ ∀ (bk : List (AssocList α γ)) (sz : Nat) (h : 0 < bk.length),
    pure { data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }
          {
            down :=
              Nat.sum
                (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data) } =
        ({ data := bk }, { down := sz }) →
      { size := sz, buckets := ⟨{ data := bk }, h⟩ }.WF

tactic: intro bk sz h e'
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
⊢ ∀ (bk : List (AssocList α γ)) (sz : Nat) (h : 0 < bk.length),
    pure { data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }
          {
            down :=
              Nat.sum
                (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data) } =
        ({ data := bk }, { down := sz }) →
      { size := sz, buckets := ⟨{ data := bk }, h⟩ }.WF
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
bk : List (AssocList α γ)
sz : Nat
h : 0 < bk.length
e' :
  pure { data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }
      {
        down :=
          Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data) } =
    ({ data := bk }, { down := sz })
⊢ { size := sz, buckets := ⟨{ data := bk }, h⟩ }.WF

tactic: cases e'
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
bk : List (AssocList α γ)
sz : Nat
h : 0 < bk.length
e' :
  pure { data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }
      {
        down :=
          Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data) } =
    ({ data := bk }, { down := sz })
⊢ { size := sz, buckets := ⟨{ data := bk }, h⟩ }.WF
state_after: case refl
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
⊢ { size := Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
      buckets := ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }, h⟩ }.WF

tactic: refine .mk (by simp [Buckets.size]) ⟨?_, fun i h => ?_⟩
state_before: case refl
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
⊢ { size := Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
      buckets := ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }, h⟩ }.WF
state_after: case refl.refine_1
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
⊢ ∀ [inst : LawfulHashable α] [inst : PartialEquivBEq α] (bucket : AssocList α γ),
    bucket ∈
        {
                size :=
                  Nat.sum
                    (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
                buckets :=
                  ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data },
                    h⟩ }.buckets.val.data →
      List.Pairwise (fun a b => ¬(a.fst == b.fst) = true) bucket.toList

case refl.refine_2
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h✝ : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
i : Nat
h :
  i <
    { size := Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
            buckets :=
              ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }, h✝⟩ }.buckets.val.size
⊢ AssocList.All
    (fun k x =>
      ((hash k).toUSize %
            {
                    size :=
                      Nat.sum
                        (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList)
                          m.buckets.val.data),
                    buckets :=
                      ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data },
                        h✝⟩ }.buckets.val.size).toNat =
        i)
    { size := Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
            buckets :=
              ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }, h✝⟩ }.buckets.val[i]

tactic: induction l generalizing n acc with simp only [filterMap.go, AssocList.toList,
  List.filterMap_nil, List.reverse_nil, List.nil_append, AssocList.toList_toAssocList,
  List.length_nil, Nat.add_zero, List.filterMap_cons, g₁, *]
| cons a b l => match f a b with
  | none => rfl
  | some c =>
    simp only [Option.map_some', List.reverse_cons, List.append_assoc, List.singleton_append,
      List.length_cons, Nat.succ_eq_add_one, Prod.mk.injEq, true_and]
    rw [Nat.add_right_comm]
    rfl
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
l : AssocList α β
n : ULift Nat
acc : AssocList α γ
⊢ filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
state_after: no goals

tactic: match f a b with
| none => rfl
| some c =>
simp only [Option.map_some', List.reverse_cons, List.append_assoc, List.singleton_append,
List.length_cons, Nat.succ_eq_add_one, Prod.mk.injEq, true_and]
rw [Nat.add_right_comm]
rfl
state_before: case cons
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
a : α
b : β
l : AssocList α β
tail_ih✝ :
  ∀ (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
n : ULift Nat
acc : AssocList α γ
⊢ (match f a b with
    | none =>
      (((List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).reverse ++
            acc.toList).toAssocList,
        {
          down :=
            n.down + (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length })
    | some c =>
      (((List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).reverse ++
            (a, c) :: acc.toList).toAssocList,
        {
          down :=
            n.down + 1 +
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length })) =
    (((match Option.map (fun x => (a, x)) (f a b) with
            | none => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
            | some b =>
              b :: List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).reverse ++
          acc.toList).toAssocList,
      {
        down :=
          n.down +
            (match Option.map (fun x => (a, x)) (f a b) with
              | none => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
              | some b =>
                b :: List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length })
state_after: no goals

tactic: rfl
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
a : α
b : β
l : AssocList α β
tail_ih✝ :
  ∀ (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
n : ULift Nat
acc : AssocList α γ
⊢ (match none with
    | none =>
      (((List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).reverse ++
            acc.toList).toAssocList,
        {
          down :=
            n.down + (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length })
    | some c =>
      (((List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).reverse ++
            (a, c) :: acc.toList).toAssocList,
        {
          down :=
            n.down + 1 +
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length })) =
    (((match Option.map (fun x => (a, x)) none with
            | none => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
            | some b =>
              b :: List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).reverse ++
          acc.toList).toAssocList,
      {
        down :=
          n.down +
            (match Option.map (fun x => (a, x)) none with
              | none => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
              | some b =>
                b :: List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length })
state_after: no goals

tactic: simp only [Option.map_some', List.reverse_cons, List.append_assoc, List.singleton_append,
  List.length_cons, Nat.succ_eq_add_one, Prod.mk.injEq, true_and]
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
a : α
b : β
l : AssocList α β
tail_ih✝ :
  ∀ (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
n : ULift Nat
acc : AssocList α γ
c : γ
⊢ (match some c with
    | none =>
      (((List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).reverse ++
            acc.toList).toAssocList,
        {
          down :=
            n.down + (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length })
    | some c =>
      (((List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).reverse ++
            (a, c) :: acc.toList).toAssocList,
        {
          down :=
            n.down + 1 +
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length })) =
    (((match Option.map (fun x => (a, x)) (some c) with
            | none => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
            | some b =>
              b :: List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).reverse ++
          acc.toList).toAssocList,
      {
        down :=
          n.down +
            (match Option.map (fun x => (a, x)) (some c) with
              | none => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
              | some b =>
                b :: List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length })
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
a : α
b : β
l : AssocList α β
tail_ih✝ :
  ∀ (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
n : ULift Nat
acc : AssocList α γ
c : γ
⊢ {
      down :=
        n.down + 1 +
          (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length } =
    {
      down :=
        n.down +
          ((List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length + 1) }

tactic: rw [Nat.add_right_comm]
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
a : α
b : β
l : AssocList α β
tail_ih✝ :
  ∀ (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
n : ULift Nat
acc : AssocList α γ
c : γ
⊢ {
      down :=
        n.down + 1 +
          (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length } =
    {
      down :=
        n.down +
          ((List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length + 1) }
state_after: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
a : α
b : β
l : AssocList α β
tail_ih✝ :
  ∀ (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
n : ULift Nat
acc : AssocList α γ
c : γ
⊢ {
      down :=
        n.down + (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length +
          1 } =
    {
      down :=
        n.down +
          ((List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length + 1) }

tactic: rfl
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
a : α
b : β
l : AssocList α β
tail_ih✝ :
  ∀ (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
n : ULift Nat
acc : AssocList α γ
c : γ
⊢ {
      down :=
        n.down + (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length +
          1 } =
    {
      down :=
        n.down +
          ((List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList).length + 1) }
state_after: no goals

tactic: induction l generalizing n with
| nil => rfl
| cons l L IH => simp [bind, StateT.bind, IH, H1, Nat.add_assoc, g]; rfl
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
l : List (AssocList α β)
n : ULift Nat
⊢ List.mapM (filterMap.go f AssocList.nil) l n =
    (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
state_after: no goals

tactic: rfl
state_before: case nil
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
n : ULift Nat
⊢ List.mapM (filterMap.go f AssocList.nil) [] n =
    (List.map g [], { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g [])) })
state_after: no goals

tactic: simp [bind, StateT.bind, IH, H1, Nat.add_assoc, g]
state_before: case cons
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
l : AssocList α β
L : List (AssocList α β)
IH :
  ∀ (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) L n =
      (List.map g L, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g L)) })
n : ULift Nat
⊢ List.mapM (filterMap.go f AssocList.nil) (l :: L) n =
    (List.map g (l :: L), { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g (l :: L))) })
state_after: case cons
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
l : AssocList α β
L : List (AssocList α β)
IH :
  ∀ (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) L n =
      (List.map g L, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g L)) })
n : ULift Nat
⊢ pure ((g₁ l).reverse.toAssocList :: List.map (fun l => (g₁ l).reverse.toAssocList) L)
      {
        down :=
          n.down +
            ((g₁ l).length +
              Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) L)) } =
    ((g₁ l).reverse.toAssocList :: List.map (fun l => (g₁ l).reverse.toAssocList) L,
      {
        down :=
          n.down +
            ((g₁ l).length + Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) L)) })

tactic: rfl
state_before: case cons
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
l : AssocList α β
L : List (AssocList α β)
IH :
  ∀ (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) L n =
      (List.map g L, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g L)) })
n : ULift Nat
⊢ pure ((g₁ l).reverse.toAssocList :: List.map (fun l => (g₁ l).reverse.toAssocList) L)
      {
        down :=
          n.down +
            ((g₁ l).length +
              Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) L)) } =
    ((g₁ l).reverse.toAssocList :: List.map (fun l => (g₁ l).reverse.toAssocList) L,
      {
        down :=
          n.down +
            ((g₁ l).length + Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) L)) })
state_after: no goals

tactic: induction l with
| nil => exact .slnil
| cons a l ih =>
  simp only [List.filterMap_cons, List.map_cons]; exact match f a.1 a.2 with
  | none => .cons _ ih
  | some b => .cons₂ _ ih
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
l : List (α × β)
⊢ (List.map (fun a => a.fst)
        (List.filterMap
          (fun x =>
            match x with
            | (a, b) => Option.map (fun x => (a, x)) (f a b))
          l)).Sublist
    (List.map (fun x => x.fst) l)
state_after: no goals

tactic: exact .slnil
state_before: case nil
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
⊢ (List.map (fun a => a.fst)
        (List.filterMap
          (fun x =>
            match x with
            | (a, b) => Option.map (fun x => (a, x)) (f a b))
          [])).Sublist
    (List.map (fun x => x.fst) [])
state_after: no goals

tactic: simp only [List.filterMap_cons, List.map_cons]
state_before: case cons
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
a : α × β
l : List (α × β)
ih :
  (List.map (fun a => a.fst)
        (List.filterMap
          (fun x =>
            match x with
            | (a, b) => Option.map (fun x => (a, x)) (f a b))
          l)).Sublist
    (List.map (fun x => x.fst) l)
⊢ (List.map (fun a => a.fst)
        (List.filterMap
          (fun x =>
            match x with
            | (a, b) => Option.map (fun x => (a, x)) (f a b))
          (a :: l))).Sublist
    (List.map (fun x => x.fst) (a :: l))
state_after: case cons
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
a : α × β
l : List (α × β)
ih :
  (List.map (fun a => a.fst)
        (List.filterMap
          (fun x =>
            match x with
            | (a, b) => Option.map (fun x => (a, x)) (f a b))
          l)).Sublist
    (List.map (fun x => x.fst) l)
⊢ (List.map (fun a => a.fst)
        (match Option.map (fun x => (a.fst, x)) (f a.fst a.snd) with
        | none => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l
        | some b => b :: List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l)).Sublist
    (a.fst :: List.map (fun x => x.fst) l)

tactic: exact match f a.1 a.2 with
| none => .cons _ ih
| some b => .cons₂ _ ih
state_before: case cons
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
a : α × β
l : List (α × β)
ih :
  (List.map (fun a => a.fst)
        (List.filterMap
          (fun x =>
            match x with
            | (a, b) => Option.map (fun x => (a, x)) (f a b))
          l)).Sublist
    (List.map (fun x => x.fst) l)
⊢ (List.map (fun a => a.fst)
        (match Option.map (fun x => (a.fst, x)) (f a.fst a.snd) with
        | none => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l
        | some b => b :: List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l)).Sublist
    (a.fst :: List.map (fun x => x.fst) l)
state_after: no goals

tactic: simp [Buckets.size]
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
⊢ { size := Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
        buckets := ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }, h⟩ }.size =
    { size := Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
          buckets := ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }, h⟩ }.buckets.size
state_after: no goals

tactic: simp only [List.forall_mem_map_iff, List.toList_toAssocList]
state_before: case refl.refine_1
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
⊢ ∀ [inst : LawfulHashable α] [inst : PartialEquivBEq α] (bucket : AssocList α γ),
    bucket ∈
        {
                size :=
                  Nat.sum
                    (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
                buckets :=
                  ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data },
                    h⟩ }.buckets.val.data →
      List.Pairwise (fun a b => ¬(a.fst == b.fst) = true) bucket.toList
state_after: case refl.refine_1
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
⊢ ∀ [inst : LawfulHashable α] [inst : PartialEquivBEq α] (j : AssocList α β),
    j ∈ m.buckets.val.data → List.Pairwise (fun a b => ¬(a.fst == b.fst) = true) (g₁ j).reverse

tactic: refine fun l h => (List.pairwise_reverse.2 ?_).imp (mt PartialEquivBEq.symm)
state_before: case refl.refine_1
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
⊢ ∀ [inst : LawfulHashable α] [inst : PartialEquivBEq α] (j : AssocList α β),
    j ∈ m.buckets.val.data → List.Pairwise (fun a b => ¬(a.fst == b.fst) = true) (g₁ j).reverse
state_after: case refl.refine_1
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝³ : BEq α
inst✝² : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h✝ : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
inst✝¹ : LawfulHashable α
inst✝ : PartialEquivBEq α
l : AssocList α β
h : l ∈ m.buckets.val.data
⊢ List.Pairwise (fun a b => ¬(a.fst == b.fst) = true) (g₁ l)

tactic: have := H.out.2.1 _ h
state_before: case refl.refine_1
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝³ : BEq α
inst✝² : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h✝ : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
inst✝¹ : LawfulHashable α
inst✝ : PartialEquivBEq α
l : AssocList α β
h : l ∈ m.buckets.val.data
⊢ List.Pairwise (fun a b => ¬(a.fst == b.fst) = true) (g₁ l)
state_after: case refl.refine_1
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝³ : BEq α
inst✝² : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h✝ : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
inst✝¹ : LawfulHashable α
inst✝ : PartialEquivBEq α
l : AssocList α β
h : l ∈ m.buckets.val.data
this : List.Pairwise (fun a b => ¬(a.fst == b.fst) = true) l.toList
⊢ List.Pairwise (fun a b => ¬(a.fst == b.fst) = true) (g₁ l)

tactic: exact this.sublist (H3 l.toList)
state_before: case refl.refine_1
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝³ : BEq α
inst✝² : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h✝ : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
inst✝¹ : LawfulHashable α
inst✝ : PartialEquivBEq α
l : AssocList α β
h : l ∈ m.buckets.val.data
this : List.Pairwise (fun x x_1 => ¬(x == x_1) = true) (List.map Prod.fst l.toList)
⊢ List.Pairwise (fun x x_1 => ¬(x == x_1) = true) (List.map Prod.fst (g₁ l))
state_after: no goals

tactic: simp only [Array.size_mk, List.length_map, Array.data_length, Array.getElem_eq_data_getElem,
  List.getElem_map] at h ⊢
state_before: case refl.refine_2
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h✝ : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
i : Nat
h :
  i <
    { size := Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
            buckets :=
              ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }, h✝⟩ }.buckets.val.size
⊢ AssocList.All
    (fun k x =>
      ((hash k).toUSize %
            {
                    size :=
                      Nat.sum
                        (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList)
                          m.buckets.val.data),
                    buckets :=
                      ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data },
                        h✝⟩ }.buckets.val.size).toNat =
        i)
    { size := Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
            buckets :=
              ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }, h✝⟩ }.buckets.val[i]
state_after: case refl.refine_2
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h✝¹ : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
i : Nat
h✝ :
  i <
    { size := Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
            buckets :=
              ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }, h✝¹⟩ }.buckets.val.size
h : i < m.buckets.val.size
⊢ AssocList.All (fun k x => ((hash k).toUSize % m.buckets.val.size).toNat = i)
    (g₁ m.buckets.val.data[i]).reverse.toAssocList

tactic: have := H.out.2.2 _ h
state_before: case refl.refine_2
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h✝¹ : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
i : Nat
h✝ :
  i <
    { size := Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
            buckets :=
              ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }, h✝¹⟩ }.buckets.val.size
h : i < m.buckets.val.size
⊢ AssocList.All (fun k x => ((hash k).toUSize % m.buckets.val.size).toNat = i)
    (g₁ m.buckets.val.data[i]).reverse.toAssocList
state_after: case refl.refine_2
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h✝¹ : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
i : Nat
h✝ :
  i <
    { size := Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
            buckets :=
              ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }, h✝¹⟩ }.buckets.val.size
h : i < m.buckets.val.size
this : AssocList.All (fun k x => ((hash k).toUSize % m.buckets.val.size).toNat = i) m.buckets.val[i]
⊢ AssocList.All (fun k x => ((hash k).toUSize % m.buckets.val.size).toNat = i)
    (g₁ m.buckets.val.data[i]).reverse.toAssocList

tactic: simp only [AssocList.All, List.toList_toAssocList, List.mem_reverse, List.mem_filterMap,
  Option.map_eq_some', forall_exists_index, and_imp, g₁] at this ⊢
state_before: case refl.refine_2
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h✝¹ : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
i : Nat
h✝ :
  i <
    { size := Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
            buckets :=
              ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }, h✝¹⟩ }.buckets.val.size
h : i < m.buckets.val.size
this : AssocList.All (fun k x => ((hash k).toUSize % m.buckets.val.size).toNat = i) m.buckets.val[i]
⊢ AssocList.All (fun k x => ((hash k).toUSize % m.buckets.val.size).toNat = i)
    (g₁ m.buckets.val.data[i]).reverse.toAssocList
state_after: case refl.refine_2
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h✝¹ : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
i : Nat
h✝ :
  i <
    { size := Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
            buckets :=
              ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }, h✝¹⟩ }.buckets.val.size
h : i < m.buckets.val.size
this : ∀ (a : α × β), a ∈ m.buckets.val[i].toList → ((hash a.fst).toUSize % m.buckets.val.size).toNat = i
⊢ ∀ (a : α × γ) (x : α × β),
    x ∈ m.buckets.val.data[i].toList →
      ∀ (x_1 : γ), f x.fst x.snd = some x_1 → (x.fst, x_1) = a → ((hash a.fst).toUSize % m.buckets.val.size).toNat = i

tactic: rintro _ _ h' _ _ rfl
state_before: case refl.refine_2
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h✝¹ : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
i : Nat
h✝ :
  i <
    { size := Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
            buckets :=
              ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }, h✝¹⟩ }.buckets.val.size
h : i < m.buckets.val.size
this : ∀ (a : α × β), a ∈ m.buckets.val[i].toList → ((hash a.fst).toUSize % m.buckets.val.size).toNat = i
⊢ ∀ (a : α × γ) (x : α × β),
    x ∈ m.buckets.val.data[i].toList →
      ∀ (x_1 : γ), f x.fst x.snd = some x_1 → (x.fst, x_1) = a → ((hash a.fst).toUSize % m.buckets.val.size).toNat = i
state_after: case refl.refine_2
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h✝¹ : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
i : Nat
h✝ :
  i <
    { size := Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
            buckets :=
              ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }, h✝¹⟩ }.buckets.val.size
h : i < m.buckets.val.size
this : ∀ (a : α × β), a ∈ m.buckets.val[i].toList → ((hash a.fst).toUSize % m.buckets.val.size).toNat = i
x✝¹ : α × β
h' : x✝¹ ∈ m.buckets.val.data[i].toList
x✝ : γ
a✝ : f x✝¹.fst x✝¹.snd = some x✝
⊢ ((hash (x✝¹.fst, x✝).fst).toUSize % m.buckets.val.size).toNat = i

tactic: exact this _ h'
state_before: case refl.refine_2
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : m.WF
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) l.toList
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n = (((g₁ l).reverse ++ acc.toList).toAssocList, { down := n.down + (g₁ l).length })
g : AssocList α β → AssocList α γ := fun l => (g₁ l).reverse.toAssocList
M : Type (max u_3 u_1) → Type (max u_3 u_1) := StateT (ULift Nat) Id
H2 :
  ∀ (l : List (AssocList α β)) (n : ULift Nat),
    List.mapM (filterMap.go f AssocList.nil) l n =
      (List.map g l, { down := n.down + Nat.sum (List.map (fun x => x.toList.length) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    (List.map (fun a => a.fst)
          (List.filterMap
            (fun x =>
              match x with
              | (a, b) => Option.map (fun x => (a, x)) (f a b))
            l)).Sublist
      (List.map (fun x => x.fst) l)
h✝¹ : 0 < (List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data).length
i : Nat
h✝ :
  i <
    { size := Nat.sum (List.map ((fun x => x.toList.length) ∘ fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data),
            buckets :=
              ⟨{ data := List.map (fun l => (g₁ l).reverse.toAssocList) m.buckets.val.data }, h✝¹⟩ }.buckets.val.size
h : i < m.buckets.val.size
this : ∀ (a : α × β), a ∈ m.buckets.val[i].toList → ((hash a.fst).toUSize % m.buckets.val.size).toNat = i
x✝¹ : α × β
h' : x✝¹ ∈ m.buckets.val.data[i].toList
x✝ : γ
a✝ : f x✝¹.fst x✝¹.snd = some x✝
⊢ ((hash (x✝¹.fst, x✝).fst).toUSize % m.buckets.val.size).toNat = i
state_after: no goals