l3lab/ntp-mathlib huggingface dataset:
theorem Quotient.finChoice_eq {ι : Type*} [DecidableEq ι] [Fintype ι] {α : ι → Type*}
    [∀ i, Setoid (α i)] (f : ∀ i, α i) : (Quotient.finChoice fun i => ⟦f i⟧) = ⟦f⟧ := by
  dsimp only [Quotient.finChoice]
  conv_lhs =>
    

Proof state:
ι : Type u_1
inst✝² : DecidableEq ι
inst✝¹ : Fintype ι
α : ι → Type u_2
inst✝ : (i : ι) → Setoid (α i)
f : (i : ι) → α i
| Quotient.liftOn
    (Quotient.recOn Finset.univ.val (fun l => finChoiceAux l fun i x => ⟦f i⟧)
      (_ :
        ∀ (a b : List ι) (h : a ≈ b),
          (_ : ⟦a⟧ = ⟦b⟧) ▸ (fun l => finChoiceAux l fun i x => ⟦f i⟧) a =
            (fun l => finChoiceAux l fun i x => ⟦f i⟧) b))
    (fun f => ⟦fun i => f i (_ : i ∈ Finset.univ)⟧)
    (_ :
      ∀ (a b : (i : ι) → i ∈ Finset.univ.val → α i),
        a ≈ b → ⟦fun i => a i (_ : i ∈ Finset.univ)⟧ = ⟦fun i => b i (_ : i ∈ Finset.univ)⟧)

Next tactic:
enter [1]
theorem Quotient.finChoice_eq {ι : Type*} [DecidableEq ι] [Fintype ι] {α : ι → Type*}
    [∀ i, Setoid (α i)] (f : ∀ i, α i) : (Quotient.finChoice fun i => ⟦f i⟧) = ⟦f⟧ := by
  dsimp only [Quotient.finChoice]
  conv_lhs =>
    enter [1]
    

Proof state:
ι : Type u_1
inst✝² : DecidableEq ι
inst✝¹ : Fintype ι
α : ι → Type u_2
inst✝ : (i : ι) → Setoid (α i)
f : (i : ι) → α i
| Quotient.recOn Finset.univ.val (fun l => finChoiceAux l fun i x => ⟦f i⟧)
    (_ :
      ∀ (a b : List ι) (h : a ≈ b),
        (_ : ⟦a⟧ = ⟦b⟧) ▸ (fun l => finChoiceAux l fun i x => ⟦f i⟧) a = (fun l => finChoiceAux l fun i x => ⟦f i⟧) b)

Next tactic:
tactic =>
      change _ = ⟦fun i _ => f i⟧
      exact Quotient.inductionOn (@Finset.univ ι _).1 fun l => Quotient.finChoiceAux_eq _ _
theorem Quotient.finChoice_eq {ι : Type*} [DecidableEq ι] [Fintype ι] {α : ι → Type*}
    [∀ i, Setoid (α i)] (f : ∀ i, α i) : (Quotient.finChoice fun i => ⟦f i⟧) = ⟦f⟧ := by
  dsimp only [Quotient.finChoice]
  conv_lhs =>
    enter [1]
    tactic =>
      

Proof state:
ι : Type u_1
inst✝² : DecidableEq ι
inst✝¹ : Fintype ι
α : ι → Type u_2
inst✝ : (i : ι) → Setoid (α i)
f : (i : ι) → α i
⊢ Quotient.recOn Finset.univ.val (fun l => finChoiceAux l fun i x => ⟦f i⟧)
      (_ :
        ∀ (a b : List ι) (h : a ≈ b),
          (_ : ⟦a⟧ = ⟦b⟧) ▸ (fun l => finChoiceAux l fun i x => ⟦f i⟧) a =
            (fun l => finChoiceAux l fun i x => ⟦f i⟧) b) =
    ?m.10074

Next tactic:
change _ = ⟦fun i _ => f i⟧
theorem Quotient.finChoice_eq {ι : Type*} [DecidableEq ι] [Fintype ι] {α : ι → Type*}
    [∀ i, Setoid (α i)] (f : ∀ i, α i) : (Quotient.finChoice fun i => ⟦f i⟧) = ⟦f⟧ := by
  dsimp only [Quotient.finChoice]
  conv_lhs =>
    enter [1]
    tactic =>
      change _ = ⟦fun i _ => f i⟧
      

Proof state:
ι : Type u_1
inst✝² : DecidableEq ι
inst✝¹ : Fintype ι
α : ι → Type u_2
inst✝ : (i : ι) → Setoid (α i)
f : (i : ι) → α i
⊢ Quotient.recOn Finset.univ.val (fun l => finChoiceAux l fun i x => ⟦f i⟧)
      (_ :
        ∀ (a b : List ι) (h : a ≈ b),
          (_ : ⟦a⟧ = ⟦b⟧) ▸ (fun l => finChoiceAux l fun i x => ⟦f i⟧) a =
            (fun l => finChoiceAux l fun i x => ⟦f i⟧) b) =
    ⟦fun i x => f i⟧

Next tactic:
exact Quotient.inductionOn (@Finset.univ ι _).1 fun l => Quotient.finChoiceAux_eq _ _
@[simp]
theorem flag_zero (b : Basis (Fin n) R M) : b.flag 0 = ⊥ := by 

Proof state:
R : Type u_1
M : Type u_2
inst✝² : Semiring R
inst✝¹ : AddCommMonoid M
inst✝ : Module R M
n : ℕ
b : Basis (Fin n) R M
⊢ flag b 0 = ⊥

Next tactic:
simp [flag]
@[simp]
theorem flag_last (b : Basis (Fin n) R M) : b.flag (.last n) = ⊤ := by
  

Proof state:
R : Type u_1
M : Type u_2
inst✝² : Semiring R
inst✝¹ : AddCommMonoid M
inst✝ : Module R M
n : ℕ
b : Basis (Fin n) R M
⊢ flag b (Fin.last n) = ⊤

Next tactic:
simp [flag, Fin.castSucc_lt_last]
theorem flag_succ (b : Basis (Fin n) R M) (k : Fin n) :
    b.flag k.succ = (R ∙ b k) ⊔ b.flag k.castSucc := by
  

Proof state:
R : Type u_1
M : Type u_2
inst✝² : Semiring R
inst✝¹ : AddCommMonoid M
inst✝ : Module R M
n : ℕ
b : Basis (Fin n) R M
k : Fin n
⊢ flag b (Fin.succ k) = span R {b k} ⊔ flag b (Fin.castSucc k)

Next tactic:
simp only [flag, Fin.castSucc_lt_castSucc_iff]
theorem flag_succ (b : Basis (Fin n) R M) (k : Fin n) :
    b.flag k.succ = (R ∙ b k) ⊔ b.flag k.castSucc := by
  simp only [flag, Fin.castSucc_lt_castSucc_iff]
  

Proof state:
R : Type u_1
M : Type u_2
inst✝² : Semiring R
inst✝¹ : AddCommMonoid M
inst✝ : Module R M
n : ℕ
b : Basis (Fin n) R M
k : Fin n
⊢ span R (⇑b '' {i | Fin.castSucc i < Fin.succ k}) = span R {b k} ⊔ span R (⇑b '' {i | i < k})

Next tactic:
simp [Fin.castSucc_lt_iff_succ_le, le_iff_eq_or_lt, setOf_or, image_insert_eq, span_insert]
@[mono]
theorem flag_mono (b : Basis (Fin n) R M) : Monotone b.flag :=
  Fin.monotone_iff_le_succ.2 fun k ↦ by 

Proof state:
R : Type u_1
M : Type u_2
inst✝² : Semiring R
inst✝¹ : AddCommMonoid M
inst✝ : Module R M
n : ℕ
b : Basis (Fin n) R M
k : Fin n
⊢ flag b (Fin.castSucc k) ≤ flag b (Fin.succ k)

Next tactic:
rw [flag_succ]
@[mono]
theorem flag_mono (b : Basis (Fin n) R M) : Monotone b.flag :=
  Fin.monotone_iff_le_succ.2 fun k ↦ by rw [flag_succ]; 

Proof state:
R : Type u_1
M : Type u_2
inst✝² : Semiring R
inst✝¹ : AddCommMonoid M
inst✝ : Module R M
n : ℕ
b : Basis (Fin n) R M
k : Fin n
⊢ flag b (Fin.castSucc k) ≤ span R {b k} ⊔ flag b (Fin.castSucc k)

Next tactic:
exact le_sup_right
@[mono]
theorem flag_strictMono [Nontrivial R] (b : Basis (Fin n) R M) : StrictMono b.flag :=
  Fin.strictMono_iff_lt_succ.2 fun _ ↦ by 

Proof state:
R : Type u_1
M : Type u_2
inst✝³ : Semiring R
inst✝² : AddCommMonoid M
inst✝¹ : Module R M
n : ℕ
inst✝ : Nontrivial R
b : Basis (Fin n) R M
x✝ : Fin n
⊢ flag b (Fin.castSucc x✝) < flag b (Fin.succ x✝)

Next tactic:
simp [flag_succ]
@[simp]
theorem flag_le_ker_coord_iff [Nontrivial R] (b : Basis (Fin n) R M) {k : Fin (n + 1)} {l : Fin n} :
    b.flag k ≤ LinearMap.ker (b.coord l) ↔ k ≤ l.castSucc := by
  

Proof state:
R : Type u_1
M : Type u_2
inst✝³ : CommRing R
inst✝² : AddCommGroup M
inst✝¹ : Module R M
n : ℕ
inst✝ : Nontrivial R
b : Basis (Fin n) R M
k : Fin (n + 1)
l : Fin n
⊢ flag b k ≤ LinearMap.ker (coord b l) ↔ k ≤ Fin.castSucc l

Next tactic:
simp [flag_le_iff, Finsupp.single_apply_eq_zero, imp_false, imp_not_comm]
theorem flag_le_ker_coord (b : Basis (Fin n) R M) {k : Fin (n + 1)} {l : Fin n}
    (h : k ≤ l.castSucc) : b.flag k ≤ LinearMap.ker (b.coord l) := by
  

Proof state:
R : Type u_1
M : Type u_2
inst✝² : CommRing R
inst✝¹ : AddCommGroup M
inst✝ : Module R M
n : ℕ
b : Basis (Fin n) R M
k : Fin (n + 1)
l : Fin n
h : k ≤ Fin.castSucc l
⊢ flag b k ≤ LinearMap.ker (coord b l)

Next tactic:
nontriviality R
theorem flag_le_ker_coord (b : Basis (Fin n) R M) {k : Fin (n + 1)} {l : Fin n}
    (h : k ≤ l.castSucc) : b.flag k ≤ LinearMap.ker (b.coord l) := by
  nontriviality R
  

Proof state:
R : Type u_1
M : Type u_2
inst✝² : CommRing R
inst✝¹ : AddCommGroup M
inst✝ : Module R M
n : ℕ
b : Basis (Fin n) R M
k : Fin (n + 1)
l : Fin n
h : k ≤ Fin.castSucc l
✝ : Nontrivial R
⊢ flag b k ≤ LinearMap.ker (coord b l)

Next tactic:
exact b.flag_le_ker_coord_iff.2 h
theorem flag_covby (b : Basis (Fin n) K V) (i : Fin n) :
    b.flag i.castSucc ⋖ b.flag i.succ := by
  

Proof state:
K : Type u_1
V : Type u_2
inst✝² : DivisionRing K
inst✝¹ : AddCommGroup V
inst✝ : Module K V
n : ℕ
b : Basis (Fin n) K V
i : Fin n
⊢ flag b (Fin.castSucc i) ⋖ flag b (Fin.succ i)

Next tactic:
rw [flag_succ]
theorem flag_covby (b : Basis (Fin n) K V) (i : Fin n) :
    b.flag i.castSucc ⋖ b.flag i.succ := by
  rw [flag_succ]
  

Proof state:
K : Type u_1
V : Type u_2
inst✝² : DivisionRing K
inst✝¹ : AddCommGroup V
inst✝ : Module K V
n : ℕ
b : Basis (Fin n) K V
i : Fin n
⊢ flag b (Fin.castSucc i) ⋖ span K {b i} ⊔ flag b (Fin.castSucc i)

Next tactic:
apply covby_span_singleton_sup
theorem flag_covby (b : Basis (Fin n) K V) (i : Fin n) :
    b.flag i.castSucc ⋖ b.flag i.succ := by
  rw [flag_succ]
  apply covby_span_singleton_sup
  

Proof state:
case h
K : Type u_1
V : Type u_2
inst✝² : DivisionRing K
inst✝¹ : AddCommGroup V
inst✝ : Module K V
n : ℕ
b : Basis (Fin n) K V
i : Fin n
⊢ b i ∉ flag b (Fin.castSucc i)

Next tactic:
simp
/-- If `X : C` is projective and `n : ℕ`, then `Ext^(n + 1) X Y ≅ 0` for any `Y`. -/
lemma isZero_Ext_succ_of_projective (X Y : C) [Projective X] (n : ℕ) :
    IsZero (((Ext R C (n + 1)).obj (Opposite.op X)).obj Y) := by
  

Proof state:
R : Type u_1
inst✝⁵ : Ring R
C : Type u_2
inst✝⁴ : Category.{u_3, u_2} C
inst✝³ : Abelian C
inst✝² : Linear R C
inst✝¹ : EnoughProjectives C
X Y : C
inst✝ : Projective X
n : ℕ
⊢ IsZero (((Ext R C (n + 1)).obj (Opposite.op X)).obj Y)

Next tactic:
refine IsZero.of_iso ?_ ((ProjectiveResolution.self X).isoExt (n + 1) Y)
/-- If `X : C` is projective and `n : ℕ`, then `Ext^(n + 1) X Y ≅ 0` for any `Y`. -/
lemma isZero_Ext_succ_of_projective (X Y : C) [Projective X] (n : ℕ) :
    IsZero (((Ext R C (n + 1)).obj (Opposite.op X)).obj Y) := by
  refine IsZero.of_iso ?_ ((ProjectiveResolution.self X).isoExt (n + 1) Y)
  

Proof state:
R : Type u_1
inst✝⁵ : Ring R
C : Type u_2
inst✝⁴ : Category.{u_3, u_2} C
inst✝³ : Abelian C
inst✝² : Linear R C
inst✝¹ : EnoughProjectives C
X Y : C
inst✝ : Projective X
n : ℕ
⊢ IsZero (HomologicalComplex.homology (ChainComplex.linearYonedaObj (ProjectiveResolution.self X).complex R Y) (n + 1))

Next tactic:
rw [← HomologicalComplex.exactAt_iff_isZero_homology, HomologicalComplex.exactAt_iff]
/-- If `X : C` is projective and `n : ℕ`, then `Ext^(n + 1) X Y ≅ 0` for any `Y`. -/
lemma isZero_Ext_succ_of_projective (X Y : C) [Projective X] (n : ℕ) :
    IsZero (((Ext R C (n + 1)).obj (Opposite.op X)).obj Y) := by
  refine IsZero.of_iso ?_ ((ProjectiveResolution.self X).isoExt (n + 1) Y)
  rw [← HomologicalComplex.exactAt_iff_isZero_homology, HomologicalComplex.exactAt_iff]
  

Proof state:
R : Type u_1
inst✝⁵ : Ring R
C : Type u_2
inst✝⁴ : Category.{u_3, u_2} C
inst✝³ : Abelian C
inst✝² : Linear R C
inst✝¹ : EnoughProjectives C
X Y : C
inst✝ : Projective X
n : ℕ
⊢ ShortComplex.Exact
    (HomologicalComplex.sc (ChainComplex.linearYonedaObj (ProjectiveResolution.self X).complex R Y) (n + 1))

Next tactic:
refine ShortComplex.exact_of_isZero_X₂ _ ?_
/-- If `X : C` is projective and `n : ℕ`, then `Ext^(n + 1) X Y ≅ 0` for any `Y`. -/
lemma isZero_Ext_succ_of_projective (X Y : C) [Projective X] (n : ℕ) :
    IsZero (((Ext R C (n + 1)).obj (Opposite.op X)).obj Y) := by
  refine IsZero.of_iso ?_ ((ProjectiveResolution.self X).isoExt (n + 1) Y)
  rw [← HomologicalComplex.exactAt_iff_isZero_homology, HomologicalComplex.exactAt_iff]
  refine ShortComplex.exact_of_isZero_X₂ _ ?_
  

Proof state:
R : Type u_1
inst✝⁵ : Ring R
C : Type u_2
inst✝⁴ : Category.{u_3, u_2} C
inst✝³ : Abelian C
inst✝² : Linear R C
inst✝¹ : EnoughProjectives C
X Y : C
inst✝ : Projective X
n : ℕ
⊢ IsZero (HomologicalComplex.sc (ChainComplex.linearYonedaObj (ProjectiveResolution.self X).complex R Y) (n + 1)).X₂

Next tactic:
dsimp
/-- If `X : C` is projective and `n : ℕ`, then `Ext^(n + 1) X Y ≅ 0` for any `Y`. -/
lemma isZero_Ext_succ_of_projective (X Y : C) [Projective X] (n : ℕ) :
    IsZero (((Ext R C (n + 1)).obj (Opposite.op X)).obj Y) := by
  refine IsZero.of_iso ?_ ((ProjectiveResolution.self X).isoExt (n + 1) Y)
  rw [← HomologicalComplex.exactAt_iff_isZero_homology, HomologicalComplex.exactAt_iff]
  refine ShortComplex.exact_of_isZero_X₂ _ ?_
  dsimp
  

Proof state:
R : Type u_1
inst✝⁵ : Ring R
C : Type u_2
inst✝⁴ : Category.{u_3, u_2} C
inst✝³ : Abelian C
inst✝² : Linear R C
inst✝¹ : EnoughProjectives C
X Y : C
inst✝ : Projective X
n : ℕ
⊢ IsZero (ModuleCat.of R (HomologicalComplex.X ((ChainComplex.single₀ C).obj X) (n + 1) ⟶ Y))

Next tactic:
rw [IsZero.iff_id_eq_zero]
/-- If `X : C` is projective and `n : ℕ`, then `Ext^(n + 1) X Y ≅ 0` for any `Y`. -/
lemma isZero_Ext_succ_of_projective (X Y : C) [Projective X] (n : ℕ) :
    IsZero (((Ext R C (n + 1)).obj (Opposite.op X)).obj Y) := by
  refine IsZero.of_iso ?_ ((ProjectiveResolution.self X).isoExt (n + 1) Y)
  rw [← HomologicalComplex.exactAt_iff_isZero_homology, HomologicalComplex.exactAt_iff]
  refine ShortComplex.exact_of_isZero_X₂ _ ?_
  dsimp
  rw [IsZero.iff_id_eq_zero]
  

Proof state:
R : Type u_1
inst✝⁵ : Ring R
C : Type u_2
inst✝⁴ : Category.{u_3, u_2} C
inst✝³ : Abelian C
inst✝² : Linear R C
inst✝¹ : EnoughProjectives C
X Y : C
inst✝ : Projective X
n : ℕ
⊢ 𝟙 (ModuleCat.of R (HomologicalComplex.X ((ChainComplex.single₀ C).obj X) (n + 1) ⟶ Y)) = 0

Next tactic:
ext (x : _ ⟶ _)
/-- If `X : C` is projective and `n : ℕ`, then `Ext^(n + 1) X Y ≅ 0` for any `Y`. -/
lemma isZero_Ext_succ_of_projective (X Y : C) [Projective X] (n : ℕ) :
    IsZero (((Ext R C (n + 1)).obj (Opposite.op X)).obj Y) := by
  refine IsZero.of_iso ?_ ((ProjectiveResolution.self X).isoExt (n + 1) Y)
  rw [← HomologicalComplex.exactAt_iff_isZero_homology, HomologicalComplex.exactAt_iff]
  refine ShortComplex.exact_of_isZero_X₂ _ ?_
  dsimp
  rw [IsZero.iff_id_eq_zero]
  ext (x : _ ⟶ _)
  

Proof state:
case h
R : Type u_1
inst✝⁵ : Ring R
C : Type u_2
inst✝⁴ : Category.{u_3, u_2} C
inst✝³ : Abelian C
inst✝² : Linear R C
inst✝¹ : EnoughProjectives C
X Y : C
inst✝ : Projective X
n : ℕ
x : HomologicalComplex.X ((ChainComplex.single₀ C).obj X) (n + 1) ⟶ Y
⊢ (𝟙 (ModuleCat.of R (HomologicalComplex.X ((ChainComplex.single₀ C).obj X) (n + 1) ⟶ Y))) x = 0 x

Next tactic:
obtain rfl : x = 0 := (HomologicalComplex.isZero_single_obj_X
    (ComplexShape.down ℕ) 0 X (n + 1) (by simp)).eq_of_src _ _
/-- If `X : C` is projective and `n : ℕ`, then `Ext^(n + 1) X Y ≅ 0` for any `Y`. -/
lemma isZero_Ext_succ_of_projective (X Y : C) [Projective X] (n : ℕ) :
    IsZero (((Ext R C (n + 1)).obj (Opposite.op X)).obj Y) := by
  refine IsZero.of_iso ?_ ((ProjectiveResolution.self X).isoExt (n + 1) Y)
  rw [← HomologicalComplex.exactAt_iff_isZero_homology, HomologicalComplex.exactAt_iff]
  refine ShortComplex.exact_of_isZero_X₂ _ ?_
  dsimp
  rw [IsZero.iff_id_eq_zero]
  ext (x : _ ⟶ _)
  obtain rfl : x = 0 := (HomologicalComplex.isZero_single_obj_X
    (ComplexShape.down ℕ) 0 X (n + 1) (by 

Proof state:
R : Type u_1
inst✝⁵ : Ring R
C : Type u_2
inst✝⁴ : Category.{u_3, u_2} C
inst✝³ : Abelian C
inst✝² : Linear R C
inst✝¹ : EnoughProjectives C
X Y : C
inst✝ : Projective X
n : ℕ
x : HomologicalComplex.X ((ChainComplex.single₀ C).obj X) (n + 1) ⟶ Y
⊢ n + 1 ≠ 0

Next tactic:
simp
/-- If `X : C` is projective and `n : ℕ`, then `Ext^(n + 1) X Y ≅ 0` for any `Y`. -/
lemma isZero_Ext_succ_of_projective (X Y : C) [Projective X] (n : ℕ) :
    IsZero (((Ext R C (n + 1)).obj (Opposite.op X)).obj Y) := by
  refine IsZero.of_iso ?_ ((ProjectiveResolution.self X).isoExt (n + 1) Y)
  rw [← HomologicalComplex.exactAt_iff_isZero_homology, HomologicalComplex.exactAt_iff]
  refine ShortComplex.exact_of_isZero_X₂ _ ?_
  dsimp
  rw [IsZero.iff_id_eq_zero]
  ext (x : _ ⟶ _)
  obtain rfl : x = 0 := (HomologicalComplex.isZero_single_obj_X
    (ComplexShape.down ℕ) 0 X (n + 1) (by simp)).eq_of_src _ _
  

Proof state:
case h
R : Type u_1
inst✝⁵ : Ring R
C : Type u_2
inst✝⁴ : Category.{u_3, u_2} C
inst✝³ : Abelian C
inst✝² : Linear R C
inst✝¹ : EnoughProjectives C
X Y : C
inst✝ : Projective X
n : ℕ
⊢ (𝟙 (ModuleCat.of R (HomologicalComplex.X ((ChainComplex.single₀ C).obj X) (n + 1) ⟶ Y))) 0 = 0 0

Next tactic:
rfl
lemma unitsMap_comp {d : ℕ} (hm : n ∣ m) (hd : m ∣ d) :
    (unitsMap hm).comp (unitsMap hd) = unitsMap (dvd_trans hm hd) := by
  

Proof state:
n m d : ℕ
hm : n ∣ m
hd : m ∣ d
⊢ MonoidHom.comp (unitsMap hm) (unitsMap hd) = unitsMap (_ : n ∣ d)

Next tactic:
simp only [unitsMap_def]
lemma unitsMap_comp {d : ℕ} (hm : n ∣ m) (hd : m ∣ d) :
    (unitsMap hm).comp (unitsMap hd) = unitsMap (dvd_trans hm hd) := by
  simp only [unitsMap_def]
  

Proof state:
n m d : ℕ
hm : n ∣ m
hd : m ∣ d
⊢ MonoidHom.comp (Units.map ↑(castHom hm (ZMod n))) (Units.map ↑(castHom hd (ZMod m))) =
    Units.map ↑(castHom (_ : n ∣ d) (ZMod n))

Next tactic:
rw [← Units.map_comp]
lemma unitsMap_comp {d : ℕ} (hm : n ∣ m) (hd : m ∣ d) :
    (unitsMap hm).comp (unitsMap hd) = unitsMap (dvd_trans hm hd) := by
  simp only [unitsMap_def]
  rw [← Units.map_comp]
  

Proof state:
n m d : ℕ
hm : n ∣ m
hd : m ∣ d
⊢ Units.map (MonoidHom.comp ↑(castHom hm (ZMod n)) ↑(castHom hd (ZMod m))) = Units.map ↑(castHom (_ : n ∣ d) (ZMod n))

Next tactic:
exact congr_arg Units.map <| congr_arg RingHom.toMonoidHom <| castHom_comp hm hd
@[simp]
lemma unitsMap_self (n : ℕ) : unitsMap (dvd_refl n) = MonoidHom.id _ := by
  

Proof state:
n✝ m n : ℕ
⊢ unitsMap (_ : n ∣ n) = MonoidHom.id (ZMod n)ˣ

Next tactic:
simp [unitsMap, castHom_self]
/-- The relative product homotopy of `homotopies` between functions `f` and `g` -/
@[simps!]
def HomotopyRel.pi (homotopies : ∀ i : I, HomotopyRel (f i) (g i) S) :
    HomotopyRel (pi f) (pi g) S :=
  { Homotopy.pi fun i => (homotopies i).toHomotopy with
    prop' := by
      

Proof state:
I : Type u_1
A : Type u_2
X : I → Type u_3
inst✝¹ : (i : I) → TopologicalSpace (X i)
inst✝ : TopologicalSpace A
f g : (i : I) → C(A, X i)
S : Set A
homotopies : (i : I) → HomotopyRel (f i) (g i) S
src✝ : Homotopy (ContinuousMap.pi fun i => f i) (ContinuousMap.pi fun i => g i) :=
  Homotopy.pi fun i => (homotopies i).toHomotopy
⊢ ∀ (t : ↑unitInterval),
    ∀ x ∈ S,
      (mk fun x =>
            ContinuousMap.toFun
              { toContinuousMap := src✝.toContinuousMap,
                  map_zero_left :=
                    (_ :
                      ∀ (x : A), ContinuousMap.toFun src✝.toContinuousMap (0, x) = (ContinuousMap.pi fun i => f i) x),
                  map_one_left :=
                    (_ :
                      ∀ (x : A),
                        ContinuousMap.toFun src✝.toContinuousMap (1, x) =
                          (ContinuousMap.pi fun i => g i) x) }.toContinuousMap
              (t, x))
          x =
        (ContinuousMap.pi f) x

Next tactic:
intro t x hx
/-- The relative product homotopy of `homotopies` between functions `f` and `g` -/
@[simps!]
def HomotopyRel.pi (homotopies : ∀ i : I, HomotopyRel (f i) (g i) S) :
    HomotopyRel (pi f) (pi g) S :=
  { Homotopy.pi fun i => (homotopies i).toHomotopy with
    prop' := by
      intro t x hx
      

Proof state:
I : Type u_1
A : Type u_2
X : I → Type u_3
inst✝¹ : (i : I) → TopologicalSpace (X i)
inst✝ : TopologicalSpace A
f g : (i : I) → C(A, X i)
S : Set A
homotopies : (i : I) → HomotopyRel (f i) (g i) S
src✝ : Homotopy (ContinuousMap.pi fun i => f i) (ContinuousMap.pi fun i => g i) :=
  Homotopy.pi fun i => (homotopies i).toHomotopy
t : ↑unitInterval
x : A
hx : x ∈ S
⊢ (mk fun x =>
        ContinuousMap.toFun
          { toContinuousMap := src✝.toContinuousMap,
              map_zero_left :=
                (_ : ∀ (x : A), ContinuousMap.toFun src✝.toContinuousMap (0, x) = (ContinuousMap.pi fun i => f i) x),
              map_one_left :=
                (_ :
                  ∀ (x : A),
                    ContinuousMap.toFun src✝.toContinuousMap (1, x) =
                      (ContinuousMap.pi fun i => g i) x) }.toContinuousMap
          (t, x))
      x =
    (ContinuousMap.pi f) x

Next tactic:
dsimp only [coe_mk, pi_eval, toFun_eq_coe, HomotopyWith.coe_toContinuousMap]
/-- The relative product homotopy of `homotopies` between functions `f` and `g` -/
@[simps!]
def HomotopyRel.pi (homotopies : ∀ i : I, HomotopyRel (f i) (g i) S) :
    HomotopyRel (pi f) (pi g) S :=
  { Homotopy.pi fun i => (homotopies i).toHomotopy with
    prop' := by
      intro t x hx
      dsimp only [coe_mk, pi_eval, toFun_eq_coe, HomotopyWith.coe_toContinuousMap]
      

Proof state:
I : Type u_1
A : Type u_2
X : I → Type u_3
inst✝¹ : (i : I) → TopologicalSpace (X i)
inst✝ : TopologicalSpace A
f g : (i : I) → C(A, X i)
S : Set A
homotopies : (i : I) → HomotopyRel (f i) (g i) S
src✝ : Homotopy (ContinuousMap.pi fun i => f i) (ContinuousMap.pi fun i => g i) :=
  Homotopy.pi fun i => (homotopies i).toHomotopy
t : ↑unitInterval
x : A
hx : x ∈ S
⊢ (Homotopy.pi fun i => (homotopies i).toHomotopy).toContinuousMap (t, x) = fun i => (f i) x

Next tactic:
simp only [Function.funext_iff, ← forall_and]
/-- The relative product homotopy of `homotopies` between functions `f` and `g` -/
@[simps!]
def HomotopyRel.pi (homotopies : ∀ i : I, HomotopyRel (f i) (g i) S) :
    HomotopyRel (pi f) (pi g) S :=
  { Homotopy.pi fun i => (homotopies i).toHomotopy with
    prop' := by
      intro t x hx
      dsimp only [coe_mk, pi_eval, toFun_eq_coe, HomotopyWith.coe_toContinuousMap]
      simp only [Function.funext_iff, ← forall_and]
      

Proof state:
I : Type u_1
A : Type u_2
X : I → Type u_3
inst✝¹ : (i : I) → TopologicalSpace (X i)
inst✝ : TopologicalSpace A
f g : (i : I) → C(A, X i)
S : Set A
homotopies : (i : I) → HomotopyRel (f i) (g i) S
src✝ : Homotopy (ContinuousMap.pi fun i => f i) (ContinuousMap.pi fun i => g i) :=
  Homotopy.pi fun i => (homotopies i).toHomotopy
t : ↑unitInterval
x : A
hx : x ∈ S
⊢ ∀ (a : I), (Homotopy.pi fun i => (homotopies i).toHomotopy).toContinuousMap (t, x) a = (f a) x

Next tactic:
intro i
/-- The relative product homotopy of `homotopies` between functions `f` and `g` -/
@[simps!]
def HomotopyRel.pi (homotopies : ∀ i : I, HomotopyRel (f i) (g i) S) :
    HomotopyRel (pi f) (pi g) S :=
  { Homotopy.pi fun i => (homotopies i).toHomotopy with
    prop' := by
      intro t x hx
      dsimp only [coe_mk, pi_eval, toFun_eq_coe, HomotopyWith.coe_toContinuousMap]
      simp only [Function.funext_iff, ← forall_and]
      intro i
      

Proof state:
I : Type u_1
A : Type u_2
X : I → Type u_3
inst✝¹ : (i : I) → TopologicalSpace (X i)
inst✝ : TopologicalSpace A
f g : (i : I) → C(A, X i)
S : Set A
homotopies : (i : I) → HomotopyRel (f i) (g i) S
src✝ : Homotopy (ContinuousMap.pi fun i => f i) (ContinuousMap.pi fun i => g i) :=
  Homotopy.pi fun i => (homotopies i).toHomotopy
t : ↑unitInterval
x : A
hx : x ∈ S
i : I
⊢ (Homotopy.pi fun i => (homotopies i).toHomotopy).toContinuousMap (t, x) i = (f i) x

Next tactic:
exact (homotopies i).prop' t x hx
/-- The product of homotopies `F` and `G`,
  where `F` takes `f₀` to `f₁` and `G` takes `g₀` to `g₁` -/
@[simps]
def Homotopy.prod (F : Homotopy f₀ f₁) (G : Homotopy g₀ g₁) :
    Homotopy (ContinuousMap.prodMk f₀ g₀) (ContinuousMap.prodMk f₁ g₁) where
  toFun t := (F t, G t)
  map_zero_left x := by 

Proof state:
α : Type u_1
β : Type u_2
inst✝² : TopologicalSpace α
inst✝¹ : TopologicalSpace β
A : Type u_3
inst✝ : TopologicalSpace A
f₀ f₁ : C(A, α)
g₀ g₁ : C(A, β)
S : Set A
F : Homotopy f₀ f₁
G : Homotopy g₀ g₁
x : A
⊢ ContinuousMap.toFun (ContinuousMap.mk fun t => (F t, G t)) (0, x) = (ContinuousMap.prodMk f₀ g₀) x

Next tactic:
simp only [prod_eval, Homotopy.apply_zero]
/-- The product of homotopies `F` and `G`,
  where `F` takes `f₀` to `f₁` and `G` takes `g₀` to `g₁` -/
@[simps]
def Homotopy.prod (F : Homotopy f₀ f₁) (G : Homotopy g₀ g₁) :
    Homotopy (ContinuousMap.prodMk f₀ g₀) (ContinuousMap.prodMk f₁ g₁) where
  toFun t := (F t, G t)
  map_zero_left x := by simp only [prod_eval, Homotopy.apply_zero]
  map_one_left x := by 

Proof state:
α : Type u_1
β : Type u_2
inst✝² : TopologicalSpace α
inst✝¹ : TopologicalSpace β
A : Type u_3
inst✝ : TopologicalSpace A
f₀ f₁ : C(A, α)
g₀ g₁ : C(A, β)
S : Set A
F : Homotopy f₀ f₁
G : Homotopy g₀ g₁
x : A
⊢ ContinuousMap.toFun (ContinuousMap.mk fun t => (F t, G t)) (1, x) = (ContinuousMap.prodMk f₁ g₁) x

Next tactic:
simp only [prod_eval, Homotopy.apply_one]
theorem pi_lift (γ : ∀ i, Path (as i) (bs i)) :
    (Path.Homotopic.pi fun i => ⟦γ i⟧) = ⟦Path.pi γ⟧ := by 

Proof state:
ι : Type u_1
X : ι → Type u_2
inst✝ : (i : ι) → TopologicalSpace (X i)
as bs cs : (i : ι) → X i
γ : (i : ι) → Path (as i) (bs i)
⊢ (pi fun i => ⟦γ i⟧) = ⟦Path.pi γ⟧

Next tactic:
unfold pi
theorem pi_lift (γ : ∀ i, Path (as i) (bs i)) :
    (Path.Homotopic.pi fun i => ⟦γ i⟧) = ⟦Path.pi γ⟧ := by unfold pi; 

Proof state:
ι : Type u_1
X : ι → Type u_2
inst✝ : (i : ι) → TopologicalSpace (X i)
as bs cs : (i : ι) → X i
γ : (i : ι) → Path (as i) (bs i)
⊢ Quotient.map Path.pi (_ : ∀ (x y : (i : ι) → Path (as i) (bs i)), x ≈ y → Nonempty (Homotopy (Path.pi x) (Path.pi y)))
      (Quotient.choice fun i => ⟦γ i⟧) =
    ⟦Path.pi γ⟧

Next tactic:
simp