1-- Sums of naturals over finite sets: disjoint unions add, removing a point2-- takes its weight off, a subset sums to no more, the sums over a point and3-- over a pair, reindexing along a bijection, and the sum of w(d) · u(e) over4-- a product set as the product of the two sums5-- Part of Cumulus, the Grace17 mathematics library.6-- Copyright (c) 2026 Grant Passmore.7-- Released under the Apache License 2.0. See LICENSE in the repository root.8-- Authors: Grant Passmore910module Grace.Cumulus.Cardinal.NaturalSumLaws11import Pigeonhole1213-- The weighted pairs of a subset, of a union, and of disjoint sets.14theorem weightedPairs.monotone (S T w : Set)15requires subset : S ⊆ T16shows weightedPairs(S, w) ⊆ weightedPairs(T, w)17proof18intros p hp19have parts := weightedPairs.membership.forward with hp20obtain⟨v, hv, i, hi, shape⟩:= parts.right21have bound := parts.left22rw shape at bound23have coordinates := product.pair_membership.forward with bound24have hvT := subset with v, hv25have boundT : p ∈ T × ℕ26rw shape27exact product.pair with hvT, coordinates.right28exact weightedPairs.membership.backward with29⟨boundT, v, hvT, i, hi, shape⟩3031theorem weightedPairs.union (A B w : Set)32shows weightedPairs(A ∪ B, w) = weightedPairs(A, w) ∪ weightedPairs(B, w)33proof34have leftSubset := union2.subset_left at A, B35have rightSubset := union2.subset_right at A, B36have leftInside := weightedPairs.monotone at A, A ∪ B, w with leftSubset37have rightInside := weightedPairs.monotone at B, A ∪ B, w with rightSubset38ext p39constructor40 . intro hp41have parts := weightedPairs.membership.forward with hp42obtain⟨v, hv, i, hi, shape⟩:= parts.right43have bound := parts.left44rw shape at bound45have coordinates := product.pair_membership.forward with bound46havesplit:= union2.membership.forward with hv47apply union2.membership.backward48casessplitwith inA | inB49 . left50have boundA : p ∈ A × ℕ51rw shape52exact product.pair with inA, coordinates.right53exact weightedPairs.membership.backward with54⟨boundA, v, inA, i, hi, shape⟩55 . right56have boundB : p ∈ B × ℕ57rw shape58exact product.pair with inB, coordinates.right59exact weightedPairs.membership.backward with60⟨boundB, v, inB, i, hi, shape⟩61 . intro hp62havesplit:= union2.membership.forward with hp63casessplitwith inA | inB64 . exact leftInside with p, inA65 . exact rightInside with p, inB6667theorem weightedPairs.disjoint (A B w : Set)68requires disjoint : Disjoint(A, B)69shows Disjoint(weightedPairs(A, w), weightedPairs(B, w))70proof71have apart := Disjoint.iff.forward with disjoint72apply Disjoint.iff.backward73intros p hp hp274have parts := weightedPairs.membership.forward with hp75obtain⟨v, hv, i, hi, shape⟩:= parts.right76have parts2 := weightedPairs.membership.forward with hp277obtain⟨u, hu, j, hj, shape2⟩:= parts2.right78rw shape at shape279have coordinates := orderedPair.injective with shape280have same := coordinates.left81have notB := apart with v, hv82rw← same at hu83exact notB with hu8485-- Disjoint unions add up.86theorem natSum.union_disjoint (A B w : Set)87requires finiteA : Finite(A)88requires finiteB : Finite(B)89requires weightsA : ∀ v ∈ A, w(v) ∈ ℕ90requires weightsB : ∀ v ∈ B, w(v) ∈ ℕ91requires disjoint : Disjoint(A, B)92shows natSum(A ∪ B, w) = natSum(A, w) + natSum(B, w)93proof94have sizeA : cardinality(A) = cardinality(A) byrfl95have sizeB : cardinality(B) = cardinality(B) byrfl96have correctA := cardinality.correct with finiteA97have cardNatA := correctA.left98have correctB := cardinality.correct with finiteB99have cardNatB := correctB.left100have pairsA := weightedPairs.finite with finiteA, sizeA, weightsA101have pairsB := weightedPairs.finite with finiteB, sizeB, weightsB102have apart := weightedPairs.disjoint at A, B, w with disjoint103have added := cardinality.union_disjoint with pairsA, pairsB, apart104havesplit:= weightedPairs.union at A, B, w105unfold natSum106rwsplit107exact added108109-- Removing a point from the index set takes its weight off the sum.110theorem natSum.remove (V w a : Set)111requires finite : Finite(V)112requires member : a ∈ V113requires weights : ∀ v ∈ V, w(v) ∈ ℕ114shows natSum(V, w) = natSum(V ∖ {a}, w) + w(a)115proof116have restSubset := difference.subset_left at V, {a}117have restFinite := Finite.difference at V, {a} with finite118have restWeights : ∀ v ∈ V ∖ {a}, w(v) ∈ ℕ119intros v hv120exact weights with v, (restSubset with v, hv)121have weight := weights with a, member122have fresh : ¬a ∈ V ∖ {a} bysimp123have inserted := natSum.insert with restFinite, restWeights, weight, fresh124 rwa (insert.restore with member) at inserted125126-- A subset sums to no more.127theorem natSum.monotone (S T w : Set)128requires finite : Finite(T)129requires subset : S ⊆ T130requires weights : ∀ v ∈ T, w(v) ∈ ℕ131shows natSum(S, w) ≤ natSum(T, w)132proof133have size : cardinality(T) = cardinality(T) byrfl134have correct := cardinality.correct with finite135have cardNat := correct.left136have pairsFinite := weightedPairs.finite with finite, size, weights137have inside := weightedPairs.monotone at S, T, w with subset138have bounded := cardinality.monotone with pairsFinite, inside139simp [natSum]140141-- The sum over a point and over a pair.142theorem natSum.singleton (w a : Set)143requires weight : w(a) ∈ ℕ144shows natSum({a}, w) = w(a)145proof146have asInsert : {a} = insert(a, ∅)147ext x148simp [insert.membership]149have finite := Finite.empty150have weights : ∀ v ∈∅, w(v) ∈ ℕ151intros v hv152exfalso153exact empty.membership with v, hv154have fresh : ¬a ∈∅:= empty.membership at a155have inserted := natSum.insert with finite, weights, weight, fresh156have weightNat := nat.omega.backward with weight157rw [asInsert, inserted, natSum.empty]158exact add.left_unit at w(a)159160theorem natSum.pair (w a b : Set)161requires weightA : w(a) ∈ ℕ162requires weightB : w(b) ∈ ℕ163requires distinct : a ≠ b164shows natSum({a, b}, w) = w(a) + w(b)165proof166have asInsert : {a, b} = insert(a, {b})167ext x168simp [insert.membership, pair.membership]169have finite := Finite.singleton at b170have weights : ∀ v ∈ {b}, w(v) ∈ ℕ171intros v hv172have same := singleton.membership.forward with hv173rw same174exact weightB175have fresh : ¬a ∈ {b}176intro inside177have same := singleton.membership.forward with inside178exact distinct with same179have inserted := natSum.insert with finite, weights, weightA, fresh180have single := natSum.singleton with weightB181have aNat := nat.omega.backward with weightA182have bNat := nat.omega.backward with weightB183rw [asInsert, inserted, single]184exact add.commutative at w(a), w(b)185186-- A sum of vanishing weights vanishes: no weighted pair exists.187theorem natSum.zero_weights (V w : Set)188requires zero : ∀ v ∈ V, w(v) =0189shows natSum(V, w) =0190proof191have none : weightedPairs(V, w) =∅192apply Subset.antisymmetric193 . intros p hp194have parts := weightedPairs.membership.forward with hp195obtain⟨v, hv, i, hi, _⟩:= parts.right196have vanish := zero with v, hv197rw [vanish, nat.zero] at hi198exfalso199exact empty.membership at i with hi200 . exact empty.subset at weightedPairs(V, w)201unfold natSum202rw none203exact cardinality.empty204205-- A sum may be restricted to a subset outside which the weights vanish.206theorem natSum.restrict (V S w : Set)207requires finite : Finite(V)208requires subset : S ⊆ V209requires weights : ∀ v ∈ V, w(v) ∈ ℕ210requires outside : ∀ v ∈ V ∖ S, w(v) =0211shows natSum(V, w) = natSum(S, w)212proof213have finiteS := Finite.subset with finite, subset214have restSubset := difference.subset_left at V, S215have finiteRest := Finite.subset with finite, restSubset216have weightsS : ∀ v ∈ S, w(v) ∈ ℕ217intros v hv218exact weights with v, (subset with v, hv)219have weightsRest : ∀ v ∈ V ∖ S, w(v) ∈ ℕ220intros v hv221exact weights with v, (restSubset with v, hv)222have apart : Disjoint(S, V ∖ S) := Disjoint.difference_right at V, S223have cover : S ∪ (V ∖ S) = V := difference.union2_of_subset with subset224havesplit:= natSum.union_disjoint225with finiteS, finiteRest, weightsS, weightsRest, apart226have vanish := natSum.zero_weights at V ∖ S, w with outside227have natural := natSum.natural with finiteS, weightsS228have unit := add.right_unit at natSum(S, w)229rw [cover, vanish, unit] atsplit230exactsplit231232-- A sum of even weights is even.233theorem natSum.even_of_even_weights_of_size (w : Set, n : Nat)234shows∀ V, Finite(V) → cardinality(V) = n →235 (∀ v ∈ V, w(v) ∈ ℕ) → (∀ v ∈ V, Even(w(v))) →236 Even(natSum(V, w))237proof238induction n239| zero =>240intros V finite size weights even241have has := cardinality.correct with finite242rw size at has243have empty := HasCardinality.empty_of_zero at V with has244rw [empty, natSum.empty]245exact Even.zero246| succ(k) using ih =>247intros V finite size weights even248have has := cardinality.correct with finite249rw size at has250obtain⟨a, ha⟩:= HasCardinality.exists_member with has251have removed := cardinality.remove with finite, ha252rw size at removed253have smaller := Naturals.injective.succ with removed254have restSize : cardinality(V ∖ {a}) = k255 symm256exact smaller257have restSubset := difference.subset_left at V, {a}258have restFinite := Finite.subset with finite, restSubset259have restWeights : ∀ v ∈ V ∖ {a}, w(v) ∈ ℕ260intros v hv261have parts := difference.singleton_membership.forward with hv262exact weights with v, parts.left263have restEven : ∀ v ∈ V ∖ {a}, Even(w(v))264intros v hv265have parts := difference.singleton_membership.forward with hv266exact even with v, parts.left267have rest := ih with V ∖ {a}, restFinite, restSize, restWeights, restEven268have fresh : ¬a ∈ V ∖ {a}269intro inside270have parts := difference.singleton_membership.forward with inside271apply parts.right272rfl273have restore := insert.restore with ha274have weightA := weights with a, ha275have evenA := even with a, ha276have inserted := natSum.insert at V ∖ {a}, w, a277with restFinite, restWeights, weightA, fresh278rw restore at inserted279rw inserted280exact Even.add with rest, evenA281282-- Reindexing: a bijection f : S → T carries the weighted pairs of the283-- pulled-back weights v(s) = w(f(s)) onto those of w.284285286-- The same for a finite set, with no size parameter.287theorem natSum.even_of_even_weights (V w : Set)288requires finite : Finite(V)289requires weights : ∀ v ∈ V, w(v) ∈ ℕ290requires even : ∀ v ∈ V, Even(w(v))291shows Even(natSum(V, w))292proof293have correct := cardinality.correct with finite294have natural := correct.left295have size : cardinality(V) = cardinality(V) byrfl296exact natSum.even_of_even_weights_of_size at w, cardinality(V)297with natural, V, finite, size, weights, even298299defgraph reindexPairs (f S T v w : Set) (p ∈ weightedPairs(S, v)) :300 weightedPairs(T, w) := (f(fst(p)), snd(p))301requires fFunction : f : S → T302requires values : ∀ s ∈ S, v(s) = w(f(s))303proof304have parts := weightedPairs.membership.forward with member305obtain⟨s, hs, i, hi, shape⟩:= parts.right306have bound := parts.left307rw shape at bound308have coordinates := product.pair_membership.forward with bound309have image := FunctionBetween.apply_closed with fFunction, hs310have equal := values with s, hs311rw equal at hi312have boundT : (f(s), i) ∈ T × ℕ :=313 product.pair with image, coordinates.right314have same : (f(s), i) = (f(s), i) byrfl315rw [shape, fst.pair, snd.pair]316exact weightedPairs.membership.backward with317⟨boundT, f(s), image, i, hi, same⟩318319theorem reindexPairs.pair (f S T v w s i : Set)320requires fFunction : f : S → T321requires values : ∀ s ∈ S, v(s) = w(f(s))322requires member : (s, i) ∈ weightedPairs(S, v)323shows reindexPairs(f, S, T, v, w)((s, i)) = (f(s), i)324proof325have value := reindexPairs.value at f, S, T, v, w, (s, i) with fFunction,326 values, member327rw [value, fst.pair, snd.pair]328rfl329330theorem reindexPairs.injective (f S T v w : Set)331requires injective : InjectiveBetween(f, S, T)332requires values : ∀ s ∈ S, v(s) = w(f(s))333shows InjectiveBetween(reindexPairs(f, S, T, v, w), weightedPairs(S, v),334 weightedPairs(T, w))335proof336have fFunction := Injective.function with injective337have function := reindexPairs.function at f, S, T, v, w with fFunction, values338refine⟨function, _⟩339intros x hx y hy z hz relatesX relatesY340have partsX := weightedPairs.membership.forward with hx341obtain⟨s, hs, i, hi, shapeX⟩:= partsX.right342have partsY := weightedPairs.membership.forward with hy343obtain⟨t, ht, j, hj, shapeY⟩:= partsY.right344have valueX := FunctionBetween.apply_value with function, hx, relatesX345have valueY := FunctionBetween.apply_value with function, hy, relatesY346rw shapeX at hx347rw shapeY at hy348rw shapeX at valueX349rw shapeY at valueY350have pairX := reindexPairs.pair with fFunction, values, hx351have pairY := reindexPairs.pair with fFunction, values, hy352have same : (f(s), i) = (f(t), j) bycc353have coordinates := orderedPair.injective with same354have imageS := FunctionBetween.relates_apply with fFunction, hs355have imageT := FunctionBetween.relates_apply with fFunction, ht356have imageIn := FunctionBetween.apply_closed with fFunction, hs357rw coordinates.left at imageS358rw coordinates.left at imageIn359have sameInput : s = t := Injective.cancel with*360rw [shapeX, shapeY, sameInput, coordinates.right]361rfl362363theorem reindexPairs.surjective (f S T v w : Set)364requires bijective : BijectiveBetween(f, S, T)365requires values : ∀ s ∈ S, v(s) = w(f(s))366shows SurjectiveBetween(reindexPairs(f, S, T, v, w), weightedPairs(S, v),367 weightedPairs(T, w))368proof369have injective := Bijective.injective with bijective370have surjective := Bijective.surjective with bijective371have fFunction := Injective.function with injective372have function := reindexPairs.function at f, S, T, v, w with fFunction, values373refine⟨function, _⟩374intros z hz375have parts := weightedPairs.membership.forward with hz376obtain⟨t, ht, j, hj, shape⟩:= parts.right377have bound := parts.left378rw shape at bound379have coordinates := product.pair_membership.forward with bound380obtain⟨s, hs, relatesS⟩:= surjective.right with t, ht381have image := FunctionBetween.apply_value with fFunction, hs, relatesS382have equal := values with s, hs383rw image at equal384rw← equal at hj385have boundS : (s, j) ∈ S × ℕ := product.pair with hs, coordinates.right386have same : (s, j) = (s, j) byrfl387have memberS : (s, j) ∈ weightedPairs(S, v) :=388 weightedPairs.membership.backward with⟨boundS, s, hs, j, hj, same⟩389have value := reindexPairs.pair with fFunction, values, memberS390have relates := FunctionBetween.relates_apply with function, memberS391rw [value, image, ← shape] at relates392exact⟨(s, j), memberS, relates⟩393394theorem reindexPairs.bijective (f S T v w : Set)395requires bijective : BijectiveBetween(f, S, T)396requires values : ∀ s ∈ S, v(s) = w(f(s))397shows BijectiveBetween(reindexPairs(f, S, T, v, w), weightedPairs(S, v),398 weightedPairs(T, w))399proof400have injective := Bijective.injective with bijective401have pairsInjective := reindexPairs.injective with injective, values402have pairsSurjective := reindexPairs.surjective with bijective, values403exact⟨pairsInjective, pairsSurjective⟩404405-- The sum of w over T is the sum over S of the pulled-back weights.406theorem natSum.reindex (f S T v w : Set)407requires finite : Finite(S)408requires bijective : BijectiveBetween(f, S, T)409requires weights : ∀ t ∈ T, w(t) ∈ ℕ410requires values : ∀ s ∈ S, v(s) = w(f(s))411shows natSum(T, w) = natSum(S, v)412proof413have injective := Bijective.injective with bijective414have fFunction := Injective.function with injective415have weightsS : ∀ s ∈ S, v(s) ∈ ℕ416intros s hs417have equal := values with s, hs418have image := FunctionBetween.apply_closed with fFunction, hs419rw equal420exact weights with f(s), image421have size : cardinality(S) = cardinality(S) byrfl422have correct := cardinality.correct with finite423have cardNat := correct.left424have pairsFinite := weightedPairs.finite with finite, size, weightsS425have pairsBijective := reindexPairs.bijective with bijective, values426have same := cardinality.bijective with pairsFinite, pairsBijective427unfold natSum428rw same429430-- The weight (d, e) ↦ w(d) · u(e) on a product set.431defgraph weightProduct (D E w u : Set) (q ∈ D × E) : ℕ :=432 w(fst(q)) * u(snd(q))433requires weightsD : ∀ d ∈ D, w(d) ∈ ℕ434requires weightsE : ∀ e ∈ E, u(e) ∈ ℕ435proof436obtain⟨bound, d, hd, e, he, shape⟩:=437 product.membership.forward with member438have dNat := nat.omega.backward with (weightsD with d, hd)439have eNat := nat.omega.backward with (weightsE with e, he)440have productNat : Nat(w(d) * u(e)) bytypecheck441rw [shape, fst.pair, snd.pair]442exact nat.omega.forward with productNat443444theorem weightProduct.pair (D E w u d e : Set)445requires weightsD : ∀ d ∈ D, w(d) ∈ ℕ446requires weightsE : ∀ e ∈ E, u(e) ∈ ℕ447requires hd : d ∈ D448requires he : e ∈ E449shows weightProduct(D, E, w, u)((d, e)) = w(d) * u(e)450proof451have pairMember := product.pair with hd, he452have value := weightProduct.value at D, E, w, u, (d, e) with weightsD,453 weightsE, pairMember454rw [value, fst.pair, snd.pair]455rfl456457-- The weighted pairs of a product: ((d, i), (e, j)) ↦ ((d, e), k) with k the458-- position of (i, j) in the enumeration of w(d) × u(e) by w(d) · u(e).459defgraph productPairs (D E w u : Set)460 (q ∈ weightedPairs(D, w) × weightedPairs(E, u)) :461 weightedPairs(D × E, weightProduct(D, E, w, u)) :=462 ((fst(fst(q)), fst(snd(q))),463 natProductEquiv(w(fst(fst(q))), u(fst(snd(q))))((snd(fst(q)), snd(snd(q)))))464requires weightsD : ∀ d ∈ D, w(d) ∈ ℕ465requires weightsE : ∀ e ∈ E, u(e) ∈ ℕ466proof467obtain⟨bound, x, hx, y, hy, shape⟩:=468 product.membership.forward with member469have partsX := weightedPairs.membership.forward with hx470obtain⟨d, hd, i, hi, shapeX⟩:= partsX.right471have partsY := weightedPairs.membership.forward with hy472obtain⟨e, he, j, hj, shapeY⟩:= partsY.right473have dNat := nat.omega.backward with (weightsD with d, hd)474have eNat := nat.omega.backward with (weightsE with e, he)475have equiv := natProductEquiv.bijective at u(e), w(d)476have equivFunction := Injective.function with (Bijective.injective with equiv)477have pairIJ := product.pair with hi, hj478have kMember := FunctionBetween.apply_closed with equivFunction, pairIJ479have naturals := natural.member at w(d) * u(e)480have kNat := naturals with natProductEquiv(w(d), u(e))((i, j)), kMember481have kIn := nat.omega.forward with kNat482have weightValue := weightProduct.pair with weightsD, weightsE, hd, he483rw← weightValue at kMember484have deMember := product.pair with hd, he485have boundQ := product.pair with deMember, kIn486have same : ((d, e), natProductEquiv(w(d), u(e))((i, j))) =487 ((d, e), natProductEquiv(w(d), u(e))((i, j))) byrfl488rw [shape, shapeX, shapeY]489simp [fst.pair, snd.pair]490exact weightedPairs.membership.backward with491⟨boundQ, (d, e), deMember, natProductEquiv(w(d), u(e))((i, j)), kMember,492 same⟩493494theorem productPairs.pair (D E w u d i e j : Set)495requires weightsD : ∀ d ∈ D, w(d) ∈ ℕ496requires weightsE : ∀ e ∈ E, u(e) ∈ ℕ497requires hx : (d, i) ∈ weightedPairs(D, w)498requires hy : (e, j) ∈ weightedPairs(E, u)499shows productPairs(D, E, w, u)(((d, i), (e, j))) =500 ((d, e), natProductEquiv(w(d), u(e))((i, j)))501proof502have pairMember := product.pair with hx, hy503have value := productPairs.value at D, E, w, u, ((d, i), (e, j)) with504 weightsD, weightsE, pairMember505rw value506simp [fst.pair, snd.pair]507508theorem productPairs.injective (D E w u : Set)509requires weightsD : ∀ d ∈ D, w(d) ∈ ℕ510requires weightsE : ∀ e ∈ E, u(e) ∈ ℕ511shows InjectiveBetween(productPairs(D, E, w, u),512 weightedPairs(D, w) × weightedPairs(E, u),513 weightedPairs(D × E, weightProduct(D, E, w, u)))514proof515have function := productPairs.function at D, E, w, u with weightsD, weightsE516refine⟨function, _⟩517intros x hx y hy z hz relatesX relatesY518obtain⟨boundX, x1, hx1, x2, hx2, shapeX⟩:=519 product.membership.forward with hx520obtain⟨boundY, y1, hy1, y2, hy2, shapeY⟩:=521 product.membership.forward with hy522have partsX1 := weightedPairs.membership.forward with hx1523obtain⟨d, hd, i, hi, shapeX1⟩:= partsX1.right524have partsX2 := weightedPairs.membership.forward with hx2525obtain⟨e, he, j, hj, shapeX2⟩:= partsX2.right526have partsY1 := weightedPairs.membership.forward with hy1527obtain⟨d2, hd2, i2, hi2, shapeY1⟩:= partsY1.right528have partsY2 := weightedPairs.membership.forward with hy2529obtain⟨e2, he2, j2, hj2, shapeY2⟩:= partsY2.right530have valueX := FunctionBetween.apply_value with function, hx, relatesX531have valueY := FunctionBetween.apply_value with function, hy, relatesY532rw shapeX1 at hx1533rw shapeX2 at hx2534rw shapeY1 at hy1535rw shapeY2 at hy2536rw [shapeX, shapeX1, shapeX2] at valueX537rw [shapeY, shapeY1, shapeY2] at valueY538have pairX := productPairs.pair with weightsD, weightsE, hx1, hx2539have pairY := productPairs.pair with weightsD, weightsE, hy1, hy2540have same : ((d, e), natProductEquiv(w(d), u(e))((i, j))) =541 ((d2, e2), natProductEquiv(w(d2), u(e2))((i2, j2))) bycc542have outer := orderedPair.injective with same543have inner := orderedPair.injective with outer.left544have dEqual := inner.left545have eEqual := inner.right546have positions := outer.right547rw [← dEqual, ← eEqual] at positions548rw← dEqual at hi2549rw← eEqual at hj2550have dNat := nat.omega.backward with (weightsD with d, hd)551have eNat := nat.omega.backward with (weightsE with e, he)552have equiv := natProductEquiv.bijective at u(e), w(d)553have equivInjective := Bijective.injective with equiv554have equivFunction := Injective.function with equivInjective555have pairIJ := product.pair with hi, hj556have pairIJ2 := product.pair with hi2, hj2557have relatesIJ := FunctionBetween.relates_apply with equivFunction, pairIJ558have relatesIJ2 := FunctionBetween.relates_apply with equivFunction, pairIJ2559have kMember := FunctionBetween.apply_closed with equivFunction, pairIJ2560rw positions at relatesIJ561have sameInput := Injective.cancel at natProductEquiv(w(d), u(e)),562 w(d) × u(e), w(d) * u(e), (i, j), (i2, j2),563 natProductEquiv(w(d), u(e))((i2, j2)) with equivInjective, pairIJ,564 pairIJ2, kMember, relatesIJ, relatesIJ2565have coordinates := orderedPair.injective with sameInput566rw [shapeX, shapeY, shapeX1, shapeX2, shapeY1, shapeY2, ← dEqual,567← eEqual, ← coordinates.left, ← coordinates.right]568rfl569570theorem productPairs.surjective (D E w u : Set)571requires weightsD : ∀ d ∈ D, w(d) ∈ ℕ572requires weightsE : ∀ e ∈ E, u(e) ∈ ℕ573shows SurjectiveBetween(productPairs(D, E, w, u),574 weightedPairs(D, w) × weightedPairs(E, u),575 weightedPairs(D × E, weightProduct(D, E, w, u)))576proof577have function := productPairs.function at D, E, w, u with weightsD, weightsE578refine⟨function, _⟩579intros z hz580have parts := weightedPairs.membership.forward with hz581obtain⟨p, hp, k, hk, shape⟩:= parts.right582obtain⟨boundP, d, hd, e, he, shapeP⟩:=583 product.membership.forward with hp584have weightValue := weightProduct.pair with weightsD, weightsE, hd, he585rw [shapeP, weightValue] at hk586have dNat := nat.omega.backward with (weightsD with d, hd)587have eNat := nat.omega.backward with (weightsE with e, he)588have equiv := natProductEquiv.bijective at u(e), w(d)589have equivSurjective := Bijective.surjective with equiv590have equivFunction := Injective.function with (Bijective.injective with equiv)591obtain⟨r, hr, relatesR⟩:= equivSurjective.right with k, hk592obtain⟨boundR, i, hi, j, hj, shapeR⟩:=593 product.membership.forward with hr594have iNat := natural.member at w(d) with i, hi595have jNat := natural.member at u(e) with j, hj596have iIn := nat.omega.forward with iNat597have jIn := nat.omega.forward with jNat598have boundX := product.pair with hd, iIn599have boundY := product.pair with he, jIn600have sameX : (d, i) = (d, i) byrfl601have sameY : (e, j) = (e, j) byrfl602have memberX : (d, i) ∈ weightedPairs(D, w) :=603 weightedPairs.membership.backward with⟨boundX, d, hd, i, hi, sameX⟩604have memberY : (e, j) ∈ weightedPairs(E, u) :=605 weightedPairs.membership.backward with⟨boundY, e, he, j, hj, sameY⟩606have memberQ := product.pair with memberX, memberY607have value := productPairs.pair with weightsD, weightsE, memberX, memberY608have kValue := FunctionBetween.apply_value with equivFunction, hr, relatesR609rw shapeR at kValue610have relates := FunctionBetween.relates_apply with function, memberQ611rw [value, kValue, ← shapeP, ← shape] at relates612exact⟨((d, i), (e, j)), memberQ, relates⟩613614theorem productPairs.bijective (D E w u : Set)615requires weightsD : ∀ d ∈ D, w(d) ∈ ℕ616requires weightsE : ∀ e ∈ E, u(e) ∈ ℕ617shows BijectiveBetween(productPairs(D, E, w, u),618 weightedPairs(D, w) × weightedPairs(E, u),619 weightedPairs(D × E, weightProduct(D, E, w, u)))620proof621have injective := productPairs.injective with weightsD, weightsE622have surjective := productPairs.surjective with weightsD, weightsE623exact⟨injective, surjective⟩624625-- The sum of w(d) · u(e) over D × E is the product of the two sums.626theorem natSum.product (D E w u : Set)627requires finiteD : Finite(D)628requires finiteE : Finite(E)629requires weightsD : ∀ d ∈ D, w(d) ∈ ℕ630requires weightsE : ∀ e ∈ E, u(e) ∈ ℕ631shows natSum(D × E, weightProduct(D, E, w, u)) = natSum(D, w) * natSum(E, u)632proof633have sizeD : cardinality(D) = cardinality(D) byrfl634have sizeE : cardinality(E) = cardinality(E) byrfl635have correctD := cardinality.correct with finiteD636have cardNatD := correctD.left637have correctE := cardinality.correct with finiteE638have cardNatE := correctE.left639have pairsD := weightedPairs.finite with finiteD, sizeD, weightsD640have pairsE := weightedPairs.finite with finiteE, sizeE, weightsE641have pairsFinite := Finite.product with pairsD, pairsE642have bijective := productPairs.bijective with weightsD, weightsE643have same := cardinality.bijective with pairsFinite, bijective644have countD := cardinality.correct with pairsD645have countE := cardinality.correct with pairsE646have countProduct := HasCardinality.product with countD, countE647have productValue := cardinality.eq_of_has with countProduct648unfold natSum649rw [← same, productValue]650rfl651