1

I have this simple code (do pip install primesieve first):

def prob(n):
  it = primesieve.Iterator()
  p = 1
  prime = it.next_prime()
  while prime <= n:
    p = p * (1-1/prime)
    prime = it.next_prime()
  return p

How can I use tqdm to get a progress bar for the while loop?


import primesieve

def prob(n):
  it = primesieve.Iterator()
  p = 1
  prime = it.next_prime()
  pbar = tqdm(total=n)
  while prime <= n:
    p = p * (1-1/prime)
    prime = it.next_prime()
    pbar.update(prime)
  return p

gives an incrementing clock but it doesn't give any indication of how complete the while loop is. That is there is no progress bar.

You can test this with prob(2**32).

Simd
  • 19,447
  • 42
  • 136
  • 271
  • IIRC you can manually update the tqdm value. Have a look at this: https://stackoverflow.com/questions/45808140/using-tqdm-progress-bar-in-a-while-loop – Roland Deschain Dec 30 '22 at 10:49
  • Does this answer your question? [Using tqdm progress bar in a while loop](https://stackoverflow.com/questions/45808140/using-tqdm-progress-bar-in-a-while-loop) – luk2302 Dec 30 '22 at 10:50
  • @RolandDeschain I added an explanation of my problem. – Simd Dec 30 '22 at 10:55
  • @luk2302 I added further details – Simd Dec 30 '22 at 10:55
  • 3
    @Simd hmm, so now it is not an tqdm problem anymore but a math problem, since you would need to know the amount of prime numbers in advance. However I guess if you knew that information in advance you wouldn't need a loop in the first place, so I'm not sure if this is solveable – Roland Deschain Dec 30 '22 at 10:59
  • @RolandDeschain That would be the best but I would also be happy just showing what percentage of the way to `n` it has got to. You just need `prime` and `n` for that. E.g. if `n=100` and it has got to `47` I would like it to show it is 47% of the way through. – Simd Dec 30 '22 at 11:00
  • I'm not a math expert by any means, but I don't think there is a distribution probability for prime numbers (i.e. a probability to encounter a certain number of primes within a range of numbers) - if that existed you could at least use that as an estimate. – Roland Deschain Dec 30 '22 at 11:02
  • 1
    @RolandDeschain there is in fact. We can assume that the number of primes less than x is roughly x/log(x). But I would be happy with a solution to my easier version too. – Simd Dec 30 '22 at 11:04
  • I don't understand. If that is the case, than you can simply put `tqdm(total=n / log(n))` and have a roughly correct pbar, right? – Roland Deschain Dec 30 '22 at 11:30
  • What do you mean by a progress bar? – Pythoneer Dec 30 '22 at 11:39

2 Answers2

2

First, in pbar.update, the argument is the increment (progress), not an absolute value to set the progress bar to. Second, you need to have a final update at the end, or the bar remains incomplete unless n is a prime itself. To "finalize" the progress bar (e.g. turning it to the "complete" color --green), we also close it at the end. Putting it all together:

import primesieve
from tqdm.notebook import tqdm


def prob(n):
    it = primesieve.Iterator()
    p = 1
    prime = it.next_prime()
    pbar = tqdm(total=n)
    while prime <= n:
        p = p * (1-1/prime)
        prime = it.next_prime()
        pbar.update(prime - pbar.n)
    pbar.update(n - pbar.n)
    pbar.close()
    return p

Then try:

prob(10_000_000)

enter image description here

BTW, I was a bit surprised that primesieve.Iterator() is not iterable:

>>> list(zip(primesieve.Iterator(), range(10)))
TypeError: 'primesieve._primesieve.Iterator' object is not iterable

It would make for easier writing. To remedy that:

def prime_iterator(upto):
    it = primesieve.Iterator()
    while (prime := it.next_prime()) <= upto:
        yield prime

Then your function could be:

def prob(n):
    p = 1
    pbar = tqdm(total=n)
    for prime in prime_iterator(n):
        pbar.update(prime - pbar.n)
        p *= 1 - 1 / prime
    pbar.update(n - pbar.n)
    pbar.close()
    return p
Pierre D
  • 24,012
  • 7
  • 60
  • 96
-1

Specify pbar with parameter desc="while loop":

pbar = tqdm(desc="while loop", total=n)

I think this will give you the desired result.

stukituk
  • 168
  • 1
  • 8