From f7c58e4c4b66750cbb3afd9ad29e9c246b2480ab Mon Sep 17 00:00:00 2001 From: Nikos Giachoudis Date: Mon, 11 Jul 2022 10:36:57 -0400 Subject: [PATCH] Unify primality checking (#6228) * renames prime functions and occurances in comments * changes implementation of primality testing to be uniform * adds static typing as per conventions * updating DIRECTORY.md Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- DIRECTORY.md | 1 - data_structures/hashing/double_hash.py | 4 +- .../hashing/number_theory/prime_numbers.py | 52 ++++++++++++---- maths/prime_check.py | 61 ++++++++++--------- maths/primelib.py | 22 +++---- 5 files changed, 87 insertions(+), 53 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index c8f03658c..2e9c03cbc 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -444,7 +444,6 @@ * [Scoring Functions](machine_learning/scoring_functions.py) * [Sequential Minimum Optimization](machine_learning/sequential_minimum_optimization.py) * [Similarity Search](machine_learning/similarity_search.py) - * [Support Vector Machines](machine_learning/support_vector_machines.py) * [Word Frequency Functions](machine_learning/word_frequency_functions.py) ## Maths diff --git a/data_structures/hashing/double_hash.py b/data_structures/hashing/double_hash.py index 57b1ffff4..bd1355fca 100644 --- a/data_structures/hashing/double_hash.py +++ b/data_structures/hashing/double_hash.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 from .hash_table import HashTable -from .number_theory.prime_numbers import check_prime, next_prime +from .number_theory.prime_numbers import is_prime, next_prime class DoubleHash(HashTable): @@ -15,7 +15,7 @@ class DoubleHash(HashTable): next_prime_gt = ( next_prime(value % self.size_table) - if not check_prime(value % self.size_table) + if not is_prime(value % self.size_table) else value % self.size_table ) # gt = bigger than return next_prime_gt - (data % next_prime_gt) diff --git a/data_structures/hashing/number_theory/prime_numbers.py b/data_structures/hashing/number_theory/prime_numbers.py index bf614e7d4..b88ab76ec 100644 --- a/data_structures/hashing/number_theory/prime_numbers.py +++ b/data_structures/hashing/number_theory/prime_numbers.py @@ -3,25 +3,55 @@ module to operations with prime numbers """ +import math -def check_prime(number): - """ - it's not the best solution - """ - special_non_primes = [0, 1, 2] - if number in special_non_primes[:2]: - return 2 - elif number == special_non_primes[-1]: - return 3 - return all(number % i for i in range(2, number)) +def is_prime(number: int) -> bool: + """Checks to see if a number is a prime in O(sqrt(n)). + + A number is prime if it has exactly two factors: 1 and itself. + + >>> is_prime(0) + False + >>> is_prime(1) + False + >>> is_prime(2) + True + >>> is_prime(3) + True + >>> is_prime(27) + False + >>> is_prime(87) + False + >>> is_prime(563) + True + >>> is_prime(2999) + True + >>> is_prime(67483) + False + """ + + # precondition + assert isinstance(number, int) and ( + number >= 0 + ), "'number' must been an int and positive" + + if 1 < number < 4: + # 2 and 3 are primes + return True + elif number < 2 or not number % 2: + # Negatives, 0, 1 and all even numbers are not primes + return False + + odd_numbers = range(3, int(math.sqrt(number) + 1), 2) + return not any(not number % i for i in odd_numbers) def next_prime(value, factor=1, **kwargs): value = factor * value first_value_val = value - while not check_prime(value): + while not is_prime(value): value += 1 if not ("desc" in kwargs.keys() and kwargs["desc"] is True) else -1 if value == first_value_val: diff --git a/maths/prime_check.py b/maths/prime_check.py index 92d31cfee..315492054 100644 --- a/maths/prime_check.py +++ b/maths/prime_check.py @@ -4,31 +4,36 @@ import math import unittest -def prime_check(number: int) -> bool: +def is_prime(number: int) -> bool: """Checks to see if a number is a prime in O(sqrt(n)). A number is prime if it has exactly two factors: 1 and itself. - >>> prime_check(0) + >>> is_prime(0) False - >>> prime_check(1) + >>> is_prime(1) False - >>> prime_check(2) + >>> is_prime(2) True - >>> prime_check(3) + >>> is_prime(3) True - >>> prime_check(27) + >>> is_prime(27) False - >>> prime_check(87) + >>> is_prime(87) False - >>> prime_check(563) + >>> is_prime(563) True - >>> prime_check(2999) + >>> is_prime(2999) True - >>> prime_check(67483) + >>> is_prime(67483) False """ + # precondition + assert isinstance(number, int) and ( + number >= 0 + ), "'number' must been an int and positive" + if 1 < number < 4: # 2 and 3 are primes return True @@ -42,35 +47,35 @@ def prime_check(number: int) -> bool: class Test(unittest.TestCase): def test_primes(self): - self.assertTrue(prime_check(2)) - self.assertTrue(prime_check(3)) - self.assertTrue(prime_check(5)) - self.assertTrue(prime_check(7)) - self.assertTrue(prime_check(11)) - self.assertTrue(prime_check(13)) - self.assertTrue(prime_check(17)) - self.assertTrue(prime_check(19)) - self.assertTrue(prime_check(23)) - self.assertTrue(prime_check(29)) + self.assertTrue(is_prime(2)) + self.assertTrue(is_prime(3)) + self.assertTrue(is_prime(5)) + self.assertTrue(is_prime(7)) + self.assertTrue(is_prime(11)) + self.assertTrue(is_prime(13)) + self.assertTrue(is_prime(17)) + self.assertTrue(is_prime(19)) + self.assertTrue(is_prime(23)) + self.assertTrue(is_prime(29)) def test_not_primes(self): self.assertFalse( - prime_check(-19), + is_prime(-19), "Negative numbers are excluded by definition of prime numbers.", ) self.assertFalse( - prime_check(0), + is_prime(0), "Zero doesn't have any positive factors, primes must have exactly two.", ) self.assertFalse( - prime_check(1), + is_prime(1), "One only has 1 positive factor, primes must have exactly two.", ) - self.assertFalse(prime_check(2 * 2)) - self.assertFalse(prime_check(2 * 3)) - self.assertFalse(prime_check(3 * 3)) - self.assertFalse(prime_check(3 * 5)) - self.assertFalse(prime_check(3 * 5 * 7)) + self.assertFalse(is_prime(2 * 2)) + self.assertFalse(is_prime(2 * 3)) + self.assertFalse(is_prime(3 * 3)) + self.assertFalse(is_prime(3 * 5)) + self.assertFalse(is_prime(3 * 5 * 7)) if __name__ == "__main__": diff --git a/maths/primelib.py b/maths/primelib.py index 37883d9cf..3da9c56f6 100644 --- a/maths/primelib.py +++ b/maths/primelib.py @@ -41,7 +41,7 @@ goldbach(number) // Goldbach's assumption from math import sqrt -def isPrime(number): +def is_prime(number: int) -> bool: """ input: positive integer 'number' returns true if 'number' is prime otherwise false. @@ -129,7 +129,7 @@ def getPrimeNumbers(N): # if a number is prime then appends to list 'ans' for number in range(2, N + 1): - if isPrime(number): + if is_prime(number): ans.append(number) @@ -164,11 +164,11 @@ def primeFactorization(number): ans.append(number) # if 'number' not prime then builds the prime factorization of 'number' - elif not isPrime(number): + elif not is_prime(number): while quotient != 1: - if isPrime(factor) and (quotient % factor == 0): + if is_prime(factor) and (quotient % factor == 0): ans.append(factor) quotient /= factor else: @@ -317,8 +317,8 @@ def goldbach(number): isinstance(ans, list) and (len(ans) == 2) and (ans[0] + ans[1] == number) - and isPrime(ans[0]) - and isPrime(ans[1]) + and is_prime(ans[0]) + and is_prime(ans[1]) ), "'ans' must contains two primes. And sum of elements must been eq 'number'" return ans @@ -462,11 +462,11 @@ def getPrime(n): # if ans not prime then # runs to the next prime number. - while not isPrime(ans): + while not is_prime(ans): ans += 1 # precondition - assert isinstance(ans, int) and isPrime( + assert isinstance(ans, int) and is_prime( ans ), "'ans' must been a prime number and from type int" @@ -486,7 +486,7 @@ def getPrimesBetween(pNumber1, pNumber2): # precondition assert ( - isPrime(pNumber1) and isPrime(pNumber2) and (pNumber1 < pNumber2) + is_prime(pNumber1) and is_prime(pNumber2) and (pNumber1 < pNumber2) ), "The arguments must been prime numbers and 'pNumber1' < 'pNumber2'" number = pNumber1 + 1 # jump to the next number @@ -495,7 +495,7 @@ def getPrimesBetween(pNumber1, pNumber2): # if number is not prime then # fetch the next prime number. - while not isPrime(number): + while not is_prime(number): number += 1 while number < pNumber2: @@ -505,7 +505,7 @@ def getPrimesBetween(pNumber1, pNumber2): number += 1 # fetch the next prime number. - while not isPrime(number): + while not is_prime(number): number += 1 # precondition