1-- Associativity of convolution by induction on finite sums of monomial terms.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.Associativity8import Terms910predicate PolynomialAssociates (I A add zero neg mul one p q r : Set) :=11 polynomialProduct(I, A, add, zero, neg, mul, one, polynomialProduct(I, A, add, zero, neg, mul, one, p, q), r) = polynomialProduct(I, A, add, zero, neg, mul, one, p, polynomialProduct(I, A, add, zero, neg, mul, one, q, r))1213def associatingFirsts (I A add zero neg mul one q r : Set) : Set:=14 {p ∈ polynomials(I, A, zero) | PolynomialAssociates(I, A, add, zero, neg, mul, one, p, q, r)}1516def associatingMiddles (I A add zero neg mul one p r : Set) : Set:=17 {q ∈ polynomials(I, A, zero) | PolynomialAssociates(I, A, add, zero, neg, mul, one, p, q, r)}1819def associatingThirds (I A add zero neg mul one p q : Set) : Set:=20 {r ∈ polynomials(I, A, zero) | PolynomialAssociates(I, A, add, zero, neg, mul, one, p, q, r)}2122section Rings23variable (I A add zero neg mul one : Set)24hypothesisring : IsCommRing(A, add, zero, neg, mul, one)2526theorem PolynomialAssociates.zero_first (q r : Set)27requires memberQ : q ∈ polynomials(I, A, zero)28requires memberR : r ∈ polynomials(I, A, zero)29shows PolynomialAssociates(I, A, add, zero, neg, mul, one, constantFunction(monomials(I), A, zero), q, r)30proof31have zeroPolynomial := polynomials.zero at I, A, add, zero, neg, mul, one with*32have pair0 := polynomialProduct.member at I, A, add, zero, neg, mul, one, constantFunction(monomials(I), A, zero), q with*33have pair1 := polynomialProduct.member at I, A, add, zero, neg, mul, one, q, r with*34have left0 := polynomialProduct.zero_left at I, A, add, zero, neg, mul, one, q with*35have right0 := polynomialProduct.zero_right at I, A, add, zero, neg, mul, one, q with*36have left1 := polynomialProduct.zero_left at I, A, add, zero, neg, mul, one, r with*37have right1 := polynomialProduct.zero_right at I, A, add, zero, neg, mul, one, r with*38have product := polynomialProduct.member at I, A, add, zero, neg, mul, one, q, r with*39have left2 := polynomialProduct.zero_left at I, A, add, zero, neg, mul, one, polynomialProduct(I, A, add, zero, neg, mul, one, q, r) with*40have right2 := polynomialProduct.zero_right at I, A, add, zero, neg, mul, one, polynomialProduct(I, A, add, zero, neg, mul, one, q, r) with*41unfold PolynomialAssociates42cc4344theorem PolynomialAssociates.zero_middle (p r : Set)45requires memberP : p ∈ polynomials(I, A, zero)46requires memberR : r ∈ polynomials(I, A, zero)47shows PolynomialAssociates(I, A, add, zero, neg, mul, one, p, constantFunction(monomials(I), A, zero), r)48proof49have zeroPolynomial := polynomials.zero at I, A, add, zero, neg, mul, one with*50have pair0 := polynomialProduct.member at I, A, add, zero, neg, mul, one, p, constantFunction(monomials(I), A, zero) with*51have pair1 := polynomialProduct.member at I, A, add, zero, neg, mul, one, constantFunction(monomials(I), A, zero), r with*52have left0 := polynomialProduct.zero_left at I, A, add, zero, neg, mul, one, p with*53have right0 := polynomialProduct.zero_right at I, A, add, zero, neg, mul, one, p with*54have left1 := polynomialProduct.zero_left at I, A, add, zero, neg, mul, one, r with*55have right1 := polynomialProduct.zero_right at I, A, add, zero, neg, mul, one, r with*56have product := polynomialProduct.member at I, A, add, zero, neg, mul, one, p, r with*57have left2 := polynomialProduct.zero_left at I, A, add, zero, neg, mul, one, polynomialProduct(I, A, add, zero, neg, mul, one, p, r) with*58have right2 := polynomialProduct.zero_right at I, A, add, zero, neg, mul, one, polynomialProduct(I, A, add, zero, neg, mul, one, p, r) with*59unfold PolynomialAssociates60cc6162theorem PolynomialAssociates.zero_third (p q : Set)63requires memberP : p ∈ polynomials(I, A, zero)64requires memberQ : q ∈ polynomials(I, A, zero)65shows PolynomialAssociates(I, A, add, zero, neg, mul, one, p, q, constantFunction(monomials(I), A, zero))66proof67have zeroPolynomial := polynomials.zero at I, A, add, zero, neg, mul, one with*68have pair0 := polynomialProduct.member at I, A, add, zero, neg, mul, one, p, q with*69have pair1 := polynomialProduct.member at I, A, add, zero, neg, mul, one, q, constantFunction(monomials(I), A, zero) with*70have left0 := polynomialProduct.zero_left at I, A, add, zero, neg, mul, one, p with*71have right0 := polynomialProduct.zero_right at I, A, add, zero, neg, mul, one, p with*72have left1 := polynomialProduct.zero_left at I, A, add, zero, neg, mul, one, q with*73have right1 := polynomialProduct.zero_right at I, A, add, zero, neg, mul, one, q with*74have product := polynomialProduct.member at I, A, add, zero, neg, mul, one, p, q with*75have left2 := polynomialProduct.zero_left at I, A, add, zero, neg, mul, one, polynomialProduct(I, A, add, zero, neg, mul, one, p, q) with*76have right2 := polynomialProduct.zero_right at I, A, add, zero, neg, mul, one, polynomialProduct(I, A, add, zero, neg, mul, one, p, q) with*77unfold PolynomialAssociates78cc7980theorem PolynomialAssociates.add_first (p q r s : Set)81requires memberP : p ∈ polynomials(I, A, zero)82requires memberQ : q ∈ polynomials(I, A, zero)83requires memberR : r ∈ polynomials(I, A, zero)84requires memberS : s ∈ polynomials(I, A, zero)85requires first : PolynomialAssociates(I, A, add, zero, neg, mul, one, p, q, r)86requires second : PolynomialAssociates(I, A, add, zero, neg, mul, one, s, q, r)87shows PolynomialAssociates(I, A, add, zero, neg, mul, one, coefficientAdd(monomials(I), A, add, zero, neg, mul, one, p, s), q, r)88proof89have pair0 := polynomialProduct.member at I, A, add, zero, neg, mul, one, p, q with*90have pair1 := polynomialProduct.member at I, A, add, zero, neg, mul, one, q, r with*91have pair2 := polynomialProduct.member at I, A, add, zero, neg, mul, one, s, q with*92have distribute0 := polynomialProduct.add_left at I, A, add, zero, neg, mul, one, p, s, q with*93have distribute1 := polynomialProduct.add_left at 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, s, q), r with*94have distribute2 := polynomialProduct.add_left at I, A, add, zero, neg, mul, one, p, s, polynomialProduct(I, A, add, zero, neg, mul, one, q, r) with*95unfold PolynomialAssociates at first96unfold PolynomialAssociates at second97unfold PolynomialAssociates98cc99100theorem PolynomialAssociates.add_middle (p q r s : Set)101requires memberP : p ∈ polynomials(I, A, zero)102requires memberQ : q ∈ polynomials(I, A, zero)103requires memberR : r ∈ polynomials(I, A, zero)104requires memberS : s ∈ polynomials(I, A, zero)105requires first : PolynomialAssociates(I, A, add, zero, neg, mul, one, p, q, r)106requires second : PolynomialAssociates(I, A, add, zero, neg, mul, one, p, s, r)107shows PolynomialAssociates(I, A, add, zero, neg, mul, one, p, coefficientAdd(monomials(I), A, add, zero, neg, mul, one, q, s), r)108proof109have pair0 := polynomialProduct.member at I, A, add, zero, neg, mul, one, p, q with*110have pair1 := polynomialProduct.member at I, A, add, zero, neg, mul, one, p, s with*111have pair2 := polynomialProduct.member at I, A, add, zero, neg, mul, one, q, r with*112have pair3 := polynomialProduct.member at I, A, add, zero, neg, mul, one, s, r with*113have distribute0 := polynomialProduct.add_right at I, A, add, zero, neg, mul, one, p, q, s with*114have distribute1 := polynomialProduct.add_left at 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, s), r with*115have distribute2 := polynomialProduct.add_left at I, A, add, zero, neg, mul, one, q, s, r with*116have distribute3 := polynomialProduct.add_right at I, A, add, zero, neg, mul, one, p, polynomialProduct(I, A, add, zero, neg, mul, one, q, r), polynomialProduct(I, A, add, zero, neg, mul, one, s, r) with*117unfold PolynomialAssociates at first118unfold PolynomialAssociates at second119unfold PolynomialAssociates120cc121122theorem PolynomialAssociates.add_third (p q r s : Set)123requires memberP : p ∈ polynomials(I, A, zero)124requires memberQ : q ∈ polynomials(I, A, zero)125requires memberR : r ∈ polynomials(I, A, zero)126requires memberS : s ∈ polynomials(I, A, zero)127requires first : PolynomialAssociates(I, A, add, zero, neg, mul, one, p, q, r)128requires second : PolynomialAssociates(I, A, add, zero, neg, mul, one, p, q, s)129shows PolynomialAssociates(I, A, add, zero, neg, mul, one, p, q, coefficientAdd(monomials(I), A, add, zero, neg, mul, one, r, s))130proof131have pair0 := polynomialProduct.member at I, A, add, zero, neg, mul, one, p, q with*132have pair1 := polynomialProduct.member at I, A, add, zero, neg, mul, one, q, r with*133have pair2 := polynomialProduct.member at I, A, add, zero, neg, mul, one, q, s with*134have distribute0 := polynomialProduct.add_right at I, A, add, zero, neg, mul, one, polynomialProduct(I, A, add, zero, neg, mul, one, p, q), r, s with*135have distribute1 := polynomialProduct.add_right at I, A, add, zero, neg, mul, one, q, r, s with*136have distribute2 := polynomialProduct.add_right at I, A, add, zero, neg, mul, one, p, polynomialProduct(I, A, add, zero, neg, mul, one, q, r), polynomialProduct(I, A, add, zero, neg, mul, one, q, s) with*137unfold PolynomialAssociates at first138unfold PolynomialAssociates at second139unfold PolynomialAssociates140cc141142theorem PolynomialAssociates.terms (a b c m n k : Set)143requires coefficientA : a ∈ A144requires coefficientB : b ∈ A145requires coefficientC : c ∈ A146requires monomialM : m ∈ monomials(I)147requires monomialN : n ∈ monomials(I)148requires monomialK : k ∈ monomials(I)149shows PolynomialAssociates(I, A, add, zero, neg, mul, one, polynomialTerm(I, A, zero, a, m), polynomialTerm(I, A, zero, b, n), polynomialTerm(I, A, zero, c, k))150proof151have ordinary := IsCommRing.ring withring152have ab := IsRing.mul_closed at A, add, zero, neg, mul, one, a, b with*153have bc := IsRing.mul_closed at A, add, zero, neg, mul, one, b, c with*154have mn := monomialProduct.member at I, m, n with*155have nk := monomialProduct.member at I, n, k with*156have product0 := polynomialProduct.terms at I, A, add, zero, neg, mul, one, a, b, m, n with*157have product1 := polynomialProduct.terms at I, A, add, zero, neg, mul, one, b, c, n, k with*158have product2 := polynomialProduct.terms at I, A, add, zero, neg, mul, one, call2(mul, a, b), c, monomialProduct(I, m, n), k with*159have product3 := polynomialProduct.terms at I, A, add, zero, neg, mul, one, a, call2(mul, b, c), m, monomialProduct(I, n, k) with*160have coefficients : call2(mul, call2(mul, a, b), c) = call2(mul, a, call2(mul, b, c)) byring161have monomials := monomialProduct.associative at I, m, n, k with*162unfold PolynomialAssociates163cc164165theorem PolynomialAssociates.two_terms (a b m n r : Set)166requires coefficientA : a ∈ A167requires coefficientB : b ∈ A168requires monomialM : m ∈ monomials(I)169requires monomialN : n ∈ monomials(I)170requires memberR : r ∈ polynomials(I, A, zero)171shows PolynomialAssociates(I, A, add, zero, neg, mul, one, polynomialTerm(I, A, zero, a, m), polynomialTerm(I, A, zero, b, n), r)172proof173have ordinary := IsCommRing.ring withring174have zeroIn := IsRing.zero_in_carrier with ordinary175have zeroPolynomial := polynomials.zero at I, A, add, zero, neg, mul, one with*176have termA := polynomialTerm.member at I, A, zero, a, m with*177have termB := polynomialTerm.member at I, A, zero, b, n with*178have base : constantFunction(monomials(I), A, zero) ∈ associatingThirds(I, A, add, zero, neg, mul, one, polynomialTerm(I, A, zero, a, m), polynomialTerm(I, A, zero, b, n))179apply associatingThirds.membership.backward180constructor181 . exact zeroPolynomial182 . exact PolynomialAssociates.zero_third with*183have terms : ∀ d ∈ A, ∀ j ∈ monomials(I), polynomialTerm(I, A, zero, d, j) ∈ associatingThirds(I, A, add, zero, neg, mul, one, polynomialTerm(I, A, zero, a, m), polynomialTerm(I, A, zero, b, n))184intros d hd j hj185have member := polynomialTerm.member at I, A, zero, d, j with*186apply associatingThirds.membership.backward187constructor188 . exact member189 . exact PolynomialAssociates.terms with*190have sums : ∀ f ∈ associatingThirds(I, A, add, zero, neg, mul, one, polynomialTerm(I, A, zero, a, m), polynomialTerm(I, A, zero, b, n)), ∀ g ∈ associatingThirds(I, A, add, zero, neg, mul, one, polynomialTerm(I, A, zero, a, m), polynomialTerm(I, A, zero, b, n)), coefficientAdd(monomials(I), A, add, zero, neg, mul, one, f, g) ∈ associatingThirds(I, A, add, zero, neg, mul, one, polynomialTerm(I, A, zero, a, m), polynomialTerm(I, A, zero, b, n))191intros f hf g hg192have first := associatingThirds.membership.forward with hf193have second := associatingThirds.membership.forward with hg194have member := polynomials.add at I, A, add, zero, neg, mul, one, f, g with*195apply associatingThirds.membership.backward196constructor197 . exact member198 . exact PolynomialAssociates.add_third with*199have generated := polynomials.induction at I, A, add, zero, neg, mul, one, associatingThirds(I, A, add, zero, neg, mul, one, polynomialTerm(I, A, zero, a, m), polynomialTerm(I, A, zero, b, n)), r with*200have result := associatingThirds.membership.forward with generated201exact result.right202203theorem PolynomialAssociates.one_term (a m q r : Set)204requires coefficientA : a ∈ A205requires monomialM : m ∈ monomials(I)206requires memberQ : q ∈ polynomials(I, A, zero)207requires memberR : r ∈ polynomials(I, A, zero)208shows PolynomialAssociates(I, A, add, zero, neg, mul, one, polynomialTerm(I, A, zero, a, m), q, r)209proof210have ordinary := IsCommRing.ring withring211have zeroIn := IsRing.zero_in_carrier with ordinary212have zeroPolynomial := polynomials.zero at I, A, add, zero, neg, mul, one with*213have termA := polynomialTerm.member at I, A, zero, a, m with*214have base : constantFunction(monomials(I), A, zero) ∈ associatingMiddles(I, A, add, zero, neg, mul, one, polynomialTerm(I, A, zero, a, m), r)215apply associatingMiddles.membership.backward216constructor217 . exact zeroPolynomial218 . exact PolynomialAssociates.zero_middle with*219have terms : ∀ d ∈ A, ∀ j ∈ monomials(I), polynomialTerm(I, A, zero, d, j) ∈ associatingMiddles(I, A, add, zero, neg, mul, one, polynomialTerm(I, A, zero, a, m), r)220intros d hd j hj221have member := polynomialTerm.member at I, A, zero, d, j with*222apply associatingMiddles.membership.backward223constructor224 . exact member225 . exact PolynomialAssociates.two_terms with*226have sums : ∀ f ∈ associatingMiddles(I, A, add, zero, neg, mul, one, polynomialTerm(I, A, zero, a, m), r), ∀ g ∈ associatingMiddles(I, A, add, zero, neg, mul, one, polynomialTerm(I, A, zero, a, m), r), coefficientAdd(monomials(I), A, add, zero, neg, mul, one, f, g) ∈ associatingMiddles(I, A, add, zero, neg, mul, one, polynomialTerm(I, A, zero, a, m), r)227intros f hf g hg228have first := associatingMiddles.membership.forward with hf229have second := associatingMiddles.membership.forward with hg230have member := polynomials.add at I, A, add, zero, neg, mul, one, f, g with*231apply associatingMiddles.membership.backward232constructor233 . exact member234 . exact PolynomialAssociates.add_middle with*235have generated := polynomials.induction at I, A, add, zero, neg, mul, one, associatingMiddles(I, A, add, zero, neg, mul, one, polynomialTerm(I, A, zero, a, m), r), q with*236have result := associatingMiddles.membership.forward with generated237exact result.right238239theorem polynomialProduct.associative (p q r : Set)240requires memberP : p ∈ polynomials(I, A, zero)241requires memberQ : q ∈ polynomials(I, A, zero)242requires memberR : r ∈ polynomials(I, A, zero)243shows polynomialProduct(I, A, add, zero, neg, mul, one, polynomialProduct(I, A, add, zero, neg, mul, one, p, q), r) = polynomialProduct(I, A, add, zero, neg, mul, one, p, polynomialProduct(I, A, add, zero, neg, mul, one, q, r))244proof245have ordinary := IsCommRing.ring withring246have zeroIn := IsRing.zero_in_carrier with ordinary247have zeroPolynomial := polynomials.zero at I, A, add, zero, neg, mul, one with*248have base : constantFunction(monomials(I), A, zero) ∈ associatingFirsts(I, A, add, zero, neg, mul, one, q, r)249apply associatingFirsts.membership.backward250constructor251 . exact zeroPolynomial252 . exact PolynomialAssociates.zero_first with*253have terms : ∀ d ∈ A, ∀ j ∈ monomials(I), polynomialTerm(I, A, zero, d, j) ∈ associatingFirsts(I, A, add, zero, neg, mul, one, q, r)254intros d hd j hj255have member := polynomialTerm.member at I, A, zero, d, j with*256apply associatingFirsts.membership.backward257constructor258 . exact member259 . exact PolynomialAssociates.one_term with*260have sums : ∀ f ∈ associatingFirsts(I, A, add, zero, neg, mul, one, q, r), ∀ g ∈ associatingFirsts(I, A, add, zero, neg, mul, one, q, r), coefficientAdd(monomials(I), A, add, zero, neg, mul, one, f, g) ∈ associatingFirsts(I, A, add, zero, neg, mul, one, q, r)261intros f hf g hg262have first := associatingFirsts.membership.forward with hf263have second := associatingFirsts.membership.forward with hg264have member := polynomials.add at I, A, add, zero, neg, mul, one, f, g with*265apply associatingFirsts.membership.backward266constructor267 . exact member268 . exact PolynomialAssociates.add_first with*269have generated := polynomials.induction at I, A, add, zero, neg, mul, one, associatingFirsts(I, A, add, zero, neg, mul, one, q, r), p with*270have result := associatingFirsts.membership.forward with generated271exact result.right272273end Rings274