Skip to content

feat(multivariate): add degree-bound and partial-evaluation primitives#241

Draft
codygunton wants to merge 3 commits into
Verified-zkEVM:masterfrom
codygunton:cg/multivariate-degree-bound
Draft

feat(multivariate): add degree-bound and partial-evaluation primitives#241
codygunton wants to merge 3 commits into
Verified-zkEVM:masterfrom
codygunton:cg/multivariate-degree-bound

Conversation

@codygunton

@codygunton codygunton commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the generic computable-polynomial facts that ArkLib's interaction-native protocol work builds on:

  • Multivariate/DegreeBound.lean — degree-bound predicates (IndividualDegreeLE, CDegreeLE, CMvDegreeLE) on computable multivariate polynomials.
  • Multivariate/PartialEval.leanpartialEvalFirst (fix variable 0) with its evaluation lemma and per-variable degree-bound lemma.
  • Operations.lean — the fromCMvPolynomial_bind₁ bridge lemma (lives with the other bind₁/fromCMvPolynomial_* facts).

Usage in ArkLib

  • DegreeBound is used by the ArkLib oracle bridge (ArkLib/Data/CompPoly/Basic.lean, the core slice) and by the Sumcheck integration.
  • PartialEval (partialEvalFirst) is used by the ArkLib Sumcheck slice.

Scope

Follows CompPoly's concept-per-file layout. The sumcheck round-polynomial machinery (roundPoly and its summation/univariate-collapse helpers) deliberately does not live here — it is protocol-specific, has a single consumer, and lands in ArkLib's ProofSystem/Sumcheck. This PR keeps only the broadly-reusable primitives.

Supersedes #235 (closed). Rebased cleanly onto current master; full CompPoly build passes with no warnings.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

🤖 PR Summary

Multivariate Polynomials

  • Added degree-bound predicates for computable multivariate polynomials: IndividualDegreeLE, CDegreeLE, and CMvDegreeLE.
  • Introduced partialEvalFirst to fix the first variable of a multivariate polynomial, including evaluation correctness and degree-bound preservation lemmas.
  • Added the fromCMvPolynomial_bind₁ bridge lemma in Operations.lean, mapping bind₁ to MvPolynomial.eval₂.

Status

  • Fully formalized with no sorry or admit placeholders; all proofs are complete.

Statistics

Metric Count
📝 Files Changed 4
Lines Added 266
Lines Removed 0

Lean Declarations

✏️ **Added:** 10 declaration(s)
  • def CDegreeLE (R : Type) [BEq R] [Semiring R] [LawfulBEq R] (d : ℕ) in CompPoly/Multivariate/DegreeBound.lean
  • private lemma partialEvalFirst_subst_degreeOf_le [Nontrivial R] (a : R) in CompPoly/Multivariate/PartialEval.lean
  • private lemma partialEvalFirst_eval₂_monomial_degreeOf_le [Nontrivial R] {deg : ℕ} in CompPoly/Multivariate/PartialEval.lean
  • def IndividualDegreeLE (deg : ℕ) (p : CMvPolynomial n R) : Prop in CompPoly/Multivariate/DegreeBound.lean
  • theorem partialEvalFirst_eval (a : R) (p : CMvPolynomial (n + 1) R) (v : Fin n → R) : in CompPoly/Multivariate/PartialEval.lean
  • def partialEvalFirst (a : R) (p : CMvPolynomial (n + 1) R) : CMvPolynomial n R in CompPoly/Multivariate/PartialEval.lean
  • def CMvDegreeLE in CompPoly/Multivariate/DegreeBound.lean
  • theorem fromCMvPolynomial_bind₁ {n m : ℕ} {R : Type*} [CommSemiring R] [BEq R] in CompPoly/Multivariate/Operations.lean
  • private lemma partialEvalFirst_eval₂_degreeOf_le [Nontrivial R] {deg : ℕ} in CompPoly/Multivariate/PartialEval.lean
  • theorem partialEvalFirst_degreeOf_le [Nontrivial R] {deg : ℕ} (a : R) in CompPoly/Multivariate/PartialEval.lean

sorry Tracking

  • No sorrys were added, removed, or affected.

📋 **Additional Analysis**

Style and Naming Violations

  • Naming Convention: The definition IndividualDegreeLE in CompPoly/Multivariate/DegreeBound.lean violates naming conventions for predicates. Since it is a Prop-valued definition and not a class, it should use lowerCamelCase (e.g., individualDegreeLE). If it were intended as a class-like predicate, it should follow the Is prefix rule for adjectives (e.g., IsIndividualDegreeLE).
  • Syntax: Multiple files use the fun x => ... syntax instead of the preferred fun x ↦ ... convention specified in the guidelines (see CompPoly/Multivariate/Operations.lean and CompPoly/Multivariate/PartialEval.lean).
  • Copyright Year: The new files (DegreeBound.lean and PartialEval.lean) list 2026 in the copyright header. This should be updated to the current year or the project's standard (the guidelines use 2024 as the example).

Module Layout and Organization

  • Imports: The additions to CompPoly.lean correctly maintain the alphabetical order of imports.
  • Logic and Naming: New theorems such as partialEvalFirst_eval and partialEvalFirst_degreeOf_le correctly follow the snake_case convention and the result_of_condition naming logic.
  • Variable Conventions: Usage of R for commutative semirings and n, i, j for natural numbers and indices is consistent with the project's variable conventions.

Documentation

  • Docstrings: Both new files include appropriate module-level docstrings (/-! ... -/).
  • Definitions: Major definitions such as partialEvalFirst, CDegreeLE, and CMvDegreeLE are accompanied by docstrings as required.

📄 **Per-File Summaries**
  • CompPoly.lean: This update expands the CompPoly library by adding imports for multivariate degree bounds and partial evaluation modules. No new theorems, definitions, or 'sorry' placeholders are introduced directly in this file.
  • CompPoly/Multivariate/DegreeBound.lean: This file introduces new definitions for degree-bounded computable polynomials, including the IndividualDegreeLE property for multivariate polynomials and subtypes CDegreeLE and CMvDegreeLE that bundle univariate and multivariate polynomials with their respective degree bounds. No sorry or admit placeholders are present in the definitions.
  • CompPoly/Multivariate/Operations.lean: This change introduces the theorem fromCMvPolynomial_bind₁ to CompPoly/Multivariate/Operations.lean, which proves that the computable substitution operation bind₁ is equivalent to Mathlib's MvPolynomial.eval₂ after conversion. The theorem is fully proved without any sorry or admit placeholders.
  • CompPoly/Multivariate/PartialEval.lean: This file introduces the partialEvalFirst operation to fix the first variable of a multivariate computable polynomial to a scalar value. It provides a definition based on bind₁, an evaluation lemma for correctness, and a theorem proving that the operation preserves degree bounds for the remaining variables.

Last updated: 2026-06-23 23:39 UTC.

- Multivariate/DegreeBound.lean: degree-bound predicates (IndividualDegreeLE,
  CDegreeLE, CMvDegreeLE) on computable multivariate polynomials.
- Multivariate/PartialEval.lean: partialEvalFirst (fix variable 0) with its
  evaluation and per-variable degree-bound lemmas.
- Operations.lean: add the fromCMvPolynomial_bind₁ bridge lemma.

These are the generic polynomial facts used by ArkLib's interaction-native
oracle bridge and Sumcheck integration. The sumcheck round-polynomial machinery
lives in ArkLib, not here.
@codygunton codygunton force-pushed the cg/multivariate-degree-bound branch from a556bc1 to 6f3eb09 Compare June 5, 2026 20:10
@codygunton codygunton changed the title feat(multivariate): add degree-bounded sumcheck primitives feat(multivariate): add degree-bound and partial-evaluation primitives Jun 5, 2026

@alexanderlhicks alexanderlhicks left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — validated against current master and the ArkLib consumer branch

Verification performed (all locally, with this diff applied):

  • Full library build + full lake test pass on v4.31.0 (master has bumped the toolchain since this PR's last CI run on v4.30.0; the PR is behind but merges cleanly, so re-merging is a formality).
  • #print axioms on all 7 public declarations: only propext, Classical.choice, Quot.sound — TCB policy satisfied.
  • lint-style.sh passes; CompPoly.lean regenerated correctly.
  • Every inline suggestion below was compile-checked against this diff before posting.

ArkLib cross-check (consumer branch cg/mainline-interaction-sumcheck-pr2, tip 1617561d, and the stacked pr3/pr4 tips):

  • ArkLib currently carries local copies of IndividualDegreeLE/CDegreeLE/CMvDegreeLE in ArkLib/Data/CompPoly/Basic.lean; only partialEvalFirst and partialEvalFirst_degreeOf_le are consumed from the CompPoly package (Interaction/CompPoly.lean:30, Interaction/SingleRound.lean:35-36).
  • partialEvalFirst_eval and fromCMvPolynomial_bind₁ have no external consumers yet (both are still justified: the latter powers both PartialEval theorems, the former is the spec of the definition).
  • Everything suggested inline is strictly compatible with the ArkLib call sites — notably, I deliberately do not suggest restating partialEvalFirst_degreeOf_le via CMvPolynomial.degreeOf, because that would break the exact term-mode application at Interaction/CompPoly.lean:30. Additive corollaries (see inline) give the clean API with zero breakage, and would let ArkLib delete its partialEvalFirst_individualDegreeLE wrapper and prune the [Nontrivial R] it threads through SingleRound.

Not anchored inline:

  • Namespace/naming: CompPoly.CDegreeLE/CMvDegreeLE introduce the first non-test use of the CompPoly namespace (the library otherwise uses CPoly). Either choice works for ArkLib (use sites are unqualified under open CompPoly CPoly), so this is a deliberate maintainer call — worth a comment in the file either way. Also note the repo's existing degree-bound machinery is lowercase and Set-valued (degreeLE/degreeLT in Univariate/Linear.lean); CDegreeLE is the first {p // natDegree ≤ d} subtype. PascalCase-for-subtype is Mathlib-idiomatic, so this is defensible.
  • Headers: Authors: ArkLib Contributors — repo convention is real names (the originals in ArkLib credit Quang Dao).
  • Tests: partialEvalFirst is computable and tests/CompPolyTests/Multivariate/ exists — a small evaluation regression test would fit. The new definitions should also be exercised in tests/CompPolyTests/Multivariate/TypeclassMinimization.lean, the repo's compile-time regression suite for minimal assumptions (relevant to the inline typeclass comment).
  • Follow-up golf (assessed, not required): the ~90 lines of private degree helpers reprove what Mathlib's MvPolynomial.degreeOf_coeff_finSuccEquiv provides; routing through it (plus a small eval₂finSuccEquiv bridge, which Mathlib lacks) should collapse the block to ~20-30 lines. Confirmed Mathlib has no degreeOf_eval₂/bind₁/aeval lemma, so the helpers are not redundant as written. Similarly, MvPolynomial.eval_eval₂ shortens partialEvalFirst_eval slightly (validated at 15 lines vs 21).
  • ArkLib pin: the consumer branch pins CompPoly to a fork rev (codygunton/CompPoly @ 2ebbaac3) not in upstream; the eventual migration needs a repin plus deletion of the local copies.

Overall: mathematically sound, kernel-safe, green on the current toolchain. The inline items are small and mechanical, each with a verified fix.

Authors: ArkLib Contributors
-/
import CompPoly.Multivariate.CMvPolynomial
import CompPoly.Univariate.ToPoly.Impl

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import (verified: removal compiles). CPolynomial.natDegree lives in CompPoly/Univariate/Basic.lean, which is already transitively imported via CompPoly.Multivariate.CMvPolynomialToPoly.Impl pulls in the whole Mathlib Polynomial bridge for nothing.


namespace CPoly.CMvPolynomial

variable {n : ℕ} {R : Type} [CommSemiring R] [BEq R] [LawfulBEq R]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typeclass assumptions much stronger than needed (verified: the minimized file compiles). Everything in this file needs only [Zero R], and R : Type* matches the rest of the library:

variable {n : ℕ} {R : Type*} [Zero R]
...
def CDegreeLE (R : Type*) [Zero R] (d : ℕ) :=
  { p : CPolynomial R // p.natDegree ≤ d }

def CMvDegreeLE (R : Type*) [Zero R] (n d : ℕ) :=
  { p : CMvPolynomial n R // CMvPolynomial.IndividualDegreeLE (R := R) d p }

CPolynomial, CMvPolynomial, natDegree, and Lawful.monomials all require just [Zero R]. As written, every consumer must thread BEq/LawfulBEq/CommSemiring instances it doesn't need (per docs/wiki/typeclass-minimization.md). I checked the ArkLib consumer branch: relaxing is strictly safe — all use sites supply stronger instances. Suggest also adding these three definitions to tests/CompPolyTests/Multivariate/TypeclassMinimization.lean so the minimal assumptions are pinned.

/-- `p` has individual degree at most `deg` when every monomial exponent is
bounded by `deg` in every coordinate. -/
def IndividualDegreeLE (deg : ℕ) (p : CMvPolynomial n R) : Prop :=
letI := Classical.decEq R

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead code (verified: removal compiles). Nothing in the body needs DecidableEq RLawful.monomials is a key list and CMvMonomial.degreeOf never touches R. This looks inherited from the ArkLib original; it embeds a spurious let in the definition that every consumer unfolds past.

Separately (verified), the predicate is equivalent to a bound on the existing CMvPolynomial.degreeOf, and the connection is worth recording here so the new predicate plugs into the existing degreeOf_equiv bridge:

theorem individualDegreeLE_iff {deg : ℕ} (p : CMvPolynomial n R) :
    IndividualDegreeLE deg p ↔ ∀ i, CMvPolynomial.degreeOf i p ≤ deg := by
  unfold IndividualDegreeLE CMvPolynomial.degreeOf
  constructor
  · intro h i
    exact Finset.sup_le fun m hm => h i m (by simpa using hm)
  · intro h i m hm
    exact (Finset.le_sup (s := (Lawful.monomials p).toFinset)
      (f := fun m => CMvMonomial.degreeOf m i) (by simpa using hm)).trans (h i)

Authors: ArkLib Contributors
-/
import CompPoly.Data.MvPolynomial.Notation
import CompPoly.Multivariate.DegreeBound

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two unused imports (verified: removal compiles). Nothing in this file uses the R[X σ] notation, and nothing here references IndividualDegreeLE or the DegreeBound file. (If you adopt the IndividualDegreeLE-preservation corollary suggested below on the degree lemma, the DegreeBound import becomes genuinely used — otherwise both lines can go.)

exact (eval_equiv (p := p) (vals := Fin.cons a v)).symm

/-! ## Degree preservation -/

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Nontrivial R] can be dropped from this public lemma (verified: compiles). Over a subsingleton ring the statement is vacuous — a Lawful polynomial stores no zero coefficients, hence no monomials. The private helpers can keep their [Nontrivial R]:

theorem partialEvalFirst_degreeOf_le {deg : ℕ} (a : R)
    (i : Fin n) (p : CMvPolynomial (n + 1) R)
    (hDeg : ∀ mono ∈ Lawful.monomials p, mono.degreeOf i.succ ≤ deg) :
    ∀ mono ∈ Lawful.monomials (partialEvalFirst a p), mono.degreeOf i ≤ deg := by
  intro mono hmono
  rcases subsingleton_or_nontrivial R with hR | hR
  · have hmem : mono ∈ (partialEvalFirst a p).1 := by simpa using hmono
    have hne := (partialEvalFirst a p).2 mono
    rw [getElem?_pos _ _ hmem,
      Subsingleton.elim ((partialEvalFirst a p).1[mono]'hmem) 0] at hne
    exact absurd rfl hne
  · <original proof body>

This matters downstream: on the ArkLib consumer branch, [Nontrivial R] is threaded through partialEvalFirst_individualDegreeLE, stepResidual, and SingleRound.lean's variable block solely to satisfy this hypothesis, over a generic CommSemiring.

Note I'm deliberately not suggesting restating this lemma via CMvPolynomial.degreeOf — that would break ArkLib's exact term-mode application at Interaction/CompPoly.lean:30. Instead, two additive corollaries (both verified) give the clean API with zero breakage:

theorem partialEvalFirst_degreeOf_le' {deg : ℕ} (a : R) (i : Fin n)
    (p : CMvPolynomial (n + 1) R) (h : CMvPolynomial.degreeOf i.succ p ≤ deg) :
    CMvPolynomial.degreeOf i (partialEvalFirst a p) ≤ deg := ...

theorem partialEvalFirst_individualDegreeLE {deg : ℕ} (a : R)
    (p : CMvPolynomial (n + 1) R) (h : IndividualDegreeLE deg p) :
    IndividualDegreeLE deg (partialEvalFirst a p) :=
  fun i => partialEvalFirst_degreeOf_le a i p (fun mono hmono => h i.succ mono hmono)

The second is exactly ArkLib's wrapper in Interaction/CompPoly.lean — upstreaming it lets ArkLib delete that wrapper.

/-- The computable substitution `bind₁` agrees with Mathlib substitution after
transporting through `fromCMvPolynomial`. -/
theorem fromCMvPolynomial_bind₁ {n m : ℕ} {R : Type*} [CommSemiring R] [BEq R]
[LawfulBEq R] (f : Fin n → CMvPolynomial m R) (p : CMvPolynomial n R) :

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider spelling the RHS with MvPolynomial.aeval (verified: compiles, no new import):

fromCMvPolynomial (bind₁ f p) =
  MvPolynomial.aeval (fun i => fromCMvPolynomial (f i)) (fromCMvPolynomial p)

This mirrors CompPoly's own bind₁_eq_aeval and is more discoverable than raw eval₂ C. (MvPolynomial.bind₁ would be the most literal spelling, but it isn't in the current import closure — it lives in Mathlib.Algebra.MvPolynomial.Monad; the aeval form needs nothing new.) I checked there's no existing fromCMvPolynomial_aeval/eval₂ bridge that makes this lemma redundant, so the proof is genuinely needed — a general fromCMvPolynomial_eval₂ next to eval₂_equiv would subsume it and is nice follow-up material.

Nit: double blank line above the docstring (line 458).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants