Zulip Chat Archive
Stream: maths
Topic: An arbitrary choice that can only be made in one way
Mitchell Lee (Dec 29 2024 at 07:02):
I am asking this question purely out of curiosity. I hope that is okay.
In Lean, the axiom of choice (docs#Classical.choice) is a definition that produces a term of any nonempty type.
axiom Classical.choice {α : Sort u} : Nonempty α → α
If we add the hypothesis that the type is a subsingleton (and so, there is exactly one term of that type), we get this:
example {α : Sort u} : Nonempty α → Subsingleton α → α := sorry
Can this sorry
be completed without the axiom of choice? Is it equivalent to the axiom of choice?
Daniel Weber (Dec 29 2024 at 07:03):
This is called unique choice, see https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/Strength.20of.20Nonempty.20.CE.B1.20.E2.86.92.20Squash.20.CE.B1
Mitchell Lee (Dec 29 2024 at 07:03):
Thanks!
Kevin Buzzard (Dec 29 2024 at 08:18):
(I think the answer to both your questions is "not in lean's type theory")
Edward van de Meent (Dec 29 2024 at 09:38):
would this imply DNE in leans type theory? :thinking:
Daniel Weber (Dec 29 2024 at 11:48):
I don't think so, it only lifts propositions to data, but I think Quot a -> a
might
Jz Pan (Dec 29 2024 at 14:47):
Mitchell Lee said:
Can this
sorry
be completed without the axiom of choice
I don't think so; sometimes in mathematics, something is unique, but whose construction still requires axiom of choice...
Junyan Xu (Dec 29 2024 at 15:29):
The short answer is that you can't produce data out of proofs without choice. As an example, consider the recently added (by myself) docs#DirectLimit, defined as a quotient of the disjoint union. For a unary operation like negation or inverse, we can lift it to the quotient computably. But for a binary operation like addition or multiplication, we can't do it computably (see noncomputable def DirectLimit.map₂): the two operands can come from different components in the disjoint union, and we need to map them to the same component before performing the operation, but since docs#IsDirected is Prop-valued, it doesn't give a compuatble choice of a component that both components map into, even though the result in the quotient is independent of the choice. If we make a Type-valued version of IsDirected with field directed (a b : α) : Trunc {c : α // r a c ∧ r b c}
, then we could make map₂ computably, but mathlib doesn't care enough about computably for this to happen. (Similarly, DirectLimit.map₀ could be made computable if Nonempty
is replaced by Inhabited
or Trunc (Inhabited _)
.
Kyle Miller (Dec 29 2024 at 15:54):
Assuming just Classical.em
, it's interesting to me that you can still 'construct' unconstructable data with unique_choice
. (1) This is enough to define Classical.propDecidable
(implied by decide'_iff
below), and (2) applying decide'
to a proposition independent of Lean's theory gives an indeterminate Bool
.
axiom unique_choice {α : Sort _} : Nonempty α → Subsingleton α → α
noncomputable def decide' (p : Prop) : Bool :=
Subtype.val <| @unique_choice {b : Bool // (p ∧ b = true) ∨ (¬ p ∧ b = false)}
(by
by_cases p
· exists true
simp [*]
· exists false
simp [*])
⟨by simp⟩
theorem decide'_iff (p : Prop) : decide' p ↔ p := by
unfold decide'
generalize unique_choice _ _ = s
obtain ⟨_, ⟨hp, rfl⟩ | ⟨hp, rfl⟩⟩ := s
<;> simp [*]
Daniel Weber (Dec 29 2024 at 16:39):
Daniel Weber said:
I don't think so, it only lifts propositions to data, but I think
Quot a -> a
might
Yep,
axiom squash_choice {α : Type u} : Squash α → α
theorem test (U V : Prop → Prop) (hUV : U = V) (exU : Squash {x // U x})
(exV : Squash {x // V x}) : (squash_choice exU).1 = (squash_choice exV).1 := by
subst hUV
congr
apply Subsingleton.elim
theorem em (p : Prop) : p ∨ ¬ p :=
let U (x : Prop) : Prop := x = True ∨ p
let V (x : Prop) : Prop := x = False ∨ p
have exU : Squash {x // U x} := .mk ⟨True, Or.inl rfl⟩
have exV : Squash {x // V x} := .mk ⟨False, Or.inl rfl⟩
let u : Prop := (squash_choice exU).1
let v : Prop := (squash_choice exV).1
have u_def : U u := Subtype.property _
have v_def : V v := Subtype.property _
have not_uv_or_p : u ≠ v ∨ p :=
match u_def, v_def with
| .inr h, _ => .inr h
| _, .inr h => .inr h
| .inl hut, .inl hvf =>
have hne : u ≠ v := by simp [hut, hvf, true_ne_false]
.inl hne
have p_implies_uv : p → u = v :=
fun hp ↦
test U V (by simp [U, V, hp]) exU exV
match not_uv_or_p with
| .inl a => .inr (fun hp ↦ a (p_implies_uv hp))
| .inr a => .inl a
Mitchell Lee (Dec 29 2024 at 21:54):
Thanks everyone for the interesting answers.
Last updated: May 02 2025 at 03:31 UTC