ai-content-maker/.venv/Lib/site-packages/sympy/ntheory/generate.py

1038 lines
29 KiB
Python
Raw Normal View History

2024-05-03 04:18:51 +03:00
"""
Generating and counting primes.
"""
import random
from bisect import bisect
from itertools import count
# Using arrays for sieving instead of lists greatly reduces
# memory consumption
from array import array as _array
from sympy.core.function import Function
from sympy.core.singleton import S
from .primetest import isprime
from sympy.utilities.misc import as_int
def _azeros(n):
return _array('l', [0]*n)
def _aset(*v):
return _array('l', v)
def _arange(a, b):
return _array('l', range(a, b))
def _as_int_ceiling(a):
""" Wrapping ceiling in as_int will raise an error if there was a problem
determining whether the expression was exactly an integer or not."""
from sympy.functions.elementary.integers import ceiling
return as_int(ceiling(a))
class Sieve:
"""An infinite list of prime numbers, implemented as a dynamically
growing sieve of Eratosthenes. When a lookup is requested involving
an odd number that has not been sieved, the sieve is automatically
extended up to that number.
Examples
========
>>> from sympy import sieve
>>> sieve._reset() # this line for doctest only
>>> 25 in sieve
False
>>> sieve._list
array('l', [2, 3, 5, 7, 11, 13, 17, 19, 23])
"""
# data shared (and updated) by all Sieve instances
def __init__(self):
self._n = 6
self._list = _aset(2, 3, 5, 7, 11, 13) # primes
self._tlist = _aset(0, 1, 1, 2, 2, 4) # totient
self._mlist = _aset(0, 1, -1, -1, 0, -1) # mobius
assert all(len(i) == self._n for i in (self._list, self._tlist, self._mlist))
def __repr__(self):
return ("<%s sieve (%i): %i, %i, %i, ... %i, %i\n"
"%s sieve (%i): %i, %i, %i, ... %i, %i\n"
"%s sieve (%i): %i, %i, %i, ... %i, %i>") % (
'prime', len(self._list),
self._list[0], self._list[1], self._list[2],
self._list[-2], self._list[-1],
'totient', len(self._tlist),
self._tlist[0], self._tlist[1],
self._tlist[2], self._tlist[-2], self._tlist[-1],
'mobius', len(self._mlist),
self._mlist[0], self._mlist[1],
self._mlist[2], self._mlist[-2], self._mlist[-1])
def _reset(self, prime=None, totient=None, mobius=None):
"""Reset all caches (default). To reset one or more set the
desired keyword to True."""
if all(i is None for i in (prime, totient, mobius)):
prime = totient = mobius = True
if prime:
self._list = self._list[:self._n]
if totient:
self._tlist = self._tlist[:self._n]
if mobius:
self._mlist = self._mlist[:self._n]
def extend(self, n):
"""Grow the sieve to cover all primes <= n (a real number).
Examples
========
>>> from sympy import sieve
>>> sieve._reset() # this line for doctest only
>>> sieve.extend(30)
>>> sieve[10] == 29
True
"""
n = int(n)
if n <= self._list[-1]:
return
# We need to sieve against all bases up to sqrt(n).
# This is a recursive call that will do nothing if there are enough
# known bases already.
maxbase = int(n**0.5) + 1
self.extend(maxbase)
# Create a new sieve starting from sqrt(n)
begin = self._list[-1] + 1
newsieve = _arange(begin, n + 1)
# Now eliminate all multiples of primes in [2, sqrt(n)]
for p in self.primerange(maxbase):
# Start counting at a multiple of p, offsetting
# the index to account for the new sieve's base index
startindex = (-begin) % p
for i in range(startindex, len(newsieve), p):
newsieve[i] = 0
# Merge the sieves
self._list += _array('l', [x for x in newsieve if x])
def extend_to_no(self, i):
"""Extend to include the ith prime number.
Parameters
==========
i : integer
Examples
========
>>> from sympy import sieve
>>> sieve._reset() # this line for doctest only
>>> sieve.extend_to_no(9)
>>> sieve._list
array('l', [2, 3, 5, 7, 11, 13, 17, 19, 23])
Notes
=====
The list is extended by 50% if it is too short, so it is
likely that it will be longer than requested.
"""
i = as_int(i)
while len(self._list) < i:
self.extend(int(self._list[-1] * 1.5))
def primerange(self, a, b=None):
"""Generate all prime numbers in the range [2, a) or [a, b).
Examples
========
>>> from sympy import sieve, prime
All primes less than 19:
>>> print([i for i in sieve.primerange(19)])
[2, 3, 5, 7, 11, 13, 17]
All primes greater than or equal to 7 and less than 19:
>>> print([i for i in sieve.primerange(7, 19)])
[7, 11, 13, 17]
All primes through the 10th prime
>>> list(sieve.primerange(prime(10) + 1))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
"""
if b is None:
b = _as_int_ceiling(a)
a = 2
else:
a = max(2, _as_int_ceiling(a))
b = _as_int_ceiling(b)
if a >= b:
return
self.extend(b)
i = self.search(a)[1]
maxi = len(self._list) + 1
while i < maxi:
p = self._list[i - 1]
if p < b:
yield p
i += 1
else:
return
def totientrange(self, a, b):
"""Generate all totient numbers for the range [a, b).
Examples
========
>>> from sympy import sieve
>>> print([i for i in sieve.totientrange(7, 18)])
[6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16]
"""
a = max(1, _as_int_ceiling(a))
b = _as_int_ceiling(b)
n = len(self._tlist)
if a >= b:
return
elif b <= n:
for i in range(a, b):
yield self._tlist[i]
else:
self._tlist += _arange(n, b)
for i in range(1, n):
ti = self._tlist[i]
startindex = (n + i - 1) // i * i
for j in range(startindex, b, i):
self._tlist[j] -= ti
if i >= a:
yield ti
for i in range(n, b):
ti = self._tlist[i]
for j in range(2 * i, b, i):
self._tlist[j] -= ti
if i >= a:
yield ti
def mobiusrange(self, a, b):
"""Generate all mobius numbers for the range [a, b).
Parameters
==========
a : integer
First number in range
b : integer
First number outside of range
Examples
========
>>> from sympy import sieve
>>> print([i for i in sieve.mobiusrange(7, 18)])
[-1, 0, 0, 1, -1, 0, -1, 1, 1, 0, -1]
"""
a = max(1, _as_int_ceiling(a))
b = _as_int_ceiling(b)
n = len(self._mlist)
if a >= b:
return
elif b <= n:
for i in range(a, b):
yield self._mlist[i]
else:
self._mlist += _azeros(b - n)
for i in range(1, n):
mi = self._mlist[i]
startindex = (n + i - 1) // i * i
for j in range(startindex, b, i):
self._mlist[j] -= mi
if i >= a:
yield mi
for i in range(n, b):
mi = self._mlist[i]
for j in range(2 * i, b, i):
self._mlist[j] -= mi
if i >= a:
yield mi
def search(self, n):
"""Return the indices i, j of the primes that bound n.
If n is prime then i == j.
Although n can be an expression, if ceiling cannot convert
it to an integer then an n error will be raised.
Examples
========
>>> from sympy import sieve
>>> sieve.search(25)
(9, 10)
>>> sieve.search(23)
(9, 9)
"""
test = _as_int_ceiling(n)
n = as_int(n)
if n < 2:
raise ValueError("n should be >= 2 but got: %s" % n)
if n > self._list[-1]:
self.extend(n)
b = bisect(self._list, n)
if self._list[b - 1] == test:
return b, b
else:
return b, b + 1
def __contains__(self, n):
try:
n = as_int(n)
assert n >= 2
except (ValueError, AssertionError):
return False
if n % 2 == 0:
return n == 2
a, b = self.search(n)
return a == b
def __iter__(self):
for n in count(1):
yield self[n]
def __getitem__(self, n):
"""Return the nth prime number"""
if isinstance(n, slice):
self.extend_to_no(n.stop)
# Python 2.7 slices have 0 instead of None for start, so
# we can't default to 1.
start = n.start if n.start is not None else 0
if start < 1:
# sieve[:5] would be empty (starting at -1), let's
# just be explicit and raise.
raise IndexError("Sieve indices start at 1.")
return self._list[start - 1:n.stop - 1:n.step]
else:
if n < 1:
# offset is one, so forbid explicit access to sieve[0]
# (would surprisingly return the last one).
raise IndexError("Sieve indices start at 1.")
n = as_int(n)
self.extend_to_no(n)
return self._list[n - 1]
# Generate a global object for repeated use in trial division etc
sieve = Sieve()
def prime(nth):
r""" Return the nth prime, with the primes indexed as prime(1) = 2,
prime(2) = 3, etc.... The nth prime is approximately $n\log(n)$.
Logarithmic integral of $x$ is a pretty nice approximation for number of
primes $\le x$, i.e.
li(x) ~ pi(x)
In fact, for the numbers we are concerned about( x<1e11 ),
li(x) - pi(x) < 50000
Also,
li(x) > pi(x) can be safely assumed for the numbers which
can be evaluated by this function.
Here, we find the least integer m such that li(m) > n using binary search.
Now pi(m-1) < li(m-1) <= n,
We find pi(m - 1) using primepi function.
Starting from m, we have to find n - pi(m-1) more primes.
For the inputs this implementation can handle, we will have to test
primality for at max about 10**5 numbers, to get our answer.
Examples
========
>>> from sympy import prime
>>> prime(10)
29
>>> prime(1)
2
>>> prime(100000)
1299709
See Also
========
sympy.ntheory.primetest.isprime : Test if n is prime
primerange : Generate all primes in a given range
primepi : Return the number of primes less than or equal to n
References
==========
.. [1] https://en.wikipedia.org/wiki/Prime_number_theorem#Table_of_.CF.80.28x.29.2C_x_.2F_log_x.2C_and_li.28x.29
.. [2] https://en.wikipedia.org/wiki/Prime_number_theorem#Approximations_for_the_nth_prime_number
.. [3] https://en.wikipedia.org/wiki/Skewes%27_number
"""
n = as_int(nth)
if n < 1:
raise ValueError("nth must be a positive integer; prime(1) == 2")
if n <= len(sieve._list):
return sieve[n]
from sympy.functions.elementary.exponential import log
from sympy.functions.special.error_functions import li
a = 2 # Lower bound for binary search
b = int(n*(log(n) + log(log(n)))) # Upper bound for the search.
while a < b:
mid = (a + b) >> 1
if li(mid) > n:
b = mid
else:
a = mid + 1
n_primes = primepi(a - 1)
while n_primes < n:
if isprime(a):
n_primes += 1
a += 1
return a - 1
class primepi(Function):
r""" Represents the prime counting function pi(n) = the number
of prime numbers less than or equal to n.
Algorithm Description:
In sieve method, we remove all multiples of prime p
except p itself.
Let phi(i,j) be the number of integers 2 <= k <= i
which remain after sieving from primes less than
or equal to j.
Clearly, pi(n) = phi(n, sqrt(n))
If j is not a prime,
phi(i,j) = phi(i, j - 1)
if j is a prime,
We remove all numbers(except j) whose
smallest prime factor is j.
Let $x= j \times a$ be such a number, where $2 \le a \le i / j$
Now, after sieving from primes $\le j - 1$,
a must remain
(because x, and hence a has no prime factor $\le j - 1$)
Clearly, there are phi(i / j, j - 1) such a
which remain on sieving from primes $\le j - 1$
Now, if a is a prime less than equal to j - 1,
$x= j \times a$ has smallest prime factor = a, and
has already been removed(by sieving from a).
So, we do not need to remove it again.
(Note: there will be pi(j - 1) such x)
Thus, number of x, that will be removed are:
phi(i / j, j - 1) - phi(j - 1, j - 1)
(Note that pi(j - 1) = phi(j - 1, j - 1))
$\Rightarrow$ phi(i,j) = phi(i, j - 1) - phi(i / j, j - 1) + phi(j - 1, j - 1)
So,following recursion is used and implemented as dp:
phi(a, b) = phi(a, b - 1), if b is not a prime
phi(a, b) = phi(a, b-1)-phi(a / b, b-1) + phi(b-1, b-1), if b is prime
Clearly a is always of the form floor(n / k),
which can take at most $2\sqrt{n}$ values.
Two arrays arr1,arr2 are maintained
arr1[i] = phi(i, j),
arr2[i] = phi(n // i, j)
Finally the answer is arr2[1]
Examples
========
>>> from sympy import primepi, prime, prevprime, isprime
>>> primepi(25)
9
So there are 9 primes less than or equal to 25. Is 25 prime?
>>> isprime(25)
False
It is not. So the first prime less than 25 must be the
9th prime:
>>> prevprime(25) == prime(9)
True
See Also
========
sympy.ntheory.primetest.isprime : Test if n is prime
primerange : Generate all primes in a given range
prime : Return the nth prime
"""
@classmethod
def eval(cls, n):
if n is S.Infinity:
return S.Infinity
if n is S.NegativeInfinity:
return S.Zero
try:
n = int(n)
except TypeError:
if n.is_real == False or n is S.NaN:
raise ValueError("n must be real")
return
if n < 2:
return S.Zero
if n <= sieve._list[-1]:
return S(sieve.search(n)[0])
lim = int(n ** 0.5)
lim -= 1
lim = max(lim, 0)
while lim * lim <= n:
lim += 1
lim -= 1
arr1 = [0] * (lim + 1)
arr2 = [0] * (lim + 1)
for i in range(1, lim + 1):
arr1[i] = i - 1
arr2[i] = n // i - 1
for i in range(2, lim + 1):
# Presently, arr1[k]=phi(k,i - 1),
# arr2[k] = phi(n // k,i - 1)
if arr1[i] == arr1[i - 1]:
continue
p = arr1[i - 1]
for j in range(1, min(n // (i * i), lim) + 1):
st = i * j
if st <= lim:
arr2[j] -= arr2[st] - p
else:
arr2[j] -= arr1[n // st] - p
lim2 = min(lim, i * i - 1)
for j in range(lim, lim2, -1):
arr1[j] -= arr1[j // i] - p
return S(arr2[1])
def nextprime(n, ith=1):
""" Return the ith prime greater than n.
i must be an integer.
Notes
=====
Potential primes are located at 6*j +/- 1. This
property is used during searching.
>>> from sympy import nextprime
>>> [(i, nextprime(i)) for i in range(10, 15)]
[(10, 11), (11, 13), (12, 13), (13, 17), (14, 17)]
>>> nextprime(2, ith=2) # the 2nd prime after 2
5
See Also
========
prevprime : Return the largest prime smaller than n
primerange : Generate all primes in a given range
"""
n = int(n)
i = as_int(ith)
if i > 1:
pr = n
j = 1
while 1:
pr = nextprime(pr)
j += 1
if j > i:
break
return pr
if n < 2:
return 2
if n < 7:
return {2: 3, 3: 5, 4: 5, 5: 7, 6: 7}[n]
if n <= sieve._list[-2]:
l, u = sieve.search(n)
if l == u:
return sieve[u + 1]
else:
return sieve[u]
nn = 6*(n//6)
if nn == n:
n += 1
if isprime(n):
return n
n += 4
elif n - nn == 5:
n += 2
if isprime(n):
return n
n += 4
else:
n = nn + 5
while 1:
if isprime(n):
return n
n += 2
if isprime(n):
return n
n += 4
def prevprime(n):
""" Return the largest prime smaller than n.
Notes
=====
Potential primes are located at 6*j +/- 1. This
property is used during searching.
>>> from sympy import prevprime
>>> [(i, prevprime(i)) for i in range(10, 15)]
[(10, 7), (11, 7), (12, 11), (13, 11), (14, 13)]
See Also
========
nextprime : Return the ith prime greater than n
primerange : Generates all primes in a given range
"""
n = _as_int_ceiling(n)
if n < 3:
raise ValueError("no preceding primes")
if n < 8:
return {3: 2, 4: 3, 5: 3, 6: 5, 7: 5}[n]
if n <= sieve._list[-1]:
l, u = sieve.search(n)
if l == u:
return sieve[l-1]
else:
return sieve[l]
nn = 6*(n//6)
if n - nn <= 1:
n = nn - 1
if isprime(n):
return n
n -= 4
else:
n = nn + 1
while 1:
if isprime(n):
return n
n -= 2
if isprime(n):
return n
n -= 4
def primerange(a, b=None):
""" Generate a list of all prime numbers in the range [2, a),
or [a, b).
If the range exists in the default sieve, the values will
be returned from there; otherwise values will be returned
but will not modify the sieve.
Examples
========
>>> from sympy import primerange, prime
All primes less than 19:
>>> list(primerange(19))
[2, 3, 5, 7, 11, 13, 17]
All primes greater than or equal to 7 and less than 19:
>>> list(primerange(7, 19))
[7, 11, 13, 17]
All primes through the 10th prime
>>> list(primerange(prime(10) + 1))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
The Sieve method, primerange, is generally faster but it will
occupy more memory as the sieve stores values. The default
instance of Sieve, named sieve, can be used:
>>> from sympy import sieve
>>> list(sieve.primerange(1, 30))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
Notes
=====
Some famous conjectures about the occurrence of primes in a given
range are [1]:
- Twin primes: though often not, the following will give 2 primes
an infinite number of times:
primerange(6*n - 1, 6*n + 2)
- Legendre's: the following always yields at least one prime
primerange(n**2, (n+1)**2+1)
- Bertrand's (proven): there is always a prime in the range
primerange(n, 2*n)
- Brocard's: there are at least four primes in the range
primerange(prime(n)**2, prime(n+1)**2)
The average gap between primes is log(n) [2]; the gap between
primes can be arbitrarily large since sequences of composite
numbers are arbitrarily large, e.g. the numbers in the sequence
n! + 2, n! + 3 ... n! + n are all composite.
See Also
========
prime : Return the nth prime
nextprime : Return the ith prime greater than n
prevprime : Return the largest prime smaller than n
randprime : Returns a random prime in a given range
primorial : Returns the product of primes based on condition
Sieve.primerange : return range from already computed primes
or extend the sieve to contain the requested
range.
References
==========
.. [1] https://en.wikipedia.org/wiki/Prime_number
.. [2] https://primes.utm.edu/notes/gaps.html
"""
if b is None:
a, b = 2, a
if a >= b:
return
# if we already have the range, return it
if b <= sieve._list[-1]:
yield from sieve.primerange(a, b)
return
# otherwise compute, without storing, the desired range.
a = _as_int_ceiling(a) - 1
b = _as_int_ceiling(b)
while 1:
a = nextprime(a)
if a < b:
yield a
else:
return
def randprime(a, b):
""" Return a random prime number in the range [a, b).
Bertrand's postulate assures that
randprime(a, 2*a) will always succeed for a > 1.
Examples
========
>>> from sympy import randprime, isprime
>>> randprime(1, 30) #doctest: +SKIP
13
>>> isprime(randprime(1, 30))
True
See Also
========
primerange : Generate all primes in a given range
References
==========
.. [1] https://en.wikipedia.org/wiki/Bertrand's_postulate
"""
if a >= b:
return
a, b = map(int, (a, b))
n = random.randint(a - 1, b)
p = nextprime(n)
if p >= b:
p = prevprime(b)
if p < a:
raise ValueError("no primes exist in the specified range")
return p
def primorial(n, nth=True):
"""
Returns the product of the first n primes (default) or
the primes less than or equal to n (when ``nth=False``).
Examples
========
>>> from sympy.ntheory.generate import primorial, primerange
>>> from sympy import factorint, Mul, primefactors, sqrt
>>> primorial(4) # the first 4 primes are 2, 3, 5, 7
210
>>> primorial(4, nth=False) # primes <= 4 are 2 and 3
6
>>> primorial(1)
2
>>> primorial(1, nth=False)
1
>>> primorial(sqrt(101), nth=False)
210
One can argue that the primes are infinite since if you take
a set of primes and multiply them together (e.g. the primorial) and
then add or subtract 1, the result cannot be divided by any of the
original factors, hence either 1 or more new primes must divide this
product of primes.
In this case, the number itself is a new prime:
>>> factorint(primorial(4) + 1)
{211: 1}
In this case two new primes are the factors:
>>> factorint(primorial(4) - 1)
{11: 1, 19: 1}
Here, some primes smaller and larger than the primes multiplied together
are obtained:
>>> p = list(primerange(10, 20))
>>> sorted(set(primefactors(Mul(*p) + 1)).difference(set(p)))
[2, 5, 31, 149]
See Also
========
primerange : Generate all primes in a given range
"""
if nth:
n = as_int(n)
else:
n = int(n)
if n < 1:
raise ValueError("primorial argument must be >= 1")
p = 1
if nth:
for i in range(1, n + 1):
p *= prime(i)
else:
for i in primerange(2, n + 1):
p *= i
return p
def cycle_length(f, x0, nmax=None, values=False):
"""For a given iterated sequence, return a generator that gives
the length of the iterated cycle (lambda) and the length of terms
before the cycle begins (mu); if ``values`` is True then the
terms of the sequence will be returned instead. The sequence is
started with value ``x0``.
Note: more than the first lambda + mu terms may be returned and this
is the cost of cycle detection with Brent's method; there are, however,
generally less terms calculated than would have been calculated if the
proper ending point were determined, e.g. by using Floyd's method.
>>> from sympy.ntheory.generate import cycle_length
This will yield successive values of i <-- func(i):
>>> def iter(func, i):
... while 1:
... ii = func(i)
... yield ii
... i = ii
...
A function is defined:
>>> func = lambda i: (i**2 + 1) % 51
and given a seed of 4 and the mu and lambda terms calculated:
>>> next(cycle_length(func, 4))
(6, 2)
We can see what is meant by looking at the output:
>>> n = cycle_length(func, 4, values=True)
>>> list(ni for ni in n)
[17, 35, 2, 5, 26, 14, 44, 50, 2, 5, 26, 14]
There are 6 repeating values after the first 2.
If a sequence is suspected of being longer than you might wish, ``nmax``
can be used to exit early (and mu will be returned as None):
>>> next(cycle_length(func, 4, nmax = 4))
(4, None)
>>> [ni for ni in cycle_length(func, 4, nmax = 4, values=True)]
[17, 35, 2, 5]
Code modified from:
https://en.wikipedia.org/wiki/Cycle_detection.
"""
nmax = int(nmax or 0)
# main phase: search successive powers of two
power = lam = 1
tortoise, hare = x0, f(x0) # f(x0) is the element/node next to x0.
i = 0
while tortoise != hare and (not nmax or i < nmax):
i += 1
if power == lam: # time to start a new power of two?
tortoise = hare
power *= 2
lam = 0
if values:
yield hare
hare = f(hare)
lam += 1
if nmax and i == nmax:
if values:
return
else:
yield nmax, None
return
if not values:
# Find the position of the first repetition of length lambda
mu = 0
tortoise = hare = x0
for i in range(lam):
hare = f(hare)
while tortoise != hare:
tortoise = f(tortoise)
hare = f(hare)
mu += 1
if mu:
mu -= 1
yield lam, mu
def composite(nth):
""" Return the nth composite number, with the composite numbers indexed as
composite(1) = 4, composite(2) = 6, etc....
Examples
========
>>> from sympy import composite
>>> composite(36)
52
>>> composite(1)
4
>>> composite(17737)
20000
See Also
========
sympy.ntheory.primetest.isprime : Test if n is prime
primerange : Generate all primes in a given range
primepi : Return the number of primes less than or equal to n
prime : Return the nth prime
compositepi : Return the number of positive composite numbers less than or equal to n
"""
n = as_int(nth)
if n < 1:
raise ValueError("nth must be a positive integer; composite(1) == 4")
composite_arr = [4, 6, 8, 9, 10, 12, 14, 15, 16, 18]
if n <= 10:
return composite_arr[n - 1]
a, b = 4, sieve._list[-1]
if n <= b - primepi(b) - 1:
while a < b - 1:
mid = (a + b) >> 1
if mid - primepi(mid) - 1 > n:
b = mid
else:
a = mid
if isprime(a):
a -= 1
return a
from sympy.functions.elementary.exponential import log
from sympy.functions.special.error_functions import li
a = 4 # Lower bound for binary search
b = int(n*(log(n) + log(log(n)))) # Upper bound for the search.
while a < b:
mid = (a + b) >> 1
if mid - li(mid) - 1 > n:
b = mid
else:
a = mid + 1
n_composites = a - primepi(a) - 1
while n_composites > n:
if not isprime(a):
n_composites -= 1
a -= 1
if isprime(a):
a -= 1
return a
def compositepi(n):
""" Return the number of positive composite numbers less than or equal to n.
The first positive composite is 4, i.e. compositepi(4) = 1.
Examples
========
>>> from sympy import compositepi
>>> compositepi(25)
15
>>> compositepi(1000)
831
See Also
========
sympy.ntheory.primetest.isprime : Test if n is prime
primerange : Generate all primes in a given range
prime : Return the nth prime
primepi : Return the number of primes less than or equal to n
composite : Return the nth composite number
"""
n = int(n)
if n < 4:
return 0
return n - primepi(n) - 1