def nextprime(n): if n < 2: return 2 if n == 2: return 3 n = (n + 1) | 1 # first odd larger than n m = n % 6 if m == 3: if isprime(n+2): return n+2 n += 4 elif m == 5: if isprime(n): return n n += 2 for m in count(n, 6): if isprime(m ): return m if isprime(m+4): return m+4
def williams_pp1(n): if isprime(n): return n m = ispower(n) if m: return m for v in count(1): for p in primegen(): e = ilog(isqrt(n), p) if e == 0: break for _ in xrange(e): v = mlucas(v, p, n) g = gcd(v - 2, n) if 1 < g < n: return g if g == n: break
def pollard_pm1(n, B1=100, B2=1000): # TODO: What are the best default bounds and way to increment them? if isprime(n): return n m = ispower(n) if m: return m while True: pg = primegen() q = 2 # TODO: what about other initial values of q? p = pg.next() while p <= B1: q, p = pow(q, p**ilog(B1, p), n), pg.next() g = gcd(q-1, n) if 1 < g < n: return g while p <= B2: q, p = pow(q, p, n), pg.next() g = gcd(q-1, n) if 1 < g < n: return g # These bounds failed. Increase and try again. B1 *= 10 B2 *= 10
def pollardRho_brent(n): if isprime(n): return n g = n while g == n: y, c, m, g, r, q = randrange(1, n), randrange(1, n), randrange(1, n), 1, 1, 1 while g==1: x, k = y, 0 for i in xrange(r): y = (y**2 + c) % n while k < r and g == 1: ys = y for i in xrange(min(m, r-k)): y = (y**2 + c) % n q = q * abs(x-y) % n g, k = gcd(q, n), k+m r *= 2 if g==n: while True: ys = (ys**2+c)%n g = gcd(abs(x-ys), n) if g > 1: break return g
def ecm(n, B1=10, B2=20): # TODO: Determine the best defaults for B1 and B2 and the best way to increment them and iters # "Modern" ECM using Montgomery curves and an algorithm analogous to the two-phase variant of Pollard's p-1 method # TODO: We currently compute the prime lists from the sieve as we need them, but this means that we recompute them at every # iteration. While it would not be particularly efficient memory-wise, we might be able to increase time-efficiency # by computing the primes we need ahead of time (say once at the beginning and then once each time we increase the # bounds) and saving them in lists, and then iterate the inner while loops over those lists. if isprime(n): return n m = ispower(n) if m: return m iters = 1 while True: for _ in xrange(iters): # TODO: multiprocessing? # TODO: Do we really want to call the randomizer? Why not have seed be a function of B1, B2, and iters? # TODO: Are some seeds better than others? seed = randrange(6, n) u, v = (seed**2 - 5) % n, 4*seed % n p = pow(u, 3, n) Q, C = (pow(v-u,3,n)*(3*u+v) % n, 4*p*v % n), (p, pow(v,3,n)) pg = primegen() p = pg.next() while p <= B1: Q, p = ecmul(p**ilog(B1, p), Q, C, n), pg.next() g = gcd(Q[1], n) if 1 < g < n: return g while p <= B2: # "There is a simple coding trick that can speed up the second stage. Instead of multiplying each prime times Q, # we iterate over i from B1 + 1 to B2, adding 2Q at each step; when i is prime, the current Q can be accumulated # into the running solution. Again, we defer the calculation of the greatest common divisor until the end of the # iteration." TODO: Implement this trick and compare performance. Q = ecmul(p, Q, C, n) g *= Q[1] g %= n p = pg.next() g = gcd(g, n) if 1 < g < n: return g # This seed failed. Try again with a new one. # These bounds failed. Increase and try again. B1 *= 3 B2 *= 3 iters *= 2
def primefac(n, trial_limit=1000, rho_rounds=42000, verbose=False, methods=(pollardRho_brent, pollard_pm1, williams_pp1, ecm, mpqs)): # Obtains a complete factorization of n, yielding the prime factors as they are obtained. # If the user explicitly specifies a splitting method, use that method. Otherwise, # 1. Pull out small factors with trial division. # TODO: a few rounds of Fermat's method? # 2. Do a few rounds of Pollard's Rho algorithm. # TODO: a few rounds of ECM by itself? # TODO: a certain amount of P-1? # 3. Launch multifactor on the remainder. Multifactor has enough overhead that we want to be fairly sure that rho isn't # likely to yield new factors soon. The default value of rho_rounds=42000 seems good for that but is probably overkill. if n < 2: return if isprime(n): yield n; return factors, nroot = [], isqrt(n) for p in primegen(): # Note that we remove factors of 2 whether the user wants to or not. if n%p == 0: while n%p == 0: yield p n /= p nroot = isqrt(n) if isprime(n): yield n return if p > nroot: if n != 1: yield n return if p >= trial_limit: break if isprime(n): yield n; return if rho_rounds == "inf": factors = [n] while len(factors) != 0: n = min(factors) factors.remove(n) f = pollardRho_brent(n) if isprime(f): yield f else: factors.append(f) n /= f if isprime(n): yield n else: factors.append(n) return factors, difficult = [n], [] while len(factors) != 0: rhocount = 0 n = factors.pop() try: g = n while g == n: x, c, g = randrange(1, n), randrange(1, n), 1 y = x while g==1: if rhocount >= rho_rounds: raise Exception rhocount += 1 x = (x**2 + c) % n y = (y**2 + c) % n y = (y**2 + c) % n g = gcd(x-y, n) # We now have a nontrivial factor g of n. If we took too long to get here, we're actually at the except statement. if isprime(g): yield g else: factors.append(g) n /= g if isprime(n): yield n else: factors.append(n) except Exception: difficult.append(n) # Factoring n took too long. We'll have multifactor chug on it. factors = difficult while len(factors) != 0: n = min(factors) factors.remove(n) f = multifactor(n, methods=methods, verbose=verbose) if isprime(f): yield f else: factors.append(f) n /= f if isprime(n): yield n else: factors.append(n)
def mpqs(n): # When the bound proves insufficiently large, we throw out all our work and start over. # TODO: When this happens, get more data, but don't trash what we already have. # TODO: Rewrite to get a few more relations before proceeding to the linear algebra. # TODO: When we need to increase the bound, what is the optimal increment? # Special cases: this function poorly handles primes and perfect powers: m = ispower(n) if m: return m if isprime(n): return n root_n, root_2n = isqrt(n), isqrt(2*n) bound = ilog(n**6, 10)**2 # formula chosen by experiment while True: try: prime, mod_root, log_p, num_prime = [], [], [], 0 # find a number of small primes for which n is a quadratic residue p = 2 while p < bound or num_prime < 3: leg = legendre(n%p, p) if leg == 1: prime += [p] mod_root += [mod_sqrt(n, p)] # the rhs was [int(mod_sqrt(n, p))]. If we get errors, put it back. log_p += [log(p, 10)] num_prime += 1 elif leg == 0: return p p = nextprime(p) x_max = len(prime)*60 # size of the sieve m_val = (x_max * root_2n) >> 1 # maximum value on the sieved range # fudging the threshold down a bit makes it easier to find powers of primes as factors # as well as partial-partial relationships, but it also makes the smoothness check slower. # there's a happy medium somewhere, depending on how efficient the smoothness check is thresh = log(m_val, 10) * 0.735 # skip small primes. they contribute very little to the log sum # and add a lot of unnecessary entries to the table # instead, fudge the threshold down a bit, assuming ~1/4 of them pass min_prime = mpz(thresh*3) fudge = sum(log_p[i] for i,p in enumerate(prime) if p < min_prime)/4 thresh -= fudge smooth, used_prime, partial = [], set(), {} num_smooth, num_used_prime, num_partial, num_poly, root_A = 0, 0, 0, 0, isqrt(root_2n / x_max) while num_smooth <= num_used_prime: # find an integer value A such that: # A is =~ sqrt(2*n) / x_max # A is a perfect square # sqrt(A) is prime, and n is a quadratic residue mod sqrt(A) while True: root_A = nextprime(root_A) leg = legendre(n, root_A) if leg == 1: break elif leg == 0: return root_A A = root_A**2 # solve for an adequate B # B*B is a quadratic residue mod n, such that B*B-A*C = n # this is unsolvable if n is not a quadratic residue mod sqrt(A) b = mod_sqrt(n, root_A) B = (b + (n - b*b) * modinv(b + b, root_A))%A C = (B*B - n) / A # B*B-A*C = n <=> C = (B*B-n)/A num_poly += 1 # sieve for prime factors sums, i = [0.0]*(2*x_max), 0 for p in prime: if p < min_prime: i += 1 continue logp = log_p[i] inv_A = modinv(A, p) # modular root of the quadratic a, b, k = mpz(((mod_root[i] - B) * inv_A)%p), mpz(((p - mod_root[i] - B) * inv_A)%p), 0 while k < x_max: if k+a < x_max: sums[k+a] += logp if k+b < x_max: sums[k+b] += logp if k: sums[k-a+x_max] += logp sums[k-b+x_max] += logp k += p i += 1 # check for smooths i = 0 for v in sums: if v > thresh: x, vec, sqr = x_max-i if i > x_max else i, set(), [] # because B*B-n = A*C # (A*x+B)^2 - n = A*A*x*x+2*A*B*x + B*B - n # = A*(A*x*x+2*B*x+C) # gives the congruency # (A*x+B)^2 = A*(A*x*x+2*B*x+C) (mod n) # because A is chosen to be square, it doesn't need to be sieved val = sieve_val = (A*x + 2*B)*x + C if sieve_val < 0: vec, sieve_val = {-1}, -sieve_val for p in prime: while sieve_val%p == 0: if p in vec: sqr += [p] # track perfect sqr facs to avoid sqrting something huge at the end vec ^= {p} sieve_val = mpz(sieve_val / p) if sieve_val == 1: # smooth smooth += [(vec, (sqr, (A*x+B), root_A))] used_prime |= vec elif sieve_val in partial: # combine two partials to make a (xor) smooth # that is, every prime factor with an odd power is in our factor base pair_vec, pair_vals = partial[sieve_val] sqr += list(vec & pair_vec) + [sieve_val] vec ^= pair_vec smooth += [(vec, (sqr + pair_vals[0], (A*x+B)*pair_vals[1], root_A*pair_vals[2]))] used_prime |= vec num_partial += 1 else: partial[sieve_val] = (vec, (sqr, A*x+B, root_A)) # save partial for later pairing i += 1 num_smooth, num_used_prime = len(smooth), len(used_prime) used_prime = sorted(list(used_prime)) # set up bit fields for gaussian elimination masks, mask, bitfields = [], 1, [0]*num_used_prime for vec, vals in smooth: masks += [mask] i = 0 for p in used_prime: if p in vec: bitfields[i] |= mask i += 1 mask <<= 1 # row echelon form offset = 0 null_cols = [] for col in xrange(num_smooth): pivot = bitfields[col-offset] & masks[col] == 0 # This occasionally throws IndexErrors. # TODO: figure out why it throws errors and fix it. for row in xrange(col+1-offset, num_used_prime): if bitfields[row] & masks[col]: if pivot: bitfields[col-offset], bitfields[row], pivot = bitfields[row], bitfields[col-offset], False else: bitfields[row] ^= bitfields[col-offset] if pivot: null_cols += [col] offset += 1 # reduced row echelon form for row in xrange(num_used_prime): mask = bitfields[row] & -bitfields[row] # lowest set bit for up_row in xrange(row): if bitfields[up_row] & mask: bitfields[up_row] ^= bitfields[row] # check for non-trivial congruencies # TODO: if none exist, check combinations of null space columns... # if _still_ none exist, sieve more values for col in null_cols: all_vec, (lh, rh, rA) = smooth[col] lhs = lh # sieved values (left hand side) rhs = [rh] # sieved values - n (right hand side) rAs = [rA] # root_As (cofactor of lhs) i = 0 for field in bitfields: if field & masks[col]: vec, (lh, rh, rA) = smooth[i] lhs += list(all_vec & vec) + lh all_vec ^= vec rhs += [rh] rAs += [rA] i += 1 factor = gcd(listprod(rAs)*listprod(lhs) - listprod(rhs), n) if 1 < factor < n: return factor except IndexError: pass bound *= 1.2
if x in ms: if x in ("p-1", "p+1", "mpqs") and ms[x] in methods: continue methods.append(ms[x]) else: rpx.append(arg) nums = rpn(' '.join(rpx)) for x in nums: assert isinstance(x, inttypes) except: exit("Error while parsing arguments") if su: print for n in nums: print "%d:" % n, f = {} for p in primefac(n, trial_limit=(n if tr == "inf" else tr), rho_rounds=rr, verbose=veb, methods=methods): f[p] = f.get(p, 0) + 1 print p, stdout.flush() assert isprime(p) and n%p == 0, (n, p) print if su: print "Z%d = " % len(str(n)), outstr = "" for p in sorted(f): if f[p] == 1: outstr += "P%d x " % len(str(p)) else: outstr += "P%d^%d x " % (len(str(p)), f[p]) outstr = outstr[:-2] + " = " for p in sorted(f): if f[p] == 1: outstr += " %d x" % p else: outstr += " %d^%d x" % (p, f[p]) print outstr[:-2] print # Fun examples: