1-- Block sums of a point of the cube: each term is the coordinate or zero,2-- the sum is nonnegative and at least any selected coordinate, and it3-- transforms linearly under a common affine change of the selected coordinates4-- Part of Cumulus, the Grace17 mathematics library.5-- Copyright (c) 2026 Grant Passmore.6-- Released under the Apache License 2.0. See LICENSE in the repository root.7-- Authors: Grant Passmore89module Grace.Cumulus.FixedPoint.BlockSums10import CubeAssembly1112-- A masked term is the coordinate on the block and zero off it.13theorem maskedPoint.on_block (n : Nat) (S x i : Set)14requires xFunction : x : n → ℝ15requires hi : i ∈ n16requires inBlock : i ∈ S17shows maskedPoint(n, S, x)(i) = x(i)18proof19have value := maskedPoint.coordinate at n, S, x, i with xFunction, hi20have one := indicator.member with inBlock21have xi := FunctionBetween.apply_closed with xFunction, hi22rw [value, one, realNat.one]23exact realMulValue.one_left2425theorem maskedPoint.off_block (n : Nat) (S x i : Set)26requires xFunction : x : n → ℝ27requires hi : i ∈ n28requires outside : ¬i ∈ S29shows maskedPoint(n, S, x)(i) = (0:R)30proof31have value := maskedPoint.coordinate at n, S, x, i with xFunction, hi32have zero := indicator.absent with outside33have xi := FunctionBetween.apply_closed with xFunction, hi34rw [value, zero, realNat.zero]35exact realMulValue.zero_left3637theorem maskedPoint.nonnegative (n : Nat) (S x i : Set)38requires hx : x ∈ unitCube(n)39requires hi : i ∈ n40shows (0:R) ≤ (maskedPoint(n, S, x)(i):R)41proof42have xFunction := unitCube.point with hx43have alternatives : i ∈ S ∨¬i ∈ S bytauto44cases alternatives with inBlock | outside45 . have same := maskedPoint.on_block with xFunction, hi, inBlock46have interval := unitCube.coordinate with hx, hi47obtain⟨xReal, lower, upper⟩:= closedInterval.membership.forward with interval48 rwa same49 . have same := maskedPoint.off_block with xFunction, hi, outside50rw same51linarith5253-- Partial sums of nonnegative terms are nonnegative and bound every term.54theorem realPartialSum.nonnegative_prefix (u : Set) (m : Nat)55requires sequence : RealSequence(u)56shows (∀ k ∈ m, (0:R) ≤ (u(k):R)) → (0:R) ≤ (realPartialSum(u, m):R)57proof58induction m59| zero =>60intro terms61have zero := realPartialSum.zero at u62rw zero63linarith64| succ(j) using ih =>65intro terms66have jNat : Nat(j) bytypecheck67have last := terms with (bootstrap.succ.self at j)68have smaller : ∀ k ∈ j, (0:R) ≤ (u(k):R)69intros k hk70have kNat := natural.member at j with hk71have less := Less.of_membership with hk72have below : k < succ(j) byarith73have inSucc : k ∈ succ(j)74exact membership.of_Less with below75exact terms with inSucc76have previous := ih with smaller77have step := realPartialSum.succ at u, j78have lastReal := RealSequence.value at u, j with sequence79rw step80linarith8182theorem realPartialSum.term_le_prefix (u : Set) (m : Nat)83requires sequence : RealSequence(u)84shows (∀ k ∈ m, (0:R) ≤ (u(k):R)) →∀ j ∈ m, (u(j):R) ≤ (realPartialSum(u, m):R)85proof86induction m87| zero =>88intros terms j hj89exfalso90rw nat.zero at hj91 simpa using hj92| succ(i) using ih =>93intros terms j hj94have iNat : Nat(i) bytypecheck95have smaller : ∀ k ∈ i, (0:R) ≤ (u(k):R)96intros k hk97have kNat := natural.member at i with hk98have less := Less.of_membership with hk99have below : k < succ(i) byarith100have inSucc : k ∈ succ(i)101exact membership.of_Less with below102exact terms with inSucc103have nonnegative := realPartialSum.nonnegative_prefix at u, i with sequence104have prefixNonneg := nonnegative with smaller105have step := realPartialSum.succ at u, i106have lastReal := RealSequence.value at u, i with sequence107have last := terms with (bootstrap.succ.self at i)108havesplit:= bootstrap.succ.membership.forward with hj109rw step110casessplitwith below | same111 . have bounds := ih with smaller112have bound := bounds with below113have jNat := natural.member at i with below114have jReal := RealSequence.value at u, j with sequence115linarith116 . rw same117linarith118119-- Block sums are nonnegative and at least any selected coordinate.120theorem sumCube.terms_nonnegative (n : Nat) (S x : Set)121requires hx : x ∈ unitCube(n)122shows∀ k ∈ n, (0:R) ≤ (maskedPoint(n, S, x)(k):R)123proof124intros k hk125exact maskedPoint.nonnegative with hx, hk126127theorem sumCube.nonnegative (n : Nat) (S x : Set)128requires hx : x ∈ unitCube(n)129shows (0:R) ≤ (sumCube(n, S)(x):R)130proof131have xFunction := unitCube.point with hx132have sequence := maskedPoint.sequence at n, S, x with xFunction133have value := sumCube.value at n, S, x with hx134have terms := sumCube.terms_nonnegative at n, S, x with hx135have bound := realPartialSum.nonnegative_prefix with sequence136rw value137exact bound with terms138139theorem sumCube.ge_coordinate (n : Nat) (S x j : Set)140requires hx : x ∈ unitCube(n)141requires hj : j ∈ n142requires inBlock : j ∈ S143shows (x(j):R) ≤ (sumCube(n, S)(x):R)144proof145have xFunction := unitCube.point with hx146have sequence := maskedPoint.sequence at n, S, x with xFunction147have value := sumCube.value at n, S, x with hx148have terms := sumCube.terms_nonnegative at n, S, x with hx149have bounds := realPartialSum.term_le_prefix with sequence150have forAll := bounds with terms151have bound := forAll with hj152have same := maskedPoint.on_block with xFunction, hj, inBlock153rw value154 rwa same at bound155156-- When the selected coordinates of z are an affine image of those of x and a,157-- the block sum of z is the same affine image of the block sums of x and a.158theorem sumCube.affine (n : Nat) (S x a z : Set) (E C : Real)159requires hx : x ∈ unitCube(n)160requires ha : a ∈ unitCube(n)161requires hz : z ∈ unitCube(n)162requires shifted : ∀ j ∈ n, j ∈ S → z(j) = ((x(j):R) + E * (a(j):R)) * C163shows sumCube(n, S)(z) = ((sumCube(n, S)(x):R) + E * (sumCube(n, S)(a):R)) * C164proof165have xFunction := unitCube.point with hx166have aFunction := unitCube.point with ha167have zFunction := unitCube.point with hz168have maskedX := maskedPoint.sequence at n, S, x with xFunction169have maskedA := maskedPoint.sequence at n, S, a with aFunction170have maskedZ := maskedPoint.sequence at n, S, z with zFunction171have constantE := constantSequence.sequence at E172have constantC := constantSequence.sequence at C173have scaledA := mulSequence.sequence with constantE, maskedA174have inner := addSequence.sequence with maskedX, scaledA175have agree : ∀ k ∈ ℕ, k < n → maskedPoint(n, S, z)(k) = mulSequence(constantSequence(C), addSequence(maskedPoint(n, S, x), mulSequence(constantSequence(E), maskedPoint(n, S, a))))(k)176intros k hk hkn177have kNat : Nat(k) bytypecheck178have hkIn : k ∈ n byexact membership.of_Less with hkn179have xReal := RealSequence.value at maskedPoint(n, S, x), k with maskedX180have aReal := RealSequence.value at maskedPoint(n, S, a), k with maskedA181have eReal := RealSequence.value at constantSequence(E), k with constantE182have cReal := RealSequence.value at constantSequence(C), k with constantC183have eValue := constantSequence.value at E, k184have cValue := constantSequence.value at C, k185have scaledValue := mulSequence.value with constantE, maskedA, eReal, aReal186have scaledReal := RealSequence.value at mulSequence(constantSequence(E), maskedPoint(n, S, a)), k with scaledA187have innerValue := addSequence.value with maskedX, scaledA, xReal, scaledReal188have innerReal := RealSequence.value at addSequence(maskedPoint(n, S, x), mulSequence(constantSequence(E), maskedPoint(n, S, a))), k with inner189have outerValue := mulSequence.value with constantC, inner, cReal, innerReal190rw [outerValue, innerValue, scaledValue, eValue, cValue]191have alternatives : k ∈ S ∨¬k ∈ S bytauto192cases alternatives with inBlock | outside193 . have zSame := maskedPoint.on_block with zFunction, hkIn, inBlock194have xSame := maskedPoint.on_block with xFunction, hkIn, inBlock195have aSame := maskedPoint.on_block with aFunction, hkIn, inBlock196have zValue := shifted with hkIn, inBlock197have xk := unitCube.coordinate_real with hx, hkIn198have ak := unitCube.coordinate_real with ha, hkIn199rw [zSame, xSame, aSame, zValue]200ring201 . have zSame := maskedPoint.off_block with zFunction, hkIn, outside202have xSame := maskedPoint.off_block with xFunction, hkIn, outside203have aSame := maskedPoint.off_block with aFunction, hkIn, outside204rw [zSame, xSame, aSame]205ring206have outer := mulSequence.sequence with constantC, inner207have equal := realPartialSum.eq_prefix with maskedZ, outer, agree208have scaleC := realPartialSum.scale at addSequence(maskedPoint(n, S, x), mulSequence(constantSequence(E), maskedPoint(n, S, a))), n, C with inner209have addXA := realPartialSum.add with maskedX, scaledA210have scaleE := realPartialSum.scale at maskedPoint(n, S, a), n, E with maskedA211have zValue := sumCube.value at n, S, z with hz212have xValue := sumCube.value at n, S, x with hx213have aValue := sumCube.value at n, S, a with ha214rw [zValue, xValue, aValue, equal, scaleC, addXA, scaleE]215ring216