B
    dd(                 @   st  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	d
 Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd ZdJd d!Zd"d# Zd$d% Z d&d' Z!d(d) Z"d*d+ Z#d,d- Z$d.d/ Z%d0d1 Z&d2d3 Z'dKd4d5Z(d6d7 Z)d8d9 Z*d:d; Z+d<d= Z,d>d? Z-d@dA Z.dBdC Z/dDdE Z0dFdG Z1dHdI Z2dS )L    )Dummy)	nextprime)crt)PolynomialRing)gf_gcdgf_from_dictgf_gcdexgf_divgf_lcm)ModularGCDFailed)sqrtNc             C   s   | j }| s|s|j|j|jfS | sR|j|jjk rB| |j|j fS ||j|jfS n2|s| j|jjk rv|  |j |jfS | |j|jfS dS )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    r   c/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/sympy/polys/modulargcd.py_trivial_gcd   s    r   c             C   s   | j j}xh|rp| }| }||j|}x<| }||k r<P |||| f||j  |}q*W |} |}q
W | || 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degremr   r   r   _gf_gcd#   s    *r$   c             C   sf   | j j| j|j}d}t|}x|| dkr8t|}q"W | |}||}t|||}| }|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deghpr   r   r   _degree_bound_univariate:   s    

r*   c             C   sr   |   }| jjd }| jj}xHt|d D ]8}t||g| || ||| gddd ||f< q*W |  |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   coeffZ
strip_zero)r(   hqr   qnxhpqir   r   r   ,_chinese_remainder_reconstruction_univariate[   s    68r5   c             C   s  | j |j kr| j jjstt| |}|dk	r0|S | j }|  \}} | \}}|j||}t| |}|dkr||| || ||| fS |j| j	|j	}d}	d}
x.t
|
}
x||
 dkrt
|
}
qW | |
}||
}t|||
}| }||krqn||k rd}	|}q|||
}|	dkr>|
}	|}qt|||
|	}|	|
9 }	||ksd|}q|| }| |\}}||\}}|s|s|j	dk r| }||}||| }||| }|||fS qW dS )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]_

    Nr   r%   )r   r   is_ZZAssertionErrorr   	primitiver&   r*   r   r   r   r   r$   r   r5   
quo_groundcontentdiv)r   r   resultr   cfcgchboundr'   mr   r   r   r(   r)   hlastmhmhfquofremgquogremcffcfgr   r   r   modgcd_univariate   s`    C

"






rK   c             C   s   | j }|j}|j}i }xL|  D ]@\}}|dd |krHi ||dd < |||dd  |d < q W g }x*t| D ]}t|t|||||}qvW |j|j	|d  d}	|	
||}
|
| |
|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   clonerM   
from_denser   quoset_ring)r   r   r   r   kZcoeffsmonomr.   contyringcontfr   r   r   
_primitive  s    )r[   c             C   sF   | j j}d|d  }x,|  D ] }|dd |kr|dd }qW |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%   NrL   )r   rN   Z
itermonoms)r   rV   degfrW   r   r   r   _degZ  s    (r]   c       	      C   sx   | j }|j}|j|j|d  d}|jd }t| }|j}x8|  D ],\}}|dd |krD||||d   7 }qDW |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%   )rM   r   NrL   )r   rN   rR   rM   r,   r]   r   rO   )	r   r   rV   rY   yr\   lcfrW   r.   r   r   r   _LC  s    (
r`   c             C   sT   | j }|j}xB|  D ]6\}}|| f|d|  ||d d  }|||< qW |S )zS
    Make the variable `x_i` the leading one in a multivariate polynomial `f`.
    Nr%   )r   r   rO   )r   r4   r   fswaprW   r.   Z	monomswapr   r   r   _swap  s    &rb   c             C   s4  | j }|j| j|j}|jt| djt|dj}|| }d}t|}x|| dkrbt|}qLW | |}||}t||\}	}t||\}
}t|	|
|}|	 }tt
|t
||}x`t|D ]T}|d|| sq|d||}|d||}t|||}|	 }||fS W t|	 |	 |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   rb   r   r   r[   r$   r   r`   r-   evaluatemin)r   r   r   gamma1gamma2	badprimesr   r   r   contfpcontgpconthp
ycontbounddeltaafpagpahpaxboundr   r   r   _degree_bound_bivariate  s0    *


rr   c             C   s   t |  }t | }||}|| || | jjj}| jj}t| jjtr\t	}	ndd }	x&|D ]}
|	| |
 ||
 ||||
< qjW x"|D ]}
|	| |
 |||||
< qW x"|D ]}
|	|||
 ||||
< qW |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             S   s   t ||g| |gddd S )NT)r+   r   )r   )cpZcqr   r0   r   r   r   crt_k  s    z<_chinese_remainder_reconstruction_multivariate.<locals>.crt_)
setmonomsintersectiondifference_updater   r   r   
isinstancer   ._chinese_remainder_reconstruction_multivariate)r(   r/   r   r0   ZhpmonomsZhqmonomsrv   r   r3   rt   rW   r   r   r   rz     s"    H






rz   Fc             C   s   |j }|r |jj}|jj| }n|j}|j| }xzt| |D ]l\}	}
|j}|j}x.| D ]&}||	krdqV||| 9 }||	| 9 }qVW |||}||}||
|| 7 }q<W ||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   r,   zipr   r   r   rU   r   )
evalpointshpevalr   r4   r   groundr(   r   r^   rm   rp   Znumerdenombr.   r   r   r   _interpolate_multivariatex  s$    '


r   c       4      C   sL  | j |j kr| j jjstt| |}|dk	r0|S | j }|  \}} | \}}|j||}t| |\}}||  kr~dkrn n"||| || ||| fS t	| d}	t	|d}
|	
 }|

 }t|	|
\}}||  krdkrn n"||| || ||| fS |j| j|j}|j|	j|
j}|| }d}d}xt|}x|| dkrnt|}qTW | |}||}t||\}}t||\}}t|||}|
 }||krĐqJn||k rd}|}qJtt|t||}|
 }|
 }|
 }t|| || || | d }||k r4qJd}g } g }!d}"xt|D ]}#|d|#}$|$| slqN|d|#|}%|d|#|}&t|%|&|}'|'
 }(|(|krqNn|(|k rd}|(}d}"P |'|$|}'| |# |!|' |d7 }||krNP qNW |"rqJ||k r"qJt| |!|d|})t|)|d })|)|| })|)
d}*|*|krfqJ|*|k r|d}|*}qJ|)||})|dkr|}|)}+qJt|)|+||},||9 }|,|+ks|,}+qJ|,|, }-| |-\}.}/||-\}0}1|/sJ|1sJ|-jdk r| }|-|}-|.|| }2|0|| }3|-|2|3fS qJW d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]_

    Nr   r%   FT)r   r   r6   r7   r   r8   r&   rr   r   rb   r   r   r   r   r[   r$   r`   rd   r-   rc   appendr   rU   rz   r9   r:   r;   )4r   r   r<   r   r=   r>   r?   rq   rk   ra   ZgswapdegyfdegygZyboundZ
xcontboundre   rf   rg   rA   r   r   r   rh   ri   rj   Z	degconthprl   Z	degcontfpZ	degcontgpdegdeltaNr1   r|   r}   Zunluckyrm   deltaarn   ro   rp   Zdeghpar(   ZdegyhprB   rC   rD   rE   rF   rG   rH   rI   rJ   r   r   r   modgcd_bivariate  s    I
"

"

















r   c       #      C   s$  | j }|j}|dkrZt| |||}| }||d kr>dS ||d k rV||d< t|S | |d }	||d }
t| |\}} t||\}}t|||}| }| }| }|||d  krdS |||d  k r|||d < tt| }t|}t|||}|}x:t|d D ]*}|ttt	| |tt	|||9 }qW | }t
|	| |
| ||d  ||d   | d }||k rdS d}d}g }g }tt|}xt|rt|dd }|| |d|| sq|d|| }| |d ||}||d ||} t|| |||}!|!dkrR|d7 }||krdS q|!jrn|||}|S |!||}!|| ||! |d7 }||krt||||d |}t||d || }||d }"|"||d  krdS |"||d  k r|"||d < t|S qW dS )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   rN   r$   r   r   r   r[   r`   r-   rb   rd   listrandomsampleremoverc   _modgcd_multivariate_pZ	is_groundrU   r   r   r   )#r   r   r   degbound	contboundr   rV   rD   deghr   r   rZ   ZcontgZconthZdegcontfZdegcontgZdegconthr_   Zlcgrl   Zevaltestr4   r   r   r1   dr|   hevalpointsrm   r   fagahaZdegyhr   r   r   r     s    0*"








r   c             C   s  | j |j kr| j jjstt| |}|dk	r0|S | j }|j}|  \}} | \}}|j||}|j| j|j}|jj	}	x2t
|D ]&}
|	|jt| |
jt||
j9 }	qW dd t|  | D }t|}d}d}x6t|}x|	| dkrt|}qW | |}||}yt|||||}W n tk
rH   d}wY nX |dkrVq|||}|dkrz|}|}qt||||}||9 }||ks|}q| d }| |\}}||\}}|s|s|jdk r| }||}||| }||| }|||fS qW dS )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

    Nc             S   s   g | ]\}}t ||qS r   )rd   ).0ZfdegZgdegr   r   r   
<listcomp>  s    z'modgcd_multivariate.<locals>.<listcomp>r%   r   )r   r   r6   r7   r   rN   r8   r&   r   r   r-   rb   r{   degreesr   r   r   r   r   r   rz   r;   )r   r   r<   r   rV   r=   r>   r?   r'   rg   r4   r   r   rA   r   r   r   r(   rB   rC   rD   rE   rF   rG   rH   rI   rJ   r   r   r   modgcd_multivariate&  sd    N
&





r   c             C   s6   | j }t|  | ||j\}}||||fS )z_
    Compute `\frac f g` modulo `p` for two univariate polynomials over
    `\mathbb Z_p`.
    )r   r	   to_denser   rS   )r   r   r   r   ZdensequoZdenseremr   r   r   _gf_div  s    r   c             C   s  | j }|j}| }|d }|| d }||j }}	| |j }
}xP|
 |krt||
|d }|
|||
  | }}
||	||  | }	}qBW |
| }}| |kst|||dkrdS |j}|dk r|	||}|
||}|
||}| }|||| 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   rA   r   r   Mr   Dr0s0r1s1rT   rm   r   lcr"   fieldr   r   r   !_rational_function_reconstruction  s*    %

r   c             C   s   |j }xz|  D ]n\}}|dkr6t|||}|svdS n@|jj }x6|| D ]$\}	}
t|
||}|sjdS |||	< qNW |||< qW |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   rO   r   r   drop_to_ground)rC   r   rA   r   rV   rD   rW   r.   coeffhmonr   r?   r   r   r   $_rational_reconstruction_func_coeffs  s    .r   c             C   s@   | j }t|  | ||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   rS   )r   r   r   r   strD   r   r   r   	_gf_gcdexK  s    	r   c             C   s4   | j }||}||}| |||g|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   rU   Z
ground_newr   r    )r   minpolyr   r   Zp_r   r   r   _truncY  s    

r   c             C   s   | j }t| ||} t|||}x|r| }|d}t||||\}}}	|	dksVdS xN|d}
|
|k rlP ||| |}t|||
| df|  ||}qXW |} |}q W t|| ||d |}t| | ||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_LCrU   r   )r   r   r   r   r   r    r!   r"   _r&   r#   rT   Zlcfinvr   r   r   _euclidean_algorithmx  s&    

&r   c             C   s(  | j }|j|jd |jd fd}||}| }| }| }|d}	t||}
|j}x|r"||kr"t||}||
 ||| df|  }|r||}|d}xb|r||	krt|||}|	||d||	 f|  }|r
||}|d}qW | }q`W |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   )rM   )
r   rR   rM   rU   r   r`   r   r   r   r   )r   rD   r   r   r   Zzxringr    r#   r   ZdegmZlchlcmZlcremr   r   r   _trial_division  s.    !



 
r   c             C   sJ   | j j| j jj |d}|j}x$|  D ]\}}|||||< q*W |S )z[
    Evaluate a polynomial `f` at `a` in the `i`-th variable of the ground
    domain.
    )r   )r   rR   r   dropr   rO   rc   )r   r4   rm   r   r   rW   r.   r   r   r   _evaluate_ground  s
    r   c       &   	   C   s  | j }|j}t|tr|j}nt| |||S |dkr@|j  }n$|j |d }|j|jj  d}|j|d}d}	d}
|	| |	| }|j
}g }g }g }tt|}xV|rt|dd }|| |dkr||d || dk}n||d ||dk}|rqt||d |}t||d |}||| |gdkrNqt| |d |}t||d |}t||||}|dkr|
d7 }
|
|	krdS q|dkr|S | gdg|d   }|dkrxN| D ]B\}}|d |d kr|jt|dd kr|j|dd< qW |g}|g}|dkr@|j j}n|jj j}|j jd }xFt|||D ]6\}} }!|!|krh|| ||  ||| 9 }qhW ||}|| || || |	d7 }	t||||d |dd}"t|"||||d }"|"dkr
q|dkr\|jj }#|#j j}$x|"! D ](}|#j "t#|$$ |j%$ ||#j}$q.W n\|jjj }#|#j j}$xH|"! D ]<}x4|! D ](}%|#j "t#|$$ |%j%$ ||#j}$qW qxW |&|$|}$||"'|$( |}"t)| |"||st)||"||s|"S qW dS )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   ry   r   rN   r   r   r   rR   r   r   r   r-   r   r   r   rc   r   r   r    _func_field_modgcd_pr   rO   LMtupleget_ringr   r,   r{   r   r   r   r   
itercoeffsrS   r
   r   r   Z
domain_newr   as_exprr   )&r   r   r   r   r   r   rV   ZqdomainZqringr1   r   r'   rl   r|   r   LMlistr   rm   testZgammaaZminpolyar   r   r   r   rW   r.   Zevalpoints_aZheval_arA   r   r   ZhbZLMhbrD   r   denr   r   r   r   r     s    *





*










r   c             C   s   | dk r| |7 } ||j  }}| |j }}t|d }x8||krl|| }||||   }}||||   }}q6W t||kr~dS |dk r| |  }	}
n|dkr|| }	}
ndS | }||	||
 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   abs	get_field)r   rA   r   r   r   r   r   r@   rT   rm   r   r   r   r   r    _integer_rational_reconstruction  s$    $
r   c       	      C   sb   |j }t|jtr t}|jj}nt}| jj}x0|  D ]$\}}||||}|sRdS |||< q6W |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   ry   r   r   #_rational_reconstruction_int_coeffsr   r   rO   )	rC   rA   r   rD   Zreconstructionr   rW   r.   r   r   r   r   r     s    )
r   c             C   s  | j }|j}t|tr>|j}|j j|j d}|j|d}nd}|j|j d}|  \}} | \}	}|| || }
|j	}d}g }g }g }x
t
|}|
|dkrq|dkr|| dk}n||dk}|rq| |}||}||}t||||}|dkrq|dkr$|jS | gdg|  }|dkrxN| D ]B\}}|d |d krL|jt|dd krL|j|dd< qLW |}|}x<t|||D ],\}}}||krt||||}||9 }qW || || || t|||}|dkrq|dkr&| d }n<|jj}x(| D ]}|j|| d }q8W ||}||}| d }t| |||st||	||s|S qW d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   ry   r   rN   rR   r   r8   r   r   r   r   r   r   r   rO   r   r   r{   rz   r   r   Zclear_denomsr   r   r   rU   r   )r   r   r   r   r   rV   ZQQdomainZQQringr=   r>   r'   rl   r   ZprimesZhplistr   r   r   r   Zminpolypr(   r   rW   r.   rC   rA   r0   r/   ZLMhqrD   r   r   r   r   _func_field_modgcd_m&  sz    B






*







r   c             C   s,  |j }t|jtr|jj}n|j}|j}x2|  D ]&}x |jD ]}|r>|||j}q>W q2W x| 	 D ]\}}|j}|jj}t|jtr|
|dd }t|}	xt|	D ]t}
||
 r|||
 | | }|d |	|
 d f|kr |||d |	|
 d f< q||d |	|
 d f  |7  < qW qfW |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   ry   r   r   r   r   repr   denominatorrO   r   lenr-   )r   r   f_r   r   r.   r   rW   rA   r1   r4   r   r   r   _to_ZZ_poly  s,    
(r   c       
      C   s   |j }|j}t| jj trx|  D ]l\}}xb| D ]V\}}|d f| }|| |gdg|d   }	||kr||	||< q6||  |	7  < q6W q$W n`x^|  D ]R\}}|d f}|| |gdg|d   }	||kr|	||< q||  |	7  < qW |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   ry   r   r   rO   )
r   r   r   r   rW   r.   r   ZcoefrA   r   r   r   r   _to_ANP_poly  s"    


r   c             C   s.   |j }x"|  D ]\}}||||< qW |S )zo
    Change representation of the minimal polynomial from ``DMP`` to
    ``PolyElement`` for a given ring.
    )r   Ztermsr   )r   r   Zminpoly_rW   r.   r   r   r   _minpoly_from_dense/  s    r   c             C   sx   | j }|jtd|j }|jj }||  }|j}x0| D ]$}t||d }||j	kr<|| fS q<W || 
||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   r-   rN   r   r   r   r   func_field_modgcdr   rT   rU   )r   Zfringr   r   r   rX   r.   r   r   r   _primitive_in_x0<  s    
r   c             C   sr  | j }|j}|j}||j kr"|js&tt| |}|dk	r<|S td}|j|j|f |j	 d}|dkrt
| |}t
||}	|d|jj}
t||	|
}t||}nt| \}} t|\}}t||d }|jtd| }t
| |}t
||}	t|j|d}
t||	|
}t||}t|\}}|||9 }| ||9 } |||9 }||j}|| |||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]_

    Nz)rM   r   r%   r   )r   r   rN   Zis_Algebraicr7   r   r   rR   rM   r   r   r   rS   modr   r   r   r   r   r   r-   r   rU   r9   r   rT   )r   r   r   r   r1   r<   r   ZZZringr   Zg_r   rD   Zcontx0fZcontx0gZcontx0hZZZring_Zcontx0h_r   r   r   r   Q  s<    h





r   )F)N)3Zsympy.core.symbolr   Zsympy.ntheoryr   Zsympy.ntheory.modularr   Zsympy.polys.domainsr   Zsympy.polys.galoistoolsr   r   r   r	   r
   Zsympy.polys.polyerrorsr   Zmpmathr   r   r   r$   r*   r5   rK   r[   r]   r`   rb   rr   rz   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>   sZ   !A =05Kb
A U  
BF8
E '@= :3