1-- Positive multiplication lemmas for the Dedekind real numbers2-- 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.Real.PositiveMultiplication8import Multiplication910-- Two points of a lower cut have a common point strictly above both. This is11-- the elementary directedness fact used whenever two open-cut witnesses must12-- be represented with a common factor.13theorem DedekindCut.exists_above_pair (A a b : Set)14requires cut : DedekindCut(A)15requires aInA : a ∈ A16requires bInA : b ∈ A17shows∃ c ∈ A,18 relates(rationalLess, a, c) ∧ relates(rationalLess, b, c)19proof20obtain⟨u, uInA, aLessU⟩:= DedekindCut.no_greatest with cut, aInA21by_contra noCommonUpper22have subset := DedekindCut.subset_rationals with cut23have uInQ := subset with u, uInA24have bInQ := subset with b, bInA25have aInQ := subset with a, aInA26have aRational : Rational(a) byexact aInQ27have uRational : Rational(u) byexact uInQ28have distinct : u ≠ b29intro equal30obtain⟨v, vInA, uLessV⟩:= DedekindCut.no_greatest with cut, uInA31have vInQ := subset with v, vInA32have vRational : Rational(v) byexact vInQ33apply noCommonUpper34refine⟨v, vInA, _, _⟩35 . exact rationalLess.transitive at a, u, v with36 aRational, uRational, vRational, aLessU, uLessV37 . rw← equal38exact uLessV39have connected := rationalLess.connected_on40have comparison := connected with u, uInQ, b, bInQ, distinct41cases comparison with uLessB | bLessU42 . obtain⟨w, wInA, bLessW⟩:=43 DedekindCut.no_greatest with cut, bInA44have wInQ := subset with w, wInA45have uLessW := rationalLess.transitive with uLessB, bLessW46apply noCommonUpper47refine⟨w, wInA, _, bLessW⟩48exact rationalLess.transitive with aLessU, uLessW49 . apply noCommonUpper50refine⟨u, uInA, aLessU, bLessU⟩5152-- In a positive real cut, every chosen member can be replaced by a strictly53-- larger positive member. Thus later product arguments may work entirely54-- with the familiar positive witnesses.55theorem RealLess.exists_positive_member_above (A : Real) (b : Rational)56requires positive : 0 < A57requires bInA : b ∈ A58shows∃ c ∈ A, b < c ∧ rationalZero < c59proof60obtain⟨a, aInA, positiveA⟩:= RealLess.exists_positive_member with positive61have cutA :=Real.characterization.forward withassumption62obtain⟨c, cInA, bLessC, aLessC⟩:= DedekindCut.exists_above_pair with cutA, bInA, aInA63have subsetA := DedekindCut.subset_rationals with cutA64have aRational : Rational(a)65unfoldRational66exact subsetA with a, aInA67have cRational : Rational(c)68unfoldRational69exact subsetA with c, cInA70refine⟨c, cInA, bLessC, _⟩71exact rationalLess.transitive with rationalZero.rational, aRational, cRational, positiveA, aLessC7273-- A member of the positive-cut product of two positive reals always admits74-- positive factor witnesses, including when membership originally75-- came from the product's negative lower tail.76theorem realPosMulCut.positive_factors (A B : Real) (q : Rational)77requires positiveA : 0 < A78requires positiveB : 0 < B79requires qInProduct : q ∈ realPosMulCut(A, B)80shows∃ a ∈ ℚ, a ∈ A ∧∃ b ∈ ℚ, b ∈ B ∧81 rationalZero < a ∧ rationalZero < b ∧ q < a * b82proof83obtain⟨qInQ, rest⟩:= realPosMulCut.membership.forward with qInProduct84cases rest with qNegative | product85 . obtain⟨a, aInA, aPositive⟩:=86 RealLess.exists_positive_member with positiveA87obtain⟨b, bInB, bPositive⟩:= RealLess.exists_positive_member with positiveB88have cutA :=Real.characterization.forward at A withassumption89have cutB :=Real.characterization.forward at B withassumption90have subsetA := DedekindCut.subset_rationals with cutA91have subsetB := DedekindCut.subset_rationals with cutB92have aInQ := subsetA with a, aInA93have bInQ := subsetB with b, bInB94have aRational : Rational(a) byexact aInQ95have bRational : Rational(b) byexact bInQ96have productPositive := rationalLess.mul_positive with aRational, bRational, aPositive, bPositive97have productRational := rationalMulValue.rational with aRational, bRational98have qRational : Rational(q) bytypecheck99refine⟨a, aInQ, aInA, b, bInQ, bInB,100 aPositive, bPositive, _⟩101exact rationalLess.transitive with102 qRational, rationalZero.rational, productRational, qNegative, productPositive103 . rcases product with104⟨a2, a2InQ, a2InA, b2, b2InQ, b2InB,105 a2Positive, b2Positive, qBelow⟩106refine⟨a2, a2InQ, a2InA, b2, b2InQ, b2InB,107 a2Positive, b2Positive, qBelow⟩108109-- Monotonicity in the second summand, derived by commutativity so that the110-- public API supports the two-sided monotonicity argument.111theorem realAddCut.subset_right (A B C : Real)112requires subset : A ⊆ B113shows realAddCut(C, A) ⊆ realAddCut(C, B)114proof115haveleft:= realAddCut.subset_left at A, B, C with116*{3}, subset117have ca := realAddCut.commutative at C, A with*118have cb := realAddCut.commutative at C, B with*119 rwa [ca, cb]120121theorem realAddCut.nonnegative (A B : Real)122requires nonnegativeA : realZero ⊆ A123requires nonnegativeB : realZero ⊆ B124shows realZero ⊆ realAddCut(A, B)125proof126have first := realAddCut.subset_left at realZero, A, realZero with127 realZero.real, assumption, realZero.real, nonnegativeA128have second := realAddCut.subset_right at realZero, B, A with129 realZero.real, *{2}, nonnegativeB130have zeroSum := realAddCut.zero_left with realZero.real131rw zeroSum at first132exact Subset.transitive with first, second133134theorem realAddValue.positive (A B : Real)135requires positiveA : 0 < A136requires positiveB : 0 < B137shows0 < A + B138proof139have aboveB := realLess.add_right at realZero, A, B with140 realZero.real, *{2}, positiveA141have zeroLeft := realAddValue.zero_left at B142rw zeroLeft at aboveB143have sumReal := realAddValue.real at A, B with*144exact realLess.transitive at realZero, B, A + B with145 realZero.real, assumption, sumReal,146 positiveB, aboveB147148-- The positive product is monotone in each cut argument. This proof149-- transports the displayed factor witness; no arithmetic search is involved.150theorem realPosMulCut.subset_left (A B C : Real)151requires subset : A ⊆ B152shows realPosMulCut(A, C) ⊆ realPosMulCut(B, C)153proof154intros q qInProduct155obtain⟨qInQ, rest⟩:= realPosMulCut.membership.forward with qInProduct156apply realPosMulCut.membership.backward157refine⟨qInQ, _⟩158cases rest with negative | product159 . left160exact negative161 . rcases product with162⟨a, aInQ, aInA, c, cInQ, cInC,163 positiveA, positiveC, qBelow⟩164have aInB : a ∈ B byexact subset with a, aInA165right166refine⟨a, aInQ, aInB, c, cInQ, cInC,167 positiveA, positiveC, qBelow⟩168169theorem realPosMulCut.subset_right (A B C : Real)170requires subset : A ⊆ B171shows realPosMulCut(C, A) ⊆ realPosMulCut(C, B)172proof173haveleft:= realPosMulCut.subset_left at A, B, C with174*{3}, subset175have ca := realPosMulCut.commutative at C, A with*176have cb := realPosMulCut.commutative at C, B with*177 rwa [ca, cb]178179-- A nonnegative real is either zero or strictly positive. This is the180-- linear-order dichotomy, stated in the subset language used by181-- Dedekind cuts.182theoremReal.nonnegative_cases (A : Real)183requires nonnegative : realZero ⊆ A184shows A = realZero ∨0 < A185proof186by_contra neither187have notZero : ¬(A = realZero)188intro equal189apply neither190left191exact equal192have notPositive : ¬(0 < A)193intro positive194apply neither195right196exact positive197apply notPositive198apply realLess.characterization.backward199unfold RealLess200refine⟨realZero.real, assumption, _⟩201unfold ProperSubset202refine⟨nonnegative, _⟩203intro equal204apply notZero205rw equal206rfl207208-- One direction of distributivity for three positive cuts. Starting from209-- q < a*x with x < b+c, we move b, c, and then a slightly inward. The210-- resulting boundary products are members of A*B and A*C, while211-- rational distributivity supplies their sum.212theorem realPosMulCut.distrib_subset (A B C : Real)213requires positiveA : 0 < A214requires positiveB : 0 < B215requires positiveC : 0 < C216shows realPosMulCut(A, realAddCut(B, C)) ⊆217 realAddCut(realPosMulCut(A, B), realPosMulCut(A, C))218proof219intros q qInLeft220have qData := realPosMulCut.membership.forward with qInLeft221rcases qData with⟨qInQ, qRest⟩222have qRational : Rational(q) byexact qInQ223have sumReal := realAddCut.real at B, C with*224have sumPositiveValue := realAddValue.positive with*{2}, positiveB, positiveC225have sumCut := realAddValue.cut at B, C with*226have sumPositive : realZero < realAddCut(B, C)227 rwa ← sumCut228obtain⟨a, aInQ, aInA, x, xInQ, xInSum,229 positiveRA, positiveX, qBelowAX⟩:=230 realPosMulCut.positive_factors at A, realAddCut(B, C), q with231assumption, sumReal, qRational,232 positiveA, sumPositive, qInLeft233have aRational : Rational(a) byexact aInQ234have xRational : Rational(x) byexact xInQ235obtain⟨xAgain, b, bInB, c, cInC, xBelowSum⟩:= realAddCut.membership_value.forward with xInSum236rw← rationalAddValue.notation at xBelowSum237have cutB :=Real.characterization.forward at B withassumption238have cutC :=Real.characterization.forward at C withassumption239have subsetB := DedekindCut.subset_rationals with cutB240have subsetC := DedekindCut.subset_rationals with cutC241have bInQ := subsetB with b, bInB242have cInQ := subsetC with c, cInC243have bRational : Rational(b) byexact bInQ244have cRational : Rational(c) byexact cInQ245obtain⟨b2, b2InB, bLessB2, positiveB2⟩:= RealLess.exists_positive_member_above with246assumption, bRational, positiveB, bInB247obtain⟨c2, c2InC, cLessC2, positiveC2⟩:= RealLess.exists_positive_member_above with248assumption, cRational, positiveC, cInC249have b2InQ := subsetB with b2, b2InB250have c2InQ := subsetC with c2, c2InC251have b2Rational : Rational(b2) byexact b2InQ252have c2Rational : Rational(c2) byexact c2InQ253have firstGrowth := rationalLess.add_right with bRational, b2Rational, cRational, bLessB2254have secondGrowth := rationalLess.add_left with cRational, c2Rational, b2Rational, cLessC2255have enlargedSumRational := rationalAddValue.rational with b2Rational, c2Rational256have xBelowEnlarged : x < b2 + c2257calc258 x < b + c := xBelowSum259 _ < b2 + c := firstGrowth260 _ < b2 + c2 := secondGrowth261have scaled := rationalLess.mul_left with262 xRational, enlargedSumRational, aRational, positiveRA, xBelowEnlarged263have axRational := rationalMulValue.rational with aRational, xRational264have enlargedProductRational := rationalMulValue.rational with aRational, enlargedSumRational265have qBelowExpanded : q < a * (b2 + c2)266exact rationalLess.transitive with qRational, axRational, enlargedProductRational, qBelowAX, scaled267have distributed := rationalMulValue.distributive_left with aRational, b2Rational, c2Rational268have qBelowProducts : q < a * b2 + a * c2269 rwa ← distributed270obtain⟨a2, a2InA, aLessA2, positiveA2⟩:= RealLess.exists_positive_member_above with271assumption, aRational, positiveA, aInA272have cutA :=Real.characterization.forward at A withassumption273have subsetA := DedekindCut.subset_rationals with cutA274have a2InQ := subsetA with a2, a2InA275have a2Rational : Rational(a2) byexact a2InQ276have leftBoundary := rationalLess.mul_right with aRational, a2Rational, b2Rational, positiveB2, aLessA2277have rightBoundary := rationalLess.mul_right with aRational, a2Rational, c2Rational, positiveC2, aLessA2278have leftRational := rationalMulValue.rational with aRational, b2Rational279have rightRational := rationalMulValue.rational with aRational, c2Rational280have leftInProduct : a * b2 ∈ realPosMulCut(A, B)281apply realPosMulCut.membership.backward282refine⟨leftRational, _⟩283right284refine⟨a2, a2InQ, a2InA, b2, b2InQ, b2InB,285 positiveA2, positiveB2, leftBoundary⟩286have rightInProduct : a * c2 ∈ realPosMulCut(A, C)287apply realPosMulCut.membership.backward288refine⟨rightRational, _⟩289right290refine⟨a2, a2InQ, a2InA, c2, c2InQ, c2InC,291 positiveA2, positiveC2, rightBoundary⟩292rw rationalAddValue.notation at qBelowProducts293apply realAddCut.membership_value.backward294refine⟨qInQ, a * b2, leftInProduct,295 a * c2, rightInProduct, qBelowProducts⟩296297-- The reverse inclusion uses a common factor from A above the two displayed298-- product witnesses. Rounding b and c upward makes b+c a member of299-- the sum cut, after which rational distributivity closes the estimate.300theorem realPosMulCut.distrib_reverse_subset (A B C : Real)301requires positiveA : 0 < A302requires positiveB : 0 < B303requires positiveC : 0 < C304shows realAddCut(realPosMulCut(A, B), realPosMulCut(A, C)) ⊆305 realPosMulCut(A, realAddCut(B, C))306proof307intros q qInRight308obtain⟨qInQ, x, xInAB, y, yInAC, qBelowXY⟩:= realAddCut.membership_value.forward with qInRight309rw← rationalAddValue.notation at qBelowXY310have subsetAB := realPosMulCut.subset_rationals at A, B311have subsetAC := realPosMulCut.subset_rationals at A, C312have xInQ := subsetAB with x, xInAB313have yInQ := subsetAC with y, yInAC314have xRational : Rational(x) byexact xInQ315have yRational : Rational(y) byexact yInQ316obtain⟨a, aInQ, aInA, b, bInQ, bInB, positiveRA, positiveBFactor, xBelowAB⟩:= realPosMulCut.positive_factors with317*{2}, xRational, positiveA, positiveB, xInAB318obtain⟨c, cInQ, cInA, d, dInQ, dInC, positiveRC, positiveDFactor, yBelowCD⟩:= realPosMulCut.positive_factors with319*{2}, yRational, positiveA, positiveC, yInAC320have aRational : Rational(a) byexact aInQ321have bRational : Rational(b) byexact bInQ322have cRational : Rational(c) byexact cInQ323have dRational : Rational(d) byexact dInQ324have cutA :=Real.characterization.forward at A withassumption325obtain⟨e, eInA, aLessE, cLessE⟩:= DedekindCut.exists_above_pair with cutA, aInA, cInA326have subsetA := DedekindCut.subset_rationals with cutA327have eInQ := subsetA with e, eInA328have eRational : Rational(e) byexact eInQ329have positiveE := rationalLess.transitive with330 rationalZero.rational, aRational, eRational, positiveRA, aLessE331have abRational := rationalMulValue.rational with aRational, bRational332have cdRational := rationalMulValue.rational with cRational, dRational333have ebRational := rationalMulValue.rational with eRational, bRational334have edRational := rationalMulValue.rational with eRational, dRational335have xGrowth := rationalLess.add_right with xRational, abRational, yRational, xBelowAB336have yGrowth := rationalLess.add_left with yRational, cdRational, abRational, yBelowCD337have abGrowth := rationalLess.mul_right with positiveBFactor, aLessE338have cdGrowth := rationalLess.mul_right with positiveDFactor, cLessE339have firstProductGrowth := rationalLess.add_right with abRational, ebRational, cdRational, abGrowth340have secondProductGrowth := rationalLess.add_left with cdRational, edRational, ebRational, cdGrowth341have qBelowCommonSum : q < e * b + e * d342calc343 q < x + y := qBelowXY344 _ < a * b + y := xGrowth345 _ < a * b + c * d := yGrowth346 _ < e * b + c * d := firstProductGrowth347 _ < e * b + e * d := secondProductGrowth348have distributed := rationalMulValue.distributive_left with eRational, bRational, dRational349have qBelowFactored : q < e * (b + d) by rwa distributed350have cutB :=Real.characterization.forward at B withassumption351have cutC :=Real.characterization.forward at C withassumption352have subsetB := DedekindCut.subset_rationals with cutB353have subsetC := DedekindCut.subset_rationals with cutC354obtain⟨b2, b2InB, bLessB2, positiveB2⟩:= RealLess.exists_positive_member_above with355assumption, bRational, positiveB, bInB356obtain⟨d2, d2InC, dLessD2, positiveD2⟩:= RealLess.exists_positive_member_above with357assumption, dRational, positiveC, dInC358have b2InQ := subsetB with b2, b2InB359have d2InQ := subsetC with d2, d2InC360have b2Rational : Rational(b2) byexact b2InQ361have d2Rational : Rational(d2) byexact d2InQ362have bGrowth := rationalLess.add_right with bRational, b2Rational, dRational, bLessB2363have dGrowth := rationalLess.add_left with dRational, d2Rational, b2Rational, dLessD2364have sumBelowRounded : b + d < b2 + d2365calc366 b + d < b2 + d := bGrowth367 _ < b2 + d2 := dGrowth368have bdRational := rationalAddValue.rational with bRational, dRational369have zeroPlusD := rationalAddValue.zero_left with dRational370have dBelowSum := rationalLess.add_right with rationalZero.rational, bRational, dRational, positiveBFactor371rw zeroPlusD at dBelowSum372have positiveSum := rationalLess.transitive with373 rationalZero.rational, dRational, bdRational, positiveDFactor, dBelowSum374have sumInCut : b + d ∈ realAddCut(B, C)375apply realAddCut.membership_value.backward376refine⟨bdRational, b2, b2InB, d2, d2InC, _⟩377 rwa ← rationalAddValue.notation378apply realPosMulCut.membership.backward379refine⟨qInQ, _⟩380right381refine⟨e, eInQ, eInA, b + d, _, sumInCut,382 positiveE, positiveSum, qBelowFactored⟩383exact bdRational384385theorem realPosMulCut.distributive_of_positive (A B C : Real)386requires positiveA : 0 < A387requires positiveB : 0 < B388requires positiveC : 0 < C389shows realPosMulCut(A, realAddCut(B, C)) =390 realAddCut(realPosMulCut(A, B), realPosMulCut(A, C))391proof392apply Subset.antisymmetric393 . exact realPosMulCut.distrib_subset at A, B, C with394*{3},395 positiveA, positiveB, positiveC396 . exact realPosMulCut.distrib_reverse_subset at A, B, C with397*{3},398 positiveA, positiveB, positiveC399