l3lab/ntp-mathlib huggingface dataset:
/-- Each of the sums in this lemma is the cardinality of the set of integer points in each of the
  two triangles formed by the diagonal of the rectangle `(0, p/2) × (0, q/2)`. Adding them
  gives the number of points in the rectangle. -/
theorem sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : Fact p.Prime] (hq0 : (q : ZMod p) ≠ 0) :
    ∑ a in Ico 1 (p / 2).succ, a * q / p + ∑ a in Ico 1 (q / 2).succ, a * p / q =
    p / 2 * (q / 2) := by
  have hswap :
    ((Ico 1 (q / 2).succ ×ˢ Ico 1 (p / 2).succ).filter fun x : ℕ × ℕ => x.2 * q ≤ x.1 * p).card =
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ =>
        x.1 * q ≤ x.2 * p).card :=
    card_congr (fun x _ => Prod.swap x)
      (fun ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [mem_filter, and_self_iff, Prod.swap_prod_mk,
          forall_true_iff, mem_product])
      (fun ⟨_, _⟩ ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [Prod.mk.inj_iff, eq_self_iff_true,
          and_self_iff, Prod.swap_prod_mk, forall_true_iff])
      fun ⟨x₁, x₂⟩ h => ⟨⟨x₂, x₁⟩, by
        

Proof state:
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
x✝ : ℕ × ℕ
x₁ x₂ : ℕ
h : (x₁, x₂) ∈ filter (fun x => x.1 * q ≤ x.2 * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2)))
⊢ ∃ (ha : (x₂, x₁) ∈ filter (fun x => x.2 * q ≤ x.1 * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))),
    (fun x x_1 => Prod.swap x) (x₂, x₁) ha = (x₁, x₂)

Next tactic:
revert h
/-- Each of the sums in this lemma is the cardinality of the set of integer points in each of the
  two triangles formed by the diagonal of the rectangle `(0, p/2) × (0, q/2)`. Adding them
  gives the number of points in the rectangle. -/
theorem sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : Fact p.Prime] (hq0 : (q : ZMod p) ≠ 0) :
    ∑ a in Ico 1 (p / 2).succ, a * q / p + ∑ a in Ico 1 (q / 2).succ, a * p / q =
    p / 2 * (q / 2) := by
  have hswap :
    ((Ico 1 (q / 2).succ ×ˢ Ico 1 (p / 2).succ).filter fun x : ℕ × ℕ => x.2 * q ≤ x.1 * p).card =
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ =>
        x.1 * q ≤ x.2 * p).card :=
    card_congr (fun x _ => Prod.swap x)
      (fun ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [mem_filter, and_self_iff, Prod.swap_prod_mk,
          forall_true_iff, mem_product])
      (fun ⟨_, _⟩ ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [Prod.mk.inj_iff, eq_self_iff_true,
          and_self_iff, Prod.swap_prod_mk, forall_true_iff])
      fun ⟨x₁, x₂⟩ h => ⟨⟨x₂, x₁⟩, by
        revert h
        

Proof state:
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
x✝ : ℕ × ℕ
x₁ x₂ : ℕ
⊢ (x₁, x₂) ∈ filter (fun x => x.1 * q ≤ x.2 * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))) →
    ∃ (ha : (x₂, x₁) ∈ filter (fun x => x.2 * q ≤ x.1 * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))),
      (fun x x_1 => Prod.swap x) (x₂, x₁) ha = (x₁, x₂)

Next tactic:
simp (config := { contextual := true }) only [mem_filter, eq_self_iff_true, and_self_iff,
          exists_prop_of_true, Prod.swap_prod_mk, forall_true_iff, mem_product]
/-- Each of the sums in this lemma is the cardinality of the set of integer points in each of the
  two triangles formed by the diagonal of the rectangle `(0, p/2) × (0, q/2)`. Adding them
  gives the number of points in the rectangle. -/
theorem sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : Fact p.Prime] (hq0 : (q : ZMod p) ≠ 0) :
    ∑ a in Ico 1 (p / 2).succ, a * q / p + ∑ a in Ico 1 (q / 2).succ, a * p / q =
    p / 2 * (q / 2) := by
  have hswap :
    ((Ico 1 (q / 2).succ ×ˢ Ico 1 (p / 2).succ).filter fun x : ℕ × ℕ => x.2 * q ≤ x.1 * p).card =
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ =>
        x.1 * q ≤ x.2 * p).card :=
    card_congr (fun x _ => Prod.swap x)
      (fun ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [mem_filter, and_self_iff, Prod.swap_prod_mk,
          forall_true_iff, mem_product])
      (fun ⟨_, _⟩ ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [Prod.mk.inj_iff, eq_self_iff_true,
          and_self_iff, Prod.swap_prod_mk, forall_true_iff])
      fun ⟨x₁, x₂⟩ h => ⟨⟨x₂, x₁⟩, by
        revert h
        simp (config := { contextual := true }) only [mem_filter, eq_self_iff_true, and_self_iff,
          exists_prop_of_true, Prod.swap_prod_mk, forall_true_iff, mem_product]⟩
  

Proof state:
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.2 * q ≤ x.1 * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.1 * q ≤ x.2 * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
⊢ ∑ a in Ico 1 (succ (p / 2)), a * q / p + ∑ a in Ico 1 (succ (q / 2)), a * p / q = p / 2 * (q / 2)

Next tactic:
have hdisj :
    Disjoint ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.2 * p ≤ x.1 * q)
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.1 * q ≤ x.2 * p) := by
    apply disjoint_filter.2 fun x hx hpq hqp => ?_
    have hxp : x.1 < p := lt_of_le_of_lt
      (show x.1 ≤ p / 2 by simp_all only [lt_succ_iff, mem_Ico, mem_product])
      (Nat.div_lt_self hp.1.pos (by decide))
    have : (x.1 : ZMod p) = 0 := by
      simpa [hq0] using congr_arg ((↑) : ℕ → ZMod p) (le_antisymm hpq hqp)
    apply_fun ZMod.val at this
    rw [val_cast_of_lt hxp, val_zero] at this
    simp only [this, nonpos_iff_eq_zero, mem_Ico, one_ne_zero, false_and_iff, mem_product] at hx
/-- Each of the sums in this lemma is the cardinality of the set of integer points in each of the
  two triangles formed by the diagonal of the rectangle `(0, p/2) × (0, q/2)`. Adding them
  gives the number of points in the rectangle. -/
theorem sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : Fact p.Prime] (hq0 : (q : ZMod p) ≠ 0) :
    ∑ a in Ico 1 (p / 2).succ, a * q / p + ∑ a in Ico 1 (q / 2).succ, a * p / q =
    p / 2 * (q / 2) := by
  have hswap :
    ((Ico 1 (q / 2).succ ×ˢ Ico 1 (p / 2).succ).filter fun x : ℕ × ℕ => x.2 * q ≤ x.1 * p).card =
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ =>
        x.1 * q ≤ x.2 * p).card :=
    card_congr (fun x _ => Prod.swap x)
      (fun ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [mem_filter, and_self_iff, Prod.swap_prod_mk,
          forall_true_iff, mem_product])
      (fun ⟨_, _⟩ ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [Prod.mk.inj_iff, eq_self_iff_true,
          and_self_iff, Prod.swap_prod_mk, forall_true_iff])
      fun ⟨x₁, x₂⟩ h => ⟨⟨x₂, x₁⟩, by
        revert h
        simp (config := { contextual := true }) only [mem_filter, eq_self_iff_true, and_self_iff,
          exists_prop_of_true, Prod.swap_prod_mk, forall_true_iff, mem_product]⟩
  have hdisj :
    Disjoint ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.2 * p ≤ x.1 * q)
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.1 * q ≤ x.2 * p) := by
    

Proof state:
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.2 * q ≤ x.1 * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.1 * q ≤ x.2 * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
⊢ Disjoint (filter (fun x => x.2 * p ≤ x.1 * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
    (filter (fun x => x.1 * q ≤ x.2 * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))

Next tactic:
apply disjoint_filter.2 fun x hx hpq hqp => ?_
/-- Each of the sums in this lemma is the cardinality of the set of integer points in each of the
  two triangles formed by the diagonal of the rectangle `(0, p/2) × (0, q/2)`. Adding them
  gives the number of points in the rectangle. -/
theorem sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : Fact p.Prime] (hq0 : (q : ZMod p) ≠ 0) :
    ∑ a in Ico 1 (p / 2).succ, a * q / p + ∑ a in Ico 1 (q / 2).succ, a * p / q =
    p / 2 * (q / 2) := by
  have hswap :
    ((Ico 1 (q / 2).succ ×ˢ Ico 1 (p / 2).succ).filter fun x : ℕ × ℕ => x.2 * q ≤ x.1 * p).card =
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ =>
        x.1 * q ≤ x.2 * p).card :=
    card_congr (fun x _ => Prod.swap x)
      (fun ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [mem_filter, and_self_iff, Prod.swap_prod_mk,
          forall_true_iff, mem_product])
      (fun ⟨_, _⟩ ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [Prod.mk.inj_iff, eq_self_iff_true,
          and_self_iff, Prod.swap_prod_mk, forall_true_iff])
      fun ⟨x₁, x₂⟩ h => ⟨⟨x₂, x₁⟩, by
        revert h
        simp (config := { contextual := true }) only [mem_filter, eq_self_iff_true, and_self_iff,
          exists_prop_of_true, Prod.swap_prod_mk, forall_true_iff, mem_product]⟩
  have hdisj :
    Disjoint ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.2 * p ≤ x.1 * q)
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.1 * q ≤ x.2 * p) := by
    apply disjoint_filter.2 fun x hx hpq hqp => ?_
    

Proof state:
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.2 * q ≤ x.1 * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.1 * q ≤ x.2 * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
hx : x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
hpq : x.2 * p ≤ x.1 * q
hqp : x.1 * q ≤ x.2 * p
⊢ False

Next tactic:
have hxp : x.1 < p := lt_of_le_of_lt
      (show x.1 ≤ p / 2 by simp_all only [lt_succ_iff, mem_Ico, mem_product])
      (Nat.div_lt_self hp.1.pos (by decide))
/-- Each of the sums in this lemma is the cardinality of the set of integer points in each of the
  two triangles formed by the diagonal of the rectangle `(0, p/2) × (0, q/2)`. Adding them
  gives the number of points in the rectangle. -/
theorem sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : Fact p.Prime] (hq0 : (q : ZMod p) ≠ 0) :
    ∑ a in Ico 1 (p / 2).succ, a * q / p + ∑ a in Ico 1 (q / 2).succ, a * p / q =
    p / 2 * (q / 2) := by
  have hswap :
    ((Ico 1 (q / 2).succ ×ˢ Ico 1 (p / 2).succ).filter fun x : ℕ × ℕ => x.2 * q ≤ x.1 * p).card =
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ =>
        x.1 * q ≤ x.2 * p).card :=
    card_congr (fun x _ => Prod.swap x)
      (fun ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [mem_filter, and_self_iff, Prod.swap_prod_mk,
          forall_true_iff, mem_product])
      (fun ⟨_, _⟩ ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [Prod.mk.inj_iff, eq_self_iff_true,
          and_self_iff, Prod.swap_prod_mk, forall_true_iff])
      fun ⟨x₁, x₂⟩ h => ⟨⟨x₂, x₁⟩, by
        revert h
        simp (config := { contextual := true }) only [mem_filter, eq_self_iff_true, and_self_iff,
          exists_prop_of_true, Prod.swap_prod_mk, forall_true_iff, mem_product]⟩
  have hdisj :
    Disjoint ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.2 * p ≤ x.1 * q)
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.1 * q ≤ x.2 * p) := by
    apply disjoint_filter.2 fun x hx hpq hqp => ?_
    have hxp : x.1 < p := lt_of_le_of_lt
      (show x.1 ≤ p / 2 by 

Proof state:
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.2 * q ≤ x.1 * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.1 * q ≤ x.2 * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
hx : x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
hpq : x.2 * p ≤ x.1 * q
hqp : x.1 * q ≤ x.2 * p
⊢ x.1 ≤ p / 2

Next tactic:
simp_all only [lt_succ_iff, mem_Ico, mem_product]
/-- Each of the sums in this lemma is the cardinality of the set of integer points in each of the
  two triangles formed by the diagonal of the rectangle `(0, p/2) × (0, q/2)`. Adding them
  gives the number of points in the rectangle. -/
theorem sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : Fact p.Prime] (hq0 : (q : ZMod p) ≠ 0) :
    ∑ a in Ico 1 (p / 2).succ, a * q / p + ∑ a in Ico 1 (q / 2).succ, a * p / q =
    p / 2 * (q / 2) := by
  have hswap :
    ((Ico 1 (q / 2).succ ×ˢ Ico 1 (p / 2).succ).filter fun x : ℕ × ℕ => x.2 * q ≤ x.1 * p).card =
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ =>
        x.1 * q ≤ x.2 * p).card :=
    card_congr (fun x _ => Prod.swap x)
      (fun ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [mem_filter, and_self_iff, Prod.swap_prod_mk,
          forall_true_iff, mem_product])
      (fun ⟨_, _⟩ ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [Prod.mk.inj_iff, eq_self_iff_true,
          and_self_iff, Prod.swap_prod_mk, forall_true_iff])
      fun ⟨x₁, x₂⟩ h => ⟨⟨x₂, x₁⟩, by
        revert h
        simp (config := { contextual := true }) only [mem_filter, eq_self_iff_true, and_self_iff,
          exists_prop_of_true, Prod.swap_prod_mk, forall_true_iff, mem_product]⟩
  have hdisj :
    Disjoint ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.2 * p ≤ x.1 * q)
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.1 * q ≤ x.2 * p) := by
    apply disjoint_filter.2 fun x hx hpq hqp => ?_
    have hxp : x.1 < p := lt_of_le_of_lt
      (show x.1 ≤ p / 2 by simp_all only [lt_succ_iff, mem_Ico, mem_product])
      (Nat.div_lt_self hp.1.pos (by 

Proof state:
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.2 * q ≤ x.1 * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.1 * q ≤ x.2 * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
hx : x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
hpq : x.2 * p ≤ x.1 * q
hqp : x.1 * q ≤ x.2 * p
⊢ 1 < 2

Next tactic:
decide
/-- Each of the sums in this lemma is the cardinality of the set of integer points in each of the
  two triangles formed by the diagonal of the rectangle `(0, p/2) × (0, q/2)`. Adding them
  gives the number of points in the rectangle. -/
theorem sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : Fact p.Prime] (hq0 : (q : ZMod p) ≠ 0) :
    ∑ a in Ico 1 (p / 2).succ, a * q / p + ∑ a in Ico 1 (q / 2).succ, a * p / q =
    p / 2 * (q / 2) := by
  have hswap :
    ((Ico 1 (q / 2).succ ×ˢ Ico 1 (p / 2).succ).filter fun x : ℕ × ℕ => x.2 * q ≤ x.1 * p).card =
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ =>
        x.1 * q ≤ x.2 * p).card :=
    card_congr (fun x _ => Prod.swap x)
      (fun ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [mem_filter, and_self_iff, Prod.swap_prod_mk,
          forall_true_iff, mem_product])
      (fun ⟨_, _⟩ ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [Prod.mk.inj_iff, eq_self_iff_true,
          and_self_iff, Prod.swap_prod_mk, forall_true_iff])
      fun ⟨x₁, x₂⟩ h => ⟨⟨x₂, x₁⟩, by
        revert h
        simp (config := { contextual := true }) only [mem_filter, eq_self_iff_true, and_self_iff,
          exists_prop_of_true, Prod.swap_prod_mk, forall_true_iff, mem_product]⟩
  have hdisj :
    Disjoint ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.2 * p ≤ x.1 * q)
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.1 * q ≤ x.2 * p) := by
    apply disjoint_filter.2 fun x hx hpq hqp => ?_
    have hxp : x.1 < p := lt_of_le_of_lt
      (show x.1 ≤ p / 2 by simp_all only [lt_succ_iff, mem_Ico, mem_product])
      (Nat.div_lt_self hp.1.pos (by decide))
    

Proof state:
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.2 * q ≤ x.1 * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.1 * q ≤ x.2 * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
hx : x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
hpq : x.2 * p ≤ x.1 * q
hqp : x.1 * q ≤ x.2 * p
hxp : x.1 < p
⊢ False

Next tactic:
have : (x.1 : ZMod p) = 0 := by
      simpa [hq0] using congr_arg ((↑) : ℕ → ZMod p) (le_antisymm hpq hqp)
/-- Each of the sums in this lemma is the cardinality of the set of integer points in each of the
  two triangles formed by the diagonal of the rectangle `(0, p/2) × (0, q/2)`. Adding them
  gives the number of points in the rectangle. -/
theorem sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : Fact p.Prime] (hq0 : (q : ZMod p) ≠ 0) :
    ∑ a in Ico 1 (p / 2).succ, a * q / p + ∑ a in Ico 1 (q / 2).succ, a * p / q =
    p / 2 * (q / 2) := by
  have hswap :
    ((Ico 1 (q / 2).succ ×ˢ Ico 1 (p / 2).succ).filter fun x : ℕ × ℕ => x.2 * q ≤ x.1 * p).card =
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ =>
        x.1 * q ≤ x.2 * p).card :=
    card_congr (fun x _ => Prod.swap x)
      (fun ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [mem_filter, and_self_iff, Prod.swap_prod_mk,
          forall_true_iff, mem_product])
      (fun ⟨_, _⟩ ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [Prod.mk.inj_iff, eq_self_iff_true,
          and_self_iff, Prod.swap_prod_mk, forall_true_iff])
      fun ⟨x₁, x₂⟩ h => ⟨⟨x₂, x₁⟩, by
        revert h
        simp (config := { contextual := true }) only [mem_filter, eq_self_iff_true, and_self_iff,
          exists_prop_of_true, Prod.swap_prod_mk, forall_true_iff, mem_product]⟩
  have hdisj :
    Disjoint ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.2 * p ≤ x.1 * q)
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.1 * q ≤ x.2 * p) := by
    apply disjoint_filter.2 fun x hx hpq hqp => ?_
    have hxp : x.1 < p := lt_of_le_of_lt
      (show x.1 ≤ p / 2 by simp_all only [lt_succ_iff, mem_Ico, mem_product])
      (Nat.div_lt_self hp.1.pos (by decide))
    have : (x.1 : ZMod p) = 0 := by
      

Proof state:
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.2 * q ≤ x.1 * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.1 * q ≤ x.2 * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
hx : x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
hpq : x.2 * p ≤ x.1 * q
hqp : x.1 * q ≤ x.2 * p
hxp : x.1 < p
⊢ ↑x.1 = 0

Next tactic:
simpa [hq0] using congr_arg ((↑) : ℕ → ZMod p) (le_antisymm hpq hqp)
/-- Each of the sums in this lemma is the cardinality of the set of integer points in each of the
  two triangles formed by the diagonal of the rectangle `(0, p/2) × (0, q/2)`. Adding them
  gives the number of points in the rectangle. -/
theorem sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : Fact p.Prime] (hq0 : (q : ZMod p) ≠ 0) :
    ∑ a in Ico 1 (p / 2).succ, a * q / p + ∑ a in Ico 1 (q / 2).succ, a * p / q =
    p / 2 * (q / 2) := by
  have hswap :
    ((Ico 1 (q / 2).succ ×ˢ Ico 1 (p / 2).succ).filter fun x : ℕ × ℕ => x.2 * q ≤ x.1 * p).card =
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ =>
        x.1 * q ≤ x.2 * p).card :=
    card_congr (fun x _ => Prod.swap x)
      (fun ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [mem_filter, and_self_iff, Prod.swap_prod_mk,
          forall_true_iff, mem_product])
      (fun ⟨_, _⟩ ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [Prod.mk.inj_iff, eq_self_iff_true,
          and_self_iff, Prod.swap_prod_mk, forall_true_iff])
      fun ⟨x₁, x₂⟩ h => ⟨⟨x₂, x₁⟩, by
        revert h
        simp (config := { contextual := true }) only [mem_filter, eq_self_iff_true, and_self_iff,
          exists_prop_of_true, Prod.swap_prod_mk, forall_true_iff, mem_product]⟩
  have hdisj :
    Disjoint ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.2 * p ≤ x.1 * q)
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.1 * q ≤ x.2 * p) := by
    apply disjoint_filter.2 fun x hx hpq hqp => ?_
    have hxp : x.1 < p := lt_of_le_of_lt
      (show x.1 ≤ p / 2 by simp_all only [lt_succ_iff, mem_Ico, mem_product])
      (Nat.div_lt_self hp.1.pos (by decide))
    have : (x.1 : ZMod p) = 0 := by
      simpa [hq0] using congr_arg ((↑) : ℕ → ZMod p) (le_antisymm hpq hqp)
    

Proof state:
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.2 * q ≤ x.1 * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.1 * q ≤ x.2 * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
hx : x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
hpq : x.2 * p ≤ x.1 * q
hqp : x.1 * q ≤ x.2 * p
hxp : x.1 < p
this : ↑x.1 = 0
⊢ False

Next tactic:
apply_fun ZMod.val at this
/-- Each of the sums in this lemma is the cardinality of the set of integer points in each of the
  two triangles formed by the diagonal of the rectangle `(0, p/2) × (0, q/2)`. Adding them
  gives the number of points in the rectangle. -/
theorem sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : Fact p.Prime] (hq0 : (q : ZMod p) ≠ 0) :
    ∑ a in Ico 1 (p / 2).succ, a * q / p + ∑ a in Ico 1 (q / 2).succ, a * p / q =
    p / 2 * (q / 2) := by
  have hswap :
    ((Ico 1 (q / 2).succ ×ˢ Ico 1 (p / 2).succ).filter fun x : ℕ × ℕ => x.2 * q ≤ x.1 * p).card =
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ =>
        x.1 * q ≤ x.2 * p).card :=
    card_congr (fun x _ => Prod.swap x)
      (fun ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [mem_filter, and_self_iff, Prod.swap_prod_mk,
          forall_true_iff, mem_product])
      (fun ⟨_, _⟩ ⟨_, _⟩ => by
        simp (config := { contextual := true }) only [Prod.mk.inj_iff, eq_self_iff_true,
          and_self_iff, Prod.swap_prod_mk, forall_true_iff])
      fun ⟨x₁, x₂⟩ h => ⟨⟨x₂, x₁⟩, by
        revert h
        simp (config := { contextual := true }) only [mem_filter, eq_self_iff_true, and_self_iff,
          exists_prop_of_true, Prod.swap_prod_mk, forall_true_iff, mem_product]⟩
  have hdisj :
    Disjoint ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.2 * p ≤ x.1 * q)
      ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.1 * q ≤ x.2 * p) := by
    apply disjoint_filter.2 fun x hx hpq hqp => ?_
    have hxp : x.1 < p := lt_of_le_of_lt
      (show x.1 ≤ p / 2 by simp_all only [lt_succ_iff, mem_Ico, mem_product])
      (Nat.div_lt_self hp.1.pos (by decide))
    have : (x.1 : ZMod p) = 0 := by
      simpa [hq0] using congr_arg ((↑) : ℕ → ZMod p) (le_antisymm hpq hqp)
    apply_fun ZMod.val at this
    

Proof state:
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.2 * q ≤ x.1 * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.1 * q ≤ x.2 * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
hx : x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
hpq : x.2 * p ≤ x.1 * q
hqp : x.1 * q ≤ x.2 * p
hxp : x.1 < p
this : val ↑x.1 = val 0
⊢ False

Next tactic:
rw [val_cast_of_lt hxp, val_zero] at this