
    Ed(                     6   d dl mZ d dlmZ d dlmZ d dlmZ d dlm	Z	m
Z
mZmZmZ d dlmZ d dlmZ d dlZd	 Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd*dZd Zd Z d Z!d Z"d Z#d Z$d Z%d Z&d Z'd+dZ(d  Z)d! Z*d" Z+d# Z,d$ Z-d% Z.d& Z/d' Z0d( Z1d) Z2dS ),    )Dummy)	nextprimecrt)PolynomialRing)gf_gcdgf_from_dictgf_gcdexgf_divgf_lcm)ModularGCDFailed)sqrtNc                     | j         }| s|s|j        |j        |j        fS | s5|j        |j        j        k     r| |j        |j         fS ||j        |j        fS |s5| 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   s      6lib/python3.11/site-packages/sympy/polys/modulargcd.py_trivial_gcdr      s    
 6D * *y$)TY.. 	*4$+"" 	*2ty48)++di)) *4$+"" 	*2y$)++dh	))4    c                    | j         j        }|r| }|                                }|                    |j        |          }	 |                                }||k     rnK||                    ||z
  f                              ||j        z            z
                      |          }f|} |}||                     |                    | j        |                                        |          S )zM
    Compute the GCD of two univariate polynomials in `\mathbb{Z}_p[x]`.
    )r   r   degreeinvertr   	mul_monom
mul_groundtrunc_ground)fpgppdomremdeglcinvdegrems           r   _gf_gcdr(   #   s     '.C
 iikk

25!$$	cZZ\\F| v|o66AA%#&.QQQ__`abbC		c    ==BE1--..;;A>>>r   c                 \   | j         j                            | j        |j                  }d}t	          |          }||z  dk    rt	          |          }||z  dk    |                     |          }|                    |          }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deghps           r   _degree_bound_univariater/   :   s    & FMadAD))E	A!A
!)q. aLL !)q.  
		B	
		B	R		BIIKKELr   c           	      T   |                                  }| j        j        d         }| j        j        }t	          |dz             D ]N}t          ||g|                     ||z            |                    ||z            gd          d         ||f<   O|                                 |S )a  
    Construct a polynomial `h_{pq}` in `\mathbb{Z}_{p q}[x]` such that

    .. math ::

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

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

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

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

    Parameters
    ==========

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

    Examples
    ========

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

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

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

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

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

    r   r*   T	symmetric)r   r   gensr   ranger   coeff
strip_zero)r-   hqr"   qnxhpqis           r   ,_chinese_remainder_reconstruction_univariater=   [   s    l 			A
QA
',C1Q3ZZ U UA!Q$!Q$ @DQQQRSTQD		NNJr   c                 6   | j         |j         k    r| j         j        j        sJ t          | |          }||S | j         }|                                 \  }} |                                \  }}|j                            ||          }t          | |          }|dk    r: ||          |                     ||z            |                    ||z            fS |j                            | j        |j                  }d}	d}
	 t          |
          }
||
z  dk    rt          |
          }
||
z  dk    | 
                    |
          }|
                    |
          }t          |||
          }|                                }||k    r||k     rd}	|}|                    |          
                    |
          }|	dk    r|
}	|}t          |||
|	          }|	|
z  }	||k    s|}|                    |                                          }|                     |          \  }}|                    |          \  }}|sZ|sX|j        dk     r| }|                    |          }|                    ||z            }|                    ||z            }|||f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_ZZr   	primitiver+   r/   r   r   r   r   r(   r   r=   
quo_groundcontentdiv)r   r   resultr   cfcgchboundr,   mr"   r    r!   r-   r.   hlastmhmhfquofremgquogremcffcfgs                           r   modgcd_univariaterS      s   F 6QV3 3333!QF 6DKKMMEBKKMMEB	R	 	 B$Q**Ez HtBxxbBh//bBh1G1GGGKOOAD!$''E	A	A'aLLai1n 	!A ai1n 	 ^^A^^ARQ		5= 	U] 	AE]]5!!..q116 	AF9"faKK	QV| 	FMM"**,,''UU1XX
dUU1XX
d 	D 	tax SR  A//"(++C//"(++Cc3;O'r   c           	      B   | j         }|j        }|j        }i }|                                 D ]7\  }}|dd         |vri ||dd         <   |||dd                  |d         <   8g }t	          |                                          D ]#}t          |t          |||          ||          }$|                    |j	        |dz
                     }	|	
                    |                              |          }
|
|                     |
                    |                    fS )a  
    Compute the content and the primitive part of a polynomial in
    `\mathbb{Z}_p[x_0, \ldots, x_{k-2}, y] \cong \mathbb{Z}_p[y][x_0, \ldots, x_{k-2}]`.

    Parameters
    ==========

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

    Returns
    =======

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

    Examples
    ========

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

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

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

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

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

    Nr*   symbols)r   r   ngens	itertermsitervaluesr   r	   clonerW   
from_denser   quoset_ring)r   r"   r   r#   kcoeffsmonomr5   contyringcontfs              r   
_primitiverf     s(   R 6D
+C
AF . .u":V# 	$!#F5":(-uSbSz59%%Dfmmoo&& A AdL377C@@JJt|AaC0J11ET""//22E!%%t,,----r   c                     | j         j        }d|dz
  z  }|                                 D ]}|dd         |k    r
|dd         }|S )a  
    Compute the degree of a multivariate polynomial
    `f \in K[x_0, \ldots, x_{k-2}, y] \cong K[y][x_0, \ldots, x_{k-2}]`.

    Parameters
    ==========

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

    Returns
    =======

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

    Examples
    ========

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

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

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

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

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

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

    )r   r*   NrU   )r   rX   
itermonoms)r   r`   degfrb   s       r   _degrj   Z  sZ    P 	
A1Q3<D  ": 	":DKr   c                 "   | j         }|j        }|                    |j        |dz
                     }|j        d         }t          |           }|j        }|                                 D ]$\  }}|dd         |k    r||||d         z  z  z  }%|S )a  
    Compute the leading coefficient of a multivariate polynomial
    `f \in K[x_0, \ldots, x_{k-2}, y] \cong K[y][x_0, \ldots, x_{k-2}]`.

    Parameters
    ==========

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

    Returns
    =======

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

    Examples
    ========

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

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

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

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

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

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

    r*   rV   r   NrU   )r   rX   r\   rW   r3   rj   r   rY   )	r   r   r`   rd   yri   lcfrb   r5   s	            r   _LCrn     s    P 6D
AJJt|AaC0J11E
1A77D
*C & &u": 	&5E"I%%CJr   c                     | j         }|j        }|                                 D ],\  }}||         f|d|         z   ||dz   d         z   }|||<   -|S )zS
    Make the variable `x_i` the leading one in a multivariate polynomial `f`.
    Nr*   )r   r   rY   )r   r<   r   fswaprb   r5   	monomswaps          r   _swaprr     sh     6DIE ! !u1XK%)+eAaCDDk9	 iLr   c                 F   | j         }|j                            | j        |j                  }|j                            t	          | d          j        t	          |d          j                  }||z  }d}t          |          }||z  dk    rt          |          }||z  dk    |                     |          }|                    |          }t          ||          \  }	}t          ||          \  }
}t          |	|
|          }|	                                }t          t          |          t          |          |          }t          |          D ]}|                    d|          |z  s|                    d|                              |          }|                    d|                              |          }t          |||          }|	                                }||fc 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   rr   r   r   rf   r(   r   rn   r4   evaluatemin)r   r   r   gamma1gamma2	badprimesr"   r    r!   contfpcontgpconthp
ycontbounddeltaafpagpahpaxbounds                      r   _degree_bound_bivariater     s   T 6D[__QT14((F[__U1a[[^U1a[[^<<FI	A!A
a-1
 aLL a-1
  
		B	
		BB""JFBB""JFBVVQ''FJ CGGSWWa((E1XX " "~~a##a' 	kk!Q,,Q//kk!Q,,Q//c3""z!!!!ryy{{BIIKK((*44r   c                 J   t          |                                           }t          |                                          }|                    |          }|                    |           |                    |           | j        j        j        }| j        j        }t          | j        j        t                    rt          }	nd }	|D ]}
 |	| |
         ||
         ||          ||
<    |D ]}
 |	| |
         |||          ||
<   |D ]}
 |	|||
         ||          ||
<   |S )a:  
    Construct a polynomial `h_{pq}` in
    `\mathbb{Z}_{p q}[x_0, \ldots, x_{k-1}]` such that

    .. math ::

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

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

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

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

    Parameters
    ==========

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

    Examples
    ========

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

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

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

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

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

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

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

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

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

    c                 :    t          ||g| |gd          d         S )NTr1   r   r   )cpcqr"   r8   s       r   crt_z<_chinese_remainder_reconstruction_multivariate.<locals>.crt_k  s$    1vBx4888;;r   )
setmonomsintersectiondifference_updater   r   r   
isinstancer   ._chinese_remainder_reconstruction_multivariate)r-   r7   r"   r8   hpmonomshqmonomsr   r   r;   r   rb   s              r   r   r     s@   P 299;;H299;;H""8,,Fv&&&v&&&7>D
',C"'..11 <=	< 	< 	<  6 6T"U)RY155E

 1 1T"U)T1a00E

 1 1T$5	1a00E

Jr   Fc                    |j         }|r|j        j        }|j        j        |         }n|j        }|j        |         }t          | |          D ]u\  }	}
|j        }|j        }| D ]}||	k    r	|||z
  z  }||	|z
  z  }|                    ||          }|                    |          }||
                    |          |z  z  }v|                    |          S )a  
    Reconstruct a polynomial `h_p` in `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]`
    from a list of evaluation points in `\mathbb{Z}_p` and a list of
    polynomials in
    `\mathbb{Z}_p[x_0, \ldots, x_{i-1}, x_{i+1}, \ldots, x_{k-1}]`, which
    are the images of `h_p` evaluated in the variable `x_i`.

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

    Parameters
    ==========

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

    Returns
    =======

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

    )	r   r   r3   zipr   r   r   r_   r   )
evalpointshpevalr   r<   r"   groundr-   r   rl   r~   r   numerdenombr5   s                  r   _interpolate_multivariater   x  s    N 
B #KQIaLj&)) ) )3
 	 	AAv QUNEQUNEEeQ''  ''
cll4  5((??1r   c                    | j         |j         k    r| j         j        j        sJ t          | |          }||S | j         }|                                 \  }} |                                \  }}|j                            ||          }t          | |          \  }}||cxk    rdk    r=n n: ||          |                     ||z            |                    ||z            fS t          | d          }	t          |d          }
|		                                }|
	                                }t          |	|
          \  }}||cxk    rdk    r=n n: ||          |                     ||z            |                    ||z            fS |j                            | j
        |j
                  }|j                            |	j
        |
j
                  }||z  }d}d}	 t          |          }||z  dk    rt          |          }||z  dk    |                     |          }|                    |          }t          ||          \  }}t          ||          \  }}t          |||          }|	                                }||k    r||k     rd}|}t          t          |          t          |          |          }|	                                }|	                                }|	                                }t!          ||z
  ||z
  ||z
  |z             dz   }||k     rGd}g } g }!d}"t#          |          D ]
}#|                    d|#          }$|$|z  s|                    d|#                              |          }%|                    d|#                              |          }&t          |%|&|          }'|'	                                }(|(|k    r|(|k     rd}|(}d}" na|'                    |$                              |          }'|                     |#           |!                    |'           |dz  }||k    r n|"rn||k     rvt)          | |!|d|          })t          |)|          d         })|)|                    |          z  })|)	                    d          }*|*|k    r|*|k     rd}|*}|)                    |                              |          })|dk    r|}|)}+t-          |)|+||          },||z  }|,|+k    s|,}+5|,                    |,                                          }-|                     |-          \  }.}/|                    |-          \  }0}1|/sZ|1sX|-j
        dk     r| }|-                    |          }-|.                    ||z            }2|0                    ||z            }3|-|2|3fS )a!  
    Computes the GCD of two polynomials in `\mathbb{Z}[x, y]` using a
    modular algorithm.

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

    Parameters
    ==========

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

    Returns
    =======

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

    Examples
    ========

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

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

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

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

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

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

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

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

    References
    ==========

    1. [Monagan00]_

    Nr   r*   TF)r   r   r?   r   r@   r+   r   r   rr   r   r   r   r   rf   r(   rn   ru   r4   rt   appendr   r_   r   rA   rB   rC   )4r   r   rD   r   rE   rF   rG   r   r|   rp   gswapdegyfdegygybound
xcontboundrv   rw   rx   rI   r"   r    r!   ry   rz   r{   	degconthpr}   	degcontfp	degcontgpdegdeltaNr9   r   r   unluckyr~   deltaar   r   r   deghpar-   degyhprJ   rK   rL   rM   rN   rO   rP   rQ   rR   s4                                                       r   modgcd_bivariater     sK   R 6QV3 3333!QF 6DKKMMEBKKMMEB	R	 	 B0A66FJ H H H Hq H H H H HtBxxbBh//bBh1G1GGG!QKKE!QKKELLNNELLNNE0>>FJ H H H Hq H H H H HtBxxbBh//bBh1G1GGG [__QT14((F[__UXux00FI	A	AgaLL!mq  	!A !mq  	 ^^A^^AA&&
A&&
++MMOO	z! 	# 	A"J BR!,,MMOO	MMOO	<<>>	!59#4Z(*, ,./0 q5 	
q 	 	A^^Aq))FA: ++a##0033C++a##0033C#sA&&CZZ\\F & ..((55a88Ca   MM#FAAv   	q5 	&z64AFFAq!&//$'''1F? 	F? 	AF]]6""//226 	AF;B1MM	QV| 	FMM"**,,''UU1XX
dUU1XX
d 	D 	tax SR  A//"(++C//"(++Cc3;Ogr   c                    | j         }|j        }|dk    r`t          | ||                              |          }|                                }||d         k    rdS ||d         k     r||d<   t
          |S |                     |dz
            }	|                    |dz
            }
t          | |          \  }} t          ||          \  }}t          |||          }|                                }|                                }|                                }|||dz
           k    rdS |||dz
           k     r|||dz
  <   t
          t          |           }t          |          }t          |||          }|}t          |dz
            D ]L}|t          t          t          | |                    t          t          ||                    |          z  }M|                                }t          |	|z
  |
|z
  ||dz
           ||dz
           z
  |z             dz   }||k     rdS d}d}g }g }t          t          |                    }|rt          j        |d          d         }|                    |           |                    d|          |z  sM|                    d|          |z  }|                     |dz
  |                              |          }|                    |dz
  |                              |          } t!          || |||          }!|!|dz  }||k    rdS |!j        r*|                    |                              |          }|S |!                    |                              |          }!|                    |           |                    |!           |dz  }||k    rt+          ||||dz
  |          }t          ||          d         |                    |          z  }|                    |dz
            }"|"||dz
           k    rdS |"||dz
           k     r|"||dz
  <   t
          |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   rX   r(   r   r   r   rf   rn   r4   rr   ru   listrandomsampleremovert   _modgcd_multivariate_p	is_groundr_   r   r   r   )#r   r   r"   degbound	contboundr   r`   rL   deghr   r   re   contgconthdegcontfdegcontgdegconthrm   lcgr}   evaltestr<   r   r   r9   dr   hevalpointsr~   r   fagahadegyhs#                                      r   r   r     ss   ` 6D
AAv 
Aq!))!,,xxzz(1+ 	4(1+ 	#HQK""HHQqSMMEHHQqSMME!QHE1!QHE1E5!$$E||~~H||~~H||~~H)AaC.  t)AaC.  !	!A#
a&&C
a&&CCa  EH1Q3ZZ C CGCa,,c%1++.>.>BBB||~~HEHeh.QqSMIacN*X5	7 	79:	;A 	1u t	A	AJE%((^^F
 +M&!$$Q'a  A&&* 	1%%)ZZ!Q,,Q//ZZ!Q,,Q// $BAxCC 	FA1u t< 	t$$11!44AH]]6""//22!R	Q6 	)*eT1Q3JJA1a  #ennT&:&::AHHQqSMMEx!}$ tx!}$ ' %1&&HW  +Z 4r   c           	         | j         |j         k    r| j         j        j        sJ t          | |          }||S | j         }|j        }|                                 \  }} |                                \  }}|j                            ||          }|j                            | j        |j                  }|j        j        }	t          |          D ]F}
|	|j                            t          | |
          j        t          ||
          j                  z  }	Gd t          |                                 |                                          D             }t          |          }d}d}	 t          |          }|	|z  dk    rt          |          }|	|z  dk    |                     |          }|                    |          }	 t!          |||||          }n# t"          $ r d}Y ~w xY w||                    |                              |          }|dk    r|}|}t'          ||||          }||z  }||k    s|}|                                d         }|                     |          \  }}|                    |          \  }}|sZ|sX|j        dk     r| }|                    |          }|                    ||z            }|                    ||z            }|||f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                 4    g | ]\  }}t          ||          S  )ru   ).0fdeggdegs      r   
<listcomp>z'modgcd_multivariate.<locals>.<listcomp>  s$    PPPJD$D$PPPr   r*   Tr   )r   r   r?   r   rX   r@   r+   r   r   r4   rr   r   degreesr   r   r   r   r   r   r   rC   )r   r   rD   r   r`   rE   rF   rG   r,   rx   r<   r   r   rI   r"   r    r!   r-   rJ   rK   rL   rM   rN   rO   rP   rQ   rR   s                              r   modgcd_multivariater   &  s   \ 6QV3 3333!QF 6D
A KKMMEBKKMMEB	R	 	 BKOOAD!$''EI1XX E ET[__U1a[[^U1a[[^DDD		PP#aiikk199;;2O2OPPPHXI	A	A(aLL!mq  	!A !mq  	 ^^A^^A	'B8YGGBB 	 	 	AH	  	]]5!!..q116 	AF;B1MM	QV| 	FLLNN1UU1XX
dUU1XX
d 	D 	tax SR  A//"(++C//"(++Cc3;Q(s   G G&%G&c                     | j         }t          |                                 |                                ||j                  \  }}|                    |          |                    |          fS )z_
    Compute `\frac f g` modulo `p` for two univariate polynomials over
    `\mathbb Z_p`.
    )r   r   to_denser   r]   )r   r   r"   r   densequodenserems         r   _gf_divr     sX    
 6D

ajjllAt{KKHh??8$$dooh&?&???r   c                 (   | j         }|j        }|                                }|dz  }||z
  dz
  }||j        }	}| |j        }}
|
                                |k    rit          ||
|          d         }|
|||
z  z
                      |          }
}||	||z  z
                      |          }}	|
                                |k    i|
|}}|                                |k    st          |||          dk    rdS |j        }|dk    rf|	                    ||          }|
                    |                              |          }|
                    |                              |          }|                                } ||           ||          z  S )a  
    Reconstruct a rational function `\frac a b` in `\mathbb Z_p(t)` from

    .. math::

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

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

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

    Parameters
    ==========

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

    Returns
    =======

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

    References
    ==========

    1. [Hoeij04]_

       r*   r   N)r   r   r   r   r   r   r   r(   r   r   r   to_field)cr"   rI   r   r   Mr   Dr0s0r1s1r^   r~   r   lcr&   fields                     r   !_rational_function_reconstructionr     s   J 6D[F	

A	QA	A	A	BB
))++/ 3b"a  #b3r6k//22Bb3r6k//22B ))++/ 3
 rqAxxzzA~ Aq))Q. t	
B	Qw 0b!$$LL,,Q//LL,,Q//MMOOE588eeAhhr   c                 6   |j         }|                                 D ]|\  }}|dk    rt          |||          }|s dS nU|j        j         }|                    |                                          D ]!\  }	}
t          |
||          }|s  dS |||	<   "|||<   }|S )a  
    Reconstruct every coefficient `c_h` of a polynomial `h` in
    `\mathbb Z_p(t_k)[t_1, \ldots, t_{k-1}][x, z]` from the corresponding
    coefficient `c_{h_m}` of a polynomial `h_m` in
    `\mathbb Z_p[t_1, \ldots, t_k][x, z] \cong \mathbb Z_p[t_k][t_1, \ldots, t_{k-1}][x, z]`
    such that

    .. math::

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

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

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

    Parameters
    ==========

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

    Returns
    =======

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

    See also
    ========

    _rational_function_reconstruction

    r   N)r   rY   r   r   drop_to_ground)rK   r"   rI   r   r`   rL   rb   r5   coeffhmonr   rG   s               r   $_rational_reconstruction_func_coeffsr     s    \ 		A  u6 	!6uaCCF tt [%F..q11;;== ! !Q6q!Q??  444 s%Hr   c                 
   | 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   r]   )r   r   r"   r   strL   s          r   	_gf_gcdexr   K  sg     6Dqzz||QZZ\\1dkBBGAq!??1tq114??13E3EEEr   c                     | 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   r_   
ground_newr   r$   )r   minpolyr"   r   p_s        r   _truncr   Y  sa    0 6Dt$$G			B>>!  '2//<<Q???r   c                    | j         }t          | ||          } t          |||          }|r| }|                    d          }t          |                    |          ||          \  }}}	|	dk    sdS 	 |                    d          }
|
|k     rn[||                    |          z                      |          }t          ||                    |
|z
  df          |z  z
  ||          }w|} |}|t          |                    |           ||          d                             |          }t          | |z  ||          S )a
  
    Compute the monic GCD of two univariate polynomials in
    `\mathbb{Z}_p[z]/(\check m_{\alpha}(z))[x]` with the Euclidean
    Algorithm.

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

    Parameters
    ==========

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

    Returns
    =======

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

    r   r*   N)r   r   r   r   dmp_LCr_   r   )r   r   r   r"   r   r$   r%   r&   _r+   r'   r^   lcfinvs                r   _euclidean_algorithmr   x  sU   8 6Dq'1Aq'1A
 hhqkk!$++a..'1==q#ax 	4	OZZ]]F| 4;;s+++55d;;Cq{{FSL!+<==cAA7ANNC	O !  $ t{{1~~w2215>>tDDF!f*gq)))r   c                    | j         }|                    |j        d         |j        d         f          }|                    |          }| }|                                }|                                }|                    d          }	t          |                              |          }
|j        }|r9||k    r2t          |                              |          }||
z  |                    ||z
  df          |z  z
  }|r|                    |          }|                    d          }|r||	k    rt          |                    |                                        |          }|	                    |          |                    d||	z
  f          |z  z
  }|r|                    |          }|                    d          }|r||	k    |                                }|r||k    2|S )a=  
    Check if `h` divides `f` in
    `\mathbb K[t_1, \ldots, t_k][z]/(m_{\alpha}(z))`, where `\mathbb K` is
    either `\mathbb Q` or `\mathbb Z_p`.

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

    Parameters
    ==========

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

    Returns
    =======

    rem : PolyElement
        remainder of `\frac f h`

    References
    ==========

    .. [1] [Hoeij02]_

    r*   r   rV   )
r   r\   rW   r_   r   rn   r   r   r   r   )r   rL   r   r"   r   zxringr$   r'   r   degmlchlcmlcrems                r   _trial_divisionr     s   B 6DZZa$,q/ BZCCFt$$G
CZZ\\F88::D>>!D
a&&//$

C
*C
 &D. C!!$''#gVd]A$677== 	&""1%%CA 	#fn 	#V,,--66t<<E..%%(9(91ftm:L(M(Me(SSC *&&q))ZZ]]F  	#fn 	# !  &D. $ Jr   c                     | j                             | j         j        j                             |                    }|j        }|                                 D ]\  }}|                    ||          ||<   |S )z[
    Evaluate a polynomial `f` at `a` in the `i`-th variable of the ground
    domain.
    r   )r   r\   r   dropr   rY   rt   )r   r<   r~   r   r   rb   r5   s          r   _evaluate_groundr     sn    
 6<<qv}166q99<::D	B ) )uNN1a((5		Ir   c           
         | j         }|j        }t          |t                    r|j        }nt          | |||          S |dk    r|j                                         }nO|j                             |dz
            }|                    |j        j                                                   }|                    |          }d}	d}
|	                    |           |	                    |          z  }|j
        }g }g }g }t          t          |                    }|rt          j        |d          d         }|                    |           |dk    r!|                    |dz
  |          |z  dk    }n0|                    |dz
  |                              |          dk    }|rt%          ||dz
  |          }t%          ||dz
  |          }|                    ||                     |          g          dk    rt%          | |dz
  |          }t%          ||dz
  |          }t)          ||||          }||
dz  }
|
|	k    rdS /|dk    r|S |                                gdg|dz
  z  z   }|dk    rX|                                D ]C\  }}|d         |d         k    r,|j        t1          |dd                   k    r|j        |dd<   D|g}|g}|dk    r|j                                        j        }n#|j        j                                        j        }|j         j        d         }t9          |||          D ]>\  }} }!|!|k    r2|                    |           |                    |            |||z
  z  }?|                    |          }|                    |           |                    |           |                    |           |	dz  }	t=          ||||dz
  |d          }"t?          |"||||dz
            }"|"|dk    r|j        j         }#|#j         j        }$|"!                                D ]Z}|#j         "                    tG          |$$                                |j%        $                                ||#j                            }$[n|j        j        j         }#|#j         j        }$|"!                                D ]q}|!                                D ]Z}%|#j         "                    tG          |$$                                |%j%        $                                ||#j                            }$[r|&                    |$                    |                    }$ ||"'                    |$          (                                                              |          }"tS          | |"||          stS          ||"||          s|"S |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   r   r   rX   r   r   r   r\   r   r   r   r4   r   r   r   rt   r   r   r$   _func_field_modgcd_pr   rY   LMtupleget_ringr   r3   r   r   r   r   r   
itercoeffsr]   r   r   r   
domain_newr   as_exprr   )&r   r   r   r"   r   r   r`   qdomainqringr9   r   r,   r}   r   r   LMlistr   r~   testgammaaminpolyar   r   r   r   rb   r5   evalpoints_aheval_arI   r   r   hbLMhbrL   r#   denr   s&                                         r   r   r     s   T 6D[F&.)) 6L#Aq'1555Av G+&&((+,,QU33--w~':'C'C'E'E-FFJJgJ&&E	A	A KKNNT[[^^+EJEJEF%((^^F
 ZM&!$$Q'a6 	?>>!A#q))A-2DD>>!A#q))66q99Q>D 	!%1a00#GQqS!44::xQ011Q6 	a1a((a1a(( ""b(A66 	FA1u t7 	Iiikk]aS!A#Y&q5 	& " & &u8r!u$ &E"QRR&MM)A &"XBqrrFs$6 	3%%''+AA#,,..2AFKNz5&99 	 	KAr4rz ##A&&&r"""a!eNN1!Rb	Q &lGT1Q3RVWWW 1Aq%1EE 	6 	,,$C(,C ( (h))&AUAUAWAW3:+' +' ( ((
 ,%+C(,C , ,))++ , ,A(--fS\\^^QWEUEUEWEWsz/+ /+ , ,CC, s//2233Dc""**,,--::1==q!Wa00 	AwXY9Z9Z 	Hu  Zx 4r   c                 ^   | dk     r| |z  } ||j         }}| |j        }}t          |dz            }||k    r||z  }||||z  z
  }}||||z  z
  }}||k    t          |          |k    rdS |dk     r| | }
}	n|dk    r||}
}	ndS |                                } ||	           ||
          z  S )a  
    Reconstruct a rational number `\frac a b` from

    .. math::

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

    where `c` and `m` are integers.

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

    Parameters
    ==========

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

    Returns
    =======

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

    References
    ==========

    1. [Wang81]_

    r   r   N)r   r   r   abs	get_field)r   rI   r   r   r   r   r   rH   r^   r~   r   r   s               r    _integer_rational_reconstructionr    s   H 	1u 	QB
BQKKE
+ !BhR#b&[BR#b&[B + !
 2ww% t	Av sRC1	a 21tE588eeAhhr   c                     |j         }t          |j        t                    rt          }|j        j        }nt          }| j        j        }|                                 D ]\  }} ||||          }|s dS |||<   |S )a  
    Reconstruct every rational coefficient `c_h` of a polynomial `h` in
    `\mathbb Q[t_1, \ldots, t_k][x, z]` from the corresponding integer
    coefficient `c_{h_m}` of a polynomial `h_m` in
    `\mathbb Z[t_1, \ldots, t_k][x, z]` such that

    .. math::

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

    where `m \in \mathbb Z`.

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

    Parameters
    ==========

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

    Returns
    =======

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

    See also
    ========

    _integer_rational_reconstruction

    N)r   r   r   r   #_rational_reconstruction_int_coeffsr   r  rY   )	rK   rI   r   rL   reconstructionr   rb   r5   r   s	            r   r  r    s    R 		A$+~..  <!9  uq&11 	44%Hr   c                    | j         }|j        }t          |t                    rP|j        }|j                             |j                                                  }|                    |          }n/d}|                    |j                                                  }|                                 \  }} |                                \  }	}|                    |           |                    |          z  }
|j	        }d}g }g }g }	 t          |          }|
                    |          dk    r*|dk    r
||z  dk    }n|                    |          dk    }|rV|                     |          }|                    |          }|                    |          }t          ||||          }||dk    r|j        S |                                gdg|z  z   }|dk    rX|                                D ]C\  }}|d         |d         k    r,|j        t#          |dd                   k    r|j        |dd<   D|}|}t%          |||          D ]#\  }}}||k    rt'          ||||          }||z  }$|                    |           |                    |           |                    |           t+          |||          }||dk    r|                                d         }nk|j        j        }|                                D ]5}|j                            ||                                d                   }6|                    |          }|                    |          }|                                d         }t7          |                     |          ||          s&t7          |                    |	          ||          s|S )a  
    Compute the GCD of two polynomials in
    `\mathbb Q(t_1, \ldots, t_k)[z]/(m_{\alpha}(z))[x]` using a modular
    algorithm.

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

    Parameters
    ==========

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

    Returns
    =======

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

    Examples
    ========

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

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

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

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

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

    References
    ==========

    1. [Hoeij04]_

    See also
    ========

    _func_field_modgcd_p

    r   r   r*   TN)r   r   r   r   rX   r\   r  r@   r   r   r   r   r   r   r   rY   r   r   r   r   r   r  clear_denomsr  r   r   r_   r   )r   r   r   r   r   r`   QQdomainQQringrE   rF   r,   r}   r"   primeshplistr  r  r    r!   minpolypr-   r   rb   r5   rK   rI   r8   r7   LMhqrL   r  s                                  r   _func_field_modgcd_mr  &  s   D 6D[F&.)) <L;$$FM,C,C,E,E$FF8,,4;#8#8#:#:;;KKMMEBKKMMEB KKNNT[[^^+EJE	AFFF?aLLa  A% 	6 	0AINDD&&q))Q.D 	^^A^^A''**!"b(A66 	7 	8Oiikk]aSU"q5 	& " & &u8r!u$ &E"QRR&MM)A &"XBqrrFvvv66 	 	KAr4rz CBAqQQQabb0Q?? 	6 	#!!!$AA-#C F Fm''U-?-?-A-A!-DEEc""A JJtKKMM!R 0 0!W== 	ALL,,a99	H?r   c                    |j         }t          |j        t                    r|j        j        }n|j        }|j        }|                                 D ])}|j        D ]}|r|                    ||j                  } *| 	                                D ]\  }}|j        }|j        j        }t          |j        t                    r|
                    |dd                   }t          |          }	t          |	          D ]e}
||
         r[ |||
         |z            |z  }|d         |	|
z
  dz
  f|vr|||d         |	|
z
  dz
  f<   G||d         |	|
z
  dz
  fxx         |z  cc<   f|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  repr   denominatorrY   r   lenr4   )r   r   f_r   r  r5   r   rb   rI   r9   r<   s              r   _to_ZZ_polyr$    s   2 
B$+~.. #
*C 5 5 	5 	5A 5jjam44	5  / /u	KOdk>22 	'E!""I&&AJJq 	/ 	/AQx /F58c>**Q.!Hac!e$B. /,-Ba!A#a%())a!A#a%()))Q.)))	/ Ir   c                 @   |j         }|j        }t          | j        j         t                    r|                                 D ]q\  }}|                                D ]W\  }}|d         f|z   } ||                     |          gdg|d         z  z             }	||vr|	||<   G||xx         |	z  cc<   Xrni|                                 D ]T\  }}|d         f} ||                     |          gdg|d         z  z             }	||vr|	||<   D||xx         |	z  cc<   U|S )ar  
    Convert a polynomial
    `f \in \mathbb Z[x_1, \ldots, x_{n-1}][z]/(\check m_{\alpha}(z))[x_0]`
    to a polynomial in `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]`,
    where `\check m_{\alpha}(z) \in \mathbb Z[z]` is the primitive associate
    of the minimal polynomial `m_{\alpha}(z)` of `\alpha` over
    `\mathbb Q`.

    Parameters
    ==========

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

    Returns
    =======

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

    r   r*   )r   r   r   r   r   rY   )
r   r   r   r#  rb   r5   r   coefrI   r   s
             r   _to_ANP_polyr'    s]   0 [F	B!&-00 KKMM 	 	LE5"__..  	T1XK#%FFMM$//0A3uQx<?@@B; BqEEqEEEQJEEEE	 KKMM 	 	LE5qAe,,-E!H<==A{ 11
Ir   c                 x    |j         }|                                 D ]\  }}|                    |          ||<   |S )zo
    Change representation of the minimal polynomial from ``DMP`` to
    ``PolyElement`` for a given ring.
    )r   termsr   )r   r   minpoly_rb   r5   s        r   _minpoly_from_denser+  /  sB    
 yH - -u++e,,Or   c                 z   | j         } |j        t          d|j                   }|j        j         } ||                                           }|j        }|                                D ])}t          ||          d         }||j	        k    r|| fc S *|| 
                    |                    |                    fS )z
    Compute the content in `x_0` and the primitive part of a polynomial `f`
    in
    `\mathbb Q(\alpha)[x_0, x_1, \ldots, x_{n-1}] \cong \mathbb Q(\alpha)[x_1, \ldots, x_{n-1}][x_0]`.
    r*   r   )r   r   r4   rX   r   r  r   r  func_field_modgcdr   r^   r_   )r   fringr   r#   r#  rc   r5   s          r   _primitive_in_x0r/  <  s     FE5q%+!6!67D
+
C	aiikk		B8D   u--a037? 	7NNN	 t}}U++,,,,r   c                    | j         }|j        }|j        }||j         k    r|j        sJ t	          | |          }||S t          d          }|                    |j        |fz   |j                                                  }|dk    rut          | |          }t          ||          }	|
                    d                              |j        j                  }
t          ||	|
          }t          ||          }nt!          |           \  }} t!          |          \  }}t#          ||          d         } |j        t'          d|           }t          | |          }t          ||          }	t)          |j        |
                    d                    }
t          ||	|
          }t          ||          }t!          |          \  }}||                    |          z  }| |                    |          z  } ||                    |          z  }|                    |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)rW   r   r*   r   )r   r   rX   is_Algebraicr   r   r\   rW   r   r$  r   r]   modr   r  r'  r/  r-  r   r4   r+  r_   rA   r   r^   )r   r   r   r   r9   rD   r1  ZZringr#  g_r   rL   contx0fcontx0gcontx0hZZring_contx0h_s                    r   r-  r-  Q  s)   P 6D[F
A16>1f1111!QF c

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