From 3a407b645610759ab61bc766b2f3c375356c59d2 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 1 Jul 2025 18:03:36 +1000 Subject: [PATCH 1/2] Improved handling of prime factors, proper divisors, and aliquots --- imp/math/numbers.py | 16 ------- imp/math/numbers/__init__.py | 82 ++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 16 deletions(-) delete mode 100644 imp/math/numbers.py create mode 100644 imp/math/numbers/__init__.py diff --git a/imp/math/numbers.py b/imp/math/numbers.py deleted file mode 100644 index f414ff0..0000000 --- a/imp/math/numbers.py +++ /dev/null @@ -1,16 +0,0 @@ -from imp.math.primefac import factors - -def divisors(n: int) -> int: - ''' - Returns the proper divisors of an integer n. - Also called the "aliquot parts" of n. - ''' - pf = factors(n) - for (prime, multiplicity) in pf: - - -def aliquots(n: int) -> int: - return proper_divisors(n) - -def amicable(n: int) -> int: - sum(proper_divisors()) diff --git a/imp/math/numbers/__init__.py b/imp/math/numbers/__init__.py new file mode 100644 index 0000000..f4193b8 --- /dev/null +++ b/imp/math/numbers/__init__.py @@ -0,0 +1,82 @@ +''' +Terminology: + Although "divisor" and "factor" mean the same thing. + When Celeste discusses "divisors of n" it is implied to + mean "proper divisors of n + n itself", and "factors" are + the "prime proper divisors of n". +''' + +from imp.math.primefac import primefac + +def factors(n: int) -> int: + pfactors: list[tuple[int, int]] = [] + # generate primes and progressively store them in pfactors + pfgen = primefac(n) + watching = next(pfgen) + mult = 1 + # ASSUMPTION: prime generation is (non-strict) monotone increasing + while True: + p = next(pfgen, None) + if p == watching: + mult += 1 + else: + pfactors.append((watching, mult)) + watching = p # reset + mult = 1 # reset + if p is None: + break + return pfactors + +def factors2divisors(pfactors: list[tuple[int, int]], + sorted: bool = True) -> list[int]: + ''' + Generates all divisors < n of an integer n given its prime factorisation. + Input: prime factorisation of n (excluding 1 and n, and duplicates) + in the typical form: list[(prime, multiplicity)] + ''' + divisors = [1] + for (prime, multiplicity) in pfactors: + extension = [] + for i in range(1, multiplicity+1): + term = prime**i + extension.extend(list([divisor*term for divisor in divisors])) + divisors.extend(extension) + if sorted: divisors.sort() + return divisors + +def factors2aliquots(pfactors: list[tuple[int, int]]) -> list[int]: + return factors2divisors(pfactors)[:-1] + +# "aliquots(n)" is an alias for "divisors(n)" +def aliquots(n: int) -> int: + ''' + Returns all aliquot parts (proper divisors) of + an integer n, that is all divisors 0 < d <= n. + ''' + return factors2aliquots(factors(n)) + +def divisors(n: int) -> int: + ''' + Returns all divisors 0 < d < n of an integer n. + ''' + return factors2divisors(factors(n)) + +def aliquot_sum(n: int) -> int: + return sum(aliquots(n)) + + +def littleomega(n: int) -> int: + ''' + The Little Omega function counts the number of + distinct prime factors of an integer n. + Ref: https://en.wikipedia.org/wiki/Prime_omega_function + ''' + return len(factors(n)) + +def bigomega(n: int) -> int: + ''' + The Big Omega function counts the total number of + prime factors (including multiplicity) of an integer n. + Ref: https://en.wikipedia.org/wiki/Prime_omega_function + ''' + return sum(factor[1] for factor in factors(n)) From d403da53db27a824fc44a328d602c52b37f0d125 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 1 Jul 2025 18:04:00 +1000 Subject: [PATCH 2/2] Add basic tests of semi-primality and k-almost primality --- imp/math/numbers/functions.py | 5 +++++ imp/math/numbers/kinds.py | 1 + imp/math/primes.py | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 imp/math/numbers/functions.py create mode 100644 imp/math/numbers/kinds.py diff --git a/imp/math/numbers/functions.py b/imp/math/numbers/functions.py new file mode 100644 index 0000000..6cafa7f --- /dev/null +++ b/imp/math/numbers/functions.py @@ -0,0 +1,5 @@ +def factorial(n: int) -> int: + if n == 0: return 1 + return n * factorial(n-1) + +def diff --git a/imp/math/numbers/kinds.py b/imp/math/numbers/kinds.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/imp/math/numbers/kinds.py @@ -0,0 +1 @@ + diff --git a/imp/math/primes.py b/imp/math/primes.py index 513f61e..eaeebcb 100644 --- a/imp/math/primes.py +++ b/imp/math/primes.py @@ -1,5 +1,23 @@ from math import gcd +from imp.math.numbers import bigomega +def coprime(n: int, m: int) -> bool: + return gcd(n, m) == 1 + +def almostprime(n: int, k: int) -> bool: + ''' + A natural n is "k-almost prime" if it has exactly + k prime factors (including multiplicity). + ''' + return (bigomega(n) == k) + +def semiprime(n: int) -> bool: + ''' + A semiprime number is one that is 2-almost prime. + Ref: https://en.wikipedia.org/wiki/Semiprime + ''' + return almostprime(n, 2) + ''' Euler's Totient (Phi) Function '''