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 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 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 _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.issquare(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 testIssquare(self): self.assertTrue(arith1.issquare(1)) self.assertEqual(1, arith1.issquare(1)) self.assertTrue(arith1.issquare(289)) self.assertEqual(17, arith1.issquare(289)) self.assertFalse(arith1.issquare(2)) self.assertEqual(0, arith1.issquare(2)) self.assertFalse(arith1.issquare(0)) self.assertEqual(0, arith1.issquare(0))
def trivial_test(n): """ Test whether n is squarefree or not. This method do anything but factorization. """ if n == 1 or n == 2: return True if arith1.issquare(n): return False if n & 1: return lenstra(n) elif not (n & 3): return False raise Undetermined("trivial test can't determine squarefreeness")
def trivial_test(n): """ Test whether n is squarefree or not. This method do anything but factorization. """ if n == 1 or n == 2: return True if arith1.issquare(n): return False if n & 1: return lenstra(n) elif not (n % 4): return False raise Undetermined("trivial test can't determine squarefreeness")
def trivial_test_ternary(n): """ Test the squarefreeness of n. The return value is one of the ternary logical constants. The method uses a series of trivial tests. """ if n == 1 or n == 2: return True if arith1.issquare(n): return False if n & 1: return lenstra_ternary(n) elif not (n & 3): return False return None
def gen_discriminant(start=0): # really should consider generating list of discriminants # find a fundamental discriminant. Use start as a starting point. d = start # compute the odd part d_found = False while not d_found: '''find the next fundamental discriminant''' d -= 1 odd = odd_part(-d) # check if the odd part is square free. if issquare(odd) not in {0, 1}: continue if not ((-d) % 16 in {3, 4, 7, 8, 11, 15}): continue return d
def next_disc(d, absbound): """ Return fundamental discriminant D, such that D < d. If there is no D with |d| < |D| < absbound, return False """ # -disc % 16 negdisc_mod16 = (3, 4, 7, 8, 11, 15) for negdisc in bigrange.range(-d + 1, absbound): if negdisc & 15 not in negdisc_mod16: continue if negdisc & 1 and not squarefree.trial_division(negdisc): continue if arith1.issquare(negdisc): continue return -negdisc return False
def next_disc(d, absbound): """ Return fundamental discriminant D, such that D < d. If there is no D with |d| < |D| < absbound, return False """ # -disc % 16 negdisc_mod16 = (3, 4, 7, 8, 11, 15) for negdisc in bigrange.range(-d + 1, absbound): if negdisc % 16 not in negdisc_mod16: continue if negdisc % 2 == 1 and not squarefree.trial_division(negdisc): continue if arith1.issquare(negdisc): continue return -negdisc return False
def trivial_test_ternary(n): """ Test the squarefreeness of n. The return value is one of the ternary logical constants. The method uses a series of trivial tests. """ if n == 1 or n == 2: return True if arith1.issquare(n): return False if n & 1: return lenstra_ternary(n) elif not (n % 4): return False return None
def generate(self, target, **options): """ Generate squarefree factors of the target number with their valuations. The method may terminate with yielding (1, 1) to indicate the factorization is incomplete. If a keyword option 'strict' is False (default to True), factorization will stop after the first square factor no matter whether it is squarefree or not. """ strict = options.get('strict', True) options['n'] = target primeseq = self._parse_seq(options) for p in primeseq: if not (target % p): e, target = arith1.vp(target, p) yield p, e if target == 1: break elif e > 1 and not strict: yield 1, 1 break elif trivial_test_ternary(target): # the factor remained is squarefree. yield target, 1 break q, e = factor_misc.primePowerTest(target) if e: yield q, e break sqrt = arith1.issquare(target) if sqrt: if strict: for q, e in self.factor(sqrt, iterator=primeseq): yield q, 2 * e else: yield sqrt, 2 break if p ** 3 > target: # there are no more square factors of target, # thus target is squarefree yield target, 1 break else: # primeseq is exhausted but target has not been proven prime yield 1, 1
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))