l3lab/ntp-mathlib huggingface dataset:
/-- The group homomorphism from `Gamma0` to `ZMod N` given by mapping a matrix to its lower
right-hand entry. -/
def Gamma0Map (N : ℕ) : Gamma0 N →* ZMod N where
  toFun g := ((↑ₘg 1 1 : ℤ) : ZMod N)
  map_one' := by simp
  map_mul' := by
    

Proof state:
N✝ N : ℕ
⊢ ∀ (x y : ↥(Gamma0 N)),
    OneHom.toFun { toFun := fun g => ↑(↑↑g 1 1), map_one' := (_ : ↑(OfNat.ofNat 1 1 1) = 1) } (x * y) =
      OneHom.toFun { toFun := fun g => ↑(↑↑g 1 1), map_one' := (_ : ↑(OfNat.ofNat 1 1 1) = 1) } x *
        OneHom.toFun { toFun := fun g => ↑(↑↑g 1 1), map_one' := (_ : ↑(OfNat.ofNat 1 1 1) = 1) } y

Next tactic:
intro A B
/-- The group homomorphism from `Gamma0` to `ZMod N` given by mapping a matrix to its lower
right-hand entry. -/
def Gamma0Map (N : ℕ) : Gamma0 N →* ZMod N where
  toFun g := ((↑ₘg 1 1 : ℤ) : ZMod N)
  map_one' := by simp
  map_mul' := by
    intro A B
    

Proof state:
N✝ N : ℕ
A B : ↥(Gamma0 N)
⊢ OneHom.toFun { toFun := fun g => ↑(↑↑g 1 1), map_one' := (_ : ↑(OfNat.ofNat 1 1 1) = 1) } (A * B) =
    OneHom.toFun { toFun := fun g => ↑(↑↑g 1 1), map_one' := (_ : ↑(OfNat.ofNat 1 1 1) = 1) } A *
      OneHom.toFun { toFun := fun g => ↑(↑↑g 1 1), map_one' := (_ : ↑(OfNat.ofNat 1 1 1) = 1) } B

Next tactic:
have := (two_mul_expl A.1.1 B.1.1).2.2.2
/-- The group homomorphism from `Gamma0` to `ZMod N` given by mapping a matrix to its lower
right-hand entry. -/
def Gamma0Map (N : ℕ) : Gamma0 N →* ZMod N where
  toFun g := ((↑ₘg 1 1 : ℤ) : ZMod N)
  map_one' := by simp
  map_mul' := by
    intro A B
    have := (two_mul_expl A.1.1 B.1.1).2.2.2
    

Proof state:
N✝ N : ℕ
A B : ↥(Gamma0 N)
this : (↑↑A * ↑↑B) 1 1 = ↑↑A 1 0 * ↑↑B 0 1 + ↑↑A 1 1 * ↑↑B 1 1
⊢ OneHom.toFun { toFun := fun g => ↑(↑↑g 1 1), map_one' := (_ : ↑(OfNat.ofNat 1 1 1) = 1) } (A * B) =
    OneHom.toFun { toFun := fun g => ↑(↑↑g 1 1), map_one' := (_ : ↑(OfNat.ofNat 1 1 1) = 1) } A *
      OneHom.toFun { toFun := fun g => ↑(↑↑g 1 1), map_one' := (_ : ↑(OfNat.ofNat 1 1 1) = 1) } B

Next tactic:
simp only [Subgroup.coe_mul, coe_matrix_coe, coe_mul, Int.coe_castRingHom, map_apply] at *
/-- The group homomorphism from `Gamma0` to `ZMod N` given by mapping a matrix to its lower
right-hand entry. -/
def Gamma0Map (N : ℕ) : Gamma0 N →* ZMod N where
  toFun g := ((↑ₘg 1 1 : ℤ) : ZMod N)
  map_one' := by simp
  map_mul' := by
    intro A B
    have := (two_mul_expl A.1.1 B.1.1).2.2.2
    simp only [Subgroup.coe_mul, coe_matrix_coe, coe_mul, Int.coe_castRingHom, map_apply] at *
    

Proof state:
N✝ N : ℕ
A B : ↥(Gamma0 N)
this : (↑↑A * ↑↑B) 1 1 = ↑↑A 1 0 * ↑↑B 0 1 + ↑↑A 1 1 * ↑↑B 1 1
⊢ ↑((↑↑A * ↑↑B) 1 1) = ↑(↑↑A 1 1) * ↑(↑↑B 1 1)

Next tactic:
rw [this]
/-- The group homomorphism from `Gamma0` to `ZMod N` given by mapping a matrix to its lower
right-hand entry. -/
def Gamma0Map (N : ℕ) : Gamma0 N →* ZMod N where
  toFun g := ((↑ₘg 1 1 : ℤ) : ZMod N)
  map_one' := by simp
  map_mul' := by
    intro A B
    have := (two_mul_expl A.1.1 B.1.1).2.2.2
    simp only [Subgroup.coe_mul, coe_matrix_coe, coe_mul, Int.coe_castRingHom, map_apply] at *
    rw [this]
    

Proof state:
N✝ N : ℕ
A B : ↥(Gamma0 N)
this : (↑↑A * ↑↑B) 1 1 = ↑↑A 1 0 * ↑↑B 0 1 + ↑↑A 1 1 * ↑↑B 1 1
⊢ ↑(↑↑A 1 0 * ↑↑B 0 1 + ↑↑A 1 1 * ↑↑B 1 1) = ↑(↑↑A 1 1) * ↑(↑↑B 1 1)

Next tactic:
have ha := A.property
/-- The group homomorphism from `Gamma0` to `ZMod N` given by mapping a matrix to its lower
right-hand entry. -/
def Gamma0Map (N : ℕ) : Gamma0 N →* ZMod N where
  toFun g := ((↑ₘg 1 1 : ℤ) : ZMod N)
  map_one' := by simp
  map_mul' := by
    intro A B
    have := (two_mul_expl A.1.1 B.1.1).2.2.2
    simp only [Subgroup.coe_mul, coe_matrix_coe, coe_mul, Int.coe_castRingHom, map_apply] at *
    rw [this]
    have ha := A.property
    

Proof state:
N✝ N : ℕ
A B : ↥(Gamma0 N)
this : (↑↑A * ↑↑B) 1 1 = ↑↑A 1 0 * ↑↑B 0 1 + ↑↑A 1 1 * ↑↑B 1 1
ha : ↑A ∈ Gamma0 N
⊢ ↑(↑↑A 1 0 * ↑↑B 0 1 + ↑↑A 1 1 * ↑↑B 1 1) = ↑(↑↑A 1 1) * ↑(↑↑B 1 1)

Next tactic:
simp only [Int.cast_add, Int.cast_mul, add_left_eq_self, Gamma0_mem,
      coe_matrix_coe, Int.coe_castRingHom, map_apply] at *
/-- The group homomorphism from `Gamma0` to `ZMod N` given by mapping a matrix to its lower
right-hand entry. -/
def Gamma0Map (N : ℕ) : Gamma0 N →* ZMod N where
  toFun g := ((↑ₘg 1 1 : ℤ) : ZMod N)
  map_one' := by simp
  map_mul' := by
    intro A B
    have := (two_mul_expl A.1.1 B.1.1).2.2.2
    simp only [Subgroup.coe_mul, coe_matrix_coe, coe_mul, Int.coe_castRingHom, map_apply] at *
    rw [this]
    have ha := A.property
    simp only [Int.cast_add, Int.cast_mul, add_left_eq_self, Gamma0_mem,
      coe_matrix_coe, Int.coe_castRingHom, map_apply] at *
    

Proof state:
N✝ N : ℕ
A B : ↥(Gamma0 N)
this : (↑↑A * ↑↑B) 1 1 = ↑↑A 1 0 * ↑↑B 0 1 + ↑↑A 1 1 * ↑↑B 1 1
ha : ↑(↑↑A 1 0) = 0
⊢ ↑(↑↑A 1 0) * ↑(↑↑B 0 1) = 0

Next tactic:
rw [ha]
/-- The group homomorphism from `Gamma0` to `ZMod N` given by mapping a matrix to its lower
right-hand entry. -/
def Gamma0Map (N : ℕ) : Gamma0 N →* ZMod N where
  toFun g := ((↑ₘg 1 1 : ℤ) : ZMod N)
  map_one' := by simp
  map_mul' := by
    intro A B
    have := (two_mul_expl A.1.1 B.1.1).2.2.2
    simp only [Subgroup.coe_mul, coe_matrix_coe, coe_mul, Int.coe_castRingHom, map_apply] at *
    rw [this]
    have ha := A.property
    simp only [Int.cast_add, Int.cast_mul, add_left_eq_self, Gamma0_mem,
      coe_matrix_coe, Int.coe_castRingHom, map_apply] at *
    rw [ha]
    

Proof state:
N✝ N : ℕ
A B : ↥(Gamma0 N)
this : (↑↑A * ↑↑B) 1 1 = ↑↑A 1 0 * ↑↑B 0 1 + ↑↑A 1 1 * ↑↑B 1 1
ha : ↑(↑↑A 1 0) = 0
⊢ 0 * ↑(↑↑B 0 1) = 0

Next tactic:
simp
theorem Gamma1_to_Gamma0_mem (N : ℕ) (A : Gamma0 N) : A ∈ Gamma1' N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  

Proof state:
N✝ N : ℕ
A : ↥(Gamma0 N)
⊢ A ∈ Gamma1' N ↔ ↑(↑↑A 0 0) = 1 ∧ ↑(↑↑A 1 1) = 1 ∧ ↑(↑↑A 1 0) = 0

Next tactic:
constructor
theorem Gamma1_to_Gamma0_mem (N : ℕ) (A : Gamma0 N) : A ∈ Gamma1' N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · 

Proof state:
case mp
N✝ N : ℕ
A : ↥(Gamma0 N)
⊢ A ∈ Gamma1' N → ↑(↑↑A 0 0) = 1 ∧ ↑(↑↑A 1 1) = 1 ∧ ↑(↑↑A 1 0) = 0

Next tactic:
intro ha
theorem Gamma1_to_Gamma0_mem (N : ℕ) (A : Gamma0 N) : A ∈ Gamma1' N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    

Proof state:
case mp
N✝ N : ℕ
A : ↥(Gamma0 N)
ha : A ∈ Gamma1' N
⊢ ↑(↑↑A 0 0) = 1 ∧ ↑(↑↑A 1 1) = 1 ∧ ↑(↑↑A 1 0) = 0

Next tactic:
have hA := A.property
theorem Gamma1_to_Gamma0_mem (N : ℕ) (A : Gamma0 N) : A ∈ Gamma1' N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    have hA := A.property
    

Proof state:
case mp
N✝ N : ℕ
A : ↥(Gamma0 N)
ha : A ∈ Gamma1' N
hA : ↑A ∈ Gamma0 N
⊢ ↑(↑↑A 0 0) = 1 ∧ ↑(↑↑A 1 1) = 1 ∧ ↑(↑↑A 1 0) = 0

Next tactic:
rw [Gamma0_mem] at hA
theorem Gamma1_to_Gamma0_mem (N : ℕ) (A : Gamma0 N) : A ∈ Gamma1' N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    have hA := A.property
    rw [Gamma0_mem] at hA
    

Proof state:
case mp
N✝ N : ℕ
A : ↥(Gamma0 N)
ha : A ∈ Gamma1' N
hA : ↑(↑↑A 1 0) = 0
⊢ ↑(↑↑A 0 0) = 1 ∧ ↑(↑↑A 1 1) = 1 ∧ ↑(↑↑A 1 0) = 0

Next tactic:
have adet := Gamma0_det N A
theorem Gamma1_to_Gamma0_mem (N : ℕ) (A : Gamma0 N) : A ∈ Gamma1' N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    have hA := A.property
    rw [Gamma0_mem] at hA
    have adet := Gamma0_det N A
    

Proof state:
case mp
N✝ N : ℕ
A : ↥(Gamma0 N)
ha : A ∈ Gamma1' N
hA : ↑(↑↑A 1 0) = 0
adet : ↑(det ↑↑A) = 1
⊢ ↑(↑↑A 0 0) = 1 ∧ ↑(↑↑A 1 1) = 1 ∧ ↑(↑↑A 1 0) = 0

Next tactic:
rw [Matrix.det_fin_two] at adet
theorem Gamma1_to_Gamma0_mem (N : ℕ) (A : Gamma0 N) : A ∈ Gamma1' N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    have hA := A.property
    rw [Gamma0_mem] at hA
    have adet := Gamma0_det N A
    rw [Matrix.det_fin_two] at adet
    

Proof state:
case mp
N✝ N : ℕ
A : ↥(Gamma0 N)
ha : A ∈ Gamma1' N
hA : ↑(↑↑A 1 0) = 0
adet : ↑(↑↑A 0 0 * ↑↑A 1 1 - ↑↑A 0 1 * ↑↑A 1 0) = 1
⊢ ↑(↑↑A 0 0) = 1 ∧ ↑(↑↑A 1 1) = 1 ∧ ↑(↑↑A 1 0) = 0

Next tactic:
simp only [Gamma0Map, coe_matrix_coe, Int.coe_castRingHom, map_apply, Gamma1_mem',
      MonoidHom.coe_mk, OneHom.coe_mk, Int.cast_sub, Int.cast_mul] at *
theorem Gamma1_to_Gamma0_mem (N : ℕ) (A : Gamma0 N) : A ∈ Gamma1' N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    have hA := A.property
    rw [Gamma0_mem] at hA
    have adet := Gamma0_det N A
    rw [Matrix.det_fin_two] at adet
    simp only [Gamma0Map, coe_matrix_coe, Int.coe_castRingHom, map_apply, Gamma1_mem',
      MonoidHom.coe_mk, OneHom.coe_mk, Int.cast_sub, Int.cast_mul] at *
    

Proof state:
case mp
N✝ N : ℕ
A : ↥(Gamma0 N)
hA : ↑(↑↑A 1 0) = 0
ha : ↑(↑↑A 1 1) = 1
adet : ↑(↑↑A 0 0) * ↑(↑↑A 1 1) - ↑(↑↑A 0 1) * ↑(↑↑A 1 0) = 1
⊢ ↑(↑↑A 0 0) = 1 ∧ ↑(↑↑A 1 1) = 1 ∧ ↑(↑↑A 1 0) = 0

Next tactic:
rw [hA, ha] at adet
theorem Gamma1_to_Gamma0_mem (N : ℕ) (A : Gamma0 N) : A ∈ Gamma1' N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    have hA := A.property
    rw [Gamma0_mem] at hA
    have adet := Gamma0_det N A
    rw [Matrix.det_fin_two] at adet
    simp only [Gamma0Map, coe_matrix_coe, Int.coe_castRingHom, map_apply, Gamma1_mem',
      MonoidHom.coe_mk, OneHom.coe_mk, Int.cast_sub, Int.cast_mul] at *
    rw [hA, ha] at adet
    

Proof state:
case mp
N✝ N : ℕ
A : ↥(Gamma0 N)
hA : ↑(↑↑A 1 0) = 0
ha : ↑(↑↑A 1 1) = 1
adet : ↑(↑↑A 0 0) * 1 - ↑(↑↑A 0 1) * 0 = 1
⊢ ↑(↑↑A 0 0) = 1 ∧ ↑(↑↑A 1 1) = 1 ∧ ↑(↑↑A 1 0) = 0

Next tactic:
simp only [mul_one, mul_zero, sub_zero] at adet
theorem Gamma1_to_Gamma0_mem (N : ℕ) (A : Gamma0 N) : A ∈ Gamma1' N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    have hA := A.property
    rw [Gamma0_mem] at hA
    have adet := Gamma0_det N A
    rw [Matrix.det_fin_two] at adet
    simp only [Gamma0Map, coe_matrix_coe, Int.coe_castRingHom, map_apply, Gamma1_mem',
      MonoidHom.coe_mk, OneHom.coe_mk, Int.cast_sub, Int.cast_mul] at *
    rw [hA, ha] at adet
    simp only [mul_one, mul_zero, sub_zero] at adet
    

Proof state:
case mp
N✝ N : ℕ
A : ↥(Gamma0 N)
hA : ↑(↑↑A 1 0) = 0
ha : ↑(↑↑A 1 1) = 1
adet : ↑(↑↑A 0 0) = 1
⊢ ↑(↑↑A 0 0) = 1 ∧ ↑(↑↑A 1 1) = 1 ∧ ↑(↑↑A 1 0) = 0

Next tactic:
simp only [adet, hA, ha, eq_self_iff_true, and_self_iff]
theorem Gamma1_to_Gamma0_mem (N : ℕ) (A : Gamma0 N) : A ∈ Gamma1' N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    have hA := A.property
    rw [Gamma0_mem] at hA
    have adet := Gamma0_det N A
    rw [Matrix.det_fin_two] at adet
    simp only [Gamma0Map, coe_matrix_coe, Int.coe_castRingHom, map_apply, Gamma1_mem',
      MonoidHom.coe_mk, OneHom.coe_mk, Int.cast_sub, Int.cast_mul] at *
    rw [hA, ha] at adet
    simp only [mul_one, mul_zero, sub_zero] at adet
    simp only [adet, hA, ha, eq_self_iff_true, and_self_iff]
  · 

Proof state:
case mpr
N✝ N : ℕ
A : ↥(Gamma0 N)
⊢ ↑(↑↑A 0 0) = 1 ∧ ↑(↑↑A 1 1) = 1 ∧ ↑(↑↑A 1 0) = 0 → A ∈ Gamma1' N

Next tactic:
intro ha
theorem Gamma1_to_Gamma0_mem (N : ℕ) (A : Gamma0 N) : A ∈ Gamma1' N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    have hA := A.property
    rw [Gamma0_mem] at hA
    have adet := Gamma0_det N A
    rw [Matrix.det_fin_two] at adet
    simp only [Gamma0Map, coe_matrix_coe, Int.coe_castRingHom, map_apply, Gamma1_mem',
      MonoidHom.coe_mk, OneHom.coe_mk, Int.cast_sub, Int.cast_mul] at *
    rw [hA, ha] at adet
    simp only [mul_one, mul_zero, sub_zero] at adet
    simp only [adet, hA, ha, eq_self_iff_true, and_self_iff]
  · intro ha
    

Proof state:
case mpr
N✝ N : ℕ
A : ↥(Gamma0 N)
ha : ↑(↑↑A 0 0) = 1 ∧ ↑(↑↑A 1 1) = 1 ∧ ↑(↑↑A 1 0) = 0
⊢ A ∈ Gamma1' N

Next tactic:
simp only [Gamma1_mem', Gamma0Map, MonoidHom.coe_mk, coe_matrix_coe,
      Int.coe_castRingHom, map_apply]
theorem Gamma1_to_Gamma0_mem (N : ℕ) (A : Gamma0 N) : A ∈ Gamma1' N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    have hA := A.property
    rw [Gamma0_mem] at hA
    have adet := Gamma0_det N A
    rw [Matrix.det_fin_two] at adet
    simp only [Gamma0Map, coe_matrix_coe, Int.coe_castRingHom, map_apply, Gamma1_mem',
      MonoidHom.coe_mk, OneHom.coe_mk, Int.cast_sub, Int.cast_mul] at *
    rw [hA, ha] at adet
    simp only [mul_one, mul_zero, sub_zero] at adet
    simp only [adet, hA, ha, eq_self_iff_true, and_self_iff]
  · intro ha
    simp only [Gamma1_mem', Gamma0Map, MonoidHom.coe_mk, coe_matrix_coe,
      Int.coe_castRingHom, map_apply]
    

Proof state:
case mpr
N✝ N : ℕ
A : ↥(Gamma0 N)
ha : ↑(↑↑A 0 0) = 1 ∧ ↑(↑↑A 1 1) = 1 ∧ ↑(↑↑A 1 0) = 0
⊢ { toFun := fun g => ↑(↑↑g 1 1), map_one' := (_ : ↑(OfNat.ofNat 1 1 1) = 1) } A = 1

Next tactic:
exact ha.2.1
@[simp]
theorem Gamma1_mem (N : ℕ) (A : SL(2, ℤ)) : A ∈ Gamma1 N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  

Proof state:
N✝ N : ℕ
A : SL(2, ℤ)
⊢ A ∈ Gamma1 N ↔ ↑(↑A 0 0) = 1 ∧ ↑(↑A 1 1) = 1 ∧ ↑(↑A 1 0) = 0

Next tactic:
constructor
@[simp]
theorem Gamma1_mem (N : ℕ) (A : SL(2, ℤ)) : A ∈ Gamma1 N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · 

Proof state:
case mp
N✝ N : ℕ
A : SL(2, ℤ)
⊢ A ∈ Gamma1 N → ↑(↑A 0 0) = 1 ∧ ↑(↑A 1 1) = 1 ∧ ↑(↑A 1 0) = 0

Next tactic:
intro ha
@[simp]
theorem Gamma1_mem (N : ℕ) (A : SL(2, ℤ)) : A ∈ Gamma1 N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    

Proof state:
case mp
N✝ N : ℕ
A : SL(2, ℤ)
ha : A ∈ Gamma1 N
⊢ ↑(↑A 0 0) = 1 ∧ ↑(↑A 1 1) = 1 ∧ ↑(↑A 1 0) = 0

Next tactic:
simp_rw [Gamma1, Subgroup.mem_map] at ha
@[simp]
theorem Gamma1_mem (N : ℕ) (A : SL(2, ℤ)) : A ∈ Gamma1 N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map] at ha
    

Proof state:
case mp
N✝ N : ℕ
A : SL(2, ℤ)
ha : ∃ x ∈ ⊤, (MonoidHom.comp (Subgroup.subtype (Gamma0 N)) (Subgroup.subtype (Gamma1' N))) x = A
⊢ ↑(↑A 0 0) = 1 ∧ ↑(↑A 1 1) = 1 ∧ ↑(↑A 1 0) = 0

Next tactic:
obtain ⟨⟨x, hx⟩, hxx⟩ := ha
@[simp]
theorem Gamma1_mem (N : ℕ) (A : SL(2, ℤ)) : A ∈ Gamma1 N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map] at ha
    obtain ⟨⟨x, hx⟩, hxx⟩ := ha
    

Proof state:
case mp.intro.mk
N✝ N : ℕ
A : SL(2, ℤ)
x : ↥(Gamma0 N)
hx : x ∈ Gamma1' N
hxx :
  { val := x, property := hx } ∈ ⊤ ∧
    (MonoidHom.comp (Subgroup.subtype (Gamma0 N)) (Subgroup.subtype (Gamma1' N))) { val := x, property := hx } = A
⊢ ↑(↑A 0 0) = 1 ∧ ↑(↑A 1 1) = 1 ∧ ↑(↑A 1 0) = 0

Next tactic:
rw [Gamma1_to_Gamma0_mem] at hx
@[simp]
theorem Gamma1_mem (N : ℕ) (A : SL(2, ℤ)) : A ∈ Gamma1 N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map] at ha
    obtain ⟨⟨x, hx⟩, hxx⟩ := ha
    rw [Gamma1_to_Gamma0_mem] at hx
    

Proof state:
case mp.intro.mk
N✝ N : ℕ
A : SL(2, ℤ)
x : ↥(Gamma0 N)
hx✝ : x ∈ Gamma1' N
hx : ↑(↑↑x 0 0) = 1 ∧ ↑(↑↑x 1 1) = 1 ∧ ↑(↑↑x 1 0) = 0
hxx :
  { val := x, property := hx✝ } ∈ ⊤ ∧
    (MonoidHom.comp (Subgroup.subtype (Gamma0 N)) (Subgroup.subtype (Gamma1' N))) { val := x, property := hx✝ } = A
⊢ ↑(↑A 0 0) = 1 ∧ ↑(↑A 1 1) = 1 ∧ ↑(↑A 1 0) = 0

Next tactic:
simp only [Subgroup.mem_top, true_and] at hxx
@[simp]
theorem Gamma1_mem (N : ℕ) (A : SL(2, ℤ)) : A ∈ Gamma1 N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map] at ha
    obtain ⟨⟨x, hx⟩, hxx⟩ := ha
    rw [Gamma1_to_Gamma0_mem] at hx
    simp only [Subgroup.mem_top, true_and] at hxx
    

Proof state:
case mp.intro.mk
N✝ N : ℕ
A : SL(2, ℤ)
x : ↥(Gamma0 N)
hx✝ : x ∈ Gamma1' N
hx : ↑(↑↑x 0 0) = 1 ∧ ↑(↑↑x 1 1) = 1 ∧ ↑(↑↑x 1 0) = 0
hxx : (MonoidHom.comp (Subgroup.subtype (Gamma0 N)) (Subgroup.subtype (Gamma1' N))) { val := x, property := hx✝ } = A
⊢ ↑(↑A 0 0) = 1 ∧ ↑(↑A 1 1) = 1 ∧ ↑(↑A 1 0) = 0

Next tactic:
rw [← hxx]
@[simp]
theorem Gamma1_mem (N : ℕ) (A : SL(2, ℤ)) : A ∈ Gamma1 N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map] at ha
    obtain ⟨⟨x, hx⟩, hxx⟩ := ha
    rw [Gamma1_to_Gamma0_mem] at hx
    simp only [Subgroup.mem_top, true_and] at hxx
    rw [← hxx]
    

Proof state:
case mp.intro.mk
N✝ N : ℕ
A : SL(2, ℤ)
x : ↥(Gamma0 N)
hx✝ : x ∈ Gamma1' N
hx : ↑(↑↑x 0 0) = 1 ∧ ↑(↑↑x 1 1) = 1 ∧ ↑(↑↑x 1 0) = 0
hxx : (MonoidHom.comp (Subgroup.subtype (Gamma0 N)) (Subgroup.subtype (Gamma1' N))) { val := x, property := hx✝ } = A
⊢ ↑(↑((MonoidHom.comp (Subgroup.subtype (Gamma0 N)) (Subgroup.subtype (Gamma1' N))) { val := x, property := hx✝ }) 0
          0) =
      1 ∧
    ↑(↑((MonoidHom.comp (Subgroup.subtype (Gamma0 N)) (Subgroup.subtype (Gamma1' N))) { val := x, property := hx✝ }) 1
            1) =
        1 ∧
      ↑(↑((MonoidHom.comp (Subgroup.subtype (Gamma0 N)) (Subgroup.subtype (Gamma1' N))) { val := x, property := hx✝ }) 1
            0) =
        0

Next tactic:
convert hx
@[simp]
theorem Gamma1_mem (N : ℕ) (A : SL(2, ℤ)) : A ∈ Gamma1 N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map] at ha
    obtain ⟨⟨x, hx⟩, hxx⟩ := ha
    rw [Gamma1_to_Gamma0_mem] at hx
    simp only [Subgroup.mem_top, true_and] at hxx
    rw [← hxx]
    convert hx
  · 

Proof state:
case mpr
N✝ N : ℕ
A : SL(2, ℤ)
⊢ ↑(↑A 0 0) = 1 ∧ ↑(↑A 1 1) = 1 ∧ ↑(↑A 1 0) = 0 → A ∈ Gamma1 N

Next tactic:
intro ha
@[simp]
theorem Gamma1_mem (N : ℕ) (A : SL(2, ℤ)) : A ∈ Gamma1 N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map] at ha
    obtain ⟨⟨x, hx⟩, hxx⟩ := ha
    rw [Gamma1_to_Gamma0_mem] at hx
    simp only [Subgroup.mem_top, true_and] at hxx
    rw [← hxx]
    convert hx
  · intro ha
    

Proof state:
case mpr
N✝ N : ℕ
A : SL(2, ℤ)
ha : ↑(↑A 0 0) = 1 ∧ ↑(↑A 1 1) = 1 ∧ ↑(↑A 1 0) = 0
⊢ A ∈ Gamma1 N

Next tactic:
simp_rw [Gamma1, Subgroup.mem_map]
@[simp]
theorem Gamma1_mem (N : ℕ) (A : SL(2, ℤ)) : A ∈ Gamma1 N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map] at ha
    obtain ⟨⟨x, hx⟩, hxx⟩ := ha
    rw [Gamma1_to_Gamma0_mem] at hx
    simp only [Subgroup.mem_top, true_and] at hxx
    rw [← hxx]
    convert hx
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map]
    

Proof state:
case mpr
N✝ N : ℕ
A : SL(2, ℤ)
ha : ↑(↑A 0 0) = 1 ∧ ↑(↑A 1 1) = 1 ∧ ↑(↑A 1 0) = 0
⊢ ∃ x ∈ ⊤, (MonoidHom.comp (Subgroup.subtype (Gamma0 N)) (Subgroup.subtype (Gamma1' N))) x = A

Next tactic:
have hA : A ∈ Gamma0 N := by simp [ha.right.right, Gamma0_mem]
@[simp]
theorem Gamma1_mem (N : ℕ) (A : SL(2, ℤ)) : A ∈ Gamma1 N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map] at ha
    obtain ⟨⟨x, hx⟩, hxx⟩ := ha
    rw [Gamma1_to_Gamma0_mem] at hx
    simp only [Subgroup.mem_top, true_and] at hxx
    rw [← hxx]
    convert hx
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map]
    have hA : A ∈ Gamma0 N := by 

Proof state:
N✝ N : ℕ
A : SL(2, ℤ)
ha : ↑(↑A 0 0) = 1 ∧ ↑(↑A 1 1) = 1 ∧ ↑(↑A 1 0) = 0
⊢ A ∈ Gamma0 N

Next tactic:
simp [ha.right.right, Gamma0_mem]
@[simp]
theorem Gamma1_mem (N : ℕ) (A : SL(2, ℤ)) : A ∈ Gamma1 N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map] at ha
    obtain ⟨⟨x, hx⟩, hxx⟩ := ha
    rw [Gamma1_to_Gamma0_mem] at hx
    simp only [Subgroup.mem_top, true_and] at hxx
    rw [← hxx]
    convert hx
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map]
    have hA : A ∈ Gamma0 N := by simp [ha.right.right, Gamma0_mem]
    

Proof state:
case mpr
N✝ N : ℕ
A : SL(2, ℤ)
ha : ↑(↑A 0 0) = 1 ∧ ↑(↑A 1 1) = 1 ∧ ↑(↑A 1 0) = 0
hA : A ∈ Gamma0 N
⊢ ∃ x ∈ ⊤, (MonoidHom.comp (Subgroup.subtype (Gamma0 N)) (Subgroup.subtype (Gamma1' N))) x = A

Next tactic:
have HA : (⟨A, hA⟩ : Gamma0 N) ∈ Gamma1' N := by
      simp only [Gamma1_to_Gamma0_mem, Subgroup.coe_mk, coe_matrix_coe,
        Int.coe_castRingHom, map_apply]
      exact ha
@[simp]
theorem Gamma1_mem (N : ℕ) (A : SL(2, ℤ)) : A ∈ Gamma1 N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map] at ha
    obtain ⟨⟨x, hx⟩, hxx⟩ := ha
    rw [Gamma1_to_Gamma0_mem] at hx
    simp only [Subgroup.mem_top, true_and] at hxx
    rw [← hxx]
    convert hx
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map]
    have hA : A ∈ Gamma0 N := by simp [ha.right.right, Gamma0_mem]
    have HA : (⟨A, hA⟩ : Gamma0 N) ∈ Gamma1' N := by
      

Proof state:
N✝ N : ℕ
A : SL(2, ℤ)
ha : ↑(↑A 0 0) = 1 ∧ ↑(↑A 1 1) = 1 ∧ ↑(↑A 1 0) = 0
hA : A ∈ Gamma0 N
⊢ { val := A, property := hA } ∈ Gamma1' N

Next tactic:
simp only [Gamma1_to_Gamma0_mem, Subgroup.coe_mk, coe_matrix_coe,
        Int.coe_castRingHom, map_apply]
@[simp]
theorem Gamma1_mem (N : ℕ) (A : SL(2, ℤ)) : A ∈ Gamma1 N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map] at ha
    obtain ⟨⟨x, hx⟩, hxx⟩ := ha
    rw [Gamma1_to_Gamma0_mem] at hx
    simp only [Subgroup.mem_top, true_and] at hxx
    rw [← hxx]
    convert hx
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map]
    have hA : A ∈ Gamma0 N := by simp [ha.right.right, Gamma0_mem]
    have HA : (⟨A, hA⟩ : Gamma0 N) ∈ Gamma1' N := by
      simp only [Gamma1_to_Gamma0_mem, Subgroup.coe_mk, coe_matrix_coe,
        Int.coe_castRingHom, map_apply]
      

Proof state:
N✝ N : ℕ
A : SL(2, ℤ)
ha : ↑(↑A 0 0) = 1 ∧ ↑(↑A 1 1) = 1 ∧ ↑(↑A 1 0) = 0
hA : A ∈ Gamma0 N
⊢ ↑(↑A 0 0) = 1 ∧ ↑(↑A 1 1) = 1 ∧ ↑(↑A 1 0) = 0

Next tactic:
exact ha
@[simp]
theorem Gamma1_mem (N : ℕ) (A : SL(2, ℤ)) : A ∈ Gamma1 N ↔
    ((↑ₘA 0 0 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 1 : ℤ) : ZMod N) = 1 ∧ ((↑ₘA 1 0 : ℤ) : ZMod N) = 0 := by
  constructor
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map] at ha
    obtain ⟨⟨x, hx⟩, hxx⟩ := ha
    rw [Gamma1_to_Gamma0_mem] at hx
    simp only [Subgroup.mem_top, true_and] at hxx
    rw [← hxx]
    convert hx
  · intro ha
    simp_rw [Gamma1, Subgroup.mem_map]
    have hA : A ∈ Gamma0 N := by simp [ha.right.right, Gamma0_mem]
    have HA : (⟨A, hA⟩ : Gamma0 N) ∈ Gamma1' N := by
      simp only [Gamma1_to_Gamma0_mem, Subgroup.coe_mk, coe_matrix_coe,
        Int.coe_castRingHom, map_apply]
      exact ha
    

Proof state:
case mpr
N✝ N : ℕ
A : SL(2, ℤ)
ha : ↑(↑A 0 0) = 1 ∧ ↑(↑A 1 1) = 1 ∧ ↑(↑A 1 0) = 0
hA : A ∈ Gamma0 N
HA : { val := A, property := hA } ∈ Gamma1' N
⊢ ∃ x ∈ ⊤, (MonoidHom.comp (Subgroup.subtype (Gamma0 N)) (Subgroup.subtype (Gamma1' N))) x = A

Next tactic:
refine' ⟨(⟨(⟨A, hA⟩ : Gamma0 N), HA⟩ : (Gamma1' N : Subgroup (Gamma0 N))), _⟩