l3lab/ntp-mathlib huggingface dataset:
/-- Scalar multiplication as a bilinear map `R → M → M`. -/
def lsmul : R →ₗ[R] M →ₗ[R] M :=
  mk₂ R (· • ·) add_smul (fun _ _ _ => mul_smul _ _ _) smul_add fun r s m => by
    

Proof state:
R : Type u_1
inst✝²³ : CommSemiring R
R₂ : Type u_2
inst✝²² : CommSemiring R₂
R₃ : Type u_3
inst✝²¹ : CommSemiring R₃
R₄ : Type u_4
inst✝²⁰ : CommSemiring R₄
M : Type u_5
N : Type u_6
P : Type u_7
Q : Type u_8
Mₗ : Type u_9
Nₗ : Type u_10
Pₗ : Type u_11
Qₗ : Type u_12
Qₗ' : Type u_13
inst✝¹⁹ : AddCommMonoid M
inst✝¹⁸ : AddCommMonoid N
inst✝¹⁷ : AddCommMonoid P
inst✝¹⁶ : AddCommMonoid Q
inst✝¹⁵ : AddCommMonoid Mₗ
inst✝¹⁴ : AddCommMonoid Nₗ
inst✝¹³ : AddCommMonoid Pₗ
inst✝¹² : AddCommMonoid Qₗ
inst✝¹¹ : AddCommMonoid Qₗ'
inst✝¹⁰ : Module R M
inst✝⁹ : Module R₂ N
inst✝⁸ : Module R₃ P
inst✝⁷ : Module R₄ Q
inst✝⁶ : Module R Mₗ
inst✝⁵ : Module R Nₗ
inst✝⁴ : Module R Pₗ
inst✝³ : Module R Qₗ
inst✝² : Module R Qₗ'
σ₁₂ : R →+* R₂
σ₂₃ : R₂ →+* R₃
σ₁₃ : R →+* R₃
σ₄₂ : R₄ →+* R₂
σ₄₃ : R₄ →+* R₃
inst✝¹ : RingHomCompTriple σ₁₂ σ₂₃ σ₁₃
inst✝ : RingHomCompTriple σ₄₂ σ₂₃ σ₄₃
f : M →ₛₗ[σ₁₃] N →ₛₗ[σ₂₃] P
r s : R
m : M
⊢ (fun x x_1 => x • x_1) s (r • m) = r • (fun x x_1 => x • x_1) s m

Next tactic:
simp only [smul_smul, smul_eq_mul, mul_comm]
instance : Category (HomotopyCategory V v) := by
  

Proof state:
ι : Type u_1
V : Type u
inst✝¹ : Category.{v, u} V
inst✝ : Preadditive V
c : ComplexShape ι
ι✝ : Type ?u.1735
v : ComplexShape ι✝
⊢ Category.{?u.1732, max (max u v) ?u.1735} (HomotopyCategory V v)

Next tactic:
dsimp only [HomotopyCategory]
instance : Category (HomotopyCategory V v) := by
  dsimp only [HomotopyCategory]
  

Proof state:
ι : Type u_1
V : Type u
inst✝¹ : Category.{v, u} V
inst✝ : Preadditive V
c : ComplexShape ι
ι✝ : Type ?u.1735
v : ComplexShape ι✝
⊢ Category.{?u.1732, max (max u v) ?u.1735} (CategoryTheory.Quotient (homotopic V v))

Next tactic:
infer_instance
instance : Preadditive (HomotopyCategory V c) := Quotient.preadditive _ (by
  

Proof state:
ι : Type u_1
V : Type u
inst✝¹ : Category.{v, u} V
inst✝ : Preadditive V
c : ComplexShape ι
⊢ ∀ ⦃X Y : HomologicalComplex V c⦄ (f₁ f₂ g₁ g₂ : X ⟶ Y),
    homotopic V c f₁ f₂ → homotopic V c g₁ g₂ → homotopic V c (f₁ + g₁) (f₂ + g₂)

Next tactic:
rintro _ _ _ _ _ _ ⟨h⟩ ⟨h'⟩
instance : Preadditive (HomotopyCategory V c) := Quotient.preadditive _ (by
  rintro _ _ _ _ _ _ ⟨h⟩ ⟨h'⟩
  

Proof state:
case intro.intro
ι : Type u_1
V : Type u
inst✝¹ : Category.{v, u} V
inst✝ : Preadditive V
c : ComplexShape ι
X✝ Y✝ : HomologicalComplex V c
f₁✝ f₂✝ g₁✝ g₂✝ : X✝ ⟶ Y✝
h : Homotopy f₁✝ f₂✝
h' : Homotopy g₁✝ g₂✝
⊢ homotopic V c (f₁✝ + g₁✝) (f₂✝ + g₂✝)

Next tactic:
exact ⟨Homotopy.add h h'⟩
/-- An arbitrarily chosen representation of the image of a chain map in the homotopy category
is homotopic to the original chain map.
-/
def homotopyOutMap {C D : HomologicalComplex V c} (f : C ⟶ D) :
    Homotopy ((quotient V c).map f).out f := by
  

Proof state:
ι : Type u_1
V : Type u
inst✝¹ : Category.{v, u} V
inst✝ : Preadditive V
c : ComplexShape ι
C D : HomologicalComplex V c
f : C ⟶ D
⊢ Homotopy (Quot.out ((quotient V c).map f)) f

Next tactic:
apply homotopyOfEq
/-- An arbitrarily chosen representation of the image of a chain map in the homotopy category
is homotopic to the original chain map.
-/
def homotopyOutMap {C D : HomologicalComplex V c} (f : C ⟶ D) :
    Homotopy ((quotient V c).map f).out f := by
  apply homotopyOfEq
  

Proof state:
case w
ι : Type u_1
V : Type u
inst✝¹ : Category.{v, u} V
inst✝ : Preadditive V
c : ComplexShape ι
C D : HomologicalComplex V c
f : C ⟶ D
⊢ (quotient V c).map (Quot.out ((quotient V c).map f)) = (quotient V c).map f

Next tactic:
simp
@[simp 1100]
theorem quotient_map_out_comp_out {C D E : HomotopyCategory V c} (f : C ⟶ D) (g : D ⟶ E) :
    (quotient V c).map (Quot.out f ≫ Quot.out g) = f ≫ g := by 

Proof state:
ι : Type u_1
V : Type u
inst✝¹ : Category.{v, u} V
inst✝ : Preadditive V
c : ComplexShape ι
C D E : HomotopyCategory V c
f : C ⟶ D
g : D ⟶ E
⊢ (quotient V c).map (Quot.out f ≫ Quot.out g) = f ≫ g

Next tactic:
simp
/-- Homotopy equivalent complexes become isomorphic in the homotopy category. -/
@[simps]
def isoOfHomotopyEquiv {C D : HomologicalComplex V c} (f : HomotopyEquiv C D) :
    (quotient V c).obj C ≅ (quotient V c).obj D where
  hom := (quotient V c).map f.hom
  inv := (quotient V c).map f.inv
  hom_inv_id := by
    

Proof state:
ι : Type u_1
V : Type u
inst✝¹ : Category.{v, u} V
inst✝ : Preadditive V
c : ComplexShape ι
C D : HomologicalComplex V c
f : HomotopyEquiv C D
⊢ (quotient V c).map f.hom ≫ (quotient V c).map f.inv = 𝟙 ((quotient V c).obj C)

Next tactic:
rw [← (quotient V c).map_comp, ← (quotient V c).map_id]
/-- Homotopy equivalent complexes become isomorphic in the homotopy category. -/
@[simps]
def isoOfHomotopyEquiv {C D : HomologicalComplex V c} (f : HomotopyEquiv C D) :
    (quotient V c).obj C ≅ (quotient V c).obj D where
  hom := (quotient V c).map f.hom
  inv := (quotient V c).map f.inv
  hom_inv_id := by
    rw [← (quotient V c).map_comp, ← (quotient V c).map_id]
    

Proof state:
ι : Type u_1
V : Type u
inst✝¹ : Category.{v, u} V
inst✝ : Preadditive V
c : ComplexShape ι
C D : HomologicalComplex V c
f : HomotopyEquiv C D
⊢ (quotient V c).map (f.hom ≫ f.inv) = (quotient V c).map (𝟙 C)

Next tactic:
exact eq_of_homotopy _ _ f.homotopyHomInvId
/-- Homotopy equivalent complexes become isomorphic in the homotopy category. -/
@[simps]
def isoOfHomotopyEquiv {C D : HomologicalComplex V c} (f : HomotopyEquiv C D) :
    (quotient V c).obj C ≅ (quotient V c).obj D where
  hom := (quotient V c).map f.hom
  inv := (quotient V c).map f.inv
  hom_inv_id := by
    rw [← (quotient V c).map_comp, ← (quotient V c).map_id]
    exact eq_of_homotopy _ _ f.homotopyHomInvId
  inv_hom_id := by
    

Proof state:
ι : Type u_1
V : Type u
inst✝¹ : Category.{v, u} V
inst✝ : Preadditive V
c : ComplexShape ι
C D : HomologicalComplex V c
f : HomotopyEquiv C D
⊢ (quotient V c).map f.inv ≫ (quotient V c).map f.hom = 𝟙 ((quotient V c).obj D)

Next tactic:
rw [← (quotient V c).map_comp, ← (quotient V c).map_id]
/-- Homotopy equivalent complexes become isomorphic in the homotopy category. -/
@[simps]
def isoOfHomotopyEquiv {C D : HomologicalComplex V c} (f : HomotopyEquiv C D) :
    (quotient V c).obj C ≅ (quotient V c).obj D where
  hom := (quotient V c).map f.hom
  inv := (quotient V c).map f.inv
  hom_inv_id := by
    rw [← (quotient V c).map_comp, ← (quotient V c).map_id]
    exact eq_of_homotopy _ _ f.homotopyHomInvId
  inv_hom_id := by
    rw [← (quotient V c).map_comp, ← (quotient V c).map_id]
    

Proof state:
ι : Type u_1
V : Type u
inst✝¹ : Category.{v, u} V
inst✝ : Preadditive V
c : ComplexShape ι
C D : HomologicalComplex V c
f : HomotopyEquiv C D
⊢ (quotient V c).map (f.inv ≫ f.hom) = (quotient V c).map (𝟙 D)

Next tactic:
exact eq_of_homotopy _ _ f.homotopyInvHomId
/-- If two complexes become isomorphic in the homotopy category,
  then they were homotopy equivalent. -/
def homotopyEquivOfIso {C D : HomologicalComplex V c}
    (i : (quotient V c).obj C ≅ (quotient V c).obj D) : HomotopyEquiv C D where
  hom := Quot.out i.hom
  inv := Quot.out i.inv
  homotopyHomInvId :=
    homotopyOfEq _ _
      (by 

Proof state:
ι : Type u_1
V : Type u
inst✝¹ : Category.{v, u} V
inst✝ : Preadditive V
c : ComplexShape ι
C D : HomologicalComplex V c
i : (quotient V c).obj C ≅ (quotient V c).obj D
⊢ (quotient V c).map (Quot.out i.hom ≫ Quot.out i.inv) = (quotient V c).map (𝟙 C)

Next tactic:
rw [quotient_map_out_comp_out, i.hom_inv_id, (quotient V c).map_id]
/-- If two complexes become isomorphic in the homotopy category,
  then they were homotopy equivalent. -/
def homotopyEquivOfIso {C D : HomologicalComplex V c}
    (i : (quotient V c).obj C ≅ (quotient V c).obj D) : HomotopyEquiv C D where
  hom := Quot.out i.hom
  inv := Quot.out i.inv
  homotopyHomInvId :=
    homotopyOfEq _ _
      (by rw [quotient_map_out_comp_out, i.hom_inv_id, (quotient V c).map_id])
  homotopyInvHomId :=
    homotopyOfEq _ _
      (by 

Proof state:
ι : Type u_1
V : Type u
inst✝¹ : Category.{v, u} V
inst✝ : Preadditive V
c : ComplexShape ι
C D : HomologicalComplex V c
i : (quotient V c).obj C ≅ (quotient V c).obj D
⊢ (quotient V c).map (Quot.out i.inv ≫ Quot.out i.hom) = (quotient V c).map (𝟙 D)

Next tactic:
rw [quotient_map_out_comp_out, i.inv_hom_id, (quotient V c).map_id]
/-- The `i`-th homology, as a functor from the homotopy category. -/
noncomputable def homologyFunctor (i : ι) : HomotopyCategory V c ⥤ V :=
  CategoryTheory.Quotient.lift _ (HomologicalComplex.homologyFunctor V c i) (by
    

Proof state:
ι : Type u_1
V : Type u
inst✝² : Category.{v, u} V
inst✝¹ : Preadditive V
c : ComplexShape ι
inst✝ : CategoryWithHomology V
i : ι
⊢ ∀ (x y : HomologicalComplex V c) (f₁ f₂ : x ⟶ y),
    homotopic V c f₁ f₂ →
      (HomologicalComplex.homologyFunctor V c i).map f₁ = (HomologicalComplex.homologyFunctor V c i).map f₂

Next tactic:
rintro K L f g ⟨h⟩
/-- The `i`-th homology, as a functor from the homotopy category. -/
noncomputable def homologyFunctor (i : ι) : HomotopyCategory V c ⥤ V :=
  CategoryTheory.Quotient.lift _ (HomologicalComplex.homologyFunctor V c i) (by
    rintro K L f g ⟨h⟩
    

Proof state:
case intro
ι : Type u_1
V : Type u
inst✝² : Category.{v, u} V
inst✝¹ : Preadditive V
c : ComplexShape ι
inst✝ : CategoryWithHomology V
i : ι
K L : HomologicalComplex V c
f g : K ⟶ L
h : Homotopy f g
⊢ (HomologicalComplex.homologyFunctor V c i).map f = (HomologicalComplex.homologyFunctor V c i).map g

Next tactic:
exact h.homologyMap_eq i
instance (i : ι) : (homologyFunctor V c i).Additive := by
  

Proof state:
ι : Type u_1
V : Type u
inst✝² : Category.{v, u} V
inst✝¹ : Preadditive V
c : ComplexShape ι
inst✝ : CategoryWithHomology V
i : ι
⊢ Functor.Additive (homologyFunctor V c i)

Next tactic:
have := Functor.additive_of_iso (homologyFunctorFactors V c i).symm
instance (i : ι) : (homologyFunctor V c i).Additive := by
  have := Functor.additive_of_iso (homologyFunctorFactors V c i).symm
  

Proof state:
ι : Type u_1
V : Type u
inst✝² : Category.{v, u} V
inst✝¹ : Preadditive V
c : ComplexShape ι
inst✝ : CategoryWithHomology V
i : ι
this : Functor.Additive (quotient V c ⋙ homologyFunctor V c i)
⊢ Functor.Additive (homologyFunctor V c i)

Next tactic:
exact Functor.additive_of_full_essSurj_comp (quotient V c) _
/-- A natural transformation induces a natural transformation between
  the induced functors on the homotopy category. -/
@[simps]
def NatTrans.mapHomotopyCategory {F G : V ⥤ W} [F.Additive] [G.Additive] (α : F ⟶ G)
    (c : ComplexShape ι) : F.mapHomotopyCategory c ⟶ G.mapHomotopyCategory c where
  app C := (HomotopyCategory.quotient W c).map ((NatTrans.mapHomologicalComplex α c).app C.as)
  naturality := by
    

Proof state:
ι : Type u_1
V : Type u
inst✝⁵ : Category.{v, u} V
inst✝⁴ : Preadditive V
c✝ : ComplexShape ι
W : Type u_2
inst✝³ : Category.{?u.76350, u_2} W
inst✝² : Preadditive W
F G : V ⥤ W
inst✝¹ : Functor.Additive F
inst✝ : Functor.Additive G
α : F ⟶ G
c : ComplexShape ι
⊢ ∀ ⦃X Y : HomotopyCategory V c⦄ (f : X ⟶ Y),
    (Functor.mapHomotopyCategory F c).map f ≫
        (fun C => (HomotopyCategory.quotient W c).map ((mapHomologicalComplex α c).app C.as)) Y =
      (fun C => (HomotopyCategory.quotient W c).map ((mapHomologicalComplex α c).app C.as)) X ≫
        (Functor.mapHomotopyCategory G c).map f

Next tactic:
rintro ⟨C⟩ ⟨D⟩ ⟨f : C ⟶ D⟩
/-- A natural transformation induces a natural transformation between
  the induced functors on the homotopy category. -/
@[simps]
def NatTrans.mapHomotopyCategory {F G : V ⥤ W} [F.Additive] [G.Additive] (α : F ⟶ G)
    (c : ComplexShape ι) : F.mapHomotopyCategory c ⟶ G.mapHomotopyCategory c where
  app C := (HomotopyCategory.quotient W c).map ((NatTrans.mapHomologicalComplex α c).app C.as)
  naturality := by
    rintro ⟨C⟩ ⟨D⟩ ⟨f : C ⟶ D⟩
    

Proof state:
case mk.mk.mk
ι : Type u_1
V : Type u
inst✝⁵ : Category.{v, u} V
inst✝⁴ : Preadditive V
c✝ : ComplexShape ι
W : Type u_2
inst✝³ : Category.{?u.76350, u_2} W
inst✝² : Preadditive W
F G : V ⥤ W
inst✝¹ : Functor.Additive F
inst✝ : Functor.Additive G
α : F ⟶ G
c : ComplexShape ι
C D : HomologicalComplex V c
f✝ : { as := C } ⟶ { as := D }
f : C ⟶ D
⊢ (Functor.mapHomotopyCategory F c).map (Quot.mk (Quotient.CompClosure (homotopic V c)) f) ≫
      (fun C => (HomotopyCategory.quotient W c).map ((mapHomologicalComplex α c).app C.as)) { as := D } =
    (fun C => (HomotopyCategory.quotient W c).map ((mapHomologicalComplex α c).app C.as)) { as := C } ≫
      (Functor.mapHomotopyCategory G c).map (Quot.mk (Quotient.CompClosure (homotopic V c)) f)

Next tactic:
simp only [HomotopyCategory.quot_mk_eq_quotient_map, Functor.mapHomotopyCategory_map,
      ← Functor.map_comp, NatTrans.naturality]
@[simp]
theorem NatTrans.mapHomotopyCategory_id (c : ComplexShape ι) (F : V ⥤ W) [F.Additive] :
    NatTrans.mapHomotopyCategory (𝟙 F) c = 𝟙 (F.mapHomotopyCategory c) := by 

Proof state:
ι : Type u_1
V : Type u
inst✝⁴ : Category.{v, u} V
inst✝³ : Preadditive V
c✝ : ComplexShape ι
W : Type u_2
inst✝² : Category.{u_3, u_2} W
inst✝¹ : Preadditive W
c : ComplexShape ι
F : V ⥤ W
inst✝ : Functor.Additive F
⊢ mapHomotopyCategory (𝟙 F) c = 𝟙 (Functor.mapHomotopyCategory F c)

Next tactic:
aesop_cat
@[simp]
theorem NatTrans.mapHomotopyCategory_comp (c : ComplexShape ι) {F G H : V ⥤ W} [F.Additive]
    [G.Additive] [H.Additive] (α : F ⟶ G) (β : G ⟶ H) :
    NatTrans.mapHomotopyCategory (α ≫ β) c =
      NatTrans.mapHomotopyCategory α c ≫ NatTrans.mapHomotopyCategory β c := by 

Proof state:
ι : Type u_1
V : Type u
inst✝⁶ : Category.{v, u} V
inst✝⁵ : Preadditive V
c✝ : ComplexShape ι
W : Type u_2
inst✝⁴ : Category.{u_3, u_2} W
inst✝³ : Preadditive W
c : ComplexShape ι
F G H : V ⥤ W
inst✝² : Functor.Additive F
inst✝¹ : Functor.Additive G
inst✝ : Functor.Additive H
α : F ⟶ G
β : G ⟶ H
⊢ mapHomotopyCategory (α ≫ β) c = mapHomotopyCategory α c ≫ mapHomotopyCategory β c

Next tactic:
aesop_cat
lemma nodup_keys {m : Multiset (Σ a, β a)} : m.keys.Nodup ↔ m.NodupKeys := by
  

Proof state:
α : Type u
β : α → Type v
m : Multiset ((a : α) × β a)
⊢ Nodup (keys m) ↔ NodupKeys m

Next tactic:
rcases m with ⟨l⟩
lemma nodup_keys {m : Multiset (Σ a, β a)} : m.keys.Nodup ↔ m.NodupKeys := by
  rcases m with ⟨l⟩; 

Proof state:
case mk
α : Type u
β : α → Type v
m : Multiset ((a : α) × β a)
l : List ((a : α) × β a)
⊢ Nodup (keys (Quot.mk Setoid.r l)) ↔ NodupKeys (Quot.mk Setoid.r l)

Next tactic:
rfl
theorem AList.toFinmap_eq {s₁ s₂ : AList β} :
    toFinmap s₁ = toFinmap s₂ ↔ s₁.entries ~ s₂.entries := by
  

Proof state:
α : Type u
β : α → Type v
s₁ s₂ : AList β
⊢ ⟦s₁⟧ = ⟦s₂⟧ ↔ s₁.entries ~ s₂.entries

Next tactic:
cases s₁
theorem AList.toFinmap_eq {s₁ s₂ : AList β} :
    toFinmap s₁ = toFinmap s₂ ↔ s₁.entries ~ s₂.entries := by
  cases s₁
  

Proof state:
case mk
α : Type u
β : α → Type v
s₂ : AList β
entries✝ : List (Sigma β)
nodupKeys✝ : NodupKeys entries✝
⊢ ⟦{ entries := entries✝, nodupKeys := nodupKeys✝ }⟧ = ⟦s₂⟧ ↔
    { entries := entries✝, nodupKeys := nodupKeys✝ }.entries ~ s₂.entries

Next tactic:
cases s₂
theorem AList.toFinmap_eq {s₁ s₂ : AList β} :
    toFinmap s₁ = toFinmap s₂ ↔ s₁.entries ~ s₂.entries := by
  cases s₁
  cases s₂
  

Proof state:
case mk.mk
α : Type u
β : α → Type v
entries✝¹ : List (Sigma β)
nodupKeys✝¹ : NodupKeys entries✝¹
entries✝ : List (Sigma β)
nodupKeys✝ : NodupKeys entries✝
⊢ ⟦{ entries := entries✝¹, nodupKeys := nodupKeys✝¹ }⟧ = ⟦{ entries := entries✝, nodupKeys := nodupKeys✝ }⟧ ↔
    { entries := entries✝¹, nodupKeys := nodupKeys✝¹ }.entries ~
      { entries := entries✝, nodupKeys := nodupKeys✝ }.entries

Next tactic:
simp [AList.toFinmap]
/-- Lift a permutation-respecting function on `AList` to `Finmap`. -/
-- @[elab_as_elim] Porting note: we can't add `elab_as_elim` attr in this type
def liftOn {γ} (s : Finmap β) (f : AList β → γ)
    (H : ∀ a b : AList β, a.entries ~ b.entries → f a = f b) : γ := by
  

Proof state:
α : Type u
β : α → Type v
γ : Sort ?u.11017
s : Finmap β
f : AList β → γ
H : ∀ (a b : AList β), a.entries ~ b.entries → f a = f b
⊢ γ

Next tactic:
refine'
    (Quotient.liftOn s.entries
      (fun (l : List (Sigma β)) => (⟨_, fun nd => f ⟨l, nd⟩⟩ : Part γ))
      (fun l₁ l₂ p => Part.ext' (perm_nodupKeys p) _) : Part γ).get _
/-- Lift a permutation-respecting function on `AList` to `Finmap`. -/
-- @[elab_as_elim] Porting note: we can't add `elab_as_elim` attr in this type
def liftOn {γ} (s : Finmap β) (f : AList β → γ)
    (H : ∀ a b : AList β, a.entries ~ b.entries → f a = f b) : γ := by
  refine'
    (Quotient.liftOn s.entries
      (fun (l : List (Sigma β)) => (⟨_, fun nd => f ⟨l, nd⟩⟩ : Part γ))
      (fun l₁ l₂ p => Part.ext' (perm_nodupKeys p) _) : Part γ).get _
  · 

Proof state:
case refine'_1
α : Type u
β : α → Type v
γ : Type ?u.11069
s : Finmap β
f : AList β → γ
H : ∀ (a b : AList β), a.entries ~ b.entries → f a = f b
l₁ l₂ : List (Sigma β)
p : l₁ ≈ l₂
⊢ ∀ (h₁ : ((fun l => { Dom := NodupKeys l, get := fun nd => f { entries := l, nodupKeys := nd } }) l₁).Dom)
    (h₂ : ((fun l => { Dom := NodupKeys l, get := fun nd => f { entries := l, nodupKeys := nd } }) l₂).Dom),
    Part.get ((fun l => { Dom := NodupKeys l, get := fun nd => f { entries := l, nodupKeys := nd } }) l₁) h₁ =
      Part.get ((fun l => { Dom := NodupKeys l, get := fun nd => f { entries := l, nodupKeys := nd } }) l₂) h₂

Next tactic:
exact fun h1 h2 => H _ _ p
/-- Lift a permutation-respecting function on `AList` to `Finmap`. -/
-- @[elab_as_elim] Porting note: we can't add `elab_as_elim` attr in this type
def liftOn {γ} (s : Finmap β) (f : AList β → γ)
    (H : ∀ a b : AList β, a.entries ~ b.entries → f a = f b) : γ := by
  refine'
    (Quotient.liftOn s.entries
      (fun (l : List (Sigma β)) => (⟨_, fun nd => f ⟨l, nd⟩⟩ : Part γ))
      (fun l₁ l₂ p => Part.ext' (perm_nodupKeys p) _) : Part γ).get _
  · exact fun h1 h2 => H _ _ p
  · 

Proof state:
case refine'_2
α : Type u
β : α → Type v
γ : Type ?u.11069
s : Finmap β
f : AList β → γ
H : ∀ (a b : AList β), a.entries ~ b.entries → f a = f b
⊢ (Quotient.liftOn s.entries (fun l => { Dom := NodupKeys l, get := fun nd => f { entries := l, nodupKeys := nd } })
      (_ :
        ∀ (l₁ l₂ : List (Sigma β)),
          l₁ ≈ l₂ →
            (fun l => { Dom := NodupKeys l, get := fun nd => f { entries := l, nodupKeys := nd } }) l₁ =
              (fun l => { Dom := NodupKeys l, get := fun nd => f { entries := l, nodupKeys := nd } }) l₂)).Dom

Next tactic:
have := s.nodupKeys
/-- Lift a permutation-respecting function on `AList` to `Finmap`. -/
-- @[elab_as_elim] Porting note: we can't add `elab_as_elim` attr in this type
def liftOn {γ} (s : Finmap β) (f : AList β → γ)
    (H : ∀ a b : AList β, a.entries ~ b.entries → f a = f b) : γ := by
  refine'
    (Quotient.liftOn s.entries
      (fun (l : List (Sigma β)) => (⟨_, fun nd => f ⟨l, nd⟩⟩ : Part γ))
      (fun l₁ l₂ p => Part.ext' (perm_nodupKeys p) _) : Part γ).get _
  · exact fun h1 h2 => H _ _ p
  · have := s.nodupKeys
    -- Porting note: `revert` required because `rcases` behaves differently
    

Proof state:
case refine'_2
α : Type u
β : α → Type v
γ : Type ?u.11069
s : Finmap β
f : AList β → γ
H : ∀ (a b : AList β), a.entries ~ b.entries → f a = f b
this : Multiset.NodupKeys s.entries
⊢ (Quotient.liftOn s.entries (fun l => { Dom := NodupKeys l, get := fun nd => f { entries := l, nodupKeys := nd } })
      (_ :
        ∀ (l₁ l₂ : List (Sigma β)),
          l₁ ≈ l₂ →
            (fun l => { Dom := NodupKeys l, get := fun nd => f { entries := l, nodupKeys := nd } }) l₁ =
              (fun l => { Dom := NodupKeys l, get := fun nd => f { entries := l, nodupKeys := nd } }) l₂)).Dom

Next tactic:
revert this
/-- Lift a permutation-respecting function on `AList` to `Finmap`. -/
-- @[elab_as_elim] Porting note: we can't add `elab_as_elim` attr in this type
def liftOn {γ} (s : Finmap β) (f : AList β → γ)
    (H : ∀ a b : AList β, a.entries ~ b.entries → f a = f b) : γ := by
  refine'
    (Quotient.liftOn s.entries
      (fun (l : List (Sigma β)) => (⟨_, fun nd => f ⟨l, nd⟩⟩ : Part γ))
      (fun l₁ l₂ p => Part.ext' (perm_nodupKeys p) _) : Part γ).get _
  · exact fun h1 h2 => H _ _ p
  · have := s.nodupKeys
    -- Porting note: `revert` required because `rcases` behaves differently
    revert this
    

Proof state:
case refine'_2
α : Type u
β : α → Type v
γ : Type ?u.11069
s : Finmap β
f : AList β → γ
H : ∀ (a b : AList β), a.entries ~ b.entries → f a = f b
⊢ Multiset.NodupKeys s.entries →
    (Quotient.liftOn s.entries (fun l => { Dom := NodupKeys l, get := fun nd => f { entries := l, nodupKeys := nd } })
        (_ :
          ∀ (l₁ l₂ : List (Sigma β)),
            l₁ ≈ l₂ →
              (fun l => { Dom := NodupKeys l, get := fun nd => f { entries := l, nodupKeys := nd } }) l₁ =
                (fun l => { Dom := NodupKeys l, get := fun nd => f { entries := l, nodupKeys := nd } }) l₂)).Dom

Next tactic:
rcases s.entries with ⟨l⟩
/-- Lift a permutation-respecting function on `AList` to `Finmap`. -/
-- @[elab_as_elim] Porting note: we can't add `elab_as_elim` attr in this type
def liftOn {γ} (s : Finmap β) (f : AList β → γ)
    (H : ∀ a b : AList β, a.entries ~ b.entries → f a = f b) : γ := by
  refine'
    (Quotient.liftOn s.entries
      (fun (l : List (Sigma β)) => (⟨_, fun nd => f ⟨l, nd⟩⟩ : Part γ))
      (fun l₁ l₂ p => Part.ext' (perm_nodupKeys p) _) : Part γ).get _
  · exact fun h1 h2 => H _ _ p
  · have := s.nodupKeys
    -- Porting note: `revert` required because `rcases` behaves differently
    revert this
    rcases s.entries with ⟨l⟩
    

Proof state:
case refine'_2.mk
α : Type u
β : α → Type v
γ : Type ?u.11069
s : Finmap β
f : AList β → γ
H : ∀ (a b : AList β), a.entries ~ b.entries → f a = f b
x✝ : Multiset (Sigma β)
l : List (Sigma β)
⊢ Multiset.NodupKeys (Quot.mk Setoid.r l) →
    (Quotient.liftOn (Quot.mk Setoid.r l)
        (fun l => { Dom := NodupKeys l, get := fun nd => f { entries := l, nodupKeys := nd } })
        (_ :
          ∀ (l₁ l₂ : List (Sigma β)),
            l₁ ≈ l₂ →
              (fun l => { Dom := NodupKeys l, get := fun nd => f { entries := l, nodupKeys := nd } }) l₁ =
                (fun l => { Dom := NodupKeys l, get := fun nd => f { entries := l, nodupKeys := nd } }) l₂)).Dom

Next tactic:
exact id
@[simp]
theorem liftOn_toFinmap {γ} (s : AList β) (f : AList β → γ) (H) : liftOn ⟦s⟧ f H = f s := by
  

Proof state:
α : Type u
β : α → Type v
γ : Type u_1
s : AList β
f : AList β → γ
H : ∀ (a b : AList β), a.entries ~ b.entries → f a = f b
⊢ liftOn ⟦s⟧ f H = f s

Next tactic:
cases s
@[simp]
theorem liftOn_toFinmap {γ} (s : AList β) (f : AList β → γ) (H) : liftOn ⟦s⟧ f H = f s := by
  cases s
  

Proof state:
case mk
α : Type u
β : α → Type v
γ : Type u_1
f : AList β → γ
H : ∀ (a b : AList β), a.entries ~ b.entries → f a = f b
entries✝ : List (Sigma β)
nodupKeys✝ : NodupKeys entries✝
⊢ liftOn ⟦{ entries := entries✝, nodupKeys := nodupKeys✝ }⟧ f H = f { entries := entries✝, nodupKeys := nodupKeys✝ }

Next tactic:
rfl
/-- Lift a permutation-respecting function on 2 `AList`s to 2 `Finmap`s. -/
-- @[elab_as_elim] Porting note: we can't add `elab_as_elim` attr in this type
def liftOn₂ {γ} (s₁ s₂ : Finmap β) (f : AList β → AList β → γ)
    (H : ∀ a₁ b₁ a₂ b₂ : AList β,
      a₁.entries ~ a₂.entries → b₁.entries ~ b₂.entries → f a₁ b₁ = f a₂ b₂) : γ :=
  liftOn s₁ (fun l₁ => liftOn s₂ (f l₁) fun b₁ b₂ p => H _ _ _ _ (Perm.refl _) p) fun a₁ a₂ p => by
    

Proof state:
α : Type u
β : α → Type v
γ : Type ?u.20108
s₁ s₂ : Finmap β
f : AList β → AList β → γ
H : ∀ (a₁ b₁ a₂ b₂ : AList β), a₁.entries ~ a₂.entries → b₁.entries ~ b₂.entries → f a₁ b₁ = f a₂ b₂
a₁ a₂ : AList β
p : a₁.entries ~ a₂.entries
⊢ (fun l₁ => liftOn s₂ (f l₁) (_ : ∀ (b₁ b₂ : AList β), b₁.entries ~ b₂.entries → f l₁ b₁ = f l₁ b₂)) a₁ =
    (fun l₁ => liftOn s₂ (f l₁) (_ : ∀ (b₁ b₂ : AList β), b₁.entries ~ b₂.entries → f l₁ b₁ = f l₁ b₂)) a₂

Next tactic:
have H' : f a₁ = f a₂ := funext fun _ => H _ _ _ _ p (Perm.refl _)