Zulip Chat Archive

Stream: new members

Topic: Expand `list.countp`


Gareth Ma (Jan 23 2023 at 19:55):

Hi. I have the following goal:

list.countp prime (list.range (10 + 1)) = 4

How can I tell lean to expand countp and evaluate and actually prove this? It seems to me that by definition, lean should do this already:

def countp (p : α  Prop) [decidable_pred p] : list α  nat
| []      := 0
| (x::xs) := if p x then succ (countp xs) else countp xs

Here is reproducible code:

import data.nat.prime_norm_num
import number_theory.prime_counting

namespace nat
open_locale nat

example : prime 3 :=
begin
  norm_num,
end

example : π 10 = 4 :=
begin
  unfo
  unfold prime_counting' count prime,
  unfold list.countp,
  unfold prime_counting' count prime list.countp,
end

end nat

Kevin Buzzard (Jan 23 2023 at 20:24):

There has been far less effort been put into making Lean 3 compute like this than there has been into developing a large body of theorems. I don't even know how to prove this:

example : list.filter prime [0,1,2,3,4,5,6,7,8,9,10] = [2,3,5,7] :=
begin
  sorry,
end

Gareth Ma (Jan 23 2023 at 20:34):

Actually surprisingly, an unfold, combined with a tactic that evaluates prime n, works:

example : list.filter prime [0,1,2,3,4,5,6,7,8,9,10] = [2,3,5,7] :=
begin
  unfold list.filter,
  norm_num,
end

However, I am not sure why unfold list.countp doesn't, it gives simplify tactic failed to simplify, despite them having similar structures.

Kevin Buzzard (Jan 23 2023 at 20:38):

Oh nice! Mimicing your trick:

example : π 10 = 4 :=
begin
  change list.countp prime [0,1,2,3,4,5,6,7,8,9,10] = 4,
  unfold list.countp,
  norm_num,
end

Kevin Buzzard (Jan 23 2023 at 20:40):

The fact that some thought has to be given to navigating the minefield is just an indication that people have not put too much effort into this kind of question. Perhaps one reason for this is that lean 3 begins to struggle with computations of any kind of non-trivial size. This is the sort of question which you might hope a tactic in Lean 4 can solve much more efficiently.

Mario Carneiro (Jan 23 2023 at 20:45):

I have certainly put a lot of thought into problems of this form. The issue is that at least currently, norm_num basically needs custom implementations for every function you want to compute with, unless you can live with the fortuitous interaction it has with simp (which is often enough for list problems like this)

Kevin Buzzard (Jan 23 2023 at 20:46):

Yes -- you wrote norm_num and many custom extensions to it! Example here. But it was a one person show in Lean 3 and I for one had no motivation for trying to get stuff like this working in mathlib3 because it always seemed to me that lean 4 would be a far more appropriate tool for this kind of job.

Mario Carneiro (Jan 23 2023 at 20:46):

for an example like this I think the best approach is just to give the function a name (since this is the prime pi function after all) and implement a norm_num extension for it

Mario Carneiro (Jan 23 2023 at 20:48):

Lean 4 doesn't bring anything fundamentally new here, there are a few extra features that sometimes help like simp being able to prove stuff by decide sometimes but mostly it looks the same except that numerics are more practical because of bignum arithmetic

Gareth Ma (Jan 23 2023 at 20:48):

I see, I will definitely look into mathlib4 soon, once I get comfortable with mathlib3 and have the mental capacity haha. By the way, I modified your code to not require explicitly writing out the list:

example : π 10 = 4 :=
begin
  rw [prime_counting, prime_counting', count, list.range],

  simp only [list.range_core, list.countp], -- recursively simp.
  norm_num,
end

But then since countp by definition has a if-then-else branch, the tree grows exponentially I believe.

Kevin Buzzard (Jan 23 2023 at 20:49):

Seems to me that you're already half way towards writing the custom extension! However I would discourage you from doing this in mathlib3 because any changes to norm_num right now would need to be manually ported to mathlib4.

Mario Carneiro (Jan 23 2023 at 20:49):

more like reimplemented

Gareth Ma (Jan 23 2023 at 20:50):

Alright!

Mario Carneiro (Jan 23 2023 at 20:50):

we're implementing norm_num extensions on an as needed basis right now

Gareth Ma (Jan 23 2023 at 20:54):

If I do get to implement the norm_num extension for prime_counting at some point, probably a good idea to get Meissel-Lehmer Algorithm in too, since I believe it runs in O(n^(2/3+epsilon))

Mario Carneiro (Jan 23 2023 at 21:05):

Note that norm_num is (at least currently) primarily concerned with the small-numbers case, which is why primality checking is done using trial division instead of more sophisticated approaches with a better asymptotic complexity

Mario Carneiro (Jan 23 2023 at 21:05):

there isn't much point in having an algorithm that only pays off when the numbers are so big that other implementation limits are hit first

Gareth Ma (Jan 23 2023 at 21:09):

Ahh, that makes sense. Maybe I will add it as an extension, similar to the lucas-lehmer test?

Mario Carneiro (Jan 23 2023 at 21:09):

lucas-lehmer is also not a 100% correct test, right?

Mario Carneiro (Jan 23 2023 at 21:10):

this makes it less useful for proof purposes

Mario Carneiro (Jan 23 2023 at 21:11):

because we don't really care about certificates for compositeness, those are trivial

Gareth Ma (Jan 23 2023 at 21:15):

I think it is 100% correct for mersenne numbers - at least the wikipedia page suggests so. What I meant was to implement it as a separate tactic (lucas_lehmer.run_test) that user can use instead if required for some reason :)

Mario Carneiro (Jan 23 2023 at 21:18):

if we have the method available it makes sense to use it by default after switching based on the size of the number. I don't know whether it helps in these algorithms to know what the answer is before you start the computation (which is the usual situation in certificate generation)

Mario Carneiro (Jan 23 2023 at 21:19):

I guess you wouldn't be using it on mersenne numbers in the first place (if it's part of the algorithm for prime n or prime_counting n), because that would require recognizing mersenne numbers which seems like an unnecessary step

Junyan Xu (Jan 24 2023 at 00:04):

Gareth Ma said:

If I do get to implement the norm_num extension for prime_counting at some point, probably a good idea to get Meissel-Lehmer Algorithm in too, since I believe it runs in O(n^(2/3+epsilon))

Take a look at https://github.com/kimwalisch/primecount if you haven't :)

Gareth Ma (Jan 24 2023 at 00:11):

Yea I have, it is very cool, they computed the current prime_pi record didn't they?


Last updated: Dec 20 2023 at 11:08 UTC