Zulip Chat Archive

Stream: Is there code for X?

Topic: X^d - 1 | X^(nd) - 1


Gareth Ma (Jan 21 2023 at 18:13):

Hi, is there any existing code on the formula a^d - 1 | a^(nd) - 1 over the integers? Or if it is somehow easier, the formula X^d - 1 | X^(nd) - 1, where d and n are integers?
If not, can someone point me to how I should express the polynomial P = sum(X^(id), 0 <= i < n), as well as how I will expand P * (X^d - 1)? All the work seems quite trivial on paper, but I have not dealt with variable-number sums in Lean before, and shifting indices / cancellations sounds quite annoying.

Gareth Ma (Jan 21 2023 at 18:19):

I think another easier way is to prove X - 1 | X^n - 1, then substitute X <- X^d? But if someone can guide me on that it will be great :pleading_face:

Gareth Ma (Jan 21 2023 at 18:25):

Nevermind, I found https://leanprover-community.github.io/mathlib_docs/algebra/geom_sum.html#geom%E2%82%82_sum

Kevin Buzzard (Jan 21 2023 at 18:34):

import tactic
import algebra.geom_sum

open_locale big_operators -- so I can use ∑

open finset -- so I don't have to write `finset.range`

example (a b : ) (n d : ) : a ^ d - 1   a ^ (n * d) - 1 :=
begin
  use  i in range n, (a ^ d) ^ i,
  rw [mul_comm (a ^ d - 1), geom_sum_mul],
  ring_exp,
end

Junyan Xu (Jan 21 2023 at 19:32):

I think another easier way is to prove X - 1 | X^n - 1, then substitute X <- X^d? But if someone can guide me on that it will be great :plea

It seems we don't have polynomial.comp_dvd_comp but we do have docs#polynomial.mul_comp

Gareth Ma (Jan 21 2023 at 19:48):

That path seems quite complicated, and the geom_sum is working fine

Gareth Ma (Jan 21 2023 at 19:56):

However, I am struggling with some issue. Essentially I am trying to prove the a ^ d - 1 | a ^ (n * d) - 1 for mersenne numbers, i.e. mersenne d | mersenne (n * d). However, mersenne returns a ℕ, while the geom_sum returns a ℤ. Is there any way to convert them easily?
Here is my extremely messy code, I can prove that the divisibility holds over the integers, but the natural numbers are not a ring and so subtraction causes many problems as always.

-- I forgot how to name this
theorem int_dvd_imp_nat_dvd {m n : } :
int.of_nat m  int.of_nat n  m  n :=
begin
  rintros d, hd⟩,
  use int.to_nat d,
  sorry -- given n ≥ 0, m ≥ 0, n = d * m over ℤ, prove n = d * m over ℕ
end

theorem pow_div {m n : } (a : ) (h : m  n) : (a ^ m - 1)  (a ^ n - 1) :=
begin
  let d :  := n / m,
  use  i in range d, (a ^ m) ^ i,
  rw [mul_comm (a ^ m - 1), geom_sum_mul],
  rw [ pow_mul', (nat.dvd_iff_div_mul_eq n m).1 h],
end

-- Type coercion hell
theorem mersenne_div {m n : } (h : m  n) : mersenne m  mersenne n :=
begin
  cases pow_div 2 h with d hd,
  unfold mersenne,
  apply int_dvd_imp_nat_dvd,
  use d,
  -- ?????
end

Do you mind helping as well

Kevin Buzzard (Jan 21 2023 at 20:29):

theorem int_dvd_imp_nat_dvd {m n : } : (m : )  (n : )  m  n :=
begin
  intro h,
  exact_mod_cast h,
end

It used to be a total pain moving between nat and int and rat, but the cast tactics (norm_cast, push_cast, exact_mod_cast) etc can do it as long as you use the so-called "simp normal form" for casts, which is to use coercions (the little up-arrow) rather than the names of the functions they represent (for example int.of_nat).

Kevin Buzzard (Jan 21 2023 at 20:33):

example (n : ) : int.of_nat n = (n : ) := rfl

They're equal by definition, but many tactics (like simp, rw and the cast tactics) work up to syntactic equality, not just definitional equality. If we had X lemmas about ↑n and we wanted them to also apply to int.of_nat n then because these tactics work up to syntactic equality we'd have to have X more lemmas about int.of_nat n. The trick is to try and keep your code always in the "canonical" form which the library designers have chosen for each mathematical idea, and the canonical map from nat to int is ↑n, sometimes expressed (n : ℤ), rather than int.of_nat.

Kevin Buzzard (Jan 21 2023 at 20:37):

-- I forgot how to name this, so let's see what Lean calls it
theorem int_dvd_imp_nat_dvd {m n : } : (m : )  n  m  n :=
begin
  library_search, -- exact int.coe_nat_dvd.mp
end

The bi-implication is called int.coe_nat_dvd and probably we don't have a name for the one-sided implication (we just rewrite with the bi-implication).

Alternatively

-- I forgot how to name this, so let's see what Lean calls it
theorem int_dvd_imp_nat_dvd {m n : } : (m : )  n  m  n :=
begin
  intro h,
  show_term {exact_mod_cast h}, -- see the proof that the tactic generated
end

you can see how the cast tactic proves it and learn the name from that.

Kevin Buzzard (Jan 21 2023 at 20:38):

I can't answer your last question because your code isn't a #mwe so I can't see the exact definition of mersenne. Click on the #mwe link to learn about how to write a good question.

Gareth Ma (Jan 21 2023 at 20:39):

Thank you so much! Somehow my library_search couldn't find that case, maybe my original formulation was too weird/messy for it to find the correct clause - show_term will help me a lot too haha. Also, mersenne is from number_theory.lucas_lehmer, which is just 2^n - 1 over ℕ

def mersenne (p : ) :  := 2^p - 1

Kevin Buzzard (Jan 21 2023 at 20:45):

theorem mersenne_div {m n : } (h : m  n) : 2 ^ m - 1  2 ^ n - 1 :=
begin
  rw  int.coe_nat_dvd, -- annoying because you're not really supposed to need to know the names of these lemmas
  convert pow_div 2 h;
  { rw nat.cast_sub,
    { norm_cast, },
    exact nat.one_le_pow' _ 1, }, -- thanks `library_search`
end

Kevin Buzzard (Jan 21 2023 at 20:47):

After convert there are two very similar goals. The semicolon means "apply the following tactic to both of them", and the { } means "treat all these tactics as one tactic".

Yaël Dillies (Jan 21 2023 at 22:36):

Kevin Buzzard said:

The bi-implication is called int.coe_nat_dvd and probably we don't have a name for the one-sided implication (we just rewrite with the bi-implication).

In fact, we do: docs#has_dvd.dvd.nat_cast

Niels Voss (Jan 22 2023 at 03:16):

I got the proof down to two lines

import tactic
import algebra.geom_sum

theorem mersenne_div {m n : } (h : m  n) : 2 ^ m - 1  2 ^ n - 1 :=
begin
  rcases h with k, rfl⟩,
  simpa only [pow_mul, one_pow] using nat_sub_dvd_pow_sub_pow _ 1 _,
end

I actually had the exact same problem when writing my pseudoprimes PR so I actually wrote nat_sub_dvd_pow_sub_pow a month or so ago for this specific purpose.

Niels Voss (Jan 22 2023 at 03:20):

Here is the link to the thread where I originally discussed this: https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/divisibilty.20of.20powers


Last updated: Dec 20 2023 at 11:08 UTC