1-- Cauchy–Schwarz for arbitrary finite-dimensional real vectors2-- 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 Passmore67-- Mathematical source: imandra-ai/imandra-100-theorems, src/cauchy_schwarz.iml.8-- Sequences restricted to n coordinates replace the source's equal-length lists.910module Grace.Cumulus.LinearAlgebra.CauchySchwarz11import FiniteDimensional1213theorem dotProduct.zero_of_squaredNorm_zero (u v : Set, n : Nat)14requires sequenceU : RealSequence(u)15requires sequenceV : RealSequence(v)16shows squaredNorm(v, n) = (0:R) → dotProduct(u, v, n) = (0:R)17proof18induction n19| zero =>20intro zero21exact dotProduct.zero at u, v22| succ(k) using ih =>23intro zero24have uk := RealSequence.value at u, k with*25have vk := RealSequence.value at v, k with*26have nonnegative := squaredNorm.nonnegative at v, k with*27have squareNonnegative := realMulValue.square_nonnegative at v[k] with*28rw squaredNorm.succ at zero29have prefixZero := realAddValue.nonnegative_eq_zero at squaredNorm(v, k), v[k] * v[k] with*30have squareZero : (v[k]:R) * (v[k]:R) =031 . rw prefixZero at zero32 simpa [realAddValue.zero_left] using zero33have valueZero := realMulValue.square_eq_zero_iff.forward at v[k] with*34have dotZero := ih with prefixZero35rw [dotProduct.succ, dotZero, valueZero]36ring3738theorem squaredNorm.scaled_difference (u v : Set, C D : Real, n : Nat)39requires sequenceU : RealSequence(u)40requires sequenceV : RealSequence(v)41shows squaredNorm(subSequence(mulSequence(constantSequence(C), u), mulSequence(constantSequence(D), v)), n) =42 C * C * (squaredNorm(u, n):R) - (2:R) * C * D * (dotProduct(u, v, n):R) + D * D * (squaredNorm(v, n):R)43proof44have constantC := constantSequence.sequence at C with*45have constantD := constantSequence.sequence at D with*46have scaledU := mulSequence.sequence at constantSequence(C), u with*47have scaledV := mulSequence.sequence at constantSequence(D), v with*48simp [squaredNorm.sub, squaredNorm.scale, dotProduct.scale_left, dotProduct.scale_right]49ring5051theorem dotProduct.cauchy_schwarz (u v : Set, n : Nat)52requires sequenceU : RealSequence(u)53requires sequenceV : RealSequence(v)54shows (dotProduct(u, v, n):R) * (dotProduct(u, v, n):R) ≤55 (squaredNorm(u, n):R) * (squaredNorm(v, n):R)56proof57have normNonnegative := squaredNorm.nonnegative at v, n with*58havecases : squaredNorm(v, n) = (0:R) ∨ squaredNorm(v, n) ≠ (0:R)59 . tauto60casescaseswith zero | nonzero61 . have dotZero := dotProduct.zero_of_squaredNorm_zero at u, v, n with*62rw [dotZero, zero]63 simpa [realMulValue.zero_left, realMulValue.zero_right] using realLe.reflexive at realZero with*64 . have positive :=Real.positive_of_nonnegative_of_ne_zero with*65have constantNorm := constantSequence.sequence at squaredNorm(v, n) with*66have constantDot := constantSequence.sequence at dotProduct(u, v, n) with*67have scaledU := mulSequence.sequence at constantSequence(squaredNorm(v, n)), u with*68have scaledV := mulSequence.sequence at constantSequence(dotProduct(u, v, n)), v with*69have difference := subSequence.sequence at mulSequence(constantSequence(squaredNorm(v, n)), u), mulSequence(constantSequence(dotProduct(u, v, n)), v) with*70have nonnegative := squaredNorm.nonnegative at subSequence(mulSequence(constantSequence(squaredNorm(v, n)), u), mulSequence(constantSequence(dotProduct(u, v, n)), v)), n with*71have expansion := squaredNorm.scaled_difference at u, v, squaredNorm(v, n), dotProduct(u, v, n), n with*72rw expansion at nonnegative73have rearrange : (squaredNorm(v, n):R) * (squaredNorm(v, n):R) * (squaredNorm(u, n):R) - (2:R) * (squaredNorm(v, n):R) * (dotProduct(u, v, n):R) * (dotProduct(u, v, n):R) + (dotProduct(u, v, n):R) * (dotProduct(u, v, n):R) * (squaredNorm(v, n):R) =74 ((squaredNorm(u, n):R) * (squaredNorm(v, n):R)) * (squaredNorm(v, n):R) - ((dotProduct(u, v, n):R) * (dotProduct(u, v, n):R)) * (squaredNorm(v, n):R)75 . ring76rw rearrange at nonnegative77have products := realLe.of_nonnegative_difference with*78exact realLe.mul_right_cancel_positive with*7980theorem dotProduct.cauchy_schwarz_scalar_equality (v : Set, C : Real, n : Nat)81requires sequence : RealSequence(v)82shows (dotProduct(mulSequence(constantSequence(C), v), v, n):R) *83 (dotProduct(mulSequence(constantSequence(C), v), v, n):R) =84 (squaredNorm(mulSequence(constantSequence(C), v), n):R) * (squaredNorm(v, n):R)85proof86have constants := constantSequence.sequence with*87have scaled := mulSequence.sequence at constantSequence(C), v with*88simp [dotProduct.scale_left, squaredNorm.scale]89unfold squaredNorm90ring9192-- A zero norm is exactly coordinatewise zero on the observed prefix.93theorem squaredNorm.zero_prefix (u : Set, n : Nat)94requires sequence : RealSequence(u)95shows squaredNorm(u, n) = (0:R) →∀ i ∈ ℕ, i < n → u[i] = (0:R)96proof97induction n98| zero =>99intros zero i member before100have naturalI := nat.omega.backward with member101have impossible : i < i102 . arith103exfalso104exact Less.irreflexive with naturalI, impossible105| succ(k) using ih =>106intros zero i member before107have naturalI := nat.omega.backward with member108have uk := RealSequence.value at u, k with*109have nonnegative := squaredNorm.nonnegative at u, k with*110have squareNonnegative := realMulValue.square_nonnegative at u[k] with*111rw squaredNorm.succ at zero112have prefixZero := realAddValue.nonnegative_eq_zero at squaredNorm(u, k), u[k] * u[k] with*113have squareZero : (u[k]:R) * (u[k]:R) =0114 . rw prefixZero at zero115 simpa [realAddValue.zero_left] using zero116have valueZero := realMulValue.square_eq_zero_iff.forward at u[k] with*117have included := membership.of_Less at i, succ(k) with*, before118have alternatives := membership.successor_forward{n := k} with included119cases alternatives with earlier | equal120 . have smaller := Less.of_membership at i, k with*, earlier121exact ih with prefixZero, i, member, smaller122 . rw equal123exact valueZero124125theorem squaredNorm.of_zero_prefix (u : Set, n : Nat)126requires sequence : RealSequence(u)127shows (∀ i ∈ ℕ, i < n → u[i] = (0:R)) → squaredNorm(u, n) = (0:R)128proof129induction n130| zero =>131intro coordinates132unfold squaredNorm133exact dotProduct.zero at u, u134| succ(k) using ih =>135intro coordinates136haveprefix : ∀ i ∈ ℕ, i < k → u[i] = (0:R)137 . intros i member before138have naturalI := nat.omega.backward with member139have smaller : i < succ(k)140 . arith141exact coordinates with i, member, smaller142have zeroPrefix := ih withprefix143have memberK := nat.omega.forward at k with*144have beforeK : k < succ(k)145 . arith146have zeroLast := coordinates with k, memberK, beforeK147rw [squaredNorm.succ, zeroPrefix, zeroLast]148ring149150theorem squaredNorm.eq_zero_iff (u : Set, n : Nat)151requires sequence : RealSequence(u)152shows squaredNorm(u, n) = (0:R) ↔ (∀ i ∈ ℕ, i < n → u[i] = (0:R))153proof154constructor155 . exact squaredNorm.zero_prefix with*156 . exact squaredNorm.of_zero_prefix with*157158theorem squaredNorm.eq_prefix (u v : Set, n : Nat)159requires sequenceU : RealSequence(u)160requires sequenceV : RealSequence(v)161requires coordinates : ∀ i ∈ ℕ, i < n → u[i] = v[i]162shows squaredNorm(u, n) = squaredNorm(v, n)163proof164unfold squaredNorm165exact dotProduct.eq_prefix with*166167theorem dotProduct.cauchy_schwarz_equality_residual (u v : Set, n : Nat)168requires sequenceU : RealSequence(u)169requires sequenceV : RealSequence(v)170requires equality : (dotProduct(u, v, n):R) * (dotProduct(u, v, n):R) =171 (squaredNorm(u, n):R) * (squaredNorm(v, n):R)172shows squaredNorm(subSequence(mulSequence(constantSequence(squaredNorm(v, n)), u),173 mulSequence(constantSequence(dotProduct(u, v, n)), v)), n) = (0:R)174proof175rw squaredNorm.scaled_difference176linear_combination -(squaredNorm(v, n):R) * equality177178theorem dotProduct.cauchy_schwarz_equality_iff (u v : Set, n : Nat)179requires sequenceU : RealSequence(u)180requires sequenceV : RealSequence(v)181shows (dotProduct(u, v, n):R) * (dotProduct(u, v, n):R) =182 (squaredNorm(u, n):R) * (squaredNorm(v, n):R) ↔183 (squaredNorm(v, n) = (0:R) ∨184 (∃ C ∈ ℝ, (∀ i ∈ ℕ, i < n → u[i] = C * (v[i]:R))))185proof186constructor187 . intro equality188have alternatives : squaredNorm(v, n) = (0:R) ∨ squaredNorm(v, n) ≠ (0:R)189 . tauto190cases alternatives with zero | nonzero191 . left192exact zero193 . right194have inverseLaw := realInvValue.mul_right with*195have coefficient := realMulValue.real at dotProduct(u, v, n), realInvValue(squaredNorm(v, n)) with*196have coefficientMember : dotProduct(u, v, n) * realInvValue(squaredNorm(v, n)) ∈ ℝ197 . settlewithReal198refine⟨dotProduct(u, v, n) * realInvValue(squaredNorm(v, n)), coefficientMember, _⟩199intros i member before200have naturalI := nat.omega.backward with member201have ui := RealSequence.value at u, i with*202have vi := RealSequence.value at v, i with*203have constantNorm := constantSequence.sequence at squaredNorm(v, n) with*204have constantDot := constantSequence.sequence at dotProduct(u, v, n) with*205have scaledU := mulSequence.sequence at constantSequence(squaredNorm(v, n)), u with*206have scaledV := mulSequence.sequence at constantSequence(dotProduct(u, v, n)), v with*207have difference := subSequence.sequence at mulSequence(constantSequence(squaredNorm(v, n)), u), mulSequence(constantSequence(dotProduct(u, v, n)), v) with*208have normZero := dotProduct.cauchy_schwarz_equality_residual with*209have pointZero := squaredNorm.zero_prefix with*, normZero, i, member, before210have firstValue := RealSequence.value at mulSequence(constantSequence(squaredNorm(v, n)), u), i with*211have secondValue := RealSequence.value at mulSequence(constantSequence(dotProduct(u, v, n)), v), i with*212have normValue := RealSequence.value at constantSequence(squaredNorm(v, n)), i with*213have dotValue := RealSequence.value at constantSequence(dotProduct(u, v, n)), i with*214simp [subSequence.value, mulSequence.value, constantSequence.value] at pointZero215linear_combination realInvValue(squaredNorm(v, n)) * pointZero - (u[i]:R) * inverseLaw216 . intro alternatives217cases alternatives with zero | proportional218 . have dotZero := dotProduct.zero_of_squaredNorm_zero at u, v, n with*, zero219rw [dotZero, zero]220ring221 . obtain⟨C, memberC, coordinates⟩:= proportional222have realC : Real(C)223 . settlewithReal224have constants := constantSequence.sequence with*225have scaled := mulSequence.sequence at constantSequence(C), v with*226have equalPrefix : ∀ i ∈ ℕ, i < n → u[i] = mulSequence(constantSequence(C), v)[i]227 . intros i member before228have naturalI := nat.omega.backward with member229have vi := RealSequence.value at v, i with*230have ci := RealSequence.value at constantSequence(C), i with*231simp [mulSequence.value, constantSequence.value]232exact coordinates with i, member, before233have reflexive : ∀ i ∈ ℕ, i < n → v[i] = v[i]234 . intros i member before235rfl236have equalDot := dotProduct.eq_prefix at u, v, mulSequence(constantSequence(C), v), v, n with*237have equalNorm := squaredNorm.eq_prefix at u, mulSequence(constantSequence(C), v), n with*238rw [equalDot, equalNorm]239exact dotProduct.cauchy_schwarz_scalar_equality with*240