def test_primes(self): values = primes(1000) self.assertEqual(values, self.primes_to_1000) values = primes(0) self.assertEqual(values, []) values = primes(-1) self.assertEqual(values, []) value = sum(primes(2 * 10**6)) self.assertEqual(value, self.sum_of_primes_to_2000000)
def test_primes(self): values = primes(1000) self.assertEqual(values, self.primes_to_1000) values = primes(0) self.assertEqual(values, []) values = primes(-1) self.assertEqual(values, []) value = sum(primes(2*10**6)) self.assertEqual(value, self.sum_of_primes_to_2000000)
def pi_table(n): r"""Returns the primes <= n, as well as a table of pi(x) for x <= n. Parameters ---------- n : int Returns ------- (primes, table) : tuple The list `primes` contains the primes <= n. The list `table` is indexed 0 to n, with `table[k]` giving the number of primes <= k. Notes ----- This method uses the function `primes` to compute the primes, and simple does some bookkeeping to maintain a running count. Examples -------- >>> pi_table(10) ([2, 3, 5, 7], [0, 0, 1, 2, 2, 3, 3, 4, 4, 4, 4]) """ primes = sieves.primes(n) table = [0] * (n + 1) last = 0 for (i, p) in enumerate(primes): table[last:p] = [i] * (p - last) last = p table[last:n + 1] = [i + 1] * (n + 1 - last) return primes, table
def test_fibonacci_primitive_roots(self): values = [ (5, [3]), (11, [8]), (19, [15]), (31, [13]), (41, [7, 35]), (59, [34]), (61, [18, 44]), (71, [63]), (79, [30]), (109, [11, 99]), (131, [120]), (149, [41, 109]), (179, [105]), (191, [89]), ] computed = [] for p in primes(200): roots = fibonacci_primitive_roots(p) if roots: computed.append((p, roots)) self.assertEqual(values, computed)
def moebius_xrange(a, b=None): """Return an generator over values of moebius(k) for a <= k < b. Input: * a: int (a > 0) * b: int (b > a) (default=None) Returns: * P: generator The values output by this generator are tuples (n, moebius(n)) where n is an integer in [a, b), and moebius(n) is the value of the moebius function. Examples: >>> list(moebius_xrange(10, 20)) [(10, 1), (11, -1), (12, 0), (13, -1), (14, 1), (15, 1), (16, 0), (17, -1), (18, 0), (19, -1)] Details: All primes <= sqrt(b) are computed, and a segmented sieve is used to build the values using the multiplicative property of the moebius function. See the paper "Computing the Summation of the Moebius Function" by Deleglise and Rivat for more information. """ if a < 2: a = 1 if b is None: b, a = a, 1 if b <= a: return block_size = integer_sqrt(b) prime_list = prime_sieves.primes(block_size) for start in xrange(a, b, block_size): block = [1] * block_size values = [1] * block_size for p in prime_list: offset = ((p * (start // p + 1) - a) % block_size) % p for i in xrange(offset, block_size, p): if (start + i) % (p * p) == 0: block[i] = 0 else: block[i] *= -1 values[i] *= p for i in xrange(block_size): if start + i >= b: return if block[i] and values[i] < start + i: block[i] *= -1 yield (start + i, block[i])
def moebius_list(n): """Return a list of the values of moebius(k) for 1 <= k <= n. Parameters * n: int (n > 0) Returns: * L: list This is a list of values of moebius(k) for 1 <= k <= n. The list begins with 0, so that L[k] holds the value of moebius(k). Raises: * ValueError: If n <= 0. Examples: >>> moebius_list(10) [0, 1, -1, -1, 0, -1, 1, -1, 0, 0, 1] >>> [0] + [moebius(k) for k in xrange(1, 11)] [0, 1, -1, -1, 0, -1, 1, -1, 0, 0, 1] >>> moebius_list(0) Traceback (most recent call last): ... ValueError: moebius_list: Must have n > 0. Details: This function creates a list of (n + 1) elements, and fills the list by sieving and using the product definition of moebius(n). """ if n <= 0: raise ValueError("moebius_list: Must have n > 0.") sqrt = int(n**(0.5)) prime_list = prime_sieves.primes(sqrt) values = [1] * (n + 1) block = [1] * (n + 1) block[0] = 0 for p in prime_list: for i in xrange(p, n + 1, p): if i % (p * p) == 0: block[i] = 0 else: block[i] *= -1 values[i] *= p for i in xrange(n + 1): if block[i] and values[i] < i: block[i] *= -1 return block
def moebius_list(n): """Return a list of the values of moebius(k) for 1 <= k <= n. Parameters * n: int (n > 0) Returns: * L: list This is a list of values of moebius(k) for 1 <= k <= n. The list begins with 0, so that L[k] holds the value of moebius(k). Raises: * ValueError: If n <= 0. Examples: >>> moebius_list(10) [0, 1, -1, -1, 0, -1, 1, -1, 0, 0, 1] >>> [0] + [moebius(k) for k in xrange(1, 11)] [0, 1, -1, -1, 0, -1, 1, -1, 0, 0, 1] >>> moebius_list(0) Traceback (most recent call last): ... ValueError: moebius_list: Must have n > 0. Details: This function creates a list of (n + 1) elements, and fills the list by sieving and using the product definition of moebius(n). """ if n <= 0: raise ValueError("moebius_list: Must have n > 0.") sqrt = int(n**(0.5)) prime_list = prime_sieves.primes(sqrt) values = [1]*(n + 1) block = [1]*(n + 1) block[0] = 0 for p in prime_list: for i in xrange(p, n + 1, p): if i % (p*p) == 0: block[i] = 0 else: block[i] *= -1 values[i] *= p for i in xrange(n + 1): if block[i] and values[i] < i: block[i] *= -1 return block
def lmo_bit(x): root = int(x**(2.0 / 3.0)) primes = sieves.primes(root) t = x**(0.33333333333333) c = bisect(primes, t) b = bisect(primes, x**(0.5)) value = (b + c - 2) * (b - c + 1) // 2 for i in xrange(c, b): idx = bisect(primes, x // primes[i]) value -= idx special = defaultdict(list) stack = [(1, c, 1)] push = stack.append pop = stack.pop while stack: (n, a, sign) = pop() if a == 1 and n <= t: if sign > 0: value += (x // n + 1) // 2 else: value -= (x // n + 1) // 2 elif n > t: special[a].append((x // n, sign)) else: push((n, a - 1, sign)) push((n * primes[a - 1], a - 1, -sign)) block = bit_sieve.BITSieveArray(root) mark = block.mark_multiples total = block.partial_sum for a in sorted(special): p = primes[a - 1] mark(p) for v, sign in sorted(special[a]): if sign > 0: value += total(v) else: value -= total(v) return value
def legendre(n): r"""Returns the number of primes <= n. Parameters ---------- n : int (n > 0) Returns ------- count : int The number of primes <= n. Notes ----- This method uses the function `primes` to compute the primes, and simple does some bookkeeping to maintain a running count. Examples -------- >>> pi_table(10) ([2, 3, 5, 7], [0, 0, 1, 2, 2, 3, 3, 4, 4, 4, 4]) """ if n <= 1: return 0 elif n <= _PRIME_LIST[-1]: return bisect(_PRIME_LIST, n) root = integer_sqrt(n) primes = sieves.primes(root) a = len(primes) def phi(x, a, cache={}): if (x, a) in cache: return cache[x, a] if a == 1: return (x + 1) // 2 value = (x + 1) // 2 for i in xrange(2, a + 1): p = primes[i - 1] if p > x: break value -= phi(x // p, i - 1) cache[x, a] = value return value return phi(n, a) + a - 1
def euler_phi_list(n): """Returns a list of values of euler_phi(k) for 1 <= k <= n. Parameters * n: int (n > 0) Returns: * values: list This is a list of values of euler_phi(k) for 1 <= k <= n. The list begins with 0, so that L[k] holds the value of euler_phi(k). Raises: * ValueError: If n <= 0. Examples: >>> euler_phi_list(10) [0, 1, 1, 2, 2, 4, 2, 6, 4, 6, 4] >>> [0] + [euler_phi(k) for k in xrange(1, 11)] [0, 1, 1, 2, 2, 4, 2, 6, 4, 6, 4] >>> euler_phi_list(0) Traceback (most recent call last): ... ValueError: euler_phi_list: Must have n > 0. Details: This function initially creates a list of (n + 1) zeros, and fills the list by sieving, using the product definition of euler_phi(n). """ if n <= 0: raise ValueError("euler_phi_list: Must have n > 0.") block = [1] * (n + 1) block[0] = 0 prime_list = prime_sieves.primes(n) for p in prime_list: for mul in xrange(p, n + 1, p): block[mul] *= (p - 1) pk = p * p while pk <= n: for mul in xrange(pk, n + 1, pk): block[mul] *= p pk *= p return block
def euler_phi_list(n): """Returns a list of values of euler_phi(k) for 1 <= k <= n. Parameters * n: int (n > 0) Returns: * values: list This is a list of values of euler_phi(k) for 1 <= k <= n. The list begins with 0, so that L[k] holds the value of euler_phi(k). Raises: * ValueError: If n <= 0. Examples: >>> euler_phi_list(10) [0, 1, 1, 2, 2, 4, 2, 6, 4, 6, 4] >>> [0] + [euler_phi(k) for k in xrange(1, 11)] [0, 1, 1, 2, 2, 4, 2, 6, 4, 6, 4] >>> euler_phi_list(0) Traceback (most recent call last): ... ValueError: euler_phi_list: Must have n > 0. Details: This function initially creates a list of (n + 1) zeros, and fills the list by sieving, using the product definition of euler_phi(n). """ if n <= 0: raise ValueError("euler_phi_list: Must have n > 0.") block = [1]*(n + 1) block[0] = 0 prime_list = prime_sieves.primes(n) for p in prime_list: for mul in xrange(p, n + 1, p): block[mul] *= (p - 1) pk = p*p while pk <= n: for mul in xrange(pk, n + 1, pk): block[mul] *= p pk *= p return block
def prime_sum2(n): root = integer_sqrt(n) primes = sieves.primes(root) a = len(primes) sum_table = [0] * (root + 1) accumulation = primes[:] for i in xrange(1, len(accumulation)): accumulation[i] += accumulation[i - 1] for (p, total) in zip(primes, accumulation): sum_table[p] = total for i in xrange(2, root + 1): if not sum_table[i]: sum_table[i] = sum_table[i - 1] def phi(x, a, cache={}): if (x, a) in cache: return cache[x, a] if x == 0: return 0 if a == 0: return x * (x + 1) // 2 value = x * (x + 1) // 2 for i in xrange(1, a + 1): p = primes[i - 1] if p > x: break value -= p * phi(x // p, i - 1) cache[x, a] = value return value return phi(n, a) + sum(primes) - 1
def sigma_list(n, k=1): """Return a list of the values of sigma(i, k) for 1 <= i <= n. Parameters * n: int (n > 0) * k: int (k > 0) (default=1) Returns: * L: list This is a list of values of sigma(i, k) for 1 <= i <= n. The list begins with 0, so that L[i] holds the value of sigma(i, k). Raises: * ValueError: If n <= 1 or k < 0. Examples: >>> sigma_list(10) [0, 1, 3, 4, 7, 6, 12, 8, 15, 13, 18] >>> [0] + [sigma(k) for k in xrange(1, 11)] [0, 1, 3, 4, 7, 6, 12, 8, 15, 13, 18] >>> sigma_list(10, 2) [0, 1, 5, 10, 21, 26, 50, 50, 85, 91, 130] >>> [0] + [sigma(k, 2) for k in xrange(1, 11)] [0, 1, 5, 10, 21, 26, 50, 50, 85, 91, 130] >>> sigma_list(-1) Traceback (most recent call last): ... ValueError: sigma_list: Must have n > 0. >>> sigma_list(10, -1) Traceback (most recent call last): ... ValueError: sigma_list: Must have k >= 0. Details: This function creates a list of (n + 1) elements, and fills the list by sieving and using the product definition of sigma(n, k). For k == 1 and small values of n, a simpler but faster algorithm is used. See Section 9.8 in "Algorithmic Number Theory - Efficient Algorithms" by Bach and Shallit for details. """ if n <= 0: raise ValueError("sigma_list: Must have n > 0.") if k == 0: return tau_list(n) elif k < 0: raise ValueError("sigma_list: Must have k >= 0.") # Use a special algorithm when k == 1 for small values of n. if k == 1 and n <= 10**4: block = [0]*(n + 1) sqrt = int(n**(0.5)) for j in xrange(1, sqrt + 1): block[j*j] += j for k in xrange(j + 1, n//j + 1): block[k*j] += j + k else: block = [1]*(n + 1) block[0] = 0 prime_list = prime_sieves.primes(n) for p in prime_list: pk = p mul = p**k term = mul**2 last = mul while pk <= n: for idx in xrange(pk, n + 1, pk): block[idx] *= (term - 1) block[idx] /= (last - 1) pk *= p last = term term *= mul return block
def sigma_list(n, k=1): """Return a list of the values of sigma(i, k) for 1 <= i <= n. Parameters * n: int (n > 0) * k: int (k > 0) (default=1) Returns: * L: list This is a list of values of sigma(i, k) for 1 <= i <= n. The list begins with 0, so that L[i] holds the value of sigma(i, k). Raises: * ValueError: If n <= 1 or k < 0. Examples: >>> sigma_list(10) [0, 1, 3, 4, 7, 6, 12, 8, 15, 13, 18] >>> [0] + [sigma(k) for k in xrange(1, 11)] [0, 1, 3, 4, 7, 6, 12, 8, 15, 13, 18] >>> sigma_list(10, 2) [0, 1, 5, 10, 21, 26, 50, 50, 85, 91, 130] >>> [0] + [sigma(k, 2) for k in xrange(1, 11)] [0, 1, 5, 10, 21, 26, 50, 50, 85, 91, 130] >>> sigma_list(-1) Traceback (most recent call last): ... ValueError: sigma_list: Must have n > 0. >>> sigma_list(10, -1) Traceback (most recent call last): ... ValueError: sigma_list: Must have k >= 0. Details: This function creates a list of (n + 1) elements, and fills the list by sieving and using the product definition of sigma(n, k). For k == 1 and small values of n, a simpler but faster algorithm is used. See Section 9.8 in "Algorithmic Number Theory - Efficient Algorithms" by Bach and Shallit for details. """ if n <= 0: raise ValueError("sigma_list: Must have n > 0.") if k == 0: return tau_list(n) elif k < 0: raise ValueError("sigma_list: Must have k >= 0.") # Use a special algorithm when k == 1 for small values of n. if k == 1 and n <= 10**4: block = [0] * (n + 1) sqrt = int(n**(0.5)) for j in xrange(1, sqrt + 1): block[j * j] += j for k in xrange(j + 1, n // j + 1): block[k * j] += j + k else: block = [1] * (n + 1) block[0] = 0 prime_list = prime_sieves.primes(n) for p in prime_list: pk = p mul = p**k term = mul**2 last = mul while pk <= n: for idx in xrange(pk, n + 1, pk): block[idx] *= (term - 1) block[idx] /= (last - 1) pk *= p last = term term *= mul return block
def lmo(x): if x <= 1: return 0 elif x <= _PRIME_LIST[-1]: return bisect(_PRIME_LIST, x) root = integer_nth_root(3, x**2) primes = sieves.primes(root) t = integer_nth_root(3, x) c = bisect(primes, t) b = bisect(primes, integer_nth_root(2, x)) value = (b + c - 2) * (b - c + 1) // 2 for i in xrange(c, b): idx = bisect(primes, x // primes[i]) value -= idx special = defaultdict(list) stack = [(1, c, 1)] push = stack.append pop = stack.pop # print "recursing" while stack: (n, a, sign) = pop() if a == 1 and n <= t: if sign > 0: value += (x // n + 1) // 2 else: value -= (x // n + 1) // 2 elif n > t: special[a].append((x // n, sign)) else: push((n, a - 1, sign)) push((n * primes[a - 1], a - 1, -sign)) block = [1] * (root + 1) block[0] = 0 for a in sorted(special): p = primes[a - 1] block[p::p] = [0] * (root // p) last_v = 0 last_s = 0 for v, sign in sorted(special[a]): last_s += sum(block[last_v:v + 1]) last_v = v + 1 if sign > 0: value += last_s else: value -= last_s return value
def lehmer(n): if n <= 1: return 0 elif n <= _PRIME_LIST[-1]: return bisect(_PRIME_LIST, n) root = integer_nth_root(4, n**3) primes = sieves.primes(root) a = bisect(primes, integer_nth_root(4, n)) b = bisect(primes, integer_sqrt(n)) c = bisect(primes, integer_nth_root(3, n)) def phi(x, a, cache={}): if (x, a) in cache: return cache[x, a] if a <= 7: if a == 1: value = x - x // 2 elif a == 2: value = x - x // 2 - x // 3 + x // 6 elif a == 3: value = x - x // 2 - x // 3 - x // 5 + x // 6 + x // 10 + x // 15 - x // 30 elif a == 4: value = (x - x // 2 - x // 3 - x // 5 - x // 7 + x // 6 + x // 10 + x // 14 + x // 15 + x // 21 + x // 35 - x // 30 - x // 42 - x // 70 - x // 105 + x // 210) elif a == 5: value = (x - x // 2 - x // 3 - x // 5 - x // 7 - x // 11 + x // 6 + x // 10 + x // 14 + x // 22 + x // 15 + x // 21 + x // 33 + x // 35 + x // 55 + x // 77 - x // 30 - x // 42 - x // 66 - x // 70 - x // 110 - x // 154 - x // 105 - x // 165 - x // 231 - x // 385 + x // 210 + x // 330 + x // 462 + x // 770 + x // 1155 - x // 2310) elif a == 6: value = (x - x // 2 - x // 3 - x // 5 - x // 7 - x // 11 - x // 13 + x // 6 + x // 10 + x // 14 + x // 22 + x // 26 + x // 15 + x // 21 + x // 33 + x // 39 + x // 35 + x // 55 + x // 65 + x // 77 + x // 91 + x // 143 - x // 30 - x // 42 - x // 66 - x // 78 - x // 70 - x // 110 - x // 130 - x // 154 - x // 182 - x // 286 - x // 105 - x // 165 - x // 195 - x // 231 - x // 273 - x // 429 - x // 385 - x // 455 - x // 715 - x // 1001 + x // 210 + x // 330 + x // 390 + x // 462 + x // 546 + x // 858 + x // 770 + x // 910 + x // 1430 + x // 2002 + x // 1155 + x // 1365 + x // 2145 + x // 3003 + x // 5005 - x // 2310 - x // 2730 - x // 4290 - x // 6006 - x // 10010 - x // 15015 + x // 30030) else: value = ( x - x // 2 - x // 3 - x // 5 - x // 7 - x // 11 - x // 13 - x // 17 + x // 6 + x // 10 + x // 14 + x // 22 + x // 26 + x // 34 + x // 15 + x // 21 + x // 33 + x // 39 + x // 51 + x // 35 + x // 55 + x // 65 + x // 85 + x // 77 + x // 91 + x // 119 + x // 143 + x // 187 + x // 221 - x // 30 - x // 42 - x // 66 - x // 78 - x // 102 - x // 70 - x // 110 - x // 130 - x // 170 - x // 154 - x // 182 - x // 238 - x // 286 - x // 374 - x // 442 - x // 105 - x // 165 - x // 195 - x // 255 - x // 231 - x // 273 - x // 357 - x // 429 - x // 561 - x // 663 - x // 385 - x // 455 - x // 595 - x // 715 - x // 935 - x // 1105 - x // 1001 - x // 1309 - x // 1547 - x // 2431 + x // 210 + x // 330 + x // 390 + x // 510 + x // 462 + x // 546 + x // 714 + x // 858 + x // 1122 + x // 1326 + x // 770 + x // 910 + x // 1190 + x // 1430 + x // 1870 + x // 2210 + x // 2002 + x // 2618 + x // 3094 + x // 4862 + x // 1155 + x // 1365 + x // 1785 + x // 2145 + x // 2805 + x // 3315 + x // 3003 + x // 3927 + x // 4641 + x // 7293 + x // 5005 + x // 6545 + x // 7735 + x // 12155 + x // 17017 - x // 2310 - x // 2730 - x // 3570 - x // 4290 - x // 5610 - x // 6630 - x // 6006 - x // 7854 - x // 9282 - x // 14586 - x // 10010 - x // 13090 - x // 15470 - x // 24310 - x // 34034 - x // 15015 - x // 19635 - x // 23205 - x // 36465 - x // 51051 - x // 85085 + x // 30030 + x // 39270 + x // 46410 + x // 72930 + x // 102102 + x // 170170 + x // 255255 - x // 510510) elif a >= bisect(primes, x**(0.5)) and x < primes[-1]: pi = bisect(primes, x) value = pi - a + 1 else: value = (x + 1) // 2 for i in xrange(1, a): if primes[i] > x: break value -= phi(x // primes[i], i) cache[x, a] = value return value def phi2(n, a, b): s1 = 0 for i in xrange(a, b): s1 += phi(n // primes[i], b) + b - 1 return s1 def phi3(n, a, b, c): s2 = 0 for i in xrange(a, c): bi = phi(integer_sqrt(n // primes[i]), b) + b - 1 for j in xrange(i, bi): idx = phi(n // (primes[i] * primes[j]), b) + b - 1 s2 += idx - j return s2 value = (b + a - 2) * (b - a + 1) // 2 + phi(n, a) - phi2(n, a, b) - phi3( n, a, b, c) return value
def pollard_p_minus_1(n, limit=100000): r"""Attempts to find a nontrivial factor of `n`. Given a composite number `n` and search bound `limit`, this algorithm attempts to find a nontrivial factor of `n` using Pollard's p - 1 method. Parameters ---------- n : int (n > 1) Integer to be factored. limit : int (limit > 0) (default=100000) Search limit for possible prime divisors of p - 1. Returns ------- d : int Divisor of n. Notes ----- The algorithm used here is a one-stage form of Pollard's p - 1 method. The idea used is that if p - 1 divides Q, then p divides a^Q - 1 if (a, p) == 1. So if p is a prime factor of an integer n, then p divides gcd(a^Q - 1, n). The idea here is to choose values Q with many divisors of the form p - 1, and so search for many primes p as possible divisors at once. This is not a general purpose factoring algorithm, but this technique works well when n has a prime factor P such that P - 1 is divisible by only small primes. See chapter 6 of [2] for details. References ---------- .. [1] R. Crandall, C. Pomerance, "Prime Numbers: A Computational Perspective", Springer-Verlag, New York, 2001. .. [2] H. Riesel, "Prime Numbers and Computer Methods for Factorization", 2nd edition, Birkhauser Verlag, Basel, Switzerland, 1994. Examples -------- >>> pollard_p_minus_1(1112470797641561909) 1056689261L """ p_list = sieves.primes(limit) pow_list = [] for p in p_list: pk = p while pk <= limit: pow_list.append((pk, p)) pk *= p pow_list.sort() c = 13 for (count, (pk, p)) in enumerate(pow_list): c = pow(c, p, n) if count % 100 == 0: g = gcd(c - 1, n) if 1 < g < n: return g return gcd(c - 1, n)
def cfrac(n, k=None): r"""Returns a nontrivial divisor of `n`. Given a composite integer `n` > 1, this algorithm attempts to find a factor of `n` using Morrison and Brillhart's continued fraction method CFRAC. Parameters ---------- n : int (n > 1) Number to be factored. k : int, optional (default=None) Multiplier to use in case the period of sqrt(n) is too short. Returns ------- d : int Divisor of n. Notes ----- Morrison and Brillhart's continued fraction method was the first factorization algorithm of subexponential running time. The idea is to find a nontrivial solution to the congrunce x^2 = y^2 (mod n), and extracting a factor from gcd(x + y, n). See [1] for details, and see [2] for implementation details. References ---------- .. [1] H. Cohen, "A Course in Computational Algebraic Number Theory", Springer-Verlag, New York, 2000. .. [2] M.A. Morrison, J. Brillhart, "A Method of Factoring and the Factorization of F7", Mathematics of Computation, Vol. 29, Num. 129, Jan. 1975. .. [3] H. Riesel, "Prime Numbers and Computer Methods for Factorization", 2nd edition, Birkhauser Verlag, Basel, Switzerland, 1994. Examples -------- >>> cfrac(12007001) 4001 >>> cfrac(1112470797641561909) 1052788969L >>> cfrac(2175282241519502424792841) 513741730823L """ # B is our smoothness bound. B = int(exp(0.5 * sqrt(log(n) * log(log(n))))) + 1 prime_list = sieves.primes(B) # Choose a multiplier if none is provided. if k is None: k = _cfrac_multiplier(n) kn = k * n # Perform simple trial division by the primes we computed to find any # small prime divisors. for p in prime_list: if n % p == 0: return p # Our factor base needs to include -1 and 2, and the odd primes p for # which (kN|p) = 0 or 1. factor_base = [-1] for p in prime_list: if p == 2 or jacobi_symbol(kn, p) >= 0: factor_base.append(p) num_primes = len(factor_base) # Compute the product of the elements in our factor base for smoothness # checking computations later. prod = 1 for p in factor_base: prod *= p # Instead of using trial division to check each value for smoothness # individually, we use a batch smoothness test, processing batches of # size `batch_size` at once. # Set e as the least positive integer with n <= 2**e. e = 1 while 2**e < n: e *= 2 aq_pairs = _cfrac_aq_pairs(kn) num_smooths_found = 0 exponent_matrix = [] a_list = [] while num_smooths_found <= num_primes: (i, a, q) = aq_pairs.next() # This is from the batch smoothness test given as Algorithm 3.3.1 # in [1]. if gcd(q, pow(prod, e, q)) != q: continue if i % 2 == 1: q *= -1 # At this point, we know q is smooth, and we can factor it # completely using our factor base. exponent_vector = smooth_factor(q, factor_base) exponent_matrix.append(exponent_vector) num_smooths_found += 1 a_list.append(a) kernel = _z2_gaussian_elimination(exponent_matrix) for i in xrange(len(kernel)): y = 1 x2_exponents = [0] * num_primes for j in xrange(len(kernel[i])): if kernel[i][j]: y = (a_list[j] * y) % n for f in xrange(num_primes): x2_exponents[f] += exponent_matrix[j][f] x = 1 for j in xrange(num_primes): x *= factor_base[j]**(x2_exponents[j] // 2) for val in [x - y, x + y]: d = gcd(val, n) if 1 < d < n: return d
def cfrac(n, k=None): r"""Returns a nontrivial divisor of `n`. Given a composite integer `n` > 1, this algorithm attempts to find a factor of `n` using Morrison and Brillhart's continued fraction method CFRAC. Parameters ---------- n : int (n > 1) Number to be factored. k : int, optional (default=None) Multiplier to use in case the period of sqrt(n) is too short. Returns ------- d : int Divisor of n. Notes ----- Morrison and Brillhart's continued fraction method was the first factorization algorithm of subexponential running time. The idea is to find a nontrivial solution to the congrunce x^2 = y^2 (mod n), and extracting a factor from gcd(x + y, n). See [1] for details, and see [2] for implementation details. References ---------- .. [1] H. Cohen, "A Course in Computational Algebraic Number Theory", Springer-Verlag, New York, 2000. .. [2] M.A. Morrison, J. Brillhart, "A Method of Factoring and the Factorization of F7", Mathematics of Computation, Vol. 29, Num. 129, Jan. 1975. .. [3] H. Riesel, "Prime Numbers and Computer Methods for Factorization", 2nd edition, Birkhauser Verlag, Basel, Switzerland, 1994. Examples -------- >>> cfrac(12007001) 4001 >>> cfrac(1112470797641561909) 1052788969L >>> cfrac(2175282241519502424792841) 513741730823L """ # B is our smoothness bound. B = int(exp(0.5*sqrt(log(n)*log(log(n))))) + 1 prime_list = sieves.primes(B) # Choose a multiplier if none is provided. if k is None: k = _cfrac_multiplier(n) kn = k*n # Perform simple trial division by the primes we computed to find any # small prime divisors. for p in prime_list: if n % p == 0: return p # Our factor base needs to include -1 and 2, and the odd primes p for # which (kN|p) = 0 or 1. factor_base = [-1] for p in prime_list: if p == 2 or jacobi_symbol(kn, p) >= 0: factor_base.append(p) num_primes = len(factor_base) # Compute the product of the elements in our factor base for smoothness # checking computations later. prod = 1 for p in factor_base: prod *= p # Instead of using trial division to check each value for smoothness # individually, we use a batch smoothness test, processing batches of # size `batch_size` at once. # Set e as the least positive integer with n <= 2**e. e = 1 while 2**e < n: e *= 2 aq_pairs = _cfrac_aq_pairs(kn) num_smooths_found = 0 exponent_matrix = [] a_list = [] while num_smooths_found <= num_primes: (i, a, q) = aq_pairs.next() # This is from the batch smoothness test given as Algorithm 3.3.1 # in [1]. if gcd(q, pow(prod, e, q)) != q: continue if i % 2 == 1: q *= -1 # At this point, we know q is smooth, and we can factor it # completely using our factor base. exponent_vector = smooth_factor(q, factor_base) exponent_matrix.append(exponent_vector) num_smooths_found += 1 a_list.append(a) kernel = _z2_gaussian_elimination(exponent_matrix) for i in xrange(len(kernel)): y = 1 x2_exponents = [0]*num_primes for j in xrange(len(kernel[i])): if kernel[i][j]: y = (a_list[j]*y) % n for f in xrange(num_primes): x2_exponents[f] += exponent_matrix[j][f] x = 1 for j in xrange(num_primes): x *= factor_base[j]**(x2_exponents[j]//2) for val in [x - y, x + y]: d = gcd(val, n) if 1 < d < n: return d
def factored_xrange(a, b=None): """Returns an iterator over the factorizations of the numbers in [a, b). Given positive integers a and b with a < b, this returns an iterator over all pairs (n, n_factorization) with a <= n < b, and n_factorization is the factorization of n into prime powers. If the optional parameter b is None, then a is taken to be 1, and b = a. Input: * a: int (a > 0) * b: int (b > a) (default=None) Returns: * P: generator The values output by this generator are tuples (n, n_factorization), where n is an integer in [a, b), and n_factorization is the prime factorization of n. Examples: >>> list(factored_xrange(10, 20)) [(10, [(2, 1), (5, 1)]), (11, [(11, 1)]), (12, [(2, 2), (3, 1)]), (13, [(13, 1)]), (14, [(2, 1), (7, 1)]), (15, [(3, 1), (5, 1)]), (16, [(2, 4)]), (17, [(17, 1)]), (18, [(2, 1), (3, 2)]), (19, [(19, 1)])] Details: All primes <= sqrt(b) are computed, and a segmented sieve is used to construct the factorizations of the integers in the interval [a, b). """ if a < 2: a = 1 if b is None: b, a = a, 1 if b <= a: return block_size = int(b**(0.5)) prime_list = primes(block_size) if a == 1: yield (1, [(1, 1)]) a += 1 for start in xrange(a, b, block_size): block = range(start, start + block_size) factorizations = [[] for _ in xrange(block_size)] for p in prime_list: offset = ((p * (start // p + 1) - a) % block_size) % p for i in xrange(offset, block_size, p): k = 0 while block[i] % p == 0: block[i] /= p k += 1 factorizations[i].append((p, k)) for i in xrange(block_size): if start + i >= b: return if block[i] != 1: factorizations[i].append((block[i], 1)) yield (start + i, factorizations[i])
def pollard_p_minus_1(n, limit=100000): r"""Attempts to find a nontrivial factor of `n`. Given a composite number `n` and search bound `limit`, this algorithm attempts to find a nontrivial factor of `n` using Pollard's p - 1 method. Parameters ---------- n : int (n > 1) Integer to be factored. limit : int (limit > 0) (default=100000) Search limit for possible prime divisors of p - 1. Returns ------- d : int Divisor of n. Notes ----- The algorithm used here is a one-stage form of Pollard's p - 1 method. The idea used is that if p - 1 divides Q, then p divides a^Q - 1 if (a, p) == 1. So if p is a prime factor of an integer n, then p divides gcd(a^Q - 1, n). The idea here is to choose values Q with many divisors of the form p - 1, and so search for many primes p as possible divisors at once. This is not a general purpose factoring algorithm, but this technique works well when n has a prime factor P such that P - 1 is divisible by only small primes. See chapter 6 of [2] for details. References ---------- .. [1] R. Crandall, C. Pomerance, "Prime Numbers: A Computational Perspective", Springer-Verlag, New York, 2001. .. [2] H. Riesel, "Prime Numbers and Computer Methods for Factorization", 2nd edition, Birkhauser Verlag, Basel, Switzerland, 1994. Examples -------- >>> pollard_p_minus_1(1112470797641561909) 1056689261L """ p_list = sieves.primes(limit) pow_list = [] for p in p_list: pk = p while pk <= limit: pow_list.append((pk, p)) pk *= p pow_list.sort() c = 13 for (count, (pk, p)) in enumerate(pow_list): c = pow(c, p, n) if count % 100 == 0: g = gcd(c - 1, n) if 1 < g < n: return g return gcd(c - 1, n)