Source code for py3nt.core.sieve

"""Generate primes using sieve"""


from dataclasses import dataclass, field

import numpy as np

from py3nt.core.base import BaseSieve


[docs] @dataclass class SieveOfEratosthenes(BaseSieve): r""" Sieve of Eratosthenes for generating primes. Usually used for factorizing by division of primes not exceeding :math:`\sqrt{n}`. So, in most cases ``limit`` should be set to :math:`\ceil{\sqrt{n}}`. Methods ------- generate_primes: Generate primes up to ``limit`` using sieve of Eratosthenes. """
[docs] def generate_primes(self) -> None: """Generate primes and set it in ``self.primes_``""" flags = np.zeros(shape=(self.limit + 1,), dtype=np.byte) if (not self.limit) or self.limit < 2: return prime_count = 1 self.primes_[0] = 2 for i in np.arange(start=3, stop=self.limit + 1, step=2): if flags[i] == 0: self.primes_[prime_count] = i prime_count += 1 flags[i * i : self.limit + 1 : i * 2] = 1
[docs] @dataclass class SieveOfEratosthenesOptimized(BaseSieve): r""" We can store smallest prime factors for :math:`\log{n}` factorization. Therefore, :math:`n` must be in sieve range. Methods ------- generate_primes: Generate primes using pre-stored prime factors of positive integers. """ largest_prime_factors_: np.ndarray = field(init=False) def __post_init__(self) -> None: super().__post_init__() self.largest_prime_factors_ = np.empty(shape=(0,), dtype=int)
[docs] def generate_primes(self) -> None: """Generate primes using largest prime factors""" if self.limit < 2: return self.largest_prime_factors_ = np.empty(shape=(self.limit + 1,), dtype=int) self.primes_[0] = 2 prime_count = 1 for i in np.arange(start=0, stop=self.limit + 1): self.largest_prime_factors_[i] = i for i in np.arange(start=2, stop=self.limit + 1, step=2): self.largest_prime_factors_[i] = 2 for i in np.arange(start=3, stop=self.limit + 1, step=2): if self.largest_prime_factors_[i] == i: self.primes_[prime_count] = i prime_count += 1 self.largest_prime_factors_[i * i : self.limit + 1 : 2 * i] = i self.num_primes = prime_count