1-- Distributivity of finite polynomial convolution via common support bounds (ZF).2-- Part of Cumulus, the Grace17 mathematics library.3-- Copyright (c) 2026 Grant Passmore.4-- Released under the Apache License 2.0. See LICENSE in the repository root.5-- Authors: Grant Passmore67module Grace.Cumulus.Algebra.Polynomial.Distributivity8import ConvolutionBounds910theorem boundedConvolutionWeights.add (I D A add zero neg mul one p q r : Set)11requiresring : IsCommRing(A, add, zero, neg, mul, one)12requires memberP : p ∈ polynomials(I, A, zero)13requires memberQ : q ∈ polynomials(I, A, zero)14requires memberR : r ∈ polynomials(I, A, zero)15requires domain : D ⊆ monomials(I) × monomials(I)16shows boundedConvolutionWeights(I, D, A, add, zero, neg, mul, one, p, coefficientAdd(monomials(I), A, add, zero, neg, mul, one, q, r)) =17 coefficientAdd(D, A, add, zero, neg, mul, one, boundedConvolutionWeights(I, D, A, add, zero, neg, mul, one, p, q), boundedConvolutionWeights(I, D, A, add, zero, neg, mul, one, p, r))18proof19have memberSum := polynomials.add at I, A, add, zero, neg, mul, one, q, r with*20have functionQ := polynomials.function with memberQ21have functionR := polynomials.function with memberR22have leftFunction := boundedConvolutionWeights.function at I, D, A, add, zero, neg, mul, one, p, coefficientAdd(monomials(I), A, add, zero, neg, mul, one, q, r) with*23have weightsQ := boundedConvolutionWeights.function at I, D, A, add, zero, neg, mul, one, p, q with*24have weightsR := boundedConvolutionWeights.function at I, D, A, add, zero, neg, mul, one, p, r with*25have rightFunction := coefficientAdd.function at D, A, add, zero, neg, mul, one, boundedConvolutionWeights(I, D, A, add, zero, neg, mul, one, p, q), boundedConvolutionWeights(I, D, A, add, zero, neg, mul, one, p, r) with*26apply FunctionBetween.ext with leftFunction, rightFunction27intros t ht28have included := domain29have pair := included with t, ht30obtain⟨bound, u, hu, v, hv, shape⟩:= product.membership.forward with pair31have inD : (u, v) ∈ D by rwa ← shape32have pValue := polynomials.coefficient at I, A, zero, p, u with*33have qValue := polynomials.coefficient at I, A, zero, q, v with*34have rValue := polynomials.coefficient at I, A, zero, r, v with*35have sumValue := coefficientAdd.value at monomials(I), A, add, zero, neg, mul, one, q, r, v with*36haveleft:= boundedConvolutionWeights.pair at I, D, A, add, zero, neg, mul, one, p, coefficientAdd(monomials(I), A, add, zero, neg, mul, one, q, r), u, v with*37have first := boundedConvolutionWeights.pair at I, D, A, add, zero, neg, mul, one, p, q, u, v with*38have second := boundedConvolutionWeights.pair at I, D, A, add, zero, neg, mul, one, p, r, u, v with*39haveright:= coefficientAdd.value at D, A, add, zero, neg, mul, one, boundedConvolutionWeights(I, D, A, add, zero, neg, mul, one, p, q), boundedConvolutionWeights(I, D, A, add, zero, neg, mul, one, p, r), (u, v) with*40have distribute : call2(mul, p(u), call2(add, q(v), r(v))) = call2(add, call2(mul, p(u), q(v)), call2(mul, p(u), r(v)))41ring42cc4344theorem convolutionPairs.add_subset (I A add zero neg mul one p q r : Set)45requiresring : IsCommRing(A, add, zero, neg, mul, one)46requires memberQ : q ∈ polynomials(I, A, zero)47requires memberR : r ∈ polynomials(I, A, zero)48shows convolutionPairs(I, zero, p, coefficientAdd(monomials(I), A, add, zero, neg, mul, one, q, r)) ⊆ convolutionPairs(I, zero, p, q) ∪ convolutionPairs(I, zero, p, r)49proof50have functionQ := polynomials.function with memberQ51have functionR := polynomials.function with memberR52have support := coefficientAdd.support at monomials(I), A, add, zero, neg, mul, one, q, r with*53intros t ht54unfold convolutionPairs at ht55obtain⟨bound, u, hu, v, hv, shape⟩:= product.membership.forward with ht56have inUnion := support with v, hv57have alternatives := union2.membership.forward with inUnion58apply union2.membership.backward59cases alternatives with inQ | inR60 . left61unfold convolutionPairs62rw shape63exact product.pair with hu, inQ64 . right65unfold convolutionPairs66rw shape67exact product.pair with hu, inR6869theorem polynomialProduct.add_right (I A add zero neg mul one p q r : Set)70requiresring : IsCommRing(A, add, zero, neg, mul, one)71requires memberP : p ∈ polynomials(I, A, zero)72requires memberQ : q ∈ polynomials(I, A, zero)73requires memberR : r ∈ polynomials(I, A, zero)74shows polynomialProduct(I, A, add, zero, neg, mul, one, p, coefficientAdd(monomials(I), A, add, zero, neg, mul, one, q, r)) =75 coefficientAdd(monomials(I), A, add, zero, neg, mul, one, polynomialProduct(I, A, add, zero, neg, mul, one, p, q), polynomialProduct(I, A, add, zero, neg, mul, one, p, r))76proof77have finiteQ := convolutionPairs.finite with memberP, memberQ78have finiteR := convolutionPairs.finite with memberP, memberR79have finite := Finite.union with finiteQ, finiteR80have domainQ := convolutionPairs.subset at I, zero, p, q81have domainR := convolutionPairs.subset at I, zero, p, r82have domain : convolutionPairs(I, zero, p, q) ∪ convolutionPairs(I, zero, p, r) ⊆ monomials(I) × monomials(I)83simp [Subset, union2.membership]84have coversQ : convolutionPairs(I, zero, p, q) ⊆ convolutionPairs(I, zero, p, q) ∪ convolutionPairs(I, zero, p, r)85simp [Subset, union2.membership]86have coversR : convolutionPairs(I, zero, p, r) ⊆ convolutionPairs(I, zero, p, q) ∪ convolutionPairs(I, zero, p, r)87simp [Subset, union2.membership]88have memberSum := polynomials.add at I, A, add, zero, neg, mul, one, q, r with*89have coversSum := convolutionPairs.add_subset at I, A, add, zero, neg, mul, one, p, q, r with*90have boundQ := polynomialProduct.on_domain withring, memberP, memberQ, domain, finite, coversQ91have boundR := polynomialProduct.on_domain withring, memberP, memberR, domain, finite, coversR92have boundSum := polynomialProduct.on_domain withring, memberP, memberSum, domain, finite, coversSum93have weightSum := boundedConvolutionWeights.add withring, memberP, memberQ, memberR, domain94have weightsQ := boundedConvolutionWeights.function at I, convolutionPairs(I, zero, p, q) ∪ convolutionPairs(I, zero, p, r), A, add, zero, neg, mul, one, p, q with*95have weightsR := boundedConvolutionWeights.function at I, convolutionPairs(I, zero, p, q) ∪ convolutionPairs(I, zero, p, r), A, add, zero, neg, mul, one, p, r with*96have distribute := finitePushforward.add at A, add, zero, neg, mul, one, convolutionPairs(I, zero, p, q) ∪ convolutionPairs(I, zero, p, r), monomials(I), monomialMul(I), boundedConvolutionWeights(I, convolutionPairs(I, zero, p, q) ∪ convolutionPairs(I, zero, p, r), A, add, zero, neg, mul, one, p, q), boundedConvolutionWeights(I, convolutionPairs(I, zero, p, q) ∪ convolutionPairs(I, zero, p, r), A, add, zero, neg, mul, one, p, r) with*97cc9899theorem polynomialProduct.add_left (I A add zero neg mul one p q r : Set)100requiresring : IsCommRing(A, add, zero, neg, mul, one)101requires memberP : p ∈ polynomials(I, A, zero)102requires memberQ : q ∈ polynomials(I, A, zero)103requires memberR : r ∈ polynomials(I, A, zero)104shows polynomialProduct(I, A, add, zero, neg, mul, one, coefficientAdd(monomials(I), A, add, zero, neg, mul, one, p, q), r) =105 coefficientAdd(monomials(I), A, add, zero, neg, mul, one, polynomialProduct(I, A, add, zero, neg, mul, one, p, r), polynomialProduct(I, A, add, zero, neg, mul, one, q, r))106proof107have memberSum := polynomials.add at I, A, add, zero, neg, mul, one, p, q with*108have exchange := polynomialProduct.commutative at I, A, add, zero, neg, mul, one, coefficientAdd(monomials(I), A, add, zero, neg, mul, one, p, q), r with*109have distribute := polynomialProduct.add_right at I, A, add, zero, neg, mul, one, r, p, q with*110have first := polynomialProduct.commutative at I, A, add, zero, neg, mul, one, r, p with*111have second := polynomialProduct.commutative at I, A, add, zero, neg, mul, one, r, q with*112cc113