Zulip Chat Archive

Stream: general

Topic: Recommended way to create Finsets over ZMod


Adam Kurkiewicz (Nov 25 2024 at 10:19):

I'd like to work with Finsets with elements in ZMod p. But I'm struggling to create them in the first place.

For example, the first two statements typecheck, but the third one doesn't due to lack of Preorder (which is fair).

Is there some clever syntax like python's list comprehension or something similar that would first allow me to create a Finset in Nat and then lift it to ZMod?

import Mathlib.Tactic

#check (Finset.Icc (1 : ) 4)

#eval (Finset.Icc (1 : ) 4).prod (λ x => (x : (ZMod 5)))

#check (Finset.Icc (1 : (ZMod 5)) (4 : (ZMod 5)))

Ruben Van de Velde (Nov 25 2024 at 10:21):

#eval Finset.Icc 1 3 |>.image ((↑) : ℕ → ZMod 5) -- {1, 2, 3}

Adam Kurkiewicz (Nov 25 2024 at 10:29):

Perfect, image is the function I've been searching for. Thank you Ruben!

Adam Kurkiewicz (Nov 25 2024 at 15:09):

And how can I prove the following? Neither norm_num nor reduce_mod_char make any progress:

import Mathlib.Tactic

lemma ZMod_cast_sub (a : ) (p : ) (a_lt_p : a < p) (pprime: p.Prime) : - @Nat.cast (ZMod p) Semiring.toNatCast (p - a) = a := by
  norm_num
  reduce_mod_char
  sorry

Kevin Buzzard (Nov 25 2024 at 15:20):

My first thought is: how did you get into that mess in the first place?

Adam Kurkiewicz (Nov 25 2024 at 15:21):

lemma upper_half_factorial_is_lower_half_factorial (p : ) (pprime: p.Prime) (p_mod_4 : ((p : (ZMod 4)) = 1)):
  (Finset.Icc 1 ((p - 1)/2)).image (λ (x : ) => (x : (ZMod p)))
      = (Finset.Icc ((p + 1)/2) (p - 1)).image (λ (x : ) => (-x : (ZMod p))) := by
  have term_equality :  k, (((p - k) : ZMod p) * (2⁻¹ : ZMod p)) = -((p + k : ZMod p) * (2⁻¹ : ZMod p)) := by
      norm_num
  ext x
  constructor
  intro left
  simp_all only [CharP.cast_eq_zero, zero_sub, neg_mul, zero_add, implies_true, Finset.mem_image, Finset.mem_Icc]
  obtain a, H1, H2⟩⟩ := left
  use (p - a)
  constructor
  omega
  rw [ H2]
  have : (a < p) := by sorry
  sorry
  intro left
  simp_all
  obtain a, ⟨⟨H1, H2, H3⟩⟩ := left
  use (p - a)
  constructor
  constructor
  sorry
  sorry
  have := ZMod_cast_sub

  sorry

Adam Kurkiewicz (Nov 25 2024 at 15:22):

I know that a < p is not always true, but I can always pick a k large enough that a < k * p

Adam Kurkiewicz (Nov 25 2024 at 15:23):

I think it's a common trick in elementary number theory, to use the fact that (p - 1)/2 factorial squared is equal to -1 mod p when p - 1 is divisible by 4.

Adam Kurkiewicz (Nov 25 2024 at 15:27):

I need it specifically for IMO 2008 N6 shortlist problem, which gives a weak bound on largest prime divisors of $n^2 + 1$:

https://www.imo-official.org/problems/IMO2008SL.pdf

Daniel Weber (Nov 25 2024 at 15:41):

You can use docs#Nat.cast_sub

import Mathlib.Tactic

lemma ZMod_cast_sub (a : ) (p : ) (a_lt_p : a < p) : - @Nat.cast (ZMod p) Semiring.toNatCast (p - a) = a := by
  simp [Nat.cast_sub a_lt_p.le]

Adam Kurkiewicz (Nov 25 2024 at 15:53):

Fantastic, thank you Daniel!


Last updated: May 02 2025 at 03:31 UTC