
    wgL                     4   d dl mZ d dlmZ d dlmZ d dlmZ d dlm	Z	m
Z
mZmZmZ d dlmZ d dlmZ d dlZd	 Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd)dZd Zd Z d Z!d Z"d Z#d Z$d Z%d Z&d Z'd*dZ(d Z)d  Z*d! Z+d" Z,d# Z-d$ Z.d% Z/d& Z0d' Z1d( Z2y)+    )Dummy)	nextprimecrt)PolynomialRing)gf_gcdgf_from_dictgf_gcdexgf_divgf_lcm)ModularGCDFailed)sqrtNc                    | j                   }| s%|s#|j                  |j                  |j                  fS | sW|j                  |j                  j                  k  r| |j                  |j                   fS ||j                  |j                  fS |sW| j                  |j                  j                  k  r|  |j                   |j                  fS | |j                  |j                  fS y)zn
    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      [/home/mcse/projects/flask/flask-venv/lib/python3.12/site-packages/sympy/polys/modulargcd.py_trivial_gcdr      s    
 66Dyy$))TYY..44$++"""2tyy488)++dii))44$++"""2y$))++dhh		))    c                    | j                   j                  }|r| }|j                         }|j                  |j                  |      }	 |j                         }||k  rnD||j                  ||z
  f      j                  ||j                  z        z
  j                  |      }Z|} |}|r| j                  |j                  | j                  |            j                  |      S )zM
    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   | j                   j                  j                  | j                  |j                        }d}t	        |      }||z  dk(  rt	        |      }||z  dk(  r| j                  |      }|j                  |      }t        |||      }|j                         }|S )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	R	BIIKELr   c           	      D   | j                         }| j                  j                  d   }| j                  j                  }t	        |dz         D ]?  }t        ||g| j                  ||z        |j                  ||z        gd      d   ||f<   A |j                          |S )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 UA!Q$!Q$ @DQRSTQD	U NNJr   c                    | j                   |j                   k(  r | j                   j                  j                  sJ t        | |      }||S | j                   }| j	                         \  }} |j	                         \  }}|j                  j                  ||      }t        | |      }|dk(  r/ ||      | j                  ||z        |j                  ||z        fS |j                  j                  | j                  |j                        }d}	d}
	 t        |
      }
||
z  dk(  rt        |
      }
||
z  dk(  r| j                  |
      }|j                  |
      }t        |||
      }|j                         }||kD  rm||k  rd}	|}w|j                  |      j                  |
      }|	dk(  r|
}	|}t        ||
|	      }|	|
z  }	||k(  s|}|j                  |j                               }| j!                  |      \  }}|j!                  |      \  }}|sR|sP|j                  dk  r| }|j                  |      }|j                  ||z        }|j                  ||z        }|||fS X)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      sI   F 66QVV 3 333!QF66DKKMEBKKMEB	R	 B$Q*EzBxbBh/bBh1GGGKKOOADD!$$'E	A	A
aLai1n!A ai1n ^^A^^ARQ		5=U]AE]]5!..q16AF9"faK	QV|FMM"**,'UU1X
dUU1X
dDttaxSR A//"(+C//"(+Cc3;O r   c           	         | j                   }|j                  }|j                  }i }| j                         D ]"  \  }}|dd |vri ||dd <   |||dd    |d   <   $ g }t	        |j                               D ]  }t        |t        |||      ||      } |j                  |j                  |dz
           }	|	j                  |      j                  |      }
|
| j                  |
j                  |            fS )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 .u":V#!#F5":(-uSbz59%.
 Dfmmo& AdL37C@A JJt||AaC0J1ET"//2E!%%t,---r   c                     | j                   j                  }d|dz
  z  }| j                         D ]  }|dd |kD  s|dd } |S )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  sT    P 	
A1Q3<D ":":D Kr   c                 $   | j                   }|j                  }|j                  |j                  |dz
           }|j                  d   }t        |       }|j                  }| j                         D ]  \  }}|dd |k(  s||||d   z  z  z  } |S )a  
    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 &u":5E"I%%C& Jr   c                     | j                   }|j                  }| j                         D ]  \  }}||   f|d| z   ||dz   d z   }|||<   ! |S )zS
    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     se     66DIIE !u1XK%)+eAaCDk9	 i! Lr   c                    | j                   }|j                  j                  | j                  |j                        }|j                  j                  t	        | d      j                  t	        |d      j                        }||z  }d}t        |      }||z  dk(  rt        |      }||z  dk(  r| j                  |      }|j                  |      }t        ||      \  }	}t        ||      \  }
}t        |	|
|      }|j                         }t        t        |      t        |      |      }t        |      D ]|  }|j                  d|      |z  s|j                  d|      j                  |      }|j                  d|      j                  |      }t        |||      }|j                         }||fc S  t        |j                         |j                               |fS )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
a-1
aL a-1
 
	B	
	BB"JFBB"JFBVVQ'FJ CGSWa(E1X "~~a#a'kk!Q,,Q/kk!Q,,Q/c3"z!!" ryy{BIIK(*44r   c                 .   t        | j                               }t        |j                               }|j                  |      }|j                  |       |j                  |       | j                  j
                  j                  }| j                  j                  }t        | j                  j
                  t              rt        }	nd }	|D ]  }
 |	| |
   ||
   ||      ||
<    |D ]  }
 |	| |
   |||      ||
<    |D ]  }
 |	|||
   ||      ||
<    |S )a:  
    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                 ,    t        ||g| |gd      d   S )NTr1   r   r   )cpcqr"   r8   s       r   crt_z<_chinese_remainder_reconstruction_multivariate.<locals>.crt_k  s    1vBx48;;r   )
setmonomsintersectiondifference_updater   r   r   
isinstancer   ._chinese_remainder_reconstruction_multivariate)r-   r7   r"   r8   hpmonomshqmonomsr   r   r;   r   rb   s              r   r   r     s   P 299;H299;H""8,Fv&v&77>>D
'',,C"''...1=	<  6"U)RY15E
6 1"U)T1a0E
1 1$5	1a0E
1 Jr   c                    |j                   }|r0|j                  j                  }|j                  j                  |   }n|j                  }|j                  |   }t        | |      D ]t  \  }	}
|j                  }|j                  }| D ]  }||	k(  r	|||z
  z  }||	|z
  z  } |j                  ||      }|j                  |      }||
j                  |      |z  z  }v |j                  |      S )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   x  s    N 
B##KKQIIaLj&) )3

 	AAvQUNEQUNE	 eQ'  '
cll4 5(() ??1r   c                 
   | j                   |j                   k(  r | j                   j                  j                  sJ t        | |      }||S | j                   }| j	                         \  }} |j	                         \  }}|j                  j                  ||      }t        | |      \  }}||cxk(  rdk(  r2n n/ ||      | j                  ||z        |j                  ||z        fS t        | d      }	t        |d      }
|	j                         }|
j                         }t        |	|
      \  }}||cxk(  rdk(  r2n n/ ||      | j                  ||z        |j                  ||z        fS |j                  j                  | j                  |j                        }|j                  j                  |	j                  |
j                        }||z  }d}d}	 t        |      }||z  dk(  rt        |      }||z  dk(  r| j                  |      }|j                  |      }t        ||      \  }}t        ||      \  }}t        |||      }|j                         }||kD  r||k  rd}|}t        t        |      t        |      |      }|j                         }|j                         }|j                         }t!        ||z
  ||z
  ||z
  |z         dz   }||k  rd}g } g }!d}"t#        |      D ]  }#|j%                  d|#      }$|$|z  s|j%                  d|#      j                  |      }%|j%                  d|#      j                  |      }&t        |%|&|      }'|'j                         }(|(|kD  r|(|k  rd}|(}d}" nP|'j                  |$      j                  |      }'| j'                  |#       |!j'                  |'       |dz  }||k(  s n |"r||k  rt)        | |!|d|      })t        |)|      d   })|)|j+                  |      z  })|)j                  d      }*|*|kD  rL|*|k  rd}|*}W|)j                  |      j                  |      })|dk(  r|}|)}+t-        |)+||      },||z  }|,|+k(  s|,}+|,j/                  |,j1                               }-| j3                  |-      \  }.}/|j3                  |-      \  }0}1|/sR|1sP|-j                  dk  r| }|-j                  |      }-|.j                  ||z        }2|0j                  ||z        }3|-|2|3fS :)a!  
    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!QF66DKKMEBKKMEB	R	 B0A6FJ q BxbBh/bBh1GGG!QKE!QKELLNELLNE0>FJ q BxbBh/bBh1G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Z(*,./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                    | j                   }|j                  }|dk(  rJt        | ||      j                  |      }|j	                         }||d   kD  ry||d   k  r||d<   t
        |S | j	                  |dz
        }	|j	                  |dz
        }
t        | |      \  }} t        ||      \  }}t        |||      }|j	                         }|j	                         }|j	                         }|||dz
     kD  ry|||dz
     k  r|||dz
  <   t
        t        |       }t        |      }t        |||      }|}t        |dz
        D ]8  }|t        t        t        | |            t        t        ||            |      z  }: |j	                         }t        |	|z
  |
|z
  ||dz
     ||dz
     z
  |z         dz   }||k  ryd}d}g }g }t        t        |            }|rt        j                  |d      d   }|j                  |       |j                  d|      |z  sC|j                  d|      |z  }| j                  |dz
  |      j                  |      }|j                  |dz
  |      j                  |      } t!        || |||      }!|!|dz  }||kD  ry|!j"                  r"|j%                  |      j                  |      }|S |!j'                  |      j                  |      }!|j)                  |       |j)                  |!       |dz  }||k(  rnt+        ||||dz
  |      }t        ||      d   |j%                  |      z  }|j	                  |dz
        }"|"||dz
     kD  ry|"||dz
     k  r|"||dz
  <   t
        |S |ry)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     s   ` 66D

AAvAq!))!,xxz(1+(1+HQK""HHQqSMEHHQqSME!QHE1!QHE1E5!$E||~H||~H||~H)AaC. )AaC. !	!A#
a&C
a&CCa EH1Q3Z CGCa,c%1+.>BBC ||~HEHeh.QqSMIacN*X5	79:	;A 	1u	A	AJE%(^F
MM&!$Q'a  A&*1%)ZZ!Q,,Q/ZZ!Q,,Q/ $BAxC:FA1u<<t$11!4AH]]6"//2!R	Q6)*eT1Q3JA1a #ennT&::AHHQqSMEx!}$x!}$ %1&&HW Z r   c           	         | j                   |j                   k(  r | j                   j                  j                  sJ t        | |      }||S | j                   }|j                  }| j                         \  }} |j                         \  }}|j                  j                  ||      }|j                  j                  | j                  |j                        }|j                  j                  }	t        |      D ]I  }
|	|j                  j                  t        | |
      j                  t        ||
      j                        z  }	K t        | j                         |j                               D cg c]  \  }}t        ||       }}}t        |      }d}d}	 t        |      }|	|z  dk(  rt        |      }|	|z  dk(  r| j!                  |      }|j!                  |      }	 t#        |||||      }|]|j'                  |      j!                  |      }|dk(  r|}|}t)        |||      }||z  }||k(  s|}|j                         d   }| j+                  |      \  }}|j+                  |      \  }}|sR|sP|j                  dk  r| }|j'                  |      }|j'                  ||z        }|j'                  ||z        }|||fS 2c c}}w # t$        $ r d}Y Gw xY w)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!QF66D

A KKMEBKKMEB	R	 BKKOOADD!$$'EI1X ET[[__U1a[^^U1a[^^DD	E 36aiik199;2OPJD$D$PHPXI	A	A
aL!mq !A !mq  ^^A^^A	'B8Y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   .K	!K KKc                     | j                   }t        | j                         |j                         ||j                        \  }}|j	                  |      |j	                  |      fS )z_
    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     sO    
 66D

ajjlAt{{KHh??8$dooh&???r   c                    | j                   }|j                  }|j                         }|dz  }||z
  dz
  }||j                  }	}| |j                  }}
|
j                         |kD  rVt        ||
|      d   }|
|||
z  z
  j                  |      }
}||	||z  z
  j                  |      }}	|
j                         |kD  rV|
|}}|j                         |kD  st        |||      dk7  ry|j                  }|dk7  rR|j                  ||      }|j                  |      j                  |      }|j                  |      j                  |      }|j                         } ||       ||      z  S )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     sT   J 66D[[F	
A	QA	A	A		BB
))+/b"a #b3r6k//2Bb3r6k//2B ))+/
 rqAxxzA~Aq)Q.	
B	Qwb!$LL,,Q/LL,,Q/MMOE8eAhr   c                 ,   |j                   }| j                         D ]t  \  }}|dk(  rt        |||      }|sV y|j                  j                   }|j	                  |      j                         D ]  \  }	}
t        |
||      }|s  y|||	<    |||<   v |S )a  
    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 u66uaCF [[%%F..q1;;= !Q6q!Q? s! %#& Hr   c                     | j                   }t        | j                         |j                         ||j                        \  }}}|j	                  |      |j	                  |      |j	                  |      fS )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   K  s[     66Dqzz|QZZ\1dkkBGAq!??1tq14??13EEEr   c                     | j                   }|j                  |      }|j                  |      }| j                  |      j	                  ||g      j                  |      S )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   Y  sT    0 66Dt$G		B>>!  '2/<<Q??r   c                    | j                   }t        | ||      } t        |||      }|r| }|j                  d      }t        |j	                  |      ||      \  }}}	|	dk(  sy	 |j                  d      }
|
|k  rnK||j	                  |      z  j                  |      }t        ||j                  |
|z
  df      |z  z
  ||      }b|} |}|rt        |j	                  |       ||      d   j                  |      }t        | |z  ||      S )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   x  s   8 66Dq'1Aq'1A
hhqk!$++a.'1=q#axZZ]F|4;;s++55d;Cq{{FSL!+<=cAA7ANC  ! $ t{{1~w215>>tDF!f*gq))r   c                 V   | j                   }|j                  |j                  d   |j                  d   f      }|j                  |      }| }|j	                         }|j	                         }|j	                  d      }	t        |      j                  |      }
|j                  }|r||k\  rt        |      j                  |      }||
z  |j                  ||z
  df      |z  z
  }|r|j                  |      }|j	                  d      }|r||	k\  rt        |j                  |            j                  |      }|j                  |      |j                  d||	z
  f      |z  z
  }|r|j                  |      }|j	                  d      }|r||	k\  r|j	                         }|r||k\  r|S )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     s   B 66DZZa$,,q/ BZCFt$G
CZZ\F88:D>>!D
a&//$
C
**C
&D.C!!$'#gVd]A$67==""1%CAfnV,-66t<E..%(9(91ftm:L(Me(SSC&&q)ZZ]F fn ! &D.$ Jr   c                 
   | j                   j                  | j                   j                  j                   j                  |            }|j                  }| j                         D ]  \  }}|j                  ||      ||<    |S )z[
    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     sn    
 66<<qvv}}1166q9<:D	B )uNN1a(5	) Ir   c           
         | j                   }|j                  }t        |t              r|j                  }nt        | |||      S |dk(  r|j                   j                         }nR|j                   j                  |dz
        }|j                  |j                  j                   j                               }|j                  |      }d}	d}
|j                  |       |j                  |      z  }|j                  }g }g }g }t        t        |            }|rht        j                  |d      d   }|j                  |       |dk(  r|j!                  |dz
  |      |z  dk(  }n'|j!                  |dz
  |      j#                  |      dk(  }|rxt%        ||dz
  |      }t%        ||dz
  |      }|j'                  ||j                  |      g      dk(  rt%        | |dz
  |      }t%        ||dz
  |      }t)        ||||      }||
dz  }
|
|	kD  ry|dk(  r|S |j+                         gdg|dz
  z  z   }|dkD  rO|j-                         D ]<  \  }}|d   |d   k(  s|j.                  t1        |dd       kD  s.|j.                  |dd > |g}|g}|dk(  r%|j                  j3                         j4                  }n.|j                  j                  j3                         j4                  }|j                   j6                  d   }t9        |||      D ]6  \  }} }!|!|k(  s|j;                  |       |j;                  |        |||z
  z  }8 |j#                  |      }|j;                  |       |j;                  |       |j;                  |       |	dz  }	t=        ||||dz
  |d      }"t?        |"||||dz
        }"|"|dk(  r|j                  j@                  }#|#j                   j4                  }$|"jC                         D ]Y  }|#j                   jE                  tG        |$jI                         |jJ                  jI                         ||#j                              }$[ n|j                  j                  j@                  }#|#j                   j4                  }$|"jC                         D ]n  }|jC                         D ]Y  }%|#j                   jE                  tG        |$jI                         |%jJ                  jI                         ||#j                              }$[ p |jM                  |$j#                  |            }$ ||"jO                  |$      jQ                               j#                  |      }"tS        | |"||      stS        ||"||      s|"S |rhy)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#Aq'1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#GQqS!4::xQ01Q6a1a(a1a( ""b(A6:FA1u7Iiik]aS!A#Y&q5 " &u8r!u$E"QR&M)A"XXBqrF& s$6%%'++A##,,.22AFFKKNz5&9 	KAr4rz##A&r"a!e		 NN1!Rb	Q &lGT1Q3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!Wa0AwXY9ZHu x r   c                 v   | dk  r| |z  } ||j                   }}| |j                  }}t        |dz        }t        |      |k\  r(||z  }||||z  z
  }}||||z  z
  }}t        |      |k\  r(t	        t        |            |k\  ry|dk  r| | }
}	n|dkD  r||}
}	ny|j                         } ||	       ||
      z  S )a  
    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B

BQKE
b'U
BhR#b&[BR#b&[B b'U

 3r7|u	AvsRC1	a21E8eAhr   c                    |j                   }t        |j                  t              rt        }|j                  j
                  }nt        }| j
                  j                  }| j                         D ]  \  }} ||||      }|s y|||<    |S )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    s    R 			A$++~.<!!9 uq&1% Hr   c                    | j                   }|j                  }t        |t              rS|j                  }|j                   j                  |j                  j                               }|j                  |      }n,d}|j                  |j                  j                               }| j                         \  }} |j                         \  }	}|j                  |       |j                  |      z  }
|j                  }d}g }g }g }	 t        |      }|
j                  |      dk(  r!|dk(  r	||z  dk(  }n|j                  |      dk(  }|rF| j                  |      }|j                  |      }|j                  |      }t        ||||      }||dk(  r|j                  S |j                         gdg|z  z   }|dkD  rO|j                         D ]<  \  }}|d   |d   k(  s|j                   t#        |dd       kD  s.|j                   |dd > |}|}t%        |||      D ]  \  }}}||k(  st'        ||||      }||z  }! |j)                  |       |j)                  |       |j)                  |       t+        |||      }|~|dk(  r|j-                         d   }ni|j                  j                  }|j/                         D ]/  }|j                  j1                  ||j-                         d         }1 |j3                  |      }|j5                  |      }|j                         d   }t7        | j3                  |      ||      st7        |j3                  |	      ||      s|S _)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  &  s3   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AIND&&q)Q.D^^A^^A''*!"b(A6:788Oiik]aSU"q5 " &u8r!u$E"QR&M)A"XXBqrF& vvv6 	KAr4rzCBAqQQ	
 	abb0Q?:6!!$A--##C Fmm''U-?-?-A!-DEFc"A JJtKKM!R 0!W=ALL,a9H r   c                     |j                   }t        |j                  t              r|j                  j                  }n|j                  }|j                  }| j                         D ]6  }|j                         D ]!  }|s|j                  ||j                        }# 8 | j                         D ]  \  }}|j                         }|j                  j                  }t        |j                  t              r|j                  |dd       }t        |      }	t        |	      D ]Z  }
||
   s	|j                  ||
   |z        |z  }|d   |	|
z
  dz
  f|vr|||d   |	|
z
  dz
  f<   C||d   |	|
z
  dz
  fxx   |z  cc<   \  |S )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"    sl   2 
B$++~.##
**C 5 	5Ajjamm4	55
  /uKKOOdkk>2E!"I&AJq 	/AQxNN58c>2Q6!Hac!e$B.,-Ba!A#a%()a!A#a%()Q.)	//  Ir   c                    |j                   }|j                  }t        | j                  j                   t              rt| j                         D ]_  \  }}|j                         D ]G  \  }}|d   f|z   } ||j                  |      gdg|d   z  z         }	||vr|	||<   ;||xx   |	z  cc<   I a |S | j                         D ]D  \  }}|d   f} ||j                  |      gdg|d   z  z         }	||vr|	||<   8||xx   |	z  cc<   F |S )ar  
    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KKM 	LE5"__. 	T1XK#%FMM$/0A3uQx<?@B;BqEqEQJE	( I KKM 	LE5qAe,-E!H<=A{11
	 Ir   c                 v    |j                   }| j                         D ]  \  }}|j                  |      ||<    |S )zo
    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)  /  s?    
 yyH -u++e,- Or   c                    | j                   } |j                  t        d|j                         }|j                  j                   } || j                               }|j                  }|j                         D ]&  }t        ||      d   }||j                  k(  s"|| fc S  || j                  |j                  |            fS )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5q%++!67D
++

C	aiik	B88D  u-a0377?7N
 t}}U+,,,r   c                 N   | j                   }|j                  }|j                  }||j                   k(  r|j                  sJ t	        | |      }||S t        d      }|j                  |j                  |fz   |j                  j                               }|dk(  rjt        | |      }t        ||      }	|j                  d      j                  |j                  j                               }
t        ||	|
      }t        ||      }nt!        |       \  }} t!        |      \  }}t#        ||      d   } |j$                  t'        d|       }t        | |      }t        ||      }	t)        |j                  |j                  d            }
t        ||	|
      }t        ||      }t!        |      \  }}||j+                  |      z  }| |j+                  |      z  } ||j+                  |      z  }|j-                  |j.                        }|| j1                  |      |j1                  |      fS )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 Reconstuction. 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   r/  ZZringr!  g_r   rL   contx0fcontx0gcontx0hZZring_contx0h_s                    r   r+  r+  Q  s   P 66D[[F

A166>f1111!QFc
AZZt 3FMM<R<R<TZUFAvF#F#++a.++FJJ,>,>,@A R1D! &a(
%a(
#GW5a8'&''q!5G$G$%fjj',,q/B R1D!&q)!	Wd##	Wd##	Wd##	QTTAaeeAh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>rA     s    # # % .4 4 3  ,?.B>B~B:.z-`2j	H5V_D>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   