switching to high quality piper tts and added label translations
This commit is contained in:
@@ -0,0 +1,291 @@
|
||||
from math import prod
|
||||
|
||||
from sympy.external.gmpy import gcd, gcdext
|
||||
from sympy.ntheory.primetest import isprime
|
||||
from sympy.polys.domains import ZZ
|
||||
from sympy.polys.galoistools import gf_crt, gf_crt1, gf_crt2
|
||||
from sympy.utilities.misc import as_int
|
||||
|
||||
|
||||
def symmetric_residue(a, m):
|
||||
"""Return the residual mod m such that it is within half of the modulus.
|
||||
|
||||
>>> from sympy.ntheory.modular import symmetric_residue
|
||||
>>> symmetric_residue(1, 6)
|
||||
1
|
||||
>>> symmetric_residue(4, 6)
|
||||
-2
|
||||
"""
|
||||
if a <= m // 2:
|
||||
return a
|
||||
return a - 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.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
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
|
||||
|
||||
>>> 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.
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
solve_congruence
|
||||
sympy.polys.galoistools.gf_crt : low level crt routine used by this routine
|
||||
"""
|
||||
if check:
|
||||
m = list(map(as_int, m))
|
||||
v = list(map(as_int, 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(*list(zip(v, m)),
|
||||
check=False, symmetric=symmetric)
|
||||
if result is None:
|
||||
return result
|
||||
result, mm = result
|
||||
|
||||
if symmetric:
|
||||
return int(symmetric_residue(result, mm)), int(mm)
|
||||
return int(result), int(mm)
|
||||
|
||||
|
||||
def crt1(m):
|
||||
"""First part of Chinese Remainder Theorem, for multiple application.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.modular import crt, crt1, crt2
|
||||
>>> m = [99, 97, 95]
|
||||
>>> v = [49, 76, 65]
|
||||
|
||||
The following two codes have the same result.
|
||||
|
||||
>>> crt(m, v)
|
||||
(639985, 912285)
|
||||
|
||||
>>> mm, e, s = crt1(m)
|
||||
>>> crt2(m, v, mm, e, s)
|
||||
(639985, 912285)
|
||||
|
||||
However, it is faster when we want to fix ``m`` and
|
||||
compute for multiple ``v``, i.e. the following cases:
|
||||
|
||||
>>> mm, e, s = crt1(m)
|
||||
>>> vs = [[52, 21, 37], [19, 46, 76]]
|
||||
>>> for v in vs:
|
||||
... print(crt2(m, v, mm, e, s))
|
||||
(397042, 912285)
|
||||
(803206, 912285)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.polys.galoistools.gf_crt1 : low level crt routine used by this routine
|
||||
sympy.ntheory.modular.crt
|
||||
sympy.ntheory.modular.crt2
|
||||
|
||||
"""
|
||||
|
||||
return gf_crt1(m, ZZ)
|
||||
|
||||
|
||||
def crt2(m, v, mm, e, s, symmetric=False):
|
||||
"""Second part of Chinese Remainder Theorem, for multiple application.
|
||||
|
||||
See ``crt1`` for usage.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.modular import crt1, crt2
|
||||
>>> mm, e, s = crt1([18, 42, 6])
|
||||
>>> crt2([18, 42, 6], [0, 0, 0], mm, e, s)
|
||||
(0, 4536)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.polys.galoistools.gf_crt2 : low level crt routine used by this routine
|
||||
sympy.ntheory.modular.crt
|
||||
sympy.ntheory.modular.crt1
|
||||
|
||||
"""
|
||||
|
||||
result = gf_crt2(v, m, mm, e, s, ZZ)
|
||||
|
||||
if symmetric:
|
||||
return int(symmetric_residue(result, mm)), int(mm)
|
||||
return int(result), int(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 : high level routine implementing the Chinese Remainder Theorem
|
||||
|
||||
"""
|
||||
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
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Method_of_successive_substitution
|
||||
"""
|
||||
a1, m1 = c1
|
||||
a2, m2 = c2
|
||||
a, b, c = m1, a2 - a1, m2
|
||||
g = gcd(a, b, c)
|
||||
a, b, c = [i//g for i in [a, b, c]]
|
||||
if a != 1:
|
||||
g, inv_a, _ = gcdext(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 = [(as_int(r), as_int(m)) for r, m 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.items()]
|
||||
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 = list(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
|
||||
Reference in New Issue
Block a user