1-- Choice-free selection by least code: a set coded injectively into the2-- naturals lets every point of a domain pick, among the candidates a3-- relation offers it, the one of least code; a domain whose points are4-- separated by candidates from a countable set is countable5-- Part of Cumulus, the Grace17 mathematics library.6-- Copyright (c) 2026 Grant Passmore.7-- Released under the Apache License 2.0. See LICENSE in the repository root.8-- Authors: Grant Passmore910module Grace.Cumulus.Cardinal.LeastCode11import Countable12import Set1314-- Selection by least code. A relation R offers each point x of D the15-- candidates W ∈ B with relates(R, x, W); under an injective code16-- g : B → ℕ the point selects the candidate of least code. No choice is17-- involved: the least code is the least element of a set of naturals.1819def candidates (R x B : Set) : Set:= { W ∈ B | relates(R, x, W) }2021def candidateCodes (g R x B : Set) : Set:= { g(W) | W ∈ candidates(R, x, B) }2223def leastCoded (g R D B : Set) : Set:=24 { p ∈ D × B |∃ x ∈ D, ∃ W ∈ B, p = (x ↦ W) ∧25 relates(R, x, W) ∧ (∀ V ∈ B, relates(R, x, V) → g(W) ⊆ g(V)) }2627theorem leastCoded.relates (g R D B x W : Set)28shows relates(leastCoded(g, R, D, B), x, W) ↔29 x ∈ D ∧ W ∈ B ∧ relates(R, x, W) ∧30 (∀ V ∈ B, relates(R, x, V) → g(W) ⊆ g(V))31proof32constructor33 . intro edge34unfold relates at edge35have parts := leastCoded.membership.forward with edge36obtain⟨x2, hx2, W2, hW2, shape, related, least⟩:= parts.right37obtain⟨rfl, rfl⟩:= orderedPair.injective with shape38exact⟨hx2, hW2, related, least⟩39 . intro h40obtain⟨hx, hW, related, least⟩:= h41unfold relates42apply leastCoded.membership.backward43constructor44 . exact product.pair with hx, hW45 . exact⟨x, hx, W, hW, rfl, related, least⟩4647-- Existence: the codes of the candidates form a nonempty set of naturals,48-- hence of ordinals, and its least element is the code of a candidate.49theorem leastCoded.exists (g R D B x : Set)50requires code : InjectiveBetween(g, B, ℕ)51requires offered : ∀ x ∈ D, ∃ W ∈ B, relates(R, x, W)52requires hx : x ∈ D53shows∃ W ∈ B, relates(leastCoded(g, R, D, B), x, W)54proof55have function := Injective.function with code56obtain⟨W0, hW0, related0⟩:= offered with x, hx57have candidate0 : W0 ∈ candidates(R, x, B)58exact candidates.membership.backward with⟨hW0, related0⟩59have code0 : g(W0) ∈ candidateCodes(g, R, x, B)60exact candidateCodes.membership.backward with⟨W0, candidate0, rfl⟩61have ordinals : ∀ n ∈ candidateCodes(g, R, x, B), n ∈Ordinal62intros n hn63obtain⟨W, hW, shape⟩:= candidateCodes.membership.forward with hn64have parts := candidates.membership.forward with hW65have natural := FunctionBetween.apply_closed with function, parts.left66rw← shape67exactOrdinal.member withOrdinal.omega, natural68have inhabited : Nonempty(candidateCodes(g, R, x, B)) :=⟨g(W0), code0⟩69have nonempty := Nonempty.ne_empty with inhabited70obtain⟨m, hm, least⟩:=Ordinal.least with ordinals, nonempty71obtain⟨W, hW, shape⟩:= candidateCodes.membership.forward with hm72have parts := candidates.membership.forward with hW73witness W74constructor75 . exact parts.left76 . apply leastCoded.relates.backward77refine⟨hx, parts.left, parts.right, ?_⟩78intros V hV relatedV79have candidateV : V ∈ candidates(R, x, B)80exact candidates.membership.backward with⟨hV, relatedV⟩81have codeV : g(V) ∈ candidateCodes(g, R, x, B)82exact candidateCodes.membership.backward with⟨V, candidateV, rfl⟩83rw shape84exact least with g(V), codeV8586-- Uniqueness: two least codes are each below the other, so they are equal,87-- and the code is injective.88theorem leastCoded.unique (g R D B x W V : Set)89requires code : InjectiveBetween(g, B, ℕ)90requires first : relates(leastCoded(g, R, D, B), x, W)91requires second : relates(leastCoded(g, R, D, B), x, V)92shows W = V93proof94obtain⟨hx, hW, relatedW, leastW⟩:= leastCoded.relates.forward with first95obtain⟨hx2, hV, relatedV, leastV⟩:= leastCoded.relates.forward with96 second97have below := leastW with V, hV, relatedV98have above := leastV with W, hW, relatedW99have same := Subset.antisymmetric with below, above100exact Injective.apply_cancel with code, hW, hV, same101102theorem leastCoded.function (g R D B : Set)103requires code : InjectiveBetween(g, B, ℕ)104requires offered : ∀ x ∈ D, ∃ W ∈ B, relates(R, x, W)105shows leastCoded(g, R, D, B) : D → B106proof107refine⟨?_, ?_, ?_⟩108 . intros p hp109have parts := leastCoded.membership.forward with hp110exact parts.left111 . intros x W first V second112exact leastCoded.unique with code, first, second113 . intros x hx114exact leastCoded.exists with code, offered, hx115116-- When no candidate is offered to two different points, the selection is117-- injective.118theorem leastCoded.injective (g R D B : Set)119requires code : InjectiveBetween(g, B, ℕ)120requires offered : ∀ x ∈ D, ∃ W ∈ B, relates(R, x, W)121requires separated : ∀ x ∈ D, ∀ y ∈ D, ∀ W ∈ B,122 relates(R, x, W) → relates(R, y, W) → x = y123shows InjectiveBetween(leastCoded(g, R, D, B), D, B)124proof125constructor126 . exact leastCoded.function with code, offered127 . intros x hx y hy W hW first second128obtain⟨hx2, hW2, relatedX, leastX⟩:= leastCoded.relates.forward with129 first130obtain⟨hy2, hW3, relatedY, leastY⟩:= leastCoded.relates.forward with131 second132exact separated with x, hx, y, hy, W, hW, relatedX, relatedY133134-- Hence a domain whose points are separated by candidates from a countable135-- set is countable: compose the selection with the code.136theorem leastCoded.countable (g R D B : Set)137requires code : InjectiveBetween(g, B, ℕ)138requires offered : ∀ x ∈ D, ∃ W ∈ B, relates(R, x, W)139requires separated : ∀ x ∈ D, ∀ y ∈ D, ∀ W ∈ B,140 relates(R, x, W) → relates(R, y, W) → x = y141shows Countable(D)142proof143have injective := leastCoded.injective with code, offered, separated144have composite := compose.injective with injective, code145exact⟨compose(g, leastCoded(g, R, D, B), D, B, ℕ), composite⟩146