Zulip Chat Archive
Stream: new members
Topic: Define function from ∀x, ∃y?
Chris M (Apr 10 2020 at 18:00):
Suppose I have a theorem of the form:
constant P : X → Y → Prop theorem existenceresult : ∀x:X, ∃y:Y, P x y := sorry
How can I define a function f: X → Y
on the basis of existenceresult
, such that ∀x:X, P x f(x)
?
I've looked at the reference manual on the axiom of choice, but I can't actually see how to do this using Lean's choice.
Kevin Buzzard (Apr 10 2020 at 18:01):
You can use the choose
tactic: https://leanprover-community.github.io/mathlib_docs/tactics.html#choose
Chris M (Apr 10 2020 at 18:02):
Is there a way to do it without tactics? (I a tactic is just a command for Lean to search for a proof that doesn't contain tactics, isn't it?)
Kevin Buzzard (Apr 10 2020 at 18:05):
There is, you can use classical.some
to define the function, and classical.some_spec
to prove it has the property you want.
Kevin Buzzard (Apr 10 2020 at 18:05):
What you posted doesn't make sense right now, you have a theorem, but its conclusion isn't a Proposition.
Johan Commelin (Apr 10 2020 at 18:06):
Also see classical.choice
Chris M (Apr 10 2020 at 18:06):
Yeah sorry, typo.
Kevin Buzzard (Apr 10 2020 at 18:07):
variables (X Y : Type) (P : X → Y → Prop) (hP : ∀x:X, ∃y:Y, P x y) include P hP noncomputable def f : X → Y := λ x, classical.some (hP x)
Kevin Buzzard (Apr 10 2020 at 18:08):
People around here get edgy about constants and axioms
Chris M (Apr 10 2020 at 18:09):
Oh, why is that ?
Kevin Buzzard (Apr 10 2020 at 18:09):
variables {X Y : Type} (P : X → Y → Prop) (hP : ∀x:X, ∃y:Y, P x y) include P hP noncomputable def f : X → Y := λ x, classical.some (hP x) example : ∀ x : X, P x (f P hP x) := λ x, classical.some_spec (hP x)
Kevin Buzzard (Apr 10 2020 at 18:10):
Mathlib doesn't have any and we don't really see why we need any.
Kevin Buzzard (Apr 10 2020 at 18:10):
But note that I just had to write f P hP
instead of f
:-)
Kevin Buzzard (Apr 10 2020 at 18:11):
I think once someone told me that they were problematic in some other way, maybe something doesn't work very well with them, but I was a beginner at the time and probably didn't understand what they were talking about
Chris M (Apr 10 2020 at 18:13):
Why is f P hP x
well formed? f
takes an X
but P : X \to Y \to Prop
, and P
can't take hP
either right?
Kevin Buzzard (Apr 10 2020 at 18:14):
I changed the brackets round X and Y to be the squiggly "Lean will fill these in using unification" brackets
Kevin Buzzard (Apr 10 2020 at 18:15):
section parameters (X Y : Type) (P : X → Y → Prop) (hP : ∀x:X, ∃y:Y, P x y) noncomputable def f : X → Y := λ x, classical.some (hP x) example : ∀ x : X, P x (f x) := λ x, classical.some_spec (hP x) end
Here's another way which now looks beautiful
Kevin Buzzard (Apr 10 2020 at 18:16):
section parameters (X Y : Type) (P : X → Y → Prop) (hP : ∀x:X, ∃y:Y, P x y) noncomputable def f : X → Y := λ x, classical.some (hP x) theorem foo : ∀ x : X, P x (f x) := λ x, classical.some_spec (hP x) #check foo -- foo : ∀ (x : X), P x (f x) end #check foo /- foo : ∀ (X Y : Type) (P : X → Y → Prop) (hP : ∀ (x : X), ∃ (y : Y), P x y) (x : X), P x (f X Y P hP x) -/
Inside the section the parameters are suppressed.
Kevin Buzzard (Apr 10 2020 at 18:17):
I think there's some kind of "real Lean programmers don't use constants" thing going on, and I don't really know why, but I try and stick to the general principle of no constants and no axioms
Jannis Limperg (Apr 10 2020 at 18:33):
constant
is just another name for axiom
, isn't it? So when you write constant P : ...
, you're postulating the existence of such a P
rather than stating a result about any such P
(if they exist). The former is dangerous since you could postulate something that contradicts Lean's other axioms.
Chris M (Apr 10 2020 at 18:34):
The last couple of files make sense to me, thanks! I'm surprised though, after having just read about {}
in the docs, that f P hP x
works. I would have guessed that since X,Y
are in {}
brackets, but P
and hP
are not. I would have guessed that f X Y x
would work, but it gives me "can't synthesize placeholder"
Chris M (Apr 10 2020 at 18:35):
@Jannis Limperg, is that different from assuming a variable
that contradicts one of Lean's axioms?
Kevin Buzzard (Apr 10 2020 at 18:35):
You're talking about before I switched to parameters? {}
means "just leave this out completely, I'll guess what it is".
Kevin Buzzard (Apr 10 2020 at 18:36):
So when Lean sees f P hP x
it reads f _ _ P hP x
and then has to guess what the missing things are, and this is easy: for things to typecheck, if you look at the type of P, the missing things must be X and Y
Kevin Buzzard (Apr 10 2020 at 18:37):
The risk of using a constant is that you might be able to prove false
outright. With a variable you can't, you can only prove "forall (something), false".
Kevin Buzzard (Apr 10 2020 at 18:37):
and if you can't actually feed in an example of the something, which you can't if Lean is consistent, then you can't prove false.
Chris M (Apr 10 2020 at 18:39):
yeah, but since P
and hP
are NOT in {}
but in ()
, I would guess that f
would implicitly take the type f: {X Y :Type} \to (X\to Y)
, so that P
and hP
can't be arguments.
Chris M (Apr 10 2020 at 18:39):
Oh that makes sense.
Chris M (Apr 10 2020 at 18:42):
Ok tomorrow I'll look at how to do it with classical.choice. Going to bed now, thanks a lot for the help!
Jannis Limperg (Apr 10 2020 at 18:46):
Chris M said:
Jannis Limperg, is that different from assuming a
variable
that contradicts one of Lean's axioms?
Yes! Consider this example:
section variable FALSE : false lemma everything_is_true {α : Prop} : α := false.rec _ FALSE end #check everything_is_true -- `everything_is_true` says: Under the assumption that we have something of -- type `false`, we can prove anything. lemma zero_eq_one : 0 = 1 := begin apply everything_is_true, -- To apply everything_is_true, we need to exhibit something of type `false`, -- but thankfully there's no such thing. sorry end constant FALSE : false lemma everything_is_true' {α : Prop} : α := false.rec _ FALSE -- `everything_is_true'` says: we can prove anything, no extra assumptions -- needed. So now we're inconsistent. lemma zero_eq_one' : 0 = 1 := begin apply everything_is_true' end
Kenny Lau (Apr 10 2020 at 18:58):
Kevin Buzzard said:
People around here get edgy about constants and axioms
Kevin Buzzard said:
I think once someone told me that they were problematic in some other way, maybe something doesn't work very well with them, but I was a beginner at the time and probably didn't understand what they were talking about
Kevin Buzzard said:
I think there's some kind of "real Lean programmers don't use constants" thing going on, and I don't really know why, but I try and stick to the general principle of no constants and no axioms
Variables can be substituted. If you prove that "for any variable G, a group structure on G induces a semigroup structure on G", then you can use this "theorem" to deduce a semigroup structure on units \Z
; but if you have a constant G, a constant group structure on G, and a theorem that G has a semigroup structure, then you're in effect introducing to the world of Lean a new constant G that exists per fiat, and you cannot substitute it with units \Z
Chris M (Apr 12 2020 at 04:01):
Is it actually possible to define a function from ∀x, ∃y using classical.choice
, instead of classical.some
? I haven't heard of the some
axiom in math, so it must be Lean-specific, and in math one would use choice for this.
Andrew Ashworth (Apr 12 2020 at 04:09):
choice is a derived theorem from some more fundamental axioms assumed in Lean's classical library
Andrew Ashworth (Apr 12 2020 at 04:09):
theorem axiom_of_choice {α : Sort u} {β : α → Sort v} {r : Π x, β x → Prop} (h : ∀ x, ∃ y, r x y) : ∃ (f : Π x, β x), ∀ x, r x (f x) := ⟨_, λ x, some_spec (h x)⟩
Andrew Ashworth (Apr 12 2020 at 04:10):
er, I mean, the axiom of choice you are familiar with is derived from classical.choice. classical.some
is similarly
Andrew Ashworth (Apr 12 2020 at 04:12):
if I remember correctly, old versions of Lean didn't even use classical.choice
, it was all derived from
Andrew Ashworth (Apr 12 2020 at 04:12):
axiom strong_indefinite_description {a : Type u} (p : a → Prop) (h : nonempty a) : { x : a // (∃ y : a, p y) → p x}
Andrew Ashworth (Apr 12 2020 at 04:13):
then at some point it got simplified because it was confusing people
Chris M (Apr 12 2020 at 04:23):
My first impression is that the problem with this is that we don't actually strictly speaking know that strong_indefinite_description
is not stronger than choice? If we want to rigorously know that the classical
axioms actually correspond to the classical axioms, then we should build classical
from the same axioms that are used in mathematics?
Andrew Ashworth (Apr 12 2020 at 04:32):
what is mathematics?
Andrew Ashworth (Apr 12 2020 at 04:33):
ZFC set theory?
Andrew Ashworth (Apr 12 2020 at 04:33):
but Lean's foundations are in the type theory, specifically the calculus of inductive constructions
Andrew Ashworth (Apr 12 2020 at 04:34):
applying the axiom of choice as defined in set theory
Andrew Ashworth (Apr 12 2020 at 04:34):
doesn't really make much sense
Chris M (Apr 12 2020 at 04:39):
I see
Mario Carneiro (Apr 12 2020 at 05:18):
In lean, it is easy to prove that classical.choice
and strong_indefinite_description
are equivalent in strength
Mario Carneiro (Apr 12 2020 at 05:18):
(actually the proof that strong_indefinite_description
follows from choice
is not entirely obvious since it requires Diaconescu's proof of EM first)
Mario Carneiro (Apr 12 2020 at 05:19):
As for whether they are equivalent to the axiom known as the "axiom of choice" in ZFC, this depends on some details of the foundational setup
Mario Carneiro (Apr 12 2020 at 05:20):
lean's choice
is actually closer to Hilbert's epsilon operator, or a variant of AC called "global choice", because it posits a single class function that chooses elements simultaneously from every nonempty set
Mario Carneiro (Apr 12 2020 at 05:21):
The usual formulation of AC in ZFC puts the function that does the choosing behind an existential
Mario Carneiro (Apr 12 2020 at 05:22):
However, it is well known that this is a conservative extension; the general process is known as Skolemization
Mario Carneiro (Apr 12 2020 at 05:24):
In lean you actually can't prove classical.choice
from the theorem axiom_of_choice
mentioned above because of this
Kevin Buzzard (Apr 12 2020 at 08:26):
Chris M said:
Is it actually possible to define a function from ∀x, ∃y using
classical.choice
, instead ofclassical.some
? I haven't heard of thesome
axiom in math, so it must be Lean-specific, and in math one would use choice for this.
@Chris M here are two interesting uses of some
in Lean. For the first one, consider the proof that if is a surjection then there's an injection which is a one-sided inverse. In Lean this construction is immediate using some
-- you pick y : Y
and then observe that we have a non-empty type of x : X
to choose from and use some
to pick one. In ZFC you would use choice for this. Here choice
and some
seem to be about the same.
For the second one, consider the proof that if is a bijection then there's a bijection which is a two-sided inverse. In Lean this construction is also made using some
because even though we have a proof that the preimage contains exactly one term, the assertion has type Prop
, whereas we need to move into the Type
universe if we actually want the element. This whole some
business can be thought of as a method of getting from Lean's proof-irrelevant Prop
universe to the universe Type
where data is remembered. The way Prop
is modelled internally in Lean is that you can make a proof that the pre-image has exactly one element, but because this is in Prop
the statement is just recorded by Lean as being proved, there is no information in the system as to what that element is and in particular there is no way of extracting it. This is a foundational issue where set theory and type theory seem to me to differ. Here when people talk about choice they often just mean the ability to move from Prop
to Type
. some
is somehow the basic example of this.
Chris M (Apr 13 2020 at 04:57):
very interesting. I am actually surprised though that Prop
doesn't record that data, i.e. that propositional extentionality is used as an axiom. To put it a different way, I'm surprised that Choice is considered a classical notion. It seems to me that, according to the constructivist notion of $\exists$
, we only prove it once we have an example. Hence as soon as we've proven it, we do in fact have aconstructed example somewhere. Hence, shouldn't we be able to choose that example, without leaving constructivist logic? This argument basically makes me think that $\exists$
should just be a tuple like $\Sigma$
, i.e. that $\exists$
should just be syntactic sugar for, but otherwise identical to, $\Sigma$
, and that propositional extentionality shouldn't hold. I'm curious where people disagree with my view.
Mario Carneiro (Apr 13 2020 at 05:01):
This is the approach taken in more hardcore constructivist foundations like HoTT. There, there is no difference between Prop and Type
Mario Carneiro (Apr 13 2020 at 05:02):
although propositional extensionality still holds in HoTT, for a different reason
Mario Carneiro (Apr 13 2020 at 05:03):
In HoTT there is a version of choice that is trivial, and then there is another version that is equivalent to the mathematician's axiom of choice, which requires inserting propositional truncations to make the exists have this "forgetting" behavior
Mario Carneiro (Apr 13 2020 at 05:04):
In lean, the reason we care about having Prop around is so that we can forget about witnesses
Mario Carneiro (Apr 13 2020 at 05:04):
This has to do with the semantics behind VM computation and "proof erasure"
Mario Carneiro (Apr 13 2020 at 05:05):
proofs are generally not good for computation so it is nice to be able to forget about them in programs. Reflecting this back into the logic entails that proofs have to be irrelevant, and exists cannot record the witness that proved it
Mario Carneiro (Apr 13 2020 at 05:07):
If you want a proof relevant version of exists, you can use \Sigma
, but it is a conscious decision you have to make. This gives you a little extra bit of expressive power
Chris M (Apr 13 2020 at 05:09):
Mario Carneiro said:
proofs are generally not good for computation so it is nice to be able to forget about them in programs. Reflecting this back into the logic entails that proofs have to be irrelevant, and exists cannot record the witness that proved it
What do you mean by "proofs are generally not good for computation"? In what sense?
Andrew Ashworth (Apr 13 2020 at 05:24):
They represent pieces of code that have to be evaluated when the code is run; it can lead to large amounts of overhead and inefficiency
Mario Carneiro (Apr 13 2020 at 05:36):
If I have a vector of length 5
, say [1,2,3,4,5]
, and want to turn it into a vector of length 3 + 2
, I can do so by applying a theorem that says that 3 + 2 = 5
. But there is no need to evaluate this proof (which boils down to refl 5
) to get the resulting vector, because in memory the resulting vector has the exact same representation [1,2,3,4,5]
so it is a no-op in the computer
Mario Carneiro (Apr 13 2020 at 05:37):
If equality is proof irrelevant, then this "cast" operation is always a no-op, and the computer can just skip the proof, even though it was provided and may very well be computable
Mario Carneiro (Apr 13 2020 at 05:38):
Here the proof is being used to ensure that the program does not go wrong, but it is not needed for the program to actually get to the end result
Chris M (Apr 13 2020 at 06:23):
My impression is that a proof NEVER has to be evaluated. So it seems to me that if Lean just has a general rule that says "never evaluate proofs", then there is no danger of inefficiency. I might have some kind of misconception though.
Reid Barton (Apr 13 2020 at 06:40):
What's your notion of "proof", then, for which they never have to be evaluated?
It sounds like you are suggesting that \exists
effectively shouldn't exist; but its purpose is precisely to be usable in this "proof" context.
Chris M (Apr 13 2020 at 06:43):
My notion of proof is basically, it's a program that could in principle be evaluated, but we are not actually interested in doing so, we are only interested in type checking it to see if it's correct. Once we know it's correct, we know the theorem is true, and that's all there is to it. No need to actually run the proof. Is that wrong?
Kevin Buzzard (Apr 13 2020 at 06:44):
I'm not an expert in this area, but it sounds to me like this is right. Proofs are typechecked and then instantly forgotten
Reid Barton (Apr 13 2020 at 06:45):
Okay but if you want to extract a function from "∀x, ∃y", then you are actually interested in evaluating the "proof" after all, right?
Reid Barton (Apr 13 2020 at 06:47):
I mean, if you want to be able to evaluate the function, you'd better be able to figure out what y
was used to construct the existential and that means evaluating the term of type ∃y, ...
(we can call it a proof or not).
Reid Barton (Apr 13 2020 at 06:54):
So, in Lean, we do have some things called "proofs" that are never evaluated, namely terms whose type is a proposition, and ∃y, P y
is a proposition. That means that from h : ∀x, ∃y, P y
there is no way to extract the data of "the y
for a given x
" (or any other data for that matter) and so you need a nonconstructive axiom if you want to obtain a function. Other systems make different choices.
Chris M (Apr 13 2020 at 06:56):
Reid Barton said:
Okay but if you want to extract a function from "∀x, ∃y", then you are actually interested in evaluating the "proof" after all, right?
Well, it seems to me that I want to extract a function but again not actually evaluate that function. I just want to use it to construct further proofs, all of which won't ever be evaluated.
Reid Barton (Apr 13 2020 at 06:56):
Then that's precisely what choice
is for
Reid Barton (Apr 13 2020 at 06:58):
But if we're saying "we know that there exists such a function, but we have no access to the function", then I don't see how it could be called constructive
Kevin Buzzard (Apr 13 2020 at 07:16):
Chris M said:
Well, it seems to me that I want to extract a function but again not actually evaluate that function. I just want to use it to construct further proofs, all of which won't ever be evaluated.
import tactic example (X : Type) (P : X → Prop) (h : ∃ x : X, P x) : ∃ x : X, P x ∧ P x := begin cases h with x hx, -- x is out! /- 1 goal X : Type, P : X → Prop, x : X, hx : P x ⊢ ∃ (x : X), P x ∧ P x -/ use x, tauto, end
Kevin Buzzard (Apr 13 2020 at 07:17):
You can get to the existential witness without choice if your goal is a proposition.
Kevin Buzzard (Apr 13 2020 at 07:18):
import tactic example (X : Type) (P : X → Prop) (h : ∃ x : X, P x) : { x : X | P x ∧ P x} := begin cases h with x hx, /- induction tactic failed, recursor 'Exists.dcases_on' can only eliminate into Prop -/ sorry end
but not if your goal is data.
Sebastien Gouezel (Apr 13 2020 at 08:34):
I was surprised to see how well Lean can compute, so I just wanted to share this with you. In #2398, I introduce compositions of an integer, i.e., ways to decompose n
as a sum of positive integers, as
structure composition (n : ℕ) := (blocks_pnat : list ℕ+) (blocks_pnat_sum : (blocks_pnat.map (λ n : ℕ+, (n : ℕ))).sum = n)
In the course of the file, I register an explicit equiv between composition n
and fin (n-1)
, to get that the cardinality of composition n
is 2^(n-1)
. After this, Lean can check numerical stuff on compositions! For instance, if you want to check the number of compositions of 9 with length 4 in which the first term is 2, you can ask
#eval fintype.card {s : composition 9 // ∃ (h : s.length = 4), (list.nth_le s.blocks 3 (by { rw [composition.blocks_length, h], norm_num })) = 2}
It works, and answers 15 (I didn't check this is the right answer, but I hope we can trust Lean :). What surprises me is that there is a proof in the definition of the set, needed to show that the set makes sense, but this is not a problem at all for the computation.
Last updated: Dec 20 2023 at 11:08 UTC