1-- Signed multiplicative inverses and the ordered-field structure of the reals2-- 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.Inverse8import PositiveInverse910-- The total inverse graph sends zero to zero. Away from zero its two clauses11-- are the familiar positive reciprocal and the negative of the reciprocal of12-- the absolute value. Keeping the sign split here lets all subsequent field13-- proofs speak only about multiplication and negation.14def realInv : Set:=15 { p ∈ (ℝ × ℝ) |16∃ A ∈ ℝ, (17 (A =0∧ p = (A ↦0)) ∨18 (0 < A ∧ p = (A ↦ positiveRealInvCut(A))) ∨19 (A < 0∧20 p = (A ↦ realNegCut(positiveRealInvCut(realNegCut(A)))))) }2122theorem realInv.negative_argument_positive (A : Real)23requires negative : A < 024shows0 < -A25proof26have negativeView := realLess.characterization.forward with negative27have reversedView := RealLess.neg_reverse with negativeView28have reversed := realLess.characterization.backward with reversedView29have negZero := realNegValue.zero30 rwa negZero at reversed3132theorem realInv.relates_zero33shows relates(realInv, realZero, realZero)34proof35unfold relates36apply realInv.membership.backward37have zeroInReals : realZero ∈ ℝ byexact realZero.real38constructor39 . exact product.pair at realZero, realZero, ℝ, ℝ with40 zeroInReals, zeroInReals41 . witness realZero42constructor43 . exact zeroInReals44 . left45constructor46 . rfl47 . rfl4849theorem realInv.relates_positive (A : Real)50requires positive : 0 < A51shows relates(realInv, A, positiveRealInvCut(A))52proof53have inverseReal := positiveRealInvCut.real with positive54have realA : A ∈ ℝ bysimp [Real]55have realInverse : positiveRealInvCut(A) ∈ ℝ byexact inverseReal56unfold relates57apply realInv.membership.backward58constructor59 . exact product.pair at A, positiveRealInvCut(A), ℝ, ℝ with60 realA, realInverse61 . witness A62constructor63 . exact realA64 . right65left66constructor67 . exact positive68 . rfl6970theorem realInv.relates_negative (A : Real)71requires negative : A < 072shows relates(realInv, A,73 realNegCut(positiveRealInvCut(realNegCut(A))))74proof75have positiveNegA := realInv.negative_argument_positive with negative76have inverseReal := positiveRealInvCut.real with positiveNegA77have negInverseReal := realNegValue.real with inverseReal78have realA : A ∈ ℝ bysimp [Real]79have realInverse : realNegCut(positiveRealInvCut(realNegCut(A))) ∈ ℝ80unfoldRealat negInverseReal81 simpa [realNegValue.cut] using negInverseReal82unfold relates83apply realInv.membership.backward84constructor85 . exact product.pair at A,86 realNegCut(positiveRealInvCut(realNegCut(A))), ℝ, ℝ with87 realA, realInverse88 . witness A89constructor90 . exact realA91 . right92right93constructor94 . exact negative95 . rfl9697theorem realInv.total98shows TotalBetween(realInv, ℝ, ℝ)99proof100intros A realA101have zeroCases : A = realZero ∨ A ≠ realZero102by_contra neither103apply neither104right105intro equal106apply neither107left108exact equal109cases zeroCases with zero | nonzero110 . witness realZero111constructor112 . exact realZero.real113 . rw zero114exact realInv.relates_zero115 . have connected := realLess.connected_on116have signs := connected with A, realA, realZero, nonzero117cases signs with negative | positive118 . have positiveNegA := realInv.negative_argument_positive with negative119have inverseReal := positiveRealInvCut.real with positiveNegA120have negInverseReal := realNegValue.real with inverseReal121have cutInverseReal : Real(122 realNegCut(positiveRealInvCut(realNegCut(A))))123 simpa [realNegValue.cut] using negInverseReal124witness realNegCut(positiveRealInvCut(realNegCut(A)))125constructor126exact cutInverseReal127 . exact realInv.relates_negative with negative128 . have inverseReal := positiveRealInvCut.real with positive129witness positiveRealInvCut(A)130constructor131exact inverseReal132 . exact realInv.relates_positive with positive133134theorem realInv.negative_mul_eq_one (A : Real)135requires negative : A < 0136shows realMulValue(A,137 realNegCut(positiveRealInvCut(realNegCut(A)))) = realOne138proof139have negAReal := realNegValue.real at A140have positiveNegA := realInv.negative_argument_positive with negative141have inverseReal := positiveRealInvCut.real with positiveNegA142have positiveLaw := positiveRealInvCut.mul_eq_one with positiveNegA143unfold realMulValue at positiveLaw144have negatedProduct := realMulValue.neg_both with negAReal, inverseReal145have involutiveA := realNegValue.involutive at A146rw involutiveA at negatedProduct147have law : A * (-positiveRealInvCut(-A)) = realOne148rw negatedProduct149unfold call2150exact positiveLaw151have negACut := realNegValue.cut at A152have inverseNegCut := realNegValue.cut with inverseReal153rw negACut at inverseNegCut154rw [negACut, inverseNegCut] at law155unfold call2 at law156unfold realMulValue157exact law158159theorem realLess.not_reverse (A B : Real)160requires less : A < B161shows¬(B < A)162proof163intro reverse164have cycle := realLess.transitive with less, reverse165have irreflexive := realLess.irreflexive_on166exact irreflexive with A, cycle167168theorem realInv.factors (input output : Set)169requires mapped : relates(realInv, input, output)170shows∃ A ∈ ℝ, input = A ∧171 ((A =0∧ output = realZero) ∨172 (0 < A ∧173 output = positiveRealInvCut(A)) ∨174 (A < 0∧175 output = realNegCut(positiveRealInvCut(realNegCut(A)))))176proof177unfold relates at mapped178simp [realInv.membership] at mapped179rcases mapped with⟨bounded, A, realA, cases⟩180witness A181constructor182 . exact realA183 . casescaseswith zero | nonzero184 . rcases zero with⟨zeroA, shape⟩185obtain⟨inputA, outputZero⟩:= orderedPair.injective with shape186constructor187 . exact inputA188 . left189constructor190 . exact zeroA191 . exact outputZero192 . cases nonzero with positive | negative193 . rcases positive with⟨positiveA, shape⟩194obtain⟨inputA, outputInverse⟩:= orderedPair.injective with shape195constructor196 . exact inputA197 . right198left199constructor200 . exact positiveA201 . exact outputInverse202 . rcases negative with⟨negativeA, shape⟩203obtain⟨inputA, outputInverse⟩:= orderedPair.injective with shape204constructor205 . exact inputA206 . right207right208constructor209 . exact negativeA210 . exact outputInverse211212theorem realInv.functional213shows Functional(realInv)214proof215intros input y inputY z inputZ216obtain⟨A, realA, inputA, yCases⟩:= realInv.factors with inputY217obtain⟨B, realB, inputB, zCases⟩:= realInv.factors with inputZ218have sameInput : A = B bycc219rw← sameInput at zCases220cases yCases with yZero | yNonzero221 . rcases yZero with⟨zeroA, yShape⟩222cases zCases with zZero | zNonzero223 . rcases zZero with⟨zeroAgain, zShape⟩224cc225 . cases zNonzero with zPositive | zNegative226 . rcases zPositive with⟨positiveA, zShape⟩227rw zeroA at positiveA228exfalso229have impossible := realLess.not_reverse with realZero.real, realZero.real, positiveA230exact impossible with positiveA231 . rcases zNegative with⟨negativeA, zShape⟩232rw zeroA at negativeA233exfalso234have impossible := realLess.not_reverse with realZero.real, realZero.real, negativeA235exact impossible with negativeA236 . cases yNonzero with yPositive | yNegative237 . rcases yPositive with⟨positiveA, yShape⟩238cases zCases with zZero | zNonzero239 . rcases zZero with⟨zeroA, zShape⟩240rw zeroA at positiveA241exfalso242have impossible := realLess.not_reverse with realZero.real, realZero.real, positiveA243exact impossible with positiveA244 . cases zNonzero with zPositive | zNegative245 . rcases zPositive with⟨positiveAgain, zShape⟩246cc247 . rcases zNegative with⟨negativeA, zShape⟩248exfalso249have impossible := realLess.not_reverse with realZero.real, positiveA250exact impossible with negativeA251 . rcases yNegative with⟨negativeA, yShape⟩252cases zCases with zZero | zNonzero253 . rcases zZero with⟨zeroA, zShape⟩254rw zeroA at negativeA255exfalso256have impossible := realLess.not_reverse with realZero.real, realZero.real, negativeA257exact impossible with negativeA258 . cases zNonzero with zPositive | zNegative259 . rcases zPositive with⟨positiveA, zShape⟩260exfalso261have impossible := realLess.not_reverse with realZero.real, positiveA262exact impossible with negativeA263 . rcases zNegative with⟨negativeAgain, zShape⟩264cc265266theorem realInv.function267shows realInv : ℝ → ℝ268proof269constructor270intros p member271obtain⟨bounded, witnesses⟩:= realInv.membership.forward with member272exact bounded273 . constructor274 . exact realInv.functional275 . exact realInv.total276277-- Real division is the field operation x / y = x * y⁻¹. Its graph is278-- obtained from the generic field construction, so `/` is selected by the279-- same notation machinery as `+` and `*`.280def realDiv : Set:= fieldDiv(ℝ, realMul, realInv)281282theorem realDiv.function283shows realDiv : ℝ × ℝ → ℝ284proof285unfold realDiv286exact fieldDiv.function with realMul.function, realInv.function287288instance realDiv.operation289shows DivOperation(ℝ, realDiv)290proof291exact realDiv.function292293notationinfixl70"/"=> call2 via DivOperation(ℝ, _) forReal294295def realInvValue (A : Real) : Real:= realInv(A)296297theorem realInvValue.real (A : Real)298showsReal(realInvValue(A))299proof300have realA : A ∈ ℝ bysimp [Real]301obtain⟨B, realB, mapped⟩:= FunctionBetween.exists_value with realInv.function, realA302have applied := FunctionBetween.apply_value with realInv.function, mapped303unfold realInvValue304rw applied305exact realB306307theorem realDiv.eq_mul_inv (A B : Real)308shows A / B = A * realInvValue(B)309proof310have realA : A ∈ ℝ bysimp [Real]311have realB : B ∈ ℝ bysimp [Real]312have mapped := fieldDiv.relates with realMul.function, realInv.function, realA, realB313have inputInProduct := product.pair with realA, realB314have mappedByRealDiv : relates(realDiv, (A, B),315 realMul(A, realInv(B)))316unfold realDiv317exact mapped318have applied := FunctionBetween.apply_value with realDiv.function, inputInProduct, mappedByRealDiv319unfold call2320unfold realInvValue321unfold call2 at applied322exact applied323324theorem realDiv.real (A B : Real)325showsReal(A / B)326proof327have realA : A ∈ ℝ bysimp [Real]328have realB : B ∈ ℝ bysimp [Real]329have input := product.pair with realA, realB330have closed := FunctionBetween.apply_closed with realDiv.function, input331unfold call2332exact closed333334theorem realDiv.zero_left (B : Real)335shows0 / B =0336proof337have inverseReal := realInvValue.real at B338calc3390 / B =0* realInvValue(B) :=340 realDiv.eq_mul_inv with realZero.real341 _ =0:= realMulValue.zero_left at realInvValue(B) with inverseReal342343theorem realDiv.add_left (A B C : Real)344shows (A + B) / C = A / C + B / C345proof346have inverseReal := realInvValue.real at C347have sumReal := realAddValue.real at A, B with*348calc349 (A + B) / C = (A + B) * realInvValue(C) :=350 realDiv.eq_mul_inv with sumReal, assumption351 _ = A * realInvValue(C) + B * realInvValue(C) :=352 realMulValue.distributive_right at A, B, realInvValue(C) with353*{2}, inverseReal354 _ = A / C + B / C :=bysimp [realDiv.eq_mul_inv]355356theorem realDiv.neg_left (A B : Real)357shows (-A) / B = -(A / B)358proof359have negAReal := realNegValue.real at A360have inverseReal := realInvValue.real at B361calc362 (-A) / B = (-A) * realInvValue(B) :=363 realDiv.eq_mul_inv with negAReal, assumption364 _ = -(A * realInvValue(B)) :=365 realMulValue.neg_left at A, realInvValue(B) with366assumption, inverseReal367 _ = -(A / B) :=bysimp [realDiv.eq_mul_inv]368369theorem realInvValue.zero370shows realInvValue(realZero) = realZero371proof372have applied := FunctionBetween.apply_value with realInv.function, realInv.relates_zero373unfold realInvValue374exact applied375376theorem realInvValue.of_positive (A : Real)377requires positive : 0 < A378shows realInvValue(A) = positiveRealInvCut(A)379proof380have mapped := realInv.relates_positive with positive381have applied := FunctionBetween.apply_value with realInv.function, mapped382unfold realInvValue383exact applied384385theorem realInvValue.of_negative (A : Real)386requires negative : A < 0387shows realInvValue(A) =388 realNegCut(positiveRealInvCut(realNegCut(A)))389proof390have mapped := realInv.relates_negative with negative391have applied := FunctionBetween.apply_value with realInv.function, mapped392unfold realInvValue393exact applied394395theorem realInvValue.mul_right (A : Real)396requires nonzero : A ≠0397shows A * realInvValue(A) =1398proof399have connected := realLess.connected_on400have signs := connected with A, realZero, nonzero401cases signs with negative | positive402 . have value := realInvValue.of_negative with negative403rw value404have law := realInv.negative_mul_eq_one with negative405unfold realMulValue at law406unfold call2407exact law408 . have value := realInvValue.of_positive with positive409rw value410have law := positiveRealInvCut.mul_eq_one with positive411unfold realMulValue at law412unfold call2413exact law414415theorem realDiv.self (A : Real)416requires nonzero : A ≠0417shows A / A =1418proof419calc420 A / A = A * realInvValue(A) :=421 realDiv.eq_mul_inv with*{2}422 _ =1:= realInvValue.mul_right at A with nonzero423424-- Multiplication by a nonzero denominator cancels division.425theorem realDiv.mul_left (A B : Real)426requires nonzero : B ≠0427shows B * (A / B) = A428proof429have inverseReal := realInvValue.real at B430have inverseLaw := realInvValue.mul_right with nonzero431have oneA := realMulValue.one_left at A432have associateBA := realMulValue.associative at433 B, A, realInvValue(B) with*{2}, inverseReal434have commuteBA := realMulValue.commutative at B, A with435*{2}436have associateAB := realMulValue.associative at437 A, B, realInvValue(B) with*{2}, inverseReal438have inverseProductReal := realMulValue.real at439 B, realInvValue(B) withassumption, inverseReal440have commuteProduct := realMulValue.commutative at441 A, B * realInvValue(B) withassumption, inverseProductReal442calc443 B * (A / B) = B * (A * realInvValue(B)) :=444bysimp [realDiv.eq_mul_inv]445 _ = (B * A) * realInvValue(B) :=bycc446 _ = (A * B) * realInvValue(B) :=bycc447 _ = A * (B * realInvValue(B)) :=bycc448 _ = (B * realInvValue(B)) * A := commuteProduct449 _ =1* A :=bysimp [inverseLaw]450 _ = A := oneA451452theorem realDiv.mul_right (A B : Real)453requires nonzero : B ≠0454shows (A / B) * B = A455proof456have quotientReal := realDiv.real at A, B with*457have commute := realMulValue.commutative at A / B, B with458 quotientReal, assumption459calc460 (A / B) * B = B * (A / B) := commute461 _ = A := realDiv.mul_left at A, B with nonzero462463-- Two quotients agree once the cross products agree.464theorem realDiv.eq_of_cross (P Q D E : Real)465requires nonzeroQ : Q≠0466requires nonzeroE : E ≠0467requires cross : D * Q = E * P468shows P / Q = D / E469proof470have leftView := realDiv.eq_mul_inv at P, Q471have rightView := realDiv.eq_mul_inv at D, E472have invQ := realInvValue.real at Q473have invE := realInvValue.real at E474have unitQ := realInvValue.mul_right with nonzeroQ475have unitE := realInvValue.mul_right with nonzeroE476rw [leftView, rightView]477linear_combination (D * realInvValue(E)) * unitQ -478 (realInvValue(Q) * realInvValue(E)) * cross -479 (P * realInvValue(Q)) * unitE480481-- A factor in the numerator may be pulled outside division.482theorem realDiv.mul_numerator_left (A B C : Real)483shows (A * B) / C = A * (B / C)484proof485have productReal := realMulValue.real at A, B with*486have inverseReal := realInvValue.real at C487have associate := realMulValue.associative at488 A, B, realInvValue(C) with*{2}, inverseReal489have wholeDivision := realDiv.eq_mul_inv at A * B, C with490 productReal, assumption491have factorDivision := realDiv.eq_mul_inv at B, C with492*{2}493calc494 (A * B) / C = (A * B) * realInvValue(C) := wholeDivision495 _ = A * (B * realInvValue(C)) := associate496 _ = A * (B / C) :=bycc497498theorem realInvValue.mul_left (A : Real)499requires nonzero : A ≠0500shows realInvValue(A) * A =1501proof502have inverseReal := realInvValue.real at A503have commutative := realMulValue.commutative at realInvValue(A), A with504 inverseReal, assumption505haveright:= realInvValue.mul_right with nonzero506calc507 realInvValue(A) * A = A * realInvValue(A) := commutative508 _ =1:=right509510theorem reals.multiplicative_inverse511shows MultiplicativeInverse(ℝ, realMul, realZero, realOne, realInv)512proof513constructor514 . exact realInv.function515 . intros A realA nonzero516haveleft:= realInvValue.mul_left with nonzero517haveright:= realInvValue.mul_right with nonzero518unfold realInvValue atleft519unfold realInvValue atright520constructor521 . unfold call2522unfold call2 atleft523exactleft524 . unfold call2525unfold call2 atright526exactright527528instance reals.field529shows IsFieldWithInverse(ℝ, realAdd, realZero, realNeg, realMul, realOne,530 realInv)531proof532constructor533 . exact reals.comm_ring534 . constructor535 . exact reals.nontrivial536 . exact reals.multiplicative_inverse537538instance reals.ordered_field539shows IsOrderedField(540 ℝ, realAdd, realZero, realNeg, realMul, realOne, realInv, realLess)541proof542constructor543 . exact reals.field544 . constructor545 . exact realLess.strict_linear_order546 . constructor547 . exact realAdd.strict_mono548 . exact realMul.positive549550theorem realInvValue.nonzero (A : Real)551requires nonzero : A ≠0552shows realInvValue(A) ≠0553proof554have inverseLaw := realInvValue.mul_right with nonzero555intro inverseZero556have zeroProduct := realMulValue.zero_right at A557rw [inverseZero, zeroProduct] at inverseLaw558apply realZero.ne_one559exact inverseLaw560561-- A right inverse of a nonzero real is the inverse. This tiny uniqueness562-- lemma keeps later reciprocal calculations close to their handwritten form.563theorem realInvValue.eq_of_mul_right (A B : Real)564requires nonzero : A ≠0565requires inverseLaw : A * B =1566shows B = realInvValue(A)567proof568have inverseReal := realInvValue.real at A569have canonical := realInvValue.mul_left with nonzero570have associative := realMulValue.associative at571 realInvValue(A), A, B with inverseReal, *{2}572have oneLeft := realMulValue.one_left at B573have oneRight := realMulValue.one_right with inverseReal574calc575 B =1* B :=bycc576 _ = (realInvValue(A) * A) * B :=bycc577 _ = realInvValue(A) * (A * B) := associative578 _ = realInvValue(A) *1:=bycc579 _ = realInvValue(A) := oneRight580581theorem realInvValue.mul (A B : Real)582requires nonzeroA : A ≠0583requires nonzeroB : B ≠0584shows realInvValue(A * B) = realInvValue(A) * realInvValue(B)585proof586have inverseAReal := realInvValue.real at A587have inverseBReal := realInvValue.real at B588have productReal := realMulValue.real at A, B with*589have inverseA := realInvValue.mul_right with nonzeroA590have inverseB := realInvValue.mul_right with nonzeroB591have inverseALeft := realInvValue.mul_left with nonzeroA592have productNonzero : A * B ≠0593intro productZero594have zeroLeft := realMulValue.zero_right with inverseAReal595have associative := realMulValue.associative at596 realInvValue(A), A, B with inverseAReal, *{2}597have oneLeft := realMulValue.one_left at B598apply nonzeroB599cc600have commute := realMulValue.commutative at B, realInvValue(A) with601assumption, inverseAReal602have candidateLaw : (A * B) *603 (realInvValue(A) * realInvValue(B)) =1604have oneMul := realMulValue.one_left with realOne.real605have oneLeftB := realMulValue.one_left at B606have oneRightA := realMulValue.one_right at A607have oneRightInverseA := realMulValue.one_right with inverseAReal608have assocABInvA := realMulValue.associative at609 A, B, realInvValue(A) with*{2}, inverseAReal610have assocAInvAB := realMulValue.associative at611 A, realInvValue(A), B withassumption, inverseAReal, assumption612have assocOuter := realMulValue.associative with productReal, inverseAReal, inverseBReal613have assocFinal := realMulValue.associative at614 A, B, realInvValue(B) with*{2}, inverseBReal615calc616 (A * B) * (realInvValue(A) * realInvValue(B)) =617 ((A * B) * realInvValue(A)) * realInvValue(B) :=bycc618 _ = (A * (B * realInvValue(A))) * realInvValue(B) :=bycc619 _ = (A * (realInvValue(A) * B)) * realInvValue(B) :=bycc620 _ = ((A * realInvValue(A)) * B) * realInvValue(B) :=bycc621 _ = (1* B) * realInvValue(B) :=bycc622 _ = B * realInvValue(B) :=bycc623 _ =1:= inverseB624have unique := realInvValue.eq_of_mul_right with productNonzero, candidateLaw625calc626 realInvValue(A * B) = realInvValue(A) * realInvValue(B) :=bycc627