Zulip Chat Archive

Stream: Is there code for X?

Topic: equation in ℕ to equation in zmod n


Stuart Presnell (Jul 31 2022 at 09:51):

I feel like I'm missing something obvious here. If I'm trying to prove, for example,

example (n : ) (x : zmod n) : x ^ 2 - 1 = (x + 1) * (x - 1) := sorry

and I have the corresponding statement that holds for all x : ℕ (in this case, nat.sq_sub_sq x 1), can I use the equation in to prove the equation in zmod n?

Stuart Presnell (Jul 31 2022 at 09:53):

I suspect the answer is either going to be "No, of course not, because ..." or "Of course, it's just ...". Either way, I have the :face_palm: ready!

Mario Carneiro (Jul 31 2022 at 10:02):

No, not really, but it is an equation in the language of rings and zmod n is a ring so by ring should work

Mario Carneiro (Jul 31 2022 at 10:02):

in fact this theorem is considreably harder over nat because - doesn't mean the usual thing

Kevin Buzzard (Jul 31 2022 at 10:39):

Yeah the canonical map (call it f) from nat to zmod n is surjective which is one of the ingredients you'd need for this, but it does not satisfy f(a-b) = f(a) - f(b) which would be another.

Kevin Buzzard (Jul 31 2022 at 10:40):

eg x-(x+1)=0 can be proved for nat but can't be deduced for zmod n

Stuart Presnell (Jul 31 2022 at 10:41):

Yes, I'd once again forgotten about the problem of subtraction.

Damiano Testa (Jul 31 2022 at 10:44):

For instance, when x=0 the statement over and over zmod n are both true but represent "different" identities.

Stuart Presnell (Jul 31 2022 at 10:50):

Yeah, I realise now that if I want to get a result for zmod n from something more generic, the natural generalisation is something like comm_ring R, not .

Stuart Presnell (Jul 31 2022 at 10:51):

And indeed the example I gave above has _root_.sq_sub_sq x 1 for x : R.

Ruben Van de Velde (Jul 31 2022 at 11:06):

How about from \Z?

Kevin Buzzard (Jul 31 2022 at 11:45):

Then it becomes the statement "evaluation of a polynomial commutes with ring homomorphisms" which presumably is there somewhere...

Filippo A. E. Nuccio (Jul 31 2022 at 12:52):

Is it this result? BTW: How can I paste docs links if there is a subscript? The usual way did not work...

Eric Wieser (Jul 31 2022 at 13:23):

You can't, we need to fix the Zulip linkifiers (if they can be fixed)

Stuart Presnell (Aug 03 2022 at 10:05):

Related to my previous question, do we have this?

example {p α : } (hα0 : 0 < α) (pp : p.prime) (hp_odd : odd p) {x : zmod (p^α)}
  (root : x^2 = 1) :
  x = 1  x = -1 := sorry

Stuart Presnell (Aug 03 2022 at 10:07):

The proof for x : zmod p is more straightforward, because we have [no_zero_divisors (zmod p)]`.

Stuart Presnell (Aug 03 2022 at 10:09):

And I can prove this (without any issues with subtraction)

example {p α x : } (pp : p.prime) (hp_odd : odd p) (root : p^α  x^2 - 1) :
  (p^α  x - 1)  (p^α  x + 1) := sorry

but I can't see how to use this to get a proof of the above.

Eric Wieser (Aug 03 2022 at 10:10):

No need for hα0 : 0 < α, it's true for α = 0

Kevin Buzzard (Aug 03 2022 at 10:18):

Why not x : int instead of x : nat for the intermediate result?

Kevin Buzzard (Aug 03 2022 at 10:18):

Then the result would be easier to use.

Stuart Presnell (Aug 03 2022 at 10:24):

I've started an attempt on that, but I've run into difficulties proving it and other difficulties in using it for the zmod (p^α) result — I get tangled up in coercions.

Stuart Presnell (Aug 03 2022 at 10:28):

The outline of the proof for x : nat is:

example {p α x : } (pp : p.prime) (hp_odd : odd p) (root : p^α  x^2 - 1) :
  (p^α  x - 1)  (p^α  x + 1) :=
begin
  have h1 : p^α  (x + 1) * (x - 1), { rw nat.sq_sub_sq, simpa },
  have h2 : ¬ p  (x + 1)  ¬ p  (x - 1), { sorry },  -- because if p divides both then p ∣ 2
  cases h2 with h_plus h_minus,
  { left, sorry },
  { right, sorry },
end

where the last two sorrys are taken care of with docs#prime.pow_dvd_of_dvd_mul_left and docs#prime.pow_dvd_of_dvd_mul_right.

Stuart Presnell (Aug 03 2022 at 10:29):

But I can't see how to write the counterpart of ¬ p ∣ (x + 1) and ¬ p ∣ (x - 1) in the zmod (p^α) case.

Notification Bot (Aug 03 2022 at 18:45):

Stuart Presnell has marked this topic as unresolved.

Stuart Presnell (Aug 03 2022 at 18:46):

Sorry, I didn't check back into the thread after I marked it as resolved. Thanks @Kevin Buzzard for writing up a solution!

Stuart Presnell (Aug 03 2022 at 18:51):

Here's the version I figured out:

import data.nat.parity
import data.zmod.algebra
import ring_theory.int.basic

open nat zmod

/-- If an odd prime power `p^α` divides `x^2 - 1` then it divides `x-1` or `x+1`. -/
lemma square_roots_of_one_int {p α : } {x : } (pp : p.prime) (hp_odd : odd p)
  (root : p^α  x^2 - 1) :
  (p^α  x - 1)  (p^α  x + 1) :=
begin
  have pp' := prime_iff_prime_int.1 pp,
  have diffsquare : (p^α)  (x-1) * (x+1), { ring_nf, simp [root] },
  have h2 : ¬ p  (x + 1)  ¬ p  (x - 1),
  { rw not_and_distrib,
    rintro hp1, hp2⟩,
    have h3 : p  (x+1) - (x-1), { exact dvd_sub hp1 hp2 },
    have h4 : (x+1) - (x-1) = 2, { ring },
    rw h4 at h3,
    rw (show (2:) = 2*1^2, by linarith) at h3,
    have := prime_two_or_dvd_of_dvd_two_mul_pow_self_two pp h3,
    simp [pp.ne_one] at this,
    rw [this, odd_iff_not_even] at hp_odd,
    exact hp_odd even_two },
  cases h2 with h_plus h_minus,
  { left, apply prime.pow_dvd_of_dvd_mul_left pp' α h_plus, simpa [mul_comm] using diffsquare },
  { right, apply prime.pow_dvd_of_dvd_mul_right pp' α h_minus, simpa [mul_comm] using diffsquare },
end

/-- If `x : zmod (p^α)` (for odd prime `p`) satisfies `x^2 = 1` then `x = 1 ∨ x = -1` -/
lemma square_roots_of_one_zmod {p α : } (pp : p.prime) (hp_odd : odd p) {x : zmod (p^α)}
  (root : x^2 = 1) :
  x = 1  x = -1 :=
begin
  refine or.imp (λ h, _) (λ h, _) (@square_roots_of_one_int p α x pp hp_odd _ ),
  { have := int_coe_eq_int_coe_iff_dvd_sub 1 (x) (p^α),
    simp at this,
    rwa [eq_comm, this] },
  { have := int_coe_eq_int_coe_iff_dvd_sub (-1) (x) (p^α),
    simp at this,
    rwa [eq_comm, this] },
  { have := int_coe_eq_int_coe_iff_dvd_sub 1 (x^2) (p^α),
    simp at this,
    rw [this, root] },
end

Stuart Presnell (Aug 03 2022 at 19:00):

Of course I was cheating in the latter proof by leaving the simps unsqueezed. Here's a better version with tem changed to {norm,push}_cast

import data.nat.parity
import data.zmod.algebra
import ring_theory.int.basic

open nat zmod

/-- If `x : zmod (p^α)` (for odd prime `p`) satisfies `x^2 = 1` then `x = 1 ∨ x = -1` -/
lemma square_roots_of_one_zmod {p α : } (pp : p.prime) (hp_odd : odd p) {x : zmod (p^α)}
  (root : x^2 = 1) :
  x = 1  x = -1 :=
begin
  refine or.imp (λ h, _) (λ h, _) (@square_roots_of_one_int p α x pp hp_odd _ ),
  { have := int_coe_eq_int_coe_iff_dvd_sub 1 (x) (p^α),
    norm_cast at this,
    rwa [eq_comm, this, nat.cast_pow] },
  { have := int_coe_eq_int_coe_iff_dvd_sub (-1) (x) (p^α),
    push_cast at this,
    rw [eq_comm, this],
    simpa using h },
  { have := int_coe_eq_int_coe_iff_dvd_sub 1 (x^2) (p^α),
    push_cast at this,
    rw [this, root] },
end

Last updated: Dec 20 2023 at 11:08 UTC