1-- Summing grouped coefficients recovers the original finite sum (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.Ring.Regrouping8import FiniteDoubleSum9import Pushforward1011defunique groupingEntry (D C A zero h w t : Set) (a ∈ A) :=12∃ d ∈ D, ∃ c ∈ C, t = (d, c) ∧ a = singleValue(A, zero, w(d), h(d), c)13requires zeroIn : zero ∈ A14requires weights : w : D → A15requires pair : t ∈ D × C16proof17obtain⟨bound, d, hd, c, hc, shape⟩:= product.membership.forward at18 D, C, t with pair19have coefficient := FunctionBetween.apply_closed at w, D, A, d with*20have value := singleValue.closed at A, zero, w(d), h(d), c with*21refine⟨singleValue(A, zero, w(d), h(d), c), value, d, hd, c, hc, shape, rfl⟩22uniqueness23intros u hu first v hv second24obtain⟨d, hd, c, hc, shapeU, valueU⟩:= first25obtain⟨e, he, b, hb, shapeV, valueV⟩:= second26have equal : (d, c) = (e, b)27cc28have coordinates := orderedPair.injective at d, c, e, b with equal29cc3031defgraph groupingMatrix (D C A zero h w : Set) (t ∈ D × C) : A := groupingEntry(D, C, A, zero, h, w, t)32requires zeroIn : zero ∈ A33requires weights : w : D → A34proof35have selected := groupingEntry.selected at D, C, A, zero, h, w, t with*36exact selected.left3738theorem groupingMatrix.pair (D C A zero h w d c : Set)39requires zeroIn : zero ∈ A40requires weights : w : D → A41requires row : d ∈ D42requires column : c ∈ C43shows groupingMatrix(D, C, A, zero, h, w)((d, c)) = singleValue(A, zero, w(d), h(d), c)44proof45have pair := product.pair at d, c, D, C with*46have selected := groupingEntry.selected at D, C, A, zero, h, w, (d, c) with*47obtain⟨e, he, b, hb, shape, output⟩:= selected.right48have coordinates := orderedPair.injective with shape49have value := groupingMatrix.value at D, C, A, zero, h, w, (d, c) with*50cc5152section Rings53variable (D C A add zero neg mul one h w : Set)54hypothesisring : IsCommRing(A, add, zero, neg, mul, one)55hypothesis weights : w : D → A5657theorem groupingMatrix.rows58requires finiteC : Finite(C)59requires indexMap : h : D → C60shows finiteRowSums(D, C, A, add, zero, neg, mul, one, groupingMatrix(D, C, A, zero, h, w)) = w61proof62have ordinary := IsCommRing.ring withring63have zeroIn := IsRing.zero_in_carrier with ordinary64have matrix := groupingMatrix.function at D, C, A, zero, h, w with*65have rows := finiteRowSums.function at D, C, A, add, zero, neg, mul, one, groupingMatrix(D, C, A, zero, h, w) with*66apply FunctionBetween.ext with rows, weights67intros d hd68have coefficient := FunctionBetween.apply_closed at w, D, A, d with*69have index := FunctionBetween.apply_closed at h, D, C, d with*70have row := finiteRowWeights.function at D, C, A, groupingMatrix(D, C, A, zero, h, w), d with*71have single := coefficientSingle.function at C, A, zero, w(d), h(d) with*72have same : finiteRowWeights(D, C, A, groupingMatrix(D, C, A, zero, h, w), d) = coefficientSingle(C, A, zero, w(d), h(d))73apply FunctionBetween.ext with row, single74intros c hc75haveleft:= finiteRowWeights.value at D, C, A, groupingMatrix(D, C, A, zero, h, w), d, c with*76have entry := groupingMatrix.pair at D, C, A, zero, h, w, d, c with*77haveright:= coefficientSingle.value at C, A, zero, w(d), h(d), c with*78cc79have sum := finiteRingSum.single withring, coefficient, index80have value := finiteRowSums.value at D, C, A, add, zero, neg, mul, one, groupingMatrix(D, C, A, zero, h, w), d with*81cc8283theorem groupingMatrix.columns84requires finiteD : Finite(D)85shows finiteRowSums(C, D, A, add, zero, neg, mul, one, transposedMatrix(D, C, A, groupingMatrix(D, C, A, zero, h, w))) = finitePushforward(D, C, A, add, zero, neg, mul, one, h, w)86proof87have ordinary := IsCommRing.ring withring88have zeroIn := IsRing.zero_in_carrier with ordinary89have matrix := groupingMatrix.function at D, C, A, zero, h, w with*90have transpose := transposedMatrix.function at D, C, A, groupingMatrix(D, C, A, zero, h, w) with*91have rows := finiteRowSums.function at C, D, A, add, zero, neg, mul, one, transposedMatrix(D, C, A, groupingMatrix(D, C, A, zero, h, w)) with*92have grouped := finitePushforward.function at D, C, A, add, zero, neg, mul, one, h, w with*93apply FunctionBetween.ext with rows, grouped94intros c hc95have row := finiteRowWeights.function at C, D, A, transposedMatrix(D, C, A, groupingMatrix(D, C, A, zero, h, w)), c with*96have selected := pushforwardWeights.function at D, A, add, zero, neg, mul, one, h, w, c with*97have same : finiteRowWeights(C, D, A, transposedMatrix(D, C, A, groupingMatrix(D, C, A, zero, h, w)), c) = pushforwardWeights(D, A, add, zero, neg, mul, one, h, w, c)98apply FunctionBetween.ext with row, selected99intros d hd100haveleft:= finiteRowWeights.value at C, D, A, transposedMatrix(D, C, A, groupingMatrix(D, C, A, zero, h, w)), c, d with*101have swapped := transposedMatrix.pair with hd, hc102have entry := groupingMatrix.pair at D, C, A, zero, h, w, d, c with*103haveright:= pushforwardWeights.value at D, A, add, zero, neg, mul, one, h, w, c, d with*104cc105haveleft:= finiteRowSums.value at C, D, A, add, zero, neg, mul, one, transposedMatrix(D, C, A, groupingMatrix(D, C, A, zero, h, w)), c with*106haveright:= finitePushforward.value at D, C, A, add, zero, neg, mul, one, h, w, c with*107cc108109theorem finitePushforward.sum110requires finiteD : Finite(D)111requires finiteC : Finite(C)112requires indexMap : h : D → C113shows finiteRingSum(C, A, add, zero, neg, mul, one, finitePushforward(D, C, A, add, zero, neg, mul, one, h, w)) = finiteRingSum(D, A, add, zero, neg, mul, one, w)114proof115have ordinary := IsCommRing.ring withring116have zeroIn := IsRing.zero_in_carrier with ordinary117have matrix := groupingMatrix.function at D, C, A, zero, h, w with*118have rows := groupingMatrix.rows withring, weights, finiteC, indexMap119have columns := groupingMatrix.columns at D, C, A, add, zero, neg, mul, one, h, w with*120have interchange := finiteDoubleSum.interchange withring, finiteD, finiteC, matrix121unfold finiteDoubleSum at interchange122cc123124-- Only the finite image needs to be summed, even if C itself is infinite.125theorem finitePushforward.sum_image126requires finiteD : Finite(D)127requires indexMap : h : D → C128shows finiteRingSum(functionImage(h, D, C), A, add, zero, neg, mul, one,129 finitePushforward(D, functionImage(h, D, C), A, add, zero, neg, mul, one, h, w)) =130 finiteRingSum(D, A, add, zero, neg, mul, one, w)131proof132have reflexive : D ⊆ D bysimp [Subset]133have finiteImage := Finite.function_image at D, C, h, D with*134have corestricted := functionImage.corestrict at h, D, C with*135exact finitePushforward.sum with*136137end Rings138theorem finitePushforward.constant_index (D A add zero neg mul one w c : Set)139requiresring : IsCommRing(A, add, zero, neg, mul, one)140requires finite : Finite(D)141requires weights : w : D → A142shows finitePushforward(D, {c}, A, add, zero, neg, mul, one, constantFunction(D, {c}, c), w)(c) =143 finiteRingSum(D, A, add, zero, neg, mul, one, w)144proof145have member : c ∈ {c} bysimp [singleton.membership]146have indexMap := constantFunction.function at D, {c}, c with member147have finiteC := Finite.singleton at c148have grouped := finitePushforward.function at D, {c}, A, add, zero, neg, mul, one, constantFunction(D, {c}, c), w with*149have total := finitePushforward.sum at D, {c}, A, add, zero, neg, mul, one, constantFunction(D, {c}, c), w with*150have singleton := finiteRingSum.singleton with*151cc152