U
    L?hM                     @   s  d Z ddlmZmZmZmZmZmZmZm	Z	m
Z
mZ ddlmZmZmZmZmZmZmZmZmZmZmZmZ ddlmZmZmZmZmZmZm Z m!Z!m"Z" ddl#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z) ddl*m+Z+m,Z, ddl-m.Z.m/Z/ dd	 Z0d
d Z1dd Z2dd Z3dd Z4dd Z5dd Z6dd Z7dd Z8dd Z9dd Z:dd Z;d2d!d"Z<d3d#d$Z=d4d%d&Z>d5d'd(Z?d6d)d*Z@d7d+d,ZAd-d. ZBd/d0 ZCd1S )8z8Square-free decomposition algorithms and related tools.     )
dup_negdmp_negdup_subdmp_subdup_muldmp_muldup_quodmp_quodup_mul_grounddmp_mul_ground)	dup_stripdup_LCdmp_ground_LC
dmp_zero_p
dmp_ground
dup_degree
dmp_degreedmp_degree_indmp_degree_list	dmp_raise
dmp_injectdup_convert)	dup_diffdmp_diffdmp_diff_in	dup_shift	dmp_shift	dup_monicdmp_ground_monicdup_primitivedmp_ground_primitive)dup_inner_gcddmp_inner_gcddup_gcddmp_gcddmp_resultantdmp_primitive)gf_sqf_listgf_sqf_part)MultivariatePolynomialErrorDomainErrorc                 C   s&   t dd |D }|t| ks"tdS )z=Sanity check the degrees of a computed factorization in K[x].c                 s   s   | ]\}}|t | V  qd S )N)r   ).0fack r.   I/var/www/html/venv/lib/python3.8/site-packages/sympy/polys/sqfreetools.py	<genexpr>$   s     z%_dup_check_degrees.<locals>.<genexpr>N)sumr   AssertionError)fresultdegr.   r.   r/   _dup_check_degrees"   s    r6   c                    sX   dg|d  }|D ]*\} t ||} fddt||D }qt|t | |ksTtdS )z=Sanity check the degrees of a computed factorization in K[X].r      c                    s   g | ]\}}| |  qS r.   r.   )r+   Zd1Zd2r-   r.   r/   
<listcomp>-   s     z&_dmp_check_degrees.<locals>.<listcomp>N)r   ziptupler2   )r3   ur4   Zdegsr,   Zdegs_facr.   r8   r/   _dmp_check_degrees(   s
    
r=   c                 C   s&   | sdS t t| t| d|| S dS )a  
    Return ``True`` if ``f`` is a square-free polynomial in ``K[x]``.

    Examples
    ========

    >>> from sympy.polys import ring, ZZ
    >>> R, x = ring("x", ZZ)

    >>> R.dup_sqf_p(x**2 - 2*x + 1)
    False
    >>> R.dup_sqf_p(x**2 - 1)
    True

    Tr7   N)r   r#   r   )r3   Kr.   r.   r/   	dup_sqf_p1   s    r?   c                 C   sd   t | |rdS t|d D ]D}t| d|||}t ||r:qt| |||}t|||dkr dS qdS )a  
    Return ``True`` if ``f`` is a square-free polynomial in ``K[X]``.

    Examples
    ========

    >>> from sympy.polys import ring, ZZ
    >>> R, x,y = ring("x,y", ZZ)

    >>> R.dmp_sqf_p(x**2 + 2*x*y + y**2)
    False
    >>> R.dmp_sqf_p(x**2 + y**2)
    True

    Tr7   r   F)r   ranger   r$   r   )r3   r<   r>   ifpgcdr.   r.   r/   	dmp_sqf_pG   s    

rD   c                 C   s   |j stddt|j dd|j }}t| d|dd\}}t||d|j}t||jr^qzq*t	| |j
 ||d  } }q*|| |fS )ag  
    Find a shift of `f` in `K[x]` that has square-free norm.

    The domain `K` must be an algebraic number field `k(a)` (see :ref:`QQ(a)`).

    Returns `(s,g,r)`, such that `g(x)=f(x-sa)`, `r(x)=\text{Norm}(g(x))` and
    `r` is a square-free polynomial over `k`.

    Examples
    ========

    We first create the algebraic number field `K=k(a)=\mathbb{Q}(\sqrt{3})`
    and rings `K[x]` and `k[x]`:

    >>> from sympy.polys import ring, QQ
    >>> from sympy import sqrt

    >>> K = QQ.algebraic_field(sqrt(3))
    >>> R, x = ring("x", K)
    >>> _, X = ring("x", QQ)

    We can now find a square free norm for a shift of `f`:

    >>> f = x**2 - 1
    >>> s, g, r = R.dup_sqf_norm(f)

    The choice of shift `s` is arbitrary and the particular values returned for
    `g` and `r` are determined by `s`.

    >>> s == 1
    True
    >>> g == x**2 - 2*sqrt(3)*x + 2
    True
    >>> r == X**4 - 8*X**2 + 4
    True

    The invariants are:

    >>> g == f.shift(-s*K.unit)
    True
    >>> g.norm() == r
    True
    >>> r.is_squarefree
    True

    Explanation
    ===========

    This is part of Trager's algorithm for factorizing polynomials over
    algebraic number fields. In particular this function is algorithm
    ``sqfr_norm`` from [Trager76]_.

    See Also
    ========

    dmp_sqf_norm:
        Analogous function for multivariate polynomials over ``k(a)``.
    dmp_norm:
        Computes the norm of `f` directly without any shift.
    dup_ext_factor:
        Function implementing Trager's algorithm that uses this.
    sympy.polys.polytools.sqf_norm:
        High-level interface for using this function.
    ground domain must be algebraicr   r7   TZfront)is_Algebraicr*   r   modto_listdomr   r%   r?   r   unit)r3   r>   sgh_rr.   r.   r/   dup_sqf_normi   s    ArQ   c                 #   s   |d }dg| }|| fV  |j  t| |}dd tt|t|d D }|D ]>}| }d||<  fdd|D }	t| |	||}
||
fV  qPd}|d7 }|g| }  | g| }t| |||}||fV  qdS )z9Generate a sequence of candidate shifts for dmp_sqf_norm.r7   r   c                 S   s   g | ]\}}|d kr|qS )r   r.   )r+   ZdirA   r.   r.   r/   r9      s      z(_dmp_sqf_norm_shifts.<locals>.<listcomp>c                    s   g | ]}  | qS r.   r.   )r+   Zs1iar.   r/   r9      s     N)rK   r   sortedr:   r@   copyr   )r3   r<   r>   ns0dZvar_indicesrA   s1Za1f1jZsjZajfjr.   rR   r/   _dmp_sqf_norm_shifts   s$    


 
r]   c                 C   s   |s t | |\}}}|g||fS |js.tdt|j |d d|j}t| ||D ]B\}} t| ||dd\}}t	|||d |j}t
|||jrT qqT|| |fS )a  
    Find a shift of ``f`` in ``K[X]`` that has square-free norm.

    The domain `K` must be an algebraic number field `k(a)` (see :ref:`QQ(a)`).

    Returns `(s,g,r)`, such that `g(x_1,x_2,\cdots)=f(x_1-s_1 a, x_2 - s_2 a,
    \cdots)`, `r(x)=\text{Norm}(g(x))` and `r` is a square-free polynomial over
    `k`.

    Examples
    ========

    We first create the algebraic number field `K=k(a)=\mathbb{Q}(i)` and rings
    `K[x,y]` and `k[x,y]`:

    >>> from sympy.polys import ring, QQ
    >>> from sympy import I

    >>> K = QQ.algebraic_field(I)
    >>> R, x, y = ring("x,y", K)
    >>> _, X, Y = ring("x,y", QQ)

    We can now find a square free norm for a shift of `f`:

    >>> f = x*y + y**2
    >>> s, g, r = R.dmp_sqf_norm(f)

    The choice of shifts ``s`` is arbitrary and the particular values returned
    for ``g`` and ``r`` are determined by ``s``.

    >>> s
    [0, 1]
    >>> g == x*y - I*x + y**2 - 2*I*y - 1
    True
    >>> r == X**2*Y**2 + X**2 + 2*X*Y**3 + 2*X*Y + Y**4 + 2*Y**2 + 1
    True

    The required invariants are:

    >>> g == f.shift_list([-si*K.unit for si in s])
    True
    >>> g.norm() == r
    True
    >>> r.is_squarefree
    True

    Explanation
    ===========

    This is part of Trager's algorithm for factorizing polynomials over
    algebraic number fields. In particular this function is a multivariate
    generalization of algorithm ``sqfr_norm`` from [Trager76]_.

    See Also
    ========

    dup_sqf_norm:
        Analogous function for univariate polynomials over ``k(a)``.
    dmp_norm:
        Computes the norm of `f` directly without any shift.
    dmp_ext_factor:
        Function implementing Trager's algorithm that uses this.
    sympy.polys.polytools.sqf_norm:
        High-level interface for using this function.
    rE   r7   r   TrF   )rQ   rG   r*   r   rH   rI   rJ   r]   r   r%   rD   )r3   r<   r>   rL   rM   rP   rN   rO   r.   r.   r/   dmp_sqf_norm   s    Br^   c                 C   sP   |j stdt|j |d d|j}t| ||dd\}}t|||d |jS )aE	  
    Norm of ``f`` in ``K[X]``, often not square-free.

    The domain `K` must be an algebraic number field `k(a)` (see :ref:`QQ(a)`).

    Examples
    ========

    We first define the algebraic number field `K = k(a) = \mathbb{Q}(\sqrt{2})`:

    >>> from sympy import QQ, sqrt
    >>> from sympy.polys.sqfreetools import dmp_norm
    >>> k = QQ
    >>> K = k.algebraic_field(sqrt(2))

    We can now compute the norm of a polynomial `p` in `K[x,y]`:

    >>> p = [[K(1)], [K(1),K.unit]]                  # x + y + sqrt(2)
    >>> N = [[k(1)], [k(2),k(0)], [k(1),k(0),k(-2)]] # x**2 + 2*x*y + y**2 - 2
    >>> dmp_norm(p, 1, K) == N
    True

    In higher level functions that is:

    >>> from sympy import expand, roots, minpoly
    >>> from sympy.abc import x, y
    >>> from math import prod
    >>> a = sqrt(2)
    >>> e = (x + y + a)
    >>> e.as_poly([x, y], extension=a).norm()
    Poly(x**2 + 2*x*y + y**2 - 2, x, y, domain='QQ')

    This is equal to the product of the expressions `x + y + a_i` where the
    `a_i` are the conjugates of `a`:

    >>> pa = minpoly(a)
    >>> pa
    _x**2 - 2
    >>> rs = roots(pa, multiple=True)
    >>> rs
    [sqrt(2), -sqrt(2)]
    >>> n = prod(e.subs(a, r) for r in rs)
    >>> n
    (x + y - sqrt(2))*(x + y + sqrt(2))
    >>> expand(n)
    x**2 + 2*x*y + y**2 - 2

    Explanation
    ===========

    Given an algebraic number field `K = k(a)` any element `b` of `K` can be
    represented as polynomial function `b=g(a)` where `g` is in `k[x]`. If the
    minimal polynomial of `a` over `k` is `p_a` then the roots `a_1`, `a_2`,
    `\cdots` of `p_a(x)` are the conjugates of `a`. The norm of `b` is the
    product `g(a1) \times g(a2) \times \cdots` and is an element of `k`.

    As in [Trager76]_ we extend this norm to multivariate polynomials over `K`.
    If `b(x)` is a polynomial in `k(a)[X]` then we can think of `b` as being
    alternately a function `g_X(a)` where `g_X` is an element of `k[X][y]` i.e.
    a polynomial function with coefficients that are elements of `k[X]`. Then
    the norm of `b` is the product `g_X(a1) \times g_X(a2) \times \cdots` and
    will be an element of `k[X]`.

    See Also
    ========

    dmp_sqf_norm:
        Compute a shift of `f` so that the `\text{Norm}(f)` is square-free.
    sympy.polys.polytools.Poly.norm:
        Higher-level function that calls this.
    rE   r7   r   TrF   )rG   r*   r   rH   rI   rJ   r   r%   )r3   r<   r>   rM   rN   rO   r.   r.   r/   dmp_norm9  s
    Hr_   c                 C   s,   t | ||j} t| |j|j}t ||j|S )z3Compute square-free part of ``f`` in ``GF(p)[x]``. )r   rJ   r(   rH   )r3   r>   rM   r.   r.   r/   dup_gf_sqf_part  s    r`   c                 C   s   t ddS )z3Compute square-free part of ``f`` in ``GF(p)[X]``. +multivariate polynomials over finite fieldsNNotImplementedErrorr3   r<   r>   r.   r.   r/   dmp_gf_sqf_part  s    re   c                 C   st   |j rt| |S | s| S |t| |r2t| |} t| t| d||}t| ||}|jrbt	||S t
||d S dS )a  
    Returns square-free part of a polynomial in ``K[x]``.

    Examples
    ========

    >>> from sympy.polys import ring, ZZ
    >>> R, x = ring("x", ZZ)

    >>> R.dup_sqf_part(x**3 - 3*x - 2)
    x**2 - x - 2

    See Also
    ========

    sympy.polys.polytools.Poly.sqf_part
    r7   N)is_FiniteFieldr`   is_negativer   r   r#   r   r   is_Fieldr   r   )r3   r>   rC   sqfr.   r.   r/   dup_sqf_part  s    


rj   c              	   C   s   |st | |S |jr t| ||S t| |r.| S |t| ||rLt| ||} | }t|d D ]}t|t	| d|||||}q\t
| |||}|jrt|||S t|||d S dS )z
    Returns square-free part of a polynomial in ``K[X]``.

    Examples
    ========

    >>> from sympy.polys import ring, ZZ
    >>> R, x,y = ring("x,y", ZZ)

    >>> R.dmp_sqf_part(x**3 + 2*x**2*y + x*y**2)
    x**2 + x*y

    r7   N)rj   rf   re   r   rg   r   r   r@   r$   r   r	   rh   r   r    )r3   r<   r>   rC   rA   ri   r.   r.   r/   dmp_sqf_part  s    

rk   Fc                 C   sr   | }t | ||j} t| |j|j|d\}}t|D ]"\}\} }t | |j||f||< q2t|| |||j|fS )z<Compute square-free decomposition of ``f`` in ``GF(p)[x]``. all)r   rJ   r'   rH   	enumerater6   convert)r3   r>   rm   f_origcoefffactorsrA   r-   r.   r.   r/   dup_gf_sqf_list  s    
rs   c                 C   s   t ddS )z<Compute square-free decomposition of ``f`` in ``GF(p)[X]``. ra   Nrb   )r3   r<   r>   rm   r.   r.   r/   dmp_gf_sqf_list  s    rt   c                 C   s  |j rt| ||dS | }|jr4t| |}t| |} n.t| |\}} |t| |rbt| |} | }t| dkrv|g fS g d }}t	| d|}t
| ||\}}	}
t	|	d|}t|
||}|s||	|f qt
|	||\}}	}
|st|dkr|||f |d7 }qt|| ||fS )a  
    Return square-free decomposition of a polynomial in ``K[x]``.

    Uses Yun's algorithm from [Yun76]_.

    Examples
    ========

    >>> from sympy.polys import ring, ZZ
    >>> R, x = ring("x", ZZ)

    >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16

    >>> R.dup_sqf_list(f)
    (2, [(x + 1, 2), (x + 2, 3)])
    >>> R.dup_sqf_list(f, all=True)
    (2, [(1, 1), (x + 1, 2), (x + 2, 3)])

    See Also
    ========

    dmp_sqf_list:
        Corresponding function for multivariate polynomials.
    sympy.polys.polytools.sqf_list:
        High-level function for square-free factorization of expressions.
    sympy.polys.polytools.Poly.sqf_list:
        Analogous method on :class:`~.Poly`.

    References
    ==========

    [Yun76]_
    rl   r   r7   )rf   rs   rh   r   r   r   rg   r   r   r   r!   r   appendr6   )r3   r>   rm   rp   rq   r4   rA   rN   rM   pqrX   r.   r.   r/   dup_sqf_list  s4    "




rx   c                 C   sl   t | ||d\}}|rP|d d dkrPt|d d ||}|dfg|dd  S t|g}|dfg| S dS )a  
    Return square-free decomposition of a polynomial in ``K[x]``.

    Examples
    ========

    >>> from sympy.polys import ring, ZZ
    >>> R, x = ring("x", ZZ)

    >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16

    >>> R.dup_sqf_list_include(f)
    [(2, 1), (x + 1, 2), (x + 2, 3)]
    >>> R.dup_sqf_list_include(f, all=True)
    [(2, 1), (x + 1, 2), (x + 2, 3)]

    rl   r   r7   N)rx   r
   r   )r3   r>   rm   rq   rr   rM   r.   r.   r/   dup_sqf_list_includeA  s    
ry   c                    s  |st | ||dS |jr(t| |||dS | }|jrLt| ||}t| ||} n4t| ||\}} |t| ||rt| ||} | }t	| |}|dk r|g fS t
| ||\}} i  |dkrNt| d||}t| |||\}	}
}d}t|
d||}t||||}t||r|
 |< qNt|
|||\}	}
}|s<t	|	|dkrD|	 |< |d7 }qt||d ||d\}}||9 }|D ]:\}}|g}| krt | ||| |< n| |< qr fddt D  t||  | fS )a1  
    Return square-free decomposition of a polynomial in `K[X]`.

    Examples
    ========

    >>> from sympy.polys import ring, ZZ
    >>> R, x,y = ring("x,y", ZZ)

    >>> f = x**5 + 2*x**4*y + x**3*y**2

    >>> R.dmp_sqf_list(f)
    (1, [(x + y, 2), (x, 3)])
    >>> R.dmp_sqf_list(f, all=True)
    (1, [(1, 1), (x + y, 2), (x, 3)])

    Explanation
    ===========

    Uses Yun's algorithm for univariate polynomials from [Yun76]_ recrusively.
    The multivariate polynomial is treated as a univariate polynomial in its
    leading variable. Then Yun's algorithm computes the square-free
    factorization of the primitive and the content is factored recursively.

    It would be better to use a dedicated algorithm for multivariate
    polynomials instead.

    See Also
    ========

    dup_sqf_list:
        Corresponding function for univariate polynomials.
    sympy.polys.polytools.sqf_list:
        High-level function for square-free factorization of expressions.
    sympy.polys.polytools.Poly.sqf_list:
        Analogous method on :class:`~.Poly`.
    rl   r   r7   c                    s   g | ]} | |fqS r.   r.   )r+   rA   r4   r.   r/   r9     s     z dmp_sqf_list.<locals>.<listcomp>)rx   rf   rt   rh   r   r   r    rg   r   r   r&   r   r"   r   r   dmp_sqf_listr   rT   r=   )r3   r<   r>   rm   rp   rq   r5   contentrN   rM   rv   rw   rA   rX   Zcoeff_contentZresult_contentr,   r.   rz   r/   r{   ]  sP    &



r{   c                 C   s   |st | ||dS t| |||d\}}|rf|d d dkrft|d d |||}|dfg|dd  S t||}|dfg| S dS )ah  
    Return square-free decomposition of a polynomial in ``K[x]``.

    Examples
    ========

    >>> from sympy.polys import ring, ZZ
    >>> R, x,y = ring("x,y", ZZ)

    >>> f = x**5 + 2*x**4*y + x**3*y**2

    >>> R.dmp_sqf_list_include(f)
    [(1, 1), (x + y, 2), (x, 3)]
    >>> R.dmp_sqf_list_include(f, all=True)
    [(1, 1), (x + y, 2), (x, 3)]

    rl   r   r7   N)ry   r{   r   r   )r3   r<   r>   rm   rq   rr   rM   r.   r.   r/   dmp_sqf_list_include  s    
r}   c                 C   s   | st dt| |} t| s"g S t| t| |j||}t||}t|D ]6\}\}}t|t||| ||}||d f||< qJt	| ||} t| s|S | dfg| S dS )z
    Compute greatest factorial factorization of ``f`` in ``K[x]``.

    Examples
    ========

    >>> from sympy.polys import ring, ZZ
    >>> R, x = ring("x", ZZ)

    >>> R.dup_gff_list(x**5 + 2*x**4 - x**3 - 2*x**2)
    [(x, 1), (x + 2, 4)]

    zDgreatest factorial factorization doesn't exist for a zero polynomialr7   N)

ValueErrorr   r   r#   r   onedup_gff_listrn   r   r   )r3   r>   rM   HrA   rN   r-   r.   r.   r/   r     s    

r   c                 C   s   |st | |S t| dS )z
    Compute greatest factorial factorization of ``f`` in ``K[X]``.

    Examples
    ========

    >>> from sympy.polys import ring, ZZ
    >>> R, x,y = ring("x,y", ZZ)

    N)r   r)   rd   r.   r.   r/   dmp_gff_list  s    
r   N)F)F)F)F)F)F)D__doc__Zsympy.polys.densearithr   r   r   r   r   r   r   r	   r
   r   Zsympy.polys.densebasicr   r   r   r   r   r   r   r   r   r   r   r   Zsympy.polys.densetoolsr   r   r   r   r   r   r   r   r    Zsympy.polys.euclidtoolsr!   r"   r#   r$   r%   r&   Zsympy.polys.galoistoolsr'   r(   Zsympy.polys.polyerrorsr)   r*   r6   r=   r?   rD   rQ   r]   r^   r_   r`   re   rj   rk   rs   rt   rx   ry   r{   r}   r   r   r.   r.   r.   r/   <module>   s4   08, 	"R(VQ$%


M

l
%