
    \hi                     8   S SK Jr  S SKJr  S SKJr  S SKJr  S SKJ	r	J
r
JrJrJr  S SKJr  S SKJr  S SKrS	 rS
 rS rS rS rS rS rS rS rS rS rS)S jrS rS r S r!S r"S r#S r$S r%S r&S r'S*S jr(S r)S  r*S! r+S" r,S# r-S$ r.S% r/S& r0S' r1S( r2g)+    )Dummy)	nextprimecrt)PolynomialRing)gf_gcdgf_from_dictgf_gcdexgf_divgf_lcm)ModularGCDFailed)sqrtNc                    U R                   nU (       d*  U(       d#  UR                  UR                  UR                  4$ U (       dW  UR                  UR                  R                  :  a  U* UR                  UR                  * 4$ XR                  UR                  4$ U(       dW  U R                  UR                  R                  :  a  U * UR                  * UR                  4$ XR                  UR                  4$ g)zb
Compute the GCD of two polynomials in trivial cases, i.e. when one
or both polynomials are zero.
N)ringzeroLCdomainone)fgr   s      N/var/www/auris/envauris/lib/python3.13/site-packages/sympy/polys/modulargcd.py_trivial_gcdr      s    
 66Dyy$))TYY..44$++"""2tyy488)++ii))44$++"""2y$))++hh		))    c                    U R                   R                  nU(       a  U nUR                  5       nUR                  UR                  U5      n UR                  5       nXu:  a  OBXAR                  Xu-
  45      R                  XdR                  -  5      -
  R                  U5      nMX  Un UnU(       a  M  U R                  UR                  U R                  U5      5      R                  U5      $ )zE
Compute the GCD of two univariate polynomials in `\mathbb{Z}_p[x]`.
)r   r   degreeinvertr   	mul_monom
mul_groundtrunc_ground)fpgppdomremdeglcinvdegrems           r   _gf_gcdr(   #   s     ''..C
iik

255!$ZZ\F|v|o6AA%&&.QQ__`abC	   " ==BEE1-.;;A>>r   c                 J   U R                   R                  R                  U R                  UR                  5      nSn[	        U5      nX#-  S:X  a  [	        U5      nX#-  S:X  a  M  U R                  U5      nUR                  U5      n[        XEU5      nUR                  5       nU$ )a  
Compute an upper bound for the degree of the GCD of two univariate
integer polynomials `f` and `g`.

The function chooses a suitable prime `p` and computes the GCD of
`f` and `g` in `\mathbb{Z}_p[x]`. The choice of `p` guarantees that
the degree in `\mathbb{Z}_p[x]` is greater than or equal to the degree
in `\mathbb{Z}[x]`.

Parameters
==========

f : PolyElement
    univariate integer polynomial
g : PolyElement
    univariate integer polynomial

   r   )r   r   gcdr   r   r   r(   r   )r   r   gammar"   r    r!   hpdeghps           r   _degree_bound_univariater/   :   s    & FFMMaddADD)E	A!A
)q.aL )q. 
	B	
	B		BIIKELr   c           	      :   U R                  5       nU R                  R                  S   nU R                  R                  n[	        US-   5       H9  n[        X#/U R                  XW-  5      UR                  XW-  5      /SS9S   Xg4'   M;     UR                  5         U$ )a  
Construct a polynomial `h_{pq}` in `\mathbb{Z}_{p q}[x]` such that

.. math ::

    h_{pq} = h_p \; \mathrm{mod} \, p

    h_{pq} = h_q \; \mathrm{mod} \, q

for relatively prime integers `p` and `q` and polynomials
`h_p` and `h_q` in `\mathbb{Z}_p[x]` and `\mathbb{Z}_q[x]`
respectively.

The coefficients of the polynomial `h_{pq}` are computed with the
Chinese Remainder Theorem. The symmetric representation in
`\mathbb{Z}_p[x]`, `\mathbb{Z}_q[x]` and `\mathbb{Z}_{p q}[x]` is used.
It is assumed that `h_p` and `h_q` have the same degree.

Parameters
==========

hp : PolyElement
    univariate integer polynomial with coefficients in `\mathbb{Z}_p`
hq : PolyElement
    univariate integer polynomial with coefficients in `\mathbb{Z}_q`
p : Integer
    modulus of `h_p`, relatively prime to `q`
q : Integer
    modulus of `h_q`, relatively prime to `p`

Examples
========

>>> from sympy.polys.modulargcd import _chinese_remainder_reconstruction_univariate
>>> from sympy.polys import ring, ZZ

>>> R, x = ring("x", ZZ)
>>> p = 3
>>> q = 5

>>> hp = -x**3 - 1
>>> hq = 2*x**3 - 2*x**2 + x

>>> hpq = _chinese_remainder_reconstruction_univariate(hp, hq, p, q)
>>> hpq
2*x**3 + 3*x**2 + 6*x + 5

>>> hpq.trunc_ground(p) == hp
True
>>> hpq.trunc_ground(q) == hq
True

r   r*   T	symmetric)r   r   gensr   ranger   coeff
strip_zero)r-   hqr"   qnxhpqis           r   ,_chinese_remainder_reconstruction_univariater=   [   s    l 			A
QA
'',,C1Q3Z!$!$ @DQRSTD	  NNJr   c                    U R                   UR                   :X  a%  U R                   R                  R                  (       d   e[        X5      nUb  U$ U R                   nU R	                  5       u  p@UR	                  5       u  pQUR                  R                  XE5      n[        X5      nUS:X  a-  U" U5      U R                  XF-  5      UR                  XV-  5      4$ UR                  R                  U R                  UR                  5      nSn	Sn
 [        U
5      n
X-  S:X  a  [        U
5      n
X-  S:X  a  M  U R                  U
5      nUR                  U
5      n[        XU
5      nUR                  5       nX:  a  Mn  X:  a  Sn	UnMy  UR                  U5      R                  U
5      nU	S:X  a  U
n	UnM  [        UWX5      nX-  n	UU:X  d  UnM  UR                  UR                  5       5      nU R!                  U5      u  nnUR!                  U5      u  nnU(       dV  U(       dO  UR                  S:  a  U* nUR                  U5      nUR                  XF-  5      nUR                  XV-  5      nUUU4$ GMf  )a  
Computes the GCD of two polynomials in `\mathbb{Z}[x]` using a modular
algorithm.

The algorithm computes the GCD of two univariate integer polynomials
`f` and `g` by computing the GCD in `\mathbb{Z}_p[x]` for suitable
primes `p` and then reconstructing the coefficients with the Chinese
Remainder Theorem. Trial division is only made for candidates which
are very likely the desired GCD.

Parameters
==========

f : PolyElement
    univariate integer polynomial
g : PolyElement
    univariate integer polynomial

Returns
=======

h : PolyElement
    GCD of the polynomials `f` and `g`
cff : PolyElement
    cofactor of `f`, i.e. `\frac{f}{h}`
cfg : PolyElement
    cofactor of `g`, i.e. `\frac{g}{h}`

Examples
========

>>> from sympy.polys.modulargcd import modgcd_univariate
>>> from sympy.polys import ring, ZZ

>>> R, x = ring("x", ZZ)

>>> f = x**5 - 1
>>> g = x - 1

>>> h, cff, cfg = modgcd_univariate(f, g)
>>> h, cff, cfg
(x - 1, x**4 + x**3 + x**2 + x + 1, 1)

>>> cff * h == f
True
>>> cfg * h == g
True

>>> f = 6*x**2 - 6
>>> g = 2*x**2 + 4*x + 2

>>> h, cff, cfg = modgcd_univariate(f, g)
>>> h, cff, cfg
(2*x + 2, 3*x - 3, x + 1)

>>> cff * h == f
True
>>> cfg * h == g
True

References
==========

1. [Monagan00]_

r   r*   )r   r   is_ZZr   	primitiver+   r/   r   r   r   r   r(   r   r=   
quo_groundcontentdiv)r   r   resultr   cfcgchboundr,   mr"   r    r!   r-   r.   hlastmhmhfquofremgquogremcffcfgs                           r   modgcd_univariaterS      s)   F 66QVV 3 333!F66DKKMEBKKMEB		 B$Q*EzBxbh/bh1GGGKKOOADD!$$'E	A	A
aLi1n!A i1n ^^A^^ARQ		=]AE]]5!..q16AF9"faK	V|FMM"**,'UU1X
dUU1X
dDttaxSR A//"(+C//"(+Cc3;O r   c           	         U R                   nUR                  nUR                  n0 nU R                  5        H"  u  pgUSS U;  a  0 XVSS '   XuUSS    US   '   M$     / n[	        UR                  5       5       H  n[        U[        XqU5      X5      nM     UR                  UR                  US-
     S9n	U	R                  U5      R                  U5      n
XR                  U
R                  U5      5      4$ )a  
Compute the content and the primitive part of a polynomial in
`\mathbb{Z}_p[x_0, \ldots, x_{k-2}, y] \cong \mathbb{Z}_p[y][x_0, \ldots, x_{k-2}]`.

Parameters
==========

f : PolyElement
    integer polynomial in `\mathbb{Z}_p[x0, \ldots, x{k-2}, y]`
p : Integer
    modulus of `f`

Returns
=======

contf : PolyElement
    integer polynomial in `\mathbb{Z}_p[y]`, content of `f`
ppf : PolyElement
    primitive part of `f`, i.e. `\frac{f}{contf}`

Examples
========

>>> from sympy.polys.modulargcd import _primitive
>>> from sympy.polys import ring, ZZ

>>> R, x, y = ring("x, y", ZZ)
>>> p = 3

>>> f = x**2*y**2 + x**2*y - y**2 - y
>>> _primitive(f, p)
(y**2 + y, x**2 - 1)

>>> R, x, y, z = ring("x, y, z", ZZ)

>>> f = x*y*z - y**2*z**2
>>> _primitive(f, p)
(z, x*y - y**2*z)

Nr*   symbols)r   r   ngens	itertermsitervaluesr   r	   clonerW   
from_denser   quoset_ring)r   r"   r   r#   kcoeffsmonomr5   contyringcontfs              r   
_primitiverf     s    R 66D
++C

AF":V#!#F":(-uSbz59% &
 Dfmmo&dL37@ ' JJt||AaC0J1ET"//2E%%t,---r   c                     U R                   R                  nSUS-
  -  nU R                  5        H  nUSS U:  d  M  USS nM     U$ )a^  
Compute the degree of a multivariate polynomial
`f \in K[x_0, \ldots, x_{k-2}, y] \cong K[y][x_0, \ldots, x_{k-2}]`.

Parameters
==========

f : PolyElement
    polynomial in `K[x_0, \ldots, x_{k-2}, y]`

Returns
=======

degf : Integer tuple
    degree of `f` in `x_0, \ldots, x_{k-2}`

Examples
========

>>> from sympy.polys.modulargcd import _deg
>>> from sympy.polys import ring, ZZ

>>> R, x, y = ring("x, y", ZZ)

>>> f = x**2*y**2 + x**2*y - 1
>>> _deg(f)
(2,)

>>> R, x, y, z = ring("x, y, z", ZZ)

>>> f = x**2*y**2 + x**2*y - 1
>>> _deg(f)
(2, 2)

>>> f = x*y*z - y**2*z**2
>>> _deg(f)
(1, 1)

)r   r*   NrU   )r   rX   
itermonoms)r   r`   degfrb   s       r   _degrj   Z  sO    P 	
A1Q3<D":":D   Kr   c                     U R                   nUR                  nUR                  UR                  US-
     S9nUR                  S   n[        U 5      nUR                  nU R                  5        H  u  pxUSS U:X  d  M  XhXGS   -  -  -  nM     U$ )ag  
Compute the leading coefficient of a multivariate polynomial
`f \in K[x_0, \ldots, x_{k-2}, y] \cong K[y][x_0, \ldots, x_{k-2}]`.

Parameters
==========

f : PolyElement
    polynomial in `K[x_0, \ldots, x_{k-2}, y]`

Returns
=======

lcf : PolyElement
    polynomial in `K[y]`, leading coefficient of `f`

Examples
========

>>> from sympy.polys.modulargcd import _LC
>>> from sympy.polys import ring, ZZ

>>> R, x, y = ring("x, y", ZZ)

>>> f = x**2*y**2 + x**2*y - 1
>>> _LC(f)
y**2 + y

>>> R, x, y, z = ring("x, y, z", ZZ)

>>> f = x**2*y**2 + x**2*y - 1
>>> _LC(f)
1

>>> f = x*y*z - y**2*z**2
>>> _LC(f)
z

r*   rV   r   NrU   )r   rX   r\   rW   r3   rj   r   rY   )	r   r   r`   rd   yri   lcfrb   r5   s	            r   _LCrn     s    P 66D

AJJt||AaC0J1E

1A7D
**C":"I%%C & Jr   c                     U R                   nUR                  nU R                  5        H  u  pEXA   4USU -   XAS-   S -   nXSU'   M     U$ )zK
Make the variable `x_i` the leading one in a multivariate polynomial `f`.
Nr*   )r   r   rY   )r   r<   r   fswaprb   r5   	monomswaps          r   _swaprr     sX     66DIIEXK%)+eaCDk9	 i & Lr   c                    U R                   nUR                  R                  U R                  UR                  5      nUR                  R                  [	        U S5      R                  [	        US5      R                  5      nX4-  nSn[        U5      nXV-  S:X  a  [        U5      nXV-  S:X  a  M  U R                  U5      nUR                  U5      n[        Xv5      u  p[        X5      u  p[        XU5      nUR                  5       n[        [        U5      [        U5      U5      n[        U5       H  nUR                  SU5      U-  (       d  M  UR                  SU5      R                  U5      nUR                  SU5      R                  U5      n[        UUU5      nUR                  5       nUU4s  $    [        UR                  5       UR                  5       5      U4$ )a'  
Compute upper degree bounds for the GCD of two bivariate
integer polynomials `f` and `g`.

The GCD is viewed as a polynomial in `\mathbb{Z}[y][x]` and the
function returns an upper bound for its degree and one for the degree
of its content. This is done by choosing a suitable prime `p` and
computing the GCD of the contents of `f \; \mathrm{mod} \, p` and
`g \; \mathrm{mod} \, p`. The choice of `p` guarantees that the degree
of the content in `\mathbb{Z}_p[y]` is greater than or equal to the
degree in `\mathbb{Z}[y]`. To obtain the degree bound in the variable
`x`, the polynomials are evaluated at `y = a` for a suitable
`a \in \mathbb{Z}_p` and then their GCD in `\mathbb{Z}_p[x]` is
computed. If no such `a` exists, i.e. the degree in `\mathbb{Z}_p[x]`
is always smaller than the one in `\mathbb{Z}[y][x]`, then the bound is
set to the minimum of the degrees of `f` and `g` in `x`.

Parameters
==========

f : PolyElement
    bivariate integer polynomial
g : PolyElement
    bivariate integer polynomial

Returns
=======

xbound : Integer
    upper bound for the degree of the GCD of the polynomials `f` and
    `g` in the variable `x`
ycontbound : Integer
    upper bound for the degree of the content of the GCD of the
    polynomials `f` and `g` in the variable `y`

References
==========

1. [Monagan00]_

r*   r   )r   r   r+   r   rr   r   r   rf   r(   r   rn   r4   evaluatemin)r   r   r   gamma1gamma2	badprimesr"   r    r!   contfpcontgpconthp
ycontbounddeltaafpagpahpaxbounds                      r   _degree_bound_bivariater     s   T 66D[[__QTT144(F[[__U1a[^^U1a[^^<FI	A!A
-1
aL -1
 
	B	
	BB"JFB"JFVQ'FJ CGSWa(E1X~~a#a'kk!Q,,Q/kk!Q,,Q/c3"z!!  ryy{BIIK(*44r   c                 <  ^ [        U R                  5       5      n[        UR                  5       5      nUR                  U5      nUR                  U5        UR                  U5        U R                  R
                  mTR                  nU R                  R                  n[        U R                  R
                  [        5      (       a  [        n	OU4S jn	U H  n
U	" X
   X   X#5      X'   M     U H  n
U	" X
   XrU5      X'   M     U H  n
U	" XqU
   X#5      X'   M     U$ )aj  
Construct a polynomial `h_{pq}` in
`\mathbb{Z}_{p q}[x_0, \ldots, x_{k-1}]` such that

.. math ::

    h_{pq} = h_p \; \mathrm{mod} \, p

    h_{pq} = h_q \; \mathrm{mod} \, q

for relatively prime integers `p` and `q` and polynomials
`h_p` and `h_q` in `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]` and
`\mathbb{Z}_q[x_0, \ldots, x_{k-1}]` respectively.

The coefficients of the polynomial `h_{pq}` are computed with the
Chinese Remainder Theorem. The symmetric representation in
`\mathbb{Z}_p[x_0, \ldots, x_{k-1}]`,
`\mathbb{Z}_q[x_0, \ldots, x_{k-1}]` and
`\mathbb{Z}_{p q}[x_0, \ldots, x_{k-1}]` is used.

Parameters
==========

hp : PolyElement
    multivariate integer polynomial with coefficients in `\mathbb{Z}_p`
hq : PolyElement
    multivariate integer polynomial with coefficients in `\mathbb{Z}_q`
p : Integer
    modulus of `h_p`, relatively prime to `q`
q : Integer
    modulus of `h_q`, relatively prime to `p`

Examples
========

>>> from sympy.polys.modulargcd import _chinese_remainder_reconstruction_multivariate
>>> from sympy.polys import ring, ZZ

>>> R, x, y = ring("x, y", ZZ)
>>> p = 3
>>> q = 5

>>> hp = x**3*y - x**2 - 1
>>> hq = -x**3*y - 2*x*y**2 + 2

>>> hpq = _chinese_remainder_reconstruction_multivariate(hp, hq, p, q)
>>> hpq
4*x**3*y + 5*x**2 + 3*x*y**2 + 2

>>> hpq.trunc_ground(p) == hp
True
>>> hpq.trunc_ground(q) == hq
True

>>> R, x, y, z = ring("x, y, z", ZZ)
>>> p = 6
>>> q = 5

>>> hp = 3*x**4 - y**3*z + z
>>> hq = -2*x**4 + z

>>> hpq = _chinese_remainder_reconstruction_multivariate(hp, hq, p, q)
>>> hpq
3*x**4 + 5*y**3*z + z

>>> hpq.trunc_ground(p) == hp
True
>>> hpq.trunc_ground(q) == hq
True

c                 0   > T" [        X#/X/SS9S   5      $ )NTr1   r   r   )cpcqr"   r8   r   s       r   crt_<_chinese_remainder_reconstruction_multivariate.<locals>.crt_l  s     #qfrh$?BCCr   )
setmonomsintersectiondifference_updater   r   r   
isinstancer   ._chinese_remainder_reconstruction_multivariate)r-   r7   r"   r8   hpmonomshqmonomsr   r   r;   r   rb   r   s              @r   r   r     s    P 299;H299;H""8,Fv&v&WW^^F;;D
'',,C"''...11=	D ")RY5
 ")Ta0
 $5	10
  Jr   c                    UR                   nU(       a0  UR                  R                  nUR                  R                  U   nOUR                  nUR                  U   n[        X5       Hs  u  pUR                  nUR                  nU  H  nX:X  a  M
  XU-
  -  nXU-
  -  nM     UR                  X5      nUR                  U5      nXjR                  U5      U-  -  nMu     UR                  U5      $ )a  
Reconstruct a polynomial `h_p` in `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]`
from a list of evaluation points in `\mathbb{Z}_p` and a list of
polynomials in
`\mathbb{Z}_p[x_0, \ldots, x_{i-1}, x_{i+1}, \ldots, x_{k-1}]`, which
are the images of `h_p` evaluated in the variable `x_i`.

It is also possible to reconstruct a parameter of the ground domain,
i.e. if `h_p` is a polynomial over `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]`.
In this case, one has to set ``ground=True``.

Parameters
==========

evalpoints : list of Integer objects
    list of evaluation points in `\mathbb{Z}_p`
hpeval : list of PolyElement objects
    list of polynomials in (resp. over)
    `\mathbb{Z}_p[x_0, \ldots, x_{i-1}, x_{i+1}, \ldots, x_{k-1}]`,
    images of `h_p` evaluated in the variable `x_i`
ring : PolyRing
    `h_p` will be an element of this ring
i : Integer
    index of the variable which has to be reconstructed
p : Integer
    prime number, modulus of `h_p`
ground : Boolean
    indicates whether `x_i` is in the ground domain, default is
    ``False``

Returns
=======

hp : PolyElement
    interpolated polynomial in (resp. over)
    `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]`

)	r   r   r3   zipr   r   r   r_   r   )
evalpointshpevalr   r<   r"   groundr-   r   rl   r~   r   numerdenombr5   s                  r   _interpolate_multivariater   y  s    N 
B##KKQIIaLj)

AvUNEUNE  e'  '
ll4 5(( * ??1r   c                 r
   U R                   UR                   :X  a%  U R                   R                  R                  (       d   e[        X5      nUb  U$ U R                   nU R	                  5       u  p@UR	                  5       u  pQUR                  R                  XE5      n[        X5      u  pxXxs=:X  a  S:X  a0  O  O-U" U5      U R                  XF-  5      UR                  XV-  5      4$ [        U S5      n	[        US5      n
U	R                  5       nU
R                  5       n[        X5      u  pXs=:X  a  S:X  a0  O  O-U" U5      U R                  XF-  5      UR                  XV-  5      4$ UR                  R                  U R                  UR                  5      nUR                  R                  U	R                  U
R                  5      nUU-  nSnSn [        U5      nUU-  S:X  a  [        U5      nUU-  S:X  a  M  U R                  U5      nUR                  U5      n[        UU5      u  nn[        UU5      u  nn[        UUU5      nUR                  5       nUU:  a  M  UU:  a  SnUnM  [        [        U5      [        U5      U5      nUR                  5       nUR                  5       nUR                  5       n[!        UU-
  UU-
  X-
  U-   5      S-   nUU:  a  GM  Sn/ n / n!Sn"[#        U5       H  n#UR%                  SU#5      n$U$U-  (       d  M!  UR%                  SU#5      R                  U5      n%UR%                  SU#5      R                  U5      n&[        U%U&U5      n'U'R                  5       n(U(U:  a  M  U(U:  a  SnU(nSn"  OSU'R                  U$5      R                  U5      n'U R'                  U#5        U!R'                  U'5        US-  nUU:X  d  M    O   U"(       a  GM  UU:  a  GM  [)        U U!USU5      n)[        U)U5      S   n)U)UR+                  U5      -  n)U)R                  S5      n*U*U:  a  GMj  U*U:  a  SnU*nGMw  U)R                  U5      R                  U5      n)US:X  a  UnU)n+GM  [-        U)W+UU5      n,UU-  nU,U+:X  d  U,n+GM  U,R/                  U,R1                  5       5      n-U R3                  U-5      u  n.n/UR3                  U-5      u  n0n1U/(       dV  U1(       dO  U-R                  S:  a  U* nU-R                  U5      n-U.R                  XF-  5      n2U0R                  XV-  5      n3U-U2U34$ GMh  )aI  
Computes the GCD of two polynomials in `\mathbb{Z}[x, y]` using a
modular algorithm.

The algorithm computes the GCD of two bivariate integer polynomials
`f` and `g` by calculating the GCD in `\mathbb{Z}_p[x, y]` for
suitable primes `p` and then reconstructing the coefficients with the
Chinese Remainder Theorem. To compute the bivariate GCD over
`\mathbb{Z}_p`, the polynomials `f \; \mathrm{mod} \, p` and
`g \; \mathrm{mod} \, p` are evaluated at `y = a` for certain
`a \in \mathbb{Z}_p` and then their univariate GCD in `\mathbb{Z}_p[x]`
is computed. Interpolating those yields the bivariate GCD in
`\mathbb{Z}_p[x, y]`. To verify the result in `\mathbb{Z}[x, y]`, trial
division is done, but only for candidates which are very likely the
desired GCD.

Parameters
==========

f : PolyElement
    bivariate integer polynomial
g : PolyElement
    bivariate integer polynomial

Returns
=======

h : PolyElement
    GCD of the polynomials `f` and `g`
cff : PolyElement
    cofactor of `f`, i.e. `\frac{f}{h}`
cfg : PolyElement
    cofactor of `g`, i.e. `\frac{g}{h}`

Examples
========

>>> from sympy.polys.modulargcd import modgcd_bivariate
>>> from sympy.polys import ring, ZZ

>>> R, x, y = ring("x, y", ZZ)

>>> f = x**2 - y**2
>>> g = x**2 + 2*x*y + y**2

>>> h, cff, cfg = modgcd_bivariate(f, g)
>>> h, cff, cfg
(x + y, x - y, x + y)

>>> cff * h == f
True
>>> cfg * h == g
True

>>> f = x**2*y - x**2 - 4*y + 4
>>> g = x + 2

>>> h, cff, cfg = modgcd_bivariate(f, g)
>>> h, cff, cfg
(x + 2, x*y - x - 2*y + 2, 1)

>>> cff * h == f
True
>>> cfg * h == g
True

References
==========

1. [Monagan00]_

r   r*   TF)r   r   r?   r   r@   r+   r   r   rr   r   r   r   r   rf   r(   rn   ru   r4   rt   appendr   r_   r   rA   rB   rC   )4r   r   rD   r   rE   rF   rG   r   r|   rp   gswapdegyfdegygybound
xcontboundrv   rw   rx   rI   r"   r    r!   ry   rz   r{   	degconthpr}   	degcontfp	degcontgpdegdeltaNr9   r   r   unluckyr~   deltaar   r   r   deghpar-   degyhprJ   rK   rL   rM   rN   rO   rP   rQ   rR   s4                                                       r   modgcd_bivariater     s   R 66QVV 3 333!F66DKKMEBKKMEB		 B06F q Bxbh/bh1GGG!QKE!QKELLNELLNE0>F q Bxbh/bh1GGG [[__QTT144(F[[__UXXuxx0FI	A	A
aL!mq !A !mq  ^^A^^AA&
A&
+MMO	z!#A"J BR!,MMO	MMO	<<>	!59#4(*,./0 q5
qA^^Aq)FA:++a#003C++a#003C#sA&CZZ\F&..(55a8Ca MM#FAAv1 4 q5&z64AFAq!&//$''1F?F?AF]]6"//26AF;B1M	QV|FMM"**,'UU1X
dUU1X
dDttaxSR A//"(+C//"(+Cc3;O r   c                 "   U R                   nUR                  nUS:X  aH  [        XU5      R                  U5      nUR	                  5       nXS   :  a  gXS   :  a
  XS'   [
        eU$ U R	                  US-
  5      n	UR	                  US-
  5      n
[        X5      u  p[        X5      u  p[        XU5      nUR	                  5       nUR	                  5       nUR	                  5       nUXFS-
     :  a  gUXFS-
     :  a  UXFS-
  '   [
        e[        U 5      n[        U5      n[        UUU5      nUn[        US-
  5       H9  nU[        [        [        U U5      5      [        [        UU5      5      U5      -  nM;     UR	                  5       n[        X-
  X-
  X6S-
     XFS-
     -
  U-   5      S-   nUU:  a  gSnSn/ n/ n[        [        U5      5      nU(       Ga  [        R                  " US5      S   nUR                  U5        UR                  SU5      U-  (       d  MO  UR                  SU5      U-  nU R                  US-
  U5      R                  U5      nUR                  US-
  U5      R                  U5      n [!        UU X#U5      n!U!c  US-  nUU:  a  gM  U!R"                  (       a"  UR%                  U5      R                  U5      nU$ U!R'                  U5      R                  U5      n!UR)                  U5        UR)                  U!5        US-  nUU:X  ak  [+        UUXVS-
  U5      n[        Xr5      S   UR%                  U5      -  nUR	                  US-
  5      n"U"X6S-
     :  a  gU"X6S-
     :  a  U"X6S-
  '   [
        eU$ U(       a  GM  g)a  
Compute the GCD of two polynomials in
`\mathbb{Z}_p[x_0, \ldots, x_{k-1}]`.

The algorithm reduces the problem step by step by evaluating the
polynomials `f` and `g` at `x_{k-1} = a` for suitable
`a \in \mathbb{Z}_p` and then calls itself recursively to compute the GCD
in `\mathbb{Z}_p[x_0, \ldots, x_{k-2}]`. If these recursive calls are
successful for enough evaluation points, the GCD in `k` variables is
interpolated, otherwise the algorithm returns ``None``. Every time a GCD
or a content is computed, their degrees are compared with the bounds. If
a degree greater then the bound is encountered, then the current call
returns ``None`` and a new evaluation point has to be chosen. If at some
point the degree is smaller, the correspondent bound is updated and the
algorithm fails.

Parameters
==========

f : PolyElement
    multivariate integer polynomial with coefficients in `\mathbb{Z}_p`
g : PolyElement
    multivariate integer polynomial with coefficients in `\mathbb{Z}_p`
p : Integer
    prime number, modulus of `f` and `g`
degbound : list of Integer objects
    ``degbound[i]`` is an upper bound for the degree of the GCD of `f`
    and `g` in the variable `x_i`
contbound : list of Integer objects
    ``contbound[i]`` is an upper bound for the degree of the content of
    the GCD in `\mathbb{Z}_p[x_i][x_0, \ldots, x_{i-1}]`,
    ``contbound[0]`` is not used can therefore be chosen
    arbitrarily.

Returns
=======

h : PolyElement
    GCD of the polynomials `f` and `g` or ``None``

References
==========

1. [Monagan00]_
2. [Brown71]_

r*   r   N)r   rX   r(   r   r   r   rf   rn   r4   rr   ru   listrandomsampleremovert   _modgcd_multivariate_p	is_groundr_   r   r   r   )#r   r   r"   degbound	contboundr   r`   rL   deghr   r   re   contgconthdegcontfdegcontgdegconthrm   lcgr}   evaltestr<   r   r   r9   dr   hevalpointsr~   r   fagahadegyhs#                                      r   r   r     sx   ` 66D

AAvA!))!,xxz1+1+QK""HHQqSMEHHQqSME!HE!HEE!$E||~H||~H||~H)aC. )aC. !	A#
a&C
a&CCa EH1Q3ZGCa,c%1+.>BB  ||~HEe.qSMIcN*X5	79:	;A 	1u	A	AJE%(^F
MM&!$Q'a  A&*1%)ZZ!Q,,Q/ZZ!Q,,Q/ $BAC:FA1u<<t$11!4AH]]6"//2!R	Q6)*eTQ3JA1 #ennT&::AHHQqSMEx!}$x!}$ %1&&HW &Z r   c           	         U R                   UR                   :X  a%  U R                   R                  R                  (       d   e[        X5      nUb  U$ U R                   nUR                  nU R                  5       u  pPUR                  5       u  paUR                  R                  XV5      nUR                  R                  U R                  UR                  5      nUR                  R                  n	[        U5       HG  n
XR                  R                  [        X
5      R                  [        X5      R                  5      -  n	MI     [        U R                  5       UR                  5       5       VVs/ s H  u  p[        X5      PM     nnn[        U5      nSnSn [        U5      nU	U-  S:X  a  [        U5      nU	U-  S:X  a  M  U R!                  U5      nUR!                  U5      n [#        UUUX5      nUc  Ma  UR'                  U5      R!                  U5      nUS:X  a  UnUnM  [)        UWUU5      nUU-  nUU:X  d  UnM  UR                  5       S   nU R+                  U5      u  nnUR+                  U5      u  nnU(       dV  U(       dO  UR                  S:  a  U* nUR'                  U5      nUR'                  XW-  5      nUR'                  Xg-  5      nUUU4$ GMD  s  snnf ! [$         a    Sn GM[  f = f)a  
Compute the GCD of two polynomials in `\mathbb{Z}[x_0, \ldots, x_{k-1}]`
using a modular algorithm.

The algorithm computes the GCD of two multivariate integer polynomials
`f` and `g` by calculating the GCD in
`\mathbb{Z}_p[x_0, \ldots, x_{k-1}]` for suitable primes `p` and then
reconstructing the coefficients with the Chinese Remainder Theorem. To
compute the multivariate GCD over `\mathbb{Z}_p` the recursive
subroutine :func:`_modgcd_multivariate_p` is used. To verify the result in
`\mathbb{Z}[x_0, \ldots, x_{k-1}]`, trial division is done, but only for
candidates which are very likely the desired GCD.

Parameters
==========

f : PolyElement
    multivariate integer polynomial
g : PolyElement
    multivariate integer polynomial

Returns
=======

h : PolyElement
    GCD of the polynomials `f` and `g`
cff : PolyElement
    cofactor of `f`, i.e. `\frac{f}{h}`
cfg : PolyElement
    cofactor of `g`, i.e. `\frac{g}{h}`

Examples
========

>>> from sympy.polys.modulargcd import modgcd_multivariate
>>> from sympy.polys import ring, ZZ

>>> R, x, y = ring("x, y", ZZ)

>>> f = x**2 - y**2
>>> g = x**2 + 2*x*y + y**2

>>> h, cff, cfg = modgcd_multivariate(f, g)
>>> h, cff, cfg
(x + y, x - y, x + y)

>>> cff * h == f
True
>>> cfg * h == g
True

>>> R, x, y, z = ring("x, y, z", ZZ)

>>> f = x*z**2 - y*z**2
>>> g = x**2*z + z

>>> h, cff, cfg = modgcd_multivariate(f, g)
>>> h, cff, cfg
(z, x*z - y*z, x**2 + 1)

>>> cff * h == f
True
>>> cfg * h == g
True

References
==========

1. [Monagan00]_
2. [Brown71]_

See also
========

_modgcd_multivariate_p

r*   r   )r   r   r?   r   rX   r@   r+   r   r   r4   rr   r   degreesru   r   r   r   r   r   r   r   rC   )r   r   rD   r   r`   rE   rF   rG   r,   rx   r<   fdeggdegr   r   rI   r"   r    r!   r-   rJ   rK   rL   rM   rN   rO   rP   rQ   rR   s                                r   modgcd_multivariater   '  s   \ 66QVV 3 333!F66D

A KKMEBKKMEB		 BKKOOADD!$$'EI1X[[__U1[^^U1[^^DD	  36aiik199;2OP2OJDD2OHPXI	A	A
aL!mq !A !mq  ^^A^^A	'B8GB
 :]]5!..q16AF;B1M	QV|FLLN1UU1X
dUU1X
dDttaxSR A//"(+C//"(+Cc3;Q  Q"   	A	s   0K'K$ $K54K5c                     U R                   n[        U R                  5       UR                  5       X#R                  5      u  pEUR	                  U5      UR	                  U5      4$ )zS
Compute `\frac f g` modulo `p` for two univariate polynomials over
`\mathbb Z_p`.
)r   r   to_denser   r]   )r   r   r"   r   densequodenserems         r   _gf_divr     sK    
 66D

ajjlA{{KH??8$dooh&???r   c                    U R                   nUR                  nUR                  5       nUS-  nXV-
  S-
  nX#R                  pXR                  pU
R                  5       U:  aQ  [        XU5      S   nXX-  -
  R                  U5      pXX-  -
  R                  U5      pU
R                  5       U:  a  MQ  XpUR                  5       U:  d  [        XU5      S:w  a  gUR                  nUS:w  aQ  UR                  X5      nUR                  U5      R                  U5      nUR                  U5      R                  U5      nUR                  5       nU" U5      U" U5      -  $ )a  
Reconstruct a rational function `\frac a b` in `\mathbb Z_p(t)` from

.. math::

    c = \frac a b \; \mathrm{mod} \, m,

where `c` and `m` are polynomials in `\mathbb Z_p[t]` and `m` has
positive degree.

The algorithm is based on the Euclidean Algorithm. In general, `m` is
not irreducible, so it is possible that `b` is not invertible modulo
`m`. In that case ``None`` is returned.

Parameters
==========

c : PolyElement
    univariate polynomial in `\mathbb Z[t]`
p : Integer
    prime number
m : PolyElement
    modulus, not necessarily irreducible

Returns
=======

frac : FracElement
    either `\frac a b` in `\mathbb Z(t)` or ``None``

References
==========

1. [Hoeij04]_

   r*   r   N)r   r   r   r   r   r   r   r(   r   r   r   to_field)cr"   rI   r   r   Mr   Dr0s0r1s1r^   r~   r   lcr&   fields                     r   !_rational_function_reconstructionr     s4   J 66D[[F	
A	QA		A		
))+/ba #36k//2B36k//2B ))+/
 qxxzA~q)Q.	
B	Qwb$LL,,Q/LL,,Q/MMOE8eAhr   c                 @   UR                   nU R                  5        H}  u  pgUS:X  a  [        XqU5      nU(       d    gOXUR                  R                   nUR	                  U5      R                  5        H  u  p[        XU5      nU(       d      gXU	'   M!     XU'   M     U$ )au  
Reconstruct every coefficient `c_h` of a polynomial `h` in
`\mathbb Z_p(t_k)[t_1, \ldots, t_{k-1}][x, z]` from the corresponding
coefficient `c_{h_m}` of a polynomial `h_m` in
`\mathbb Z_p[t_1, \ldots, t_k][x, z] \cong \mathbb Z_p[t_k][t_1, \ldots, t_{k-1}][x, z]`
such that

.. math::

    c_{h_m} = c_h \; \mathrm{mod} \, m,

where `m \in \mathbb Z_p[t]`.

The reconstruction is based on the Euclidean Algorithm. In general, `m`
is not irreducible, so it is possible that this fails for some
coefficient. In that case ``None`` is returned.

Parameters
==========

hm : PolyElement
    polynomial in `\mathbb Z[t_1, \ldots, t_k][x, z]`
p : Integer
    prime number, modulus of `\mathbb Z_p`
m : PolyElement
    modulus, polynomial in `\mathbb Z[t]`, not necessarily irreducible
ring : PolyRing
    `\mathbb Z(t_k)[t_1, \ldots, t_{k-1}][x, z]`, `h` will be an
    element of this ring
k : Integer
    index of the parameter `t_k` which will be reconstructed

Returns
=======

h : PolyElement
    reconstructed polynomial in
    `\mathbb Z(t_k)[t_1, \ldots, t_{k-1}][x, z]` or ``None``

See also
========

_rational_function_reconstruction

r   N)r   rY   r   r   drop_to_ground)rK   r"   rI   r   r`   rL   rb   r5   coeffhmonr   rG   s               r   $_rational_reconstruction_func_coeffsr     s    \ 			A66uCF  [[%%F..q1;;=6qQ? s > %# '& Hr   c                     U R                   n[        U R                  5       UR                  5       X#R                  5      u  pEnUR	                  U5      UR	                  U5      UR	                  U5      4$ )z
Extended Euclidean Algorithm for two univariate polynomials over
`\mathbb Z_p`.

Returns polynomials `s, t` and `h`, such that `h` is the GCD of `f` and
`g` and `sf + tg = h \; \mathrm{mod} \, p`.

)r   r
   r   r   r]   )r   r   r"   r   strL   s          r   	_gf_gcdexr   L  sW     66Dqzz|QZZ\1kkBGA!??1tq14??13EEEr   c                     U R                   nUR                  U5      nUR                  U5      nU R                  U5      R	                  X/5      R                  U5      $ )a  
Compute the reduced representation of a polynomial `f` in
`\mathbb Z_p[z] / (\check m_{\alpha}(z))[x]`

Parameters
==========

f : PolyElement
    polynomial in `\mathbb Z[x, z]`
minpoly : PolyElement
    polynomial `\check m_{\alpha} \in \mathbb Z[z]`, not necessarily
    irreducible
p : Integer
    prime number, modulus of `\mathbb Z_p`

Returns
=======

ftrunc : PolyElement
    polynomial in `\mathbb Z[x, z]`, reduced modulo
    `\check m_{\alpha}(z)` and `p`

)r   r_   
ground_newr   r$   )r   minpolyr"   r   p_s        r   _truncr   Z  sR    0 66Dt$G		B>>!  '/<<Q??r   c                    U R                   n[        XU5      n [        XU5      nU(       a  U nUR                  S5      n[        UR	                  U5      X#5      u  pxn	U	S:X  d  g UR                  S5      n
X:  a  OHXtR	                  U5      -  R                  U5      n[        XQR                  X-
  S45      U-  -
  X#5      nM_  Un UnU(       a  M  [        UR	                  U 5      X#5      S   R                  U5      n[        X-  X#5      $ )a  
Compute the monic GCD of two univariate polynomials in
`\mathbb{Z}_p[z]/(\check m_{\alpha}(z))[x]` with the Euclidean
Algorithm.

In general, `\check m_{\alpha}(z)` is not irreducible, so it is possible
that some leading coefficient is not invertible modulo
`\check m_{\alpha}(z)`. In that case ``None`` is returned.

Parameters
==========

f, g : PolyElement
    polynomials in `\mathbb Z[x, z]`
minpoly : PolyElement
    polynomial in `\mathbb Z[z]`, not necessarily irreducible
p : Integer
    prime number, modulus of `\mathbb Z_p`

Returns
=======

h : PolyElement
    GCD of `f` and `g` in `\mathbb Z[z, x]` or ``None``, coefficients
    are in `\left[ -\frac{p-1} 2, \frac{p-1} 2 \right]`

r   r*   N)r   r   r   r   dmp_LCr_   r   )r   r   r   r"   r   r$   r%   r&   _r+   r'   r^   lcfinvs                r   _euclidean_algorithmr   y  s   8 66Dq1Aq1A
hhqk!$++a.'=#axZZ]F|;;s++55d;C{{FL!+<=cAA7NC  ! !$ t{{1~w215>>tDF!*g))r   c                    U R                   nUR                  UR                  S   UR                  S   4S9nUR                  U5      nU nUR	                  5       nUR	                  5       nUR	                  S5      n	[        U5      R                  U5      n
UR                  nU(       Ga  Xx:  Ga  [        U5      R                  U5      nXj-  UR                  Xx-
  S45      U-  -
  nU(       a  UR                  U5      nUR	                  S5      nU(       a  Xy:  a  [        UR                  U5      5      R                  U5      nUR                  U5      UR                  SXy-
  45      U-  -
  nU(       a  UR                  U5      nUR	                  S5      nU(       a  Xy:  a  M  UR	                  5       nU(       a  Xx:  a  GM  U$ )a  
Check if `h` divides `f` in
`\mathbb K[t_1, \ldots, t_k][z]/(m_{\alpha}(z))`, where `\mathbb K` is
either `\mathbb Q` or `\mathbb Z_p`.

This algorithm is based on pseudo division and does not use any
fractions. By default `\mathbb K` is `\mathbb Q`, if a prime number `p`
is given, `\mathbb Z_p` is chosen instead.

Parameters
==========

f, h : PolyElement
    polynomials in `\mathbb Z[t_1, \ldots, t_k][x, z]`
minpoly : PolyElement
    polynomial `m_{\alpha}(z)` in `\mathbb Z[t_1, \ldots, t_k][z]`
p : Integer or None
    if `p` is given, `\mathbb K` is set to `\mathbb Z_p` instead of
    `\mathbb Q`, default is ``None``

Returns
=======

rem : PolyElement
    remainder of `\frac f h`

References
==========

.. [1] [Hoeij02]_

r*   r   rV   )
r   r\   rW   r_   r   rn   r   r   r   r   )r   rL   r   r"   r   zxringr$   r'   r   degmlchlcmlcrems                r   _trial_divisionr     sx   B 66DZZa$,,q/ BZCFt$G
CZZ\F88:D>>!D
a&//$
C
**C
&.C!!$'gV]A$67==""1%CAfnV,-66t<E..%(9(91fm:L(Me(SSC&&q)ZZ]F fn ! &.$ Jr   c                    U R                   R                  U R                   R                  R                   R                  U5      S9nUR                  nU R                  5        H  u  pVUR                  X5      XE'   M     U$ )zO
Evaluate a polynomial `f` at `a` in the `i`-th variable of the ground
domain.
r   )r   r\   r   dropr   rY   rt   )r   r<   r~   r   r   rb   r5   s          r   _evaluate_groundr     sc    
 66<<qvv}}1166q9<:D	BNN1(	 & Ir   c           
      V   U R                   nUR                  n[        U[        5      (       a  UR                  nO[        XX#5      $ US:X  a  UR                   R                  5       nOOUR                   R                  US-
  5      nUR                  UR                  R                   R                  5       S9nUR                  US9nSn	Sn
UR                  U 5      UR                  U5      -  nUR                  n/ n/ n/ n[        [        U5      5      nU(       Ga  [        R                  " US5      S   nUR                  U5        US:X  a  UR!                  US-
  U5      U-  S:H  nO'UR!                  US-
  U5      R#                  U5      S:H  nU(       a  M  [%        XS-
  U5      n[%        X&S-
  U5      nUR'                  UUR                  U5      /5      S:X  a  M  [%        XS-
  U5      n[%        XS-
  U5      n[)        UUUU5      nUc  U
S-  n
X:  a  gGM  US:X  a  U$ UR+                  5       /S/US-
  -  -   nUS:  aU  UR-                  5        HA  u  nnUS   US   :X  d  M  UR.                  [1        USS 5      :  d  M2  UR.                  USS& MC     U/nU/nUS:X  a%  UR                  R3                  5       R4                  nO.UR                  R                  R3                  5       R4                  nUR                   R6                  S   n[9        XU5       H9  u  nn n!U!U:X  d  M  UR;                  U5        UR;                  U 5        UUU-
  -  nM;     UR#                  U5      nUR;                  U5        UR;                  U5        UR;                  U5        U	S-  n	[=        UUXFS-
  USS9n"[?        U"UUXS-
  5      n"U"c  GM  US:X  a  UR                  R@                  n#U#R                   R4                  n$U"RC                  5        HZ  nU#R                   RE                  [G        U$RI                  5       URJ                  RI                  5       UU#R                  5      5      n$M\     OUR                  R                  R@                  n#U#R                   R4                  n$U"RC                  5        Hq  nURC                  5        HZ  n%U#R                   RE                  [G        U$RI                  5       U%RJ                  RI                  5       UU#R                  5      5      n$M\     Ms     URM                  U$R#                  U5      5      n$U" U"RO                  U$5      RQ                  5       5      R#                  U5      n"[S        U U"X#5      (       d  [S        UU"X#5      (       d  U"$ U(       a  GM  g)a  
Compute the GCD of two polynomials `f` and `g` in
`\mathbb Z_p(t_1, \ldots, t_k)[z]/(\check m_\alpha(z))[x]`.

The algorithm reduces the problem step by step by evaluating the
polynomials `f` and `g` at `t_k = a` for suitable `a \in \mathbb Z_p`
and then calls itself recursively to compute the GCD in
`\mathbb Z_p(t_1, \ldots, t_{k-1})[z]/(\check m_\alpha(z))[x]`. If these
recursive calls are successful, the GCD over `k` variables is
interpolated, otherwise the algorithm returns ``None``. After
interpolation, Rational Function Reconstruction is used to obtain the
correct coefficients. If this fails, a new evaluation point has to be
chosen, otherwise the desired polynomial is obtained by clearing
denominators. The result is verified with a fraction free trial
division.

Parameters
==========

f, g : PolyElement
    polynomials in `\mathbb Z[t_1, \ldots, t_k][x, z]`
minpoly : PolyElement
    polynomial in `\mathbb Z[t_1, \ldots, t_k][z]`, not necessarily
    irreducible
p : Integer
    prime number, modulus of `\mathbb Z_p`

Returns
=======

h : PolyElement
    primitive associate in `\mathbb Z[t_1, \ldots, t_k][x, z]` of the
    GCD of the polynomials `f` and `g`  or ``None``, coefficients are
    in `\left[ -\frac{p-1} 2, \frac{p-1} 2 \right]`

References
==========

1. [Hoeij04]_

r*   r   r   NT)r   )*r   r   r   r   rX   r   r   r   r\   r   r   r   r4   r   r   r   rt   r   r   r$   _func_field_modgcd_pr   rY   LMtupleget_ringr   r3   r   r   r   r   r   
itercoeffsr]   r   r   r   
domain_newr   as_exprr   )&r   r   r   r"   r   r   r`   qdomainqringr9   r   r,   r}   r   r   LMlistr   r~   testgammaaminpolyar   r   r   r   rb   r5   evalpoints_aheval_arI   r   r   hbLMhbrL   r#   denr   s&                                         r   r   r     s   T 66D[[F&.))LL#A'55Av++&&(++,,QU3--w~~':':'C'C'E-FJJgJ&E	A	A KKNT[[^+EJJEJEF%(^F
MM&!$Q'a6>>!A#q)A-2D>>!A#q)66q9Q>D!%1a0#GqS!4::xQ01Q6a1a(a1a( ""b(A6:FAu7Iiik]aS!A#Y&q5 "u8r!u$E"QR&M)A"XXBqrF !/ s$6%%'++A##,,.22AFFKKNz&9KAr4rz##A&r"a!e	 : NN1!Rb	Q &lGTQ3RVW 1Aq%1E96,,$$C((,,Chh))&AUAUAW3::+' ( (
 ,,%%++C((,,C))+A((--fS\\^QWWEUEUEWszz/+ ,C , (
 s//23c"**,-::1=q!W00Aw9Z9ZHu &x r   c                 f   U S:  a  X-  n XR                   pCXR                  pe[        US-  5      n[        U5      U:  a#  X5-  nXSX-  -
  pSXdX-  -
  pd[        U5      U:  a  M#  [	        [        U5      5      U:  a  gUS:  a  U* U* pO
US:  a  XVpOgUR                  5       nU" U	5      U" U
5      -  $ )ap  
Reconstruct a rational number `\frac a b` from

.. math::

    c = \frac a b \; \mathrm{mod} \, m,

where `c` and `m` are integers.

The algorithm is based on the Euclidean Algorithm. In general, `m` is
not a prime number, so it is possible that `b` is not invertible modulo
`m`. In that case ``None`` is returned.

Parameters
==========

c : Integer
    `c = \frac a b \; \mathrm{mod} \, m`
m : Integer
    modulus, not necessarily prime
domain : IntegerRing
    `a, b, c` are elements of ``domain``

Returns
=======

frac : Rational
    either `\frac a b` in `\mathbb Q` or ``None``

References
==========

1. [Wang81]_

r   r   N)r   r   r   intabs	get_field)r   rI   r   r   r   r   r   rH   r^   r~   r   r   s               r    _integer_rational_reconstructionr    s    H 	1u	

QKE
b'U
h#&[B#&[B b'U

 3r7|u	AvsRC1	a1E8eAhr   c                 ,   UR                   n[        UR                  [        5      (       a  [        nUR                  R
                  nO[        nU R
                  R                  nU R                  5        H  u  pgU" XqU5      nU(       d    gXU'   M     U$ )a  
Reconstruct every rational coefficient `c_h` of a polynomial `h` in
`\mathbb Q[t_1, \ldots, t_k][x, z]` from the corresponding integer
coefficient `c_{h_m}` of a polynomial `h_m` in
`\mathbb Z[t_1, \ldots, t_k][x, z]` such that

.. math::

    c_{h_m} = c_h \; \mathrm{mod} \, m,

where `m \in \mathbb Z`.

The reconstruction is based on the Euclidean Algorithm. In general,
`m` is not a prime number, so it is possible that this fails for some
coefficient. In that case ``None`` is returned.

Parameters
==========

hm : PolyElement
    polynomial in `\mathbb Z[t_1, \ldots, t_k][x, z]`
m : Integer
    modulus, not necessarily prime
ring : PolyRing
    `\mathbb Q[t_1, \ldots, t_k][x, z]`, `h` will be an element of this
    ring

Returns
=======

h : PolyElement
    reconstructed polynomial in `\mathbb Q[t_1, \ldots, t_k][x, z]` or
    ``None``

See also
========

_integer_rational_reconstruction

N)r   r   r   r   #_rational_reconstruction_int_coeffsr   r  rY   )	rK   rI   r   rL   reconstructionr   rb   r5   r   s	            r   r  r    sw    R 			A$++~..<!!9&1% ' Hr   c                    U R                   nUR                  n[        U[        5      (       aM  UR                  nUR                   R                  UR                  R                  5       S9nUR                  US9nO)SnUR                  UR                  R                  5       S9nU R                  5       u  pUR                  5       u  pUR                  U 5      UR                  U5      -  n
UR                  nSn/ n/ n/ n [        U5      nU
R                  U5      S:X  a  M#  US:X  a  X-  S:H  nOUR                  U5      S:H  nU(       a  MN  U R                  U5      nUR                  U5      nUR                  U5      n[        UUUU5      nUc  M  US:X  a  UR                  $ UR                  5       /S/U-  -   nUS:  aU  UR                  5        HA  u  nnUS   US   :X  d  M  UR                   [#        USS 5      :  d  M2  UR                   USS& MC     UnUn[%        XU5       H"  u  nnnUU:X  d  M  ['        UUUU5      nUU-  nM$     UR)                  U5        UR)                  U5        UR)                  U5        [+        UUU5      nUc  GM  US:X  a  UR-                  5       S   nOkUR                  R                  nUR/                  5        H0  nUR                  R1                  UUR-                  5       S   5      nM2     UR3                  U5      nUR5                  U5      nUR                  5       S   n[7        U R3                  U5      UU5      (       d#  [7        UR3                  U	5      UU5      (       d  U$ GM  )a-  
Compute the GCD of two polynomials in
`\mathbb Q(t_1, \ldots, t_k)[z]/(m_{\alpha}(z))[x]` using a modular
algorithm.

The algorithm computes the GCD of two polynomials `f` and `g` by
calculating the GCD in
`\mathbb Z_p(t_1, \ldots, t_k)[z] / (\check m_{\alpha}(z))[x]` for
suitable primes `p` and the primitive associate `\check m_{\alpha}(z)`
of `m_{\alpha}(z)`. Then the coefficients are reconstructed with the
Chinese Remainder Theorem and Rational Reconstruction. To compute the
GCD over `\mathbb Z_p(t_1, \ldots, t_k)[z] / (\check m_{\alpha})[x]`,
the recursive subroutine ``_func_field_modgcd_p`` is used. To verify the
result in `\mathbb Q(t_1, \ldots, t_k)[z] / (m_{\alpha}(z))[x]`, a
fraction free trial division is used.

Parameters
==========

f, g : PolyElement
    polynomials in `\mathbb Z[t_1, \ldots, t_k][x, z]`
minpoly : PolyElement
    irreducible polynomial in `\mathbb Z[t_1, \ldots, t_k][z]`

Returns
=======

h : PolyElement
    the primitive associate in `\mathbb Z[t_1, \ldots, t_k][x, z]` of
    the GCD of `f` and `g`

Examples
========

>>> from sympy.polys.modulargcd import _func_field_modgcd_m
>>> from sympy.polys import ring, ZZ

>>> R, x, z = ring('x, z', ZZ)
>>> minpoly = (z**2 - 2).drop(0)

>>> f = x**2 + 2*x*z + 2
>>> g = x + z
>>> _func_field_modgcd_m(f, g, minpoly)
x + z

>>> D, t = ring('t', ZZ)
>>> R, x, z = ring('x, z', D)
>>> minpoly = (z**2-3).drop(0)

>>> f = x**2 + (t + 1)*x*z + 3*t
>>> g = x*z + 3*t
>>> _func_field_modgcd_m(f, g, minpoly)
x + t*z

References
==========

1. [Hoeij04]_

See also
========

_func_field_modgcd_p

r   r   r*   N)r   r   r   r   rX   r\   r  r@   r   r   r   r   r   r   r   rY   r   r   r   r   r   r  clear_denomsr   r   r   r_   r   )r   r   r   r   r   r`   QQdomainQQringrE   rF   r,   r}   r"   primeshplistr  r  r    r!   minpolypr-   r   rb   r5   rK   rI   r8   r7   LMhqrL   r  s                                  r   _func_field_modgcd_mr  '  s#   D 66D[[F&.))LL;;$$FMM,C,C,E$F8,4;;#8#8#:;KKMEBKKMEB KKNT[[^+EJJE	AFFF
aLa A%6IND&&q)Q.D^^A^^A''*!"b(A6:788Oiik]aSU"q5 "u8r!u$E"QR&M)A"XXBqrF !/ vv6KAr4rzCBAqQQ 7
 	abb0Q?:6!!$A--##Cmm''U-?-?-A!-DE )c"A JJtKKM!R 0!W==ALL,a99H r   c                 0   UR                   n[        UR                  [        5      (       a  UR                  R                  nOUR                  nUR                  nU R                  5        H>  nUR                  5        H'  nU(       d  M  UR                  XFR                  5      nM)     M@     U R                  5        H  u  puUR                  5       nUR                  R                  n[        UR                  [        5      (       a  UR                  USS 5      n[        U5      n	[        U	5       H]  n
XZ   (       d  M  UR                  XZ   U-  5      U-  nUS   X-
  S-
  4U;  a  XbUS   X-
  S-
  4'   MG  X'S   X-
  S-
  4==   U-  ss'   M_     M     U$ )a:  
Compute an associate of a polynomial
`f \in \mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]` in
`\mathbb Z[x_1, \ldots, x_{n-1}][z] / (\check m_{\alpha}(z))[x_0]`,
where `\check m_{\alpha}(z) \in \mathbb Z[z]` is the primitive associate
of the minimal polynomial `m_{\alpha}(z)` of `\alpha` over
`\mathbb Q`.

Parameters
==========

f : PolyElement
    polynomial in `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]`
ring : PolyRing
    `\mathbb Z[x_1, \ldots, x_{n-1}][x_0, z]`

Returns
=======

f_ : PolyElement
    associate of `f` in
    `\mathbb Z[x_1, \ldots, x_{n-1}][x_0, z]`

r*   Nr   )r   r   r   r   r   r   to_listr   denominatorrY   r   lenr4   convert)r   r   f_r   r  r5   r   rb   rI   r9   r<   s              r   _to_ZZ_polyr#    sP   2 
B$++~..##
**CAqjjmm4 !  
 KKOOdkk>22E!"I&AJqAxxNN58c>2Q6!Hac!e$B.,-a!#a%()a!#a%()Q.)  &  Ir   c                 $   UR                   nUR                  n[        U R                  R                   [        5      (       av  U R                  5        H`  u  pEUR                  5        HG  u  pgUS   4U-   nU" UR                  U5      /S/US   -  -   5      n	X;  a  XU'   M;  X8==   U	-  ss'   MI     Mb     U$ U R                  5        HD  u  pEUS   4nU" UR                  U5      /S/US   -  -   5      n	X;  a  XU'   M8  X8==   U	-  ss'   MF     U$ )a.  
Convert a polynomial
`f \in \mathbb Z[x_1, \ldots, x_{n-1}][z]/(\check m_{\alpha}(z))[x_0]`
to a polynomial in `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]`,
where `\check m_{\alpha}(z) \in \mathbb Z[z]` is the primitive associate
of the minimal polynomial `m_{\alpha}(z)` of `\alpha` over
`\mathbb Q`.

Parameters
==========

f : PolyElement
    polynomial in `\mathbb Z[x_1, \ldots, x_{n-1}][x_0, z]`
ring : PolyRing
    `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]`

Returns
=======

f_ : PolyElement
    polynomial in `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]`

r   r*   )r   r   r   r   r   rY   )
r   r   r   r"  rb   r5   r   coefrI   r   s
             r   _to_ANP_polyr&    s   0 [[F	B!&&--00KKMLE"__.	1XK#%FMM$/0A3uQx<?@;qEEQJE / *( I KKMLEqAe,-E!H<=A{1
 * Ir   c                 v    UR                   nU R                  5        H  u  p4UR                  U5      X#'   M     U$ )zc
Change representation of the minimal polynomial from ``DMP`` to
``PolyElement`` for a given ring.
)r   termsr   )r   r   minpoly_rb   r5   s        r   _minpoly_from_denser*  0  s6    
 yyH++e, ( Or   c                    U R                   nUR                  " [        SUR                  5      6 nUR                  R                   nU" U R                  5       5      nUR                  nUR                  5        H%  n[        XV5      S   nXSR                  :X  d  M"  XP4s  $    XPR                  UR                  U5      5      4$ )z
Compute the content in `x_0` and the primitive part of a polynomial `f`
in
`\mathbb Q(\alpha)[x_0, x_1, \ldots, x_{n-1}] \cong \mathbb Q(\alpha)[x_1, \ldots, x_{n-1}][x_0]`.
r*   r   )r   r   r4   rX   r   r   r   r   func_field_modgcdr   r^   r_   )r   fringr   r#   r"  rc   r5   s          r   _primitive_in_x0r.  =  s     FFEq%++!67D
++

C	aiik	B88D -a077?7N !
 t}}U+,,,r   c                 6   U R                   nUR                  nUR                  nX!R                   :X  a  UR                  (       d   e[	        X5      nUb  U$ [        S5      nUR                  UR                  U4-   UR                  R                  5       S9nUS:X  af  [        X5      n[        X5      n	UR                  S5      R                  UR                  R                  5       5      n
[        XU
5      n[        X5      nO[!        U 5      u  p[!        U5      u  p[#        X5      S   nUR$                  " ['        SU5      6 n[        X5      n[        X5      n	[)        UR                  UR                  S5      5      n
[        XU
5      n[        X5      n[!        U5      u  nnXR+                  U5      -  nXR+                  U5      -  n XR+                  U5      -  nUR-                  UR.                  5      nXR1                  U5      UR1                  U5      4$ )a
  
Compute the GCD of two polynomials `f` and `g` in
`\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]` using a modular algorithm.

The algorithm first computes the primitive associate
`\check m_{\alpha}(z)` of the minimal polynomial `m_{\alpha}` in
`\mathbb{Z}[z]` and the primitive associates of `f` and `g` in
`\mathbb{Z}[x_1, \ldots, x_{n-1}][z]/(\check m_{\alpha})[x_0]`. Then it
computes the GCD in
`\mathbb Q(x_1, \ldots, x_{n-1})[z]/(m_{\alpha}(z))[x_0]`.
This is done by calculating the GCD in
`\mathbb{Z}_p(x_1, \ldots, x_{n-1})[z]/(\check m_{\alpha}(z))[x_0]` for
suitable primes `p` and then reconstructing the coefficients with the
Chinese Remainder Theorem and Rational Reconstruction. The GCD over
`\mathbb{Z}_p(x_1, \ldots, x_{n-1})[z]/(\check m_{\alpha}(z))[x_0]` is
computed with a recursive subroutine, which evaluates the polynomials at
`x_{n-1} = a` for suitable evaluation points `a \in \mathbb Z_p` and
then calls itself recursively until the ground domain does no longer
contain any parameters. For
`\mathbb{Z}_p[z]/(\check m_{\alpha}(z))[x_0]` the Euclidean Algorithm is
used. The results of those recursive calls are then interpolated and
Rational Function Reconstruction is used to obtain the correct
coefficients. The results, both in
`\mathbb Q(x_1, \ldots, x_{n-1})[z]/(m_{\alpha}(z))[x_0]` and
`\mathbb{Z}_p(x_1, \ldots, x_{n-1})[z]/(\check m_{\alpha}(z))[x_0]`, are
verified by a fraction free trial division.

Apart from the above GCD computation some GCDs in
`\mathbb Q(\alpha)[x_1, \ldots, x_{n-1}]` have to be calculated,
because treating the polynomials as univariate ones can result in
a spurious content of the GCD. For this ``func_field_modgcd`` is
called recursively.

Parameters
==========

f, g : PolyElement
    polynomials in `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]`

Returns
=======

h : PolyElement
    monic GCD of the polynomials `f` and `g`
cff : PolyElement
    cofactor of `f`, i.e. `\frac f h`
cfg : PolyElement
    cofactor of `g`, i.e. `\frac g h`

Examples
========

>>> from sympy.polys.modulargcd import func_field_modgcd
>>> from sympy.polys import AlgebraicField, QQ, ring
>>> from sympy import sqrt

>>> A = AlgebraicField(QQ, sqrt(2))
>>> R, x = ring('x', A)

>>> f = x**2 - 2
>>> g = x + sqrt(2)

>>> h, cff, cfg = func_field_modgcd(f, g)

>>> h == x + sqrt(2)
True
>>> cff * h == f
True
>>> cfg * h == g
True

>>> R, x, y = ring('x, y', A)

>>> f = x**2 + 2*sqrt(2)*x*y + 2*y**2
>>> g = x + sqrt(2)*y

>>> h, cff, cfg = func_field_modgcd(f, g)

>>> h == x + sqrt(2)*y
True
>>> cff * h == f
True
>>> cfg * h == g
True

>>> f = x + sqrt(2)*y
>>> g = x + y

>>> h, cff, cfg = func_field_modgcd(f, g)

>>> h == R.one
True
>>> cff * h == f
True
>>> cfg * h == g
True

References
==========

1. [Hoeij04]_

z)rW   r   r*   r   )r   r   rX   is_Algebraicr   r   r\   rW   r   r#  r   r]   modr  r  r&  r.  r,  r   r4   r*  r_   rA   r   r^   )r   r   r   r   r9   rD   r0  ZZringr"  g_r   rL   contx0fcontx0gcontx0hZZring_contx0h_s                    r   r,  r,  R  s   P 66D[[F

A66>f1111!Fc
AZZt 3FMM<R<R<TZUFAv##++a.++FJJ,>,>,@A 1! &a(
%a(
#G5a8''q!5$$%fjj',,q/B 1!&q)!	d##	d##	d##	QTTAeeAha  r   )F)N)3sympy.core.symbolr   sympy.ntheoryr   sympy.ntheory.modularr   sympy.polys.domainsr   sympy.polys.galoistoolsr   r	   r
   r   r   sympy.polys.polyerrorsr   mpmathr   r   r   r(   r/   r=   rS   rf   rj   rn   rr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r#  r&  r*  r.  r,   r   r   <module>rB     s    # # % .4 4 3  ,?.B>B~B:.z-`2j	H5V`F>BQhVrPf@?DCLF@>5*pBJcL=@:zYx7t0f
-*T!r   