1-- Minimum and maximum of two integers2-- 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.Int.MinMax8import AbsoluteValueOrder910theorem integerLess.or_le (x y : Integer)11shows x < y ∨ y ≤ x12proof13havesplit : x < y ∨¬x < y bytauto14casessplitwith less | notLess15 . left16exact less17 . right18exact integerLe.of_not_less with notLess1920defunique integerMin (a b : Set) (m ∈ ℤ) :=21 (integerLe(a, b) ∧ m = a) ∨ (integerLess(b, a) ∧ m = b)22requires aInteger : Integer(a)23requires bInteger : Integer(b)24proof25havesplit:= integerLess.or_le at b, a26casessplitwith above | below27 . have bMember : b ∈ ℤ bysettlewith Integer28refine⟨b, bMember, ?_⟩29right30exact⟨above, rfl⟩31 . have aMember : a ∈ ℤ bysettlewith Integer32refine⟨a, aMember, ?_⟩33left34exact⟨below, rfl⟩3536uniqueness37intros m mMember first n nMember second38cases first with firstLow | firstHigh39 . cases second with secondLow | secondHigh40 . cc41 . exfalso42exact integerLe.not_less with firstLow.left, secondHigh.left43 . cases second with secondLow | secondHigh44 . exfalso45exact integerLe.not_less with secondLow.left, firstHigh.left46 . cc4748defunique integerMax (a b : Set) (m ∈ ℤ) :=49 (integerLe(a, b) ∧ m = b) ∨ (integerLess(b, a) ∧ m = a)50requires aInteger : Integer(a)51requires bInteger : Integer(b)52proof53havesplit:= integerLess.or_le at b, a54casessplitwith above | below55 . have aMember : a ∈ ℤ bysettlewith Integer56refine⟨a, aMember, ?_⟩57right58exact⟨above, rfl⟩59 . have bMember : b ∈ ℤ bysettlewith Integer60refine⟨b, bMember, ?_⟩61left62exact⟨below, rfl⟩6364uniqueness65intros m mMember first n nMember second66cases first with firstLow | firstHigh67 . cases second with secondLow | secondHigh68 . cc69 . exfalso70exact integerLe.not_less with firstLow.left, secondHigh.left71 . cases second with secondLow | secondHigh72 . exfalso73exact integerLe.not_less with secondLow.left, firstHigh.left74 . cc7576theorem integerMin.integer (a b : Integer)77shows Integer(integerMin(a, b))78proof79have selected := integerMin.selected at a, b with*80exact selected.left8182theorem integerMax.integer (a b : Integer)83shows Integer(integerMax(a, b))84proof85have selected := integerMax.selected at a, b with*86exact selected.left8788theorem integerMin.of_le (a b : Integer)89requires below : a ≤ b90shows integerMin(a, b) = a91proof92have selected := integerMin.selected at a, b with*93rcases selected with⟨member, property⟩94cases property with low | high95 . exact low.right96 . exfalso97exact integerLe.not_less with below, high.left9899theorem integerMin.of_ge (a b : Integer)100requires above : b ≤ a101shows integerMin(a, b) = b102proof103have selected := integerMin.selected at a, b with*104rcases selected with⟨member, property⟩105cases property with low | high106 . have same := integerLe.antisymmetric with low.left, above107rw low.right108exact same109 . exact high.right110111theorem integerMax.of_le (a b : Integer)112requires below : a ≤ b113shows integerMax(a, b) = b114proof115have selected := integerMax.selected at a, b with*116rcases selected with⟨member, property⟩117cases property with low | high118 . exact low.right119 . exfalso120exact integerLe.not_less with below, high.left121122theorem integerMax.of_ge (a b : Integer)123requires above : b ≤ a124shows integerMax(a, b) = a125proof126have selected := integerMax.selected at a, b with*127rcases selected with⟨member, property⟩128cases property with low | high129 . have same := integerLe.antisymmetric with low.left, above130rw low.right131 symm132exact same133 . exact high.right134135theorem integerMin.self (a : Integer)136shows integerMin(a, a) = a137proof138exact integerMin.of_le with (integerLe.reflexive at a)139140theorem integerMax.self (a : Integer)141shows integerMax(a, a) = a142proof143exact integerMax.of_le with (integerLe.reflexive at a)144145theorem integerMin.commutative (a b : Integer)146shows integerMin(a, b) = integerMin(b, a)147proof148have total := integerLe.total at a, b149cases total with below | above150 . haveleft:= integerMin.of_le with below151haveright:= integerMin.of_ge at b, a with below152rw [left, right]153rfl154 . haveleft:= integerMin.of_ge with above155haveright:= integerMin.of_le at b, a with above156rw [left, right]157rfl158159theorem integerMax.commutative (a b : Integer)160shows integerMax(a, b) = integerMax(b, a)161proof162have total := integerLe.total at a, b163cases total with below | above164 . haveleft:= integerMax.of_le with below165haveright:= integerMax.of_ge at b, a with below166rw [left, right]167rfl168 . haveleft:= integerMax.of_ge with above169haveright:= integerMax.of_le at b, a with above170rw [left, right]171rfl172173theorem integerMin.cases (a b : Integer)174shows integerMin(a, b) = a ∨ integerMin(a, b) = b175proof176have total := integerLe.total at a, b177cases total with below | above178 . left179exact integerMin.of_le with below180 . right181exact integerMin.of_ge with above182183theorem integerMax.cases (a b : Integer)184shows integerMax(a, b) = a ∨ integerMax(a, b) = b185proof186have total := integerLe.total at a, b187cases total with below | above188 . right189exact integerMax.of_le with below190 . left191exact integerMax.of_ge with above192193theorem integerMin.le_left (a b : Integer)194shows integerMin(a, b) ≤ a195proof196have total := integerLe.total at a, b197cases total with below | above198 . have value101 := integerMin.of_le with below199rw value101200exact integerLe.reflexive with*201 . have value102 := integerMin.of_ge with above202rw value102203exact above204205theorem integerMin.le_right (a b : Integer)206shows integerMin(a, b) ≤ b207proof208have total := integerLe.total at a, b209cases total with below | above210 . have value103 := integerMin.of_le with below211rw value103212exact below213 . have value104 := integerMin.of_ge with above214rw value104215exact integerLe.reflexive with*216217theorem integerMax.ge_left (a b : Integer)218shows a ≤ integerMax(a, b)219proof220have total := integerLe.total at a, b221cases total with below | above222 . have value105 := integerMax.of_le with below223rw value105224exact below225 . have value106 := integerMax.of_ge with above226rw value106227exact integerLe.reflexive with*228229theorem integerMax.ge_right (a b : Integer)230shows b ≤ integerMax(a, b)231proof232have total := integerLe.total at a, b233cases total with below | above234 . have value107 := integerMax.of_le with below235rw value107236exact integerLe.reflexive with*237 . have value108 := integerMax.of_ge with above238rw value108239exact above240241theorem integerMin.le_integerMax (a b : Integer)242shows integerLe(integerMin(a, b), integerMax(a, b))243proof244have low := integerMin.le_left at a, b245have high := integerMax.ge_left at a, b246exact integerLe.transitive with low, high247248theorem integerMin.le_iff (a b c : Integer)249shows c ≤ integerMin(a, b) ↔ c ≤ a ∧ c ≤ b250proof251have minNat := integerMin.integer at a, b252have low := integerMin.le_left at a, b253have high := integerMin.le_right at a, b254constructor255 . intro below256constructor257 . exact integerLe.transitive with below, low258 . exact integerLe.transitive with below, high259 . intro both260have total := integerLe.total at a, b261cases total with first | second262 . have value109 := integerMin.of_le with first263rw value109264exact both.left265 . have value110 := integerMin.of_ge with second266rw value110267exact both.right268269theorem integerMin.le_iff_or (a b c : Integer)270shows integerMin(a, b) ≤ c ↔ a ≤ c ∨ b ≤ c271proof272have minNat := integerMin.integer at a, b273constructor274 . intro below275havesplit:= integerMin.cases at a, b276casessplitwith first | second277 . left278rw← first279exact below280 . right281rw← second282exact below283 . introsplit284casessplitwith first | second285 . have low := integerMin.le_left at a, b286exact integerLe.transitive with low, first287 . have high := integerMin.le_right at a, b288exact integerLe.transitive with high, second289290theorem integerMax.le_iff (a b c : Integer)291shows integerMax(a, b) ≤ c ↔ a ≤ c ∧ b ≤ c292proof293have maxNat := integerMax.integer at a, b294have low := integerMax.ge_left at a, b295have high := integerMax.ge_right at a, b296constructor297 . intro below298constructor299 . exact integerLe.transitive with low, below300 . exact integerLe.transitive with high, below301 . intro both302have total := integerLe.total at a, b303cases total with first | second304 . have value111 := integerMax.of_le with first305rw value111306exact both.right307 . have value112 := integerMax.of_ge with second308rw value112309exact both.left310311theorem integerMax.ge_iff_or (a b c : Integer)312shows c ≤ integerMax(a, b) ↔ c ≤ a ∨ c ≤ b313proof314have maxNat := integerMax.integer at a, b315constructor316 . intro below317havesplit:= integerMax.cases at a, b318casessplitwith first | second319 . left320rw← first321exact below322 . right323rw← second324exact below325 . introsplit326casessplitwith first | second327 . have low := integerMax.ge_left at a, b328exact integerLe.transitive with first, low329 . have high := integerMax.ge_right at a, b330exact integerLe.transitive with second, high331332theorem integerMin.lt_iff (a b c : Integer)333shows c < integerMin(a, b) ↔ c < a ∧ c < b334proof335have minNat := integerMin.integer at a, b336have low := integerMin.le_left at a, b337have high := integerMin.le_right at a, b338constructor339 . intro below340constructor341 . exact integerLess.transitive_le with below, low342 . exact integerLess.transitive_le with below, high343 . intro both344have total := integerLe.total at a, b345cases total with first | second346 . have value113 := integerMin.of_le with first347rw value113348exact both.left349 . have value114 := integerMin.of_ge with second350rw value114351exact both.right352353theorem integerMax.lt_iff (a b c : Integer)354shows integerMax(a, b) < c ↔ a < c ∧ b < c355proof356have maxNat := integerMax.integer at a, b357have low := integerMax.ge_left at a, b358have high := integerMax.ge_right at a, b359constructor360 . intro below361constructor362 . exact integerLe.transitive_less with low, below363 . exact integerLe.transitive_less with high, below364 . intro both365have total := integerLe.total at a, b366cases total with first | second367 . have value115 := integerMax.of_le with first368rw value115369exact both.right370 . have value116 := integerMax.of_ge with second371rw value116372exact both.left373374theorem integerMin.eq_left_iff (a b : Integer)375shows integerMin(a, b) = a ↔ a ≤ b376proof377constructor378 . intro same379have high := integerMin.le_right at a, b380rw same at high381exact high382 . intro below383exact integerMin.of_le with below384385theorem integerMin.eq_right_iff (a b : Integer)386shows integerMin(a, b) = b ↔ b ≤ a387proof388constructor389 . intro same390have low := integerMin.le_left at a, b391rw same at low392exact low393 . intro above394exact integerMin.of_ge with above395396theorem integerMax.eq_left_iff (a b : Integer)397shows integerMax(a, b) = a ↔ b ≤ a398proof399constructor400 . intro same401have high := integerMax.ge_right at a, b402rw same at high403exact high404 . intro above405exact integerMax.of_ge with above406407theorem integerMax.eq_right_iff (a b : Integer)408shows integerMax(a, b) = b ↔ a ≤ b409proof410constructor411 . intro same412have low := integerMax.ge_left at a, b413rw same at low414exact low415 . intro below416exact integerMax.of_le with below417418theorem integerMin.monotone (a b c d : Integer)419requires first : a ≤ c420requires second : b ≤ d421shows integerLe(integerMin(a, b), integerMin(c, d))422proof423have low := integerMin.le_left at a, b424have high := integerMin.le_right at a, b425apply integerMin.le_iff.backward426constructor427 . exact integerLe.transitive with low, first428 . exact integerLe.transitive with high, second429430theorem integerMax.monotone (a b c d : Integer)431requires first : a ≤ c432requires second : b ≤ d433shows integerLe(integerMax(a, b), integerMax(c, d))434proof435have low := integerMax.ge_left at c, d436have high := integerMax.ge_right at c, d437apply integerMax.le_iff.backward438constructor439 . exact integerLe.transitive with first, low440 . exact integerLe.transitive with second, high441442theorem integerMin.associative (a b c : Integer)443shows integerMin(integerMin(a, b), c) = integerMin(a, integerMin(b, c))444proof445have innerLeft := integerMin.integer at a, b446have innerRight := integerMin.integer at b, c447have total := integerLe.total at a, b448cases total with below | above449 . have value117 := integerMin.of_le with below450rw value117451have totalAC := integerLe.total at a, c452cases totalAC with belowAC | aboveAC453 . have bound : a ≤ integerMin(b, c)454exact integerMin.le_iff.backward with⟨below, belowAC⟩455have value1 := integerMin.of_le with belowAC456have value2 := integerMin.of_le with bound457rw [value1, value2]458rfl459 . have bound : integerMin(b, c) ≤ a460have inner := integerMin.le_right at b, c461exact integerLe.transitive with inner, aboveAC462have value3 := integerMin.of_ge with aboveAC463have value4 := integerMin.of_ge with bound464rw [value3, value4]465have totalBC := integerLe.total at b, c466cases totalBC with belowBC | aboveBC467 . have value118 := integerMin.of_le with belowBC468rw value118469have bound2 : c ≤ b := integerLe.transitive with aboveAC, below470exact integerLe.antisymmetric with bound2, belowBC471 . have value119 := integerMin.of_ge with aboveBC472rw value119473rfl474 . have value120 := integerMin.of_ge with above475rw value120476have totalBC := integerLe.total at b, c477cases totalBC with belowBC | aboveBC478 . have value121 := integerMin.of_le with belowBC479rw value121480have value5 := integerMin.of_ge with above481rw value5482rfl483 . have value122 := integerMin.of_ge with aboveBC484rw value122485have bound : c ≤ a := integerLe.transitive with aboveBC, above486have value6 := integerMin.of_ge with bound487rw value6488rfl489490theorem integerMax.associative (a b c : Integer)491shows integerMax(integerMax(a, b), c) = integerMax(a, integerMax(b, c))492proof493have innerLeft := integerMax.integer at a, b494have innerRight := integerMax.integer at b, c495have total := integerLe.total at a, b496cases total with below | above497 . have value123 := integerMax.of_le with below498rw value123499have totalBC := integerLe.total at b, c500cases totalBC with belowBC | aboveBC501 . have value124 := integerMax.of_le with belowBC502rw value124503have bound : a ≤ c := integerLe.transitive with below, belowBC504have value7 := integerMax.of_le with bound505rw value7506rfl507 . have value125 := integerMax.of_ge with aboveBC508rw value125509have value8 := integerMax.of_le with below510rw value8511rfl512 . have value126 := integerMax.of_ge with above513rw value126514have totalAC := integerLe.total at a, c515cases totalAC with belowAC | aboveAC516 . have bound : a ≤ integerMax(b, c)517have inner := integerMax.ge_right at b, c518exact integerLe.transitive with belowAC, inner519have value9 := integerMax.of_le with belowAC520have value10 := integerMax.of_le with bound521rw [value9, value10]522have totalBC := integerLe.total at b, c523cases totalBC with belowBC | aboveBC524 . have value127 := integerMax.of_le with belowBC525rw value127526rfl527 . have value128 := integerMax.of_ge with aboveBC528rw value128529have bound2 : b ≤ c := integerLe.transitive with above, belowAC530exact integerLe.antisymmetric with aboveBC, bound2531 . have bound : integerMax(b, c) ≤ a532exact integerMax.le_iff.backward with⟨above, aboveAC⟩533have value11 := integerMax.of_ge with aboveAC534have value12 := integerMax.of_ge with bound535rw [value11, value12]536rfl537538theorem integerMin.add_left (a b k : Integer)539shows integerMin(k + a, k + b) = k + integerMin(a, b)540proof541have total := integerLe.total at a, b542cases total with below | above543 . have shifted := integerLe.add_left at a, b, k with below544have value13 := integerMin.of_le with below545have value14 := integerMin.of_le with shifted546rw [value13, value14]547rfl548 . have shifted := integerLe.add_left at b, a, k with above549have value15 := integerMin.of_ge with above550have value16 := integerMin.of_ge with shifted551rw [value15, value16]552rfl553554theorem integerMin.add_right (a b k : Integer)555shows integerMin(a + k, b + k) = integerMin(a, b) + k556proof557have total := integerLe.total at a, b558cases total with below | above559 . have shifted := integerLe.add_right at a, b, k with below560have value17 := integerMin.of_le with below561have value18 := integerMin.of_le with shifted562rw [value17, value18]563rfl564 . have shifted := integerLe.add_right at b, a, k with above565have value19 := integerMin.of_ge with above566have value20 := integerMin.of_ge with shifted567rw [value19, value20]568rfl569570theorem integerMax.add_left (a b k : Integer)571shows integerMax(k + a, k + b) = k + integerMax(a, b)572proof573have total := integerLe.total at a, b574cases total with below | above575 . have shifted := integerLe.add_left at a, b, k with below576have value21 := integerMax.of_le with below577have value22 := integerMax.of_le with shifted578rw [value21, value22]579rfl580 . have shifted := integerLe.add_left at b, a, k with above581have value23 := integerMax.of_ge with above582have value24 := integerMax.of_ge with shifted583rw [value23, value24]584rfl585586theorem integerMax.add_right (a b k : Integer)587shows integerMax(a + k, b + k) = integerMax(a, b) + k588proof589have total := integerLe.total at a, b590cases total with below | above591 . have shifted := integerLe.add_right at a, b, k with below592have value25 := integerMax.of_le with below593have value26 := integerMax.of_le with shifted594rw [value25, value26]595rfl596 . have shifted := integerLe.add_right at b, a, k with above597have value27 := integerMax.of_ge with above598have value28 := integerMax.of_ge with shifted599rw [value27, value28]600rfl601602theorem integerMin.add_one (a b : Integer)603shows integerMin(a +1, b +1) = integerMin(a, b) +1604proof605exact integerMin.add_right at a, b, integerOne606607theorem integerMax.add_one (a b : Integer)608shows integerMax(a +1, b +1) = integerMax(a, b) +1609proof610exact integerMax.add_right at a, b, integerOne611612theorem integerMin.add_integerMax (a b : Integer)613shows integerMin(a, b) + integerMax(a, b) = a + b614proof615have total := integerLe.total at a, b616cases total with below | above617 . have value129 := integerMin.of_le with below618have value130 := integerMax.of_le with below619rw [value129, value130]620rfl621 . have value131 := integerMin.of_ge with above622have value132 := integerMax.of_ge with above623rw [value131, value132]624ring625626theorem integerMax.distribute_integerMin (a b c : Integer)627shows628 integerMax(a, integerMin(b, c)) =629 integerMin(integerMax(a, b), integerMax(a, c))630proof631have leftNat := integerMax.integer at a, b632have rightNat := integerMax.integer at a, c633have reflexive := integerLe.reflexive at a634have total := integerLe.total at b, c635cases total with below | above636 . have outer := integerMax.monotone at a, b, a, c with reflexive, below637have value45 := integerMin.of_le with below638have value46 := integerMin.of_le with outer639rw [value45, value46]640rfl641 . have outer := integerMax.monotone at a, c, a, b with reflexive, above642have value47 := integerMin.of_ge with above643have value48 := integerMin.of_ge with outer644rw [value47, value48]645rfl646647theorem integerMin.distribute_integerMax (a b c : Integer)648shows649 integerMin(a, integerMax(b, c)) =650 integerMax(integerMin(a, b), integerMin(a, c))651proof652have leftNat := integerMin.integer at a, b653have rightNat := integerMin.integer at a, c654have reflexive := integerLe.reflexive at a655have total := integerLe.total at b, c656cases total with below | above657 . have outer := integerMin.monotone at a, b, a, c with reflexive, below658have value49 := integerMax.of_le with below659have value50 := integerMax.of_le with outer660rw [value49, value50]661rfl662 . have outer := integerMin.monotone at a, c, a, b with reflexive, above663have value51 := integerMax.of_ge with above664have value52 := integerMax.of_ge with outer665rw [value51, value52]666rfl667668theorem integerMin.absorb_integerMax (a b : Integer)669shows integerMin(a, integerMax(a, b)) = a670proof671have high := integerMax.ge_left at a, b672exact integerMin.of_le with high673674theorem integerMax.absorb_integerMin (a b : Integer)675shows integerMax(a, integerMin(a, b)) = a676proof677have low := integerMin.le_left at a, b678exact integerMax.of_ge with low679680theorem integerMin.mul_left (a b k : Integer)681requires nonnegative : 0≤ k682shows integerMin(k * a, k * b) = k * integerMin(a, b)683proof684have total := integerLe.total at a, b685cases total with below | above686 . have scaled := integerLe.mul_left at a, b, k with nonnegative, below687have value1 := integerMin.of_le with below688have value2 := integerMin.of_le with scaled689rw [value1, value2]690rfl691 . have scaled := integerLe.mul_left at b, a, k with nonnegative, above692have value1 := integerMin.of_ge with above693have value2 := integerMin.of_ge with scaled694rw [value1, value2]695rfl696697theorem integerMax.mul_left (a b k : Integer)698requires nonnegative : 0≤ k699shows integerMax(k * a, k * b) = k * integerMax(a, b)700proof701have total := integerLe.total at a, b702cases total with below | above703 . have scaled := integerLe.mul_left at a, b, k with nonnegative, below704have value1 := integerMax.of_le with below705have value2 := integerMax.of_le with scaled706rw [value1, value2]707rfl708 . have scaled := integerLe.mul_left at b, a, k with nonnegative, above709have value1 := integerMax.of_ge with above710have value2 := integerMax.of_ge with scaled711rw [value1, value2]712rfl713714theorem integerMin.neg (a b : Integer)715shows integerMin(-a, -b) = -integerMax(a, b)716proof717have total := integerLe.total at a, b718cases total with below | above719 . have flipped := integerLe.neg.forward with below720have value1 := integerMin.of_ge at -a, -b with flipped721have value2 := integerMax.of_le with below722rw [value1, value2]723rfl724 . have flipped := integerLe.neg.forward with above725have value1 := integerMin.of_le at -a, -b with flipped726have value2 := integerMax.of_ge with above727rw [value1, value2]728rfl729730theorem integerMax.neg (a b : Integer)731shows integerMax(-a, -b) = -integerMin(a, b)732proof733have total := integerLe.total at a, b734cases total with below | above735 . have flipped := integerLe.neg.forward with below736have value1 := integerMax.of_ge at -a, -b with flipped737have value2 := integerMin.of_le with below738rw [value1, value2]739rfl740 . have flipped := integerLe.neg.forward with above741have value1 := integerMax.of_le at -a, -b with flipped742have value2 := integerMin.of_ge with above743rw [value1, value2]744rfl745746theorem integerAbs.eq_integerMax (z : Integer)747shows integerAbs(z) = integerMax(z, -z)748proof749havesplit:= integerLe.cases_sign at z750casessplitwith nonnegative | nonpositive751 . have value := integerAbs.of_nonneg with nonnegative752have negated := integerLe.neg_nonneg_iff.forward at z753have flipped : -z ≤ z754have bound := integerLe.neg.forward with nonnegative755have zero : -integerZero = integerZero byring756rw zero at bound757exact integerLe.transitive with bound, nonnegative758have maxValue := integerMax.of_ge at z, -z with flipped759rw [value, maxValue]760rfl761 . have value := integerAbs.of_nonpos with nonpositive762have flipped : z ≤ -z763have bound := integerLe.neg.forward with nonpositive764have zero : -integerZero = integerZero byring765rw zero at bound766exact integerLe.transitive with nonpositive, bound767have maxValue := integerMax.of_le at z, -z with flipped768rw [value, maxValue]769rfl770771theorem integerMin.le_integerAbs (z : Integer)772shows integerMin(z, -z) ≤ integerAbs(z)773proof774have negatedAbs := integerAbs.neg at z775have low := integerMin.le_left at z, -z776have bound := integerAbs.le_self at z777exact integerLe.transitive with low, bound778