o
    oÇhLå  ã                   @   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 | s(|j|jjk r!| |j|j fS ||j|jfS |sA| j|jjk r:|  |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   új/var/www/html/construction_image-detection-poc/venv/lib/python3.10/site-packages/sympy/polys/modulargcd.pyÚ_trivial_gcd   s   r   c                 C   sˆ   | j j}|r7| }| ¡ }| |j|¡}	 | ¡ }||k rn|| || f¡ ||j ¡  |¡}q|} |}|s|  | | 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   sl   | j j | j|j¡}d}t|ƒ}|| dkr t|ƒ}|| dks|  |¡}| |¡}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   sn   |   ¡ }| jjd }| jj}t|d ƒD ]}t||g|  || ¡| || ¡gddd ||f< q| ¡  |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Úir   r   r   Ú,_chinese_remainder_reconstruction_univariate[   s   66r8   c                 C   sÒ  | j |j kr| j jjsJ ‚t| |ƒ}|dur|S | j }|  ¡ \}} | ¡ \}}|j ||¡}t| |ƒ}|dkrH||ƒ|  || ¡| || ¡fS |j | j|j¡}d}	d}
	 t	|
ƒ}
||
 dkrjt	|
ƒ}
||
 dks`|  
|
¡}| 
|
¡}t|||
ƒ}| ¡ }||krƒqU||k rŒd}	|}qU| |¡ 
|
¡}|	dkr|
}	|}qUt|||
|	ƒ}|	|
9 }	||ks¯|}qU| | ¡ ¡}|  |¡\}}| |¡\}}|sè|sè|jdk rÐ| }| |¡}| || ¡}| || ¡}|||fS qV)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_ZZr   Ú	primitiver'   r+   r   r   r   r   r%   r   r8   Ú
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œ   sd   C

"ÿ




ÙrM   c                 C   sÆ   | j }|j}|j}i }|  ¡ D ] \}}|dd… |vr#i ||dd… < |||dd…  |d < qg }t| ¡ ƒD ]}t|t|||ƒ||ƒ}q8|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)

    Néÿÿÿÿr&   ©Úsymbols)r   r   ÚngensÚ	itertermsÚiterÚvaluesr   r   ÚclonerP   Ú
from_denser   ÚquoÚset_ring)r   r   r   r    ÚkÚcoeffsÚmonomr0   ÚcontÚyringÚcontfr   r   r   Ú
_primitive  s   )r_   c                 C   sB   | j j}d|d  }|  ¡ D ]}|dd… |kr|dd… }q|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&   NrN   )r   rQ   Ú
itermonoms)r   rY   Údegfr[   r   r   r   Ú_degZ  s   (€rb   c           	      C   st   | j }|j}|j|j|d  d}|jd }t| ƒ}|j}|  ¡ D ]\}}|dd… |kr7||||d   7 }q!|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&   rO   r   NrN   )r   rQ   rU   rP   r.   rb   r   rR   )	r   r   rY   r]   Úyra   Úlcfr[   r0   r   r   r   Ú_LCŠ  s   (
€re   c                 C   sP   | j }|j}|  ¡ D ]\}}|| f|d|…  ||d d…  }|||< q
|S )zS
    Make the variable `x_i` the leading one in a multivariate polynomial `f`.
    Nr&   )r   r   rR   )r   r7   r   Úfswapr[   r0   Ú	monomswapr   r   r   Ú_swap¿  s   &
rh   c                 C   s:  | j }|j | j|j¡}|j t| dƒjt|dƒj¡}|| }d}t|ƒ}|| dkr5t|ƒ}|| dks+|  |¡}| |¡}t||ƒ\}	}t||ƒ\}
}t|	|
|ƒ}| 	¡ }tt
|ƒt
|ƒ|ƒ}t|ƒD ],}| d|¡| spqe| d|¡ |¡}| d|¡ |¡}t|||ƒ}| 	¡ }||f  S 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   rh   r   r   r_   r%   r   re   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Ë  s2   *ÿ

rx   c                 C   sÌ   t |  ¡ ƒ}t | ¡ ƒ}| |¡}| |¡ | |¡ | jjj}| jj}t| jjtƒr.t	}	ndd„ }	|D ]}
|	| |
 ||
 ||ƒ||
< q4|D ]}
|	| |
 |||ƒ||
< qF|D ]}
|	|||
 ||ƒ||
< qV|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 )NTr,   r   r   )ÚcpÚcqr   r3   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)   r2   r   r3   ÚhpmonomsÚhqmonomsr}   r   r6   r{   r[   r   r   r   r     s"   H



r   Fc                 C   s®   |j }|r|jj}|jj| }n|j}|j| }t| |ƒD ]4\}	}
|j}|j}| D ]}||	kr0q)||| 9 }||	| 9 }q)| ||¡}| |¡}||
 |¡| 7 }q| |¡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   rX   r   )Ú
evalpointsÚhpevalr   r7   r   Úgroundr)   r   rc   rs   rv   ÚnumerÚdenomÚbr0   r   r   r   Ú_interpolate_multivariatex  s$   '


r‹   c           4      C   s(  | j |j kr| j jjsJ ‚t| |ƒ}|dur|S | j }|  ¡ \}} | ¡ \}}|j ||¡}t| |ƒ\}}||  kr?dkrRn n||ƒ|  || ¡| || ¡fS t| dƒ}	t|dƒ}
|	 	¡ }|
 	¡ }t|	|
ƒ\}}||  krudkrˆn n||ƒ|  || ¡| || ¡fS |j | j
|j
¡}|j |	j
|
j
¡}|| }d}d}	 t|ƒ}|| dkr·t|ƒ}|| dks­|  |¡}| |¡}t||ƒ\}}t||ƒ\}}t|||ƒ}| 	¡ }||krÞq¢||k rçd}|}q¢tt|ƒt|ƒ|ƒ}| 	¡ }| 	¡ }| 	¡ }t|| || || | ƒd }||k rq¢d}g } g }!d}"t|ƒD ]]}#| d|#¡}$|$| s.q| d|#¡ |¡}%| d|#¡ |¡}&t|%|&|ƒ}'|' 	¡ }(|(|krQq|(|k r^d}|(}d}" n|' |$¡ |¡}'|  |#¡ |! |'¡ |d7 }||kr{ nq|"rq¢||k r‡q¢t| |!|d|ƒ})t|)|ƒd })|)| |¡ })|) 	d¡}*|*|kr¨q¢|*|k r²d}|*}q¢|) |¡ |¡})|dkrÄ|}|)}+q¢t|)|+||ƒ},||9 }|,|+ks×|,}+q¢|, |, ¡ ¡}-|  |-¡\}.}/| |-¡\}0}1|/s|1s|-j
dk rû| }|- |¡}-|. || ¡}2|0 || ¡}3|-|2|3fS q£)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&   TF)r   r   r9   r   r:   r'   rx   r   rh   r   r   r   r   r_   r%   re   rj   r/   ri   Úappendr‹   rX   r   r;   r<   r=   )4r   r   r>   r   r?   r@   rA   rw   rq   rf   ÚgswapÚdegyfÚdegygÚyboundÚ
xcontboundrk   rl   rm   rC   r   r   r   rn   ro   rp   Ú	degconthprr   Ú	degcontfpÚ	degcontgpÚdegdeltaÚNr4   r…   r†   Úunluckyrs   Údeltaart   ru   rv   Údeghpar)   ÚdegyhprD   rE   rF   rG   rH   rI   rJ   rK   rL   r   r   r   Úmodgcd_bivariate¹  sà   I
"

"ÿ


ÿÿ






ÿ







™r›   c           #      C   s  | j }|j}|dkr-t| ||ƒ |¡}| ¡ }||d krdS ||d k r+||d< t‚|S |  |d ¡}	| |d ¡}
t| |ƒ\}} t||ƒ\}}t|||ƒ}| ¡ }| ¡ }| ¡ }|||d  kredS |||d  k ru|||d < t‚t| ƒ}t|ƒ}t|||ƒ}|}t|d ƒD ]}|ttt	| |ƒƒtt	||ƒƒ|ƒ9 }q‹| ¡ }t
|	| |
| ||d  ||d   | ƒd }||k rÂdS d}d}g }g }tt|ƒƒ}|r†t |d¡d }| |¡ | d|¡| séqÐ| d|¡| }|  |d |¡ |¡}| |d |¡ |¡} t|| |||ƒ}!|!du r |d7 }||krdS qÐ|!jr.| |¡ |¡}|S |! |¡ |¡}!| |¡ | |!¡ |d7 }||kr„t||||d |ƒ}t||ƒd | |¡ }| |d ¡}"|"||d  krqdS |"||d  k r‚|"||d < t‚|S |sÓ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   rQ   r%   r   r   r   r_   re   r/   rh   rj   ÚlistÚrandomÚsampleÚremoveri   Ú_modgcd_multivariate_pÚ	is_groundrX   r   rŒ   r‹   )#r   r   r   ÚdegboundÚ	contboundr   rY   rF   ÚdeghrŽ   r   r^   ÚcontgÚconthÚdegcontfÚdegcontgÚdegconthrd   Úlcgrr   Úevaltestr7   r•   r–   r4   Údr…   ÚhevalÚpointsrs   r˜   ÚfaÚgaÚhaÚdegyhr   r   r   r      s˜   0&ÿÿ





Õ-r    c                 C   s  | j |j kr| j jjsJ ‚t| |ƒ}|dur|S | j }|j}|  ¡ \}} | ¡ \}}|j ||¡}|j | j|j¡}|jj}	t	|ƒD ]}
|	|j t
| |
ƒjt
||
ƒj¡9 }	qBdd„ t|  ¡ | ¡ ƒD ƒ}t|ƒ}d}d}	 t|ƒ}|	| dkrt|ƒ}|	| dksw|  |¡}| |¡}z
t|||||ƒ}W n ty    d}Y qlw |du r¦ql| |¡ |¡}|dkr·|}|}qlt||||ƒ}||9 }||ksÉ|}ql| ¡ d }|  |¡\}}| |¡\}}|s|s|jdk rë| }| |¡}| || ¡}| || ¡}|||fS qm)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   )rj   )Ú.0ÚfdegÚgdegr   r   r   Ú
<listcomp>ˆ  s    z'modgcd_multivariate.<locals>.<listcomp>r&   Tr   )r   r   r9   r   rQ   r:   r'   r   r   r/   rh   r„   Údegreesrœ   r   r   r    r   r   r   r=   )r   r   r>   r   rY   r?   r@   rA   r(   rm   r7   r¢   r£   rC   r   r   r   r)   rD   rE   rF   rG   rH   rI   rJ   rK   rL   r   r   r   Úmodgcd_multivariate&  sj   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   rV   )r   r   r   r   ÚdensequoÚdenseremr   r   r   Ú_gf_div¹  s   r¼   c                 C   s  | j }|j}| ¡ }|d }|| d }||j}}	| |j}
}|
 ¡ |krLt||
|ƒd }|
|||
   |¡}}
||	||   |¡}	}|
 ¡ |ks&|
|}}| ¡ |ks_t|||ƒdkrad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   rC   r   r   ÚMr–   ÚDÚr0Ús0Úr1Ús1rW   rs   rŠ   Úlcr#   Úfieldr   r   r   Ú!_rational_function_reconstructionÃ  s,   %ý
rÈ   c                 C   s„   |j }|  ¡ D ]8\}}|dkrt|||ƒ}|s dS n |jj }| |¡ ¡ D ]\}	}
t|
||ƒ}|s6  dS |||	< q&|||< q|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   rR   rÈ   r   Údrop_to_ground)rE   r   rC   r   rY   rF   r[   r0   ÚcoeffhÚmonr¿   rA   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   rV   )r   r   r   r   ÚsÚtrF   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   rX   Ú
ground_newr   r!   )r   Úminpolyr   r   Úp_r   r   r   Ú_truncY  s   

rÓ   c                 C   sÚ   | j }t| ||ƒ} t|||ƒ}|rW| }| d¡}t| |¡||ƒ\}}}	|	dks*dS 	 | d¡}
|
|k r5n|| |¡  |¡}t|| |
| df¡|  ||ƒ}q+|} |}|s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_LCrX   r   )r   r   rÑ   r   r   r!   r"   r#   Ú_r'   r$   rW   Úlcfinvr   r   r   Ú_euclidean_algorithmx  s*   

"ûðr×   c                 C   s*  | j }|j|jd |jd fd}| |¡}| }| ¡ }| ¡ }| d¡}	t|ƒ |¡}
|j}|r“||kr“t|ƒ |¡}||
 | || df¡|  }|rR| |¡}| d¡}|r‰||	kr‰t| |¡ƒ |¡}| 	|¡| d||	 f¡|  }|r~| |¡}| d¡}|r‰||	ks]| ¡ }|r“||ks5|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   rO   )
r   rU   rP   rX   r   re   r   r   r   r   )r   rF   rÑ   r   r   Úzxringr!   r$   r¤   ÚdegmÚlchÚlcmÚlcremr   r   r   Ú_trial_division°  s2   !



 

úðrÝ   c                 C   sF   | j j| j jj  |¡d}|j}|  ¡ D ]\}}| ||¡||< q|S )z[
    Evaluate a polynomial `f` at `a` in the `i`-th variable of the ground
    domain.
    ©r   )r   rU   r   Údropr   rR   ri   )r   r7   rs   r   r¯   r[   r0   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|ƒƒ}|rót |d¡d }| |¡ |dkrv| |d |¡| dk}n| |d |¡ |¡dk}|r†qUt||d |ƒ}t||d |ƒ}| ||  |¡g¡dkr£qUt| |d |ƒ}t||d |ƒ}t||||ƒ}|du rÉ|
d7 }
|
|	krÈdS qU|dkrÏ|S | ¡ gdg|d   }|dkr| ¡ D ] \}}|d |d kr|jt|dd… ƒkr|j|dd…< qä|g}|g}|dkr|j ¡ j}n|jj ¡ j}|j jd }t|||ƒD ]\}} }!|!|krD| |¡ | | ¡ ||| 9 }q*| |¡}| |¡ | |¡ | |¡ |	d7 }	t||||d |dd}"t|"||||d ƒ}"|"du rzqU|dkr¡|jj }#|#j j}$|" !¡ D ]}|#j  "t#|$ $¡ |j% $¡ ||#jƒ¡}$q‹n*|jjj }#|#j j}$|" !¡ D ]}| !¡ D ]}%|#j  "t#|$ $¡ |%j% $¡ ||#jƒ¡}$q´q®| &|$ |¡¡}$||" '|$¡ (¡ ƒ |¡}"t)| |"||ƒsñt)||"||ƒsñ|"S |sXd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   r€   r   rQ   r×   r¾   rÉ   rU   rÔ   r   rœ   r/   r   rž   rŸ   ri   r   rà   r!   Ú_func_field_modgcd_pr   rR   ÚLMÚtupleÚget_ringr   r.   r„   rŒ   r‹   rÌ   rÇ   Ú
itercoeffsrV   r   r¹   r‰   Ú
domain_newr   Úas_exprrÝ   )&r   r   rÑ   r   r   r   rY   ÚqdomainÚqringr4   r¬   r(   rr   r…   r­   ÚLMlistr®   rs   ÚtestÚgammaaÚminpolyar¯   r°   r±   râ   r[   r0   Úevalpoints_aÚheval_arC   rÎ   rŠ   ÚhbÚLMhbrF   r    Údenr¿   r   r   r   rá     s²   *


*€



€






ÿÿ

ÿÿ ¦\rá   c                 C   sÔ   | dk r| |7 } ||j }}| |j}}t|d ƒ}t|ƒ|kr<|| }||||  }}||||  }}t|ƒ|ks tt|ƒƒ|krFdS |dk rR| | }	}
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   ÚintÚabsÚ	get_field)r¿   rC   r   rÂ   rÃ   rÄ   rÅ   rB   rW   rs   rŠ   rÇ   r   r   r   Ú _integer_rational_reconstruction©  s&   $ýrö   c           	      C   s`   |j }t|jtƒrt}|jj}nt}| jj}|  ¡ D ]\}}||||ƒ}|s) dS |||< q|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ö   rR   )	rE   rC   r   rF   Úreconstructionr   r[   r0   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 }	 t
|ƒ}|
 |¡dkrXqK|dkrc|| dk}n| |¡dk}|rmqK|  |¡}| |¡}| |¡}t||||ƒ}|du rˆqK|dkr|jS | ¡ gdg|  }|dkrÀ| ¡ D ]\}}|d |d kr¿|jt|dd… ƒkr¿|j|dd…< q¡|}|}t|||ƒD ]\}}}||krÞt||||ƒ}||9 }qÊ| |¡ | |¡ | |¡ t|||ƒ}|du rùqK|dkr| ¡ d }n|jj}| ¡ D ]}|j || ¡ d ¡}q| |¡}| |¡}| ¡ d }t|  |¡||ƒsBt| |	¡||ƒsB|S qL)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&   TN)r   r   r€   r   rQ   rU   rõ   r:   rÔ   r   r   r   rá   r   r   rR   râ   rã   r„   r   rŒ   r÷   Úclear_denomsrå   rÛ   r   rX   rÝ   )r   r   rÑ   r   r   rY   ÚQQdomainÚQQringr?   r@   r(   rr   r   ÚprimesÚhplistrê   rë   r   r   Úminpolypr)   râ   r[   r0   rE   rC   r3   r2   ÚLMhqrF   rò   r   r   r   Ú_func_field_modgcd_m&  s‚   B



&€€





ÿÁr   c                 C   s   |j }t|jtƒr|jj}n|j}|j}|  ¡ D ]}| ¡ D ]}|r)| ||j¡}qq|  	¡ D ]^\}}| ¡ }|jj}t|jtƒrJ| 
|dd… ¡}t|ƒ}	t|	ƒD ]:}
||
 rŒ| ||
 | ¡| }|d |	|
 d f|vr||||d |	|
 d f< qR||d |	|
 d f  |7  < qRq/|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Û   ÚdenominatorrR   r   Úlenr/   Úconvert)r   r   Úf_r   rò   r0   r¿   r[   rC   r4   r7   r   r   r   Ú_to_ZZ_polyÂ  s4   
€þ €ù	r  c           
      C   sð   |j }|j}t| jj tƒrH|  ¡ D ]4\}}| ¡ D ]+\}}|d f| }||  |¡gdg|d   ƒ}	||vr<|	||< q||  |	7  < qq|S |  ¡ D ])\}}|d f}||  |¡gdg|d   ƒ}	||vrm|	||< qL||  |	7  < qL|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   rR   )
r   r   r   r  r[   r0   rË   ÚcoefrC   r¿   r   r   r   Ú_to_ANP_polyü  s&   
ù÷

r  c                 C   s*   |j }|  ¡ D ]\}}| |¡||< q|S )zo
    Change representation of the minimal polynomial from ``DMP`` to
    ``PolyElement`` for a given ring.
    )r   Útermsr   )rÑ   r   Úminpoly_r[   r0   r   r   r   Ú_minpoly_from_dense/  s   r  c                 C   sx   | j }|jtd|jƒŽ }|jj }||  ¡ ƒ}|j}| ¡ D ]}t||ƒd }||j	kr1|| f  S q||  
| |¡¡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/   rQ   r   rç   r   rå   Úfunc_field_modgcdr   rW   rX   )r   Úfringr   r    r  r\   r0   r   r   r   Ú_primitive_in_x0<  s   
ÿr  c                 C   st  | j }|j}|j}||j kr|jsJ ‚t| |ƒ}|dur|S tdƒ}|j|j|f |j ¡ d}|dkrUt	| |ƒ}t	||ƒ}	| 
d¡ |j ¡ ¡}
t||	|
ƒ}t||ƒ}nTt| ƒ\}} 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)rP   r   r&   r   )r   r   rQ   Úis_Algebraicr   r   rU   rP   rä   r  rß   rV   Úmodr  r   r  r  r  rÉ   r/   r  rX   r;   r   rW   )r   r   r   r   r4   r>   r  ÚZZringr  Úg_rÑ   rF   Úcontx0fÚcontx0gÚcontx0hÚZZring_Úcontx0h_r   r   r   r  Q  s<   h





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+   r8   rM   r_   rb   re   rh   rx   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   r   Ú<module>   s\    !A =05K
bA U  
BF
8E '@= :3