def __new__(cls, partition, integer=None): """ Generates a new IntegerPartition object from a list or dictionary. The partition can be given as a list of positive integers or a dictionary of (integer, multiplicity) items. If the partition is preceeded by an integer an error will be raised if the partition does not sum to that given integer. Examples ======== >>> from sympy.combinatorics.partitions import IntegerPartition >>> a = IntegerPartition([5, 4, 3, 1, 1]) >>> a IntegerPartition(14, (5, 4, 3, 1, 1)) >>> print a [5, 4, 3, 1, 1] >>> IntegerPartition({1:3, 2:1}) IntegerPartition(5, (2, 1, 1, 1)) If the value that the partion should sum to is given first, a check will be made to see n error will be raised if there is a discrepancy: >>> IntegerPartition(10, [5, 4, 3, 1]) Traceback (most recent call last): ... ValueError: The partition is not valid """ from sympy.ntheory.residue_ntheory import int_tested if integer is not None: integer, partition = partition, integer if isinstance(partition, (dict, Dict)): _ = [] for k, v in sorted(partition.items(), reverse=True): if not v: continue k, v = int_tested(k, v) _.extend([k] * v) partition = tuple(_) else: partition = tuple(sorted(int_tested(partition), reverse=True)) sum_ok = False if integer is None: integer = sum(partition) sum_ok = True else: integer = int_tested(integer) if not sum_ok and sum(partition) != integer: raise ValueError("Partition did not add to %s" % integer) if any(i < 1 for i in partition): raise ValueError("The summands must all be positive.") obj = Basic.__new__(cls, integer, partition) obj.partition = list(partition) obj.integer = integer return obj
def __new__(cls, partition, integer=None): """ Generates a new IntegerPartition object from a list or dictionary. The partition can be given as a list of positive integers or a dictionary of (integer, multiplicity) items. If the partition is preceeded by an integer an error will be raised if the partition does not sum to that given integer. Examples ======== >>> from sympy.combinatorics.partitions import IntegerPartition >>> a = IntegerPartition([5, 4, 3, 1, 1]) >>> a IntegerPartition(14, (5, 4, 3, 1, 1)) >>> print a [5, 4, 3, 1, 1] >>> IntegerPartition({1:3, 2:1}) IntegerPartition(5, (2, 1, 1, 1)) If the value that the partion should sum to is given first, a check will be made to see n error will be raised if there is a discrepancy: >>> IntegerPartition(10, [5, 4, 3, 1]) Traceback (most recent call last): ... ValueError: The partition is not valid """ from sympy.ntheory.residue_ntheory import int_tested if integer is not None: integer, partition = partition, integer if isinstance(partition, (dict, Dict)): _ = [] for k, v in sorted(partition.items(), reverse=True): if not v: continue k, v = int_tested(k, v) _.extend([k]*v) partition = tuple(_) else: partition = tuple(sorted(int_tested(partition), reverse=True)) sum_ok = False if integer is None: integer = sum(partition) sum_ok = True else: integer = int_tested(integer) if not sum_ok and sum(partition) != integer: raise ValueError("Partition did not add to %s" % integer) if any(i < 1 for i in partition): raise ValueError("The summands must all be positive.") obj = Basic.__new__(cls, integer, partition) obj.partition = list(partition) obj.integer = integer return obj
def prevprime(n): """ Return the largest prime smaller than n. Potential primes are located at 6*j +/- 1. >>> 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 """ n = int_tested(n, strict=False) if n < 3: raise ValueError("no preceding primes") if n < 8: return {3: 2, 4: 3, 5: 3, 6: 5, 7: 5}[n] 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
def real_root(arg, n=None): """Return the real nth-root of arg if possible. If n is omitted then all instances of -1**(1/odd) will be changed to -1. Examples ======== >>> from sympy import root, real_root, Rational >>> from sympy.abc import x, n >>> real_root(-8, 3) -2 >>> root(-8, 3) 2*(-1)**(1/3) >>> real_root(_) -2 See Also ======== sympy.polys.rootoftools.RootOf sympy.core.power.integer_nthroot root, sqrt """ if n is not None: n = int_tested(n) rv = C.Pow(arg, Rational(1, n)) if n % 2 == 0: return rv else: rv = sympify(arg) n1pow = Transform( lambda x: S.NegativeOne, lambda x: x.is_Pow and x.base is S.NegativeOne and x.exp.is_Rational and x.exp.p == 1 and x.exp.q % 2) return rv.xreplace(n1pow)
def primepi(n): """ Return the value of the prime counting function pi(n) = the number of prime numbers less than or equal to n. The number n need not necessarily be an integer. Examples ======== >>> from sympy import primepi >>> primepi(25) 9 See Also ======== sympy.ntheory.primetest.isprime : Test if n is prime primerange : Generate all primes in a given range prime : Return the nth prime """ n = int_tested(n, strict=False) if n < 2: return 0 else: n = int(n) return sieve.search(n)[0]
def prime(nth): """ Return the nth prime, with the primes indexed as prime(1) = 2, prime(2) = 3, etc.... The nth prime is approximately n*log(n) and can never be larger than 2**n. References ========== - http://primes.utm.edu/glossary/xpage/BertrandsPostulate.html Examples ======== >>> from sympy import prime >>> prime(10) 29 >>> prime(1) 2 See Also ======== sympy.ntheory.primetest.isprime : Test if n is prime primerange : Generate all primes in a given range primepi : Return the number of primes less than or equal to n """ n = int_tested(nth) if n < 1: raise ValueError("nth must be a positive integer; prime(1) == 2") return sieve[n]
def prevprime(n): """ Return the largest prime smaller than n. Potential primes are located at 6*j +/- 1. >>> 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 """ n = int_tested(n, strict=False) if n < 3: raise ValueError("no preceding primes") if n < 8: return {3: 2, 4: 3, 5: 3, 6: 5, 7: 5}[n] 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
def real_root(arg, n=None): """Return the real nth-root of arg if possible. If n is omitted then all instances of -1**(1/odd) will be changed to -1. Examples ======== >>> from sympy import root, real_root, Rational >>> from sympy.abc import x, n >>> real_root(-8, 3) -2 >>> root(-8, 3) 2*(-1)**(1/3) >>> real_root(_) -2 See Also ======== L{sqrt}, L{RootOf}, L{root}, L{integer_nthroot} """ if n is not None: n = int_tested(n) rv = C.Pow(arg, Rational(1, n)) if n % 2 == 0: return rv else: rv = sympify(arg) n1pow = Transform( lambda x: S.NegativeOne, lambda x: x.is_Pow and x.base is S.NegativeOne and x.exp.is_Rational and x.exp.p == 1 and x.exp.q % 2 ) return rv.xreplace(n1pow)
def nextprime(n, ith=1): """ Return the ith prime greater than n. i must be an integer. Notes ===== Potential primes are located at 6*j +/- 1. This property is used during searching. >>> from sympy import nextprime >>> [(i, nextprime(i)) for i in range(10, 15)] [(10, 11), (11, 13), (12, 13), (13, 17), (14, 17)] >>> nextprime(2, ith=2) # the 2nd prime after 2 5 See Also ======== prevprime : Return the largest prime smaller than n primerange : Generate all primes in a given range """ n = int(n) i = int_tested(ith) if i > 1: pr = n j = 1 while 1: pr = nextprime(pr) j += 1 if j > i: break return pr if n < 2: return 2 if n < 7: return {2: 3, 3: 5, 4: 5, 5: 7, 6: 7}[n] nn = 6 * (n // 6) if nn == n: n += 1 if isprime(n): return n n += 4 elif n - nn == 5: n += 2 if isprime(n): return n n += 4 else: n = nn + 5 while 1: if isprime(n): return n n += 2 if isprime(n): return n n += 4
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 = int_tested(n) rank = int_tested(rank) L = defaultdict(int) for i in xrange(n - 3, -1, -1): L[i] = rank % n rank = (rank - L[i]) // n return Prufer([L[i] for i in xrange(len(L))])
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 = int_tested(n) rank = int_tested(rank) L = defaultdict(int) for i in xrange(n - 3, -1, -1): L[i] = rank % n rank = (rank - L[i])//n return Prufer([L[i] for i in xrange(len(L))])
def __contains__(self, n): try: n = int_tested(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 extend_to_no(self, n): """Extend to include (at least) the nth prime numbers Examples ======== >>> from sympy import sieve >>> sieve.extend_to_no(9) >>> sieve[10] == 29 True """ n = int_tested(n, strict=False) while len(self._list) < n: self.extend(int(self._list[-1] * 1.5))
def give(a, b, seq=seed): from sympy.ntheory.residue_ntheory import int_tested a, b = int_tested(a, b) w = b - a if w < 0: raise ValueError('_randint got empty range') try: x = seq.pop() except AttributeError: raise ValueError('_randint expects a list-like sequence') except IndexError: raise ValueError('_randint sequence was too short') if a <= x <= b: return x else: return give(a, b, seq)
def primorial(n, nth=True): """ Returns the product of either 1. the first n primes (default) or 2. the primes less than or equal to n (when ``nth=False``). >>> from sympy.ntheory.generate import primorial, randprime, primerange >>> from sympy import factorint, Mul, primefactors >>> primorial(4) # the first 4 primes are 2, 3, 5, 7 210 >>> primorial(4, nth=0) # primes <= 4 are 2 and 3 6 >>> primorial(1) 2 >>> primorial(1, nth=0) 1 One can argue that the primes are infinite since if you take a set of primes and multiply them together (e.g. the primorial) and then add or subtract 1, the result cannot be divided by any of the original factors, hence either 1 or more primes must divide this product of primes. >>> factorint(primorial(4) + 1) {211: 1} >>> factorint(primorial(4) - 1) {11: 1, 19: 1} >>> p = list(primerange(10, 20)) >>> sorted(set(primefactors(Mul(*p) + 1)).difference(set(p))) [2, 5, 31, 149] See Also ======== primerange : Generate all primes in a given range """ n = int_tested(n, strict=False) if n < 1: raise ValueError("primorial argument must be >= 1") p = 1 if nth: for i in range(1, n + 1): p *= prime(i) else: for i in primerange(2, n + 1): p *= i return p
def __new__(cls, *args): # expand range slc = slice(*args) start, stop, step = slc.start or 0, slc.stop, slc.step or 1 try: start, stop, step = [S(int_tested(w)) for w in (start, stop, step)] except ValueError: raise ValueError("Inputs to Range must be Integer Valued\n"+ "Use TransformationSets of Ranges for other cases") n = ceiling((stop - start)/step) if n <= 0: return S.EmptySet # normalize args: regardless of how they are entered they will show # canonically as Range(inf, sup, step) with step > 0 start, stop = sorted((start, start + (n - 1)*step)) step = abs(step) return Basic.__new__(cls, start, stop + step, step)
def __new__(cls, *args): # expand range slc = slice(*args) start, stop, step = slc.start or 0, slc.stop, slc.step or 1 try: start, stop, step = [S(int_tested(w)) for w in (start, stop, step)] except ValueError: raise ValueError( "Inputs to Range must be Integer Valued\n" + "Use TransformationSets of Ranges for other cases") n = ceiling((stop - start) / step) if n <= 0: return S.EmptySet # normalize args: regardless of how they are entered they will show # canonically as Range(inf, sup, step) with step > 0 start, stop = sorted((start, start + (n - 1) * step)) step = abs(step) return Basic.__new__(cls, start, stop + step, step)
def __add__(self, other): """ Return permutation whose rank is ``other`` greater than current rank, (mod the maximum rank for the set). Examples ======== >>> from sympy.combinatorics.partitions import Partition >>> a = Partition([[1, 2], [3]]) >>> a.rank 1 >>> (a + 1).rank 2 >>> (a + 100).rank 1 """ other = int_tested(other) offset = self.rank + other result = RGS_unrank((offset) % RGS_enum(self.size), self.size) return Partition.from_rgs(result, self.members)
def search(self, n): """For n >= 2, return the tightest a, b such that self[a] <= n <= self[b] Examples ======== >>> from sympy import sieve >>> sieve.search(25) (9, 10) """ n = int_tested(n, strict=False) if n < 2: raise ValueError("n must be greater than 1") if n > self._list[-1]: self.extend(n) b = bisect(self._list, n) if self._list[b-1] == n: return b, b else: return b, b+1
def search(self, n): """For n >= 2, return the tightest a, b such that self[a] <= n <= self[b] Examples ======== >>> from sympy import sieve >>> sieve.search(25) (9, 10) """ n = int_tested(n, strict=False) if n < 2: raise ValueError("n must be greater than 1") if n > self._list[-1]: self.extend(n) b = bisect(self._list, n) if self._list[b - 1] == n: return b, b else: return b, b + 1
def extend_to_no(self, i): """Extend to include the ith prime number. i must be an integer. The list is extended by 50% if it is too short, so it is likely that it will be longer than requested. Examples ======== >>> from sympy import sieve >>> from array import array # this line and next for doctest only >>> sieve._list = array('l', [2, 3, 5, 7, 11, 13]) >>> sieve.extend_to_no(9) >>> sieve._list array('l', [2, 3, 5, 7, 11, 13, 17, 19, 23]) """ i = int_tested(i) while len(self._list) < i: self.extend(int(self._list[-1] * 1.5))
def random_integer_partition(n, seed=None): """ Generates a random integer partition summing to ``n`` as a list of reverse-sorted integers. Examples ======== >>> from sympy.combinatorics.partitions import random_integer_partition For the following, a seed is given so a known value can be shown; in practice, the seed would not be given. >>> random_integer_partition(100, seed=[1, 1, 12, 1, 2, 1, 85, 1]) [85, 12, 2, 1] >>> random_integer_partition(10, seed=[1, 2, 3, 1, 5, 1]) [5, 3, 1, 1] >>> random_integer_partition(1) [1] """ from sympy.utilities.randtest import _randint n = int_tested(n) if n < 1: raise ValueError('n must be a positive integer') randint = _randint(seed) partition = [] while (n > 0): k = randint(1, n) mult = randint(1, n // k) partition.append((k, mult)) n -= k * mult partition.sort(reverse=True) partition = flatten([[k] * m for k, m in partition]) return partition
def random_integer_partition(n, seed=None): """ Generates a random integer partition summing to ``n`` as a list of reverse-sorted integers. Examples ======== >>> from sympy.combinatorics.partitions import random_integer_partition For the following, a seed is given so a known value can be shown; in practice, the seed would not be given. >>> random_integer_partition(100, seed=[1, 1, 12, 1, 2, 1, 85, 1]) [85, 12, 2, 1] >>> random_integer_partition(10, seed=[1, 2, 3, 1, 5, 1]) [5, 3, 1, 1] >>> random_integer_partition(1) [1] """ from sympy.utilities.randtest import _randint n = int_tested(n) if n < 1: raise ValueError('n must be a positive integer') randint = _randint(seed) partition = [] while (n > 0): k = randint(1, n) mult = randint(1, n//k) partition.append((k, mult)) n -= k*mult partition.sort(reverse=True) partition = flatten([[k]*m for k, m in partition]) return partition
def partitions(n, m=None, k=None): """Generate all partitions of integer n (>= 0). 'm' limits the number of parts in the partition, e.g. if m=2 then partitions will contain no more than 2 numbers, while 'k' limits the numbers which may appear in the partition, e.g. k=2 will return partitions with no element greater than 2. Each partition is represented as a dictionary, mapping an integer to the number of copies of that integer in the partition. For example, the first partition of 4 returned is {4: 1}: a single 4. >>> from sympy.utilities.iterables import partitions Maximum key (number in partition) limited with k (in this case, 2): >>> for p in partitions(6, k=2): ... print p {2: 3} {1: 2, 2: 2} {1: 4, 2: 1} {1: 6} Maximum number of parts in partion limited with m (in this case, 2): >>> for p in partitions(6, m=2): ... print p ... {6: 1} {1: 1, 5: 1} {2: 1, 4: 1} {3: 2} Note that the _same_ dictionary object is returned each time. This is for speed: generating each partition goes quickly, taking constant time independent of n. >>> [p for p in partitions(6, k=2)] [{1: 6}, {1: 6}, {1: 6}, {1: 6}] If you want to build a list of the returned dictionaries then make a copy of them: >>> [p.copy() for p in partitions(6, k=2)] [{2: 3}, {1: 2, 2: 2}, {1: 4, 2: 1}, {1: 6}] Reference: modified from Tim Peter's version to allow for k and m values: code.activestate.com/recipes/218332-generator-for-integer-partitions/ See Also ======== sympy.combinatorics.partitions.Partition sympy.combinatorics.partitions.IntegerPartition """ from sympy.ntheory.residue_ntheory import int_tested if n < 0: raise ValueError("n must be >= 0") if m == 0: raise ValueError("m must be > 0") m = min(m or n, n) if m < 1: raise ValueError("maximum numbers in partition, m, must be > 0") k = min(k or n, n) if k < 1: raise ValueError("maximum value in partition, k, must be > 0") if m * k < n: return n, m, k = int_tested(n, m, k) q, r = divmod(n, k) ms = {k: q} keys = [k] # ms.keys(), from largest to smallest if r: ms[r] = 1 keys.append(r) room = m - q - bool(r) yield ms while keys != [1]: # Reuse any 1's. if keys[-1] == 1: del keys[-1] reuse = ms.pop(1) room += reuse else: reuse = 0 while 1: # Let i be the smallest key larger than 1. Reuse one # instance of i. i = keys[-1] newcount = ms[i] = ms[i] - 1 reuse += i if newcount == 0: del keys[-1], ms[i] room += 1 # Break the remainder into pieces of size i-1. i -= 1 q, r = divmod(reuse, i) need = q + bool(r) if need > room: if not keys: return continue ms[i] = q keys.append(i) if r: ms[r] = 1 keys.append(r) break room -= need yield ms
def __getitem__(self, n): """Return the nth prime number""" n = int_tested(n) self.extend_to_no(n) return self._list[n - 1]
def partitions(n, m=None, k=None): """Generate all partitions of integer n (>= 0). 'm' limits the number of parts in the partition, e.g. if m=2 then partitions will contain no more than 2 numbers, while 'k' limits the numbers which may appear in the partition, e.g. k=2 will return partitions with no element greater than 2. Each partition is represented as a dictionary, mapping an integer to the number of copies of that integer in the partition. For example, the first partition of 4 returned is {4: 1}: a single 4. >>> from sympy.utilities.iterables import partitions Maximum key (number in partition) limited with k (in this case, 2): >>> for p in partitions(6, k=2): ... print p {2: 3} {1: 2, 2: 2} {1: 4, 2: 1} {1: 6} Maximum number of parts in partion limited with m (in this case, 2): >>> for p in partitions(6, m=2): ... print p ... {6: 1} {1: 1, 5: 1} {2: 1, 4: 1} {3: 2} Note that the _same_ dictionary object is returned each time. This is for speed: generating each partition goes quickly, taking constant time independent of n. >>> [p for p in partitions(6, k=2)] [{1: 6}, {1: 6}, {1: 6}, {1: 6}] If you want to build a list of the returned dictionaries then make a copy of them: >>> [p.copy() for p in partitions(6, k=2)] [{2: 3}, {1: 2, 2: 2}, {1: 4, 2: 1}, {1: 6}] Reference: modified from Tim Peter's version to allow for k and m values: code.activestate.com/recipes/218332-generator-for-integer-partitions/ See Also ======== sympy.combinatorics.partitions.Partition sympy.combinatorics.partitions.IntegerPartition """ from sympy.ntheory.residue_ntheory import int_tested if n < 0: raise ValueError("n must be >= 0") if m == 0: raise ValueError("m must be > 0") m = min(m or n, n) if m < 1: raise ValueError("maximum numbers in partition, m, must be > 0") k = min(k or n, n) if k < 1: raise ValueError("maximum value in partition, k, must be > 0") if m*k < n: return n, m, k = int_tested(n, m, k) q, r = divmod(n, k) ms = {k: q} keys = [k] # ms.keys(), from largest to smallest if r: ms[r] = 1 keys.append(r) room = m - q - bool(r) yield ms while keys != [1]: # Reuse any 1's. if keys[-1] == 1: del keys[-1] reuse = ms.pop(1) room += reuse else: reuse = 0 while 1: # Let i be the smallest key larger than 1. Reuse one # instance of i. i = keys[-1] newcount = ms[i] = ms[i] - 1 reuse += i if newcount == 0: del keys[-1], ms[i] room += 1 # Break the remainder into pieces of size i-1. i -= 1 q, r = divmod(reuse, i) need = q + bool(r) if need > room: if not keys: return continue ms[i] = q keys.append(i) if r: ms[r] = 1 keys.append(r) break room -= need yield ms
def solve_congruence(*remainder_modulus_pairs, **hint): """Compute the integer ``n`` that has the residual ``ai`` when it is divided by ``mi`` where the ``ai`` and ``mi`` are given as pairs to this function: ((a1, m1), (a2, m2), ...). If there is no solution, return None. Otherwise return ``n`` and its modulus. The ``mi`` values need not be co-prime. If it is known that the moduli are not co-prime then the hint ``check`` can be set to False (default=True) and the check for a quicker solution via crt() (valid when the moduli are co-prime) will be skipped. If the hint ``symmetric`` is True (default is False), the value of ``n`` will be within 1/2 of the modulus, possibly negative. Examples ======== >>> from sympy.ntheory.modular import solve_congruence What number is 2 mod 3, 3 mod 5 and 2 mod 7? >>> solve_congruence((2, 3), (3, 5), (2, 7)) (23, 105) >>> [23 % m for m in [3, 5, 7]] [2, 3, 2] If you prefer to work with all remainder in one list and all moduli in another, send the arguments like this: >>> solve_congruence(*zip((2, 3, 2), (3, 5, 7))) (23, 105) The moduli need not be co-prime; in this case there may or may not be a solution: >>> solve_congruence((2, 3), (4, 6)) is None True >>> solve_congruence((2, 3), (5, 6)) (5, 6) The symmetric flag will make the result be within 1/2 of the modulus: >>> solve_congruence((2, 3), (5, 6), symmetric=True) (-1, 6) See also: crt and sympy.polys.galoistools.gf_crt """ def combine(c1, c2): """Return the tuple (a, m) which satisfies the requirement that n = a + i*m satisfy n = a1 + j*m1 and n = a2 = k*m2. References ========== - http://en.wikipedia.org/wiki/Method_of_successive_substitution """ from sympy.core.numbers import igcdex a1, m1 = c1 a2, m2 = c2 a, b, c = m1, a2 - a1, m2 g = reduce(igcd, [a, b, c]) a, b, c = [i // g for i in [a, b, c]] if a != 1: inv_a, _, g = igcdex(a, c) if g != 1: return None b *= inv_a a, m = a1 + m1 * b, m1 * c return a, m rm = remainder_modulus_pairs symmetric = hint.get('symmetric', False) if hint.get('check', True): rm = [int_tested(*pair) for pair in rm] # ignore redundant pairs but raise an error otherwise; also # make sure that a unique set of bases is sent to gf_crt if # they are all prime. # # The routine will work out less-trivial violations and # return None, e.g. for the pairs (1,3) and (14,42) there # is no answer because 14 mod 42 (having a gcd of 14) implies # (14/2) mod (42/2), (14/7) mod (42/7) and (14/14) mod (42/14) # which, being 0 mod 3, is inconsistent with 1 mod 3. But to # preprocess the input beyond checking of another pair with 42 # or 3 as the modulus (for this example) is not necessary. uniq = {} for r, m in rm: r %= m if m in uniq: if r != uniq[m]: return None continue uniq[m] = r rm = [(r, m) for m, r in uniq.iteritems()] del uniq # if the moduli are co-prime, the crt will be significantly faster; # checking all pairs for being co-prime gets to be slow but a prime # test is a good trade-off if all(isprime(m) for r, m in rm): r, m = zip(*rm) return crt(m, r, symmetric=symmetric, check=False) rv = (0, 1) for rmi in rm: rv = combine(rv, rmi) if rv is None: break n, m = rv n = n % m else: if symmetric: return symmetric_residue(n, m), m return n, m
def crt(m, v, symmetric=False, check=True): r"""Chinese Remainder Theorem. The moduli in m are assumed to be pairwise coprime. The output is then an integer f, such that f = v_i mod m_i for each pair out of v and m. If ``symmetric`` is False a positive integer will be returned, else \|f\| will be less than or equal to the LCM of the moduli, and thus f may be negative. If the moduli are not co-prime the correct result will be returned if/when the test of the result is found to be incorrect. This result will be None if there is no solution. The keyword ``check`` can be set to False if it is known that the moduli are coprime. As an example consider a set of residues ``U = [49, 76, 65]`` and a set of moduli ``M = [99, 97, 95]``. Then we have:: >>> from sympy.ntheory.modular import crt, solve_congruence >>> crt([99, 97, 95], [49, 76, 65]) (639985, 912285) This is the correct result because:: >>> [639985 % m for m in [99, 97, 95]] [49, 76, 65] If the moduli are not co-prime, you may receive an incorrect result if you use ``check=False``: >>> crt([12, 6, 17], [3, 4, 2], check=False) (954, 1224) >>> [954 % m for m in [12, 6, 17]] [6, 0, 2] >>> crt([12, 6, 17], [3, 4, 2]) is None True >>> crt([3, 6], [2, 5]) (5, 6) Note: the order of gf_crt's arguments is reversed relative to crt, and that solve_congruence takes residue, modulus pairs. Programmer's note: rather than checking that all pairs of moduli share no GCD (an O(n**2) test) and rather than factoring all moduli and seeing that there is no factor in common, a check that the result gives the indicated residuals is performed -- an O(n) operation. """ if check: m = int_tested(*m) v = int_tested(*v) result = gf_crt(v, m, ZZ) mm = prod(m) if check: if not all(v % m == result % m for v, m in zip(v, m)): result = solve_congruence(*zip(v, m), **dict(check=False, symmetric=symmetric)) if result is None: return result result, mm = result if symmetric: return symmetric_residue(result, mm), mm return result, mm
def crt(m, v, symmetric=False, check=True): """Chinese Remainder Theorem. The moduli in m are assumed to be pairwise coprime. The output is then an integer f, such that f = v_i mod m_i for each pair out of v and m. If ``symmetric`` is False a positive integer will be returned, else |f| will be less than or equal to the LCM of the moduli, and thus f may be negative. If the moduli are not co-prime the correct result will be returned if/when the test of the result is found to be incorrect. This result will be None if there is no solution. The keyword ``check`` can be set to False if it is known that the moduli are coprime. As an example consider a set of residues ``U = [49, 76, 65]`` and a set of moduli ``M = [99, 97, 95]``. Then we have:: >>> from sympy.ntheory.modular import crt, solve_congruence >>> crt([99, 97, 95], [49, 76, 65]) (639985, 912285) This is the correct result because:: >>> [639985 % m for m in [99, 97, 95]] [49, 76, 65] If the moduli are not co-prime, you may receive an incorrect result if you use ``check=False``: >>> crt([12, 6, 17], [3, 4, 2], check=False) (954, 1224) >>> [954 % m for m in [12, 6, 17]] [6, 0, 2] >>> crt([12, 6, 17], [3, 4, 2]) is None True >>> crt([3, 6], [2, 5]) (5, 6) Note: the order of gf_crt's arguments is reversed relative to crt, and that solve_congruence takes residue, modulus pairs. Programmer's note: rather than checking that all pairs of moduli share no GCD (an O(n**2) test) and rather than factoring all moduli and seeing that there is no factor in common, a check that the result gives the indicated residuals is performed -- an O(n) operation. """ if check: m = int_tested(*m) v = int_tested(*v) result = gf_crt(v, m, ZZ) mm = prod(m) if check: if not all(v % m == result % m for v, m in zip(v, m)): result = solve_congruence(*zip(v, m), **dict(check=False, symmetric=symmetric)) if result is None: return result result, mm = result if symmetric: return symmetric_residue(result, mm), mm return result, mm
def solve_congruence(*remainder_modulus_pairs, **hint): """Compute the integer ``n`` that has the residual ``ai`` when it is divided by ``mi`` where the ``ai`` and ``mi`` are given as pairs to this function: ((a1, m1), (a2, m2), ...). If there is no solution, return None. Otherwise return ``n`` and its modulus. The ``mi`` values need not be co-prime. If it is known that the moduli are not co-prime then the hint ``check`` can be set to False (default=True) and the check for a quicker solution via crt() (valid when the moduli are co-prime) will be skipped. If the hint ``symmetric`` is True (default is False), the value of ``n`` will be within 1/2 of the modulus, possibly negative. Examples:: >>> from sympy.ntheory.modular import solve_congruence What number is 2 mod 3, 3 mod 5 and 2 mod 7? >>> solve_congruence((2, 3), (3, 5), (2, 7)) (23, 105) >>> [23 % m for m in [3, 5, 7]] [2, 3, 2] If you prefer to work with all remainder in one list and all moduli in another, send the arguments like this: >>> solve_congruence(*zip((2, 3, 2), (3, 5, 7))) (23, 105) The moduli need not be co-prime; in this case there may or may not be a solution: >>> solve_congruence((2, 3), (4, 6)) is None True >>> solve_congruence((2, 3), (5, 6)) (5, 6) The symmetric flag will make the result be within 1/2 of the modulus: >>> solve_congruence((2, 3), (5, 6), symmetric=True) (-1, 6) See also: crt and sympy.polys.galoistools.gf_crt """ def combine(c1, c2): """Return the tuple (a, m) which satisfies the requirement that n = a + i*m satisfy n = a1 + j*m1 and n = a2 = k*m2. Reference: http://en.wikipedia.org/wiki/Method_of_successive_substitution """ from sympy.core.numbers import igcdex a1, m1 = c1 a2, m2 = c2 a, b, c = m1, a2 - a1, m2 g = reduce(igcd, [a, b, c]) a, b, c = [i//g for i in [a, b, c]] if a != 1: inv_a, _, g = igcdex(a, c) if g != 1: return None b *= inv_a a, m = a1 + m1*b, m1*c return a, m rm = remainder_modulus_pairs symmetric = hint.get('symmetric', False) if hint.get('check', True): rm = [int_tested(*pair) for pair in rm] # ignore redundant pairs but raise an error otherwise; also # make sure that a unique set of bases is sent to gf_crt if # they are all prime. # # The routine will work out less-trivial violations and # return None, e.g. for the pairs (1,3) and (14,42) there # is no answer because 14 mod 42 (having a gcd of 14) implies # (14/2) mod (42/2), (14/7) mod (42/7) and (14/14) mod (42/14) # which, being 0 mod 3, is inconsistent with 1 mod 3. But to # preprocess the input beyond checking of another pair with 42 # or 3 as the modulus (for this example) is not necessary. uniq = {} for r, m in rm: r %= m if m in uniq: if r != uniq[m]: return None continue uniq[m] = r rm = [(r, m) for m, r in uniq.iteritems()] del uniq # if the moduli are co-prime, the crt will be significantly faster; # checking all pairs for being co-prime gets to be slow but a prime # test is a good trade-off if all(isprime(m) for r, m in rm): r, m = zip(*rm) return crt(m, r, symmetric=symmetric, check=False) rv = (0, 1) for rmi in rm: rv = combine(rv, rmi) if rv is None: break n, m = rv n = n % m else: if symmetric: return symmetric_residue(n, m), m return n, m