@@ -9,10 +9,12 @@ import ArkLib.Data.Probability.Notation
99import ArkLib.Data.Fin.BigOperators
1010import ArkLib.Data.Nat.Bitwise
1111import Mathlib.Algebra.MvPolynomial.SchwartzZippel
12-
12+ import ArkLib.Data.MvPolynomial.Notation
13+ import ArkLib.ToMathlib.MvPolynomial.Equiv
14+ import VCVio.EvalDist.Basic
1315open ProbabilityTheory Filter
1416open NNReal Finset Function
15- open scoped BigOperators ProbabilityTheory
17+ open scoped BigOperators ProbabilityTheory Polynomial
1618open Real
1719
1820section
@@ -373,6 +375,26 @@ theorem Pr_le_Pr_of_implies {α : Type} (D : PMF α)
373375 -- 5. Prove the factor `D r` is non-negative
374376 · exact zero_le (D r) -- Probabilities are always non-negative
375377
378+ alias prob_mono := Pr_le_Pr_of_implies
379+
380+ /-- **Union bound** : Pr[A ∨ B] ≤ Pr[ A ] + Pr[ B ] . -/
381+ theorem Pr_or_le {α : Type } (D : PMF α)
382+ (f g : α → Prop ) [DecidablePred f] [DecidablePred g] [DecidablePred (fun r => f r ∨ g r)] :
383+ Pr_{ let r ← D }[ f r ∨ g r ] ≤ Pr_{ let r ← D }[ f r ] + Pr_{ let r ← D }[ g r ] := by
384+ rw [prob_tsum_form_singleton D (fun r => f r ∨ g r),
385+ prob_tsum_form_singleton D f, prob_tsum_form_singleton D g]
386+ trans ∑' r, (D r * (if f r then 1 else 0 ) + D r * (if g r then 1 else 0 ))
387+ · apply ENNReal.tsum_le_tsum
388+ intro r
389+ by_cases hf : f r
390+ · by_cases hg : g r
391+ · simp only [hf, hg, or_true, ↓reduceIte, mul_one]; exact le_add_of_nonneg_right (zero_le (D r))
392+ · simp only [hf, hg, or_true, true_or, ↓reduceIte, mul_one, mul_zero, add_zero]; exact le_refl (D r)
393+ · by_cases hg : g r
394+ · simp only [hf, hg, true_or, or_true, ↓reduceIte, mul_one, mul_zero, zero_add]; exact le_refl (D r)
395+ · simp only [hf, hg, false_or, ↓reduceIte, mul_zero, zero_add]; exact le_refl 0
396+ · rw [ENNReal.tsum_add];
397+
376398theorem Pr_multi_let_equiv_single_let {α β : Type }
377399 (D₁ : PMF α) (D₂ : PMF β) -- Assuming D₂ is independent for simplicity
378400 (P : α → β → Prop ) [∀ x, DecidablePred (P x)] :
@@ -454,6 +476,98 @@ lemma Pr_congr {α : Type} {D : PMF α} {P Q : α → Prop}
454476 congr 2 ; funext x;
455477 congr 1 ; exact propext (h x)
456478
479+ section ProbabilitySplitting
480+ variable {A : Type } [Fintype A] [Nonempty A]
481+
482+ /-- Helper: Probability over functions can be split into iterated product.
483+ For uniform sampling over `Fin n → A`, if the predicate factors as a conjunction
484+ over each index, the probability equals the product of individual probabilities.
485+
486+ This is the key lemma for showing that independent repetitions multiply their error rates. -/
487+ theorem prob_pow_of_forall_finFun
488+ (n : ℕ) (P : A → Prop ) [DecidablePred P]
489+ [DecidablePred (fun (f : Fin n → A) => ∀ i, P (f i))] :
490+ Pr_{ let f ← $ᵖ (Fin n → A) }[ ∀ i, P (f i) ] =
491+ (Pr_{ let a ← $ᵖ A }[ P a ])^n := by
492+ induction n with
493+ | zero =>
494+ simp only [IsEmpty.forall_iff, PMF.monad_pure_eq_pure, PMF.monad_bind_eq_bind, PMF.bind_const,
495+ PMF.pure_apply, ↓reduceIte, PMF.bind_apply, PMF.uniformOfFintype_apply, eq_iff_iff, true_iff,
496+ mul_ite, mul_one, mul_zero, pow_zero]
497+ | succ n ih =>
498+ -- Shorter equivalence proof
499+ have h_eqv (f : Fin (n + 1 ) → A) : (∀ i, P (f i)) ↔ P (f (Fin.last n)) ∧ ∀ (i : Fin n), P (f i.castSucc) := by
500+ constructor
501+ · intro h; exact ⟨h _, fun i => h _⟩
502+ · rintro ⟨h_last, h_init⟩ ⟨i, hi⟩
503+ by_cases h : i < n
504+ · exact h_init ⟨i, h⟩
505+ · have : i = n := by omega
506+ simp only [this]
507+ exact h_last
508+ rw [Pr_congr (h := h_eqv)]
509+ -- Chain the splitting and independence results
510+ calc Pr_{ let f ← $ᵖ (Fin (n + 1 ) → A) }[ P (f (Fin.last n)) ∧ ∀ (i : Fin n), P (f i.castSucc) ]
511+ _ = Pr_{ let a ← $ᵖ A; let f_init ← $ᵖ (Fin n → A) }[ P a ∧ ∀ (i : Fin n), P (f_init i) ] := by
512+ have h := prob_split_last_uniform_sampling_of_finFun (ϑ := n)
513+ (P := fun a (f_init : Fin n → A) => P a ∧ ∀ (i : Fin n), P (f_init i))
514+ simpa using h
515+ _ = Pr_{ let a ← $ᵖ A }[ P a ] * Pr_{ let f_init ← $ᵖ (Fin n → A) }[ ∀ (i : Fin n), P (f_init i) ] := by
516+ -- Convert sequential bind to single uniform over product
517+ have h_prod : Pr_{ let a ← $ᵖ A; let f_init ← $ᵖ (Fin n → A) }[ P a ∧ ∀ (i : Fin n), P (f_init i) ] =
518+ Pr_{ let p ← $ᵖ (A × (Fin n → A)) }[ P p.1 ∧ ∀ (i : Fin n), P (p.2 i) ] := by
519+ rw [prob_split_uniform_sampling_of_prod]
520+ rw [h_prod]
521+ -- Use counting formula for product and components
522+ rw [prob_uniform_eq_card_filter_div_card, prob_uniform_eq_card_filter_div_card,
523+ prob_uniform_eq_card_filter_div_card]
524+ simp only [Fintype.card_prod, ENNReal.div_eq_inv_mul]
525+ -- Filter cardinality multiplies
526+ have h_filter :
527+ (Finset.filter (fun (p : A × (Fin n → A)) => P p.1 ∧ ∀ (i : Fin n), P (p.2 i)) Finset.univ).card =
528+ (Finset.filter (fun (a : A) => P a) Finset.univ).card *
529+ (Finset.filter (fun (f : Fin n → A) => ∀ (i : Fin n), P (f i)) Finset.univ).card := by
530+ have : Finset.filter (fun (p : A × (Fin n → A)) => P p.1 ∧ ∀ (i : Fin n), P (p.2 i)) Finset.univ =
531+ (Finset.filter (fun (a : A) => P a) Finset.univ) ×ˢ
532+ (Finset.filter (fun (f : Fin n → A) => ∀ (i : Fin n), P (f i)) Finset.univ) := by
533+ ext ⟨a, f⟩; simp
534+ rw [this, Finset.card_product]
535+ rw [h_filter]
536+ simp only [Fintype.card_pi, Finset.prod_const, Finset.card_univ, Fintype.card_fin,
537+ Nat.cast_mul, Nat.cast_pow, ENNReal.coe_mul, ENNReal.coe_natCast, ENNReal.coe_pow]
538+ -- (↑(card A))^n = ↑((card A)^n) so lemma pattern (↑a * ↑b)⁻¹ matches
539+ rw [← Nat.cast_pow]
540+ rw [← ENNReal.mul_inv_rev_ENNReal (ha := Fintype.card_ne_zero)
541+ (hb := ne_of_gt (Nat.pow_pos Fintype.card_pos))]
542+ have h_eq : (Finset.filter (fun a => P a) Finset.univ) = Finset.filter P Finset.univ :=
543+ Finset.filter_congr (fun a _ => by rfl)
544+ rw [← h_eq]
545+ conv_lhs =>
546+ rw [←mul_assoc];
547+ rw [mul_assoc (c := ((Finset.filter (fun a => P a) Finset.univ).card : ENNReal))]
548+ rw [mul_comm (b := ((Finset.filter (fun a => P a) Finset.univ).card : ENNReal))]
549+ rw [←mul_assoc]
550+ rw [mul_assoc (a := ((Fintype.card A):ENNReal)⁻¹ * (Finset.filter (fun a => P a) Finset.univ).card)]
551+ _ = (Pr_{ let a ← $ᵖ A }[ P a ]) ^ (n + 1 ) := by
552+ rw [ih, pow_succ', mul_comm]
553+
554+ /-- Specialization: Probability bound for failing all proximity checks.
555+ When each repetition independently bounds bad events by ε, running n repetitions
556+ has cumulative bound ε^n (product rule for independent events). -/
557+ theorem prob_pow_bound_of_forall
558+ (n : ℕ) (P : A → Prop ) [DecidablePred P]
559+ [DecidablePred (fun (f : Fin n → A) => ∀ i, P (f i))]
560+ (ε : ENNReal) (h_bound : Pr_{ let a ← $ᵖ A}[P a] ≤ ε) :
561+ Pr_{ let f ← $ᵖ (Fin n → A) }[ ∀ i, P (f i) ] ≤ ε^n := by
562+ calc Pr_{ let f ← $ᵖ (Fin n → A) }[ ∀ i, P (f i) ]
563+ = (Pr_{ let a ← $ᵖ A }[ P a ])^n := prob_pow_of_forall_finFun n P
564+ _ ≤ ε^n := by
565+ -- Use the fact that x ≤ y implies x^n ≤ y^n for ENNReal
566+ apply pow_le_pow_left'
567+ · exact h_bound
568+
569+ end ProbabilitySplitting
570+
457571/-- **Schwartz-Zippel Lemma** (Probability Form):
458572For a non-zero multivariate polynomial `P` of total degree at most `d` over a finite field `L`,
459573the probability that `P(r)` evaluates to 0 for a uniformly random `r` is at most `d / |L|`. -/
@@ -493,4 +607,125 @@ lemma prob_schwartz_zippel_mv_polynomial {R : Type} [CommRing R] [IsDomain R] [F
493607 rw [Nat.cast_pow] at sz_bound_ENNReal
494608 exact sz_bound_ENNReal
495609
610+ /-- **Schwartz-Zippel for univariate (Fin 1) polynomials with arbitrary degree bound** .
611+ For a non-zero `P : MvPolynomial (Fin 1) R` with `P.totalDegree ≤ d`, the probability that
612+ `P(r)` is 0 for uniform `r : Fin 1 → R` is at most `d / |R|`. -/
613+ lemma prob_schwartz_zippel_univariate_deg {R : Type } [CommRing R] [IsDomain R] [Fintype R]
614+ [DecidableEq R] (d : ℕ) (P : MvPolynomial (Fin 1 ) R) (h_nonzero : P ≠ 0 )
615+ (h_deg : P.totalDegree ≤ d) :
616+ Pr_{ let r ←$ᵖ (Fin 1 → R) }[ MvPolynomial.eval r P = 0 ] ≤
617+ (d : ℝ≥0 ) / (Fintype.card R : ℝ≥0 ) := by
618+ rw [prob_uniform_eq_card_filter_div_card]
619+ push_cast
620+ have sz_bound := MvPolynomial.schwartz_zippel_totalDegree (R := R) (n := 1 )
621+ (p := P) (hp := h_nonzero) (S := Finset.univ)
622+ simp only [Fintype.piFinset_univ, card_univ] at sz_bound
623+ have sz_bound_le_d_div_card_R : ((#{f | (MvPolynomial.eval f) P = 0 }) : ℚ≥0 )
624+ / ((Fintype.card R ^ 1 )) ≤ (d : ℚ≥0 ) / ((#(Finset.univ : Finset R)) : ℚ≥0 ) := by
625+ calc
626+ _ ≤ (P.totalDegree : ℚ≥0 ) / ((#(Finset.univ : Finset R)) : ℚ≥0 ) := sz_bound
627+ _ ≤ (d : ℚ≥0 ) / ((#(Finset.univ : Finset R)) : ℚ≥0 ) := by
628+ simp only [card_univ]
629+ apply div_le_of_le_mul₀ (hb := by simp only [zero_le]) (hc := by simp only [zero_le])
630+ rw [div_mul_cancel₀ (h := by simp only [ne_eq, Nat.cast_eq_zero, Fintype.card_ne_zero,
631+ not_false_eq_true])]
632+ exact Nat.cast_le.mpr h_deg
633+ have sz_bound_le_d_div_card_R' : ((#{f | (MvPolynomial.eval f) P = 0 }) : ℚ≥0 )
634+ / (Fintype.card R : ℚ≥0 ) ≤ (d : ℚ≥0 ) / (Fintype.card R : ℚ≥0 ) := by
635+ rw [pow_one, card_univ] at sz_bound_le_d_div_card_R
636+ exact sz_bound_le_d_div_card_R
637+ have sz_bound_ENNReal : ((#{f | (MvPolynomial.eval f) P = 0 }) : ENNReal)
638+ / (Fintype.card R : ENNReal) ≤ (d : ENNReal) / (Fintype.card R : ENNReal) := by
639+ simp_rw [ENNReal.coe_Nat_coe_NNRat]
640+ conv_lhs => rw [ENNReal.coe_div_of_NNRat (hb := by
641+ simp only [pow_one, ne_eq, Nat.cast_eq_zero, Fintype.card_ne_zero, not_false_eq_true])]
642+ conv_rhs => rw [ENNReal.coe_div_of_NNRat (hb := by simp only [ne_eq, Nat.cast_eq_zero,
643+ Fintype.card_ne_zero, not_false_eq_true])]
644+ rw [ENNReal.coe_le_of_NNRat]
645+ exact sz_bound_le_d_div_card_R'
646+ simp only [Fintype.card_pi, prod_const, card_univ, Fintype.card_fin, pow_one, ge_iff_le]
647+ exact sz_bound_ENNReal
648+
649+ /-- **Schwartz-Zippel for degree-1 univariate polynomials** .
650+ For two distinct degree-1 univariate polynomials over a commutative ring, the probability
651+ that they agree at a random point is at most `1 / |R|`. -/
652+ lemma prob_poly_agreement_degree_one {R : Type } [CommRing R] [IsDomain R] [Fintype R]
653+ [DecidableEq R]
654+ (p q : R⦃≤ 1 ⦄[X])
655+ (h_ne : p ≠ q) :
656+ Pr_{ let r ←$ᵖ R }[ p.val.eval r = q.val.eval r ] ≤
657+ (1 : ℝ≥0 ) / (Fintype.card R : ℝ≥0 ) := by
658+ -- 1. Setup the multivariate polynomial P = p - q
659+ let P := (p.val - q.val).toMvPolynomial (σ := Fin 1 ) 0
660+ -- 2. Prove P is non-zero (immediate from p ≠ q)
661+ have h_nz : P ≠ 0 := by
662+ rw [Polynomial.toMvPolynomial_ne_zero_iff, sub_ne_zero]
663+ exact fun h => h_ne (Subtype.eq h)
664+ have h_p_deg : p.val.degree ≤ 1 :=
665+ Polynomial.mem_degreeLE (f := p.val) (n := 1 ).mp (by simp only [SetLike.coe_mem])
666+ have h_q_deg : q.val.degree ≤ 1 :=
667+ Polynomial.mem_degreeLE (f := q.val) (n := 1 ).mp (by simp only [SetLike.coe_mem])
668+ -- 3. Prove totalDegree P ≤ 1
669+ have h_deg : P.totalDegree ≤ 1 := by
670+ apply (Polynomial.toMvPolynomial_totalDegree_le _ _).trans
671+ apply (Polynomial.natDegree_sub_le _ _).trans
672+ -- Use the fact that p, q are in R{≤1}[ X ] directly
673+ simp only [max_le_iff]
674+ constructor <;> apply Polynomial.natDegree_le_of_degree_le <;>
675+ first | exact h_p_deg | exact h_q_deg
676+ -- 4. Apply Schwartz-Zippel
677+ calc Pr_{ let r ←$ᵖ R }[ p.val.eval r = q.val.eval r ]
678+ _ = Pr_{ let r ←$ᵖ R }[ (p.val - q.val).eval r = 0 ] := by
679+ apply Pr_congr; simp [sub_eq_zero]
680+ _ = Pr_{ let r ←$ᵖ R }[ MvPolynomial.eval (fun _ ↦ r) P = 0 ] := by
681+ apply Pr_congr; intro; simp [P, MvPolynomial.eval_toMvPolynomial]
682+ _ = Pr_{ let f ←$ᵖ (Fin 1 → R) }[ MvPolynomial.eval f P = 0 ] := by
683+ -- Move to function space (Fin 1 → R)
684+ rw [← prob_uniform_singleton_finFun_eq]
685+ congr; funext f
686+ -- Collapse: eval f (toMv p) = eval (f 0) p
687+ simp [P, MvPolynomial.eval_toMvPolynomial]
688+ _ ≤ _ := by
689+ have h := prob_schwartz_zippel_mv_polynomial P h_nz h_deg
690+ simp only [Nat.cast_one] at h
691+ exact h
692+
693+ alias prob_schwartz_zippel_univariate_poly := prob_poly_agreement_degree_one
694+
695+ /-- **Schwartz-Zippel for degree-2 univariate polynomials** .
696+ For two distinct degree-2 univariate polynomials over a commutative ring, the probability
697+ that they agree at a random point is at most `2 / |R|`. -/
698+ lemma prob_poly_agreement_degree_two {R : Type } [CommRing R] [IsDomain R] [Fintype R]
699+ [DecidableEq R]
700+ (p q : R⦃≤ 2 ⦄[X])
701+ (h_ne : p ≠ q) :
702+ Pr_{ let r ←$ᵖ R }[ p.val.eval r = q.val.eval r ] ≤
703+ (2 : ℝ≥0 ) / (Fintype.card R : ℝ≥0 ) := by
704+ let P := (p.val - q.val).toMvPolynomial (σ := Fin 1 ) 0
705+ have h_nz : P ≠ 0 := by
706+ rw [Polynomial.toMvPolynomial_ne_zero_iff, sub_ne_zero]
707+ exact fun h => h_ne (Subtype.eq h)
708+ have h_p_deg : p.val.degree ≤ 2 :=
709+ Polynomial.mem_degreeLE (f := p.val) (n := 2 ).mp (by simp only [SetLike.coe_mem])
710+ have h_q_deg : q.val.degree ≤ 2 :=
711+ Polynomial.mem_degreeLE (f := q.val) (n := 2 ).mp (by simp only [SetLike.coe_mem])
712+ have h_deg : P.totalDegree ≤ 2 := by
713+ apply (Polynomial.toMvPolynomial_totalDegree_le _ _).trans
714+ apply (Polynomial.natDegree_sub_le _ _).trans
715+ simp only [max_le_iff]
716+ constructor <;> apply Polynomial.natDegree_le_of_degree_le <;>
717+ first | exact h_p_deg | exact h_q_deg
718+ calc Pr_{ let r ←$ᵖ R }[ p.val.eval r = q.val.eval r ]
719+ _ = Pr_{ let r ←$ᵖ R }[ (p.val - q.val).eval r = 0 ] := by apply Pr_congr; simp [sub_eq_zero]
720+ _ = Pr_{ let r ←$ᵖ R }[ MvPolynomial.eval (fun _ ↦ r) P = 0 ] := by
721+ apply Pr_congr; intro; simp [P, MvPolynomial.eval_toMvPolynomial]
722+ _ = Pr_{ let f ←$ᵖ (Fin 1 → R) }[ MvPolynomial.eval f P = 0 ] := by
723+ rw [← prob_uniform_singleton_finFun_eq]
724+ congr; funext f
725+ simp [P, MvPolynomial.eval_toMvPolynomial]
726+ _ ≤ _ := by
727+ -- The lemma returns (P.totalDegree / card R), which is ≤ (2 / card R)
728+ have h := prob_schwartz_zippel_univariate_deg 2 P h_nz h_deg
729+ exact h
730+
496731end ProbabilityTools
0 commit comments