Zulip Chat Archive
Stream: new members
Topic: negative natural numbers
Damiano Testa (Sep 02 2020 at 07:42):
Dear All,
every once in a while, I am confronted with Lean accepting and working with functions that I thought would not have to exist. Here is a simple example
def shift1 : ℕ → ℕ := λ i : ℕ , i-1
#eval shift1 0 --- 0
#eval shift1 1 --- 0
#eval shift1 0 - shift1 1 --- 0
I gather than Lean considers "negative natural numbers" as equal to 0
. I always feel a little worried by this.
- Why does Lean not ask me to prove that the codomain of
shift1
isℕ
? - Assuming that Lean is being lazy about it, why does Lean not complain when I apply
shift1
at0
? - Does this not cause consistency issues with proof checking?
Mario Carneiro (Sep 02 2020 at 07:45):
When you use -
and the domain is natural numbers, you get the function nat.sub : nat -> nat -> nat
, which is truncated subtraction
Mario Carneiro (Sep 02 2020 at 07:45):
there is no inference of alternatives, and this can sometimes cause surprises, but there is no consistency concern, it's just a weird function
Bryan Gin-ge Chen (Sep 02 2020 at 07:45):
As Mario says, 1+2 might be cleared up if you inspect the definition of natural number subtraction in Lean. This blog post of @Kevin Buzzard is related too.
Mario Carneiro (Sep 02 2020 at 07:47):
If you want "proper subtraction", you should write (a - b : int)
(even if a
and b
have type nat
). Then it will infer int.sub
instead (which is sensible) and coerce a
and b
to integers
Mario Carneiro (Sep 02 2020 at 07:48):
Of course, if you do this lean will complain about the type you have given shift1
Damiano Testa (Sep 02 2020 at 07:48):
Ok, so you are saying that what Lean checks is correct, but it is on me to check that I am not using -
where I should not?
Mario Carneiro (Sep 02 2020 at 07:48):
well, if you wanted truncated subtraction then it might be the right thing
Johan Commelin (Sep 02 2020 at 07:49):
@Damiano Testa You cannot prove that a function (or any term, for that matter) has a certain type. It has only one type, Lean can try to check it for you, but from a proving point of view, it's inaccesible.
Scott Morrison (Sep 02 2020 at 07:49):
Yes, just like it's on you to put parentheses in the right places!
Damiano Testa (Sep 02 2020 at 07:49):
Mario Carneiro said:
If you want "proper subtraction", you should write
(a - b : int)
(even ifa
andb
have typenat
). Then it will inferint.sub
instead (which is sensible) and coercea
andb
to integers
I see, so, to be safe, I should be using "integer subtraction" and prove that I land in the naturals in my applications
Mario Carneiro (Sep 02 2020 at 07:49):
but usually yes, you should just always use it when you have a hypothesis saying it is sensible
Johan Commelin (Sep 02 2020 at 07:49):
So if you write def shift1 : ℕ → ℕ :=
then what ever comes afterwards must be a function that has a well-defined nat
value when you stick in 0
.
Johan Commelin (Sep 02 2020 at 07:50):
You could also define shift1 : pnat -> nat
... and then you cannot evaluate it on 0
, but only on terms of type pnat
, which consist of nat
+ a proof of positivity.
Johan Commelin (Sep 02 2020 at 07:50):
In practice however, it is easier to use the shift1
that you defined.
Mario Carneiro (Sep 02 2020 at 07:51):
(It's called nat.pred
btw)
Johan Commelin (Sep 02 2020 at 07:51):
And then put the possitivity assumptions in the theorems that you want to prove.
Damiano Testa (Sep 02 2020 at 07:51):
Ok, these answers clarified my doubts and confirmed my fears! I am glad to hear that Lean is acting consistently, I am less happy about having to now check that when I use -
is really should make sure that -
is the function that I think it is!
Johan Commelin (Sep 02 2020 at 07:51):
Mario Carneiro said:
(It's called
nat.pred
btw)
But that one has syntactic issues... because i - 1
looks a lot better.
Mario Carneiro (Sep 02 2020 at 07:52):
it is nat.pred
up to equality
Mario Carneiro (Sep 02 2020 at 07:52):
Kevin will tell you to just avoid ever using -
on naturals
Johan Commelin (Sep 02 2020 at 07:52):
But you can't avoid using 1/x
on the rationals...
Johan Commelin (Sep 02 2020 at 07:53):
Damiano Testa said:
Ok, these answers clarified my doubts and confirmed my fears! I am glad to hear that Lean is acting consistently, I am less happy about having to now check that when I use
-
is really should make sure that-
is the function that I think it is!
There will be a theorem that says that it is the function you think it is for all sensible inputs.
Mario Carneiro (Sep 02 2020 at 07:53):
If you prove a good selection of theorems about your definitions, you will very likely notice if you have missed a hypothesis
Damiano Testa (Sep 02 2020 at 07:53):
So, just to make it completely explicit: a-b
in Lean means what I would write on a board as max 0 (a-b)
Lean takes care of checking that with this definition, everything follows
Johan Commelin (Sep 02 2020 at 07:53):
1/0 = 0
, but for all nonzero x
, we have a theorem that says x * (1/x) = 1
Damiano Testa (Sep 02 2020 at 07:54):
Alright, my doubts have dissolved, my fears have crystallized!
Damiano Testa (Sep 02 2020 at 07:54):
thank you!
Mario Carneiro (Sep 02 2020 at 07:54):
similarly, we have a theorem that says a-b
means what you would write on a board as a-b
whenever it could possibly land in the type you have ascribed to it
Johan Commelin (Sep 02 2020 at 07:55):
Of course def shift1' : int -> int := \lam i, i - 1
is mathematically pure
Mario Carneiro (Sep 02 2020 at 07:55):
otherwise it yields "garbage"and we quietly ignore that case
Johan Commelin (Sep 02 2020 at 07:56):
@Damiano Testa Have you ever tried #eval 7.3/2.5
?
Mario Carneiro (Sep 02 2020 at 07:56):
ouch
Damiano Testa (Sep 02 2020 at 07:56):
Right, except that if I am trying to shift the coefficients of a polynomial, then I am assigning the constant term to lots of coefficients that should be getting a coefficient of 0
Mario Carneiro (Sep 02 2020 at 07:57):
shouldn't the coefficient map be going the other direction?
Damiano Testa (Sep 02 2020 at 07:57):
Johan Commelin said:
Damiano Testa Have you ever tried
#eval 7.3/2.5
?
are you trying to discourage me from using Lean?!?! Ahahaha
Johan Commelin (Sep 02 2020 at 07:57):
What exactly are you trying to do? Can you write down the function in maths $$ \latex here $$
Johan Commelin (Sep 02 2020 at 07:59):
@Damiano Testa Is it , or what kind of map do you want?
Damiano Testa (Sep 02 2020 at 07:59):
Mario Carneiro said:
shouldn't the coefficient map be going the other direction?
In my mind, I have a polynomial f
and I want to write is as x^N*g
, where g
is not divisible by x
. For this, I shift coefficients by N
...
Mario Carneiro (Sep 02 2020 at 08:00):
What's happening with the coefficients below N
?
Damiano Testa (Sep 02 2020 at 08:00):
the polynomial f
has coefficients below N
equal to 0...
Mario Carneiro (Sep 02 2020 at 08:01):
In that situation you can define g(i) = f(i+N)
Johan Commelin (Sep 02 2020 at 08:01):
I wish multiplicity
would be easier to use... but I'm scared of sending you in that direction. It is what should be used here.
Mario Carneiro (Sep 02 2020 at 08:01):
where ()
is coeff
Damiano Testa (Sep 02 2020 at 08:02):
but in order to construct the support
for g
i need to do the opposite shift, no?
Johan Commelin (Sep 02 2020 at 08:02):
I don't think you should construct the polynomial by hand.
Damiano Testa (Sep 02 2020 at 08:02):
Johan Commelin said:
I don't think you should construct the polynomial by hand.
Ok, but I know of no other way...
Mario Carneiro (Sep 02 2020 at 08:03):
You could say N
is the largest integer such that there exists g
such that f = x^N*g
Damiano Testa (Sep 02 2020 at 08:03):
(to be clear, in this specific case, I do not think that there is a problem with using Lean's -
, but the proof checker in my mind was having some difficult times reconciling the two notions!)
Johan Commelin (Sep 02 2020 at 08:03):
\lam poly, \sum i in range (nat_degree poly), coeff i poly * X ^ (i - N)
is one definition... but I don't think it's the best.
Johan Commelin (Sep 02 2020 at 08:04):
Mario Carneiro said:
You could say
N
is the largest integer such that there existsg
such thatf = x^N*g
This is multiplicity
Mario Carneiro (Sep 02 2020 at 08:04):
indeed
Johan Commelin (Sep 02 2020 at 08:04):
@Damiano Testa Do you already have a proof that your poly is nonzero?
Damiano Testa (Sep 02 2020 at 08:04):
Johan Commelin said:
Damiano Testa Do you already have a proof that your poly is nonzero?
yes
Mario Carneiro (Sep 02 2020 at 08:05):
you could try using N = multiplicity x f
Johan Commelin (Sep 02 2020 at 08:05):
Great... then multiplicity
might not be too bad.
Mario Carneiro (Sep 02 2020 at 08:05):
(roughly)
Damiano Testa (Sep 02 2020 at 08:05):
I will look up multiplicity
, then!
Damiano Testa (Sep 02 2020 at 08:05):
(and use it carefully: I am fed up of finsets
)
Mario Carneiro (Sep 02 2020 at 08:06):
oh, enats are even more fun! :smiling_devil:
Damiano Testa (Sep 02 2020 at 08:06):
i had to write a lemma to show that a bounded subset of the naturals is a finset
and i do not want to think about finset
s again, if possible!
Mario Carneiro (Sep 02 2020 at 08:06):
it's a subset of fin.range n
Damiano Testa (Sep 02 2020 at 08:06):
enats?! I am not sure that I want to know what those are
Johan Commelin (Sep 02 2020 at 08:07):
Scott Morrison (Sep 02 2020 at 08:07):
"extended" natural numbers
Mario Carneiro (Sep 02 2020 at 08:07):
you will be getting acquainted with them because that's the type of multiplicity
Damiano Testa (Sep 02 2020 at 08:08):
oooh no! at least, I also produced many lemmas proving that a polynomial is non-zero, so hopefully I can steer away from enats! for finsets
the bad guy was nonempty
...
Damiano Testa (Sep 02 2020 at 08:09):
it looks like the "good" non-zero saves you from the evil of enats and nonempty
Kevin Buzzard (Sep 02 2020 at 08:09):
@Damiano Testa I was going to be using multiplicity
in about an hour on the Discord.
Kevin Buzzard (Sep 02 2020 at 08:09):
I want to define the valuation on a discrete valuation ring
Johan Commelin (Sep 02 2020 at 08:10):
let N := enat.get (multiplicity X f) _
obtain \<g, hg\> : X ^ N \| f := pow_multiplicity_dvd _,
Damiano Testa (Sep 02 2020 at 08:10):
Kevin Buzzard said:
Damiano Testa I was going to be using
multiplicity
in about an hour on the Discord.
I see! I will try to work with it a little first and if I am still having problems, I will come to discord. i feel a little awkward on the discord: I am listening in on the conversation, but not able to talk. I feel like I am eavesdropping...
Johan Commelin (Sep 02 2020 at 08:10):
Kevin Buzzard said:
I want to define the valuation on a discrete valuation ring
Where will it take values?
Kevin Buzzard (Sep 02 2020 at 08:11):
You should buy an external mic on amazon or whatever
Kevin Buzzard (Sep 02 2020 at 08:11):
with_zero (multiplicative \Z)
Johan Commelin (Sep 02 2020 at 08:11):
Note that (factors x).card
is also very useful. See the dvr.lean file
Damiano Testa (Sep 02 2020 at 08:11):
Kevin Buzzard said:
You should buy an external mic on amazon or whatever
Yes, I am going to, I just have not gotten around to doing it, yet
Johan Commelin (Sep 02 2020 at 08:11):
I've used it as a "pseudo" valuation already
Kevin Buzzard (Sep 02 2020 at 08:14):
The issue with DVRs will be proving v(xy)=v(x)v(y).
Damiano Testa (Sep 02 2020 at 08:14):
Ok, I have made a note of all the commands that you suggested wrt multiplicities and also made a mental note that -
in Lean is not the -
in my mind, at least when it comes to the naturals!
I feel kind of strange that in my mind, shift1
does not compile as a function from nat to nat, while for Lean it does, although now I understand the reason behind it!
Kevin Buzzard (Sep 02 2020 at 08:16):
To find "all of the commands for multiplicity" you should #check the definition, right click to find it in the source code, and then read the statements of the theorems that come immediately after the definition.
Johan Commelin (Sep 02 2020 at 08:16):
@Damiano Testa But like I said... multiplicity
API needs quite a bit of love
Damiano Testa (Sep 02 2020 at 08:17):
Johan Commelin said:
Damiano Testa But like I said...
multiplicity
API needs quite a bit of love
that is ok: i feel like I have not really taken advantage of the existing API's of almost all the definitions that I have been using so far...
Damiano Testa (Sep 02 2020 at 08:20):
Kevin Buzzard said:
To find "all of the commands for multiplicity" you should #check the definition, right click to find it in the source code, and then read the statements of the theorems that come immediately after the definition.
I know that you mentioned this many times and I am making progress with this!
- I am getting better at reading Lean code, so I can actually understand the statements (although the proof escape me, usually, but, by proof irrelevance, I can work with the one in my head and I am happy!)
- I am starting to realize that files are not so long, so "reading the whole file" is actually not a daunting task!
- I am also understanding how to convert these statement into commands that I can use.
Probably, these 3 points above are clear to everyone else, but I am trying to internalize them, albeit slowly!
Kevin Buzzard (Sep 02 2020 at 08:33):
For me this was a key point. I remember thinking "I need to use finite sets, so I should carefully read all of data.finset so I should probably also read all of data.multiset" and these files are (or were -- maybe now they have been split up a bit) gigantic, and the proofs were incomprehensible. I thought I was in trouble! I tried to work through some of the early proofs but they were in term mode and I found it extremely difficult.
I later on realised that I was doing the wrong thing. The key things to do are: (1) isolate the key definitions in the file (which nowadays should be easy because they should be in the module documentation at the top of the file) and (2) for each definition which you want to use, get to know its interface by reading the statements of the theorems proved about it; often some of the important ones are proved in the code directly after the definition is made. Don't worry about the proofs. Just figure out what you can do with the definition. Then you can use it in your own work.
Damiano Testa (Sep 02 2020 at 08:42):
Johan Commelin said:
\lam poly, \sum i in range (nat_degree poly), coeff i poly * X ^ (i - N)
is one definition... but I don't think it's the best.
Johan, when you write \sum
, I imagine that you are telling Lean that you want to sum over the set. What is the syntax? I am using
λ p : polynomial R , (∑ ( i in range (nat_degree p)), coeff i p * X ^ (nat_degree p - i))
and Lean does not like it...
Kenny Lau (Sep 02 2020 at 08:43):
it's ∑ i in range (nat_degree p)
not ∑ ( i in range (nat_degree p))
Kenny Lau (Sep 02 2020 at 08:43):
the in
is part of the syntax
Kenny Lau (Sep 02 2020 at 08:43):
btw this is polynomial.derivative
Kenny Lau (Sep 02 2020 at 08:43):
so you can just look at how they do it
Kenny Lau (Sep 02 2020 at 08:43):
Kenny Lau (Sep 02 2020 at 08:44):
nvm this isn't the derivative
Damiano Testa (Sep 02 2020 at 08:44):
with
λ p : polynomial R , (∑ i in range (nat_degree p) , coeff i p * X ^ (nat_degree p - i))
I still get an unexpected token
and a red underlined \Sigma
Kenny Lau (Sep 02 2020 at 08:45):
you need to open_locale big_operators
at the top of the file after the imports
Damiano Testa (Sep 02 2020 at 08:45):
Kenny Lau said:
nvm this isn't the derivative
That is ok, they probably do something similar to what I want: I will take a look!
Kenny Lau (Sep 02 2020 at 08:45):
you'll find that "Lean does not like it" doesn't tell much
Kenny Lau (Sep 02 2020 at 08:45):
it's like people saying that some code "doesn't work"
Kenny Lau (Sep 02 2020 at 08:46):
including the error would be more efficient
Damiano Testa (Sep 02 2020 at 08:46):
Now "Lean does not like range"! Wow Progress!!
Damiano Testa (Sep 02 2020 at 08:47):
Kenny Lau said:
including the error would be more efficient
The error was unexpected token
, though...
Kenny Lau (Sep 02 2020 at 08:48):
yes, and that's more helpful than "Lean doesn't like it"
Kenny Lau (Sep 02 2020 at 08:48):
so Lean doesn't like range
because it's finset.range
, so you either type the full name or open finset
Damiano Testa (Sep 02 2020 at 08:49):
yes, I added the finset
. Still...
type mismatch at application
p.coeff
term
p
has type
polynomial R
but is expected to have type
polynomial (polynomial R)
Damiano Testa (Sep 02 2020 at 08:49):
(coeff
is underlined)
Kenny Lau (Sep 02 2020 at 08:52):
Lean sees coeff i p * X ^ (nat_degree p - i))
and knows that X ^ (nat_degree p - i)) : polynomial R
Kenny Lau (Sep 02 2020 at 08:52):
so Lean expects coeff i p : polynomial R
as well
Kenny Lau (Sep 02 2020 at 08:52):
so Lean expects p : polynomial (polynomial R)
Kenny Lau (Sep 02 2020 at 08:52):
because you need C (coeff i p)
instead of coeff i p
Damiano Testa (Sep 02 2020 at 08:52):
Ok, I added a C, indeed! Thanks!
Damiano Testa (Sep 02 2020 at 08:52):
(also, the i and the p are flipped, but I got as far!)
Johan Commelin (Sep 02 2020 at 08:55):
Sorry for not testing the code...
Damiano Testa (Sep 02 2020 at 08:57):
Johan Commelin said:
Sorry for not testing the code...
No problem: it is more helpful when I also have to do some work to understand how to use it!
Damiano Testa (Sep 02 2020 at 11:11):
Johan Commelin said:
\lam poly, \sum i in range (nat_degree poly), coeff i poly * X ^ (i - N)
is one definition... but I don't think it's the best.
Dear Johan,
as I am making progress in unwrapping the definitions, I think that the range should be nat_degree p + 1
, rather than nat_degree p
, if I understand correctly.
lemma larger_range {R : Type*} [comm_ring R] {f : polynomial R} : f = ∑ i in finset.range (nat_degree f + 1) , (polynomial.C (coeff f i)) * X ^i :=
begin
exact as_sum f,
end
Kevin Buzzard (Sep 02 2020 at 12:06):
There was no point proving that lemma; it is best if you delete it and just use as_sum
. The more functions there are, the more the chances are that Lean will get confused.
Damiano Testa (Sep 02 2020 at 12:09):
I agree, although I would like to use the "reversal of coefficients", which I am not sure is already defined:
noncomputable def at_infty {R : Type*} [comm_ring R] : polynomial R → polynomial R :=
λ p : polynomial R , ∑ i in finset.range (nat_degree p + 1) , (polynomial.C (coeff p i)) * X ^ (nat_degree p - i)
Damiano Testa (Sep 02 2020 at 12:10):
(and now I am struggling to prove that the coefficients satisfy the identity
coeff f a = coeff (at_infty f) (nat_degree f - a)
)
Reid Barton (Sep 02 2020 at 12:17):
This operation was actually discussed here but I don't know whether a PR was ever made
Damiano Testa (Sep 02 2020 at 12:21):
Reid Barton said:
This operation was actually discussed here but I don't know whether a PR was ever made
Thank you! I tried
#check polynomial.reverse
but there is not hit, unfortunately.
Johan Commelin (Sep 02 2020 at 12:55):
@Damiano Testa oops, you are right about the nat.degree f + 1
Last updated: Dec 20 2023 at 11:08 UTC