Zulip Chat Archive
Stream: general
Topic: Quot lifting `(_ -> T) -> T` to `(_ -> Q) -> Q`
Max Nowak 🐉 (Nov 26 2024 at 21:41):
Take the following MWE. How do you implement Q.ctor
? I haven't played around with Quotients before.
inductive T
| ctor : (Nat -> T) -> T
| ...
inductive Rel : T -> T -> Prop | ...
def Q := Quot Rel
def Q.ctor : (Nat -> Q) -> Q := ?
Edward van de Meent (Nov 26 2024 at 21:43):
this depends a lot on the Rel
you defined.
Max Nowak 🐉 (Nov 26 2024 at 21:44):
I can prove that it is an equivalence relation. Other than that, it's a little complex unfortunately.
Edward van de Meent (Nov 26 2024 at 21:46):
can you prove that, for example, (\forall n, Rel (f n) (g n)) -> Rel (ctor f) (ctor g)
? because if that's not true, there is no clear "natural" implementation.
Edward van de Meent (Nov 26 2024 at 21:47):
also, if you can prove that the relation is an equivalence relation, better use Quotient
for that better API
Max Nowak 🐉 (Nov 26 2024 at 21:49):
Yes I can prove that.
Max Nowak 🐉 (Nov 26 2024 at 21:49):
And yeah I am using Quotient
in my own code.
Edward van de Meent (Nov 26 2024 at 22:16):
by the way, such a function cannot generally be computable, since it requires a choice for every Nat
.
Max Nowak 🐉 (Nov 26 2024 at 22:17):
That is fine, this is supposed to be a ctor anyway.
Edward van de Meent (Nov 26 2024 at 22:22):
here you go:
import Mathlib.Data.Quot
inductive T
| ctor : (Nat -> T) -> T
| nil
noncomputable def Q.ctor (r : Setoid T)
(hr:∀ (f g : Nat → T), (∀ n, f n ≈ g n) → r (T.ctor f) (T.ctor g)):
(Nat -> Quotient r) -> Quotient r := fun g =>
Quotient.lift
(⟦T.ctor ·⟧ : (Nat → T) → Quotient r)
(by simp_rw [Quotient.eq]; exact hr)
(Quotient.choice g)
Max Nowak 🐉 (Nov 26 2024 at 22:41):
I also managed to get the following working:
noncomputable def Q.ctor (r : Setoid T)
(hr: ∀ (f g : Nat → T), f ≈ g → T.ctor f ≈ T.ctor g)
(g : Nat -> Quotient r)
: Quotient r
:= Quotient.lift (fun k => ⟦.ctor k⟧) (fun f g p => Quot.sound (hr f g p)) (Quotient.choice g)
Thanks a ton! :D
Max Nowak 🐉 (Nov 26 2024 at 23:13):
Slightly off-topic, but: Since this is supposed to be a ctor anyway, I don't care about it being noncomputable. I don't want to have to mark any code that uses this ctor as noncomputable however. How do I deal with that?
Right now I'm doing opaque impl := sorry
, and then @[implemented_by]
, but this feels very dirty.
Edward van de Meent (Nov 27 2024 at 06:43):
Afaik, that's the only way to do this...
Kim Morrison (Nov 28 2024 at 05:13):
You can write noncomputable theory
at the top of every file!
Eric Wieser (Nov 28 2024 at 09:56):
Edward van de Meent said:
by the way, such a function cannot generally be computable, (since it requires a choice for every
Nat
)
I know that finite choice can be done computably; can countable choice not also be?
Johan Commelin (Nov 28 2024 at 11:42):
That's Nat.find
Yaël Dillies (Nov 28 2024 at 11:44):
No, Johan. Computable choice is (∀ n, Inhabited (α n)) → Inhabited (∀ n, α n)
. This cannot be done computably
Johan Commelin (Nov 28 2024 at 12:01):
Ooh, right, I got something mixed up
Johan Commelin (Nov 28 2024 at 12:14):
And just to clarify. When you write Inhabited
, you mean it in the sense it is typically used in type theory lingo. I.e., what we call Trunc
in Lean:
import Mathlib
variable (α : Nat → Type)
def countableChoice₁ [∀ n, Inhabited (α n)] : Inhabited (∀ n, α n) :=
⟨fun _ ↦ default⟩
def countableChoice₂ [∀ n, Nonempty (α n)] : Nonempty (∀ n, α n) :=
⟨fun _ ↦ Classical.choice inferInstance⟩
noncomputable
def countableChoice₃ (h : ∀ n, Trunc (α n)) : Trunc (∀ n, α n) :=
Trunc.mk fun n ↦ Trunc.out (h n)
#print axioms countableChoice₁ -- 'countableChoice₁' does not depend on any axioms
#print axioms countableChoice₂ -- 'countableChoice₃' depends on axioms: [Classical.choice]
#print axioms countableChoice₃ -- 'countableChoice₃' depends on axioms: [Classical.choice]
Last updated: May 02 2025 at 03:31 UTC