U
    ZÊ¹j¤M  ã                   @   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.   úV/var/www/html/bwave/python/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©Ú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rR   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  q”d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)rL   r   Úsortedr:   r@   Úcopyr   )r3   r<   r>   ÚnÚs0ÚdZvar_indicesrA   Ús1Za1Úf1ÚjZsjZajÚfjr.   rS   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 q˜qT|| |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   )rR   rH   r*   r   rI   rJ   rK   r^   r   r%   rD   )r3   r<   r>   rM   rN   rQ   rO   rP   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   )rH   r*   r   rI   rJ   rK   r   r%   )r3   r<   r>   rN   rO   rP   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   rK   r(   rI   )r3   r>   rN   r.   r.   r/   Údup_gf_sqf_partŠ  s    ra   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    rf   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_FiniteFieldra   Úis_negativer   r   r#   r   r   Úis_Fieldr   r   )r3   r>   rC   Úsqfr.   r.   r/   Údup_sqf_part–  s    


rk   c              	   C   s°   |st | |ƒS |jr t| ||ƒS t| |ƒr.| S | t| ||ƒ¡rLt| ||ƒ} | }t|d ƒD ]}t|t	| d|||ƒ||ƒ}q\t
| |||ƒ}|jrœt|||ƒ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)rk   rg   rf   r   rh   r   r   r@   r$   r   r	   ri   r   r    )r3   r<   r>   rC   rA   rj   r.   r.   r/   Údmp_sqf_partº  s    

rl   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   rK   r'   rI   Ú	enumerater6   Úconvert)r3   r>   rn   Úf_origÚcoeffÚfactorsrA   r-   r.   r.   r/   Údup_gf_sqf_listß  s    
rt   c                 C   s   t dƒ‚dS )z<Compute square-free decomposition of ``f`` in ``GF(p)[X]``. rb   Nrc   )r3   r<   r>   rn   r.   r.   r/   Údmp_gf_sqf_listï  s    ru   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
|	||ƒ\}}	}
|sît|ƒdkrü| ||f¡ |d7 }qžt||ƒ ||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]_
    rm   r   r7   )rg   rt   ri   r   r   r   rh   r   r   r   r!   r   Úappendr6   )r3   r>   rn   rq   rr   r4   rA   rO   rN   ÚpÚqrY   r.   r.   r/   Údup_sqf_listô  s4    "




ry   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)]

    rm   r   r7   N)ry   r
   r   )r3   r>   rn   rr   rs   rN   r.   r.   r/   Údup_sqf_list_includeA  s    
rz   c                    sØ  |st | ||d�S |jr(t| |||d�S | }|jrLt| ||ƒ}t| ||ƒ} n4t| ||ƒ\}} | t| ||ƒ¡r€t| ||ƒ} | }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 }qÞt||d ||d�\}}||9 }|D ]:\}}|g}|ˆ k�r¢tˆ | |||ƒˆ |< 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`.
    rm   r   r7   c                    s   g | ]}ˆ | |f‘qS r.   r.   )r+   rA   ©r4   r.   r/   r9   Â  s     z dmp_sqf_list.<locals>.<listcomp>)ry   rg   ru   ri   r   r   r    rh   r   r   r&   r   r"   r   r   Údmp_sqf_listr   rU   r=   )r3   r<   r>   rn   rq   rr   r5   ÚcontentrO   rN   rw   rx   rA   rY   Zcoeff_contentZresult_contentr,   r.   r{   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)]

    rm   r   r7   N)rz   r|   r   r   )r3   r<   r>   rn   rr   rs   rN   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_listro   r   r   )r3   r>   rN   ÚHrA   rO   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)   re   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   rR   r^   r_   r`   ra   rf   rk   rl   rt   ru   ry   rz   r|   r~   r�   rƒ   r.   r.   r.   r/   Ú<module>   s4   08, 	"R(VQ$%


M

l
%