Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Combinatorics/Nullstellensatz): formalize Alon's Combinatorial Nullstellensatz #20495

Open
wants to merge 167 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
167 commits
Select commit Hold shift + click to select a range
dd41a2c
initial commit
AntoineChambert-Loir Aug 18, 2024
5839a85
add docstring
AntoineChambert-Loir Aug 18, 2024
4f3169c
progress
AntoineChambert-Loir Aug 19, 2024
e490d4f
small progress
AntoineChambert-Loir Aug 22, 2024
c46fff9
start defining linear order
AntoineChambert-Loir Aug 22, 2024
37feb31
prob. ok pour la multiplication
AntoineChambert-Loir Aug 22, 2024
94f83d0
presque rien
AntoineChambert-Loir Aug 22, 2024
ce26f63
big progress
AntoineChambert-Loir Aug 25, 2024
434d61b
Alon's First Combinatorial Nullstellensatz
AntoineChambert-Loir Aug 26, 2024
b2327b3
full proof of Combinatorial Nullstellensatz
AntoineChambert-Loir Aug 27, 2024
244d91a
fix lint style
AntoineChambert-Loir Aug 27, 2024
74b2d05
make it work for finite types
AntoineChambert-Loir Aug 30, 2024
eaca76d
lint-style
AntoineChambert-Loir Aug 30, 2024
57063ff
try to have euclDivd work recursively
AntoineChambert-Loir Aug 31, 2024
7beb580
lint-style
AntoineChambert-Loir Aug 31, 2024
e79b5ca
initial commit
AntoineChambert-Loir Aug 31, 2024
b9e1875
starting
AntoineChambert-Loir Aug 31, 2024
a8ff2b1
apply zuggestions from Giacomo Stevanato
AntoineChambert-Loir Aug 31, 2024
ef9bb5e
lint-style
AntoineChambert-Loir Aug 31, 2024
e0c6b4f
some progress
AntoineChambert-Loir Aug 31, 2024
a76a105
lint-style
AntoineChambert-Loir Aug 31, 2024
27d6b7d
progress
AntoineChambert-Loir Sep 4, 2024
ac438fd
euclidean division for a monomial order
AntoineChambert-Loir Sep 5, 2024
e9beb33
division algorithm
AntoineChambert-Loir Sep 6, 2024
8f70271
delete #printaxioms
AntoineChambert-Loir Sep 6, 2024
7cfdfce
clean namespace, partially add DegLex
AntoineChambert-Loir Sep 6, 2024
709fa0b
have 4 monomial orders
AntoineChambert-Loir Sep 7, 2024
eeeaa2d
lint-style
AntoineChambert-Loir Sep 7, 2024
14afba4
lint style and update Mathlib.lean
AntoineChambert-Loir Sep 7, 2024
fab4b25
add copyright
AntoineChambert-Loir Sep 7, 2024
ab5bd1c
remove import
AntoineChambert-Loir Sep 7, 2024
fda8779
remove one more trailing space
AntoineChambert-Loir Sep 7, 2024
1832055
add docstring, remove useless simp tags, remove unused
AntoineChambert-Loir Sep 7, 2024
0bd630f
lint-style
AntoineChambert-Loir Sep 8, 2024
cbdda48
Merge branch 'master' into ACL/CombNS
AntoineChambert-Loir Sep 8, 2024
74d5847
use groebner division
AntoineChambert-Loir Sep 8, 2024
0421491
lint-style
AntoineChambert-Loir Sep 9, 2024
6ae0f9c
lint-style
AntoineChambert-Loir Sep 9, 2024
7b66920
update Mathlib.lean
AntoineChambert-Loir Sep 9, 2024
12aaa4a
use more monomial orders
AntoineChambert-Loir Sep 9, 2024
d3183a9
revert WeightedHomogeneous and Homogeneous
AntoineChambert-Loir Sep 9, 2024
bbdfdd9
simplify a little bit using EW's ideas
AntoineChambert-Loir Sep 10, 2024
b83b5d5
split into various files
AntoineChambert-Loir Sep 10, 2024
b8bcb90
update Mathlib.lean
AntoineChambert-Loir Sep 10, 2024
8d6f7d0
Merge branch 'master' into ACL/Groebner
AntoineChambert-Loir Sep 10, 2024
8a353cf
update Mathlib.lean
AntoineChambert-Loir Sep 10, 2024
85743f8
Merge branch 'ACL/Groebner' of https://github.com/leanprover-communit…
AntoineChambert-Loir Sep 10, 2024
888f1ab
update Mathlib.lean
AntoineChambert-Loir Sep 10, 2024
19a9ac4
update Mathlib.lean
AntoineChambert-Loir Sep 10, 2024
648532d
Update Mathlib.lean
AntoineChambert-Loir Sep 10, 2024
5471a1d
adjust Groebner
AntoineChambert-Loir Sep 11, 2024
8a368ce
lint-style - trailing spaces
AntoineChambert-Loir Sep 11, 2024
75ccc3e
add docstring
AntoineChambert-Loir Sep 11, 2024
b9ad12f
add docstring, add indexed division
AntoineChambert-Loir Sep 11, 2024
27dc14e
add docstring
AntoineChambert-Loir Sep 11, 2024
cc1e661
lint-style - remove trailing spaces
AntoineChambert-Loir Sep 11, 2024
fcea481
lint-style - remove trailing spaces
AntoineChambert-Loir Sep 11, 2024
21b605b
adjust name (monomialOrderDiv -> MonomialOrder.div)
AntoineChambert-Loir Sep 11, 2024
261de0d
adjust (nonworking dot notation)
AntoineChambert-Loir Sep 11, 2024
f6adc0b
lake shake
AntoineChambert-Loir Sep 11, 2024
de3af11
lake shake - correct
AntoineChambert-Loir Sep 11, 2024
7fe6c4f
add noshake
AntoineChambert-Loir Sep 11, 2024
bb46d41
remove Dickson
AntoineChambert-Loir Sep 11, 2024
ed60468
merge Groebner
AntoineChambert-Loir Sep 11, 2024
d5d6cb1
adjust
AntoineChambert-Loir Sep 11, 2024
b7f1420
lint-style - trailing spaces
AntoineChambert-Loir Sep 11, 2024
e4fde07
Revert "lint-style - trailing spaces"
AntoineChambert-Loir Sep 11, 2024
ff5e6c1
simplify the proof of Alon2
AntoineChambert-Loir Sep 12, 2024
42e11dd
Update Mathlib/Combinatorics/Nullstellensatz.lean
AntoineChambert-Loir Sep 12, 2024
d1861ea
initial commit
AntoineChambert-Loir Nov 25, 2024
19846a5
initial commit
AntoineChambert-Loir Nov 25, 2024
7510d50
add degree and leading term wrt MonomialOrder
AntoineChambert-Loir Nov 25, 2024
e18438b
update Mathlib.lean
AntoineChambert-Loir Nov 25, 2024
0cccee7
remove useless instances (linter alert)
AntoineChambert-Loir Nov 25, 2024
6f841ee
Merge branch 'ACL/Groebner-mo' into ACL/Groebner-da
AntoineChambert-Loir Nov 25, 2024
b483dfb
initial commit
AntoineChambert-Loir Nov 25, 2024
146967f
initial commit
AntoineChambert-Loir Nov 25, 2024
bb9f2c7
address two linter issues
AntoineChambert-Loir Nov 25, 2024
ed2cf6c
add lemma (sup_mem_of_nonempty)
AntoineChambert-Loir Nov 25, 2024
a6fbe9b
add two import
AntoineChambert-Loir Nov 25, 2024
664a11e
update after rename
AntoineChambert-Loir Nov 25, 2024
b3d9a6c
add finsupp/weight lemmas
AntoineChambert-Loir Nov 25, 2024
03a67c7
add finsupp/Lex lemmas
AntoineChambert-Loir Nov 25, 2024
2d8270c
add references
AntoineChambert-Loir Nov 25, 2024
cda269f
add references
AntoineChambert-Loir Nov 25, 2024
b50d800
Merge branch 'ACL/Groebner-deglex' into ACL/Groebner-degrevlex
AntoineChambert-Loir Nov 25, 2024
2d9def9
adjust
AntoineChambert-Loir Nov 25, 2024
d6488a1
Update Mathlib/Combinatorics/Nullstellensatz.lean
AntoineChambert-Loir Nov 25, 2024
076c83c
merge master and adjust
AntoineChambert-Loir Nov 25, 2024
cac1417
adjust import
AntoineChambert-Loir Nov 25, 2024
a92a6f2
Merge branch 'ACL/Groebner-da' into ACL/CombNS
AntoineChambert-Loir Nov 25, 2024
5a5bc74
update scripts/noshake
AntoineChambert-Loir Nov 25, 2024
4e786c4
update Mathlib.lean
AntoineChambert-Loir Nov 25, 2024
8feeada
Update Mathlib/RingTheory/MvPolynomial/MonomialOrder.lean
AntoineChambert-Loir Nov 25, 2024
65d4cd0
merge ACL/Groebner-degrevlex
AntoineChambert-Loir Nov 25, 2024
c037288
Merge branch 'ACL/CombNS' of https://github.com/leanprover-community/…
AntoineChambert-Loir Nov 25, 2024
219b7d3
remove unused import
AntoineChambert-Loir Nov 25, 2024
6f17daa
delete degrevlex and udpate Mathlib
AntoineChambert-Loir Nov 25, 2024
6b1f433
Merge branch 'master' into ACL/CombNS
AntoineChambert-Loir Nov 25, 2024
4ca1256
update, simplify
AntoineChambert-Loir Nov 25, 2024
44ba602
update, simplify again
AntoineChambert-Loir Nov 25, 2024
0860c24
remove trailing spaces
AntoineChambert-Loir Nov 25, 2024
bb1a2b9
adjust in order
AntoineChambert-Loir Nov 25, 2024
4d88261
adjust import (following linter instruction)
AntoineChambert-Loir Nov 25, 2024
9d7a6a3
Merge branch 'master' into ACL/CombNS
AntoineChambert-Loir Dec 11, 2024
375fd43
remove duplicated lemma (bad merge)
AntoineChambert-Loir Dec 11, 2024
4966e0d
update import
AntoineChambert-Loir Dec 11, 2024
bdcbe9b
postpone Combinatorial Nullstellensatz
AntoineChambert-Loir Jan 5, 2025
fc40ab1
Merge branch 'ACL/CombNS' into ACL/CombNS-2
AntoineChambert-Loir Jan 5, 2025
c3489d7
initial commit
AntoineChambert-Loir Jan 5, 2025
2d544bf
generalize from Unit to Unique
AntoineChambert-Loir Jan 6, 2025
0b6b39d
generalize lemmas for weights and degrees
AntoineChambert-Loir Jan 6, 2025
269377e
adjust to comments
AntoineChambert-Loir Jan 6, 2025
7963359
Merge branch 'master' into ACL/CombNS
AntoineChambert-Loir Jan 6, 2025
c2e5f70
one last adjustment
AntoineChambert-Loir Jan 6, 2025
de5891a
Merge branch 'ACL/CombNS' of https://github.com/leanprover-community/…
AntoineChambert-Loir Jan 6, 2025
175b4af
Update Mathlib/Data/Finsupp/Weight.lean
AntoineChambert-Loir Jan 10, 2025
246f251
revert changes to weight
AntoineChambert-Loir Jan 10, 2025
aa8bdd3
Update Order.lean
AntoineChambert-Loir Jan 10, 2025
03d3d10
Merge branch 'master' into ACL/CombNS
AntoineChambert-Loir Jan 30, 2025
57d8cc8
Merge branch 'master' into ACL/CombNS-2
AntoineChambert-Loir Jan 30, 2025
4343774
Merge branch 'ACL/CombNS' into ACL/CombNS-2
AntoineChambert-Loir Jan 30, 2025
df70157
adjust
AntoineChambert-Loir Jan 30, 2025
e48329c
merge
AntoineChambert-Loir Jan 30, 2025
ffc15ef
add prefix
AntoineChambert-Loir Jan 30, 2025
c801df8
rename lCoeff to leadingCoeff
AntoineChambert-Loir Jan 31, 2025
5fb9596
follow YD's suggestions minus an unresolved question
AntoineChambert-Loir Jan 31, 2025
3f9b138
adjust lCoeff to leadingCoeff
AntoineChambert-Loir Jan 31, 2025
11205fc
delete lemmas for subsingleton
AntoineChambert-Loir Jan 31, 2025
4a696f9
try to merge master
AntoineChambert-Loir Jan 31, 2025
8ae4248
merge master
AntoineChambert-Loir Jan 31, 2025
4f922d8
Merge branch 'master' into ACL/CombNS-2
AntoineChambert-Loir Jan 31, 2025
1ecc17b
Merge branch 'master' into ACL/CombNS-2
AntoineChambert-Loir Jan 31, 2025
0b554c6
restore leadingCoeff (WTF?)
AntoineChambert-Loir Jan 31, 2025
833d6a8
adjust
AntoineChambert-Loir Jan 31, 2025
71f8b36
mv hypotheses to variable
AntoineChambert-Loir Jan 31, 2025
3e67b87
adjust to bad merge
AntoineChambert-Loir Jan 31, 2025
0f2bb63
it\'s time to stop
AntoineChambert-Loir Jan 31, 2025
d44d411
adjust to ACL/CombNS
AntoineChambert-Loir Jan 31, 2025
b91b913
adjust
AntoineChambert-Loir Jan 31, 2025
d952c8d
Merge branch 'master' into ACL/CombNS-2
AntoineChambert-Loir Feb 1, 2025
6ff8662
add documentation
AntoineChambert-Loir Feb 4, 2025
96bb234
move a lemma to an earlier file
AntoineChambert-Loir Feb 4, 2025
b88b468
address comments of YD (and simplify)
AntoineChambert-Loir Feb 5, 2025
83abff6
further comments of YD
AntoineChambert-Loir Feb 5, 2025
38a5736
adjust
AntoineChambert-Loir Feb 5, 2025
b0210e3
pass to finset, simplify
AntoineChambert-Loir Feb 7, 2025
c8bfb74
feat(RingTheory/MvPolynomial/MonomialOrder/Monic): monic polynomials …
AntoineChambert-Loir Feb 7, 2025
0c5db85
additions
AntoineChambert-Loir Feb 7, 2025
e423433
add some monic lemmas
AntoineChambert-Loir Feb 7, 2025
5438a0f
remove simp tag
AntoineChambert-Loir Feb 7, 2025
99f1d64
add binomial
AntoineChambert-Loir Feb 7, 2025
59359d6
delete unused import (shake)
AntoineChambert-Loir Feb 7, 2025
ee0bd0f
add some stuff
AntoineChambert-Loir Feb 8, 2025
d18832e
address remarks by YD
AntoineChambert-Loir Feb 8, 2025
dabd038
merge ACL/MonomialOrderMonic
AntoineChambert-Loir Feb 8, 2025
6632a09
use Monic
AntoineChambert-Loir Feb 8, 2025
f4fc71c
merge master
AntoineChambert-Loir Feb 20, 2025
e6efcc8
Apply suggestions from code review
AntoineChambert-Loir Feb 21, 2025
4a0fd4c
follow hint
AntoineChambert-Loir Feb 21, 2025
5998128
delete Polynomial.monomial_eq
AntoineChambert-Loir Feb 21, 2025
9f10ed0
Apply suggestions from code review
AntoineChambert-Loir Feb 21, 2025
24f5dc9
Apply suggestions from code review
AntoineChambert-Loir Feb 21, 2025
fe99c17
adjust docstring (long line)
AntoineChambert-Loir Feb 21, 2025
8a85c49
find home
AntoineChambert-Loir Mar 4, 2025
40f60f9
try to mv function
AntoineChambert-Loir Mar 4, 2025
ea00909
Apply suggestions from code review
AntoineChambert-Loir Mar 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Mathlib.lean
Original file line number Diff line number Diff line change
Expand Up @@ -2421,6 +2421,7 @@ import Mathlib.Combinatorics.HalesJewett
import Mathlib.Combinatorics.Hall.Basic
import Mathlib.Combinatorics.Hall.Finite
import Mathlib.Combinatorics.Hindman
import Mathlib.Combinatorics.Nullstellensatz
import Mathlib.Combinatorics.Optimization.ValuedCSP
import Mathlib.Combinatorics.Pigeonhole
import Mathlib.Combinatorics.Quiver.Arborescence
Expand Down
54 changes: 53 additions & 1 deletion Mathlib/Algebra/MvPolynomial/Equiv.lean
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,58 @@ lemma optionEquivLeft_X_none : optionEquivLeft R S₁ (X none) = Polynomial.X :=
lemma optionEquivLeft_C (r : R) : optionEquivLeft R S₁ (C r) = Polynomial.C (C r) := by
simp only [optionEquivLeft_apply, aeval_C, Polynomial.algebraMap_apply, algebraMap_eq]

theorem optionEquivLeft_monomial (m : Option S₁ →₀ ℕ) (r : R) :
optionEquivLeft R S₁ (monomial m r) = .monomial (m none) (monomial m.some r) := by
rw [optionEquivLeft_apply, aeval_monomial, prod_option_index]
· rw [MvPolynomial.monomial_eq, ← Polynomial.C_mul_X_pow_eq_monomial]
simp only [Polynomial.algebraMap_apply, algebraMap_eq, Option.elim_none, Option.elim_some,
map_mul, mul_assoc]
apply congr_arg₂ _ rfl
simp only [mul_comm, map_finsupp_prod, map_pow]
· intros; simp
· intros; rw [pow_add]

/-- The coefficient of `n.some` in the `n none`-th coefficient of `optionEquivLeft R S₁ f`
equals the coefficient of `n` in `f` -/
theorem optionEquivLeft_coeff_coeff (n : Option S₁ →₀ ℕ) (f : MvPolynomial (Option S₁) R) :
coeff n.some (Polynomial.coeff (optionEquivLeft R S₁ f) (n none)) =
coeff n f := by
induction' f using MvPolynomial.induction_on' with j r p q hp hq generalizing n
swap
· simp only [map_add, Polynomial.coeff_add, coeff_add, hp, hq]
· rw [optionEquivLeft_monomial]
classical
simp only [Polynomial.coeff_monomial, MvPolynomial.coeff_monomial, apply_ite]
simp only [coeff_zero]
by_cases hj : j = n
· simp [hj]
· rw [if_neg hj]
simp only [ite_eq_right_iff]
intro hj_none hj_some
apply False.elim (hj _)
simp only [Finsupp.ext_iff, Option.forall, hj_none, true_and]
simpa only [Finsupp.ext_iff] using hj_some

theorem optionEquivLeft_elim_eval (s : S₁ → R) (y : R) (f : MvPolynomial (Option S₁) R) :
eval (fun x ↦ Option.elim x y s) f =
Polynomial.eval y (Polynomial.map (eval s) (optionEquivLeft R S₁ f)) := by
-- turn this into a def `Polynomial.mapAlgHom`
let φ : (MvPolynomial S₁ R)[X] →ₐ[R] R[X] :=
{ Polynomial.mapRingHom (eval s) with
commutes' := fun r => by
convert Polynomial.map_C (eval s)
exact (eval_C _).symm }
show
aeval (fun x ↦ Option.elim x y s) f =
(Polynomial.aeval y).comp (φ.comp (optionEquivLeft _ _).toAlgHom) f
congr 2
apply MvPolynomial.algHom_ext
rw [Option.forall]
simp only [aeval_X, Option.elim_none, AlgEquiv.toAlgHom_eq_coe, AlgHom.coe_comp,
Polynomial.coe_aeval_eq_eval, AlgHom.coe_mk, coe_mapRingHom, AlgHom.coe_coe, comp_apply,
optionEquivLeft_apply, Polynomial.map_X, Polynomial.eval_X, Option.elim_some, Polynomial.map_C,
eval_X, Polynomial.eval_C, implies_true, and_self, φ]

end

/-- The algebra isomorphism between multivariable polynomials in `Option S₁` and
Expand Down Expand Up @@ -437,7 +489,7 @@ theorem eval_eq_eval_mv_eval' (s : Fin n → R) (y : R) (f : MvPolynomial (Fin (
RingHom.coe_mk, MonoidHom.coe_coe, AlgHom.coe_coe, implies_true, and_self,
RingHom.toMonoidHom_eq_coe]

theorem coeff_eval_eq_eval_coeff (s' : Fin n → R) (f : Polynomial (MvPolynomial (Fin n) R))
theorem coeff_eval_eq_eval_coeff (s' : S₁ → R) (f : Polynomial (MvPolynomial S₁ R))
(i : ℕ) : Polynomial.coeff (Polynomial.map (eval s') f) i = eval s' (Polynomial.coeff f i) := by
simp only [Polynomial.coeff_map]

Expand Down
290 changes: 290 additions & 0 deletions Mathlib/Combinatorics/Nullstellensatz.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
/-
Copyright (c) 2024 Antoine Chambert-Loir. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Antoine Chambert-Loir
-/
import Mathlib.Algebra.MvPolynomial.Equiv
import Mathlib.Algebra.Polynomial.Degree.Definitions
import Mathlib.Data.Finsupp.MonomialOrder.DegLex
import Mathlib.RingTheory.Ideal.Maps
import Mathlib.RingTheory.MvPolynomial.Groebner
import Mathlib.RingTheory.MvPolynomial.Homogeneous
import Mathlib.RingTheory.MvPolynomial.MonomialOrder.DegLex

/-! # Alon's Combinatorial Nullstellensatz

This is a formalization of Noga Alon's Combinatorial Nullstellensatz. It follows [Alon_1999].

We consider a family `S : σ → Finset R` of finite subsets of a domain `R`
and a multivariate polynomial `f` in `MvPolynomial σ R`.
The combinatorial Nullstellensatz gives combinatorial constraints for
the vanishing of `f` at any `x : σ → R` such that `x s ∈ S s` for all `s`.

- `MvPolynomial.eq_zero_of_eval_zero_at_prod_finset` :
if `f` vanishes at any such point and `f.degreeOf s < #(S s)` for all `s`,
then `f = 0`.

- `combinatorial_nullstellensatz_exists_linearCombination`
If `f` vanishes at every such point, then it can be written as a linear combination
`f = linearCombination (MvPolynomial σ R) (fun i ↦ ∏ r ∈ S i, (X i - C r)) h`,
for some `h : σ →₀ MvPolynomial σ R` such that
`((∏ r ∈ S s, (X i - C r)) * h i).totalDegree ≤ f.totalDegree` for all `s`.

- `combinatorial_nullstellensatz_exists_eval_nonzero`
a multi-index `t : σ →₀ ℕ` such that `t s < (S s).card` for all `s`,
`f.totalDegree = t.degree` and `f.coeff t ≠ 0`,
there exists a point `x : σ → R` such that `x s ∈ S s` for all `s` and `f.eval s ≠ 0`.

## TODO

- Applications
- relation with Schwartz–Zippel lemma, as in [Rote_2023]

## References

- [Alon, *Combinatorial Nullstellensatz*][Alon_1999]

- [Rote, *The Generalized Combinatorial Lason-Alon-Zippel-Schwartz
Nullstellensatz Lemma*][Rote_2023]

-/

open Finsupp

open scoped Finset

variable {R : Type*} [CommRing R]

namespace MvPolynomial

open Finsupp Function

/-- A multivariate polynomial that vanishes on a large product finset is the zero polynomial. -/
theorem eq_zero_of_eval_zero_at_prod_finset {σ : Type*} [Finite σ] [IsDomain R]
(P : MvPolynomial σ R) (S : σ → Finset R)
(Hdeg : ∀ i, P.degreeOf i < #(S i))
(Heval : ∀ (x : σ → R), (∀ i, x i ∈ S i) → eval x P = 0) :
P = 0 := by
induction σ using Finite.induction_empty_option with
| @of_equiv σ τ e h =>
suffices MvPolynomial.rename e.symm P = 0 by
have that := MvPolynomial.rename_injective (R := R) e.symm (e.symm.injective)
rw [RingHom.injective_iff_ker_eq_bot] at that
rwa [← RingHom.mem_ker, that] at this
apply h _ (fun i ↦ S (e i))
· intro i
classical
convert Hdeg (e i)
conv_lhs => rw [← e.symm_apply_apply i, degreeOf_rename_of_injective e.symm.injective]
· intro x hx
simp only [MvPolynomial.eval_rename]
apply Heval
intro s
simp only [Function.comp_apply]
convert hx (e.symm s)
simp only [Equiv.apply_symm_apply]
| h_empty =>
suffices P = C (constantCoeff P) by
specialize Heval default (fun i ↦ PEmpty.elim i)
rw [this, eval_C] at Heval
rw [this, Heval, C_0]
ext m
suffices m = 0 by simp [this, ← constantCoeff_eq]
ext d; exact PEmpty.elim d
| @h_option σ _ h =>
set Q := optionEquivLeft R σ P with hQ
suffices Q = 0 by
rw [← AlgEquiv.symm_apply_apply (optionEquivLeft R σ) P, ← hQ, this, map_zero]
have Heval' (x : σ → R) (hx : ∀ i, x i ∈ S (some i)) : Polynomial.map (eval x) Q = 0 := by
apply Polynomial.eq_zero_of_natDegree_lt_card_of_eval_eq_zero' _ (S none)
· intro y hy
rw [← optionEquivLeft_elim_eval]
apply Heval
simp only [Option.forall, Option.elim_none, hy, Option.elim_some, hx, implies_true,
and_self]
· apply lt_of_le_of_lt _ (Hdeg none)
rw [Polynomial.natDegree_le_iff_coeff_eq_zero]
intro d hd
simp only [hQ]
rw [MvPolynomial.coeff_eval_eq_eval_coeff]
convert map_zero (MvPolynomial.eval x)
ext m
simp only [coeff_zero, optionEquivLeft_coeff_coeff]
set n := embDomain Function.Embedding.some m + Finsupp.single none d with hn
rw [option_embedding_add_single] at hn
rw [← hn.1, ← hn.2, optionEquivLeft_coeff_coeff]
by_contra hm
apply not_le.mpr hd
rw [MvPolynomial.degreeOf_eq_sup]
rw [← ne_eq, ← MvPolynomial.mem_support_iff] at hm
convert Finset.le_sup hm
exact hn.1.symm
ext m d
simp only [Polynomial.coeff_zero, coeff_zero]
suffices Q.coeff m = 0 by simp only [this, coeff_zero]
apply h _ (fun i ↦ S (some i))
· intro i
apply lt_of_le_of_lt _ (Hdeg (some i))
simp only [degreeOf_eq_sup, Finset.sup_le_iff, mem_support_iff, ne_eq]
intro e he
set n : Option σ →₀ ℕ := embDomain Function.Embedding.some e + Finsupp.single none m with hn
rw [option_embedding_add_single] at hn
rw [hQ, ← hn.1, ← hn.2, optionEquivLeft_coeff_coeff, ← ne_eq,
← MvPolynomial.mem_support_iff] at he
convert Finset.le_sup he
rw [← hn.2, some_apply]
· intro x hx
specialize Heval' x hx
rw [Polynomial.ext_iff] at Heval'
simpa only [Polynomial.coeff_map, Polynomial.coeff_zero] using Heval' m

open MonomialOrder

/- Here starts the actual proof of the combinatorial Nullstellensatz -/

variable {σ : Type*}

/-- The polynomial in `X i` that vanishes at all elements of `S`. -/
private noncomputable def Alon.P (S : Finset R) (i : σ) : MvPolynomial σ R :=
∏ r ∈ S, (X i - C r)

/-- The degree of `Alon.P S i` with respect to `X i` is the cardinality of `S`,
and `0` otherwise. -/
private theorem Alon.degree_P [Nontrivial R] (m : MonomialOrder σ) (S : Finset R) (i : σ) :
m.degree (Alon.P S i) = single i #S := by
simp only [P]
rw [degree_prod_of_regular]
· simp [Finset.sum_congr rfl (fun r _ ↦ m.degree_X_sub_C i r)]
· intro r _
rw [m.monic_X_sub_C]
exact isRegular_one

/-- The leading coefficient of `Alon.P S i` is `1`. -/
private theorem Alon.monic_P [Nontrivial R] (m : MonomialOrder σ) (S : Finset R) (i : σ) :
m.Monic (P S i) :=
Monic.prod (fun r _ ↦ m.monic_X_sub_C i r)

/-- The support of `Alon.P S i` is the set of exponents of the form `single i e`,
for `e ≤ S.card`. -/
private lemma Alon.of_mem_P_support {ι : Type*} (i : ι) (S : Finset R) (m : ι →₀ ℕ)
(hm : m ∈ (Alon.P S i).support) :
∃ e ≤ S.card, m = single i e := by
classical
have hP : Alon.P S i = .rename (fun _ ↦ i) (Alon.P S ()) := by simp [Alon.P, map_prod]
rw [hP, support_rename_of_injective (Function.injective_of_subsingleton _)] at hm
simp only [Finset.mem_image, mem_support_iff, ne_eq] at hm
obtain ⟨e, he, hm⟩ := hm
haveI : Nontrivial R := nontrivial_of_ne _ _ he
refine ⟨e (), ?_, ?_⟩
· suffices e ≼[lex] single () #S by
simpa [MonomialOrder.lex_le_iff_of_unique] using this
rw [← Alon.degree_P]
apply MonomialOrder.le_degree
rw [mem_support_iff]
convert he
· rw [← hm]
ext j
by_cases hj : j = i
· rw [hj, mapDomain_apply (Function.injective_of_subsingleton _), single_eq_same]
· rw [mapDomain_notin_range, single_eq_of_ne (Ne.symm hj)]
simp [Set.range_const, Set.mem_singleton_iff, hj]

variable [Fintype σ]

open scoped BigOperators

/-- The **Combinatorial Nullstellensatz**.

If `f` vanishes at every point `x : σ → R` such that `x s ∈ S s` for all `s`,
then it can be written as a linear combination
`f = linearCombination (MvPolynomial σ R) (fun i ↦ (∏ r ∈ S i, (X i - C r))) h`,
for some `h : σ →₀ MvPolynomial σ R` such that
`((∏ r ∈ S s, (X i - C r)) * h i).totalDegree ≤ f.totalDegree` for all `s`.

[Alon_1999], theorem 1. -/
theorem combinatorial_nullstellensatz_exists_linearCombination
[IsDomain R] (S : σ → Finset R) (Sne : ∀ i, (S i).Nonempty)
(f : MvPolynomial σ R) (Heval : ∀ (x : σ → R), (∀ i, x i ∈ S i) → eval x f = 0) :
∃ (h : σ →₀ MvPolynomial σ R)
(_ : ∀ i, ((∏ s ∈ S i, (X i - C s)) * h i).totalDegree ≤ f.totalDegree),
f = linearCombination (MvPolynomial σ R) (fun i ↦ ∏ r ∈ S i, (X i - C r)) h := by
letI : LinearOrder σ := WellOrderingRel.isWellOrder.linearOrder
obtain ⟨h, r, hf, hh, hr⟩ := degLex.div (b := fun i ↦ Alon.P (S i) i)
(fun i ↦ by simp only [(Alon.monic_P ..).leadingCoeff_eq_one, isUnit_one]) f
use h
suffices r = 0 by
rw [this, add_zero] at hf
exact ⟨fun i ↦ degLex_totalDegree_monotone (hh i), hf⟩
apply eq_zero_of_eval_zero_at_prod_finset r S
· intro i
rw [degreeOf_eq_sup, Finset.sup_lt_iff (by simp [Sne i])]
intro c hc
rw [← not_le]
intro h'
apply hr c hc i
intro j
rw [Alon.degree_P, single_apply]
split_ifs with hj
· rw [← hj]
exact h'
· exact zero_le _
· intro x hx
rw [Iff.symm sub_eq_iff_eq_add'] at hf
rw [← hf, map_sub, Heval x hx, zero_sub, neg_eq_zero,
linearCombination_apply, map_finsupp_sum, Finsupp.sum, Finset.sum_eq_zero]
intro i _
rw [smul_eq_mul, map_mul]
convert mul_zero _
rw [Alon.P, map_prod]
apply Finset.prod_eq_zero (hx i)
simp

/-- The **Combinatorial Nullstellensatz**.

Given a multi-index `t : σ →₀ ℕ` such that `t s < (S s).card` for all `s`,
`f.totalDegree = t.degree` and `f.coeff t ≠ 0`,
there exists a point `x : σ → R` such that `x s ∈ S s` for all `s` and `f.eval s ≠ 0`.

[Alon_1999], theorem 2 -/
theorem combinatorial_nullstellensatz_exists_eval_nonzero [IsDomain R]
(f : MvPolynomial σ R)
(t : σ →₀ ℕ) (ht : f.coeff t ≠ 0) (ht' : f.totalDegree = t.degree)
(S : σ → Finset R) (htS : ∀ i, t i < #(S i)) :
∃ (s : σ → R) (_ : ∀ i, s i ∈ S i), eval s f ≠ 0 := by
let _ : LinearOrder σ := WellOrderingRel.isWellOrder.linearOrder
classical
by_contra Heval
apply ht
push_neg at Heval
obtain ⟨h, hh, hf⟩ := combinatorial_nullstellensatz_exists_linearCombination S
(fun i ↦ by rw [← Finset.card_pos]; exact Nat.zero_lt_of_lt (htS i)) f Heval
rw [hf]
rw [linearCombination_apply, Finsupp.sum, coeff_sum]
apply Finset.sum_eq_zero
intro i _
set g := h i * Alon.P (S i) i with hg
by_cases hi : h i = 0
· simp [hi]
have : g.totalDegree ≤ f.totalDegree := by
rw [hg, mul_comm]
exact hh i
-- one could simplify this by proving `totalDegree_mul_eq` (at least in a domain)
rw [hg, ← degree_degLexDegree,
degree_mul_of_isRegular_right hi (by simp only [(Alon.monic_P ..).leadingCoeff_eq_one,
isRegular_one]),
Alon.degree_P, degree_add, degree_degLexDegree, degree_single, ht'] at this
rw [smul_eq_mul, coeff_mul, Finset.sum_eq_zero]
rintro ⟨p, q⟩ hpq
simp only [Finset.mem_antidiagonal] at hpq
simp only [mul_eq_zero, Classical.or_iff_not_imp_right]
rw [← ne_eq, ← mem_support_iff]
intro hq
obtain ⟨e, hq', hq⟩ := Alon.of_mem_P_support _ _ _ hq
apply coeff_eq_zero_of_totalDegree_lt
change (h i).totalDegree < p.degree
apply lt_of_add_lt_add_right (lt_of_le_of_lt this _)
rw [← hpq, degree_add, add_lt_add_iff_left, hq, degree_single]
apply lt_of_le_of_lt _ (htS i)
simp [← hpq, hq]

end MvPolynomial
16 changes: 16 additions & 0 deletions Mathlib/Data/Finsupp/Basic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,22 @@ theorem sum_option_index_smul [Semiring R] [AddCommMonoid M] [Module R M] (f : O
(f.sum fun o r => r • b o) = f none • b none + f.some.sum fun a r => r • b (Option.some a) :=
f.sum_option_index _ (fun _ => zero_smul _ _) fun _ _ _ => add_smul _ _ _

theorem option_embedding_add_single [AddCommMonoid M] {n : Option α →₀ M} {m : α →₀ M} {i : M} :
(n = embDomain Embedding.some m + single none i) ↔
n none = i ∧ n.some = m := by
rw [Finsupp.ext_iff, Option.forall]
apply and_congr
· simp only [coe_add, Pi.add_apply, single_eq_same]
rw [embDomain_notin_range _ _ _ ?_, zero_add]
rintro ⟨s, hs⟩
exact Option.some_ne_none s hs
· rw [Finsupp.ext_iff]
apply forall_congr'
intro s
simp only [coe_add, Pi.add_apply, ne_eq, reduceCtorEq, not_false_eq_true, single_eq_of_ne,
add_zero, some_apply]
rw [← Embedding.some_apply, embDomain_apply, Embedding.some_apply]

end Option

/-! ### Declarations about `Finsupp.filter` -/
Expand Down
Loading