Zulip Chat Archive

Stream: new members

Topic: New to Lean and MATHLIB4


Jason Mahaffey (Feb 27 2026 at 16:51):

There is much to absorb in the community. I am a hobby math enthusiast (M.S. Math) and would like to contribute to the effort. The new AI is making coding in Lean much more accessible for people like me. I have a fully compiled (no sorry, no axiom, just a definition for the recurring coefficient) version of the Waring formula for A^n+B^n=... but I don't want to contribute to the A.I. slop "crises". I used the Mathlib4 library search tool and did not see the theorem. Would this be a valuable contribution and if so, what group would be a good contact before submitting a PR?

Jason Mahaffey (Feb 27 2026 at 16:51):

Code snippet:**-- The Waring formula with division (in a Field) -/
theorem waring_formula {R : Type*} [Field R] [CharZero R] (A B : R) (p : ℕ) (hp : 0 < p) :
    A^p + B^p = (A + B)^p + ∑ j ∈ Finset.Icc 1 (p / 2),
      (-1 : R)^j * ((p : R) * (Nat.choose (p - j - 1) (j - 1) +
      Nat.choose (p - j - 1) j) / (p - j : R)) * (A + B)^(p - 2 * j) * (A * B)^j**

Matt Diamond (Feb 27 2026 at 17:30):

welcome! please use #backticks when posting code (and also read #mwe)

Jason Mahaffey (Feb 27 2026 at 20:22):

Sorry for that. here is the mwe and I have updated the format of the formula to make it more useable.

PastedText.txt

Jason Mahaffey (Feb 27 2026 at 21:09):

I did include extra Chebyshev lemmas in there by mistake.

Julian Berman (Feb 27 2026 at 23:14):

Can you have another look at that #backticks link, the point is if you do it, then it makes it a lot easier for us to read what you wrote because it immediately becomes accessible in the Live Playground. Watch:

example : 37 = 37 := by
  rfl

Click the link that appears when you hover over the top right of the text box just above. We want to see that for your code :).

Jason Mahaffey (Feb 28 2026 at 00:30):

Having trouble getting the code to fit within the limit.

Jason Mahaffey (Feb 28 2026 at 00:52):

import Mathlib
variable {R : Type*} [CommRing R]
def waringCoeff' (n j : ) :  :=
  if j = 0 then 1
  else if n < 2 * j then 0
  else Nat.choose (n - j) j + Nat.choose (n - 1 - j) (j - 1)
-- end of waringCoeff' definition
def waringSum' (n : ) (S P : R) : R :=
  if n = 0 then 2 else
   j  Finset.range (n / 2 + 1),
    (-1 : R)^j * (waringCoeff' n j : R) * S^(n - 2 * j) * P^j
-- end
lemma waringCoeff'_succ_add (n j : ) (hn : 1  n) (hj : 1  j) :
    waringCoeff' (n + 2) j = waringCoeff' (n + 1) j + waringCoeff' n (j - 1) := by
  by_cases hj1 : j = 1
  · subst hj1
    have hw0 : waringCoeff' n (1 - 1) = 1 := rfl
    rw [hw0]
    unfold waringCoeff'
    have h_ne : 1  0 := by decide
    have h1 : ¬(n + 2 < 2 * 1) := by omega
    have h2 : ¬(n + 1 < 2 * 1) := by omega
    simp only [h_ne, h1, h2, reduceIte]
    have h_sub : 1 - 1 = 0 := rfl
    rw [h_sub]
    simp only [Nat.choose_one_right, Nat.choose_zero_right]
    omega
  · obtain k, rfl :  k, j = k + 2 := j - 2, by omega
    have hk1 : k + 2 - 1 = k + 1 := by omega
    rw [hk1]
    unfold waringCoeff'
    have hj0 : k + 2  0 := by omega
    have hj1_ne : k + 1  0 := by omega
    simp only [hj0, hj1_ne, reduceIte]
    have eq_cond : n + 2 < 2 * (k + 2)  n < 2 * (k + 1) := by omega
    by_cases c1 : n + 2 < 2 * (k + 2)
    · have c2 : n + 1 < 2 * (k + 2) := by omega
      have c3 : n < 2 * (k + 1) := eq_cond.mp c1
      simp only [c1, c2, c3, reduceIte]
    · have c1_not : ¬(n + 2 < 2 * (k + 2)) := c1
      have c3_not : ¬(n < 2 * (k + 1)) := eq_cond.not.mp c1_not
      by_cases c2 : n + 1 < 2 * (k + 2)
      · simp only [c1_not, c2, c3_not, reduceIte, zero_add]
        have eq : n = 2 * k + 2 := by omega
        rw [eq]
        have e1 : 2 * k + 2 + 2 - (k + 2) = k + 2 := by omega
        have e2 : 2 * k + 2 + 2 - 1 - (k + 2) = k + 1 := by omega
        have e3 : 2 * k + 2 - (k + 1) = k + 1 := by omega
        have e4 : 2 * k + 2 - 1 - (k + 1) = k := by omega
        have e5 : k + 2 - 1 = k + 1 := by omega
        have e6 : k + 1 - 1 = k := by omega
        rw [e1, e2, e3, e4, e5, e6]
        simp only [Nat.choose_self]
      · have c2_not : ¬(n + 1 < 2 * (k + 2)) := c2
        simp only [c1_not, c2_not, c3_not, reduceIte]
        rw [show n + 2 - (k + 2) = n - k by omega]
        rw [show n + 2 - 1 - (k + 2) = n - k - 1 by omega]
        rw [show n + 1 - (k + 2) = n - k - 1 by omega]
        rw [show n + 1 - 1 - (k + 2) = n - k - 2 by omega]
        rw [show n - (k + 1) = n - k - 1 by omega]
        rw [show n - 1 - (k + 1) = n - k - 2 by omega]
        have e_right1 : k + 2 - 1 = k + 1 := by omega
        have e_right2 : k + 1 - 1 = k := by omega
        rw [e_right1, e_right2]
        have H1 : Nat.choose (n - k) (k + 2) = Nat.choose (n - k - 1)
         (k + 1) + Nat.choose (n - k - 1) (k + 2) := by
          have h := Nat.choose_succ_succ (n - k - 1) (k + 1)
          have e1 : (n - k - 1).succ = n - k := by omega
          have e2 : (k + 1).succ = k + 2 := by omega
          rw [e1, e2] at h
          exact h
        have H2 : Nat.choose (n - k - 1) (k + 1) = Nat.choose (n - k - 2)
         k + Nat.choose (n - k - 2) (k + 1) := by
          have h := Nat.choose_succ_succ (n - k - 2) k
          have e1 : (n - k - 2).succ = n - k - 1 := by omega
          have e2 : k.succ = k + 1 := by omega
          rw [e1, e2] at h
          exact h
        rw [H1, H2]
        omega
--end
lemma waringSum'_eq_sum_range (n : ) (S P : R) :
    waringSum' n S P = if n = 0 then 2 else  j  Finset.range (n + 2), (-1 : R)^j *
    (waringCoeff' n j : R) * S^(n - 2 * j) * P^j := by
  unfold waringSum'
  split_ifs with h
  · rfl
  · apply Finset.sum_subset
    · intro j hj; rw [Finset.mem_range] at hj ⊢; omega
    · intro j hj hj'
      rw [Finset.mem_range] at hj hj'
      have hj0 : j  0 := by omega
      have hn2j : n < 2 * j := by omega
      simp [waringCoeff', hj0, hn2j]
-- end
lemma waringSum'_rec_eq (n : ) (hn : 1  n) (S P : R) :
    waringSum' (n + 2) S P = S * waringSum' (n + 1) S P - P * waringSum' n S P := by
  have hn0 : (n = 0)  False := iff_false_intro (by omega)
  have hn1 : (n + 1 = 0)  False := iff_false_intro (by omega)
  have hn2 : (n + 2 = 0)  False := iff_false_intro (by omega)
  rw [waringSum'_eq_sum_range (n + 2), waringSum'_eq_sum_range (n + 1), waringSum'_eq_sum_range n]
  simp only [hn0, hn1, hn2, ite_false]
  rw [Finset.mul_sum, Finset.mul_sum]
  have sum_P_shift :  j  Finset.range (n + 3), (if j = 0 then (0 : R) else -
   ((-1 : R) ^ j * (waringCoeff' n (j - 1) : R) * S ^ (n + 2 - 2 * j) * P ^ j)) =
       j  Finset.range (n + 2), P * ((-1 : R) ^ j * (waringCoeff' n j : R) *
       S ^ (n - 2 * j) * P ^ j) := by
    have h_split := Finset.sum_range_succ' (fun j => if j = 0 then (0 : R)
     else - ((-1 : R) ^ j * (waringCoeff' n (j - 1) : R) * S ^ (n + 2 - 2 * j) * P ^ j)) (n + 2)
    rw [h_split]
    have eq0 : (0 = 0)  True := iff_true_intro rfl
    simp only [ite_true, add_zero]
    apply Finset.sum_congr rfl
    intro j _
    have hj0 : j + 1  0 := by omega
    have hj0_iff : (j + 1 = 0)  False := iff_false_intro hj0
    simp only [hj0_iff, ite_false, Nat.add_sub_cancel_right]
    have hS : n + 2 - 2 * (j + 1) = n - 2 * j := by omega
    rw [hS]
    ring
  have lhs_eq :  j  Finset.range (n + 4), (-1 : R) ^ j *
   (waringCoeff' (n + 2) j : R) * S ^ (n + 2 - 2 * j) * P ^ j =
       j  Finset.range (n + 3), (-1 : R) ^ j * (waringCoeff' (n + 2) j : R)
       * S ^ (n + 2 - 2 * j) * P ^ j := by
    have h_split := Finset.sum_range_succ (fun j => (-1 : R) ^ j * (waringCoeff' (n + 2) j : R)
     * S ^ (n + 2 - 2 * j) * P ^ j) (n + 3)
    rw [h_split]
    have hz : waringCoeff' (n + 2) (n + 3) = 0 := by
      unfold waringCoeff'
      have h1 : (n + 3 = 0)  False := iff_false_intro (by omega)
      have h2 : (n + 2 < 2 * (n + 3))  True := iff_true_intro (by omega)
      simp only [h1, h2, ite_false, ite_true]
    rw [hz]
    simp only [Nat.cast_zero, mul_zero, zero_mul, add_zero]
  rw [ sum_P_shift, lhs_eq,  Finset.sum_sub_distrib]
  apply Finset.sum_congr rfl
  intro j _
  rcases j with _ | j
  · have eq0 : (0 = 0)  True := iff_true_intro rfl
    simp only [ ite_true, sub_zero, pow_zero, mul_one]
    have c1 : waringCoeff' (n + 2) 0 = 1 := rfl
    have c2 : waringCoeff' (n + 1) 0 = 1 := rfl
    simp only [c1, c2, Nat.cast_one, one_mul]
    have e1 : n + 2 - 2 * 0 = n + 2 := rfl
    have e2 : n + 1 - 2 * 0 = n + 1 := rfl
    rw [e1, e2]
    ring
  · have hsucc : (j + 1 = 0)  False := iff_false_intro (by omega)
    simp only [hsucc, ite_false, sub_neg_eq_add]
    rw [waringCoeff'_succ_add n (j + 1) hn (by omega)]
    push_cast
    by_cases h_bounds : n + 1 < 2 * (j + 1)
    · have z1 : waringCoeff' (n + 1) (j + 1) = 0 := by
        unfold waringCoeff'
        have h_bounds_true : (n + 1 < 2 * (j + 1))  True := iff_true_intro h_bounds
        simp only [hsucc, h_bounds_true, ite_false, ite_true]
      rw [z1]
      ring
    · have h_pow : n + 2 - 2 * (j + 1) = n + 1 - 2 * (j + 1) + 1 := by omega
      have hS : S ^ (n + 2 - 2 * (j + 1)) = S ^ (n + 1 - 2 * (j + 1))
       * S := by rw [h_pow, pow_add, pow_one]
      rw [hS]
      ring
-- end
theorem waring_formula_div_free (A B : R) (n : ) :
    A^n + B^n = waringSum' n (A + B) (A * B) := by
  induction n using Nat.strongRecOn with
  | ind n ih =>
    rcases n with _ | _ | _ | n
    · simp [waringSum']; norm_num        -- ← add norm_num here
    · simp [waringSum', waringCoeff']
    · rw [waringSum']
      simp [waringCoeff', Finset.sum_range_succ]
      ring
    · have hrec : A ^ (n + 3) + B ^ (n + 3) =
          (A + B) * (A ^ (n + 2) + B ^ (n + 2)) - A * B * (A ^ (n + 1) + B ^ (n + 1)) := by ring
      rw [hrec, ih (n + 2) (by omega), ih (n + 1) (by omega)]
      exact (waringSum'_rec_eq (n + 1) (by omega) (A + B) (A * B)).symm
-- end
lemma waringCoeff_single_eq (n j : ) (hn : n  0) (hj : j  n / 2) :
    (if j = 0 then 1 else Nat.choose (n - j) j + Nat.choose (n - 1 - j) (j - 1)) =
    n * Nat.choose (n - j) j / (n - j) := by
  split_ifs with h
  · simp only [h, Nat.sub_zero, Nat.choose_zero_right, mul_one]
    exact (Nat.div_self (by omega)).symm
  · have h_nj_pos : 0 < n - j := by omega
    symm
    apply Nat.div_eq_of_eq_mul_right h_nj_pos
    have h1 : n - 1 - j + 1 = n - j := by omega
    have h2 : j - 1 + 1 = j := by omega
    have H := Nat.add_one_mul_choose_eq (n - 1 - j) (j - 1)
    rw [h1, h2] at H
    have hn_eq : n = n - j + j := (Nat.sub_add_cancel (by omega)).symm
    have expand_lhs : n * Nat.choose (n - j) j =
        (n - j) * Nat.choose (n - j) j + j * Nat.choose (n - j) j := by
      conv_lhs => rw [hn_eq]
      simp only [Nat.add_sub_cancel]
      ring
    have expand_rhs : (Nat.choose (n - j) j + Nat.choose (n - 1 - j) (j - 1)) * (n - j) =
        (n - j) * Nat.choose (n - j) j + (n - j) * Nat.choose (n - 1 - j) (j - 1) := by
      ring
    linarith [H]
-- end
theorem waring_formula_div_free_sum_single (A B : R) {n : } (hn : n  0) :
    A^n + B^n =  j  Finset.range (n / 2 + 1),
      (-1 : R)^j * (((n * Nat.choose (n - j) j / (n - j)) : ) : R)
       * (A + B)^(n - 2 * j) * (A * B)^j := by
  rw [waring_formula_div_free A B n, waringSum', if_neg hn]
  apply Finset.sum_congr rfl
  intro j hj
  rw [waringCoeff']
  have hj_bound : j  n / 2 := by
    rw [Finset.mem_range] at hj; omega
  have h_not_lt : ¬(n < 2 * j) := by omega
  have h_simplify : (if j = 0 then 1 else if n < 2 * j then 0 else
   Nat.choose (n - j) j + Nat.choose (n - 1 - j) (j - 1)) =
                    (if j = 0 then 1 else Nat.choose (n - j) j
                     + Nat.choose (n - 1 - j) (j - 1)) := by
    split_ifs with hj0
    · rfl
    · simp
  rw [h_simplify, waringCoeff_single_eq n j hn hj_bound]
-- end

Weiyi Wang (Feb 28 2026 at 01:43):

I am not a mathlib maintainer, but given that there is a Mathworld entry for it, and the proof doesn't seem terribly long or niche, I think the theorem is something mathlib can have. As for the proof, if it was generated by AI, it usually needs to be massively polished before it meets mathlib code standard

Weiyi Wang (Feb 28 2026 at 01:44):

I also noticed there is a n-variable generalization https://planetmath.org/waringsformula. Mathlib usually wants the most general form (as long as it is reasonable)

Filippo A. E. Nuccio (Feb 28 2026 at 05:45):

Unfortunately I'm inclined to say that code in that style is really far from Mathlib. @Jason Mahaffey we've witnessed a lot of cases of this kind of efforts recently and almost none of them made it to the library. But don't get me wrong: I don't want to discourage you nor to question your good faith. Consider simply that getting something in Mathlib requires a lot of efforts from authors and if you've got limited Lean experience this will mean spending a significant amount of time learning the basics. If you're ready to embark in the adventure, great! Let's try to open a PR, first and foremost trying to reduce your imports (no file in Mathlib can import the whole of it!). Before doing so, though, I would suggest that you pick a theorem whose proof (on paper) you know and is in Mathlib : try to read Mathlib 's proof. Once you'll understand all details you might be ready to write your first one.


Last updated: Feb 28 2026 at 14:05 UTC