1-- Kuhn simplices through the face opposite the top vertex: lowering the base2-- at the last raised coordinate and shifting the permutation the other way3-- gives the second simplex through such a face4-- 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.KuhnTopFace10import KuhnRotation1112-- The inverse cyclic shift sends 0 to n − 1 and l + 1 to l.13def unrotation (n : Set) : Set:= converse(rotation(n), n, n)1415theorem unrotation.bijective (n : Nat)16shows BijectiveBetween(unrotation(n), n, n)17proof18have turn := rotation.bijective at n19unfold unrotation20exact converse.bijective with turn2122theorem unrotation.step (n : Nat) (l : Set)23requires hl : l ∈ n24requires hs : succ(l) ∈ n25shows unrotation(n)(succ(l)) = l26proof27have turn := rotation.step with hl, hs28have bijective := rotation.bijective at n29have same : unrotation(n)(succ(l)) = converse(rotation(n), n, n)(succ(l))30unfold unrotation31rfl32rw [same, ← turn]33exact Bijective.inverse_apply with bijective, hl3435theorem unrotation.wrap (n : Nat) (m : Set)36requires hm : m ∈ n37requires top : succ(m) = n38shows unrotation(n)(0) = m39proof40have turn := rotation.wrap with hm, top41have bijective := rotation.bijective at n42have same : unrotation(n)(0) = converse(rotation(n), n, n)(0)43unfold unrotation44rfl45rw [same, ← turn]46exact Bijective.inverse_apply with bijective, hm4748def unrotated (n upd : Set) : Set:= compose(upd, unrotation(n), n, n, n)4950theorem unrotated.bijective (n : Nat) (upd : Set)51requires updBijective : BijectiveBetween(upd, n, n)52shows BijectiveBetween(unrotated(n, upd), n, n)53proof54have turn := unrotation.bijective at n55unfold unrotated56exact compose.bijective with turn, updBijective5758theorem unrotated.value (n : Nat) (upd l : Set)59requires updBijective : BijectiveBetween(upd, n, n)60requires hl : l ∈ n61shows unrotated(n, upd)(l) = upd(unrotation(n)(l))62proof63have updFunction := Injective.function with (Bijective.injective with updBijective)64have turn := Injective.function with (Bijective.injective with (unrotation.bijective at n))65have same : unrotated(n, upd)(l) = compose(upd, unrotation(n), n, n, n)(l)66unfold unrotated67rfl68rw same69exact compose.apply with turn, updFunction, hl7071theorem unrotated.step (n : Nat) (upd l : Set)72requires updBijective : BijectiveBetween(upd, n, n)73requires hl : l ∈ n74requires hs : succ(l) ∈ n75shows unrotated(n, upd)(succ(l)) = upd(l)76proof77have value := unrotated.value with updBijective, hs78have turn := unrotation.step with hl, hs79rw [value, turn]80rfl8182theorem unrotated.wrap (n : Nat) (upd m : Set)83requires updBijective : BijectiveBetween(upd, n, n)84requires hm : m ∈ n85requires top : succ(m) = n86shows unrotated(n, upd)(0) = upd(m)87proof88have mNat := natural.member at n with hm89have mLess := Less.of_membership with hm90have zeroLess : 0 < n byarith91have zeroIn := membership.of_Less with zeroLess92have value := unrotated.value with updBijective, zeroIn93have turn := unrotation.wrap with hm, top94rw [value, turn]95rfl9697-- The first k + 1 shifted coordinates are upd(n − 1) and the first k of the98-- original.99theorem raised.unrotated (n : Nat) (upd m k : Set)100requires updBijective : BijectiveBetween(upd, n, n)101requires hm : m ∈ n102requires top : succ(m) = n103requires hk : k ∈ n104shows raised(n, unrotated(n, upd), succ(k)) = insert(upd(m), raised(n, upd, k))105proof106have updFunction := Injective.function with (Bijective.injective with updBijective)107have kNat := natural.member at n with hk108have kLess := Less.of_membership with hk109have kInside :=Ordinal.member_subset with (Ordinal.natural at n), hk110ext y111constructor112 . intro hy113obtain⟨inN, l, hl, shape⟩:= raised.membership.forward with hy114have lNat := natural.member at succ(k) with hl115have lLess := Less.of_membership with hl116havesplit:= natural.zero_or_successor with lNat117apply insert.membership.backward118casessplitwith zero | successor119 . left120have value := unrotated.wrap with updBijective, hm, top121rw [shape, zero, value]122rfl123 . right124obtain⟨l2, l2Nat, lEq⟩:= successor125rw lEq at lLess126have l2Less : l2 < k byarith127have l2In := membership.of_Less with l2Less128have l2InN := kInside with l2, l2In129have sLess : succ(l2) < n byarith130have sIn := membership.of_Less with sLess131have value := unrotated.step with updBijective, l2InN, sIn132apply raised.membership.backward133constructor134 . exact inN135 . witness l2136constructor137 . exact l2In138 . rw [shape, lEq, value]139rfl140 . intro hy141havesplit:= insert.membership.forward with hy142casessplitwith same | below143 . have value := unrotated.wrap with updBijective, hm, top144apply raised.membership.backward145constructor146 . rw same147exact FunctionBetween.apply_closed with updFunction, hm148 . witness0149constructor150 . have less : 0 < succ(k) byarith151exact membership.of_Less with less152 . rw [same, value]153rfl154 . obtain⟨inN, l, hl, shape⟩:= raised.membership.forward with below155have lInN := kInside with l, hl156have lNat := natural.member at n with lInN157have lLess := Less.of_membership with hl158have sLess : succ(l) < n byarith159have sIn := membership.of_Less with sLess160have value := unrotated.step with updBijective, lInN, sIn161apply raised.membership.backward162constructor163 . exact inN164 . witness succ(l)165constructor166 . have less : succ(l) < succ(k) byarith167exact membership.of_Less with less168 . rw [shape, value]169rfl170171theorem raised.unrotated_fresh (n : Nat) (upd m k : Set)172requires updBijective : BijectiveBetween(upd, n, n)173requires hm : m ∈ n174requires top : succ(m) = n175requires hk : k ∈ n176shows¬upd(m) ∈ raised(n, upd, k)177proof178have updInjective := Bijective.injective with updBijective179have mNat := natural.member at n with hm180have kNat := natural.member at n with hk181have kLess := Less.of_membership with hk182have kInside :=Ordinal.member_subset with (Ordinal.natural at n), hk183intro inside184obtain⟨inN, l, hl, shape⟩:= raised.membership.forward with inside185have lInN := kInside with l, hl186have lNat := natural.member at n with lInN187have lLess := Less.of_membership with hl188have same := Injective.apply_cancel with updInjective, hm, lInN, shape189rw← top at kLess190arith191192-- The base lowered by one at coordinate upd(m): the unique function with193-- lowered(j) + [j = upd(m)] = base(j).194defunique loweredValue (n base upd m j : Set) (y ∈ ℕ) := y + indicator({upd(m)}, j) = base(j)195requires baseFunction : base : n → ℕ196requires rooted : 0 < base(upd(m))197requires hj : j ∈ n198proof199have baseIn := FunctionBetween.apply_closed with baseFunction, hj200have baseNat := nat.omega.backward with baseIn201have alternatives : j = upd(m) ∨ j ≠ upd(m) bytauto202cases alternatives with same | different203 . have positive : 0 < base(j)204 rwa same205have shape := natural.zero_or_successor with baseNat206cases shape with zero | successor207 . exfalso208rw zero at positive209arith210 . obtain⟨k, kNat, eq⟩:= successor211have kIn := nat.omega.forward with kNat212refine⟨k, kIn, ?_⟩213have one : indicator({upd(m)}, j) =1214rw same215exact indicator.singleton_self216rw [one, eq]217exact add.right_one218 . have separated : upd(m) ≠ j219intro equal220apply different221 symm222exact equal223have zero := indicator.singleton_other with separated224refine⟨base(j), baseIn, ?_⟩225rw zero226exact add.right_unit227uniqueness228intros u hu first v hv second229have uNat := nat.omega.backward with hu230have vNat := nat.omega.backward with hv231have same : u + indicator({upd(m)}, j) = v + indicator({upd(m)}, j)232rw [first, second]233rfl234exact add.right_cancel with same235236defgraph lowered (n base upd m : Set) (j ∈ n) : ℕ := loweredValue(n, base, upd, m, j)237requires baseFunction : base : n → ℕ238requires rooted : 0 < base(upd(m))239proof240have selected := loweredValue.selected at n, base, upd, m, j with*241exact selected.left242243theorem lowered.restores (n : Nat) (base upd m j : Set)244requires baseFunction : base : n → ℕ245requires rooted : 0 < base(upd(m))246requires hj : j ∈ n247shows lowered(n, base, upd, m)(j) + indicator({upd(m)}, j) = base(j)248proof249have value := lowered.value at n, base, upd, m, j with*250have selected := loweredValue.selected at n, base, upd, m, j with*251rw value252exact selected.right253254-- The lowered simplex lists a new bottom followed by vertices 0, …, n − 1 of255-- the original.256theorem kuhnVertex.unrotated (n : Nat) (base upd m k : Set)257requires baseFunction : base : n → ℕ258requires updBijective : BijectiveBetween(upd, n, n)259requires hm : m ∈ n260requires top : succ(m) = n261requires rooted : 0 < base(upd(m))262requires hk : k ∈ n263shows kuhnVertex(n, lowered(n, base, upd, m), unrotated(n, upd))(succ(k)) = kuhnVertex(n, base, upd)(k)264proof265have lowFunction := lowered.function with baseFunction, rooted266have kNat := natural.member at n with hk267have kLess := Less.of_membership with hk268have kInSucc := membership.into_successor with hk269have sLess : succ(k) < succ(n) byarith270have sIn := membership.of_Less with sLess271have leftFunction := kuhnVertex.function_on at n, lowered(n, base, upd, m), unrotated(n, upd), succ(k) with lowFunction, sIn272have rightFunction := kuhnVertex.function_on at n, base, upd, k with baseFunction, kInSucc273apply FunctionBetween.ext with leftFunction, rightFunction274intros j hj275have leftValue := kuhnVertex.coordinate at n, lowered(n, base, upd, m), unrotated(n, upd), succ(k), j with lowFunction, sIn, hj276have rightValue := kuhnVertex.coordinate at n, base, upd, k, j with baseFunction, kInSucc, hj277have image := raised.unrotated with updBijective, hm, top, hk278have fresh := raised.unrotated_fresh with updBijective, hm, top, hk279havesplit:= indicator.insert_fresh at upd(m), raised(n, upd, k), j with fresh280have restores := lowered.restores with baseFunction, rooted, hj281have lowNat := nat.omega.backward with (FunctionBetween.apply_closed with lowFunction, hj)282rw [leftValue, rightValue, image, split, ← restores]283exact add.associative_reverse284285theorem kuhnSimplex.unrotated_face (n : Nat) (base upd m : Set)286requires baseFunction : base : n → ℕ287requires updBijective : BijectiveBetween(upd, n, n)288requires hm : m ∈ n289requires top : succ(m) = n290requires rooted : 0 < base(upd(m))291shows kuhnSimplex(n, base, upd) ∖ {kuhnVertex(n, base, upd)(n)} =292 kuhnSimplex(n, lowered(n, base, upd, m), unrotated(n, upd)) ∖293 {kuhnVertex(n, lowered(n, base, upd, m), unrotated(n, upd))(0)}294proof295have updInjective := Bijective.injective with updBijective296have lowFunction := lowered.function with baseFunction, rooted297have unrotatedInjective := Bijective.injective with (unrotated.bijective with updBijective)298have zeroLess : 0 < succ(n) byarith299have zeroIn := membership.of_Less with zeroLess300have nIn := bootstrap.succ.self at n301ext x302constructor303 . intro hx304have parts := difference.singleton_membership.forward with hx305obtain⟨inSpace, k, hk, shape⟩:= kuhnSimplex.membership.forward with parts.left306have kIn : k ∈ n307havesplit:= bootstrap.succ.membership.forward with hk308casessplitwith below | same309 . exact below310 . exfalso311apply parts.right312rw [shape, same]313rfl314have kNat := natural.member at n with kIn315have kLess := Less.of_membership with kIn316have sLess : succ(k) < succ(n) byarith317have sIn := membership.of_Less with sLess318have agree := kuhnVertex.unrotated with baseFunction, updBijective, hm, top, rooted, kIn319apply difference.singleton_membership.backward320constructor321 . rw [shape, ← agree]322exact kuhnVertex.member with lowFunction, sIn323 . intro equal324rw [shape, ← agree] at equal325have same := kuhnVertex.injective with lowFunction, unrotatedInjective, sIn, zeroIn, equal326arith327 . intro hx328have parts := difference.singleton_membership.forward with hx329obtain⟨inSpace, l, hl, shape⟩:= kuhnSimplex.membership.forward with parts.left330have lNat := natural.member at succ(n) with hl331have lLess := Less.of_membership with hl332havesplit:= natural.zero_or_successor with lNat333casessplitwith zero | successor334 . exfalso335apply parts.right336rw [shape, zero]337rfl338 . obtain⟨k, kNat, lEq⟩:= successor339rw lEq at lLess340have kLess : k < n byarith341have kIn := membership.of_Less with kLess342have kInSucc := membership.into_successor with kIn343have agree := kuhnVertex.unrotated with baseFunction, updBijective, hm, top, rooted, kIn344apply difference.singleton_membership.backward345constructor346 . rw [shape, lEq, agree]347exact kuhnVertex.member with baseFunction, kInSucc348 . intro equal349rw [shape, lEq, agree] at equal350have same := kuhnVertex.injective with baseFunction, updInjective, kInSucc, nIn, equal351rw same at kIn352exact membership.irreflexive with kIn353354-- Away from the top vertex, coordinate upd(n − 1) is constant on a simplex.355theorem kuhnSimplex.top_face_constant (n : Nat) (base upd m x : Set)356requires baseFunction : base : n → ℕ357requires updBijective : BijectiveBetween(upd, n, n)358requires hm : m ∈ n359requires top : succ(m) = n360requires hx : x ∈ kuhnSimplex(n, base, upd) ∖ {kuhnVertex(n, base, upd)(n)}361shows x(upd(m)) = base(upd(m))362proof363have updFunction := Injective.function with (Bijective.injective with updBijective)364have jIn := FunctionBetween.apply_closed with updFunction, hm365have parts := difference.singleton_membership.forward with hx366obtain⟨inSpace, k, hk, shape⟩:= kuhnSimplex.membership.forward with parts.left367have kIn : k ∈ n368havesplit:= bootstrap.succ.membership.forward with hk369casessplitwith below | same370 . exact below371 . exfalso372apply parts.right373rw [shape, same]374rfl375have fresh := raised.unrotated_fresh with updBijective, hm, top, kIn376have zero := indicator.absent with fresh377have value := kuhnVertex.coordinate at n, base, upd, k, upd(m) with baseFunction, hk, jIn378have baseNat := nat.omega.backward with (FunctionBetween.apply_closed with baseFunction, jIn)379rw [shape, value, zero]380exact add.right_unit381382-- A top face off the wall x_{upd(n − 1)} = 0 has a positive base coordinate383-- there, so the lowered base exists.384theorem kuhnSimplex.top_face_rooted (n : Nat) (base upd m : Set)385requires baseFunction : base : n → ℕ386requires updBijective : BijectiveBetween(upd, n, n)387requires hm : m ∈ n388requires top : succ(m) = n389requires notZero : ∃ x ∈ kuhnSimplex(n, base, upd) ∖ {kuhnVertex(n, base, upd)(n)}, x(upd(m)) ≠0390shows0 < base(upd(m))391proof392have updFunction := Injective.function with (Bijective.injective with updBijective)393have jIn := FunctionBetween.apply_closed with updFunction, hm394have baseNat := nat.omega.backward with (FunctionBetween.apply_closed with baseFunction, jIn)395obtain⟨x, hx, apart⟩:= notZero396have constant := kuhnSimplex.top_face_constant with baseFunction, updBijective, hm, top, hx397rw constant at apart398have shape := natural.zero_or_successor with baseNat399cases shape with zero | successor400 . exfalso401exact apart with zero402 . obtain⟨k, kNat, eq⟩:= successor403rw eq404arith405406-- Through the face opposite the top vertex there are exactly the original407-- simplex and its lowering.408theorem kuhnSimplex.top_face_neighbours (n : Nat) (base upd m b2 u2 c : Set)409requires baseFunction : base : n → ℕ410requires updBijective : BijectiveBetween(upd, n, n)411requires hm : m ∈ n412requires top : succ(m) = n413requires rooted : 0 < base(upd(m))414requires f2 : b2 : n → ℕ415requires bij2 : BijectiveBetween(u2, n, n)416requires hc : c ∈ kuhnSimplex(n, b2, u2)417requires same : kuhnSimplex(n, b2, u2) ∖ {c} = kuhnSimplex(n, base, upd) ∖ {kuhnVertex(n, base, upd)(n)}418shows kuhnSimplex(n, b2, u2) = kuhnSimplex(n, base, upd) ∨419 kuhnSimplex(n, b2, u2) = kuhnSimplex(n, lowered(n, base, upd, m), unrotated(n, upd))420proof421have updFunction := Injective.function with (Bijective.injective with updBijective)422have injective2 := Bijective.injective with bij2423have jIn := FunctionBetween.apply_closed with updFunction, hm424have mNat := natural.member at n with hm425have mLess := Less.of_membership with hm426have zeroLess : 0 < n byarith427have positive := membership.of_Less with zeroLess428have lowFunction := lowered.function with baseFunction, rooted429have unrotatedBijective := unrotated.bijective with updBijective430obtain⟨inSpace, k, hk, shape⟩:= kuhnSimplex.membership.forward with hc431have constant : ∀ l ∈ succ(n), l ≠ k → kuhnVertex(n, b2, u2)(l)(upd(m)) = base(upd(m))432intros l hl different433have vertexMember := kuhnVertex.member at n, b2, u2, l with f2, hl434have inFace : kuhnVertex(n, b2, u2)(l) ∈ kuhnSimplex(n, b2, u2) ∖ {c}435apply difference.singleton_membership.backward436constructor437 . exact vertexMember438 . intro equal439rw shape at equal440have index := kuhnVertex.injective with f2, injective2, hl, hk, equal441exact different with index442rw same at inFace443exact kuhnSimplex.top_face_constant with baseFunction, updBijective, hm, top, inFace444have index := kuhnSimplex.constant_face_index with f2, bij2, hk, jIn, constant445cases index with zero | topIndex446 . right447rw [shape, zero] at same448have face := kuhnSimplex.unrotated_face with baseFunction, updBijective, hm, top, rooted449rw face at same450exact kuhnSimplex.eq_bottom with f2, bij2, lowFunction, unrotatedBijective, positive, same451 . left452rw [shape, topIndex] at same453exact kuhnSimplex.eq_top with f2, bij2, baseFunction, updBijective, positive, same454455theorem kuhnSimplex.unrotated_ne (n : Nat) (base upd m : Set)456requires baseFunction : base : n → ℕ457requires updBijective : BijectiveBetween(upd, n, n)458requires hm : m ∈ n459requires top : succ(m) = n460requires rooted : 0 < base(upd(m))461shows kuhnSimplex(n, lowered(n, base, upd, m), unrotated(n, upd)) ≠ kuhnSimplex(n, base, upd)462proof463have updInjective := Bijective.injective with updBijective464have lowFunction := lowered.function with baseFunction, rooted465have unrotatedInjective := Bijective.injective with (unrotated.bijective with updBijective)466have mNat := natural.member at n with hm467have mLess := Less.of_membership with hm468have zeroLess : 0 < n byarith469have positive := membership.of_Less with zeroLess470have zeroIn := membership.into_successor with positive471have oneLess : succ(0) < succ(n) byarith472have oneIn := membership.of_Less with oneLess473intro equal474have bottomMember := kuhnVertex.member at n, lowered(n, base, upd, m), unrotated(n, upd), 0with lowFunction, zeroIn475rw equal at bottomMember476have bounds := kuhnSimplex.sum_bounds with baseFunction, updInjective, bottomMember477have bottomSum := kuhnVertex.sum with lowFunction, unrotatedInjective, zeroIn478have oneSum := kuhnVertex.sum with lowFunction, unrotatedInjective, oneIn479have agree := kuhnVertex.unrotated with baseFunction, updBijective, hm, top, rooted, positive480have zeroSum := kuhnVertex.sum with baseFunction, updInjective, zeroIn481rw [agree, zeroSum] at oneSum482have lower := bounds.left483rw bottomSum at lower484have baseWeights : ∀ j ∈ n, base(j) ∈ ℕ485intros j hj486exact FunctionBetween.apply_closed with baseFunction, hj487have baseSum := natSum.natural with (Finite.natural at n), baseWeights488have lowWeights : ∀ j ∈ n, lowered(n, base, upd, m)(j) ∈ ℕ489intros j hj490exact FunctionBetween.apply_closed with lowFunction, hj491have lowSum := natSum.natural with (Finite.natural at n), lowWeights492arith493