Zulip Chat Archive

Stream: mathlib4

Topic: How to lemma polynomial equality


Andrew Z (Nov 11 2025 at 16:42):

Hi, I have a newbie question about solving goal for univariate polynomials that I know are equivalent:

the unsolved goal is: Polynomial.C 13 * Polynomial.X = Polynomial.X * Polynomial.C 5 * 2 + Polynomial.X * Polynomial.C 3

the coeff_val lemma passes

import Mathlib.Algebra.Polynomial.Basic
import Mathlib.Algebra.Polynomial.Eval.Defs
import Mathlib.Algebra.MvPolynomial.SchwartzZippel
import Mathlib.Tactic.NormNum
import Mathlib.Tactic.Ring
import Mathlib.Data.ZMod.Basic
import Mathlib.Tactic

@[simp]
noncomputable def test_p : MvPolynomial (Fin 2) (ZMod 19) := 3 * MvPolynomial.X 0 * MvPolynomial.X 1 + 5 * MvPolynomial.X 0 + 1

@[simp]
noncomputable def point_00 : (ZMod 19) := MvPolynomial.eval ![0, 0] test_p
lemma point_00_val : point_00 = (1 : ZMod 19) := by
  simp [point_00, test_p]

@[simp]
noncomputable def point_01 : (ZMod 19) := MvPolynomial.eval ![1, 0] test_p
lemma point_01_val : point_01 = (6 : ZMod 19) := by
  simp [point_00, test_p]
  ring_nf

@[simp]
noncomputable def point_10 : (ZMod 19) := MvPolynomial.eval ![0, 1] test_p
lemma point_10_val : point_10 = (1 : ZMod 19) := by
  simp [point_10, test_p]

@[simp]
noncomputable def point_11 : (ZMod 19) := MvPolynomial.eval ![1, 1] test_p
lemma point_11_val : point_11 = (9 : ZMod 19) := by
  simp [point_11, test_p]
  ring_nf

@[simp]
noncomputable def sum_0 : (ZMod 19) := point_00 + point_10
lemma sum_0_val : sum_0 = (2 : ZMod 19) := by
  simp [point_11, test_p]
  ring_nf

@[simp]
noncomputable def sum_1 : (ZMod 19) := point_01 + point_11
lemma sum_1_val : sum_1 = (15 : ZMod 19) := by
  simp [point_11, test_p]
  ring_nf


@[simp]
noncomputable def coeff : (ZMod 19) := sum_1 - sum_0
lemma coeff_val : coeff = (13 : ZMod 19) := by
  simp [coeff, test_p]
  ring_nf


noncomputable def expected_g_0 : Polynomial (ZMod 19) :=  Polynomial.C 13 *  Polynomial.X +  Polynomial.C sum_0
noncomputable def computed_g_0 : Polynomial (ZMod 19) := Polynomial.C coeff * Polynomial.X + Polynomial.C sum_0

lemma equal_value : expected_g_0 = computed_g_0 := by
  unfold computed_g_0 expected_g_0
  simp [coeff]
  ring_nf

  -- simp [test_p, List.range, List.foldl, List.flatMap, List.map, List.range.loop, coeff]
  -- ring_nf
  -- rfl

Appreciate the support. Thanks.

Ruben Van de Velde (Nov 11 2025 at 16:49):

First error:

Function expected at
  ZMod
but this term has type
  ?m.1

Note: Expected a function because this term is being applied to the argument
  19

Please update your code with the relevant imports and anything else needed to make it a #mwe (click the link)

Andrew Z (Nov 11 2025 at 16:57):

I updated with the whole file. Thanks

František Silváši 🦉 (Nov 11 2025 at 17:35):

Here's a step by step proof; there's about half a million ways to make this shorter of course :).

open Polynomial in
lemma equal_value : expected_g_0 = computed_g_0 := by
  unfold computed_g_0 expected_g_0
  simp [_root_.coeff]
  ring_nf
  symm
  calc X * C (5 : ZMod 19) * 2 + X * C 3
    _ = X * (C 5 * 2) + X * C 3 := by rw [mul_assoc]
    _ = X * (C 5 * 2 + C 3)     := by rw [mul_add]
    _ = X * (C 5 * C 2 + C 3)   := by rfl
    _ = X * (C (5 * 2) + C 3)   := by rw [C_mul]
    _ = X * (C (5 * 2 + 3))     := by rw [C_add]
    _ = X * (C 13)              := rfl
    _ = C 13 * X                := by rw [mul_comm]

Andrew Z (Nov 11 2025 at 17:41):

Thank you @František Silváši 🦉 :smiley:

Andrew Z (Nov 11 2025 at 21:51):

I’m not sure if it’s reasonable to manually do this each time

Andrew Z (Nov 11 2025 at 21:52):

I thought ring_nf would accomplish this. Does anyone know of a tactic or way to do this without completing the proof manually?

Kim Morrison (Nov 12 2025 at 02:54):

open Polynomial in
lemma equal_value : expected_g_0 = computed_g_0 := by
  unfold computed_g_0 expected_g_0
  simp [_root_.coeff]
  ring_nf
  symm
  calc X * C (5 : ZMod 19) * 2 + X * C 3
    _ = X * (C (5 * 2 + 3))     := by grind [C_ofNat, C_mul, C_add]
    _ = X * (C 13)              := rfl
    _ = C 13 * X                := by grind

also works, although it is terrible and embarrassing that the rfl step is apparently necessary there!

(How to obtain this from @František Silváši 🦉's proof? Work out which lemma the first rfl is using (remember: rfl is a code smell!), then replace each rw [X] with grind or grind [X], then start combining steps.)

Presumably there are a lot of polynomial-related lemmas we need to annotate for @[grind], but I think no one has got there yet.

Damiano Testa (Nov 12 2025 at 08:37):

If you do not want to do a lot of manual labor, you can also prove it like this:

lemma equal_value : expected_g_0 = computed_g_0 := by
  unfold computed_g_0 expected_g_0
  congr
  aesop

Andrew Z (Nov 12 2025 at 09:37):

@Damiano Testa :gold: :muscle: :pray:


Last updated: Dec 20 2025 at 21:32 UTC