Zulip Chat Archive

Stream: general

Topic: choice compatible with products


Sébastien Gouëzel (Aug 22 2024 at 09:01):

Is there a way to do something like

def my_better_choice (α : Type*) [Nonempty α] : α := by
  match α with
  | X × Y => (my_better_choice X, my_better_choice Y)
  | _ => Classical.choice α

I.e., have a choice function on nonempty types, which is compatible with the projections in product types?

Sébastien Gouëzel (Aug 22 2024 at 09:33):

I guess no, by the cardinality model (which shows that asking if a type is a product type hasn't a well defined answer).

Filippo A. E. Nuccio (Aug 22 2024 at 09:40):

Interesting! Can you speculate a bit or point to a reference?

Kevin Buzzard (Aug 22 2024 at 09:55):

There's a model of Lean where Fin 2 \times Fin 2 and Fin 4 are equal as types.

Eric Wieser (Aug 22 2024 at 10:29):

Not a great solution, but:

import Mathlib

class HasNiceChoice (α) where
  niceChoice : Nonempty α  α

export HasNiceChoice (niceChoice)

noncomputable instance (priority := low) defaultNiceChoice {α : Type*} : HasNiceChoice α where
  niceChoice := Classical.choice

noncomputable instance Prod.instNiceChoice {α β : Type*}
    [HasNiceChoice α] [HasNiceChoice β] : HasNiceChoice (α × β) where
  niceChoice h := (niceChoice sorry, niceChoice sorry)

Floris van Doorn (Aug 22 2024 at 10:39):

I expect that it is consistent to assume this, i.e. to assume

axiom prodChoice (α : Type*) [Nonempty α] : α
axiom prodChoice_spec {α β : Type*} [Nonempty α] [Nonempty β] :
  prodChoice (α × β) = (prodChoice α, prodChoice β)

I don't see why this should be inconsistent even in the cardinality model. In the model when defining the interpretation of Prod and Prod.mk I think you can ensure that prodChoice_spec holds.
However, I also expect that such a function is not definable in Lean from ordinary choice.

Yaël Dillies (Aug 22 2024 at 11:00):

Isn't HasNiceChoice basically docs#Inhabited ?

Eric Wieser (Aug 22 2024 at 11:01):

Not quite, because HasNiceChoice Empty exists

Sébastien Gouëzel (Aug 22 2024 at 12:33):

I agree that it's certainly consistent to assume this. However, it is also not provable, because the cardinality model gives you a model where this doesn't hold, as follows.

In the cardinality model, all types with the same cardinality are equal. This can be built by starting from a model where the types are distinct, choosing compatible bijections between the types with the same cardinality, and identifying the types under these bijections. Let me start from such a bijection f between and ℕ x ℕ. Assume I have distinguished points in each type (say x : ℕ and y : ℕ x ℕ), compatible with the product structure (i.e. y = (x, x)) and with the identifications (i.e. y = f x). Then f x = (x, x). But it is easy to construct f such that this equality is never true (choose for instance f x to not be in the vertical line above x). This shows that, in the cardinality model constructed using this specific f, then prodChoice is false.

Kyle Miller (Aug 22 2024 at 20:38):

I think this is one of those places where you need your own type universe to keep track of how the type is a product.

import Mathlib.Tactic.Common

universe u

@[pp_with_univ]
inductive PType : Type (u + 1) where
  | incl (α : Type u)
  | prod (α β : PType)

def PType.toType : PType.{u}  Type u
  | .incl α => α
  | .prod α β => α.toType × β.toType

instance : CoeSort PType.{u} (Type u) := PType.toType

noncomputable def PType.choice (α : PType) [inst : Nonempty α] : α :=
  match α, inst with
  | .incl _, inst => Classical.choice inst
  | .prod α β, inst =>
    have := (nonempty_prod.mp inst).1
    have := (nonempty_prod.mp inst).2
    (PType.choice α, PType.choice β)

Last updated: May 02 2025 at 03:31 UTC