l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem Gamma_mem (N : ℕ) (γ : SL(2, ℤ)) : γ ∈ Gamma N ↔ ((↑ₘγ 0 0 : ℤ) : ZMod N) = 1 ∧
    ((↑ₘγ 0 1 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 0 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 1 : ℤ) : ZMod N) = 1 := by
  rw [Gamma_mem']
  constructor
  · intro h
    simp [← SL_reduction_mod_hom_val N γ, h]
  · intro h
    ext i j
    

Proof state:
case mpr.a
N✝ N : ℕ
γ : SL(2, ℤ)
h : ↑(↑γ 0 0) = 1 ∧ ↑(↑γ 0 1) = 0 ∧ ↑(↑γ 1 0) = 0 ∧ ↑(↑γ 1 1) = 1
i j : Fin 2
⊢ ↑((SpecialLinearGroup.map (Int.castRingHom (ZMod N))) γ) i j = ↑1 i j

Next tactic:
rw [SL_reduction_mod_hom_val N γ]
@[simp]
theorem Gamma_mem (N : ℕ) (γ : SL(2, ℤ)) : γ ∈ Gamma N ↔ ((↑ₘγ 0 0 : ℤ) : ZMod N) = 1 ∧
    ((↑ₘγ 0 1 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 0 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 1 : ℤ) : ZMod N) = 1 := by
  rw [Gamma_mem']
  constructor
  · intro h
    simp [← SL_reduction_mod_hom_val N γ, h]
  · intro h
    ext i j
    rw [SL_reduction_mod_hom_val N γ]
    

Proof state:
case mpr.a
N✝ N : ℕ
γ : SL(2, ℤ)
h : ↑(↑γ 0 0) = 1 ∧ ↑(↑γ 0 1) = 0 ∧ ↑(↑γ 1 0) = 0 ∧ ↑(↑γ 1 1) = 1
i j : Fin 2
⊢ ↑(↑γ i j) = ↑1 i j

Next tactic:
fin_cases i
@[simp]
theorem Gamma_mem (N : ℕ) (γ : SL(2, ℤ)) : γ ∈ Gamma N ↔ ((↑ₘγ 0 0 : ℤ) : ZMod N) = 1 ∧
    ((↑ₘγ 0 1 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 0 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 1 : ℤ) : ZMod N) = 1 := by
  rw [Gamma_mem']
  constructor
  · intro h
    simp [← SL_reduction_mod_hom_val N γ, h]
  · intro h
    ext i j
    rw [SL_reduction_mod_hom_val N γ]
    fin_cases i <;> 

Proof state:
case mpr.a.head
N✝ N : ℕ
γ : SL(2, ℤ)
h : ↑(↑γ 0 0) = 1 ∧ ↑(↑γ 0 1) = 0 ∧ ↑(↑γ 1 0) = 0 ∧ ↑(↑γ 1 1) = 1
j : Fin 2
⊢ ↑(↑γ { val := 0, isLt := (_ : 0 < 2) } j) = ↑1 { val := 0, isLt := (_ : 0 < 2) } j

Next tactic:
fin_cases j
@[simp]
theorem Gamma_mem (N : ℕ) (γ : SL(2, ℤ)) : γ ∈ Gamma N ↔ ((↑ₘγ 0 0 : ℤ) : ZMod N) = 1 ∧
    ((↑ₘγ 0 1 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 0 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 1 : ℤ) : ZMod N) = 1 := by
  rw [Gamma_mem']
  constructor
  · intro h
    simp [← SL_reduction_mod_hom_val N γ, h]
  · intro h
    ext i j
    rw [SL_reduction_mod_hom_val N γ]
    fin_cases i <;> 

Proof state:
case mpr.a.tail.head
N✝ N : ℕ
γ : SL(2, ℤ)
h : ↑(↑γ 0 0) = 1 ∧ ↑(↑γ 0 1) = 0 ∧ ↑(↑γ 1 0) = 0 ∧ ↑(↑γ 1 1) = 1
j : Fin 2
⊢ ↑(↑γ { val := 1, isLt := (_ : (fun a => a < 2) 1) } j) = ↑1 { val := 1, isLt := (_ : (fun a => a < 2) 1) } j

Next tactic:
fin_cases j
@[simp]
theorem Gamma_mem (N : ℕ) (γ : SL(2, ℤ)) : γ ∈ Gamma N ↔ ((↑ₘγ 0 0 : ℤ) : ZMod N) = 1 ∧
    ((↑ₘγ 0 1 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 0 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 1 : ℤ) : ZMod N) = 1 := by
  rw [Gamma_mem']
  constructor
  · intro h
    simp [← SL_reduction_mod_hom_val N γ, h]
  · intro h
    ext i j
    rw [SL_reduction_mod_hom_val N γ]
    fin_cases i <;> fin_cases j <;> 

Proof state:
case mpr.a.head.head
N✝ N : ℕ
γ : SL(2, ℤ)
h : ↑(↑γ 0 0) = 1 ∧ ↑(↑γ 0 1) = 0 ∧ ↑(↑γ 1 0) = 0 ∧ ↑(↑γ 1 1) = 1
⊢ ↑(↑γ { val := 0, isLt := (_ : 0 < 2) } { val := 0, isLt := (_ : 0 < 2) }) =
    ↑1 { val := 0, isLt := (_ : 0 < 2) } { val := 0, isLt := (_ : 0 < 2) }

Next tactic:
simp only [h]
@[simp]
theorem Gamma_mem (N : ℕ) (γ : SL(2, ℤ)) : γ ∈ Gamma N ↔ ((↑ₘγ 0 0 : ℤ) : ZMod N) = 1 ∧
    ((↑ₘγ 0 1 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 0 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 1 : ℤ) : ZMod N) = 1 := by
  rw [Gamma_mem']
  constructor
  · intro h
    simp [← SL_reduction_mod_hom_val N γ, h]
  · intro h
    ext i j
    rw [SL_reduction_mod_hom_val N γ]
    fin_cases i <;> fin_cases j <;> 

Proof state:
case mpr.a.head.tail.head
N✝ N : ℕ
γ : SL(2, ℤ)
h : ↑(↑γ 0 0) = 1 ∧ ↑(↑γ 0 1) = 0 ∧ ↑(↑γ 1 0) = 0 ∧ ↑(↑γ 1 1) = 1
⊢ ↑(↑γ { val := 0, isLt := (_ : 0 < 2) } { val := 1, isLt := (_ : (fun a => a < 2) 1) }) =
    ↑1 { val := 0, isLt := (_ : 0 < 2) } { val := 1, isLt := (_ : (fun a => a < 2) 1) }

Next tactic:
simp only [h]
@[simp]
theorem Gamma_mem (N : ℕ) (γ : SL(2, ℤ)) : γ ∈ Gamma N ↔ ((↑ₘγ 0 0 : ℤ) : ZMod N) = 1 ∧
    ((↑ₘγ 0 1 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 0 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 1 : ℤ) : ZMod N) = 1 := by
  rw [Gamma_mem']
  constructor
  · intro h
    simp [← SL_reduction_mod_hom_val N γ, h]
  · intro h
    ext i j
    rw [SL_reduction_mod_hom_val N γ]
    fin_cases i <;> fin_cases j <;> 

Proof state:
case mpr.a.tail.head.head
N✝ N : ℕ
γ : SL(2, ℤ)
h : ↑(↑γ 0 0) = 1 ∧ ↑(↑γ 0 1) = 0 ∧ ↑(↑γ 1 0) = 0 ∧ ↑(↑γ 1 1) = 1
⊢ ↑(↑γ { val := 1, isLt := (_ : (fun a => a < 2) 1) } { val := 0, isLt := (_ : 0 < 2) }) =
    ↑1 { val := 1, isLt := (_ : (fun a => a < 2) 1) } { val := 0, isLt := (_ : 0 < 2) }

Next tactic:
simp only [h]
@[simp]
theorem Gamma_mem (N : ℕ) (γ : SL(2, ℤ)) : γ ∈ Gamma N ↔ ((↑ₘγ 0 0 : ℤ) : ZMod N) = 1 ∧
    ((↑ₘγ 0 1 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 0 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 1 : ℤ) : ZMod N) = 1 := by
  rw [Gamma_mem']
  constructor
  · intro h
    simp [← SL_reduction_mod_hom_val N γ, h]
  · intro h
    ext i j
    rw [SL_reduction_mod_hom_val N γ]
    fin_cases i <;> fin_cases j <;> 

Proof state:
case mpr.a.tail.head.tail.head
N✝ N : ℕ
γ : SL(2, ℤ)
h : ↑(↑γ 0 0) = 1 ∧ ↑(↑γ 0 1) = 0 ∧ ↑(↑γ 1 0) = 0 ∧ ↑(↑γ 1 1) = 1
⊢ ↑(↑γ { val := 1, isLt := (_ : (fun a => a < 2) 1) } { val := 1, isLt := (_ : (fun a => a < 2) 1) }) =
    ↑1 { val := 1, isLt := (_ : (fun a => a < 2) 1) } { val := 1, isLt := (_ : (fun a => a < 2) 1) }

Next tactic:
simp only [h]
@[simp]
theorem Gamma_mem (N : ℕ) (γ : SL(2, ℤ)) : γ ∈ Gamma N ↔ ((↑ₘγ 0 0 : ℤ) : ZMod N) = 1 ∧
    ((↑ₘγ 0 1 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 0 : ℤ) : ZMod N) = 0 ∧ ((↑ₘγ 1 1 : ℤ) : ZMod N) = 1 := by
  rw [Gamma_mem']
  constructor
  · intro h
    simp [← SL_reduction_mod_hom_val N γ, h]
  · intro h
    ext i j
    rw [SL_reduction_mod_hom_val N γ]
    fin_cases i <;> fin_cases j <;> simp only [h]
    

Proof state:
case mpr.a.head.head
N✝ N : ℕ
γ : SL(2, ℤ)
h : ↑(↑γ 0 0) = 1 ∧ ↑(↑γ 0 1) = 0 ∧ ↑(↑γ 1 0) = 0 ∧ ↑(↑γ 1 1) = 1
⊢ ↑(↑γ { val := 0, isLt := (_ : 0 < 2) } { val := 0, isLt := (_ : 0 < 2) }) =
    ↑1 { val := 0, isLt := (_ : 0 < 2) } { val := 0, isLt := (_ : 0 < 2) }
case mpr.a.head.tail.head
N✝ N : ℕ
γ : SL(2, ℤ)
h : ↑(↑γ 0 0) = 1 ∧ ↑(↑γ 0 1) = 0 ∧ ↑(↑γ 1 0) = 0 ∧ ↑(↑γ 1 1) = 1
⊢ ↑(↑γ { val := 0, isLt := (_ : 0 < 2) } { val := 1, isLt := (_ : (fun a => a < 2) 1) }) =
    ↑1 { val := 0, isLt := (_ : 0 < 2) } { val := 1, isLt := (_ : (fun a => a < 2) 1) }
case mpr.a.tail.head.head
N✝ N : ℕ
γ : SL(2, ℤ)
h : ↑(↑γ 0 0) = 1 ∧ ↑(↑γ 0 1) = 0 ∧ ↑(↑γ 1 0) = 0 ∧ ↑(↑γ 1 1) = 1
⊢ ↑(↑γ { val := 1, isLt := (_ : (fun a => a < 2) 1) } { val := 0, isLt := (_ : 0 < 2) }) =
    ↑1 { val := 1, isLt := (_ : (fun a => a < 2) 1) } { val := 0, isLt := (_ : 0 < 2) }
case mpr.a.tail.head.tail.head
N✝ N : ℕ
γ : SL(2, ℤ)
h : ↑(↑γ 0 0) = 1 ∧ ↑(↑γ 0 1) = 0 ∧ ↑(↑γ 1 0) = 0 ∧ ↑(↑γ 1 1) = 1
⊢ ↑(↑γ { val := 1, isLt := (_ : (fun a => a < 2) 1) } { val := 1, isLt := (_ : (fun a => a < 2) 1) }) =
    ↑1 { val := 1, isLt := (_ : (fun a => a < 2) 1) } { val := 1, isLt := (_ : (fun a => a < 2) 1) }

Next tactic:
exacts [h.1, h.2.1, h.2.2.1, h.2.2.2]
theorem Gamma_one_top : Gamma 1 = ⊤ := by
  

Proof state:
N : ℕ
⊢ Gamma 1 = ⊤

Next tactic:
ext
theorem Gamma_one_top : Gamma 1 = ⊤ := by
  ext
  

Proof state:
case h
N : ℕ
x✝ : SL(2, ℤ)
⊢ x✝ ∈ Gamma 1 ↔ x✝ ∈ ⊤

Next tactic:
simp [eq_iff_true_of_subsingleton]
theorem Gamma_zero_bot : Gamma 0 = ⊥ := by
  

Proof state:
N : ℕ
⊢ Gamma 0 = ⊥

Next tactic:
ext
theorem Gamma_zero_bot : Gamma 0 = ⊥ := by
  ext
  

Proof state:
case h
N : ℕ
x✝ : SL(2, ℤ)
⊢ x✝ ∈ Gamma 0 ↔ x✝ ∈ ⊥

Next tactic:
simp only [Gamma_mem, coe_matrix_coe, Int.coe_castRingHom, map_apply, Int.cast_id,
    Subgroup.mem_bot]
theorem Gamma_zero_bot : Gamma 0 = ⊥ := by
  ext
  simp only [Gamma_mem, coe_matrix_coe, Int.coe_castRingHom, map_apply, Int.cast_id,
    Subgroup.mem_bot]
  

Proof state:
case h
N : ℕ
x✝ : SL(2, ℤ)
⊢ ↑(↑x✝ 0 0) = 1 ∧ ↑(↑x✝ 0 1) = 0 ∧ ↑(↑x✝ 1 0) = 0 ∧ ↑(↑x✝ 1 1) = 1 ↔ x✝ = 1

Next tactic:
constructor
theorem Gamma_zero_bot : Gamma 0 = ⊥ := by
  ext
  simp only [Gamma_mem, coe_matrix_coe, Int.coe_castRingHom, map_apply, Int.cast_id,
    Subgroup.mem_bot]
  constructor
  · 

Proof state:
case h.mp
N : ℕ
x✝ : SL(2, ℤ)
⊢ ↑(↑x✝ 0 0) = 1 ∧ ↑(↑x✝ 0 1) = 0 ∧ ↑(↑x✝ 1 0) = 0 ∧ ↑(↑x✝ 1 1) = 1 → x✝ = 1

Next tactic:
intro h
theorem Gamma_zero_bot : Gamma 0 = ⊥ := by
  ext
  simp only [Gamma_mem, coe_matrix_coe, Int.coe_castRingHom, map_apply, Int.cast_id,
    Subgroup.mem_bot]
  constructor
  · intro h
    

Proof state:
case h.mp
N : ℕ
x✝ : SL(2, ℤ)
h : ↑(↑x✝ 0 0) = 1 ∧ ↑(↑x✝ 0 1) = 0 ∧ ↑(↑x✝ 1 0) = 0 ∧ ↑(↑x✝ 1 1) = 1
⊢ x✝ = 1

Next tactic:
ext i j
theorem Gamma_zero_bot : Gamma 0 = ⊥ := by
  ext
  simp only [Gamma_mem, coe_matrix_coe, Int.coe_castRingHom, map_apply, Int.cast_id,
    Subgroup.mem_bot]
  constructor
  · intro h
    ext i j
    

Proof state:
case h.mp.a
N : ℕ
x✝ : SL(2, ℤ)
h : ↑(↑x✝ 0 0) = 1 ∧ ↑(↑x✝ 0 1) = 0 ∧ ↑(↑x✝ 1 0) = 0 ∧ ↑(↑x✝ 1 1) = 1
i j : Fin 2
⊢ ↑x✝ i j = ↑1 i j

Next tactic:
fin_cases i
theorem Gamma_zero_bot : Gamma 0 = ⊥ := by
  ext
  simp only [Gamma_mem, coe_matrix_coe, Int.coe_castRingHom, map_apply, Int.cast_id,
    Subgroup.mem_bot]
  constructor
  · intro h
    ext i j
    fin_cases i <;> 

Proof state:
case h.mp.a.head
N : ℕ
x✝ : SL(2, ℤ)
h : ↑(↑x✝ 0 0) = 1 ∧ ↑(↑x✝ 0 1) = 0 ∧ ↑(↑x✝ 1 0) = 0 ∧ ↑(↑x✝ 1 1) = 1
j : Fin 2
⊢ ↑x✝ { val := 0, isLt := (_ : 0 < 2) } j = ↑1 { val := 0, isLt := (_ : 0 < 2) } j

Next tactic:
fin_cases j
theorem Gamma_zero_bot : Gamma 0 = ⊥ := by
  ext
  simp only [Gamma_mem, coe_matrix_coe, Int.coe_castRingHom, map_apply, Int.cast_id,
    Subgroup.mem_bot]
  constructor
  · intro h
    ext i j
    fin_cases i <;> 

Proof state:
case h.mp.a.tail.head
N : ℕ
x✝ : SL(2, ℤ)
h : ↑(↑x✝ 0 0) = 1 ∧ ↑(↑x✝ 0 1) = 0 ∧ ↑(↑x✝ 1 0) = 0 ∧ ↑(↑x✝ 1 1) = 1
j : Fin 2
⊢ ↑x✝ { val := 1, isLt := (_ : (fun a => a < 2) 1) } j = ↑1 { val := 1, isLt := (_ : (fun a => a < 2) 1) } j

Next tactic:
fin_cases j
theorem Gamma_zero_bot : Gamma 0 = ⊥ := by
  ext
  simp only [Gamma_mem, coe_matrix_coe, Int.coe_castRingHom, map_apply, Int.cast_id,
    Subgroup.mem_bot]
  constructor
  · intro h
    ext i j
    fin_cases i <;> fin_cases j <;> 

Proof state:
case h.mp.a.head.head
N : ℕ
x✝ : SL(2, ℤ)
h : ↑(↑x✝ 0 0) = 1 ∧ ↑(↑x✝ 0 1) = 0 ∧ ↑(↑x✝ 1 0) = 0 ∧ ↑(↑x✝ 1 1) = 1
⊢ ↑x✝ { val := 0, isLt := (_ : 0 < 2) } { val := 0, isLt := (_ : 0 < 2) } =
    ↑1 { val := 0, isLt := (_ : 0 < 2) } { val := 0, isLt := (_ : 0 < 2) }

Next tactic:
simp only [h]
theorem Gamma_zero_bot : Gamma 0 = ⊥ := by
  ext
  simp only [Gamma_mem, coe_matrix_coe, Int.coe_castRingHom, map_apply, Int.cast_id,
    Subgroup.mem_bot]
  constructor
  · intro h
    ext i j
    fin_cases i <;> fin_cases j <;> 

Proof state:
case h.mp.a.head.tail.head
N : ℕ
x✝ : SL(2, ℤ)
h : ↑(↑x✝ 0 0) = 1 ∧ ↑(↑x✝ 0 1) = 0 ∧ ↑(↑x✝ 1 0) = 0 ∧ ↑(↑x✝ 1 1) = 1
⊢ ↑x✝ { val := 0, isLt := (_ : 0 < 2) } { val := 1, isLt := (_ : (fun a => a < 2) 1) } =
    ↑1 { val := 0, isLt := (_ : 0 < 2) } { val := 1, isLt := (_ : (fun a => a < 2) 1) }

Next tactic:
simp only [h]
theorem Gamma_zero_bot : Gamma 0 = ⊥ := by
  ext
  simp only [Gamma_mem, coe_matrix_coe, Int.coe_castRingHom, map_apply, Int.cast_id,
    Subgroup.mem_bot]
  constructor
  · intro h
    ext i j
    fin_cases i <;> fin_cases j <;> 

Proof state:
case h.mp.a.tail.head.head
N : ℕ
x✝ : SL(2, ℤ)
h : ↑(↑x✝ 0 0) = 1 ∧ ↑(↑x✝ 0 1) = 0 ∧ ↑(↑x✝ 1 0) = 0 ∧ ↑(↑x✝ 1 1) = 1
⊢ ↑x✝ { val := 1, isLt := (_ : (fun a => a < 2) 1) } { val := 0, isLt := (_ : 0 < 2) } =
    ↑1 { val := 1, isLt := (_ : (fun a => a < 2) 1) } { val := 0, isLt := (_ : 0 < 2) }

Next tactic:
simp only [h]
theorem Gamma_zero_bot : Gamma 0 = ⊥ := by
  ext
  simp only [Gamma_mem, coe_matrix_coe, Int.coe_castRingHom, map_apply, Int.cast_id,
    Subgroup.mem_bot]
  constructor
  · intro h
    ext i j
    fin_cases i <;> fin_cases j <;> 

Proof state:
case h.mp.a.tail.head.tail.head
N : ℕ
x✝ : SL(2, ℤ)
h : ↑(↑x✝ 0 0) = 1 ∧ ↑(↑x✝ 0 1) = 0 ∧ ↑(↑x✝ 1 0) = 0 ∧ ↑(↑x✝ 1 1) = 1
⊢ ↑x✝ { val := 1, isLt := (_ : (fun a => a < 2) 1) } { val := 1, isLt := (_ : (fun a => a < 2) 1) } =
    ↑1 { val := 1, isLt := (_ : (fun a => a < 2) 1) } { val := 1, isLt := (_ : (fun a => a < 2) 1) }

Next tactic:
simp only [h]
theorem Gamma_zero_bot : Gamma 0 = ⊥ := by
  ext
  simp only [Gamma_mem, coe_matrix_coe, Int.coe_castRingHom, map_apply, Int.cast_id,
    Subgroup.mem_bot]
  constructor
  · intro h
    ext i j
    fin_cases i <;> fin_cases j <;> simp only [h]
    

Proof state:
case h.mp.a.head.head
N : ℕ
x✝ : SL(2, ℤ)
h : ↑(↑x✝ 0 0) = 1 ∧ ↑(↑x✝ 0 1) = 0 ∧ ↑(↑x✝ 1 0) = 0 ∧ ↑(↑x✝ 1 1) = 1
⊢ ↑x✝ { val := 0, isLt := (_ : 0 < 2) } { val := 0, isLt := (_ : 0 < 2) } =
    ↑1 { val := 0, isLt := (_ : 0 < 2) } { val := 0, isLt := (_ : 0 < 2) }
case h.mp.a.head.tail.head
N : ℕ
x✝ : SL(2, ℤ)
h : ↑(↑x✝ 0 0) = 1 ∧ ↑(↑x✝ 0 1) = 0 ∧ ↑(↑x✝ 1 0) = 0 ∧ ↑(↑x✝ 1 1) = 1
⊢ ↑x✝ { val := 0, isLt := (_ : 0 < 2) } { val := 1, isLt := (_ : (fun a => a < 2) 1) } =
    ↑1 { val := 0, isLt := (_ : 0 < 2) } { val := 1, isLt := (_ : (fun a => a < 2) 1) }
case h.mp.a.tail.head.head
N : ℕ
x✝ : SL(2, ℤ)
h : ↑(↑x✝ 0 0) = 1 ∧ ↑(↑x✝ 0 1) = 0 ∧ ↑(↑x✝ 1 0) = 0 ∧ ↑(↑x✝ 1 1) = 1
⊢ ↑x✝ { val := 1, isLt := (_ : (fun a => a < 2) 1) } { val := 0, isLt := (_ : 0 < 2) } =
    ↑1 { val := 1, isLt := (_ : (fun a => a < 2) 1) } { val := 0, isLt := (_ : 0 < 2) }
case h.mp.a.tail.head.tail.head
N : ℕ
x✝ : SL(2, ℤ)
h : ↑(↑x✝ 0 0) = 1 ∧ ↑(↑x✝ 0 1) = 0 ∧ ↑(↑x✝ 1 0) = 0 ∧ ↑(↑x✝ 1 1) = 1
⊢ ↑x✝ { val := 1, isLt := (_ : (fun a => a < 2) 1) } { val := 1, isLt := (_ : (fun a => a < 2) 1) } =
    ↑1 { val := 1, isLt := (_ : (fun a => a < 2) 1) } { val := 1, isLt := (_ : (fun a => a < 2) 1) }

Next tactic:
exacts [h.1, h.2.1, h.2.2.1, h.2.2.2]
theorem Gamma_zero_bot : Gamma 0 = ⊥ := by
  ext
  simp only [Gamma_mem, coe_matrix_coe, Int.coe_castRingHom, map_apply, Int.cast_id,
    Subgroup.mem_bot]
  constructor
  · intro h
    ext i j
    fin_cases i <;> fin_cases j <;> simp only [h]
    exacts [h.1, h.2.1, h.2.2.1, h.2.2.2]
  · 

Proof state:
case h.mpr
N : ℕ
x✝ : SL(2, ℤ)
⊢ x✝ = 1 → ↑(↑x✝ 0 0) = 1 ∧ ↑(↑x✝ 0 1) = 0 ∧ ↑(↑x✝ 1 0) = 0 ∧ ↑(↑x✝ 1 1) = 1

Next tactic:
intro h
theorem Gamma_zero_bot : Gamma 0 = ⊥ := by
  ext
  simp only [Gamma_mem, coe_matrix_coe, Int.coe_castRingHom, map_apply, Int.cast_id,
    Subgroup.mem_bot]
  constructor
  · intro h
    ext i j
    fin_cases i <;> fin_cases j <;> simp only [h]
    exacts [h.1, h.2.1, h.2.2.1, h.2.2.2]
  · intro h
    

Proof state:
case h.mpr
N : ℕ
x✝ : SL(2, ℤ)
h : x✝ = 1
⊢ ↑(↑x✝ 0 0) = 1 ∧ ↑(↑x✝ 0 1) = 0 ∧ ↑(↑x✝ 1 0) = 0 ∧ ↑(↑x✝ 1 1) = 1

Next tactic:
simp [h]
/-- The congruence subgroup of `SL(2, ℤ)` of matrices whose lower left-hand entry reduces to zero
modulo `N`. -/
def Gamma0 (N : ℕ) : Subgroup SL(2, ℤ) where
  carrier := { g : SL(2, ℤ) | ((↑ₘg 1 0 : ℤ) : ZMod N) = 0 }
  one_mem' := by simp
  mul_mem' := by
    

Proof state:
N✝ N : ℕ
⊢ ∀ {a b : SL(2, ℤ)}, a ∈ {g | ↑(↑g 1 0) = 0} → b ∈ {g | ↑(↑g 1 0) = 0} → a * b ∈ {g | ↑(↑g 1 0) = 0}

Next tactic:
intro a b ha hb
/-- The congruence subgroup of `SL(2, ℤ)` of matrices whose lower left-hand entry reduces to zero
modulo `N`. -/
def Gamma0 (N : ℕ) : Subgroup SL(2, ℤ) where
  carrier := { g : SL(2, ℤ) | ((↑ₘg 1 0 : ℤ) : ZMod N) = 0 }
  one_mem' := by simp
  mul_mem' := by
    intro a b ha hb
    

Proof state:
N✝ N : ℕ
a b : SL(2, ℤ)
ha : a ∈ {g | ↑(↑g 1 0) = 0}
hb : b ∈ {g | ↑(↑g 1 0) = 0}
⊢ a * b ∈ {g | ↑(↑g 1 0) = 0}

Next tactic:
simp only [Set.mem_setOf_eq]
/-- The congruence subgroup of `SL(2, ℤ)` of matrices whose lower left-hand entry reduces to zero
modulo `N`. -/
def Gamma0 (N : ℕ) : Subgroup SL(2, ℤ) where
  carrier := { g : SL(2, ℤ) | ((↑ₘg 1 0 : ℤ) : ZMod N) = 0 }
  one_mem' := by simp
  mul_mem' := by
    intro a b ha hb
    simp only [Set.mem_setOf_eq]
    

Proof state:
N✝ N : ℕ
a b : SL(2, ℤ)
ha : a ∈ {g | ↑(↑g 1 0) = 0}
hb : b ∈ {g | ↑(↑g 1 0) = 0}
⊢ ↑(↑(a * b) 1 0) = 0

Next tactic:
have h := (Matrix.two_mul_expl a.1 b.1).2.2.1
/-- The congruence subgroup of `SL(2, ℤ)` of matrices whose lower left-hand entry reduces to zero
modulo `N`. -/
def Gamma0 (N : ℕ) : Subgroup SL(2, ℤ) where
  carrier := { g : SL(2, ℤ) | ((↑ₘg 1 0 : ℤ) : ZMod N) = 0 }
  one_mem' := by simp
  mul_mem' := by
    intro a b ha hb
    simp only [Set.mem_setOf_eq]
    have h := (Matrix.two_mul_expl a.1 b.1).2.2.1
    

Proof state:
N✝ N : ℕ
a b : SL(2, ℤ)
ha : a ∈ {g | ↑(↑g 1 0) = 0}
hb : b ∈ {g | ↑(↑g 1 0) = 0}
h : (↑a * ↑b) 1 0 = ↑a 1 0 * ↑b 0 0 + ↑a 1 1 * ↑b 1 0
⊢ ↑(↑(a * b) 1 0) = 0

Next tactic:
simp only [coe_matrix_coe, coe_mul, Int.coe_castRingHom, map_apply, Set.mem_setOf_eq] at *
/-- The congruence subgroup of `SL(2, ℤ)` of matrices whose lower left-hand entry reduces to zero
modulo `N`. -/
def Gamma0 (N : ℕ) : Subgroup SL(2, ℤ) where
  carrier := { g : SL(2, ℤ) | ((↑ₘg 1 0 : ℤ) : ZMod N) = 0 }
  one_mem' := by simp
  mul_mem' := by
    intro a b ha hb
    simp only [Set.mem_setOf_eq]
    have h := (Matrix.two_mul_expl a.1 b.1).2.2.1
    simp only [coe_matrix_coe, coe_mul, Int.coe_castRingHom, map_apply, Set.mem_setOf_eq] at *
    

Proof state:
N✝ N : ℕ
a b : SL(2, ℤ)
ha : ↑(↑a 1 0) = 0
hb : ↑(↑b 1 0) = 0
h : (↑a * ↑b) 1 0 = ↑a 1 0 * ↑b 0 0 + ↑a 1 1 * ↑b 1 0
⊢ ↑((↑a * ↑b) 1 0) = 0

Next tactic:
rw [h]
/-- The congruence subgroup of `SL(2, ℤ)` of matrices whose lower left-hand entry reduces to zero
modulo `N`. -/
def Gamma0 (N : ℕ) : Subgroup SL(2, ℤ) where
  carrier := { g : SL(2, ℤ) | ((↑ₘg 1 0 : ℤ) : ZMod N) = 0 }
  one_mem' := by simp
  mul_mem' := by
    intro a b ha hb
    simp only [Set.mem_setOf_eq]
    have h := (Matrix.two_mul_expl a.1 b.1).2.2.1
    simp only [coe_matrix_coe, coe_mul, Int.coe_castRingHom, map_apply, Set.mem_setOf_eq] at *
    rw [h]
    

Proof state:
N✝ N : ℕ
a b : SL(2, ℤ)
ha : ↑(↑a 1 0) = 0
hb : ↑(↑b 1 0) = 0
h : (↑a * ↑b) 1 0 = ↑a 1 0 * ↑b 0 0 + ↑a 1 1 * ↑b 1 0
⊢ ↑(↑a 1 0 * ↑b 0 0 + ↑a 1 1 * ↑b 1 0) = 0

Next tactic:
simp [ha, hb]
/-- The congruence subgroup of `SL(2, ℤ)` of matrices whose lower left-hand entry reduces to zero
modulo `N`. -/
def Gamma0 (N : ℕ) : Subgroup SL(2, ℤ) where
  carrier := { g : SL(2, ℤ) | ((↑ₘg 1 0 : ℤ) : ZMod N) = 0 }
  one_mem' := by 

Proof state:
N✝ N : ℕ
⊢ 1 ∈
    { carrier := {g | ↑(↑g 1 0) = 0},
        mul_mem' :=
          (_ :
            ∀ {a b : SL(2, ℤ)},
              a ∈ {g | ↑(↑g 1 0) = 0} → b ∈ {g | ↑(↑g 1 0) = 0} → a * b ∈ {g | ↑(↑g 1 0) = 0}) }.carrier

Next tactic:
simp
/-- The congruence subgroup of `SL(2, ℤ)` of matrices whose lower left-hand entry reduces to zero
modulo `N`. -/
def Gamma0 (N : ℕ) : Subgroup SL(2, ℤ) where
  carrier := { g : SL(2, ℤ) | ((↑ₘg 1 0 : ℤ) : ZMod N) = 0 }
  one_mem' := by simp
  mul_mem' := by
    intro a b ha hb
    simp only [Set.mem_setOf_eq]
    have h := (Matrix.two_mul_expl a.1 b.1).2.2.1
    simp only [coe_matrix_coe, coe_mul, Int.coe_castRingHom, map_apply, Set.mem_setOf_eq] at *
    rw [h]
    simp [ha, hb]
  inv_mem' := by
    

Proof state:
N✝ N : ℕ
⊢ ∀ {x : SL(2, ℤ)},
    x ∈
        {
              toSubsemigroup :=
                { carrier := {g | ↑(↑g 1 0) = 0},
                  mul_mem' :=
                    (_ :
                      ∀ {a b : SL(2, ℤ)},
                        a ∈ {g | ↑(↑g 1 0) = 0} → b ∈ {g | ↑(↑g 1 0) = 0} → a * b ∈ {g | ↑(↑g 1 0) = 0}) },
              one_mem' := (_ : ↑(OfNat.ofNat 1 1 0) = 0) }.toSubsemigroup.carrier →
      x⁻¹ ∈
        {
              toSubsemigroup :=
                { carrier := {g | ↑(↑g 1 0) = 0},
                  mul_mem' :=
                    (_ :
                      ∀ {a b : SL(2, ℤ)},
                        a ∈ {g | ↑(↑g 1 0) = 0} → b ∈ {g | ↑(↑g 1 0) = 0} → a * b ∈ {g | ↑(↑g 1 0) = 0}) },
              one_mem' := (_ : ↑(OfNat.ofNat 1 1 0) = 0) }.toSubsemigroup.carrier

Next tactic:
intro a ha
/-- The congruence subgroup of `SL(2, ℤ)` of matrices whose lower left-hand entry reduces to zero
modulo `N`. -/
def Gamma0 (N : ℕ) : Subgroup SL(2, ℤ) where
  carrier := { g : SL(2, ℤ) | ((↑ₘg 1 0 : ℤ) : ZMod N) = 0 }
  one_mem' := by simp
  mul_mem' := by
    intro a b ha hb
    simp only [Set.mem_setOf_eq]
    have h := (Matrix.two_mul_expl a.1 b.1).2.2.1
    simp only [coe_matrix_coe, coe_mul, Int.coe_castRingHom, map_apply, Set.mem_setOf_eq] at *
    rw [h]
    simp [ha, hb]
  inv_mem' := by
    intro a ha
    

Proof state:
N✝ N : ℕ
a : SL(2, ℤ)
ha :
  a ∈
    {
          toSubsemigroup :=
            { carrier := {g | ↑(↑g 1 0) = 0},
              mul_mem' :=
                (_ :
                  ∀ {a b : SL(2, ℤ)},
                    a ∈ {g | ↑(↑g 1 0) = 0} → b ∈ {g | ↑(↑g 1 0) = 0} → a * b ∈ {g | ↑(↑g 1 0) = 0}) },
          one_mem' := (_ : ↑(OfNat.ofNat 1 1 0) = 0) }.toSubsemigroup.carrier
⊢ a⁻¹ ∈
    {
          toSubsemigroup :=
            { carrier := {g | ↑(↑g 1 0) = 0},
              mul_mem' :=
                (_ :
                  ∀ {a b : SL(2, ℤ)},
                    a ∈ {g | ↑(↑g 1 0) = 0} → b ∈ {g | ↑(↑g 1 0) = 0} → a * b ∈ {g | ↑(↑g 1 0) = 0}) },
          one_mem' := (_ : ↑(OfNat.ofNat 1 1 0) = 0) }.toSubsemigroup.carrier

Next tactic:
simp only [Set.mem_setOf_eq]
/-- The congruence subgroup of `SL(2, ℤ)` of matrices whose lower left-hand entry reduces to zero
modulo `N`. -/
def Gamma0 (N : ℕ) : Subgroup SL(2, ℤ) where
  carrier := { g : SL(2, ℤ) | ((↑ₘg 1 0 : ℤ) : ZMod N) = 0 }
  one_mem' := by simp
  mul_mem' := by
    intro a b ha hb
    simp only [Set.mem_setOf_eq]
    have h := (Matrix.two_mul_expl a.1 b.1).2.2.1
    simp only [coe_matrix_coe, coe_mul, Int.coe_castRingHom, map_apply, Set.mem_setOf_eq] at *
    rw [h]
    simp [ha, hb]
  inv_mem' := by
    intro a ha
    simp only [Set.mem_setOf_eq]
    

Proof state:
N✝ N : ℕ
a : SL(2, ℤ)
ha :
  a ∈
    {
          toSubsemigroup :=
            { carrier := {g | ↑(↑g 1 0) = 0},
              mul_mem' :=
                (_ :
                  ∀ {a b : SL(2, ℤ)},
                    a ∈ {g | ↑(↑g 1 0) = 0} → b ∈ {g | ↑(↑g 1 0) = 0} → a * b ∈ {g | ↑(↑g 1 0) = 0}) },
          one_mem' := (_ : ↑(OfNat.ofNat 1 1 0) = 0) }.toSubsemigroup.carrier
⊢ ↑(↑a⁻¹ 1 0) = 0

Next tactic:
rw [SL2_inv_expl a]
/-- The congruence subgroup of `SL(2, ℤ)` of matrices whose lower left-hand entry reduces to zero
modulo `N`. -/
def Gamma0 (N : ℕ) : Subgroup SL(2, ℤ) where
  carrier := { g : SL(2, ℤ) | ((↑ₘg 1 0 : ℤ) : ZMod N) = 0 }
  one_mem' := by simp
  mul_mem' := by
    intro a b ha hb
    simp only [Set.mem_setOf_eq]
    have h := (Matrix.two_mul_expl a.1 b.1).2.2.1
    simp only [coe_matrix_coe, coe_mul, Int.coe_castRingHom, map_apply, Set.mem_setOf_eq] at *
    rw [h]
    simp [ha, hb]
  inv_mem' := by
    intro a ha
    simp only [Set.mem_setOf_eq]
    rw [SL2_inv_expl a]
    

Proof state:
N✝ N : ℕ
a : SL(2, ℤ)
ha :
  a ∈
    {
          toSubsemigroup :=
            { carrier := {g | ↑(↑g 1 0) = 0},
              mul_mem' :=
                (_ :
                  ∀ {a b : SL(2, ℤ)},
                    a ∈ {g | ↑(↑g 1 0) = 0} → b ∈ {g | ↑(↑g 1 0) = 0} → a * b ∈ {g | ↑(↑g 1 0) = 0}) },
          one_mem' := (_ : ↑(OfNat.ofNat 1 1 0) = 0) }.toSubsemigroup.carrier
⊢ ↑(↑{ val := ![![↑a 1 1, -↑a 0 1], ![-↑a 1 0, ↑a 0 0]],
            property := (_ : det ![![↑a 1 1, -↑a 0 1], ![-↑a 1 0, ↑a 0 0]] = 1) }
        1 0) =
    0

Next tactic:
simp only [cons_val_zero, cons_val_one, head_cons, coe_matrix_coe,
      coe_mk, Int.coe_castRingHom, map_apply, Int.cast_neg, neg_eq_zero, Set.mem_setOf_eq] at *
/-- The congruence subgroup of `SL(2, ℤ)` of matrices whose lower left-hand entry reduces to zero
modulo `N`. -/
def Gamma0 (N : ℕ) : Subgroup SL(2, ℤ) where
  carrier := { g : SL(2, ℤ) | ((↑ₘg 1 0 : ℤ) : ZMod N) = 0 }
  one_mem' := by simp
  mul_mem' := by
    intro a b ha hb
    simp only [Set.mem_setOf_eq]
    have h := (Matrix.two_mul_expl a.1 b.1).2.2.1
    simp only [coe_matrix_coe, coe_mul, Int.coe_castRingHom, map_apply, Set.mem_setOf_eq] at *
    rw [h]
    simp [ha, hb]
  inv_mem' := by
    intro a ha
    simp only [Set.mem_setOf_eq]
    rw [SL2_inv_expl a]
    simp only [cons_val_zero, cons_val_one, head_cons, coe_matrix_coe,
      coe_mk, Int.coe_castRingHom, map_apply, Int.cast_neg, neg_eq_zero, Set.mem_setOf_eq] at *
    

Proof state:
N✝ N : ℕ
a : SL(2, ℤ)
ha : ↑(↑a 1 0) = 0
⊢ ↑(↑a 1 0) = 0

Next tactic:
exact ha
theorem Gamma0_det (N : ℕ) (A : Gamma0 N) : (A.1.1.det : ZMod N) = 1 := by 

Proof state:
N✝ N : ℕ
A : ↥(Gamma0 N)
⊢ ↑(det ↑↑A) = 1

Next tactic:
simp [A.1.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 

Proof state:
N✝ N : ℕ
⊢ (fun g => ↑(↑↑g 1 1)) 1 = 1

Next tactic:
simp