def isfinished_bsgscv(n, sossp, sogsp, nt, lpt, qpt, disc, classnum, indofg): """ Determine whether the bsgs algorithm is finished or not yet. This is a submodule called by the bsgs module. """ lpt.append(n) sumn = 1 for nid in lpt: sumn = sumn * nid if sumn == qpt: return True, sossp, sogsp elif sumn > qpt: raise ValueError if n == 1: return False, sossp, sogsp else: tpsq = misc.primePowerTest(n) if (tpsq[1] != 0) and ((tpsq[1] % 2) == 0): q = arith1.floorsqrt(n) else: q = arith1.floorsqrt(n) + 1 ss = sossp.retel() new_sossp = ClassGroup(disc, classnum, []) tnt = copy.deepcopy(nt) for i in range(q): base = tnt ** i for ssi in ss: newel = base * ssi if new_sossp.search(newel) is False: newel.alpha = ssi.alpha[:] lenal = len(newel.alpha) sfind = indofg - lenal for sit in range(sfind): newel.alpha.append([lenal + sit, 0, 0]) newel.alpha.append([indofg, tnt, i]) new_sossp.insttree(newel) # multiple of two elements of G y = nt ** q ltl = sogsp.retel() new_sogsp = ClassGroup(disc, classnum, []) for i in range(q + 1): base = y ** (-i) for eol in ltl: newel2 = base * eol if new_sogsp.search(newel2) is False: newel2.beta = eol.beta[:] lenbt = len(newel2.beta) gfind = indofg - lenbt for git in range(gfind): newel2.beta.append([lenbt + git, 0, 0]) newel2.beta.append([indofg, tnt, q * (-i)]) new_sogsp.insttree(newel2) # multiple of two elements of G return False, new_sossp, new_sogsp
def testFloorsqrt(self): self.assertEqual(0, arith1.floorsqrt(0)) self.assertEqual(1, arith1.floorsqrt(1)) self.assertEqual(1, arith1.floorsqrt(3)) self.assertEqual(2, arith1.floorsqrt(4)) self.assertEqual(3, arith1.floorsqrt(10)) self.assertEqual(arith1.floorsqrt(400000000000000000000), 20000000000) self.assertEqual(arith1.floorsqrt(400000000000000000000 - 1), 19999999999) self.assertTrue(arith1.floorsqrt(2**60 - 1)**2 <= 2**60 - 1) self.assertTrue(arith1.floorsqrt(2**59 - 1)**2 <= 2**59 - 1)
def _lucas_test_sequence(n, a, b): """ Return x_0, x_1, x_m, x_{m+1} of Lucas sequence of parameter a, b, where m = (n - (a**2 - 4*b / n)) // 2. """ d = a**2 - 4*b if (d >= 0 and arith1.floorsqrt(d) ** 2 == d) \ or not(gcd.coprime(n, 2*a*b*d)): raise ValueError("Choose another parameters.") x_0 = 2 inv_b = arith1.inverse(b, n) x_1 = ((a ** 2) * inv_b - 2) % n # Chain functions def even_step(u): """ 'double' u. """ return (u**2 - x_0) % n def odd_step(u, v): """ 'add' u and v. """ return (u*v - x_1) % n m = (n - arith1.legendre(d, n)) // 2 x_m, x_mplus1 = Lucas_chain(m, even_step, odd_step, x_0, x_1) return x_0, x_1, x_m, x_mplus1
def _lucas_test_sequence(n, a, b): """ Return x_0, x_1, x_m, x_{m+1} of Lucas sequence of parameter a, b, where m = (n - (a**2 - 4*b / n)) >> 1. """ d = a**2 - 4 * b if (d >= 0 and arith1.floorsqrt(d) ** 2 == d) \ or not(gcd.coprime(n, 2*a*b*d)): raise ValueError("Choose another parameters.") x_0 = 2 inv_b = arith1.inverse(b, n) x_1 = ((a**2) * inv_b - 2) % n # Chain functions def even_step(u): """ 'double' u. """ return (u**2 - x_0) % n def odd_step(u, v): """ 'add' u and v. """ return (u * v - x_1) % n m = (n - arith1.legendre(d, n)) >> 1 x_m, x_mplus1 = Lucas_chain(m, even_step, odd_step, x_0, x_1) return x_0, x_1, x_m, x_mplus1
def cornacchia(d, p): """ Return the solution of x^2 + d * y^2 = p . p be a prime and d be an integer such that 0 < d < p. """ if (d <= 0) or (d >= p): raise ValueError("invalid input") k = arith1.legendre(-d, p) if k == -1: raise ValueError("no solution") x0 = arith1.modsqrt(-d, p) if x0 < (p / 2): x0 = p - x0 a = p b = x0 l = arith1.floorsqrt(p) while b > l: a, b = b, a % b c, r = divmod(p - b * b, d) if r: raise ValueError("no solution") t = arith1.issquare(c) if t == 0: raise ValueError("no solution") else: return (b, t)
def cornacchiamodify(d, p): """ Algorithm 26 (Modified cornacchia) Input : p be a prime and d be an integer such that d < 0 and d > -4p with d = 0, 1 (mod 4) Output : the solution of u^2 -d * v^2 = 4p. """ q = 4 * p if (d >= 0) or (d <= -q): raise ValueError("invalid input") if p == 2: b = arith1.issquare(d + 8) if b: return (b, 1) else: raise ValueError("no solution") if arith1.legendre(d, p) == -1: raise ValueError("no solution") x0 = arith1.modsqrt(d, p) if (x0 - d) & 1: x0 = p - x0 a = 2 * p b = x0 l = arith1.floorsqrt(q) while b > l: a, b = b, a % b c, r = divmod(q - b * b, -d) if r: raise ValueError("no solution") t = arith1.issquare(c) if t: return (b, t) else: raise ValueError("no solution")
def cornacchiamodify(d, p): """ Algorithm 26 (Modified cornacchia) Input : p be a prime and d be an integer such that d < 0 and d > -4p with d = 0, 1 (mod 4) Output : the solution of u^2 -d * v^2 = 4p. """ q = 4 * p if (d >= 0) or (d <= -q): raise ValueError("invalid input") if p == 2: b = arith1.issquare(d + 8) if b: return (b, 1) else: raise ValueError("no solution") if arith1.legendre(d, p) == -1: raise ValueError("no solution") x0 = arith1.modsqrt(d, p) if (x0 - d) % 2 != 0: x0 = p - x0 a = 2 * p b = x0 l = arith1.floorsqrt(q) while b > l: a, b = b, a % b c, r = divmod(q - b * b, -d) if r: raise ValueError("no solution") t = arith1.issquare(c) if t: return (b, t) else: raise ValueError("no solution")
def trialDivision(n, bound=0): """ Trial division primality test for an odd natural number. Optional second argument is a search bound of primes. If the bound is given and less than the sqaure root of n and True is returned, it only means there is no prime factor less than the bound. """ if bound: m = min(bound, arith1.floorsqrt(n)) else: m = arith1.floorsqrt(n) for p in bigrange.range(3, m+1, 2): if not (n % p): return False return True
def trialDivision(n, bound=0): """ Trial division primality test for an odd natural number. Optional second argument is a search bound of primes. If the bound is given and less than the sqaure root of n and True is returned, it only means there is no prime factor less than the bound. """ if bound: m = min(bound, arith1.floorsqrt(n)) else: m = arith1.floorsqrt(n) for p in bigrange.range(3, m + 1, 2): if not (n % p): return False return True
def generator_eratosthenes(n): """ Generate primes up to n (inclusive) using Eratosthenes sieve. """ if n < 2: return yield 2 if n <= 2: return yield 3 # make list for sieve sieve_len_max = (n + 1) >> 1 sieve = [True, False, True] sieve_len = 3 k = 5 i = 2 while sieve_len < sieve_len_max: if sieve[i]: yield k sieve_len *= k if sieve_len_max < sieve_len: sieve_len //= k # adjust sieve list length sieve *= sieve_len_max // sieve_len sieve += sieve[:(sieve_len_max - len(sieve))] sieve_len = sieve_len_max else: sieve = sieve * k for j in range(i, sieve_len, k): sieve[j] = False k += 2 i += 1 # sieve limit = arith1.floorsqrt(n) while k <= limit: if sieve[i]: yield k j = (k**2 - 1) >> 1 while j < sieve_len_max: sieve[j] = False j += k k += 2 i += 1 # output result limit = (n - 1) >> 1 while i <= limit: if sieve[i]: yield 2 * i + 1 i += 1
def class_number_bsgs(disc): """ Return the class number with the given discriminant. """ if disc % 4 not in (0, 1): raise ValueError("a discriminant must be 0 or 1 mod 4") if disc >= 0: raise ValueError("a discriminant must be negative") lx = max(arith1.floorpowerroot(abs(disc), 5), 500 * (math.log(abs(disc)))**2) uprbd = int(class_formula(disc, int(lx)) * 3 / 2) lwrbd = uprbd // 2 + 1 bounds = [lwrbd, uprbd] # get the unit element = RetNext(disc) ut = element.unit() # append the unit to subset of G sossp = ClassGroup(disc, 0, []) sogsp = ClassGroup(disc, 0, []) sossp.insttree(ut) sogsp.insttree(ut) h = 1 # order finished = False while not finished: mstp1 = bounds[1] - bounds[0] if mstp1 <= 1: q = 1 else: q = arith1.floorsqrt(mstp1) if misc.primePowerTest(mstp1)[1] != 2: q += 1 # get next element nt = element.retnext() # x is the set of elements of G x = [ut, nt ** h] if q > 2: x.extend([0] * (q - 2)) # compute small steps if x[1] == ut: # compute the order of nt n = trorder(h, sossp, sogsp, nt, disc) else: n = trbabysp(q, x, bounds, sossp, sogsp, ut, h, nt, disc) # finished? finished, h, sossp, sogsp = isfinished_trbsgs(lwrbd, bounds, h, n, sossp, sogsp, nt, disc) return h
def isfinished_trbsgs(lwrbd, bounds, h, n, sossp, sogsp, nt, disc): """ Determine whether bsgs is finished or not yet. This is a submodule called by the bsgs module. lwrbd, h, n: int nt: element """ h *= n if h >= lwrbd: result = True elif n == 1: result = False else: bounds[0] = (bounds[0] + n - 1) // n # ceil of lower bound // n bounds[1] = bounds[1] // n # floor of upper bound // n q = arith1.floorsqrt(n) if misc.primePowerTest(n)[1] != 2: q = arith1.floorsqrt(n) + 1 # ceil of sqrt sossp, sogsp = _update_subgrps(q, nt, sossp, sogsp, disc) result = False return result, h, sossp, sogsp
def apr(n): """ apr is the main function for Adleman-Pomerance-Rumery primality test. Assuming n has no prime factors less than 32. Assuming n is spsp for several bases. """ L = Status() rb = arith1.floorsqrt(n) + 1 el = TestPrime() while el.et <= rb: el = el.next() plist = el.t.factors.keys() plist.remove(2) L.yet(2) for p in plist: if pow(n, p-1, p*p) != 1: L.done(p) else: L.yet(p) qlist = el.et.factors.keys() qlist.remove(2) J = JacobiSum() for q in qlist: for p in plist: if (q-1) % p != 0: continue if not L.subodd(p, q, n, J): return False k = arith1.vp(q-1, 2)[0] if k == 1: if not L.sub2(q, n): return False elif k == 2: if not L.sub4(q, n, J): return False else: if not L.sub8(q, k, n, J): return False for p in L.yet_keys(): if not L.subrest(p, n, el.et, J): return False r = int(n) for _ in bigrange.range(1, el.t.integer): r = (r*n) % el.et.integer if n % r == 0 and r != 1 and r != n: _log.info("%s divides %s.\n" %(r, n)) return False return True
def apr(n): """ apr is the main function for Adleman-Pomerance-Rumery primality test. Assuming n has no prime factors less than 32. Assuming n is spsp for several bases. """ L = Status() rb = arith1.floorsqrt(n) + 1 el = TestPrime() while el.et <= rb: el = next(el) plist = list(el.t.factors.keys()) plist.remove(2) L.yet(2) for p in plist: if pow(n, p - 1, p * p) != 1: L.done(p) else: L.yet(p) qlist = list(el.et.factors.keys()) qlist.remove(2) J = JacobiSum() for q in qlist: for p in plist: if (q - 1) % p != 0: continue if not L.subodd(p, q, n, J): return False k = arith1.vp(q - 1, 2)[0] if k == 1: if not L.sub2(q, n): return False elif k == 2: if not L.sub4(q, n, J): return False else: if not L.sub8(q, k, n, J): return False for p in L.yet_keys(): if not L.subrest(p, n, el.et, J): return False r = int(n) for _ in bigrange.range(1, el.t.integer): r = (r * n) % el.et.integer if n % r == 0 and r != 1 and r != n: _log.info("%s divides %s.\n" % (r, n)) return False return True
def babyspcv(bounds, sossp, sogsp, utwi, nt, disc, classnum): """ Compute small steps """ mstp1 = bounds[1] - bounds[0] if (mstp1 == 0) or (mstp1 == 1): q = 1 else: tppm = misc.primePowerTest(mstp1) q = arith1.floorsqrt(mstp1) if (tppm[1] == 0) or (tppm[1] % 2): q += 1 n_should_be_set = True # initialize c_s1 = ClassGroup(disc, classnum, []) # a subset of G # extracting i = 0 case of main loop for ttr in sossp.retel(): tmpx = ttr tmpx.s_parent = ttr # tmpx belongs ttr in the set of smallstep # index of the element tmpx.ind = 0 c_s1.insttree(tmpx) # main loop x_i = nt for i in range(1, q): for ttr in sossp.retel(): tmpx = x_i * ttr tmpx.s_parent = ttr # tmpx belongs ttr in the set of smallstep if n_should_be_set and tmpx == utwi: n = i tmp_ss = tmpx.s_parent tmp_gs = utwi n_should_be_set = False # index of the element tmpx.ind = i c_s1.insttree(tmpx) x_i = nt * x_i assert x_i == nt ** q if n_should_be_set: sz = nt ** bounds[0] n, tmp_ss, tmp_gs = giantspcv(q, sz, x_i, c_s1, bounds, sogsp) return ordercv(n, sossp, sogsp, nt, disc, classnum, tmp_ss, tmp_gs)
def _parse_seq(self, options): """ Parse 'options' to define trial sequaence. """ if 'start' in options and 'stop' in options: if 'step' in options: trials = bigrange.range(options['start'], options['stop'], options['step']) else: trials = bigrange.range(options['start'], options['stop']) elif 'iterator' in options: trials = options['iterator'] elif 'eratosthenes' in options: trials = prime.generator_eratosthenes(options['eratosthenes']) elif options['n'] < 1000000: trials = prime.generator_eratosthenes(arith1.floorsqrt(options['n'])) else: trials = prime.generator() return trials
def cornacchia_smith(p, d): ''' modified Cornacchia's Algorithm to solve a^2 + b^2 |D| = 4p for a and b Args: p: d: Returns: a, b such that a^2 + b^2 |D| = 4p ''' # check input if not -4 * p < d < 0: raise ValueError(" -4p < D < 0 not true.") elif not (d % 4 in {0, 1}): raise ValueError(" D = 0, 1 (mod 4) not true.") # case where p=2 if p == 2: r = sqrt(d + 8) if r != -1: return r, 1 else: return None # test for solvability if jacobi(d % p, p) < 1: return None x = modsqrt(d, p) if (x % 2) != (d % 2): x = p - x # euclid chain a, b = (2 * p, x) c = floorsqrt(4 * p) while b > c: a, b = b, a % b t = 4 * p - b * b if t % (-d) != 0: return None if not issquare(t / (-d)): return None return b, int(mpmath.sqrt(t / -d))
def _parse_seq(self, options): """ Parse 'options' to define trial sequaence. """ if 'start' in options and 'stop' in options: if 'step' in options: trials = bigrange.range(options['start'], options['stop'], options['step']) else: trials = bigrange.range(options['start'], options['stop']) elif 'iterator' in options: trials = options['iterator'] elif 'eratosthenes' in options: trials = prime.generator_eratosthenes(options['eratosthenes']) elif options['n'] < 1000000: trials = prime.generator_eratosthenes( arith1.floorsqrt(options['n'])) else: trials = prime.generator() return trials
def mpqsfind(n, s=0, f=0, m=0, verbose=False): """ This is main function of MPQS. Arguments are (composite_number, sieve_range, factorbase_size, multiplier) You must input composite_number at least. """ # verbosity if verbose: _log.setLevel(logging.DEBUG) _log.debug("verbose") else: _log.setLevel(logging.NOTSET) starttime = time.time() M = MPQS(n, s, f, m) _log.info("Sieve range is [%d, %d]" % (M.move_range[0], M.move_range[-1])) _log.info("Factorbase size = %d, Max Factorbase %d" % (len(M.FB), M.maxFB)) M.get_vector() N = M.number // M.multiplier V = Elimination(M.smooth) A = V.gaussian() _log.info("Found %d linearly dependent relations" % len(A)) differences = [] for i in A: B = V.history[i].keys() X = 1 Y = 1 for j in B: X *= M.smooth[j][1][0] Y *= M.smooth[j][1][1] Y = Y % M.number X = arith1.floorsqrt(X) % M.number if X != Y: differences.append(X-Y) for diff in differences: divisor = gcd.gcd(diff, N) if 1 < divisor < N: _log.info("Total time = %f sec" % (time.time() - starttime)) return divisor
def upper_bound_of_coefficient(f): """ upper_bound_of_coefficient(polynomial) -> int Compute Landau-Mignotte bound of coefficients of factors, whose degree is no greater than half of the given polynomial. The given polynomial must have integer coefficients. """ weight = 0 for c in f.itercoefficients(): weight += abs(c)**2 weight = arith1.floorsqrt(weight) + 1 degree = f.degree() lc = f[degree] m = degree // 2 + 1 bound = 1 for i in range(1, m): b = combinatorial.binomial(m - 1, i) * weight + \ combinatorial.binomial(m - 1, i - 1) * lc if bound < b: bound = b return bound
def testFloorpowerroot(self): self.assertEqual(0, arith1.floorpowerroot(0, 1)) self.assertEqual(0, arith1.floorpowerroot(0, 4)) self.assertEqual(0, arith1.floorpowerroot(0, 7)) self.assertEqual(1, arith1.floorpowerroot(1, 2)) self.assertEqual(1, arith1.floorpowerroot(1, 6)) self.assertEqual(1, arith1.floorpowerroot(1, 9)) self.assertEqual(1, arith1.floorpowerroot(2, 3)) self.assertEqual(1, arith1.floorpowerroot(2, 7)) self.assertEqual(2, arith1.floorpowerroot(8, 3)) self.assertEqual(2, arith1.floorpowerroot(128, 7)) self.assertEqual((5, 5), arith1.floorpowerroot(5, 1, True)) self.assertEqual((5, 25), arith1.floorpowerroot(27, 2, True)) self.assertEqual((0, 0), arith1.floorpowerroot(0, 7, True)) self.assertEqual((3, 243), arith1.floorpowerroot(245, 5, True)) self.assertEqual((-3, -243), arith1.floorpowerroot(-245, 5, True)) for j in range(3, 100, 10): k = 5**j self.assertEqual(4, arith1.floorpowerroot(k - 1, j)) self.assertEqual(5, arith1.floorpowerroot(k, j)) self.assertEqual(5, arith1.floorpowerroot(k + 1, j)) self.assertEqual(arith1.floorpowerroot(400000000000000000000, 4), arith1.floorsqrt(20000000000))
def trialDivision(n, **options): """ Return a factor of given integer by trial division. options can be either: 1) 'start' and 'stop' as range parameters. 2) 'iterator' as an iterator of primes. If both options are not given, prime factor is searched from 2 to the square root of the given integer. """ # verbosity verbose = options.get('verbose', False) if not verbose: _silence() if 'start' in options and 'stop' in options: if 'step' in options: trials = range(options['start'], options['stop'], options['step']) else: trials = range(options['start'], options['stop']) elif 'iterator' in options: trials = options['iterator'] elif n < 1000000: trials = prime.generator_eratosthenes(arith1.floorsqrt(n)) else: trials = prime.generator() for p in trials: if not (n % p): if not verbose: _verbose() return p if p ** 2 > n: break if not verbose: _verbose() return 1
def _calc_bound(n, bound=0): if bound: m = min((bound, arith1.floorsqrt(n))) else: m = arith1.floorsqrt(n) return m