Theorem: Std.HashMap.Imp.WF.filterMap
File: Std/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 [filterMap.go, *]
  | cons a b l => match f a b with
    | none => rfl
    | some c => simp; 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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
⊢ WF (Imp.filterMap f m)

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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
⊢ WF (Imp.filterMap f m)

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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
⊢ WF (Imp.filterMap f m)

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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    List.Sublist
      (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))
      (List.map (fun x => x.fst) l)
⊢ WF (Imp.filterMap f m)

tactic: simp [Array.mapM_eq_mapM_data, bind, StateT.bind, H2]
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    List.Sublist
      (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))
      (List.map (fun x => x.fst) l)
⊢ ∀ (bk : List (AssocList α γ)) (sz : Nat) (h : 0 < List.length bk),
    Array.mapM (filterMap.go f AssocList.nil) m.buckets.val { down := 0 } = ({ data := bk }, { down := sz }) →
      WF { size := sz, buckets := { val := { data := bk }, property := h } }

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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    List.Sublist
      (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))
      (List.map (fun x => x.fst) l)
⊢ ∀ (bk : List (AssocList α γ)) (sz : Nat) (h : 0 < List.length bk),
    pure
          {
            data :=
              List.map
                (fun l =>
                  List.toAssocList
                    (List.reverse
                      (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                        (AssocList.toList l))))
                m.buckets.val.data }
          {
            down :=
              Nat.sum
                (List.map
                  ((fun x => List.length (AssocList.toList x)) ∘ fun l =>
                    List.toAssocList
                      (List.reverse
                        (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                          (AssocList.toList l))))
                  m.buckets.val.data) } =
        ({ data := bk }, { down := sz }) →
      WF { size := sz, buckets := { val := { data := bk }, property := h } }

tactic: cases e'
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    List.Sublist
      (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))
      (List.map (fun x => x.fst) l)
bk : List (AssocList α γ)
sz : Nat
h : 0 < List.length bk
e' :
  pure
      {
        data :=
          List.map
            (fun l =>
              List.toAssocList
                (List.reverse
                  (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                    (AssocList.toList l))))
            m.buckets.val.data }
      {
        down :=
          Nat.sum
            (List.map
              ((fun x => List.length (AssocList.toList x)) ∘ fun l =>
                List.toAssocList
                  (List.reverse
                    (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                      (AssocList.toList l))))
              m.buckets.val.data) } =
    ({ data := bk }, { down := sz })
⊢ WF { size := sz, buckets := { val := { data := bk }, property := h } }

tactic: refine .mk (by simp [Bucket.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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    List.Sublist
      (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))
      (List.map (fun x => x.fst) l)
h :
  0 <
    List.length
      (List.map
        (fun l =>
          List.toAssocList
            (List.reverse
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l))))
        m.buckets.val.data)
⊢ WF
    {
      size :=
        Nat.sum
          (List.map
            ((fun x => List.length (AssocList.toList x)) ∘ fun l =>
              List.toAssocList
                (List.reverse
                  (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                    (AssocList.toList l))))
            m.buckets.val.data),
      buckets :=
        {
          val :=
            {
              data :=
                List.map
                  (fun l =>
                    List.toAssocList
                      (List.reverse
                        (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                          (AssocList.toList l))))
                  m.buckets.val.data },
          property := h } }

tactic: induction l generalizing n acc with simp [filterMap.go, *]
| cons a b l => match f a b with
  | none => rfl
  | some c => simp; 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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
l : AssocList α β
n : ULift Nat
acc : AssocList α γ
⊢ filterMap.go f acc l n =
    (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })

tactic: match f a b with
| none => rfl
| some c => simp; 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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
a : α
b : β
l : AssocList α β
tail_ih✝ :
  ∀ (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
n : ULift Nat
acc : AssocList α γ
⊢ (match f a b with
    | none =>
      (List.toAssocList
          (List.reverse
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)) ++
            AssocList.toList acc),
        {
          down :=
            n.down +
              List.length
                (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)) })
    | some c =>
      (List.toAssocList
          (List.reverse
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)) ++
            (a, c) :: AssocList.toList acc),
        {
          down :=
            n.down + 1 +
              List.length
                (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                  (AssocList.toList l)) })) =
    (List.toAssocList
        (List.reverse
            (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)) (AssocList.toList l)
            | some b =>
              b ::
                List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)) ++
          AssocList.toList acc),
      {
        down :=
          n.down +
            List.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)) (AssocList.toList l)
              | some b =>
                b ::
                  List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                    (AssocList.toList l)) })

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

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

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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
a : α
b : β
l : AssocList α β
tail_ih✝ :
  ∀ (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
n : ULift Nat
acc : AssocList α γ
c : γ
⊢ {
      down :=
        n.down + 1 +
          List.length
            (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)) } =
    {
      down :=
        n.down +
          Nat.succ
            (List.length
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l))) }

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

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

tactic: rfl
state_before: case nil
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g [])) })

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

tactic: induction l with
| nil => exact .slnil
| cons a l ih =>
  simp; 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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
l : List (α × β)
⊢ List.Sublist
    (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))
    (List.map (fun x => x.fst) l)

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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
⊢ List.Sublist
    (List.map (fun a => a.fst)
      (List.filterMap
        (fun x =>
          match x with
          | (a, b) => Option.map (fun x => (a, x)) (f a b))
        []))
    (List.map (fun x => x.fst) [])

tactic: simp
state_before: case cons
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
a : α × β
l : List (α × β)
ih :
  List.Sublist
    (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))
    (List.map (fun x => x.fst) l)
⊢ List.Sublist
    (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)))
    (List.map (fun x => x.fst) (a :: 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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
a : α × β
l : List (α × β)
ih :
  List.Sublist
    (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))
    (List.map (fun x => x.fst) l)
⊢ List.Sublist
    (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))
    (a.fst :: List.map (fun x => x.fst) l)

tactic: simp [Bucket.size]
state_before: α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β → Option γ
inst✝¹ : BEq α
inst✝ : Hashable α
m : Imp α β
H : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    List.Sublist
      (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))
      (List.map (fun x => x.fst) l)
h :
  0 <
    List.length
      (List.map
        (fun l =>
          List.toAssocList
            (List.reverse
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l))))
        m.buckets.val.data)
⊢ {
        size :=
          Nat.sum
            (List.map
              ((fun x => List.length (AssocList.toList x)) ∘ fun l =>
                List.toAssocList
                  (List.reverse
                    (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                      (AssocList.toList l))))
              m.buckets.val.data),
        buckets :=
          {
            val :=
              {
                data :=
                  List.map
                    (fun l =>
                      List.toAssocList
                        (List.reverse
                          (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                            (AssocList.toList l))))
                    m.buckets.val.data },
            property := h } }.size =
    Bucket.size
      {
          size :=
            Nat.sum
              (List.map
                ((fun x => List.length (AssocList.toList x)) ∘ fun l =>
                  List.toAssocList
                    (List.reverse
                      (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                        (AssocList.toList l))))
                m.buckets.val.data),
          buckets :=
            {
              val :=
                {
                  data :=
                    List.map
                      (fun l =>
                        List.toAssocList
                          (List.reverse
                            (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                              (AssocList.toList l))))
                      m.buckets.val.data },
              property := h } }.buckets

tactic: simp only [List.forall_mem_map_iff, List.toAssocList_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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    List.Sublist
      (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))
      (List.map (fun x => x.fst) l)
h :
  0 <
    List.length
      (List.map
        (fun l =>
          List.toAssocList
            (List.reverse
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l))))
        m.buckets.val.data)
⊢ ∀ [inst : LawfulHashable α] [inst : PartialEquivBEq α] (bucket : AssocList α γ),
    bucket ∈
        {
                size :=
                  Nat.sum
                    (List.map
                      ((fun x => List.length (AssocList.toList x)) ∘ fun l =>
                        List.toAssocList
                          (List.reverse
                            (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                              (AssocList.toList l))))
                      m.buckets.val.data),
                buckets :=
                  {
                    val :=
                      {
                        data :=
                          List.map
                            (fun l =>
                              List.toAssocList
                                (List.reverse
                                  (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                                    (AssocList.toList l))))
                            m.buckets.val.data },
                    property := h } }.buckets.val.data →
      List.Pairwise (fun a b => ¬(a.fst == b.fst) = true) (AssocList.toList bucket)

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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    List.Sublist
      (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))
      (List.map (fun x => x.fst) l)
h :
  0 <
    List.length
      (List.map
        (fun l =>
          List.toAssocList
            (List.reverse
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l))))
        m.buckets.val.data)
⊢ ∀ [inst : LawfulHashable α] [inst : PartialEquivBEq α] (j : AssocList α β),
    j ∈ m.buckets.val.data →
      List.Pairwise (fun a b => ¬(a.fst == b.fst) = true)
        (List.reverse
          (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList j)))

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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    List.Sublist
      (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))
      (List.map (fun x => x.fst) l)
h✝ :
  0 <
    List.length
      (List.map
        (fun l =>
          List.toAssocList
            (List.reverse
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l))))
        m.buckets.val.data)
inst✝¹ : LawfulHashable α
inst✝ : PartialEquivBEq α
l : AssocList α β
h : l ∈ m.buckets.val.data
⊢ List.Pairwise (fun a b => ¬(a.fst == b.fst) = true)
    (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList 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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    List.Sublist
      (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))
      (List.map (fun x => x.fst) l)
h✝ :
  0 <
    List.length
      (List.map
        (fun l =>
          List.toAssocList
            (List.reverse
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l))))
        m.buckets.val.data)
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 (fun a => a.fst) (AssocList.toList l))
⊢ List.Pairwise (fun x x_1 => ¬(x == x_1) = true)
    (List.map (fun a => a.fst)
      (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)))

tactic: simp [Array.getElem_eq_data_get] 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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    List.Sublist
      (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))
      (List.map (fun x => x.fst) l)
h✝ :
  0 <
    List.length
      (List.map
        (fun l =>
          List.toAssocList
            (List.reverse
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l))))
        m.buckets.val.data)
i : Nat
h :
  i <
    Array.size
      {
            size :=
              Nat.sum
                (List.map
                  ((fun x => List.length (AssocList.toList x)) ∘ fun l =>
                    List.toAssocList
                      (List.reverse
                        (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                          (AssocList.toList l))))
                  m.buckets.val.data),
            buckets :=
              {
                val :=
                  {
                    data :=
                      List.map
                        (fun l =>
                          List.toAssocList
                            (List.reverse
                              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                                (AssocList.toList l))))
                        m.buckets.val.data },
                property := h✝ } }.buckets.val
⊢ AssocList.All
    (fun k x =>
      USize.toNat
          (UInt64.toUSize (hash k) %
            Array.size
              {
                    size :=
                      Nat.sum
                        (List.map
                          ((fun x => List.length (AssocList.toList x)) ∘ fun l =>
                            List.toAssocList
                              (List.reverse
                                (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                                  (AssocList.toList l))))
                          m.buckets.val.data),
                    buckets :=
                      {
                        val :=
                          {
                            data :=
                              List.map
                                (fun l =>
                                  List.toAssocList
                                    (List.reverse
                                      (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                                        (AssocList.toList l))))
                                m.buckets.val.data },
                        property := h✝ } }.buckets.val) =
        i)
    {
            size :=
              Nat.sum
                (List.map
                  ((fun x => List.length (AssocList.toList x)) ∘ fun l =>
                    List.toAssocList
                      (List.reverse
                        (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                          (AssocList.toList l))))
                  m.buckets.val.data),
            buckets :=
              {
                val :=
                  {
                    data :=
                      List.map
                        (fun l =>
                          List.toAssocList
                            (List.reverse
                              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                                (AssocList.toList l))))
                        m.buckets.val.data },
                property := h✝ } }.buckets.val[i]

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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    List.Sublist
      (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))
      (List.map (fun x => x.fst) l)
h✝¹ :
  0 <
    List.length
      (List.map
        (fun l =>
          List.toAssocList
            (List.reverse
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l))))
        m.buckets.val.data)
i : Nat
h✝ :
  i <
    Array.size
      {
            size :=
              Nat.sum
                (List.map
                  ((fun x => List.length (AssocList.toList x)) ∘ fun l =>
                    List.toAssocList
                      (List.reverse
                        (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                          (AssocList.toList l))))
                  m.buckets.val.data),
            buckets :=
              {
                val :=
                  {
                    data :=
                      List.map
                        (fun l =>
                          List.toAssocList
                            (List.reverse
                              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                                (AssocList.toList l))))
                        m.buckets.val.data },
                property := h✝¹ } }.buckets.val
h : i < List.length m.buckets.val.data
⊢ AssocList.All (fun k x => USize.toNat (UInt64.toUSize (hash k) % List.length m.buckets.val.data) = i)
    (List.toAssocList
      (List.reverse
        (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
          (AssocList.toList
            (List.get m.buckets.val.data
              { val := i, isLt := (_ : { val := i, isLt := h✝ }.val < List.length m.buckets.val.data) })))))

tactic: simp [AssocList.All] 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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    List.Sublist
      (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))
      (List.map (fun x => x.fst) l)
h✝¹ :
  0 <
    List.length
      (List.map
        (fun l =>
          List.toAssocList
            (List.reverse
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l))))
        m.buckets.val.data)
i : Nat
h✝ :
  i <
    Array.size
      {
            size :=
              Nat.sum
                (List.map
                  ((fun x => List.length (AssocList.toList x)) ∘ fun l =>
                    List.toAssocList
                      (List.reverse
                        (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                          (AssocList.toList l))))
                  m.buckets.val.data),
            buckets :=
              {
                val :=
                  {
                    data :=
                      List.map
                        (fun l =>
                          List.toAssocList
                            (List.reverse
                              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                                (AssocList.toList l))))
                        m.buckets.val.data },
                property := h✝¹ } }.buckets.val
h : i < List.length m.buckets.val.data
this : AssocList.All (fun k x => USize.toNat (UInt64.toUSize (hash k) % Array.size m.buckets.val) = i) m.buckets.val[i]
⊢ AssocList.All (fun k x => USize.toNat (UInt64.toUSize (hash k) % List.length m.buckets.val.data) = i)
    (List.toAssocList
      (List.reverse
        (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
          (AssocList.toList
            (List.get m.buckets.val.data
              { val := i, isLt := (_ : { val := i, isLt := h✝ }.val < List.length m.buckets.val.data) })))))

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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    List.Sublist
      (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))
      (List.map (fun x => x.fst) l)
h✝¹ :
  0 <
    List.length
      (List.map
        (fun l =>
          List.toAssocList
            (List.reverse
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l))))
        m.buckets.val.data)
i : Nat
h✝ :
  i <
    Array.size
      {
            size :=
              Nat.sum
                (List.map
                  ((fun x => List.length (AssocList.toList x)) ∘ fun l =>
                    List.toAssocList
                      (List.reverse
                        (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                          (AssocList.toList l))))
                  m.buckets.val.data),
            buckets :=
              {
                val :=
                  {
                    data :=
                      List.map
                        (fun l =>
                          List.toAssocList
                            (List.reverse
                              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                                (AssocList.toList l))))
                        m.buckets.val.data },
                property := h✝¹ } }.buckets.val
h : i < List.length m.buckets.val.data
this :
  ∀ (a : α × β),
    a ∈ AssocList.toList m.buckets.val[i] → USize.toNat (UInt64.toUSize (hash a.fst) % Array.size m.buckets.val) = i
⊢ ∀ (a : α × γ) (x : α × β),
    x ∈
        AssocList.toList
          (List.get m.buckets.val.data
            { val := i, isLt := (_ : { val := i, isLt := h✝ }.val < List.length m.buckets.val.data) }) →
      ∀ (x_1 : γ),
        f x.fst x.snd = some x_1 →
          (x.fst, x_1) = a → USize.toNat (UInt64.toUSize (hash a.fst) % List.length m.buckets.val.data) = 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 : WF m
g₁ : AssocList α β → List (α × γ) :=
  fun l => List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l)
H1 :
  ∀ (l : AssocList α β) (n : ULift Nat) (acc : AssocList α γ),
    filterMap.go f acc l n =
      (List.toAssocList (List.reverse (g₁ l) ++ AssocList.toList acc), { down := n.down + List.length (g₁ l) })
g : AssocList α β → AssocList α γ := fun l => List.toAssocList (List.reverse (g₁ l))
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 => List.length (AssocList.toList x)) (List.map g l)) })
H3 :
  ∀ (l : List (α × β)),
    List.Sublist
      (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))
      (List.map (fun x => x.fst) l)
h✝¹ :
  0 <
    List.length
      (List.map
        (fun l =>
          List.toAssocList
            (List.reverse
              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd)) (AssocList.toList l))))
        m.buckets.val.data)
i : Nat
h✝ :
  i <
    Array.size
      {
            size :=
              Nat.sum
                (List.map
                  ((fun x => List.length (AssocList.toList x)) ∘ fun l =>
                    List.toAssocList
                      (List.reverse
                        (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                          (AssocList.toList l))))
                  m.buckets.val.data),
            buckets :=
              {
                val :=
                  {
                    data :=
                      List.map
                        (fun l =>
                          List.toAssocList
                            (List.reverse
                              (List.filterMap (fun x => Option.map (fun x_1 => (x.fst, x_1)) (f x.fst x.snd))
                                (AssocList.toList l))))
                        m.buckets.val.data },
                property := h✝¹ } }.buckets.val
h : i < List.length m.buckets.val.data
this :
  ∀ (a : α × β),
    a ∈ AssocList.toList m.buckets.val[i] → USize.toNat (UInt64.toUSize (hash a.fst) % Array.size m.buckets.val) = i
x✝¹ : α × β
h' :
  x✝¹ ∈
    AssocList.toList
      (List.get m.buckets.val.data
        { val := i, isLt := (_ : { val := i, isLt := h✝ }.val < List.length m.buckets.val.data) })
x✝ : γ
a✝ : f x✝¹.fst x✝¹.snd = some x✝
⊢ USize.toNat (UInt64.toUSize (hash (x✝¹.fst, x✝).fst) % List.length m.buckets.val.data) = i