data.int.modeqMathlib.Data.Int.ModEq

This file has been ported!

Changes since the initial port

The following section lists changes to this file in mathlib3 and mathlib4 that occured after the initial port. Most recent changes are shown first. Hovering over a commit will show all commits associated with the same mathlib3 commit.

Changes in mathlib3

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(last sync)

feat(data/{int,nat}/modeq): a/c ≡ b/c mod m/c → a ≡ b mod m (#18666)

Also prove -a ≡ -b [ZMOD n] ↔ a ≡ b [ZMOD n], a ≡ b [ZMOD -n] ↔ a ≡ b [ZMOD n], generalise int.modeq.mul_left'/int.modeq.mul_right', and rename

  • int.gcd_pos_of_non_zero_leftint.gcd_pos_of_ne_zero_left
  • int.gcd_pos_of_non_zero_rightint.gcd_pos_of_ne_zero_right
  • eq_iff_modeq_int, char_p.int_coe_eq_int_coe_iffchar_p.int_cast_eq_int_cast (they were duplicates)
Diff
@@ -45,8 +45,12 @@ instance : is_refl _ (modeq n) := ⟨modeq.refl⟩
 
 @[trans] protected theorem trans : a ≡ b [ZMOD n] → b ≡ c [ZMOD n] → a ≡ c [ZMOD n] := eq.trans
 
+protected lemma eq : a ≡ b [ZMOD n] → a % n = b % n := id
+
 end modeq
 
+lemma modeq_comm : a ≡ b [ZMOD n] ↔ b ≡ a [ZMOD n] := ⟨modeq.symm, modeq.symm⟩
+
 lemma coe_nat_modeq_iff {a b n : ℕ} : a ≡ b [ZMOD n] ↔ a ≡ b [MOD n] :=
 by unfold modeq nat.modeq; rw ← int.coe_nat_eq_coe_nat_iff; simp [coe_nat_mod]
 
@@ -70,19 +74,27 @@ alias modeq_iff_dvd ↔ modeq.dvd modeq_of_dvd
 
 theorem mod_modeq (a n) : a % n ≡ a [ZMOD n] := mod_mod _ _
 
+@[simp] lemma neg_modeq_neg : -a ≡ -b [ZMOD n] ↔ a ≡ b [ZMOD n] :=
+by simp [modeq_iff_dvd, dvd_sub_comm]
+
+@[simp] lemma modeq_neg : a ≡ b [ZMOD -n] ↔ a ≡ b [ZMOD n] := by simp [modeq_iff_dvd]
+
 namespace modeq
 
 protected lemma of_dvd (d : m ∣ n) (h : a ≡ b [ZMOD n]) : a ≡ b [ZMOD m] :=
 modeq_of_dvd $ d.trans h.dvd
 
-protected theorem mul_left' (hc : 0 ≤ c) (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD (c * n)] :=
-or.cases_on hc.lt_or_eq (λ hc,
-  by unfold modeq;
-  simp [mul_mod_mul_of_pos hc, (show _ = _, from h)] )
-(λ hc, by simp [hc.symm])
+protected theorem mul_left' (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD (c * n)] :=
+begin
+  obtain hc | rfl | hc := lt_trichotomy c 0,
+  { rw [←neg_modeq_neg, ←modeq_neg, ←neg_mul, ←neg_mul, ←neg_mul],
+    simp only [modeq, mul_mod_mul_of_pos (neg_pos.2 hc), h.eq] },
+  { simp },
+  { simp only [modeq, mul_mod_mul_of_pos hc, h.eq] }
+end
 
-protected theorem mul_right' (hc : 0 ≤ c) (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD (n * c)] :=
-by rw [mul_comm a, mul_comm b, mul_comm n]; exact h.mul_left' hc
+protected theorem mul_right' (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD (n * c)] :=
+by rw [mul_comm a, mul_comm b, mul_comm n]; exact h.mul_left'
 
 protected theorem add (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a + c ≡ b + d [ZMOD n] :=
 modeq_iff_dvd.2 $ by { convert dvd_add h₁.dvd h₂.dvd, ring }
@@ -122,13 +134,10 @@ protected theorem sub_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a - c ≡ b - c [
 h.sub modeq.rfl
 
 protected theorem mul_left (c : ℤ) (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD n] :=
-or.cases_on (le_total 0 c)
-(λ hc, (h.mul_left' hc).of_dvd (dvd_mul_left _ _) )
-(λ hc, by rw [← neg_neg c, neg_mul, neg_mul _ b];
-    exact ((h.mul_left' $ neg_nonneg.2 hc).of_dvd (dvd_mul_left _ _)).neg)
+h.mul_left'.of_dvd $ dvd_mul_left _ _
 
 protected theorem mul_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n] :=
-by { rw [mul_comm a, mul_comm b], exact h.mul_left c }
+h.mul_right'.of_dvd $ dvd_mul_right _ _
 
 protected theorem mul (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a * c ≡ b * d [ZMOD n] :=
 (h₂.mul_left _).trans (h₁.mul_right _)
@@ -146,6 +155,28 @@ by rw [modeq_iff_dvd] at *; exact (dvd_mul_left n m).trans h
 theorem of_mul_right (m : ℤ) : a ≡ b [ZMOD n * m] → a ≡ b [ZMOD n] :=
 mul_comm m n ▸ of_mul_left _
 
+/-- To cancel a common factor `c` from a `modeq` we must divide the modulus `m` by `gcd m c`. -/
+lemma cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) : a ≡ b [ZMOD m / gcd m c] :=
+begin
+  let d := gcd m c,
+  have hmd := gcd_dvd_left m c,
+  have hcd := gcd_dvd_right m c,
+  rw modeq_iff_dvd at ⊢ h,
+  refine int.dvd_of_dvd_mul_right_of_gcd_one _ _,
+  show m / d ∣ c / d * (b - a),
+  { rw [mul_comm, ←int.mul_div_assoc (b - a) hcd, sub_mul],
+    exact int.div_dvd_div hmd h },
+  { rw [gcd_div hmd hcd, nat_abs_of_nat, nat.div_self (gcd_pos_of_ne_zero_left c hm.ne')] }
+end
+
+/-- To cancel a common factor `c` from a `modeq` we must divide the modulus `m` by `gcd m c`. -/
+lemma cancel_left_div_gcd (hm : 0 < m) (h : c * a ≡ c * b [ZMOD m]) : a ≡ b [ZMOD m / gcd m c] :=
+cancel_right_div_gcd hm $ by simpa [mul_comm] using h
+
+lemma of_div (h : a / c ≡ b / c [ZMOD m / c]) (ha : c ∣ a) (ha : c ∣ b) (ha : c ∣ m) :
+  a ≡ b [ZMOD m] :=
+by convert h.mul_left'; rwa int.mul_div_cancel'
+
 end modeq
 
 theorem modeq_one : a ≡ b [ZMOD 1] := modeq_of_dvd (one_dvd _)
@@ -153,6 +184,11 @@ theorem modeq_one : a ≡ b [ZMOD 1] := modeq_of_dvd (one_dvd _)
 lemma modeq_sub (a b : ℤ) : a ≡ b [ZMOD a - b] :=
 (modeq_of_dvd dvd_rfl).symm
 
+@[simp] lemma modeq_zero_iff : a ≡ b [ZMOD 0] ↔ a = b := by rw [modeq, mod_zero, mod_zero]
+
+@[simp] lemma add_modeq_left : n + a ≡ a [ZMOD n] := modeq.symm $ modeq_iff_dvd.2 $ by simp
+@[simp] lemma add_modeq_right : a + n ≡ a [ZMOD n] := modeq.symm $ modeq_iff_dvd.2 $ by simp
+
 lemma modeq_and_modeq_iff_modeq_mul {a b m n : ℤ} (hmn : m.nat_abs.coprime n.nat_abs) :
   a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ (a ≡ b [ZMOD m * n]) :=
 ⟨λ h, begin

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

chore(data/{int,nat}/modeq): Rationalise lemma names (#17902)

Quite a few modeq lemmas are still called nat.modeq.modeq_something or int.modeq.modeq_something. I'm deleting the duplicated modeq, so that lemmas (usually) become nat.modeq.something and int.modeq.something.

Also add nat.modeq.eq_of_lt_of_lt as a corollary to nat.modeq.eq_of_abs_lt.

Diff
@@ -66,15 +66,14 @@ begin
   exact exists_congr (λ t, sub_eq_iff_eq_add'),
 end
 
-theorem modeq.dvd : a ≡ b [ZMOD n] → n ∣ b - a := modeq_iff_dvd.1
-theorem modeq_of_dvd : n ∣ b - a → a ≡ b [ZMOD n] := modeq_iff_dvd.2
+alias modeq_iff_dvd ↔ modeq.dvd modeq_of_dvd
 
 theorem mod_modeq (a n) : a % n ≡ a [ZMOD n] := mod_mod _ _
 
 namespace modeq
 
-protected theorem modeq_of_dvd (d : m ∣ n) (h : a ≡ b [ZMOD n]) : a ≡ b [ZMOD m] :=
-modeq_iff_dvd.2 $ d.trans h.dvd
+protected lemma of_dvd (d : m ∣ n) (h : a ≡ b [ZMOD n]) : a ≡ b [ZMOD m] :=
+modeq_of_dvd $ d.trans h.dvd
 
 protected theorem mul_left' (hc : 0 ≤ c) (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD (c * n)] :=
 or.cases_on hc.lt_or_eq (λ hc,
@@ -124,9 +123,9 @@ h.sub modeq.rfl
 
 protected theorem mul_left (c : ℤ) (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD n] :=
 or.cases_on (le_total 0 c)
-(λ hc, (h.mul_left' hc).modeq_of_dvd (dvd_mul_left _ _) )
+(λ hc, (h.mul_left' hc).of_dvd (dvd_mul_left _ _) )
 (λ hc, by rw [← neg_neg c, neg_mul, neg_mul _ b];
-    exact ((h.mul_left' $ neg_nonneg.2 hc).modeq_of_dvd (dvd_mul_left _ _)).neg)
+    exact ((h.mul_left' $ neg_nonneg.2 hc).of_dvd (dvd_mul_left _ _)).neg)
 
 protected theorem mul_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n] :=
 by { rw [mul_comm a, mul_comm b], exact h.mul_left c }
@@ -141,11 +140,11 @@ begin
   exact h.mul hd,
 end
 
-theorem of_modeq_mul_left (m : ℤ) (h : a ≡ b [ZMOD m * n]) : a ≡ b [ZMOD n] :=
+theorem of_mul_left (m : ℤ) (h : a ≡ b [ZMOD m * n]) : a ≡ b [ZMOD n] :=
 by rw [modeq_iff_dvd] at *; exact (dvd_mul_left n m).trans h
 
-theorem of_modeq_mul_right (m : ℤ) : a ≡ b [ZMOD n * m] → a ≡ b [ZMOD n] :=
-mul_comm m n ▸ of_modeq_mul_left _
+theorem of_mul_right (m : ℤ) : a ≡ b [ZMOD n * m] → a ≡ b [ZMOD n] :=
+mul_comm m n ▸ of_mul_left _
 
 end modeq
 
@@ -163,7 +162,7 @@ lemma modeq_and_modeq_iff_modeq_mul {a b m n : ℤ} (hmn : m.nat_abs.coprime n.n
     refine hmn.mul_dvd_of_dvd_of_dvd _ _;
     rw [← coe_nat_dvd, nat_abs_dvd, dvd_nat_abs]; tauto
   end,
-λ h, ⟨h.of_modeq_mul_right _, h.of_modeq_mul_left _⟩⟩
+λ h, ⟨h.of_mul_right _, h.of_mul_left _⟩⟩
 
 lemma gcd_a_modeq (a b : ℕ) : (a : ℤ) * nat.gcd_a a b ≡ nat.gcd a b [ZMOD b] :=
 by { rw [← add_zero ((a : ℤ) * _), nat.gcd_eq_gcd_ab],
@@ -197,9 +196,9 @@ let ⟨z, hz1, hz2, hz3⟩ := exists_unique_equiv a hb in
 
 
 @[simp] lemma mod_mul_right_mod (a b c : ℤ) : a % (b * c) % b = a % b :=
-(mod_modeq _ _).of_modeq_mul_right _
+(mod_modeq _ _).of_mul_right _
 
 @[simp] lemma mod_mul_left_mod (a b c : ℤ) : a % (b * c) % c = a % c :=
-(mod_modeq _ _).of_modeq_mul_left _
+(mod_modeq _ _).of_mul_left _
 
 end int

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(first ported)

Changes in mathlib3port

mathlib3
mathlib3port
Diff
@@ -3,7 +3,7 @@ Copyright (c) 2018 Chris Hughes. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Chris Hughes
 -/
-import Data.Nat.Modeq
+import Data.Nat.ModEq
 import Tactic.Ring
 
 #align_import data.int.modeq from "leanprover-community/mathlib"@"47a1a73351de8dd6c8d3d32b569c8e434b03ca47"
@@ -86,10 +86,10 @@ theorem modEq_comm : a ≡ b [ZMOD n] ↔ b ≡ a [ZMOD n] :=
 #align int.modeq_comm Int.modEq_comm
 -/
 
-#print Int.coe_nat_modEq_iff /-
-theorem coe_nat_modEq_iff {a b n : ℕ} : a ≡ b [ZMOD n] ↔ a ≡ b [MOD n] := by
+#print Int.natCast_modEq_iff /-
+theorem natCast_modEq_iff {a b n : ℕ} : a ≡ b [ZMOD n] ↔ a ≡ b [MOD n] := by
   unfold modeq Nat.ModEq <;> rw [← Int.ofNat_inj] <;> simp [coe_nat_mod]
-#align int.coe_nat_modeq_iff Int.coe_nat_modEq_iff
+#align int.coe_nat_modeq_iff Int.natCast_modEq_iff
 -/
 
 #print Int.modEq_zero_iff_dvd /-
@@ -260,7 +260,7 @@ protected theorem mul (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a *
 protected theorem pow (m : ℕ) (h : a ≡ b [ZMOD n]) : a ^ m ≡ b ^ m [ZMOD n] :=
   by
   induction' m with d hd; · rfl
-  rw [pow_succ, pow_succ]
+  rw [pow_succ', pow_succ']
   exact h.mul hd
 #align int.modeq.pow Int.ModEq.pow
 -/
Diff
@@ -204,7 +204,7 @@ protected theorem add_left_cancel' (c : ℤ) (h : c + a ≡ c + b [ZMOD n]) : a
 
 #print Int.ModEq.add_right_cancel /-
 protected theorem add_right_cancel (h₁ : c ≡ d [ZMOD n]) (h₂ : a + c ≡ b + d [ZMOD n]) :
-    a ≡ b [ZMOD n] := by rw [add_comm a, add_comm b] at h₂ ; exact h₁.add_left_cancel h₂
+    a ≡ b [ZMOD n] := by rw [add_comm a, add_comm b] at h₂; exact h₁.add_left_cancel h₂
 #align int.modeq.add_right_cancel Int.ModEq.add_right_cancel
 -/
 
@@ -344,7 +344,7 @@ theorem add_modEq_right : a + n ≡ a [ZMOD n] :=
 theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.Coprime n.natAbs) :
     a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ a ≡ b [ZMOD m * n] :=
   ⟨fun h => by
-    rw [modeq_iff_dvd, modeq_iff_dvd] at h 
+    rw [modeq_iff_dvd, modeq_iff_dvd] at h
     rw [modeq_iff_dvd, ← nat_abs_dvd, ← dvd_nat_abs, coe_nat_dvd, nat_abs_mul]
     refine' hmn.mul_dvd_of_dvd_of_dvd _ _ <;> rw [← coe_nat_dvd, nat_abs_dvd, dvd_nat_abs] <;>
       tauto,
@@ -392,7 +392,7 @@ theorem exists_unique_equiv (a : ℤ) {b : ℤ} (hb : 0 < b) :
   ⟨a % b, emod_nonneg _ (ne_of_gt hb),
     by
     have : a % b < |b| := emod_lt _ (ne_of_gt hb)
-    rwa [abs_of_pos hb] at this , by simp [modeq]⟩
+    rwa [abs_of_pos hb] at this, by simp [modeq]⟩
 #align int.exists_unique_equiv Int.exists_unique_equiv
 -/
 
Diff
@@ -3,8 +3,8 @@ Copyright (c) 2018 Chris Hughes. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Chris Hughes
 -/
-import Mathbin.Data.Nat.Modeq
-import Mathbin.Tactic.Ring
+import Data.Nat.Modeq
+import Tactic.Ring
 
 #align_import data.int.modeq from "leanprover-community/mathlib"@"47a1a73351de8dd6c8d3d32b569c8e434b03ca47"
 
Diff
@@ -341,7 +341,7 @@ theorem add_modEq_right : a + n ≡ a [ZMOD n] :=
 -/
 
 #print Int.modEq_and_modEq_iff_modEq_mul /-
-theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.coprime n.natAbs) :
+theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.Coprime n.natAbs) :
     a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ a ≡ b [ZMOD m * n] :=
   ⟨fun h => by
     rw [modeq_iff_dvd, modeq_iff_dvd] at h 
@@ -376,9 +376,9 @@ theorem modEq_add_fac_self {a t n : ℤ} : a + n * t ≡ a [ZMOD n] :=
 -/
 
 #print Int.mod_coprime /-
-theorem mod_coprime {a b : ℕ} (hab : Nat.coprime a b) : ∃ y : ℤ, a * y ≡ 1 [ZMOD b] :=
+theorem mod_coprime {a b : ℕ} (hab : Nat.Coprime a b) : ∃ y : ℤ, a * y ≡ 1 [ZMOD b] :=
   ⟨Nat.gcdA a b,
-    have hgcd : Nat.gcd a b = 1 := Nat.coprime.gcd_eq_one hab
+    have hgcd : Nat.gcd a b = 1 := Nat.Coprime.gcd_eq_one hab
     calc
       ↑a * Nat.gcdA a b ≡ ↑a * Nat.gcdA a b + ↑b * Nat.gcdB a b [ZMOD ↑b] :=
         ModEq.symm <| modEq_add_fac _ <| ModEq.refl _
Diff
@@ -123,7 +123,7 @@ theorem modEq_iff_add_fac {a b n : ℤ} : a ≡ b [ZMOD n] ↔ ∃ t, b = a + n
 #align int.modeq_iff_add_fac Int.modEq_iff_add_fac
 -/
 
-alias modeq_iff_dvd ↔ modeq.dvd modeq_of_dvd
+alias ⟨modeq.dvd, modeq_of_dvd⟩ := modeq_iff_dvd
 #align int.modeq.dvd Int.ModEq.dvd
 #align int.modeq_of_dvd Int.modEq_of_dvd
 
Diff
@@ -252,7 +252,7 @@ protected theorem mul_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [
 
 #print Int.ModEq.mul /-
 protected theorem mul (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a * c ≡ b * d [ZMOD n] :=
-  (h₂.mul_left _).trans (h₁.mul_right _)
+  (h₂.hMul_left _).trans (h₁.hMul_right _)
 #align int.modeq.mul Int.ModEq.mul
 -/
 
Diff
@@ -2,15 +2,12 @@
 Copyright (c) 2018 Chris Hughes. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Chris Hughes
-
-! This file was ported from Lean 3 source module data.int.modeq
-! leanprover-community/mathlib commit 47a1a73351de8dd6c8d3d32b569c8e434b03ca47
-! Please do not edit these lines, except to modify the commit id
-! if you have ported upstream changes.
 -/
 import Mathbin.Data.Nat.Modeq
 import Mathbin.Tactic.Ring
 
+#align_import data.int.modeq from "leanprover-community/mathlib"@"47a1a73351de8dd6c8d3d32b569c8e434b03ca47"
+
 /-!
 
 # Congruences modulo an integer
Diff
@@ -39,7 +39,6 @@ deriving Decidable
 #align int.modeq Int.ModEq
 -/
 
--- mathport name: «expr ≡ [ZMOD ]»
 notation:50 a " ≡ " b " [ZMOD " n "]" => ModEq n a b
 
 variable {m n a b c d : ℤ}
@@ -96,20 +95,28 @@ theorem coe_nat_modEq_iff {a b n : ℕ} : a ≡ b [ZMOD n] ↔ a ≡ b [MOD n] :
 #align int.coe_nat_modeq_iff Int.coe_nat_modEq_iff
 -/
 
+#print Int.modEq_zero_iff_dvd /-
 theorem modEq_zero_iff_dvd : a ≡ 0 [ZMOD n] ↔ n ∣ a := by rw [modeq, zero_mod, dvd_iff_mod_eq_zero]
 #align int.modeq_zero_iff_dvd Int.modEq_zero_iff_dvd
+-/
 
+#print Dvd.dvd.modEq_zero_int /-
 theorem Dvd.dvd.modEq_zero_int (h : n ∣ a) : a ≡ 0 [ZMOD n] :=
   modEq_zero_iff_dvd.2 h
 #align has_dvd.dvd.modeq_zero_int Dvd.dvd.modEq_zero_int
+-/
 
+#print Dvd.dvd.zero_modEq_int /-
 theorem Dvd.dvd.zero_modEq_int (h : n ∣ a) : 0 ≡ a [ZMOD n] :=
   h.modEq_zero_int.symm
 #align has_dvd.dvd.zero_modeq_int Dvd.dvd.zero_modEq_int
+-/
 
+#print Int.modEq_iff_dvd /-
 theorem modEq_iff_dvd : a ≡ b [ZMOD n] ↔ n ∣ b - a := by
   rw [modeq, eq_comm] <;> simp [mod_eq_mod_iff_mod_sub_eq_zero, dvd_iff_mod_eq_zero]
 #align int.modeq_iff_dvd Int.modEq_iff_dvd
+-/
 
 #print Int.modEq_iff_add_fac /-
 theorem modEq_iff_add_fac {a b n : ℤ} : a ≡ b [ZMOD n] ↔ ∃ t, b = a + n * t :=
@@ -143,9 +150,11 @@ theorem modEq_neg : a ≡ b [ZMOD -n] ↔ a ≡ b [ZMOD n] := by simp [modeq_iff
 
 namespace Modeq
 
+#print Int.ModEq.of_dvd /-
 protected theorem of_dvd (d : m ∣ n) (h : a ≡ b [ZMOD n]) : a ≡ b [ZMOD m] :=
   modEq_of_dvd <| d.trans h.Dvd
 #align int.modeq.of_dvd Int.ModEq.of_dvd
+-/
 
 #print Int.ModEq.mul_left' /-
 protected theorem mul_left' (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD c * n] :=
@@ -250,12 +259,14 @@ protected theorem mul (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a *
 #align int.modeq.mul Int.ModEq.mul
 -/
 
+#print Int.ModEq.pow /-
 protected theorem pow (m : ℕ) (h : a ≡ b [ZMOD n]) : a ^ m ≡ b ^ m [ZMOD n] :=
   by
   induction' m with d hd; · rfl
   rw [pow_succ, pow_succ]
   exact h.mul hd
 #align int.modeq.pow Int.ModEq.pow
+-/
 
 #print Int.ModEq.of_mul_left /-
 theorem of_mul_left (m : ℤ) (h : a ≡ b [ZMOD m * n]) : a ≡ b [ZMOD n] := by
@@ -292,9 +303,11 @@ theorem cancel_left_div_gcd (hm : 0 < m) (h : c * a ≡ c * b [ZMOD m]) : a ≡
 #align int.modeq.cancel_left_div_gcd Int.ModEq.cancel_left_div_gcd
 -/
 
+#print Int.ModEq.of_div /-
 theorem of_div (h : a / c ≡ b / c [ZMOD m / c]) (ha : c ∣ a) (ha : c ∣ b) (ha : c ∣ m) :
     a ≡ b [ZMOD m] := by convert h.mul_left' <;> rwa [Int.mul_ediv_cancel']
 #align int.modeq.of_div Int.ModEq.of_div
+-/
 
 end Modeq
 
Diff
@@ -356,7 +356,6 @@ theorem modEq_add_fac {a b n : ℤ} (c : ℤ) (ha : a ≡ b [ZMOD n]) : a + n *
     a + n * c ≡ b + n * c [ZMOD n] := ha.add_right _
     _ ≡ b + 0 [ZMOD n] := ((dvd_mul_right _ _).modEq_zero_int.add_left _)
     _ ≡ b [ZMOD n] := by rw [add_zero]
-    
 #align int.modeq_add_fac Int.modEq_add_fac
 -/
 
@@ -373,8 +372,7 @@ theorem mod_coprime {a b : ℕ} (hab : Nat.coprime a b) : ∃ y : ℤ, a * y ≡
     calc
       ↑a * Nat.gcdA a b ≡ ↑a * Nat.gcdA a b + ↑b * Nat.gcdB a b [ZMOD ↑b] :=
         ModEq.symm <| modEq_add_fac _ <| ModEq.refl _
-      _ ≡ 1 [ZMOD ↑b] := by rw [← Nat.gcd_eq_gcd_ab, hgcd] <;> rfl
-      ⟩
+      _ ≡ 1 [ZMOD ↑b] := by rw [← Nat.gcd_eq_gcd_ab, hgcd] <;> rfl⟩
 #align int.mod_coprime Int.mod_coprime
 -/
 
Diff
@@ -34,7 +34,8 @@ namespace Int
 #print Int.ModEq /-
 /-- `a ≡ b [ZMOD n]` when `a % n = b % n`. -/
 def ModEq (n a b : ℤ) :=
-  a % n = b % n deriving Decidable
+  a % n = b % n
+deriving Decidable
 #align int.modeq Int.ModEq
 -/
 
@@ -197,7 +198,7 @@ protected theorem add_left_cancel' (c : ℤ) (h : c + a ≡ c + b [ZMOD n]) : a
 
 #print Int.ModEq.add_right_cancel /-
 protected theorem add_right_cancel (h₁ : c ≡ d [ZMOD n]) (h₂ : a + c ≡ b + d [ZMOD n]) :
-    a ≡ b [ZMOD n] := by rw [add_comm a, add_comm b] at h₂; exact h₁.add_left_cancel h₂
+    a ≡ b [ZMOD n] := by rw [add_comm a, add_comm b] at h₂ ; exact h₁.add_left_cancel h₂
 #align int.modeq.add_right_cancel Int.ModEq.add_right_cancel
 -/
 
@@ -275,7 +276,7 @@ theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) : a ≡
   let d := gcd m c
   have hmd := gcd_dvd_left m c
   have hcd := gcd_dvd_right m c
-  rw [modeq_iff_dvd] at h⊢
+  rw [modeq_iff_dvd] at h ⊢
   refine' Int.dvd_of_dvd_mul_right_of_gcd_one _ _
   show m / d ∣ c / d * (b - a)
   · rw [mul_comm, ← Int.mul_ediv_assoc (b - a) hcd, sub_mul]
@@ -333,7 +334,7 @@ theorem add_modEq_right : a + n ≡ a [ZMOD n] :=
 theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.coprime n.natAbs) :
     a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ a ≡ b [ZMOD m * n] :=
   ⟨fun h => by
-    rw [modeq_iff_dvd, modeq_iff_dvd] at h
+    rw [modeq_iff_dvd, modeq_iff_dvd] at h 
     rw [modeq_iff_dvd, ← nat_abs_dvd, ← dvd_nat_abs, coe_nat_dvd, nat_abs_mul]
     refine' hmn.mul_dvd_of_dvd_of_dvd _ _ <;> rw [← coe_nat_dvd, nat_abs_dvd, dvd_nat_abs] <;>
       tauto,
@@ -383,7 +384,7 @@ theorem exists_unique_equiv (a : ℤ) {b : ℤ} (hb : 0 < b) :
   ⟨a % b, emod_nonneg _ (ne_of_gt hb),
     by
     have : a % b < |b| := emod_lt _ (ne_of_gt hb)
-    rwa [abs_of_pos hb] at this, by simp [modeq]⟩
+    rwa [abs_of_pos hb] at this , by simp [modeq]⟩
 #align int.exists_unique_equiv Int.exists_unique_equiv
 -/
 
Diff
@@ -95,41 +95,17 @@ theorem coe_nat_modEq_iff {a b n : ℕ} : a ≡ b [ZMOD n] ↔ a ≡ b [MOD n] :
 #align int.coe_nat_modeq_iff Int.coe_nat_modEq_iff
 -/
 
-/- warning: int.modeq_zero_iff_dvd -> Int.modEq_zero_iff_dvd is a dubious translation:
-lean 3 declaration is
-  forall {n : Int} {a : Int}, Iff (Int.ModEq n a (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) (Dvd.Dvd.{0} Int (semigroupDvd.{0} Int Int.semigroup) n a)
-but is expected to have type
-  forall {n : Int} {a : Int}, Iff (Int.ModEq n a (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) (Dvd.dvd.{0} Int Int.instDvdInt n a)
-Case conversion may be inaccurate. Consider using '#align int.modeq_zero_iff_dvd Int.modEq_zero_iff_dvdₓ'. -/
 theorem modEq_zero_iff_dvd : a ≡ 0 [ZMOD n] ↔ n ∣ a := by rw [modeq, zero_mod, dvd_iff_mod_eq_zero]
 #align int.modeq_zero_iff_dvd Int.modEq_zero_iff_dvd
 
-/- warning: has_dvd.dvd.modeq_zero_int -> Dvd.dvd.modEq_zero_int is a dubious translation:
-lean 3 declaration is
-  forall {n : Int} {a : Int}, (Dvd.Dvd.{0} Int (semigroupDvd.{0} Int Int.semigroup) n a) -> (Int.ModEq n a (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero))))
-but is expected to have type
-  forall {n : Int} {a : Int}, (Dvd.dvd.{0} Int Int.instDvdInt n a) -> (Int.ModEq n a (OfNat.ofNat.{0} Int 0 (instOfNatInt 0)))
-Case conversion may be inaccurate. Consider using '#align has_dvd.dvd.modeq_zero_int Dvd.dvd.modEq_zero_intₓ'. -/
 theorem Dvd.dvd.modEq_zero_int (h : n ∣ a) : a ≡ 0 [ZMOD n] :=
   modEq_zero_iff_dvd.2 h
 #align has_dvd.dvd.modeq_zero_int Dvd.dvd.modEq_zero_int
 
-/- warning: has_dvd.dvd.zero_modeq_int -> Dvd.dvd.zero_modEq_int is a dubious translation:
-lean 3 declaration is
-  forall {n : Int} {a : Int}, (Dvd.Dvd.{0} Int (semigroupDvd.{0} Int Int.semigroup) n a) -> (Int.ModEq n (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero))) a)
-but is expected to have type
-  forall {n : Int} {a : Int}, (Dvd.dvd.{0} Int Int.instDvdInt n a) -> (Int.ModEq n (OfNat.ofNat.{0} Int 0 (instOfNatInt 0)) a)
-Case conversion may be inaccurate. Consider using '#align has_dvd.dvd.zero_modeq_int Dvd.dvd.zero_modEq_intₓ'. -/
 theorem Dvd.dvd.zero_modEq_int (h : n ∣ a) : 0 ≡ a [ZMOD n] :=
   h.modEq_zero_int.symm
 #align has_dvd.dvd.zero_modeq_int Dvd.dvd.zero_modEq_int
 
-/- warning: int.modeq_iff_dvd -> Int.modEq_iff_dvd is a dubious translation:
-lean 3 declaration is
-  forall {n : Int} {a : Int} {b : Int}, Iff (Int.ModEq n a b) (Dvd.Dvd.{0} Int (semigroupDvd.{0} Int Int.semigroup) n (HSub.hSub.{0, 0, 0} Int Int Int (instHSub.{0} Int Int.hasSub) b a))
-but is expected to have type
-  forall {n : Int} {a : Int} {b : Int}, Iff (Int.ModEq n a b) (Dvd.dvd.{0} Int Int.instDvdInt n (HSub.hSub.{0, 0, 0} Int Int Int (instHSub.{0} Int Int.instSubInt) b a))
-Case conversion may be inaccurate. Consider using '#align int.modeq_iff_dvd Int.modEq_iff_dvdₓ'. -/
 theorem modEq_iff_dvd : a ≡ b [ZMOD n] ↔ n ∣ b - a := by
   rw [modeq, eq_comm] <;> simp [mod_eq_mod_iff_mod_sub_eq_zero, dvd_iff_mod_eq_zero]
 #align int.modeq_iff_dvd Int.modEq_iff_dvd
@@ -142,18 +118,6 @@ theorem modEq_iff_add_fac {a b n : ℤ} : a ≡ b [ZMOD n] ↔ ∃ t, b = a + n
 #align int.modeq_iff_add_fac Int.modEq_iff_add_fac
 -/
 
-/- warning: int.modeq.dvd -> Int.ModEq.dvd is a dubious translation:
-lean 3 declaration is
-  forall {n : Int} {a : Int} {b : Int}, (Int.ModEq n a b) -> (Dvd.Dvd.{0} Int (semigroupDvd.{0} Int Int.semigroup) n (HSub.hSub.{0, 0, 0} Int Int Int (instHSub.{0} Int Int.hasSub) b a))
-but is expected to have type
-  forall {n : Int} {a : Int} {b : Int}, (Int.ModEq n a b) -> (Dvd.dvd.{0} Int Int.instDvdInt n (HSub.hSub.{0, 0, 0} Int Int Int (instHSub.{0} Int Int.instSubInt) b a))
-Case conversion may be inaccurate. Consider using '#align int.modeq.dvd Int.ModEq.dvdₓ'. -/
-/- warning: int.modeq_of_dvd -> Int.modEq_of_dvd is a dubious translation:
-lean 3 declaration is
-  forall {n : Int} {a : Int} {b : Int}, (Dvd.Dvd.{0} Int (semigroupDvd.{0} Int Int.semigroup) n (HSub.hSub.{0, 0, 0} Int Int Int (instHSub.{0} Int Int.hasSub) b a)) -> (Int.ModEq n a b)
-but is expected to have type
-  forall {n : Int} {a : Int} {b : Int}, (Dvd.dvd.{0} Int Int.instDvdInt n (HSub.hSub.{0, 0, 0} Int Int Int (instHSub.{0} Int Int.instSubInt) b a)) -> (Int.ModEq n a b)
-Case conversion may be inaccurate. Consider using '#align int.modeq_of_dvd Int.modEq_of_dvdₓ'. -/
 alias modeq_iff_dvd ↔ modeq.dvd modeq_of_dvd
 #align int.modeq.dvd Int.ModEq.dvd
 #align int.modeq_of_dvd Int.modEq_of_dvd
@@ -178,12 +142,6 @@ theorem modEq_neg : a ≡ b [ZMOD -n] ↔ a ≡ b [ZMOD n] := by simp [modeq_iff
 
 namespace Modeq
 
-/- warning: int.modeq.of_dvd -> Int.ModEq.of_dvd is a dubious translation:
-lean 3 declaration is
-  forall {m : Int} {n : Int} {a : Int} {b : Int}, (Dvd.Dvd.{0} Int (semigroupDvd.{0} Int Int.semigroup) m n) -> (Int.ModEq n a b) -> (Int.ModEq m a b)
-but is expected to have type
-  forall {m : Int} {n : Int} {a : Int} {b : Int}, (Dvd.dvd.{0} Int Int.instDvdInt m n) -> (Int.ModEq n a b) -> (Int.ModEq m a b)
-Case conversion may be inaccurate. Consider using '#align int.modeq.of_dvd Int.ModEq.of_dvdₓ'. -/
 protected theorem of_dvd (d : m ∣ n) (h : a ≡ b [ZMOD n]) : a ≡ b [ZMOD m] :=
   modEq_of_dvd <| d.trans h.Dvd
 #align int.modeq.of_dvd Int.ModEq.of_dvd
@@ -291,12 +249,6 @@ protected theorem mul (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a *
 #align int.modeq.mul Int.ModEq.mul
 -/
 
-/- warning: int.modeq.pow -> Int.ModEq.pow is a dubious translation:
-lean 3 declaration is
-  forall {n : Int} {a : Int} {b : Int} (m : Nat), (Int.ModEq n a b) -> (Int.ModEq n (HPow.hPow.{0, 0, 0} Int Nat Int (instHPow.{0, 0} Int Nat (Monoid.Pow.{0} Int Int.monoid)) a m) (HPow.hPow.{0, 0, 0} Int Nat Int (instHPow.{0, 0} Int Nat (Monoid.Pow.{0} Int Int.monoid)) b m))
-but is expected to have type
-  forall {n : Int} {a : Int} {b : Int} (m : Nat), (Int.ModEq n a b) -> (Int.ModEq n (HPow.hPow.{0, 0, 0} Int Nat Int Int.instHPowIntNat a m) (HPow.hPow.{0, 0, 0} Int Nat Int Int.instHPowIntNat b m))
-Case conversion may be inaccurate. Consider using '#align int.modeq.pow Int.ModEq.powₓ'. -/
 protected theorem pow (m : ℕ) (h : a ≡ b [ZMOD n]) : a ^ m ≡ b ^ m [ZMOD n] :=
   by
   induction' m with d hd; · rfl
@@ -339,12 +291,6 @@ theorem cancel_left_div_gcd (hm : 0 < m) (h : c * a ≡ c * b [ZMOD m]) : a ≡
 #align int.modeq.cancel_left_div_gcd Int.ModEq.cancel_left_div_gcd
 -/
 
-/- warning: int.modeq.of_div -> Int.ModEq.of_div is a dubious translation:
-lean 3 declaration is
-  forall {m : Int} {a : Int} {b : Int} {c : Int}, (Int.ModEq (HDiv.hDiv.{0, 0, 0} Int Int Int (instHDiv.{0} Int Int.hasDiv) m c) (HDiv.hDiv.{0, 0, 0} Int Int Int (instHDiv.{0} Int Int.hasDiv) a c) (HDiv.hDiv.{0, 0, 0} Int Int Int (instHDiv.{0} Int Int.hasDiv) b c)) -> (Dvd.Dvd.{0} Int (semigroupDvd.{0} Int Int.semigroup) c a) -> (Dvd.Dvd.{0} Int (semigroupDvd.{0} Int Int.semigroup) c b) -> (Dvd.Dvd.{0} Int (semigroupDvd.{0} Int Int.semigroup) c m) -> (Int.ModEq m a b)
-but is expected to have type
-  forall {m : Int} {a : Int} {b : Int} {c : Int}, (Int.ModEq (HDiv.hDiv.{0, 0, 0} Int Int Int (instHDiv.{0} Int Int.instDivInt_1) m c) (HDiv.hDiv.{0, 0, 0} Int Int Int (instHDiv.{0} Int Int.instDivInt_1) a c) (HDiv.hDiv.{0, 0, 0} Int Int Int (instHDiv.{0} Int Int.instDivInt_1) b c)) -> (Dvd.dvd.{0} Int Int.instDvdInt c a) -> (Dvd.dvd.{0} Int Int.instDvdInt c b) -> (Dvd.dvd.{0} Int Int.instDvdInt c m) -> (Int.ModEq m a b)
-Case conversion may be inaccurate. Consider using '#align int.modeq.of_div Int.ModEq.of_divₓ'. -/
 theorem of_div (h : a / c ≡ b / c [ZMOD m / c]) (ha : c ∣ a) (ha : c ∣ b) (ha : c ∣ m) :
     a ≡ b [ZMOD m] := by convert h.mul_left' <;> rwa [Int.mul_ediv_cancel']
 #align int.modeq.of_div Int.ModEq.of_div
Diff
@@ -207,9 +207,7 @@ protected theorem mul_right' (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n *
 
 #print Int.ModEq.add /-
 protected theorem add (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a + c ≡ b + d [ZMOD n] :=
-  modEq_iff_dvd.2 <| by
-    convert dvd_add h₁.dvd h₂.dvd
-    ring
+  modEq_iff_dvd.2 <| by convert dvd_add h₁.dvd h₂.dvd; ring
 #align int.modeq.add Int.ModEq.add
 -/
 
@@ -229,9 +227,7 @@ protected theorem add_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a + c ≡ b + c [
 protected theorem add_left_cancel (h₁ : a ≡ b [ZMOD n]) (h₂ : a + c ≡ b + d [ZMOD n]) :
     c ≡ d [ZMOD n] :=
   have : d - c = b + d - (a + c) - (b - a) := by ring
-  modEq_iff_dvd.2 <| by
-    rw [this]
-    exact dvd_sub h₂.dvd h₁.dvd
+  modEq_iff_dvd.2 <| by rw [this]; exact dvd_sub h₂.dvd h₁.dvd
 #align int.modeq.add_left_cancel Int.ModEq.add_left_cancel
 -/
 
@@ -243,9 +239,7 @@ protected theorem add_left_cancel' (c : ℤ) (h : c + a ≡ c + b [ZMOD n]) : a
 
 #print Int.ModEq.add_right_cancel /-
 protected theorem add_right_cancel (h₁ : c ≡ d [ZMOD n]) (h₂ : a + c ≡ b + d [ZMOD n]) :
-    a ≡ b [ZMOD n] := by
-  rw [add_comm a, add_comm b] at h₂
-  exact h₁.add_left_cancel h₂
+    a ≡ b [ZMOD n] := by rw [add_comm a, add_comm b] at h₂; exact h₁.add_left_cancel h₂
 #align int.modeq.add_right_cancel Int.ModEq.add_right_cancel
 -/
 
@@ -262,10 +256,8 @@ protected theorem neg (h : a ≡ b [ZMOD n]) : -a ≡ -b [ZMOD n] :=
 -/
 
 #print Int.ModEq.sub /-
-protected theorem sub (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a - c ≡ b - d [ZMOD n] :=
-  by
-  rw [sub_eq_add_neg, sub_eq_add_neg]
-  exact h₁.add h₂.neg
+protected theorem sub (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a - c ≡ b - d [ZMOD n] := by
+  rw [sub_eq_add_neg, sub_eq_add_neg]; exact h₁.add h₂.neg
 #align int.modeq.sub Int.ModEq.sub
 -/
 
Diff
@@ -75,15 +75,19 @@ protected theorem trans : a ≡ b [ZMOD n] → b ≡ c [ZMOD n] → a ≡ c [ZMO
 #align int.modeq.trans Int.ModEq.trans
 -/
 
+#print Int.ModEq.eq /-
 protected theorem eq : a ≡ b [ZMOD n] → a % n = b % n :=
   id
 #align int.modeq.eq Int.ModEq.eq
+-/
 
 end Modeq
 
+#print Int.modEq_comm /-
 theorem modEq_comm : a ≡ b [ZMOD n] ↔ b ≡ a [ZMOD n] :=
   ⟨ModEq.symm, ModEq.symm⟩
 #align int.modeq_comm Int.modEq_comm
+-/
 
 #print Int.coe_nat_modEq_iff /-
 theorem coe_nat_modEq_iff {a b n : ℕ} : a ≡ b [ZMOD n] ↔ a ≡ b [MOD n] := by
@@ -160,13 +164,17 @@ theorem mod_modEq (a n) : a % n ≡ a [ZMOD n] :=
 #align int.mod_modeq Int.mod_modEq
 -/
 
+#print Int.neg_modEq_neg /-
 @[simp]
 theorem neg_modEq_neg : -a ≡ -b [ZMOD n] ↔ a ≡ b [ZMOD n] := by simp [modeq_iff_dvd, dvd_sub_comm]
 #align int.neg_modeq_neg Int.neg_modEq_neg
+-/
 
+#print Int.modEq_neg /-
 @[simp]
 theorem modEq_neg : a ≡ b [ZMOD -n] ↔ a ≡ b [ZMOD n] := by simp [modeq_iff_dvd]
 #align int.modeq_neg Int.modEq_neg
+-/
 
 namespace Modeq
 
@@ -180,12 +188,7 @@ protected theorem of_dvd (d : m ∣ n) (h : a ≡ b [ZMOD n]) : a ≡ b [ZMOD m]
   modEq_of_dvd <| d.trans h.Dvd
 #align int.modeq.of_dvd Int.ModEq.of_dvd
 
-/- warning: int.modeq.mul_left' -> Int.ModEq.mul_left' is a dubious translation:
-lean 3 declaration is
-  forall {n : Int} {a : Int} {b : Int} {c : Int}, (Int.ModEq n a b) -> (Int.ModEq (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) c n) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) c a) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) c b))
-but is expected to have type
-  forall {n : Int} {a : Int} {b : Int} {c : Int}, (LE.le.{0} Int Int.instLEInt (OfNat.ofNat.{0} Int 0 (instOfNatInt 0)) c) -> (Int.ModEq n a b) -> (Int.ModEq (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) c n) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) c a) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) c b))
-Case conversion may be inaccurate. Consider using '#align int.modeq.mul_left' Int.ModEq.mul_left'ₓ'. -/
+#print Int.ModEq.mul_left' /-
 protected theorem mul_left' (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD c * n] :=
   by
   obtain hc | rfl | hc := lt_trichotomy c 0
@@ -194,16 +197,13 @@ protected theorem mul_left' (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD c * n
   · simp
   · simp only [modeq, mul_mod_mul_of_pos hc, h.eq]
 #align int.modeq.mul_left' Int.ModEq.mul_left'
+-/
 
-/- warning: int.modeq.mul_right' -> Int.ModEq.mul_right' is a dubious translation:
-lean 3 declaration is
-  forall {n : Int} {a : Int} {b : Int} {c : Int}, (Int.ModEq n a b) -> (Int.ModEq (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) n c) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) a c) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) b c))
-but is expected to have type
-  forall {n : Int} {a : Int} {b : Int} {c : Int}, (LE.le.{0} Int Int.instLEInt (OfNat.ofNat.{0} Int 0 (instOfNatInt 0)) c) -> (Int.ModEq n a b) -> (Int.ModEq (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) n c) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) a c) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) b c))
-Case conversion may be inaccurate. Consider using '#align int.modeq.mul_right' Int.ModEq.mul_right'ₓ'. -/
+#print Int.ModEq.mul_right' /-
 protected theorem mul_right' (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n * c] := by
   rw [mul_comm a, mul_comm b, mul_comm n] <;> exact h.mul_left'
 #align int.modeq.mul_right' Int.ModEq.mul_right'
+-/
 
 #print Int.ModEq.add /-
 protected theorem add (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a + c ≡ b + d [ZMOD n] :=
@@ -324,6 +324,7 @@ theorem of_mul_right (m : ℤ) : a ≡ b [ZMOD n * m] → a ≡ b [ZMOD n] :=
 #align int.modeq.of_mul_right Int.ModEq.of_mul_right
 -/
 
+#print Int.ModEq.cancel_right_div_gcd /-
 /-- To cancel a common factor `c` from a `modeq` we must divide the modulus `m` by `gcd m c`. -/
 theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) : a ≡ b [ZMOD m / gcd m c] :=
   by
@@ -337,12 +338,21 @@ theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) : a ≡
     exact Int.ediv_dvd_ediv hmd h
   · rw [gcd_div hmd hcd, nat_abs_of_nat, Nat.div_self (gcd_pos_of_ne_zero_left c hm.ne')]
 #align int.modeq.cancel_right_div_gcd Int.ModEq.cancel_right_div_gcd
+-/
 
+#print Int.ModEq.cancel_left_div_gcd /-
 /-- To cancel a common factor `c` from a `modeq` we must divide the modulus `m` by `gcd m c`. -/
 theorem cancel_left_div_gcd (hm : 0 < m) (h : c * a ≡ c * b [ZMOD m]) : a ≡ b [ZMOD m / gcd m c] :=
   cancel_right_div_gcd hm <| by simpa [mul_comm] using h
 #align int.modeq.cancel_left_div_gcd Int.ModEq.cancel_left_div_gcd
+-/
 
+/- warning: int.modeq.of_div -> Int.ModEq.of_div is a dubious translation:
+lean 3 declaration is
+  forall {m : Int} {a : Int} {b : Int} {c : Int}, (Int.ModEq (HDiv.hDiv.{0, 0, 0} Int Int Int (instHDiv.{0} Int Int.hasDiv) m c) (HDiv.hDiv.{0, 0, 0} Int Int Int (instHDiv.{0} Int Int.hasDiv) a c) (HDiv.hDiv.{0, 0, 0} Int Int Int (instHDiv.{0} Int Int.hasDiv) b c)) -> (Dvd.Dvd.{0} Int (semigroupDvd.{0} Int Int.semigroup) c a) -> (Dvd.Dvd.{0} Int (semigroupDvd.{0} Int Int.semigroup) c b) -> (Dvd.Dvd.{0} Int (semigroupDvd.{0} Int Int.semigroup) c m) -> (Int.ModEq m a b)
+but is expected to have type
+  forall {m : Int} {a : Int} {b : Int} {c : Int}, (Int.ModEq (HDiv.hDiv.{0, 0, 0} Int Int Int (instHDiv.{0} Int Int.instDivInt_1) m c) (HDiv.hDiv.{0, 0, 0} Int Int Int (instHDiv.{0} Int Int.instDivInt_1) a c) (HDiv.hDiv.{0, 0, 0} Int Int Int (instHDiv.{0} Int Int.instDivInt_1) b c)) -> (Dvd.dvd.{0} Int Int.instDvdInt c a) -> (Dvd.dvd.{0} Int Int.instDvdInt c b) -> (Dvd.dvd.{0} Int Int.instDvdInt c m) -> (Int.ModEq m a b)
+Case conversion may be inaccurate. Consider using '#align int.modeq.of_div Int.ModEq.of_divₓ'. -/
 theorem of_div (h : a / c ≡ b / c [ZMOD m / c]) (ha : c ∣ a) (ha : c ∣ b) (ha : c ∣ m) :
     a ≡ b [ZMOD m] := by convert h.mul_left' <;> rwa [Int.mul_ediv_cancel']
 #align int.modeq.of_div Int.ModEq.of_div
@@ -361,19 +371,25 @@ theorem modEq_sub (a b : ℤ) : a ≡ b [ZMOD a - b] :=
 #align int.modeq_sub Int.modEq_sub
 -/
 
+#print Int.modEq_zero_iff /-
 @[simp]
 theorem modEq_zero_iff : a ≡ b [ZMOD 0] ↔ a = b := by rw [modeq, mod_zero, mod_zero]
 #align int.modeq_zero_iff Int.modEq_zero_iff
+-/
 
+#print Int.add_modEq_left /-
 @[simp]
 theorem add_modEq_left : n + a ≡ a [ZMOD n] :=
   ModEq.symm <| modEq_iff_dvd.2 <| by simp
 #align int.add_modeq_left Int.add_modEq_left
+-/
 
+#print Int.add_modEq_right /-
 @[simp]
 theorem add_modEq_right : a + n ≡ a [ZMOD n] :=
   ModEq.symm <| modEq_iff_dvd.2 <| by simp
 #align int.add_modeq_right Int.add_modEq_right
+-/
 
 #print Int.modEq_and_modEq_iff_modEq_mul /-
 theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.coprime n.natAbs) :
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Chris Hughes
 
 ! This file was ported from Lean 3 source module data.int.modeq
-! leanprover-community/mathlib commit c0dbeca1a7a7f4959cdf6b2817629bafbf1547a0
+! leanprover-community/mathlib commit 47a1a73351de8dd6c8d3d32b569c8e434b03ca47
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -75,8 +75,16 @@ protected theorem trans : a ≡ b [ZMOD n] → b ≡ c [ZMOD n] → a ≡ c [ZMO
 #align int.modeq.trans Int.ModEq.trans
 -/
 
+protected theorem eq : a ≡ b [ZMOD n] → a % n = b % n :=
+  id
+#align int.modeq.eq Int.ModEq.eq
+
 end Modeq
 
+theorem modEq_comm : a ≡ b [ZMOD n] ↔ b ≡ a [ZMOD n] :=
+  ⟨ModEq.symm, ModEq.symm⟩
+#align int.modeq_comm Int.modEq_comm
+
 #print Int.coe_nat_modEq_iff /-
 theorem coe_nat_modEq_iff {a b n : ℕ} : a ≡ b [ZMOD n] ↔ a ≡ b [MOD n] := by
   unfold modeq Nat.ModEq <;> rw [← Int.ofNat_inj] <;> simp [coe_nat_mod]
@@ -152,6 +160,14 @@ theorem mod_modEq (a n) : a % n ≡ a [ZMOD n] :=
 #align int.mod_modeq Int.mod_modEq
 -/
 
+@[simp]
+theorem neg_modEq_neg : -a ≡ -b [ZMOD n] ↔ a ≡ b [ZMOD n] := by simp [modeq_iff_dvd, dvd_sub_comm]
+#align int.neg_modeq_neg Int.neg_modEq_neg
+
+@[simp]
+theorem modEq_neg : a ≡ b [ZMOD -n] ↔ a ≡ b [ZMOD n] := by simp [modeq_iff_dvd]
+#align int.modeq_neg Int.modEq_neg
+
 namespace Modeq
 
 /- warning: int.modeq.of_dvd -> Int.ModEq.of_dvd is a dubious translation:
@@ -164,19 +180,30 @@ protected theorem of_dvd (d : m ∣ n) (h : a ≡ b [ZMOD n]) : a ≡ b [ZMOD m]
   modEq_of_dvd <| d.trans h.Dvd
 #align int.modeq.of_dvd Int.ModEq.of_dvd
 
-#print Int.ModEq.mul_left' /-
-protected theorem mul_left' (hc : 0 ≤ c) (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD c * n] :=
-  Or.cases_on hc.lt_or_eq
-    (fun hc => by unfold modeq <;> simp [mul_mod_mul_of_pos hc, show _ = _ from h]) fun hc => by
-    simp [hc.symm]
+/- warning: int.modeq.mul_left' -> Int.ModEq.mul_left' is a dubious translation:
+lean 3 declaration is
+  forall {n : Int} {a : Int} {b : Int} {c : Int}, (Int.ModEq n a b) -> (Int.ModEq (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) c n) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) c a) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) c b))
+but is expected to have type
+  forall {n : Int} {a : Int} {b : Int} {c : Int}, (LE.le.{0} Int Int.instLEInt (OfNat.ofNat.{0} Int 0 (instOfNatInt 0)) c) -> (Int.ModEq n a b) -> (Int.ModEq (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) c n) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) c a) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) c b))
+Case conversion may be inaccurate. Consider using '#align int.modeq.mul_left' Int.ModEq.mul_left'ₓ'. -/
+protected theorem mul_left' (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD c * n] :=
+  by
+  obtain hc | rfl | hc := lt_trichotomy c 0
+  · rw [← neg_modeq_neg, ← modeq_neg, ← neg_mul, ← neg_mul, ← neg_mul]
+    simp only [modeq, mul_mod_mul_of_pos (neg_pos.2 hc), h.eq]
+  · simp
+  · simp only [modeq, mul_mod_mul_of_pos hc, h.eq]
 #align int.modeq.mul_left' Int.ModEq.mul_left'
--/
 
-#print Int.ModEq.mul_right' /-
-protected theorem mul_right' (hc : 0 ≤ c) (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n * c] := by
-  rw [mul_comm a, mul_comm b, mul_comm n] <;> exact h.mul_left' hc
+/- warning: int.modeq.mul_right' -> Int.ModEq.mul_right' is a dubious translation:
+lean 3 declaration is
+  forall {n : Int} {a : Int} {b : Int} {c : Int}, (Int.ModEq n a b) -> (Int.ModEq (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) n c) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) a c) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) b c))
+but is expected to have type
+  forall {n : Int} {a : Int} {b : Int} {c : Int}, (LE.le.{0} Int Int.instLEInt (OfNat.ofNat.{0} Int 0 (instOfNatInt 0)) c) -> (Int.ModEq n a b) -> (Int.ModEq (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) n c) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) a c) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) b c))
+Case conversion may be inaccurate. Consider using '#align int.modeq.mul_right' Int.ModEq.mul_right'ₓ'. -/
+protected theorem mul_right' (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n * c] := by
+  rw [mul_comm a, mul_comm b, mul_comm n] <;> exact h.mul_left'
 #align int.modeq.mul_right' Int.ModEq.mul_right'
--/
 
 #print Int.ModEq.add /-
 protected theorem add (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a + c ≡ b + d [ZMOD n] :=
@@ -256,17 +283,13 @@ protected theorem sub_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a - c ≡ b - c [
 
 #print Int.ModEq.mul_left /-
 protected theorem mul_left (c : ℤ) (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD n] :=
-  Or.cases_on (le_total 0 c) (fun hc => (h.mul_left' hc).of_dvd (dvd_mul_left _ _)) fun hc => by
-    rw [← neg_neg c, neg_mul, neg_mul _ b] <;>
-      exact ((h.mul_left' <| neg_nonneg.2 hc).of_dvd (dvd_mul_left _ _)).neg
+  h.mul_left'.of_dvd <| dvd_mul_left _ _
 #align int.modeq.mul_left Int.ModEq.mul_left
 -/
 
 #print Int.ModEq.mul_right /-
 protected theorem mul_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n] :=
-  by
-  rw [mul_comm a, mul_comm b]
-  exact h.mul_left c
+  h.mul_right'.of_dvd <| dvd_mul_right _ _
 #align int.modeq.mul_right Int.ModEq.mul_right
 -/
 
@@ -301,6 +324,29 @@ theorem of_mul_right (m : ℤ) : a ≡ b [ZMOD n * m] → a ≡ b [ZMOD n] :=
 #align int.modeq.of_mul_right Int.ModEq.of_mul_right
 -/
 
+/-- To cancel a common factor `c` from a `modeq` we must divide the modulus `m` by `gcd m c`. -/
+theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) : a ≡ b [ZMOD m / gcd m c] :=
+  by
+  let d := gcd m c
+  have hmd := gcd_dvd_left m c
+  have hcd := gcd_dvd_right m c
+  rw [modeq_iff_dvd] at h⊢
+  refine' Int.dvd_of_dvd_mul_right_of_gcd_one _ _
+  show m / d ∣ c / d * (b - a)
+  · rw [mul_comm, ← Int.mul_ediv_assoc (b - a) hcd, sub_mul]
+    exact Int.ediv_dvd_ediv hmd h
+  · rw [gcd_div hmd hcd, nat_abs_of_nat, Nat.div_self (gcd_pos_of_ne_zero_left c hm.ne')]
+#align int.modeq.cancel_right_div_gcd Int.ModEq.cancel_right_div_gcd
+
+/-- To cancel a common factor `c` from a `modeq` we must divide the modulus `m` by `gcd m c`. -/
+theorem cancel_left_div_gcd (hm : 0 < m) (h : c * a ≡ c * b [ZMOD m]) : a ≡ b [ZMOD m / gcd m c] :=
+  cancel_right_div_gcd hm <| by simpa [mul_comm] using h
+#align int.modeq.cancel_left_div_gcd Int.ModEq.cancel_left_div_gcd
+
+theorem of_div (h : a / c ≡ b / c [ZMOD m / c]) (ha : c ∣ a) (ha : c ∣ b) (ha : c ∣ m) :
+    a ≡ b [ZMOD m] := by convert h.mul_left' <;> rwa [Int.mul_ediv_cancel']
+#align int.modeq.of_div Int.ModEq.of_div
+
 end Modeq
 
 #print Int.modEq_one /-
@@ -315,6 +361,20 @@ theorem modEq_sub (a b : ℤ) : a ≡ b [ZMOD a - b] :=
 #align int.modeq_sub Int.modEq_sub
 -/
 
+@[simp]
+theorem modEq_zero_iff : a ≡ b [ZMOD 0] ↔ a = b := by rw [modeq, mod_zero, mod_zero]
+#align int.modeq_zero_iff Int.modEq_zero_iff
+
+@[simp]
+theorem add_modEq_left : n + a ≡ a [ZMOD n] :=
+  ModEq.symm <| modEq_iff_dvd.2 <| by simp
+#align int.add_modeq_left Int.add_modEq_left
+
+@[simp]
+theorem add_modEq_right : a + n ≡ a [ZMOD n] :=
+  ModEq.symm <| modEq_iff_dvd.2 <| by simp
+#align int.add_modeq_right Int.add_modEq_right
+
 #print Int.modEq_and_modEq_iff_modEq_mul /-
 theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.coprime n.natAbs) :
     a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ a ≡ b [ZMOD m * n] :=
Diff
@@ -339,7 +339,7 @@ theorem gcd_a_modEq (a b : ℕ) : (a : ℤ) * Nat.gcdA a b ≡ Nat.gcd a b [ZMOD
 theorem modEq_add_fac {a b n : ℤ} (c : ℤ) (ha : a ≡ b [ZMOD n]) : a + n * c ≡ b [ZMOD n] :=
   calc
     a + n * c ≡ b + n * c [ZMOD n] := ha.add_right _
-    _ ≡ b + 0 [ZMOD n] := (dvd_mul_right _ _).modEq_zero_int.add_left _
+    _ ≡ b + 0 [ZMOD n] := ((dvd_mul_right _ _).modEq_zero_int.add_left _)
     _ ≡ b [ZMOD n] := by rw [add_zero]
     
 #align int.modeq_add_fac Int.modEq_add_fac

Changes in mathlib4

mathlib3
mathlib4
chore: unify date formatting in lemma deprecations (#12334)
  • consistently use the YYYY-MM-DD format
  • when easily possible, put the date on the same line as the deprecated attribute
  • when easily possible, format the entire declaration on the same line

Why these changes?

  • consistency makes it easier for tools to parse this information
  • compactness: I don't see a good reason for these declarations taking up more space than needed; as I understand it, deprecated lemmas are not supposed to be used in mathlib anyway
  • putting the date on the same line as the attribute makes it easier to discover un-dated deprecations; they also ease writing a tool to replace these by a machine-readable version using leanprover/lean4#3968
Diff
@@ -325,7 +325,6 @@ theorem mod_mul_left_mod (a b c : ℤ) : a % (b * c) % c = a % c :=
   (mod_modEq _ _).of_mul_left _
 #align int.mod_mul_left_mod Int.mod_mul_left_mod
 
--- 2024-04-02
-@[deprecated] alias coe_nat_modEq_iff := natCast_modEq_iff
+@[deprecated] alias coe_nat_modEq_iff := natCast_modEq_iff -- 2024-04-02
 
 end Int
chore(Data/Int): Rename coe_nat to natCast (#11637)

Reduce the diff of #11499

Renames

All in the Int namespace:

  • ofNat_eq_castofNat_eq_natCast
  • cast_eq_cast_iff_NatnatCast_inj
  • natCast_eq_ofNatofNat_eq_natCast
  • coe_nat_subnatCast_sub
  • coe_nat_nonnegnatCast_nonneg
  • sign_coe_add_onesign_natCast_add_one
  • nat_succ_eq_int_succnatCast_succ
  • succ_neg_nat_succsucc_neg_natCast_succ
  • coe_pred_of_posnatCast_pred_of_pos
  • coe_nat_divnatCast_div
  • coe_nat_edivnatCast_ediv
  • sign_coe_nat_of_nonzerosign_natCast_of_ne_zero
  • toNat_coe_nattoNat_natCast
  • toNat_coe_nat_add_onetoNat_natCast_add_one
  • coe_nat_dvdnatCast_dvd_natCast
  • coe_nat_dvd_leftnatCast_dvd
  • coe_nat_dvd_rightdvd_natCast
  • le_coe_nat_suble_natCast_sub
  • succ_coe_nat_possucc_natCast_pos
  • coe_nat_modEq_iffnatCast_modEq_iff
  • coe_natAbsnatCast_natAbs
  • coe_nat_eq_zeronatCast_eq_zero
  • coe_nat_ne_zeronatCast_ne_zero
  • coe_nat_ne_zero_iff_posnatCast_ne_zero_iff_pos
  • abs_coe_natabs_natCast
  • coe_nat_nonpos_iffnatCast_nonpos_iff

Also rename Nat.coe_nat_dvd to Nat.cast_dvd_cast

Diff
@@ -75,9 +75,9 @@ end ModEq
 theorem modEq_comm : a ≡ b [ZMOD n] ↔ b ≡ a [ZMOD n] := ⟨ModEq.symm, ModEq.symm⟩
 #align int.modeq_comm Int.modEq_comm
 
-theorem coe_nat_modEq_iff {a b n : ℕ} : a ≡ b [ZMOD n] ↔ a ≡ b [MOD n] := by
-  unfold ModEq Nat.ModEq; rw [← Int.ofNat_inj]; simp [coe_nat_mod]
-#align int.coe_nat_modeq_iff Int.coe_nat_modEq_iff
+theorem natCast_modEq_iff {a b n : ℕ} : a ≡ b [ZMOD n] ↔ a ≡ b [MOD n] := by
+  unfold ModEq Nat.ModEq; rw [← Int.ofNat_inj]; simp [natCast_mod]
+#align int.coe_nat_modeq_iff Int.natCast_modEq_iff
 
 theorem modEq_zero_iff_dvd : a ≡ 0 [ZMOD n] ↔ n ∣ a := by
   rw [ModEq, zero_emod, dvd_iff_emod_eq_zero]
@@ -267,8 +267,8 @@ theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.Coprime n.
     a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ a ≡ b [ZMOD m * n] :=
   ⟨fun h => by
     rw [modEq_iff_dvd, modEq_iff_dvd] at h
-    rw [modEq_iff_dvd, ← natAbs_dvd, ← dvd_natAbs, coe_nat_dvd, natAbs_mul]
-    refine' hmn.mul_dvd_of_dvd_of_dvd _ _ <;> rw [← coe_nat_dvd, natAbs_dvd, dvd_natAbs] <;>
+    rw [modEq_iff_dvd, ← natAbs_dvd, ← dvd_natAbs, natCast_dvd_natCast, natAbs_mul]
+    refine' hmn.mul_dvd_of_dvd_of_dvd _ _ <;> rw [← natCast_dvd_natCast, natAbs_dvd, dvd_natAbs] <;>
       tauto,
     fun h => ⟨h.of_mul_right _, h.of_mul_left _⟩⟩
 #align int.modeq_and_modeq_iff_modeq_mul Int.modEq_and_modEq_iff_modEq_mul
@@ -325,4 +325,7 @@ theorem mod_mul_left_mod (a b c : ℤ) : a % (b * c) % c = a % c :=
   (mod_modEq _ _).of_mul_left _
 #align int.mod_mul_left_mod Int.mod_mul_left_mod
 
+-- 2024-04-02
+@[deprecated] alias coe_nat_modEq_iff := natCast_modEq_iff
+
 end Int
change the order of operation in zsmulRec and nsmulRec (#11451)

We change the following field in the definition of an additive commutative monoid:

 nsmul_succ : ∀ (n : ℕ) (x : G),
-  AddMonoid.nsmul (n + 1) x = x + AddMonoid.nsmul n x
+  AddMonoid.nsmul (n + 1) x = AddMonoid.nsmul n x + x

where the latter is more natural

We adjust the definitions of ^ in monoids, groups, etc. Originally there was a warning comment about why this natural order was preferred

use x * npowRec n x and not npowRec n x * x in the definition to make sure that definitional unfolding of npowRec is blocked, to avoid deep recursion issues.

but it seems to no longer apply.

Remarks on the PR :

  • pow_succ and pow_succ' have switched their meanings.
  • Most of the time, the proofs were adjusted by priming/unpriming one lemma, or exchanging left and right; a few proofs were more complicated to adjust.
  • In particular, [Mathlib/NumberTheory/RamificationInertia.lean] used Ideal.IsPrime.mul_mem_pow which is defined in [Mathlib/RingTheory/DedekindDomain/Ideal.lean]. Changing the order of operation forced me to add the symmetric lemma Ideal.IsPrime.mem_pow_mul.
  • the docstring for Cauchy condensation test in [Mathlib/Analysis/PSeries.lean] was mathematically incorrect, I added the mention that the function is antitone.
Diff
@@ -208,7 +208,7 @@ protected theorem mul (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a *
 @[gcongr] protected theorem pow (m : ℕ) (h : a ≡ b [ZMOD n]) : a ^ m ≡ b ^ m [ZMOD n] := by
   induction' m with d hd; · rfl
   rw [pow_succ, pow_succ]
-  exact h.mul hd
+  exact hd.mul h
 #align int.modeq.pow Int.ModEq.pow
 
 lemma of_mul_left (m : ℤ) (h : a ≡ b [ZMOD m * n]) : a ≡ b [ZMOD n] := by
style: homogenise porting notes (#11145)

Homogenises porting notes via capitalisation and addition of whitespace.

It makes the following changes:

  • converts "--porting note" into "-- Porting note";
  • converts "porting note" into "Porting note".
Diff
@@ -111,7 +111,7 @@ theorem mod_modEq (a n) : a % n ≡ a [ZMOD n] :=
 
 @[simp]
 theorem neg_modEq_neg : -a ≡ -b [ZMOD n] ↔ a ≡ b [ZMOD n] := by
---porting note: Restore old proof once #3309 is through
+-- Porting note: Restore old proof once #3309 is through
   simp [-sub_neg_eq_add, neg_sub_neg, modEq_iff_dvd, dvd_sub_comm]
 #align int.neg_modeq_neg Int.neg_modEq_neg
 
@@ -224,7 +224,7 @@ theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) :
     a ≡ b [ZMOD m / gcd m c] := by
   letI d := gcd m c
   rw [modEq_iff_dvd] at h ⊢
-  -- porting note: removed `show` due to leanprover-community/mathlib4#3305
+  -- Porting note: removed `show` due to leanprover-community/mathlib4#3305
   refine Int.dvd_of_dvd_mul_right_of_gcd_one (?_ : m / d ∣ c / d * (b - a)) ?_
   · rw [mul_comm, ← Int.mul_ediv_assoc (b - a) gcd_dvd_right, sub_mul]
     exact Int.ediv_dvd_ediv gcd_dvd_left h
chore: bump Std to leanprover/std4#541 (#9828)

Notable changes: lemmas were added in https://github.com/leanprover/std4/pull/538 about gcd and lcm, that now have implicit arguments. Mostly this is a positive change in Mathlib, we can just delete the arguments. The one to consider in review is in ModEq.

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -223,14 +223,13 @@ lemma of_mul_right (m : ℤ) : a ≡ b [ZMOD n * m] → a ≡ b [ZMOD n] :=
 theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) :
     a ≡ b [ZMOD m / gcd m c] := by
   letI d := gcd m c
-  have hmd := gcd_dvd_left m c
-  have hcd := gcd_dvd_right m c
   rw [modEq_iff_dvd] at h ⊢
   -- porting note: removed `show` due to leanprover-community/mathlib4#3305
   refine Int.dvd_of_dvd_mul_right_of_gcd_one (?_ : m / d ∣ c / d * (b - a)) ?_
-  · rw [mul_comm, ← Int.mul_ediv_assoc (b - a) hcd, sub_mul]
-    exact Int.ediv_dvd_ediv hmd h
-  · rw [gcd_div hmd hcd, natAbs_ofNat, Nat.div_self (gcd_pos_of_ne_zero_left c hm.ne')]
+  · rw [mul_comm, ← Int.mul_ediv_assoc (b - a) gcd_dvd_right, sub_mul]
+    exact Int.ediv_dvd_ediv gcd_dvd_left h
+  · rw [gcd_div gcd_dvd_left gcd_dvd_right, natAbs_ofNat,
+      Nat.div_self (gcd_pos_of_ne_zero_left c hm.ne')]
 #align int.modeq.cancel_right_div_gcd Int.ModEq.cancel_right_div_gcd
 
 /-- To cancel a common factor `c` from a `ModEq` we must divide the modulus `m` by `gcd m c`. -/
chore: bump Std dependency to leanprover/std4#432 (#9094)

This covers these changes in Std: https://github.com/leanprover/std4/compare/6b4cf96c89e53cfcd73350bbcd90333a051ff4f0...[9dd24a34](https://github.com/leanprover-community/mathlib/commit/9dd24a3493cceefa2bede383f21e4ef548990b68)

  • Int.ofNat_natAbs_eq_of_nonneg has become Int.natAbs_of_nonneg (and one argument has become implicit)
  • List.map_id'' and List.map_id' have exchanged names. (Yay naming things using primes!)
  • Some meta functions have moved to Std and can be deleted here.

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -315,7 +315,7 @@ theorem exists_unique_equiv (a : ℤ) {b : ℤ} (hb : 0 < b) :
 theorem exists_unique_equiv_nat (a : ℤ) {b : ℤ} (hb : 0 < b) : ∃ z : ℕ, ↑z < b ∧ ↑z ≡ a [ZMOD b] :=
   let ⟨z, hz1, hz2, hz3⟩ := exists_unique_equiv a hb
   ⟨z.natAbs, by
-    constructor <;> rw [ofNat_natAbs_eq_of_nonneg z hz1] <;> assumption⟩
+    constructor <;> rw [natAbs_of_nonneg hz1] <;> assumption⟩
 #align int.exists_unique_equiv_nat Int.exists_unique_equiv_nat
 
 theorem mod_mul_right_mod (a b c : ℤ) : a % (b * c) % b = a % b :=
chore: tidy various files (#8818)
Diff
@@ -129,7 +129,7 @@ protected theorem mul_left' (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD c * n
   obtain hc | rfl | hc := lt_trichotomy c 0
   · rw [← neg_modEq_neg, ← modEq_neg, ← neg_mul, ← neg_mul, ← neg_mul]
     simp only [ModEq, mul_emod_mul_of_pos _ _ (neg_pos.2 hc), h.eq]
-  · simp only [zero_mul]; rfl
+  · simp only [zero_mul, ModEq.rfl]
   · simp only [ModEq, mul_emod_mul_of_pos _ _ hc, h.eq]
 #align int.modeq.mul_left' Int.ModEq.mul_left'
 
feat: add a few simp lemmas (#8750)
  • Remove simp-lemma bitwise_of_ne_zero, since it wasn't used, and could cause loops in an inconsistent context.
Diff
@@ -42,7 +42,7 @@ instance : Decidable (ModEq n a b) := decEq (a % n) (b % n)
 
 namespace ModEq
 
-@[refl]
+@[refl, simp]
 protected theorem refl (a : ℤ) : a ≡ a [ZMOD n] :=
   @rfl _ _
 #align int.modeq.refl Int.ModEq.refl
chore: bump to v4.3.0-rc2 (#8366)

PR contents

This is the supremum of

along with some minor fixes from failures on nightly-testing as Mathlib master is merged into it.

Note that some PRs for changes that are already compatible with the current toolchain and will be necessary have already been split out: #8380.

I am hopeful that in future we will be able to progressively merge adaptation PRs into a bump/v4.X.0 branch, so we never end up with a "big merge" like this. However one of these adaptation PRs (#8056) predates my new scheme for combined CI, and it wasn't possible to keep that PR viable in the meantime.

Lean PRs involved in this bump

In particular this includes adjustments for the Lean PRs

leanprover/lean4#2778

We can get rid of all the

local macro_rules | `($x ^ $y) => `(HPow.hPow $x $y) -- Porting note: See issue [lean4#2220](https://github.com/leanprover/lean4/pull/2220)

macros across Mathlib (and in any projects that want to write natural number powers of reals).

leanprover/lean4#2722

Changes the default behaviour of simp to (config := {decide := false}). This makes simp (and consequentially norm_num) less powerful, but also more consistent, and less likely to blow up in long failures. This requires a variety of changes: changing some previously by simp or norm_num to decide or rfl, or adding (config := {decide := true}).

leanprover/lean4#2783

This changed the behaviour of simp so that simp [f] will only unfold "fully applied" occurrences of f. The old behaviour can be recovered with simp (config := { unfoldPartialApp := true }). We may in future add a syntax for this, e.g. simp [!f]; please provide feedback! In the meantime, we have made the following changes:

  • switching to using explicit lemmas that have the intended level of application
  • (config := { unfoldPartialApp := true }) in some places, to recover the old behaviour
  • Using @[eqns] to manually adjust the equation lemmas for a particular definition, recovering the old behaviour just for that definition. See #8371, where we do this for Function.comp and Function.flip.

This change in Lean may require further changes down the line (e.g. adding the !f syntax, and/or upstreaming the special treatment for Function.comp and Function.flip, and/or removing this special treatment). Please keep an open and skeptical mind about these changes!

Co-authored-by: leanprover-community-mathlib4-bot <leanprover-community-mathlib4-bot@users.noreply.github.com> Co-authored-by: Scott Morrison <scott.morrison@gmail.com> Co-authored-by: Eric Wieser <wieser.eric@gmail.com> Co-authored-by: Mauricio Collares <mauricio@collares.org>

Diff
@@ -129,7 +129,7 @@ protected theorem mul_left' (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD c * n
   obtain hc | rfl | hc := lt_trichotomy c 0
   · rw [← neg_modEq_neg, ← modEq_neg, ← neg_mul, ← neg_mul, ← neg_mul]
     simp only [ModEq, mul_emod_mul_of_pos _ _ (neg_pos.2 hc), h.eq]
-  · simp
+  · simp only [zero_mul]; rfl
   · simp only [ModEq, mul_emod_mul_of_pos _ _ hc, h.eq]
 #align int.modeq.mul_left' Int.ModEq.mul_left'
 
chore: bump to v4.1.0-rc1 (2nd attempt) (#7216)

Co-authored-by: Eric Wieser <wieser.eric@gmail.com> Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -264,7 +264,7 @@ theorem add_modEq_left : n + a ≡ a [ZMOD n] := ModEq.symm <| modEq_iff_dvd.2 <
 theorem add_modEq_right : a + n ≡ a [ZMOD n] := ModEq.symm <| modEq_iff_dvd.2 <| by simp
 #align int.add_modeq_right Int.add_modEq_right
 
-theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.coprime n.natAbs) :
+theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.Coprime n.natAbs) :
     a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ a ≡ b [ZMOD m * n] :=
   ⟨fun h => by
     rw [modEq_iff_dvd, modEq_iff_dvd] at h
@@ -294,9 +294,9 @@ theorem modEq_add_fac_self {a t n : ℤ} : a + n * t ≡ a [ZMOD n] :=
   modEq_add_fac _ ModEq.rfl
 #align int.modeq_add_fac_self Int.modEq_add_fac_self
 
-theorem mod_coprime {a b : ℕ} (hab : Nat.coprime a b) : ∃ y : ℤ, a * y ≡ 1 [ZMOD b] :=
+theorem mod_coprime {a b : ℕ} (hab : Nat.Coprime a b) : ∃ y : ℤ, a * y ≡ 1 [ZMOD b] :=
   ⟨Nat.gcdA a b,
-    have hgcd : Nat.gcd a b = 1 := Nat.coprime.gcd_eq_one hab
+    have hgcd : Nat.gcd a b = 1 := Nat.Coprime.gcd_eq_one hab
     calc
       ↑a * Nat.gcdA a b ≡ ↑a * Nat.gcdA a b + ↑b * Nat.gcdB a b [ZMOD ↑b] :=
         ModEq.symm <| modEq_add_fac _ <| ModEq.refl _
Revert "chore: bump to v4.1.0-rc1 (#7174)" (#7198)

This reverts commit 6f8e8104. Unfortunately this bump was not linted correctly, as CI did not run runLinter Mathlib.

We can unrevert once that's fixed.

Diff
@@ -264,7 +264,7 @@ theorem add_modEq_left : n + a ≡ a [ZMOD n] := ModEq.symm <| modEq_iff_dvd.2 <
 theorem add_modEq_right : a + n ≡ a [ZMOD n] := ModEq.symm <| modEq_iff_dvd.2 <| by simp
 #align int.add_modeq_right Int.add_modEq_right
 
-theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.Coprime n.natAbs) :
+theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.coprime n.natAbs) :
     a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ a ≡ b [ZMOD m * n] :=
   ⟨fun h => by
     rw [modEq_iff_dvd, modEq_iff_dvd] at h
@@ -294,9 +294,9 @@ theorem modEq_add_fac_self {a t n : ℤ} : a + n * t ≡ a [ZMOD n] :=
   modEq_add_fac _ ModEq.rfl
 #align int.modeq_add_fac_self Int.modEq_add_fac_self
 
-theorem mod_coprime {a b : ℕ} (hab : Nat.Coprime a b) : ∃ y : ℤ, a * y ≡ 1 [ZMOD b] :=
+theorem mod_coprime {a b : ℕ} (hab : Nat.coprime a b) : ∃ y : ℤ, a * y ≡ 1 [ZMOD b] :=
   ⟨Nat.gcdA a b,
-    have hgcd : Nat.gcd a b = 1 := Nat.Coprime.gcd_eq_one hab
+    have hgcd : Nat.gcd a b = 1 := Nat.coprime.gcd_eq_one hab
     calc
       ↑a * Nat.gcdA a b ≡ ↑a * Nat.gcdA a b + ↑b * Nat.gcdB a b [ZMOD ↑b] :=
         ModEq.symm <| modEq_add_fac _ <| ModEq.refl _
chore: bump to v4.1.0-rc1 (#7174)

Some changes have already been review and delegated in #6910 and #7148.

The diff that needs looking at is https://github.com/leanprover-community/mathlib4/pull/7174/commits/64d6d07ee18163627c8f517eb31455411921c5ac

The std bump PR was insta-merged already!

Co-authored-by: leanprover-community-mathlib4-bot <leanprover-community-mathlib4-bot@users.noreply.github.com> Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -264,7 +264,7 @@ theorem add_modEq_left : n + a ≡ a [ZMOD n] := ModEq.symm <| modEq_iff_dvd.2 <
 theorem add_modEq_right : a + n ≡ a [ZMOD n] := ModEq.symm <| modEq_iff_dvd.2 <| by simp
 #align int.add_modeq_right Int.add_modEq_right
 
-theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.coprime n.natAbs) :
+theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.Coprime n.natAbs) :
     a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ a ≡ b [ZMOD m * n] :=
   ⟨fun h => by
     rw [modEq_iff_dvd, modEq_iff_dvd] at h
@@ -294,9 +294,9 @@ theorem modEq_add_fac_self {a t n : ℤ} : a + n * t ≡ a [ZMOD n] :=
   modEq_add_fac _ ModEq.rfl
 #align int.modeq_add_fac_self Int.modEq_add_fac_self
 
-theorem mod_coprime {a b : ℕ} (hab : Nat.coprime a b) : ∃ y : ℤ, a * y ≡ 1 [ZMOD b] :=
+theorem mod_coprime {a b : ℕ} (hab : Nat.Coprime a b) : ∃ y : ℤ, a * y ≡ 1 [ZMOD b] :=
   ⟨Nat.gcdA a b,
-    have hgcd : Nat.gcd a b = 1 := Nat.coprime.gcd_eq_one hab
+    have hgcd : Nat.gcd a b = 1 := Nat.Coprime.gcd_eq_one hab
     calc
       ↑a * Nat.gcdA a b ≡ ↑a * Nat.gcdA a b + ↑b * Nat.gcdB a b [ZMOD ↑b] :=
         ModEq.symm <| modEq_add_fac _ <| ModEq.refl _
feat: patch for new alias command (#6172)
Diff
@@ -101,7 +101,7 @@ theorem modEq_iff_add_fac {a b n : ℤ} : a ≡ b [ZMOD n] ↔ ∃ t, b = a + n
   exact exists_congr fun t => sub_eq_iff_eq_add'
 #align int.modeq_iff_add_fac Int.modEq_iff_add_fac
 
-alias modEq_iff_dvd ↔ ModEq.dvd modEq_of_dvd
+alias ⟨ModEq.dvd, modEq_of_dvd⟩ := modEq_iff_dvd
 #align int.modeq.dvd Int.ModEq.dvd
 #align int.modeq_of_dvd Int.modEq_of_dvd
 
feat: Data/Int/ModEq add theorem modEq_sub_fac, compliment modEq_add_fac (#6040)

Easy of use function to compliment modEq_add_fac, the statement that :

a = b [ZMOD n] implies a - c * n = b [ZMOD n]

Diff
@@ -286,6 +286,10 @@ theorem modEq_add_fac {a b n : ℤ} (c : ℤ) (ha : a ≡ b [ZMOD n]) : a + n *
     _ ≡ b [ZMOD n] := by rw [add_zero]
 #align int.modeq_add_fac Int.modEq_add_fac
 
+theorem modEq_sub_fac {a b n : ℤ} (c : ℤ) (ha : a ≡ b [ZMOD n]) : a - n * c ≡ b [ZMOD n] := by
+  convert Int.modEq_add_fac (-c) ha using 1
+  ring
+
 theorem modEq_add_fac_self {a t n : ℤ} : a + n * t ≡ a [ZMOD n] :=
   modEq_add_fac _ ModEq.rfl
 #align int.modeq_add_fac_self Int.modEq_add_fac_self
chore: script to replace headers with #align_import statements (#5979)

Open in Gitpod

Co-authored-by: Eric Wieser <wieser.eric@gmail.com> Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -2,17 +2,14 @@
 Copyright (c) 2018 Chris Hughes. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Chris Hughes
-
-! This file was ported from Lean 3 source module data.int.modeq
-! leanprover-community/mathlib commit 47a1a73351de8dd6c8d3d32b569c8e434b03ca47
-! Please do not edit these lines, except to modify the commit id
-! if you have ported upstream changes.
 -/
 import Std.Data.Int.DivMod
 import Mathlib.Data.Nat.ModEq
 import Mathlib.Tactic.GCongr.Core
 import Mathlib.Tactic.Ring
 
+#align_import data.int.modeq from "leanprover-community/mathlib"@"47a1a73351de8dd6c8d3d32b569c8e434b03ca47"
+
 /-!
 
 # Congruences modulo an integer
feat: tactic gcongr for "relational congruence" (#3965)

This PR implements a new tactic, gcongr, which applies "relational congruence" rules, reducing a relational goal between a LHS and RHS matching the same pattern to relational subgoals between the differing inputs to the pattern. For example,

example {a b x c d : ℝ} (h1 : a + 1 ≤ b + 1) (h2 : c + 2 ≤ d + 2) :
    x ^ 4 * a + c ≤ x ^ 4 * b + d := by
  gcongr
  · linarith
  · linarith

This example has the goal of proving the relation between a LHS and RHS both of the pattern

x ^ 4 * ?_ + ?_

(with inputs a, c on the left and b, d on the right); after the use of gcongr, we have the simpler goals a ≤ b and c ≤ d.

For a sense of the style of argument facilitated by the tactic, this commit (which will be PR'd separately) gives >100 examples of use cases in the existing library.

The tactic's syntax allows for a pattern to be provided explicitly; this is useful if a non-maximal match is desired:

example {a b c d x : ℝ} (h : a + c + 1 ≤ b + d + 1) :
    x ^ 4 * (a + c) + 5 ≤ x ^ 4 * (b + d) + 5 := by
  gcongr x ^ 4 * ?_ + 5
  linarith

This feature is the analogue for general relations of the mathlib3 congrm tactic.

The "relational congruence" rules used are the library lemmas which have been tagged with the attribute @[gcongr]. For example, the first example constructs the proof term

add_le_add (mul_le_mul_of_nonneg_left _ (pow_bit0_nonneg x 2)) _

using the relational congruence lemmas add_le_add and mul_le_mul_of_nonneg_left. In this initial implementation, the @[gcongr] tagging has been set up for arithmetic head functions (+, * etc) and the relations , < and congruence-mod-n.

The tactic attempts to discharge side goals to these "relational congruence" lemmas (such as the side goal 0 ≤ x ^ 4 in the above application of mul_le_mul_of_nonneg_left) using the tactic gcongr_discharger, which wraps positivity but can also be extended. Side goals not discharged in this way are left for the user.

Zulip discussion

Co-authored-by: Mario Carneiro <di.gama@gmail.com>

Co-authored-by: Mario Carneiro <di.gama@gmail.com> Co-authored-by: Moritz Doll <moritz.doll@googlemail.com>

Diff
@@ -10,6 +10,7 @@ Authors: Chris Hughes
 -/
 import Std.Data.Int.DivMod
 import Mathlib.Data.Nat.ModEq
+import Mathlib.Tactic.GCongr.Core
 import Mathlib.Tactic.Ring
 
 /-!
@@ -139,17 +140,18 @@ protected theorem mul_right' (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n *
   rw [mul_comm a, mul_comm b, mul_comm n]; exact h.mul_left'
 #align int.modeq.mul_right' Int.ModEq.mul_right'
 
+@[gcongr]
 protected theorem add (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a + c ≡ b + d [ZMOD n] :=
   modEq_iff_dvd.2 <| by
     convert dvd_add h₁.dvd h₂.dvd using 1
     ring
 #align int.modeq.add Int.ModEq.add
 
-protected theorem add_left (c : ℤ) (h : a ≡ b [ZMOD n]) : c + a ≡ c + b [ZMOD n] :=
+@[gcongr] protected theorem add_left (c : ℤ) (h : a ≡ b [ZMOD n]) : c + a ≡ c + b [ZMOD n] :=
   ModEq.rfl.add h
 #align int.modeq.add_left Int.ModEq.add_left
 
-protected theorem add_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a + c ≡ b + c [ZMOD n] :=
+@[gcongr] protected theorem add_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a + c ≡ b + c [ZMOD n] :=
   h.add ModEq.rfl
 #align int.modeq.add_right Int.ModEq.add_right
 
@@ -175,36 +177,38 @@ protected theorem add_right_cancel' (c : ℤ) (h : a + c ≡ b + c [ZMOD n]) : a
   ModEq.rfl.add_right_cancel h
 #align int.modeq.add_right_cancel' Int.ModEq.add_right_cancel'
 
-protected theorem neg (h : a ≡ b [ZMOD n]) : -a ≡ -b [ZMOD n] :=
+@[gcongr] protected theorem neg (h : a ≡ b [ZMOD n]) : -a ≡ -b [ZMOD n] :=
   h.add_left_cancel (by simp_rw [← sub_eq_add_neg, sub_self]; rfl)
 #align int.modeq.neg Int.ModEq.neg
 
+@[gcongr]
 protected theorem sub (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a - c ≡ b - d [ZMOD n] := by
   rw [sub_eq_add_neg, sub_eq_add_neg]
   exact h₁.add h₂.neg
 #align int.modeq.sub Int.ModEq.sub
 
-protected theorem sub_left (c : ℤ) (h : a ≡ b [ZMOD n]) : c - a ≡ c - b [ZMOD n] :=
+@[gcongr] protected theorem sub_left (c : ℤ) (h : a ≡ b [ZMOD n]) : c - a ≡ c - b [ZMOD n] :=
   ModEq.rfl.sub h
 #align int.modeq.sub_left Int.ModEq.sub_left
 
-protected theorem sub_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a - c ≡ b - c [ZMOD n] :=
+@[gcongr] protected theorem sub_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a - c ≡ b - c [ZMOD n] :=
   h.sub ModEq.rfl
 #align int.modeq.sub_right Int.ModEq.sub_right
 
-protected theorem mul_left (c : ℤ) (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD n] :=
+@[gcongr] protected theorem mul_left (c : ℤ) (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD n] :=
   h.mul_left'.of_dvd <| dvd_mul_left _ _
 #align int.modeq.mul_left Int.ModEq.mul_left
 
-protected theorem mul_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n] :=
+@[gcongr] protected theorem mul_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n] :=
   h.mul_right'.of_dvd <| dvd_mul_right _ _
 #align int.modeq.mul_right Int.ModEq.mul_right
 
+@[gcongr]
 protected theorem mul (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a * c ≡ b * d [ZMOD n] :=
   (h₂.mul_left _).trans (h₁.mul_right _)
 #align int.modeq.mul Int.ModEq.mul
 
-protected theorem pow (m : ℕ) (h : a ≡ b [ZMOD n]) : a ^ m ≡ b ^ m [ZMOD n] := by
+@[gcongr] protected theorem pow (m : ℕ) (h : a ≡ b [ZMOD n]) : a ^ m ≡ b ^ m [ZMOD n] := by
   induction' m with d hd; · rfl
   rw [pow_succ, pow_succ]
   exact h.mul hd
chore: bye-bye, solo bys! (#3825)

This PR puts, with one exception, every single remaining by that lies all by itself on its own line to the previous line, thus matching the current behaviour of start-port.sh. The exception is when the by begins the second or later argument to a tuple or anonymous constructor; see https://github.com/leanprover-community/mathlib4/pull/3825#discussion_r1186702599.

Essentially this is s/\n *by$/ by/g, but with manual editing to satisfy the linter's max-100-char-line requirement. The Python style linter is also modified to catch these "isolated bys".

Diff
@@ -219,8 +219,8 @@ lemma of_mul_right (m : ℤ) : a ≡ b [ZMOD n * m] → a ≡ b [ZMOD n] :=
 #align int.modeq.of_mul_right Int.ModEq.of_mul_right
 
 /-- To cancel a common factor `c` from a `ModEq` we must divide the modulus `m` by `gcd m c`. -/
-theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) : a ≡ b [ZMOD m / gcd m c] :=
-  by
+theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) :
+    a ≡ b [ZMOD m / gcd m c] := by
   letI d := gcd m c
   have hmd := gcd_dvd_left m c
   have hcd := gcd_dvd_right m c
@@ -303,8 +303,8 @@ theorem exists_unique_equiv (a : ℤ) {b : ℤ} (hb : 0 < b) :
     ∃ z : ℤ, 0 ≤ z ∧ z < b ∧ z ≡ a [ZMOD b] :=
   ⟨a % b, emod_nonneg _ (ne_of_gt hb),
     by
-    have : a % b < |b| := emod_lt _ (ne_of_gt hb)
-    rwa [abs_of_pos hb] at this, by simp [ModEq]⟩
+      have : a % b < |b| := emod_lt _ (ne_of_gt hb)
+      rwa [abs_of_pos hb] at this, by simp [ModEq]⟩
 #align int.exists_unique_equiv Int.exists_unique_equiv
 
 theorem exists_unique_equiv_nat (a : ℤ) {b : ℤ} (hb : 0 < b) : ∃ z : ℕ, ↑z < b ∧ ↑z ≡ a [ZMOD b] :=
chore: fix #align lines (#3640)

This PR fixes two things:

  • Most align statements for definitions and theorems and instances that are separated by two newlines from the relevant declaration (s/\n\n#align/\n#align). This is often seen in the mathport output after ending calc blocks.
  • All remaining more-than-one-line #align statements. (This was needed for a script I wrote for #3630.)
Diff
@@ -96,7 +96,6 @@ theorem _root_.Dvd.dvd.zero_modEq_int (h : n ∣ a) : 0 ≡ a [ZMOD n] :=
 theorem modEq_iff_dvd : a ≡ b [ZMOD n] ↔ n ∣ b - a := by
   rw [ModEq, eq_comm]
   simp [emod_eq_emod_iff_emod_sub_eq_zero, dvd_iff_emod_eq_zero]
-
 #align int.modeq_iff_dvd Int.modEq_iff_dvd
 
 theorem modEq_iff_add_fac {a b n : ℤ} : a ≡ b [ZMOD n] ↔ ∃ t, b = a + n * t := by
@@ -284,7 +283,6 @@ theorem modEq_add_fac {a b n : ℤ} (c : ℤ) (ha : a ≡ b [ZMOD n]) : a + n *
     a + n * c ≡ b + n * c [ZMOD n] := ha.add_right _
     _ ≡ b + 0 [ZMOD n] := (dvd_mul_right _ _).modEq_zero_int.add_left _
     _ ≡ b [ZMOD n] := by rw [add_zero]
-
 #align int.modeq_add_fac Int.modEq_add_fac
 
 theorem modEq_add_fac_self {a t n : ℤ} : a + n * t ≡ a [ZMOD n] :=
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Chris Hughes
 
 ! This file was ported from Lean 3 source module data.int.modeq
-! leanprover-community/mathlib commit 2ed7e4aec72395b6a7c3ac4ac7873a7a43ead17c
+! leanprover-community/mathlib commit 47a1a73351de8dd6c8d3d32b569c8e434b03ca47
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -69,8 +69,14 @@ protected theorem trans : a ≡ b [ZMOD n] → b ≡ c [ZMOD n] → a ≡ c [ZMO
 instance : IsTrans ℤ (ModEq n) where
   trans := @Int.ModEq.trans n
 
+protected theorem eq : a ≡ b [ZMOD n] → a % n = b % n := id
+#align int.modeq.eq Int.ModEq.eq
+
 end ModEq
 
+theorem modEq_comm : a ≡ b [ZMOD n] ↔ b ≡ a [ZMOD n] := ⟨ModEq.symm, ModEq.symm⟩
+#align int.modeq_comm Int.modEq_comm
+
 theorem coe_nat_modEq_iff {a b n : ℕ} : a ≡ b [ZMOD n] ↔ a ≡ b [MOD n] := by
   unfold ModEq Nat.ModEq; rw [← Int.ofNat_inj]; simp [coe_nat_mod]
 #align int.coe_nat_modeq_iff Int.coe_nat_modEq_iff
@@ -106,23 +112,32 @@ theorem mod_modEq (a n) : a % n ≡ a [ZMOD n] :=
   emod_emod _ _
 #align int.mod_modeq Int.mod_modEq
 
+@[simp]
+theorem neg_modEq_neg : -a ≡ -b [ZMOD n] ↔ a ≡ b [ZMOD n] := by
+--porting note: Restore old proof once #3309 is through
+  simp [-sub_neg_eq_add, neg_sub_neg, modEq_iff_dvd, dvd_sub_comm]
+#align int.neg_modeq_neg Int.neg_modEq_neg
+
+@[simp]
+theorem modEq_neg : a ≡ b [ZMOD -n] ↔ a ≡ b [ZMOD n] := by simp [modEq_iff_dvd]
+#align int.modeq_neg Int.modEq_neg
+
 namespace ModEq
 
 protected theorem of_dvd (d : m ∣ n) (h : a ≡ b [ZMOD n]) : a ≡ b [ZMOD m] :=
   modEq_iff_dvd.2 <| d.trans h.dvd
 #align int.modeq.of_dvd Int.ModEq.of_dvd
 
-protected theorem mul_left' (hc : 0 ≤ c) (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD c * n] :=
-  match hc.lt_or_eq with
-  | .inl hc => by
-    unfold ModEq
-    simp [mul_emod_mul_of_pos _ _ hc, show _ = _ from h]
-  | .inr hc => by
-    simp [hc.symm]
+protected theorem mul_left' (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD c * n] := by
+  obtain hc | rfl | hc := lt_trichotomy c 0
+  · rw [← neg_modEq_neg, ← modEq_neg, ← neg_mul, ← neg_mul, ← neg_mul]
+    simp only [ModEq, mul_emod_mul_of_pos _ _ (neg_pos.2 hc), h.eq]
+  · simp
+  · simp only [ModEq, mul_emod_mul_of_pos _ _ hc, h.eq]
 #align int.modeq.mul_left' Int.ModEq.mul_left'
 
-protected theorem mul_right' (hc : 0 ≤ c) (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n * c] := by
-  rw [mul_comm a, mul_comm b, mul_comm n]; exact h.mul_left' hc
+protected theorem mul_right' (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n * c] := by
+  rw [mul_comm a, mul_comm b, mul_comm n]; exact h.mul_left'
 #align int.modeq.mul_right' Int.ModEq.mul_right'
 
 protected theorem add (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a + c ≡ b + d [ZMOD n] :=
@@ -179,16 +194,11 @@ protected theorem sub_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a - c ≡ b - c [
 #align int.modeq.sub_right Int.ModEq.sub_right
 
 protected theorem mul_left (c : ℤ) (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD n] :=
-  match (le_total 0 c) with
-  | .inl hc => (h.mul_left' hc).of_dvd (dvd_mul_left _ _)
-  | .inr hc => by
-    rw [← neg_neg c, neg_mul, neg_mul _ b]
-    exact ((h.mul_left' <| neg_nonneg.2 hc).of_dvd (dvd_mul_left _ _)).neg
+  h.mul_left'.of_dvd <| dvd_mul_left _ _
 #align int.modeq.mul_left Int.ModEq.mul_left
 
-protected theorem mul_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n] := by
-  rw [mul_comm a, mul_comm b]
-  exact h.mul_left c
+protected theorem mul_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n] :=
+  h.mul_right'.of_dvd <| dvd_mul_right _ _
 #align int.modeq.mul_right Int.ModEq.mul_right
 
 protected theorem mul (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a * c ≡ b * d [ZMOD n] :=
@@ -209,6 +219,29 @@ lemma of_mul_right (m : ℤ) : a ≡ b [ZMOD n * m] → a ≡ b [ZMOD n] :=
   mul_comm m n ▸ of_mul_left _
 #align int.modeq.of_mul_right Int.ModEq.of_mul_right
 
+/-- To cancel a common factor `c` from a `ModEq` we must divide the modulus `m` by `gcd m c`. -/
+theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) : a ≡ b [ZMOD m / gcd m c] :=
+  by
+  letI d := gcd m c
+  have hmd := gcd_dvd_left m c
+  have hcd := gcd_dvd_right m c
+  rw [modEq_iff_dvd] at h ⊢
+  -- porting note: removed `show` due to leanprover-community/mathlib4#3305
+  refine Int.dvd_of_dvd_mul_right_of_gcd_one (?_ : m / d ∣ c / d * (b - a)) ?_
+  · rw [mul_comm, ← Int.mul_ediv_assoc (b - a) hcd, sub_mul]
+    exact Int.ediv_dvd_ediv hmd h
+  · rw [gcd_div hmd hcd, natAbs_ofNat, Nat.div_self (gcd_pos_of_ne_zero_left c hm.ne')]
+#align int.modeq.cancel_right_div_gcd Int.ModEq.cancel_right_div_gcd
+
+/-- To cancel a common factor `c` from a `ModEq` we must divide the modulus `m` by `gcd m c`. -/
+theorem cancel_left_div_gcd (hm : 0 < m) (h : c * a ≡ c * b [ZMOD m]) : a ≡ b [ZMOD m / gcd m c] :=
+  cancel_right_div_gcd hm <| by simpa [mul_comm] using h
+#align int.modeq.cancel_left_div_gcd Int.ModEq.cancel_left_div_gcd
+
+theorem of_div (h : a / c ≡ b / c [ZMOD m / c]) (ha : c ∣ a) (ha : c ∣ b) (ha : c ∣ m) :
+    a ≡ b [ZMOD m] := by convert h.mul_left' <;> rwa [Int.mul_ediv_cancel']
+#align int.modeq.of_div Int.ModEq.of_div
+
 end ModEq
 
 theorem modEq_one : a ≡ b [ZMOD 1] :=
@@ -219,6 +252,18 @@ theorem modEq_sub (a b : ℤ) : a ≡ b [ZMOD a - b] :=
   (modEq_of_dvd dvd_rfl).symm
 #align int.modeq_sub Int.modEq_sub
 
+@[simp]
+theorem modEq_zero_iff : a ≡ b [ZMOD 0] ↔ a = b := by rw [ModEq, emod_zero, emod_zero]
+#align int.modeq_zero_iff Int.modEq_zero_iff
+
+@[simp]
+theorem add_modEq_left : n + a ≡ a [ZMOD n] := ModEq.symm <| modEq_iff_dvd.2 <| by simp
+#align int.add_modeq_left Int.add_modEq_left
+
+@[simp]
+theorem add_modEq_right : a + n ≡ a [ZMOD n] := ModEq.symm <| modEq_iff_dvd.2 <| by simp
+#align int.add_modeq_right Int.add_modEq_right
+
 theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.coprime n.natAbs) :
     a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ a ≡ b [ZMOD m * n] :=
   ⟨fun h => by
feat: improvements to congr! and convert (#2606)
  • There is now configuration for congr!, convert, and convert_to to control parts of the congruence algorithm, in particular transparency settings when applying congruence lemmas.
  • congr! now applies congruence lemmas with reducible transparency by default. This prevents it from unfolding definitions when applying congruence lemmas. It also now tries both the LHS-biased and RHS-biased simp congruence lemmas, with a configuration option to set which it should try first.
  • There is now a new HEq congruence lemma generator that gives each hypothesis access to the proofs of previous hypotheses. This means that if you have an equality ⊢ ⟨a, x⟩ = ⟨b, y⟩ of sigma types, congr! turns this into goals ⊢ a = b and ⊢ a = b → HEq x y (note that congr! will also auto-introduce a = b for you in the second goal). This congruence lemma generator applies to more cases than the simp congruence lemma generator does.
  • congr! (and hence convert) are more careful about applying lemmas that don't force definitions to unfold. There were a number of cases in mathlib where the implementation of congr was being abused to unfold definitions.
  • With set_option trace.congr! true you can see what congr! sees when it is deciding on congruence lemmas.
  • There is also a bug fix in convert_to to do using 1 when there is no using clause, to match its documentation.

Note that congr! is more capable than congr at finding a way to equate left-hand sides and right-hand sides, so you will frequently need to limit its depth with a using clause. However, there is also a new heuristic to prevent considering unlikely-to-be-provable type equalities (controlled by the typeEqs option), which can help limit the depth automatically.

There is also a predefined configuration that you can invoke with, for example, convert (config := .unfoldSameFun) h, that causes it to behave more like congr, including using default transparency when unfolding.

Diff
@@ -127,7 +127,7 @@ protected theorem mul_right' (hc : 0 ≤ c) (h : a ≡ b [ZMOD n]) : a * c ≡ b
 
 protected theorem add (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a + c ≡ b + d [ZMOD n] :=
   modEq_iff_dvd.2 <| by
-    convert dvd_add h₁.dvd h₂.dvd
+    convert dvd_add h₁.dvd h₂.dvd using 1
     ring
 #align int.modeq.add Int.ModEq.add
 
Feat: prove IsTrans α r → Trans r r r and Trans r r r → IsTrans α r (#1522)

Now Trans.trans conflicts with _root_.trans.

Diff
@@ -66,8 +66,8 @@ protected theorem trans : a ≡ b [ZMOD n] → b ≡ c [ZMOD n] → a ≡ c [ZMO
   Eq.trans
 #align int.modeq.trans Int.ModEq.trans
 
-instance : Trans (ModEq n) (ModEq n) (ModEq n) where
-  trans := Int.ModEq.trans
+instance : IsTrans ℤ (ModEq n) where
+  trans := @Int.ModEq.trans n
 
 end ModEq
 
chore: format by line breaks (#1523)

During porting, I usually fix the desired format we seem to want for the line breaks around by with

awk '{do {{if (match($0, "^  by$") && length(p) < 98) {p=p " by";} else {if (NR!=1) {print p}; p=$0}}} while (getline == 1) if (getline==0) print p}' Mathlib/File/Im/Working/On.lean

I noticed there are some more files that slipped through.

This pull request is the result of running this command:

grep -lr "^  by\$" Mathlib | xargs -n 1 awk -i inplace '{do {{if (match($0, "^  by$") && length(p) < 98 && not (match(p, "^[ \t]*--"))) {p=p " by";} else {if (NR!=1) {print p}; p=$0}}} while (getline == 1) if (getline==0) print p}'

Co-authored-by: Moritz Firsching <firsching@google.com>

Diff
@@ -93,8 +93,7 @@ theorem modEq_iff_dvd : a ≡ b [ZMOD n] ↔ n ∣ b - a := by
 
 #align int.modeq_iff_dvd Int.modEq_iff_dvd
 
-theorem modEq_iff_add_fac {a b n : ℤ} : a ≡ b [ZMOD n] ↔ ∃ t, b = a + n * t :=
-  by
+theorem modEq_iff_add_fac {a b n : ℤ} : a ≡ b [ZMOD n] ↔ ∃ t, b = a + n * t := by
   rw [modEq_iff_dvd]
   exact exists_congr fun t => sub_eq_iff_eq_add'
 #align int.modeq_iff_add_fac Int.modEq_iff_add_fac
@@ -166,8 +165,7 @@ protected theorem neg (h : a ≡ b [ZMOD n]) : -a ≡ -b [ZMOD n] :=
   h.add_left_cancel (by simp_rw [← sub_eq_add_neg, sub_self]; rfl)
 #align int.modeq.neg Int.ModEq.neg
 
-protected theorem sub (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a - c ≡ b - d [ZMOD n] :=
-  by
+protected theorem sub (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a - c ≡ b - d [ZMOD n] := by
   rw [sub_eq_add_neg, sub_eq_add_neg]
   exact h₁.add h₂.neg
 #align int.modeq.sub Int.ModEq.sub
@@ -188,8 +186,7 @@ protected theorem mul_left (c : ℤ) (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [Z
     exact ((h.mul_left' <| neg_nonneg.2 hc).of_dvd (dvd_mul_left _ _)).neg
 #align int.modeq.mul_left Int.ModEq.mul_left
 
-protected theorem mul_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n] :=
-  by
+protected theorem mul_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n] := by
   rw [mul_comm a, mul_comm b]
   exact h.mul_left c
 #align int.modeq.mul_right Int.ModEq.mul_right
@@ -198,8 +195,7 @@ protected theorem mul (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a *
   (h₂.mul_left _).trans (h₁.mul_right _)
 #align int.modeq.mul Int.ModEq.mul
 
-protected theorem pow (m : ℕ) (h : a ≡ b [ZMOD n]) : a ^ m ≡ b ^ m [ZMOD n] :=
-  by
+protected theorem pow (m : ℕ) (h : a ≡ b [ZMOD n]) : a ^ m ≡ b ^ m [ZMOD n] := by
   induction' m with d hd; · rfl
   rw [pow_succ, pow_succ]
   exact h.mul hd
@@ -233,8 +229,7 @@ theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.coprime n.
     fun h => ⟨h.of_mul_right _, h.of_mul_left _⟩⟩
 #align int.modeq_and_modeq_iff_modeq_mul Int.modEq_and_modEq_iff_modEq_mul
 
-theorem gcd_a_modEq (a b : ℕ) : (a : ℤ) * Nat.gcdA a b ≡ Nat.gcd a b [ZMOD b] :=
-  by
+theorem gcd_a_modEq (a b : ℕ) : (a : ℤ) * Nat.gcdA a b ≡ Nat.gcd a b [ZMOD b] := by
   rw [← add_zero ((a : ℤ) * _), Nat.gcd_eq_gcd_ab]
   exact (dvd_mul_right _ _).zero_modEq_int.add_left _
 #align int.gcd_a_modeq Int.gcd_a_modEq
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Chris Hughes
 
 ! This file was ported from Lean 3 source module data.int.modeq
-! leanprover-community/mathlib commit ffc3730d545623aedf5d5bd46a3153cbf41f6c2c
+! leanprover-community/mathlib commit 2ed7e4aec72395b6a7c3ac4ac7873a7a43ead17c
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -99,12 +99,8 @@ theorem modEq_iff_add_fac {a b n : ℤ} : a ≡ b [ZMOD n] ↔ ∃ t, b = a + n
   exact exists_congr fun t => sub_eq_iff_eq_add'
 #align int.modeq_iff_add_fac Int.modEq_iff_add_fac
 
-theorem ModEq.dvd : a ≡ b [ZMOD n] → n ∣ b - a :=
-  modEq_iff_dvd.1
+alias modEq_iff_dvd ↔ ModEq.dvd modEq_of_dvd
 #align int.modeq.dvd Int.ModEq.dvd
-
-theorem modEq_of_dvd : n ∣ b - a → a ≡ b [ZMOD n] :=
-  modEq_iff_dvd.2
 #align int.modeq_of_dvd Int.modEq_of_dvd
 
 theorem mod_modEq (a n) : a % n ≡ a [ZMOD n] :=
@@ -113,9 +109,9 @@ theorem mod_modEq (a n) : a % n ≡ a [ZMOD n] :=
 
 namespace ModEq
 
-protected theorem modEq_of_dvd (d : m ∣ n) (h : a ≡ b [ZMOD n]) : a ≡ b [ZMOD m] :=
+protected theorem of_dvd (d : m ∣ n) (h : a ≡ b [ZMOD n]) : a ≡ b [ZMOD m] :=
   modEq_iff_dvd.2 <| d.trans h.dvd
-#align int.modeq.modeq_of_dvd Int.ModEq.modEq_of_dvd
+#align int.modeq.of_dvd Int.ModEq.of_dvd
 
 protected theorem mul_left' (hc : 0 ≤ c) (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD c * n] :=
   match hc.lt_or_eq with
@@ -186,10 +182,10 @@ protected theorem sub_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a - c ≡ b - c [
 
 protected theorem mul_left (c : ℤ) (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD n] :=
   match (le_total 0 c) with
-  | .inl hc => (h.mul_left' hc).modEq_of_dvd (dvd_mul_left _ _)
+  | .inl hc => (h.mul_left' hc).of_dvd (dvd_mul_left _ _)
   | .inr hc => by
     rw [← neg_neg c, neg_mul, neg_mul _ b]
-    exact ((h.mul_left' <| neg_nonneg.2 hc).modEq_of_dvd (dvd_mul_left _ _)).neg
+    exact ((h.mul_left' <| neg_nonneg.2 hc).of_dvd (dvd_mul_left _ _)).neg
 #align int.modeq.mul_left Int.ModEq.mul_left
 
 protected theorem mul_right (c : ℤ) (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n] :=
@@ -209,13 +205,13 @@ protected theorem pow (m : ℕ) (h : a ≡ b [ZMOD n]) : a ^ m ≡ b ^ m [ZMOD n
   exact h.mul hd
 #align int.modeq.pow Int.ModEq.pow
 
-theorem of_modEq_mul_left (m : ℤ) (h : a ≡ b [ZMOD m * n]) : a ≡ b [ZMOD n] := by
+lemma of_mul_left (m : ℤ) (h : a ≡ b [ZMOD m * n]) : a ≡ b [ZMOD n] := by
   rw [modEq_iff_dvd] at *; exact (dvd_mul_left n m).trans h
-#align int.modeq.of_modeq_mul_left Int.ModEq.of_modEq_mul_left
+#align int.modeq.of_mul_left Int.ModEq.of_mul_left
 
-theorem of_modEq_mul_right (m : ℤ) : a ≡ b [ZMOD n * m] → a ≡ b [ZMOD n] :=
-  mul_comm m n ▸ of_modEq_mul_left _
-#align int.modeq.of_modeq_mul_right Int.ModEq.of_modEq_mul_right
+lemma of_mul_right (m : ℤ) : a ≡ b [ZMOD n * m] → a ≡ b [ZMOD n] :=
+  mul_comm m n ▸ of_mul_left _
+#align int.modeq.of_mul_right Int.ModEq.of_mul_right
 
 end ModEq
 
@@ -234,7 +230,7 @@ theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.coprime n.
     rw [modEq_iff_dvd, ← natAbs_dvd, ← dvd_natAbs, coe_nat_dvd, natAbs_mul]
     refine' hmn.mul_dvd_of_dvd_of_dvd _ _ <;> rw [← coe_nat_dvd, natAbs_dvd, dvd_natAbs] <;>
       tauto,
-    fun h => ⟨h.of_modEq_mul_right _, h.of_modEq_mul_left _⟩⟩
+    fun h => ⟨h.of_mul_right _, h.of_mul_left _⟩⟩
 #align int.modeq_and_modeq_iff_modeq_mul Int.modEq_and_modEq_iff_modEq_mul
 
 theorem gcd_a_modEq (a b : ℕ) : (a : ℤ) * Nat.gcdA a b ≡ Nat.gcd a b [ZMOD b] :=
@@ -248,7 +244,7 @@ theorem modEq_add_fac {a b n : ℤ} (c : ℤ) (ha : a ≡ b [ZMOD n]) : a + n *
     a + n * c ≡ b + n * c [ZMOD n] := ha.add_right _
     _ ≡ b + 0 [ZMOD n] := (dvd_mul_right _ _).modEq_zero_int.add_left _
     _ ≡ b [ZMOD n] := by rw [add_zero]
-    
+
 #align int.modeq_add_fac Int.modEq_add_fac
 
 theorem modEq_add_fac_self {a t n : ℤ} : a + n * t ≡ a [ZMOD n] :=
@@ -280,11 +276,11 @@ theorem exists_unique_equiv_nat (a : ℤ) {b : ℤ} (hb : 0 < b) : ∃ z : ℕ,
 #align int.exists_unique_equiv_nat Int.exists_unique_equiv_nat
 
 theorem mod_mul_right_mod (a b c : ℤ) : a % (b * c) % b = a % b :=
-  (mod_modEq _ _).of_modEq_mul_right _
+  (mod_modEq _ _).of_mul_right _
 #align int.mod_mul_right_mod Int.mod_mul_right_mod
 
 theorem mod_mul_left_mod (a b c : ℤ) : a % (b * c) % c = a % c :=
-  (mod_modEq _ _).of_modEq_mul_left _
+  (mod_modEq _ _).of_mul_left _
 #align int.mod_mul_left_mod Int.mod_mul_left_mod
 
 end Int
feat: port Data.Int.ModEq (#1285)

Dependencies 2

3 files ported (100.0%)
1313 lines ported (100.0%)

All dependencies are ported!