For the segmented Sieve Of Eratosthenes, I have devised the following code provided. And I understand that it is not the best implementation; However, it should be much quicker than what it is now. The c Profile provides numerous results. However, it only defines built-in methods and gives no further context as to which built-in method is taking up the most time. I wish to optimize this sieve to the maximum possible performance capable through python.
Which numpy built-in method is making my program slower?
import numpy as np
import math
import cProfile
def generateprimes(n: int = 0) -> list:#simple sieve of Eratosthenes to find primes that make up
#all factors of the upper bound.
Primelist = np.full((1,int(math.sqrt(n) )),1, dtype='int8')
Primelist[0,0], Primelist[0,1] = 0,0
for i in range(2,int(math.sqrt(math.sqrt(n))) + 1):
if Primelist[0,i] == 1:
for x in range (i*i,int(math.sqrt(n) ),i):
Primelist[0,x] = 0
indices = np.where(Primelist == 1)[1]
return indices
#unique, counts = np.unique(Primelist, return_counts=True)
#dict(zip(unique, counts))
#return [b for b in range(int(math.sqrt(n))) if Primelist[0,b] == 1]
def SegmentedSieve(R: int, L:int, Primes: tuple) -> tuple:
Finalprime = np.empty((0,1), dtype = 'int32')
limit = (R//L) # Total amount of segments
Finalprime = np.append(Finalprime, Primes)
for x in range(1, limit):
Low = (L * x)
High = Low + L
Segment = np.full((1,High-Low),1,dtype='int8') #creates a segment that is the size of the differences between L and R
NewPrimes = np.extract(Primes <= int(math.sqrt(High)),Primes) # Only taking the primes that are less than the square root of the upperbound.
#i.e the limit of the current segment
for p in NewPrimes:
s = ((int(math.ceil(Low / p))) * p) % Low # Finds the position of the first occurrence of the prime in the
# newest lowest bound or Low
for i in range(s,L,p): # starts at the position found and skips every p distance. The upperbound is the
#amount of elements in each segment.
Segment[0, i] = 0
indices = np.where(Segment == 1)[1] + Low
Finalprime = np.append(Finalprime, indices)
continue
return Finalprime
def main():
R = (10 ** 7)
L = int(math.sqrt(R))
SegmentedSieve(R, L, generateprimes(R))
if __name__ == '__main__':
cProfile.run('main()')