
    wgM                     `   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 Z0d	 Z1d
 Z2d Z3d Z4d Z5d Z6d Z7d Z8d Z9d Z:d Z;ddZ<ddZ=ddZ>ddZ?ddZ@ddZAd ZBd ZCy)z8Square-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                 H    t        d |D              }|t        |       k(  sJ y)z=Sanity check the degrees of a computed factorization in K[x].c              3   >   K   | ]  \  }}|t        |      z    y w)N)r   ).0facks      \/home/mcse/projects/flask/flask-venv/lib/python3.12/site-packages/sympy/polys/sqfreetools.py	<genexpr>z%_dup_check_degrees.<locals>.<genexpr>$   s     9hsAa*S/!9s   N)sumr   )fresultdegs      r1   _dup_check_degreesr7   "   s$    
9&9
9C*Q-    c                     dg|dz   z  }|D ]5  \  }}t        ||      }t        ||      D cg c]  \  }}|||z  z    }}}7 t        |      t        | |      k(  sJ yc c}}w )z=Sanity check the degrees of a computed factorization in K[X].r      N)r   ziptuple)	r4   ur5   degsr/   r0   degs_facd1d2s	            r1   _dmp_check_degreesrB   (   sv    3!a%=D ?Q"3**-dH*=>BQV>>? ;/!Q//// ?s   Ac           
      L    | syt        t        | t        | 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

    Tr:   )r   r$   r   )r4   Ks     r1   	dup_sqf_prE   1   s*      ga!Q):A>???r8   c                     t        | |      ryt        |dz         D ]>  }t        | d|||      }t        ||      rt        | |||      }t	        |||      dk7  s> y y)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

    Tr:   r   F)r   ranger   r%   r   )r4   r=   rD   ifpgcds         r1   	dmp_sqf_prK   G   sp      !Q1Q3Z 
Aq!Q'b!aQ"a#q(
 r8   c                 ^   |j                   st        d      dt        |j                  j	                         dd|j
                        }}	 t        | d|d      \  }}t        ||d|j
                        }t        ||j
                        rnt        | |j                   |      |dz   }} _|| |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   r:   Tfront)is_Algebraicr+   r   modto_listdomr   r&   rE   r   unit)r4   rD   sgh_rs          r1   dup_sqf_normrZ   i   s    B >>;<<iAquu5qA
!Q.1!Q155)QQ+QUqA  a7Nr8   c           	   #     K   |dz   }dg|z  }|| f |j                   }t        | |      }t        t        |t	        |dz                     D cg c]  \  }}|dkD  s| }	}}|	D ]>  }|j                         }
d|
|<   |
D cg c]  }| |z  
 }}t        | |||      }|
|f @ d}	 |dz  }|g|z  }| |z  g|z  }t        | |||      }||f *c c}}w c c}w w)z9Generate a sequence of candidate shifts for dmp_sqf_norm.r:   r   )rT   r   sortedr;   rG   copyr   )r4   r=   rD   ns0addirH   var_indicess1s1ia1f1jsjajfjs                     r1   _dmp_sqf_norm_shiftsrl      s     	
AA
qB
a%K 	
A 	1A"(Qac
);"<GQQ1GKG  WWY1 "#qbf##q"a#"f 	
A
	QS1WbdVaZq"a#"f  H $s%   AC CC"!C CAC c                    |st        | |      \  }}}|g||fS |j                  st        d      t        |j                  j                         |dz   d|j                        }t        | ||      D ]K  \  }} t        | ||d      \  }}t        |||dz   |j                        }t        |||j                        sK n | 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.
    rM   r:   r   TrN   )rZ   rP   r+   r   rQ   rR   rS   rl   r   r&   rK   )r4   r=   rD   rU   rV   rY   rW   rX   s           r1   dmp_sqf_normrn      s    D q!$1asAqy>>;<<!%%--/1q5!QUU3A$Q1- 1!Q.1!QAquu-Q155! a7Nr8   c                     |j                   st        d      t        |j                  j	                         |dz   d|j
                        }t        | ||d      \  }}t        |||dz   |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.
    rM   r:   r   TrN   )rP   r+   r   rQ   rR   rS   r   r&   )r4   r=   rD   rV   rW   rX   s         r1   dmp_normrp   9  sg    P >>;<<!%%--/1q5!QUU3AaAT*DAqAq1uaee,,r8   c                     t        | ||j                        } t        | |j                  |j                        }t        ||j                  |      S )z3Compute square-free part of ``f`` in ``GF(p)[x]``. )r   rS   r)   rQ   )r4   rD   rV   s      r1   dup_gf_sqf_partrr     s=    Aq!%% AAquuaee$Aq!%%##r8   c                     t        d      )z3Compute square-free part of ``f`` in ``GF(p)[X]``. +multivariate polynomials over finite fieldsNotImplementedErrorr4   r=   rD   s      r1   dmp_gf_sqf_partrx         
K
LLr8   c                     |j                   rt        | |      S | s| S |j                  t        | |            rt	        | |      } t        | t        | d|      |      }t        | ||      }|j                  rt        ||      S t        ||      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
    r:   )is_FiniteFieldrr   is_negativer   r   r$   r   r	   is_Fieldr   r    )r4   rD   rJ   sqfs       r1   dup_sqf_partr     s    $ 	q!$$}}VAq\"AqM
!XaA&
*C
!S!
Czza  S!$Q''r8   c                    |st        | |      S |j                  rt        | ||      S t        | |      r| S |j	                  t        | ||            rt        | ||      } | }t        |dz         D ]  }t        |t        | d|||      ||      } t        | |||      }|j                  rt        |||      S t        |||      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

    r:   )r   r{   rx   r   r|   r   r   rG   r%   r   r
   r}   r   r!   )r4   r=   rD   rJ   rH   r~   s         r1   dmp_sqf_partr     s     Aq!!q!Q''!Q}}]1a+,Aq!
C1Q3Z =c;q!Q15q!<=
!S!Q
CzzQ**#CA.q11r8   c                 8   | }t        | ||j                        } t        | |j                  |j                  |      \  }}t	        |      D ]$  \  }\  } }t        | |j                  |      |f||<   & t        ||       |j                  ||j                        |fS )z<Compute square-free decomposition of ``f`` in ``GF(p)[x]``. all)r   rS   r(   rQ   	enumerater7   convert)r4   rD   r   f_origcoefffactorsrH   r0   s           r1   dup_gf_sqf_listr     s    FAq!%% A AEE155c:NE7w' 3	6Aq!!QUUA.2
3 vw'99UAEE"G++r8   c                     t        d      )z<Compute square-free decomposition of ``f`` in ``GF(p)[X]``. rt   ru   )r4   r=   rD   r   s       r1   dmp_gf_sqf_listr     ry   r8   c                 T   |j                   rt        | ||      S | }|j                  rt        | |      }t	        | |      } n9t        | |      \  }} |j                  t        | |            rt        | |      } | }t        |       dk  r|g fS g d}}t        | d|      }t        | ||      \  }}	}
	 t        |	d|      }t        |
||      }|s|j                  |	|f       n:t        |	||      \  }}	}
|st        |      dkD  r|j                  ||f       |dz  }jt        ||       ||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]_
    r   r   r:   )r{   r   r}   r   r   r    r|   r   r   r   r"   r   appendr7   )r4   rD   r   r   r   r5   rH   rW   rV   pqra   s               r1   dup_sqf_listr     s?   D 	q!--Fzzq!aO A&q==1&1AFE!}byAAFAqAAq!$GAq!
Q1Aq!MM1a&!1a(1a*Q-!#MM1a&!	Q  vv&&=r8   c                     t        | ||      \  }}|r)|d   d   dk(  rt        |d   d   ||      }|dfg|dd z   S t        |g      }|dfg|z   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)]

    r   r   r:   N)r   r   r   )r4   rD   r   r   r   rV   s         r1   dup_sqf_list_includer   A  sr    $ "!QC0NE771:a=A%71:a=%3Ax'!"+%%ugAx'!!r8   c                 h   |st        | ||      S |j                  rt        | |||      S | }|j                  rt	        | ||      }t        | ||      } n<t        | ||      \  }} |j                  t	        | ||            rt        | ||      } | }t        | |      }|dk  r|g fS t        | ||      \  }} i }|dk7  rt        | d||      }	t        | |	||      \  }
}}d}	 t        |d||      }t        ||||      }	t        |	|      r|||<   n.t        ||	||      \  }
}}|st        |
|      dkD  r|
||<   |dz  }\t        ||dz
  ||      \  }}||z  }|D ]&  \  }}|g}||v rt!        ||   |||      ||<   "|||<   ( t#        |      D cg c]	  }||   |f }}t%        |||       ||fS c c}w )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`.
    r   r   r:   )r   r{   r   r}   r   r   r!   r|   r   r   r'   r   r#   r   r   dmp_sqf_listr   r\   rB   )r4   r=   rD   r   r   r   r6   contentr5   rW   rV   r   r   rH   ra   coeff_contentresult_contentr/   s                     r1   r   r   ]  s   L Aqc**q!QC00FzzaA&Q1%'1a0q==q!Q/01a AFE
Q
C
Qwby q!Q'JGQF
axQ1a 1a+1aAq!$A1a#A!Qq	#Aq!Q/GAq!jA&*q	FA  %1!A#qc$J!M>	]E ! Qe;q	315F1IF1I '-Vn5vay!n5F5vq&)&=	 6s   F/c                     |st        | ||      S t        | |||      \  }}|r*|d   d   dk(  rt        |d   d   |||      }|dfg|dd z   S t        ||      }|dfg|z   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)]

    r   r   r:   N)r   r   r   r   )r4   r=   rD   r   r   r   rV   s          r1   dmp_sqf_list_includer     s    $ #Aqc22!!Qs3NE771:a=A%71:a=%A6Ax'!"+%%ua Ax'!!r8   c           
      l   | st        d      t        | |      } t        |       sg S t        | t	        | |j
                  |      |      }t        ||      }t        |      D ]1  \  }\  }}t        |t	        | ||       |      |      }||dz   f||<   3 t        | ||      } t        |       s|S | dfg|z   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 polynomialr:   )

ValueErrorr   r   r$   r   onedup_gff_listr   r   r	   )r4   rD   rV   HrH   rW   r0   s          r1   r   r     s     _``!QAa=	AyAEE1-q1A"1 	IAv19Q1q115Aq1u:AaD	 Aq!!}HF8a<r8   c                 4    |st        | |      S t        |       )z
    Compute greatest factorial factorization of ``f`` in ``K[X]``.

    Examples
    ========

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

    )r   r*   rw   s      r1   dmp_gff_listr     s     Aq!!)!,,r8   N)F)D__doc__sympy.polys.densearithr   r   r   r   r   r   r	   r
   r   r   sympy.polys.densebasicr   r   r   r   r   r   r   r   r   r   r   r   sympy.polys.densetoolsr   r   r   r   r   r   r   r    r!   sympy.polys.euclidtoolsr"   r#   r$   r%   r&   r'   sympy.polys.galoistoolsr(   r)   sympy.polys.polyerrorsr*   r+   r7   rB   rE   rK   rZ   rl   rn   rp   rr   rx   r   r   r   r   r   r   r   r   r   r    r8   r1   <module>r      s    >$ $ $   ) ) )
" "
 0@,DOd%PSlN-b$M
!(H"2J, M
JZ"8iX">" J-r8   