Compare commits

..

No commits in common. "cfba98d2e0b657758748afc251c9624c16c71e5c" and "d403da53db27a824fc44a328d602c52b37f0d125" have entirely different histories.

6 changed files with 71 additions and 32 deletions

View file

View file

@ -6,7 +6,7 @@ Terminology:
the "prime proper divisors of n". the "prime proper divisors of n".
''' '''
from imp.extern.primefac import primefac from imp.math.primefac import primefac
def factors(n: int) -> int: def factors(n: int) -> int:
pfactors: list[tuple[int, int]] = [] pfactors: list[tuple[int, int]] = []

View file

@ -1,3 +1,5 @@
def factorial(n: int) -> int: def factorial(n: int) -> int:
if n == 0: return 1 if n == 0: return 1
return n * factorial(n-1) return n * factorial(n-1)
def

View file

@ -1,10 +1,5 @@
from math import gcd, inf from math import gcd
from imp.math.numbers import bigomega
from imp.math.numbers import bigomega, factors
from imp.extern.primefac import (
isprime,
primegen as Primes,
)
def coprime(n: int, m: int) -> bool: def coprime(n: int, m: int) -> bool:
return gcd(n, m) == 1 return gcd(n, m) == 1
@ -23,25 +18,68 @@ def semiprime(n: int) -> bool:
''' '''
return almostprime(n, 2) return almostprime(n, 2)
def eulertotient(x: int | list) -> int: '''
''' Euler's Totient (Phi) Function
Evaluates Euler's Totient function. '''
Input: `x: int` is prime factorised by Lucas A. Brown's primefac.py def totient(n: int) -> int:
else `x: list` is assumed to the prime factorisation of `x: int` phi = int(n > 1 and n)
''' for p in range(2, int(n ** .5) + 1):
pfactors = x if isinstance(x, list) else factors(n) if not n % p:
return prod((p-1)*(p**(e-1)) for (p, e) in pfactors) phi -= phi // p
# def eulertotient(n: int) -> int: while not n % p:
# ''' n //= p
# Uses trial division to compute #if n is > 1 it means it is prime
# Euler's Totient (Phi) Function. if n > 1: phi -= phi // n
# ''' return phi
# phi = int(n > 1 and n)
# for p in range(2, int(n ** .5) + 1): '''
# if not n % p: Tests the primality of an integer using its totient.
# phi -= phi // p NOTE: If totient(n) has already been calculated
# while not n % p: then pass it as the optional phi parameter.
# n //= p '''
# #if n is > 1 it means it is prime def is_prime(n: int, phi: int = None) -> bool:
# if n > 1: phi -= phi // n return n - 1 == (phi if phi is not None else totient(n))
# return phi
'''
Prime number generator function.
Returns the tuple (p, phi(p)) where p is prime
and phi is Euler's totient function.
'''
def prime_gen(yield_phi: bool = False) -> int | tuple[int, int]:
n = 1
while True:
n += 1
phi = totient(n)
if is_prime(n, phi=phi):
if yield_phi:
yield (n, phi)
else:
yield n
'''
Returns the prime factorisation of a number.
Returns a list of tuples (p, m) where p is
a prime factor and m is its multiplicity.
NOTE: uses a trial division algorithm
'''
def prime_factors(n: int) -> list[tuple[int, int]]:
phi = totient(n)
if is_prime(n, phi=phi):
return [(n, 1)]
factors = []
for p in prime_gen(yield_phi=False):
if p >= n:
break
# check if divisor
multiplicity = 0
while n % p == 0:
n //= p
multiplicity += 1
if multiplicity:
factors.append((p, multiplicity))
if is_prime(n):
break
if n != 1:
factors.append((n, 1))
return factors

View file

@ -1,9 +1,8 @@
from collections.abc import Iterable
from itertools import chain, combinations from itertools import chain, combinations
def digits(n: int) -> int: def digits(n: int) -> int:
return len(str(n)) return len(str(n))
def powerset(iterable: Iterable) -> Iterable: def powerset(iterable):
s = list(iterable) s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1)) return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))