def is_quad_residue(a, p): """ Returns True if ``a`` (mod ``p``) is in the set of squares mod ``p``, i.e a % p in set([i**2 % p for i in range(p)]). If ``p`` is an odd prime, an iterative method is used to make the determination: >>> from sympy.ntheory import is_quad_residue >>> sorted(set([i**2 % 7 for i in range(7)])) [0, 1, 2, 4] >>> [j for j in range(7) if is_quad_residue(j, 7)] [0, 1, 2, 4] See Also ======== legendre_symbol, jacobi_symbol """ a, p = as_int(a), as_int(p) if p < 1: raise ValueError('p must be > 0') if a >= p or a < 0: a = a % p if a < 2 or p < 3: return True if not isprime(p): if p % 2 and jacobi_symbol(a, p) == -1: return False r = sqrt_mod(a, p) if r is None: return False else: return True return pow(a, (p - 1) // 2, p) == 1
def multinomial_coefficients_iterator(m, n, _tuple=tuple): """multinomial coefficient iterator This routine has been optimized for `m` large with respect to `n` by taking advantage of the fact that when the monomial tuples `t` are stripped of zeros, their coefficient is the same as that of the monomial tuples from ``multinomial_coefficients(n, n)``. Therefore, the latter coefficients are precomputed to save memory and time. >>> from sympy.ntheory.multinomial import multinomial_coefficients >>> m53, m33 = multinomial_coefficients(5,3), multinomial_coefficients(3,3) >>> m53[(0,0,0,1,2)] == m53[(0,0,1,0,2)] == m53[(1,0,2,0,0)] == m33[(0,1,2)] True Examples ======== >>> from sympy.ntheory.multinomial import multinomial_coefficients_iterator >>> it = multinomial_coefficients_iterator(20,3) >>> next(it) ((3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 1) """ m = as_int(m) n = as_int(n) if m < 2 * n or n == 1: mc = multinomial_coefficients(m, n) yield from mc.items() else: mc = multinomial_coefficients(n, n) mc1 = {} for k, v in mc.items(): mc1[_tuple(filter(None, k))] = v mc = mc1 t = [n] + [0] * (m - 1) t1 = _tuple(t) b = _tuple(filter(None, t1)) yield (t1, mc[b]) if n: j = 0 # j will be the leftmost nonzero position else: j = m # enumerate tuples in co-lex order while j < m - 1: # compute next tuple tj = t[j] if j: t[j] = 0 t[0] = tj if tj > 1: t[j + 1] += 1 j = 0 else: j += 1 t[j] += 1 t[0] -= 1 t1 = _tuple(t) b = _tuple(filter(None, t1)) yield (t1, mc[b])
def is_nthpow_residue(a, n, m): """ Returns True if ``x**n == a (mod m)`` has solutions. References ========== .. [1] P. Hackman "Elementary Number Theory" (2009), page 76 """ a = a % m a, n, m = as_int(a), as_int(n), as_int(m) if m <= 0: raise ValueError('m must be > 0') if n < 0: raise ValueError('n must be >= 0') if n == 0: if m == 1: return False return a == 1 if a == 0: return True if n == 1: return True if n == 2: return is_quad_residue(a, m) return _is_nthpow_residue_bign(a, n, m)
def is_primitive_root(a, p): """ Returns True if ``a`` is a primitive root of ``p`` ``a`` is said to be the primitive root of ``p`` if gcd(a, p) == 1 and totient(p) is the smallest positive number s.t. a**totient(p) cong 1 mod(p) Examples ======== >>> from sympy.ntheory import is_primitive_root, n_order, totient >>> is_primitive_root(3, 10) True >>> is_primitive_root(9, 10) False >>> n_order(3, 10) == totient(10) True >>> n_order(9, 10) == totient(10) False """ a, p = as_int(a), as_int(p) if igcd(a, p) != 1: raise ValueError("The two numbers should be relatively prime") if a > p: a = a % p return n_order(a, p) == totient(p)
def search(self, n): """Return the indices i, j of the primes that bound n. If n is prime then i == j. Although n can be an expression, if ceiling cannot convert it to an integer then an n error will be raised. Examples ======== >>> from sympy import sieve >>> sieve.search(25) (9, 10) >>> sieve.search(23) (9, 9) """ from sympy.functions.elementary.integers import ceiling # wrapping ceiling in as_int will raise an error if there was a problem # determining whether the expression was exactly an integer or not test = as_int(ceiling(n)) n = as_int(n) if n < 2: raise ValueError("n should be >= 2 but got: %s" % n) if n > self._list[-1]: self.extend(n) b = bisect(self._list, n) if self._list[b - 1] == test: return b, b else: return b, b + 1
def _number_theoretic_transform(seq, prime, inverse=False): """Utility function for the Number Theoretic Transform""" if not iterable(seq): raise TypeError("Expected a sequence of integer coefficients " "for Number Theoretic Transform") p = as_int(prime) if not isprime(p): raise ValueError("Expected prime modulus for " "Number Theoretic Transform") a = [as_int(x) % p for x in seq] n = len(a) if n < 1: return a b = n.bit_length() - 1 if n&(n - 1): b += 1 n = 2**b if (p - 1) % n: raise ValueError("Expected prime modulus of the form (m*2**k + 1)") a += [0]*(n - len(a)) for i in range(1, n): j = int(ibin(i, b, str=True)[::-1], 2) if i < j: a[i], a[j] = a[j], a[i] pr = primitive_root(p) rt = pow(pr, (p - 1) // n, p) if inverse: rt = pow(rt, p - 2, p) w = [1]*(n // 2) for i in range(1, n // 2): w[i] = w[i - 1]*rt % p h = 2 while h <= n: hf, ut = h // 2, n // h for i in range(0, n, h): for j in range(hf): u, v = a[i + j], a[i + j + hf]*w[ut * j] a[i + j], a[i + j + hf] = (u + v) % p, (u - v) % p h *= 2 if inverse: rv = pow(n, p - 2, p) a = [x*rv % p for x in a] return a
def sqrt_mod_iter(a, p, domain=int): """ Iterate over solutions to ``x**2 = a mod p`` Parameters ========== a : integer p : positive integer domain : integer domain, ``int``, ``ZZ`` or ``Integer`` Examples ======== >>> from sympy.ntheory.residue_ntheory import sqrt_mod_iter >>> list(sqrt_mod_iter(11, 43)) [21, 22] """ from sympy.polys.galoistools import gf_crt1, gf_crt2 a, p = as_int(a), abs(as_int(p)) if isprime(p): a = a % p if a == 0: res = _sqrt_mod1(a, p, 1) else: res = _sqrt_mod_prime_power(a, p, 1) if res: if domain is ZZ: yield from res else: for x in res: yield domain(x) else: f = factorint(p) v = [] pv = [] for px, ex in f.items(): if a % px == 0: rx = _sqrt_mod1(a, px, ex) if not rx: return else: rx = _sqrt_mod_prime_power(a, px, ex) if not rx: return v.append(rx) pv.append(px**ex) mm, e, s = gf_crt1(pv, ZZ) if domain is ZZ: for vx in _product(*v): r = gf_crt2(vx, pv, mm, e, s, ZZ) yield r else: for vx in _product(*v): r = gf_crt2(vx, pv, mm, e, s, ZZ) yield domain(r)
def give(a, b, seq=seed): a, b = as_int(a), as_int(b) w = b - a if w < 0: raise ValueError('_randint got empty range') try: x = seq.pop() except IndexError: raise ValueError('_randint sequence was too short') if a <= x <= b: return x else: return give(a, b, seq)
def give(a, b=None, seq=seed): if b is None: a, b = 0, a a, b = as_int(a), as_int(b) w = b - a if w < 1: raise ValueError('_randrange got empty range') try: x = seq.pop() except IndexError: raise ValueError('_randrange sequence was too short') if a <= x < b: return x else: return give(a, b, seq)
def extend_to_no(self, i): """Extend to include the ith prime number. Parameters ========== i : integer Examples ======== >>> from sympy import sieve >>> sieve._reset() # this line for doctest only >>> sieve.extend_to_no(9) >>> sieve._list array('l', [2, 3, 5, 7, 11, 13, 17, 19, 23]) Notes ===== The list is extended by 50% if it is too short, so it is likely that it will be longer than requested. """ i = as_int(i) while len(self._list) < i: self.extend(int(self._list[-1] * 1.5))
def test_as_int(): raises(ValueError, lambda: as_int(True)) raises(ValueError, lambda: as_int(1.1)) raises(ValueError, lambda: as_int([])) raises(ValueError, lambda: as_int(S.NaN)) raises(ValueError, lambda: as_int(S.Infinity)) raises(ValueError, lambda: as_int(S.NegativeInfinity)) raises(ValueError, lambda: as_int(S.ComplexInfinity)) # for the following, limited precision makes int(arg) == arg # but the int value is not necessarily what a user might have # expected; Q.prime is more nuanced in its response for # expressions which might be complex representations of an # integer. This is not -- by design -- as_ints role. raises(ValueError, lambda: as_int(1e23)) raises(ValueError, lambda: as_int(S('1.' + '0' * 20 + '1'))) assert as_int(True, strict=False) == 1
def search(self, n): """Return the indices i, j of the primes that bound n. If n is prime then i == j. Although n can be an expression, if ceiling cannot convert it to an integer then an n error will be raised. Examples ======== >>> from sympy import sieve >>> sieve.search(25) (9, 10) >>> sieve.search(23) (9, 9) """ test = _as_int_ceiling(n) n = as_int(n) if n < 2: raise ValueError("n should be >= 2 but got: %s" % n) if n > self._list[-1]: self.extend(n) b = bisect(self._list, n) if self._list[b - 1] == test: return b, b else: return b, b + 1
def mobiusrange(self, a, b): """Generate all mobius numbers for the range [a, b). Parameters ========== a : integer First number in range b : integer First number outside of range Examples ======== >>> from sympy import sieve >>> print([i for i in sieve.mobiusrange(7, 18)]) [-1, 0, 0, 1, -1, 0, -1, 1, 1, 0, -1] """ from sympy.functions.elementary.integers import ceiling # wrapping ceiling in as_int will raise an error if there was a problem # determining whether the expression was exactly an integer or not a = max(1, as_int(ceiling(a))) b = as_int(ceiling(b)) n = len(self._mlist) if a >= b: return elif b <= n: for i in range(a, b): yield self._mlist[i] else: self._mlist += _azeros(b - n) for i in range(1, n): mi = self._mlist[i] startindex = (n + i - 1) // i * i for j in range(startindex, b, i): self._mlist[j] -= mi if i >= a: yield mi for i in range(n, b): mi = self._mlist[i] for j in range(2 * i, b, i): self._mlist[j] -= mi if i >= a: yield mi
def primerange(self, a, b=None): """Generate all prime numbers in the range [2, a) or [a, b). Examples ======== >>> from sympy import sieve, prime All primes less than 19: >>> print([i for i in sieve.primerange(19)]) [2, 3, 5, 7, 11, 13, 17] All primes greater than or equal to 7 and less than 19: >>> print([i for i in sieve.primerange(7, 19)]) [7, 11, 13, 17] All primes through the 10th prime >>> list(sieve.primerange(prime(10) + 1)) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] """ from sympy.functions.elementary.integers import ceiling # wrapping ceiling in as_int will raise an error if there was a problem # determining whether the expression was exactly an integer or not if b is None: b = as_int(ceiling(a)) a = 2 else: a = max(2, as_int(ceiling(a))) b = as_int(ceiling(b)) if a >= b: return self.extend(b) i = self.search(a)[1] maxi = len(self._list) + 1 while i < maxi: p = self._list[i - 1] if p < b: yield p i += 1 else: return
def unrank(self, rank, n): """Finds the unranked Prufer sequence. Examples ======== >>> from sympy.combinatorics.prufer import Prufer >>> Prufer.unrank(0, 4) Prufer([0, 0]) """ n, rank = as_int(n), as_int(rank) L = defaultdict(int) for i in range(n - 3, -1, -1): L[i] = rank % n rank = (rank - L[i])//n return Prufer([L[i] for i in range(len(L))])
def __mul__(self, other): try: n = as_int(other) except ValueError: raise TypeError( "Can't multiply sequence by non-integer of type '%s'" % type(other)) return self.func(*(self.args * n))
def discrete_log(n, a, b, order=None, prime_order=None): """ Compute the discrete logarithm of ``a`` to the base ``b`` modulo ``n``. This is a recursive function to reduce the discrete logarithm problem in cyclic groups of composite order to the problem in cyclic groups of prime order. It employs different algorithms depending on the problem (subgroup order size, prime order or not): * Trial multiplication * Baby-step giant-step * Pollard's Rho * Pohlig-Hellman Examples ======== >>> from sympy.ntheory import discrete_log >>> discrete_log(41, 15, 7) 3 References ========== .. [1] http://mathworld.wolfram.com/DiscreteLogarithm.html .. [2] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & Vanstone, S. A. (1997). """ n, a, b = as_int(n), as_int(a), as_int(b) if order is None: order = n_order(b, n) if prime_order is None: prime_order = isprime(order) if order < 1000: return _discrete_log_trial_mul(n, a, b, order) elif prime_order: if order < 1000000000000: return _discrete_log_shanks_steps(n, a, b, order) return _discrete_log_pollard_rho(n, a, b, order) return _discrete_log_pohlig_hellman(n, a, b, order)
def quadratic_congruence(a, b, c, p): """ Find the solutions to ``a x**2 + b x + c = 0 mod p a : integer b : integer c : integer p : positive integer """ from sympy.polys.galoistools import linear_congruence a = as_int(a) b = as_int(b) c = as_int(c) p = as_int(p) a = a % p b = b % p c = c % p if a == 0: return linear_congruence(b, -c, p) if p == 2: roots = [] if c % 2 == 0: roots.append(0) if (a + b + c) % 2 == 0: roots.append(1) return roots if isprime(p): inv_a = mod_inverse(a, p) b *= inv_a c *= inv_a if b % 2 == 1: b = b + p d = ((b * b) // 4 - c) % p y = sqrt_mod(d, p, all_roots=True) res = set() for i in y: res.add((i - b // 2) % p) return sorted(res) y = sqrt_mod(b * b - 4 * a * c, 4 * a * p, all_roots=True) res = set() for i in y: root = linear_congruence(2 * a, i - b, 4 * a * p) for j in root: res.add(j % p) return sorted(res)
def is_strong_lucas_prp(n): """Strong Lucas compositeness test with Selfridge parameters. Returns False if n is definitely composite, and True if n is a strong Lucas probable prime. This is often used in combination with the Miller-Rabin test, and in particular, when combined with M-R base 2 creates the strong BPSW test. References ========== - "Lucas Pseudoprimes", Baillie and Wagstaff, 1980. http://mpqs.free.fr/LucasPseudoprimes.pdf - OEIS A217255: Strong Lucas Pseudoprimes https://oeis.org/A217255 - https://en.wikipedia.org/wiki/Lucas_pseudoprime - https://en.wikipedia.org/wiki/Baillie-PSW_primality_test Examples ======== >>> from sympy.ntheory.primetest import isprime, is_strong_lucas_prp >>> for i in range(20000): ... if is_strong_lucas_prp(i) and not isprime(i): ... print(i) 5459 5777 10877 16109 18971 """ from sympy.ntheory.factor_ import trailing n = as_int(n) if n == 2: return True if n < 2 or (n % 2) == 0: return False if is_square(n, False): return False D, P, Q = _lucas_selfridge_params(n) if D == 0: return False # remove powers of 2 from n+1 (= k * 2**s) s = trailing(n + 1) k = (n + 1) >> s U, V, Qk = _lucas_sequence(n, P, Q, k) if U == 0 or V == 0: return True for r in range(1, s): V = (V * V - 2 * Qk) % n if V == 0: return True Qk = pow(Qk, 2, n) return False
def legendre_symbol(a, p): r""" Returns the Legendre symbol `(a / p)`. For an integer ``a`` and an odd prime ``p``, the Legendre symbol is defined as .. math :: \genfrac(){}{}{a}{p} = \begin{cases} 0 & \text{if } p \text{ divides } a\\ 1 & \text{if } a \text{ is a quadratic residue modulo } p\\ -1 & \text{if } a \text{ is a quadratic nonresidue modulo } p \end{cases} Parameters ========== a : integer p : odd prime Examples ======== >>> from sympy.ntheory import legendre_symbol >>> [legendre_symbol(i, 7) for i in range(7)] [0, 1, 1, -1, 1, -1, -1] >>> sorted(set([i**2 % 7 for i in range(7)])) [0, 1, 2, 4] See Also ======== is_quad_residue, jacobi_symbol """ a, p = as_int(a), as_int(p) if not isprime(p) or p == 2: raise ValueError("p should be an odd prime") a = a % p if not a: return 0 if pow(a, (p - 1) // 2, p) == 1: return 1 return -1
def __contains__(self, n): try: n = as_int(n) assert n >= 2 except (ValueError, AssertionError): return False if n % 2 == 0: return n == 2 a, b = self.search(n) return a == b
def is_gaussian_prime(num): r"""Test if num is a Gaussian prime number. References ========== .. [1] https://oeis.org/wiki/Gaussian_primes """ num = sympify(num) a, b = num.as_real_imag() a = as_int(a, strict=False) b = as_int(b, strict=False) if a == 0: b = abs(b) return isprime(b) and b % 4 == 3 elif b == 0: a = abs(a) return isprime(a) and a % 4 == 3 return isprime(a**2 + b**2)
def pi_hex_digits(n, prec=14): """Returns a string containing ``prec`` (default 14) digits starting at the nth digit of pi in hex. Counting of digits starts at 0 and the decimal is not counted, so for n = 0 the returned value starts with 3; n = 1 corresponds to the first digit past the decimal point (which in hex is 2). Examples ======== >>> from sympy.ntheory.bbp_pi import pi_hex_digits >>> pi_hex_digits(0) '3243f6a8885a30' >>> pi_hex_digits(0, 3) '324' References ========== .. [1] http://www.numberworld.org/digits/Pi/ """ n, prec = as_int(n), as_int(prec) if n < 0: raise ValueError('n cannot be negative') if prec == 0: return '' # main of implementation arrays holding formulae coefficients n -= 1 a = [4, 2, 1, 1] j = [1, 4, 5, 6] #formulae D = _dn(n, prec) x = + (a[0]*_series(j[0], n, prec) - a[1]*_series(j[1], n, prec) - a[2]*_series(j[2], n, prec) - a[3]*_series(j[3], n, prec)) & (16**D - 1) s = ("%0" + "%ix" % prec) % (x // 16**(D - prec)) return s
def n_order(a, n): """Returns the order of ``a`` modulo ``n``. The order of ``a`` modulo ``n`` is the smallest integer ``k`` such that ``a**k`` leaves a remainder of 1 with ``n``. Examples ======== >>> from sympy.ntheory import n_order >>> n_order(3, 7) 6 >>> n_order(4, 7) 3 """ from collections import defaultdict a, n = as_int(a), as_int(n) if igcd(a, n) != 1: raise ValueError("The two numbers should be relatively prime") factors = defaultdict(int) f = factorint(n) for px, kx in f.items(): if kx > 1: factors[px] += kx - 1 fpx = factorint(px - 1) for py, ky in fpx.items(): factors[py] += ky group_order = 1 for px, kx in factors.items(): group_order *= px**kx order = 1 if a > n: a = a % n for p, e in factors.items(): exponent = group_order for f in range(e + 1): if pow(a, exponent, n) != 1: order *= p ** (e - f + 1) break exponent = exponent // p return order
def totientrange(self, a, b): """Generate all totient numbers for the range [a, b). Examples ======== >>> from sympy import sieve >>> print([i for i in sieve.totientrange(7, 18)]) [6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16] """ from sympy.functions.elementary.integers import ceiling # wrapping ceiling in as_int will raise an error if there was a problem # determining whether the expression was exactly an integer or not a = max(1, as_int(ceiling(a))) b = as_int(ceiling(b)) n = len(self._tlist) if a >= b: return elif b <= n: for i in range(a, b): yield self._tlist[i] else: self._tlist += _arange(n, b) for i in range(1, n): ti = self._tlist[i] startindex = (n + i - 1) // i * i for j in range(startindex, b, i): self._tlist[j] -= ti if i >= a: yield ti for i in range(n, b): ti = self._tlist[i] for j in range(2 * i, b, i): self._tlist[j] -= ti if i >= a: yield ti
def is_square(n, prep=True): """Return True if n == a * a for some integer a, else False. If n is suspected of *not* being a square then this is a quick method of confirming that it is not. Examples ======== >>> from sympy.ntheory.primetest import is_square >>> is_square(25) True >>> is_square(2) False References ========== .. [1] http://mersenneforum.org/showpost.php?p=110896 See Also ======== sympy.core.power.integer_nthroot """ if prep: n = as_int(n) if n < 0: return False if n in (0, 1): return True # def magic(n): # s = {x**2 % n for x in range(n)} # return sum(1 << bit for bit in s) # >>> print(hex(magic(128))) # 0x2020212020202130202021202030213 # >>> print(hex(magic(99))) # 0x209060049048220348a410213 # >>> print(hex(magic(91))) # 0x102e403012a0c9862c14213 # >>> print(hex(magic(85))) # 0x121065188e001c46298213 if not 0x2020212020202130202021202030213 & (1 << (n & 127)): return False m = n % (99 * 91 * 85) if not 0x209060049048220348a410213 & (1 << (m % 99)): return False if not 0x102e403012a0c9862c14213 & (1 << (m % 91)): return False if not 0x121065188e001c46298213 & (1 << (m % 85)): return False return integer_nthroot(n, 2)[1]
def __mul__(self, n): n = as_int(n) r = self.point_at_infinity(self._curve) if n == 0: return r if n < 0: return -self * -n p = self while n: if n & 1: r = r + p n >>= 1 p = p + p return r
def quadratic_residues(p) -> list[int]: """ Returns the list of quadratic residues. Examples ======== >>> from sympy.ntheory.residue_ntheory import quadratic_residues >>> quadratic_residues(7) [0, 1, 2, 4] """ p = as_int(p) r = {pow(i, 2, p) for i in range(p // 2 + 1)} return sorted(r)
def sqrt_mod(a, p, all_roots=False): """ Find a root of ``x**2 = a mod p`` Parameters ========== a : integer p : positive integer all_roots : if True the list of roots is returned or None Notes ===== If there is no root it is returned None; else the returned root is less or equal to ``p // 2``; in general is not the smallest one. It is returned ``p // 2`` only if it is the only root. Use ``all_roots`` only when it is expected that all the roots fit in memory; otherwise use ``sqrt_mod_iter``. Examples ======== >>> from sympy.ntheory import sqrt_mod >>> sqrt_mod(11, 43) 21 >>> sqrt_mod(17, 32, True) [7, 9, 23, 25] """ if all_roots: return sorted(list(sqrt_mod_iter(a, p))) try: p = abs(as_int(p)) it = sqrt_mod_iter(a, p) r = next(it) if r > p // 2: return p - r elif r < p // 2: return r else: try: r = next(it) if r > p // 2: return p - r except StopIteration: pass return r except StopIteration: return None
def prevprime(n): """ Return the largest prime smaller than n. Notes ===== Potential primes are located at 6*j +/- 1. This property is used during searching. >>> from sympy import prevprime >>> [(i, prevprime(i)) for i in range(10, 15)] [(10, 7), (11, 7), (12, 11), (13, 11), (14, 13)] See Also ======== nextprime : Return the ith prime greater than n primerange : Generates all primes in a given range """ from sympy.functions.elementary.integers import ceiling # wrapping ceiling in as_int will raise an error if there was a problem # determining whether the expression was exactly an integer or not n = as_int(ceiling(n)) if n < 3: raise ValueError("no preceding primes") if n < 8: return {3: 2, 4: 3, 5: 3, 6: 5, 7: 5}[n] if n <= sieve._list[-1]: l, u = sieve.search(n) if l == u: return sieve[l - 1] else: return sieve[l] nn = 6 * (n // 6) if n - nn <= 1: n = nn - 1 if isprime(n): return n n -= 4 else: n = nn + 1 while 1: if isprime(n): return n n -= 2 if isprime(n): return n n -= 4