U
    	-eP                     @   s@  d Z ddlmZ ddlZddlmZmZ 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 dd
lmZmZ ddlmZmZmZmZ ddlmZ ddlmZmZmZmZ ddl m!Z! ddl"m#Z# G dd deZ$d)ddZ%dd Z&d*ddZ'd+ddZ(d,ddZ)d-d d!Z*d.d"d#Z+d/d$d%Z,e#dddd&d'd(Z-dS )0z
Compute Galois groups of polynomials.

We use algorithms from [1], with some modifications to use lookup tables for
resolvents.

References
==========

.. [1] Cohen, H. *A Course in Computational Algebraic Number Theory*.

    )defaultdictN)Dummysymbols)	is_squareZZ)
dup_random)dup_eval)dup_discriminant)dup_factor_listdup_irreducible_p)GaloisGroupExceptionget_resolvent_by_lookupdefine_resolvents	Resolvent)coeff_search)Polypoly_from_exprPolificationFailedComputationFailed)	dup_sqf_p)publicc                   @   s   e Zd ZdS )MaxTriesExceptionN)__name__
__module____qualname__ r   r   f/var/www/html/Darija-Ai-Train/env/lib/python3.8/site-packages/sympy/polys/numberfields/galoisgroups.pyr   #   s   r   
      Tc                    sP  t d}|  }|dkrt }|| j |r:i  d}d} fdd}	t|D ]}
|r|	|}t|}tdd |D }|| |kr|dkr|d	7 }|d	 }n|d	8 }|	|}t|}td	gd
d |D  }n2t	|
d d	 |}t
d|d	 }t|| |t}t|| j}t| || |}|j|krNt|jjtrN||f  S qNtdS )a  
    Given a univariate, monic, irreducible polynomial over the integers, find
    another such polynomial defining the same number field.

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

    See Alg 6.3.4 of [1].

    Parameters
    ==========

    T : Poly
        The given polynomial
    max_coeff : int
        When choosing a transformation as part of the process,
        keep the coeffs between plus and minus this.
    max_tries : int
        Consider at most this many transformations.
    history : set, None, optional (default=None)
        Pass a set of ``Poly.rep``'s in order to prevent any of these
        polynomials from being returned as the polynomial ``U`` i.e. the
        transformation of the given polynomial *T*. The given poly *T* will
        automatically be added to this set, before we try to find a new one.
    fixed_order : bool, default True
        If ``True``, work through candidate transformations A(x) in a fixed
        order, from small coeffs to large, resulting in deterministic behavior.
        If ``False``, the A(x) are chosen randomly, while still working our way
        up from small coefficients to larger ones.

    Returns
    =======

    Pair ``(A, U)``

        ``A`` and ``U`` are ``Poly``, ``A`` is the
        transformation, and ``U`` is the transformed polynomial that defines
        the same number field as *T*. The polynomial ``A`` maps the roots of
        *T* to the roots of ``U``.

    Raises
    ======

    MaxTriesException
        if could not find a polynomial before exceeding *max_tries*.

    XN      c                    s     | t| d}| | < |S )N   )getr   )degreegenZcoeff_generatorsr   r   get_coeff_generatorc   s    z9tschirnhausen_transformation.<locals>.get_coeff_generatorc                 s   s   | ]}t |V  qd S )N)abs.0cr   r   r   	<genexpr>x   s     z/tschirnhausen_transformation.<locals>.<genexpr>r#   c                 S   s   g | ]}t |qS r   r   r*   r   r   r   
<listcomp>   s     z0tschirnhausen_transformation.<locals>.<listcomp>   )r   r%   setaddreprangenextmaxr   minrandomrandintr   r   r&   Z	resultantr   r   )TZ	max_coeff	max_trieshistoryfixed_orderr    nZdeg_coeff_sumZcurrent_degreer(   ir&   ZcoeffsmaCdAUr   r'   r   tschirnhausen_transformation'   s>    1
rE   c                 C   s$   t | tr|  nt| t}t|S )z?Convenience to check if a Poly or dup has square discriminant. )
isinstancer   Zdiscriminantr
   r   r   )r9   rB   r   r   r   has_square_disc   s    rG   Fc                 C   s(   ddl m} t| r|jdfS |jdfS )z~
    Compute the Galois group of a polynomial of degree 3.

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

    Uses Prop 6.3.5 of [1].

    r   )S3TransitiveSubgroupsTF)sympy.combinatorics.galoisrH   rG   ZA3S3)r9   r:   	randomizerH   r   r   r   _galois_group_degree_3   s    
rL   c                    s  ddl m} ddlm} td}|d |d  |d |d   }|d|ddd|dddg}t|||}|d |d d  |d |d d   |d |d d   |d |d d   }	|d|dddg}
t }t|D ]}|dkrt| ||| d\}} |j	| d	d
\}}}t
|ts*qt| }|dkrZ|rL|jd	fn|jdf  S |rn|jd	f  S ||  |	jt| |d	d} fdd|
D }t|||}|	| \}}}t|t}|dkrqt|r|jdf  S |jdf  S qtdS )z
    Compute the Galois group of a polynomial of degree 4.

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

    Follows Alg 6.3.7 of [1], using a pure root approximation approach.

    r   PermutationS4TransitiveSubgroupszX0 X1 X2 X3r"   r#   r!   r:   r;   r<   T)Zfind_integer_rootNFZsimultaneousc                    s   g | ]} |   qS r   r   r+   tausigmar   r   r.      s     z6_galois_group_degree_4_root_approx.<locals>.<listcomp>) sympy.combinatorics.permutationsrN   rI   rP   r   r   r0   r3   rE   eval_for_polyr   r   rG   A4S4Vsubszipr
   r   C4D4r   )r9   r:   rK   rN   rP   r    ZF1s1ZR1F2_pres2_prer;   r>   _R_dupi0sq_discF2s2R2rB   r   rU   r   "_galois_group_degree_4_root_approx   sT    
 P





rj   c           
      C   s   ddl m} t }t|D ]2}t| d}t|tr6 qRt| ||| d\}} qtt	|t}t
tdd |d D g }	|	dgkrt| r|jdfS |jd	fS |	ddd
gkr|jd	fS |	dddgkr|jdfS |	dd
gkst|jd	fS )z
    Compute the Galois group of a polynomial of degree 4.

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

    Based on Alg 6.3.6 of [1], but uses resolvent coeff lookup.

    r   rO   rQ   c                 S   s"   g | ]\}}t |d  g| qS )r#   len)r+   rer   r   r   r.     s    z1_galois_group_degree_4_lookup.<locals>.<listcomp>r#      TF   r"   )rI   rP   r0   r3   r   r   r   rE   r   r   sortedsumrG   rY   rZ   r^   r[   AssertionErrorr_   )
r9   r:   rK   rP   r;   r>   rd   rc   flLr   r   r   _galois_group_degree_4_lookup   s6    







rv   c                    s(  ddl m} ddlm} td}t }|d \}}}	|j| }t|||	}
t }d}t	|D ]}|dkrt
| ||| d\}} t| d}t|tsq\|st| }t|tr|r|jd	fn|jdf  S |s|jdf  S d	}|
| }| D ]\}}t||ts qq|}|d |d d
  |d |d
 d
   |d
 |d d
   |d |d d
   |d |d d
   }|d|dddd
dg}|}|	|  |jt| |d	d} fdd|D }t|||}|| \}}}t|t}|dkrq\t|r|jd	f  S |jd	f  S q\tdS )z
    Compute the Galois group of a polynomial of degree 5.

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

    Based on Alg 6.3.9 of [1], but uses a hybrid approach, combining resolvent
    coeff lookup, with root approximation.

    r   S5TransitiveSubgroupsrM   zX0,X1,X2,X3,X4)r/   r#   FrQ   r#   Tr"   r!   rp   rR   c                    s   g | ]} |   qS r   r   rS   rU   r   r   r.   k  s     z1_galois_group_degree_5_hybrid.<locals>.<listcomp>N)rI   rx   rW   rN   r   r   Zas_exprr   r0   r3   rE   r   r   r   rG   r   A5S5M20Z round_roots_to_integers_for_polyitemsr	   r\   r]   rX   r
   r   C5D5r   )r9   r:   rK   rx   rN   ZX5resZF51rc   Zs51ZR51r;   Zreached_second_stager>   ZR51_duprf   Zrounded_rootsZpermutation_indexZcandidate_rootr    ra   rb   re   rg   rh   ri   rd   rB   r   rU   r   _galois_group_degree_5_hybrid)  sb    





d


r   c                 C   s   ddl m} | }t }t|D ]2}t| d}t|tr: qVt| ||| d\}} qtt	| }	t
|tr|	rv|jdfS |jdfS |	s|jdfS t|t|d d }
t|
dkr|jdfS |jdfS d	S )
z
    Compute the Galois group of a polynomial of degree 5.

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

    Based on Alg 6.3.9 of [1], but uses resolvent coeff lookup, plus
    factorization over an algebraic extension.

    r   rw   r#   rQ   TF)domainr/   N)rI   rx   r0   r3   r   r   r   rE   r   rG   r   ry   rz   r{   r   Zalg_field_from_polyZfactor_listrl   r}   r~   )r9   r:   rK   rx   _Tr;   r>   rd   rc   rf   rt   r   r   r   (_galois_group_degree_5_lookup_ext_factorz  s.    




r   c                 C   s  ddl m} t }t|D ]2}t| d}t|tr6 qRt| ||| d\}} qtt	|t}t
t}	|d D ]\}
}|	t|
d  |
 qlttdd |	 D g }t| }|dddgkr|	d d }t|r|jd	fS |jd	fS |ddgkr,|	d \}}t|pt|}|r"|jd	fS |jd	fS |dd
gkrv|rJ|jdfS |	d
 d }t|rj|jd	fS |jd	fS nn|ddd
gkr|r|jdfS |jd	fS |ddgkr|r|jdfS |jd	fS |ddddgkr|jd	fS |dgkstt }t|D ]8}t| d}t|tr" q@t| ||| d\}} qtt| }t|trn|rd|j dfS |j!d	fS |r~|j"dfS |j#d	fS dS )z
    Compute the Galois group of a polynomial of degree 6.

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

    Based on Alg 6.3.10 of [1], but uses resolvent coeff lookup.

    r   )S6TransitiveSubgroupsr#   rQ   c                 S   s   g | ]\}}|gt | qS r   rk   )r+   rB   ffr   r   r   r.     s    z1_galois_group_degree_6_lookup.<locals>.<listcomp>r"   r!   Frp   Tr/   ro   N)$rI   r   r0   r3   r   r   r   rE   r   r   r   listrl   appendrq   rr   r|   rG   ZC6ZD6ZG18ZG36mZS4pZA4xC2ZS4xC2rY   ZS4mZPSL2F5ZPGL2F5rJ   rs   r   ZA6ZS6ZG36pZG72)r9   r:   rK   r   r;   r>   rd   rc   rt   Zfactors_by_degrm   ru   ZT_has_sq_discf1f2Z
any_squarer   r   r   _galois_group_degree_6_lookup  s    







r   by_namer:   rK   c          	   
   O   sh   |pg }|pi }zt | f||\}}W n. tk
rV } ztdd|W 5 d}~X Y nX |j|||dS )a  
    Compute the Galois group for polynomials *f* up to degree 6.

    Examples
    ========

    >>> from sympy import galois_group
    >>> from sympy.abc import x
    >>> f = x**4 + 1
    >>> G, alt = galois_group(f)
    >>> print(G)
    PermutationGroup([
    (0 1)(2 3),
    (0 2)(1 3)])

    The group is returned along with a boolean, indicating whether it is
    contained in the alternating group $A_n$, where $n$ is the degree of *T*.
    Along with other group properties, this can help determine which group it
    is:

    >>> alt
    True
    >>> G.order()
    4

    Alternatively, the group can be returned by name:

    >>> G_name, _ = galois_group(f, by_name=True)
    >>> print(G_name)
    S4TransitiveSubgroups.V

    The group itself can then be obtained by calling the name's
    ``get_perm_group()`` method:

    >>> G_name.get_perm_group()
    PermutationGroup([
    (0 1)(2 3),
    (0 2)(1 3)])

    Group names are values of the enum classes
    :py:class:`sympy.combinatorics.galois.S1TransitiveSubgroups`,
    :py:class:`sympy.combinatorics.galois.S2TransitiveSubgroups`,
    etc.

    Parameters
    ==========

    f : Expr
        Irreducible polynomial over :ref:`ZZ` or :ref:`QQ`, whose Galois group
        is to be determined.
    gens : optional list of symbols
        For converting *f* to Poly, and will be passed on to the
        :py:func:`~.poly_from_expr` function.
    by_name : bool, default False
        If ``True``, the Galois group will be returned by name.
        Otherwise it will be returned as a :py:class:`~.PermutationGroup`.
    max_tries : int, default 30
        Make at most this many attempts in those steps that involve
        generating Tschirnhausen transformations.
    randomize : bool, default False
        If ``True``, then use random coefficients when generating Tschirnhausen
        transformations. Otherwise try transformations in a fixed order. Both
        approaches start with small coefficients and degrees and work upward.
    args : optional
        For converting *f* to Poly, and will be passed on to the
        :py:func:`~.poly_from_expr` function.

    Returns
    =======

    Pair ``(G, alt)``
        The first element ``G`` indicates the Galois group. It is an instance
        of one of the :py:class:`sympy.combinatorics.galois.S1TransitiveSubgroups`
        :py:class:`sympy.combinatorics.galois.S2TransitiveSubgroups`, etc. enum
        classes if *by_name* was ``True``, and a :py:class:`~.PermutationGroup`
        if ``False``.

        The second element is a boolean, saying whether the group is contained
        in the alternating group $A_n$ ($n$ the degree of *T*).

    Raises
    ======

    ValueError
        if *f* is of an unsupported degree.

    MaxTriesException
        if could not complete before exceeding *max_tries* in those steps
        that involve generating Tschirnhausen transformations.

    See Also
    ========

    .Poly.galois_group

    galois_groupr#   Nr   )r   r   r   r   )	fr   r:   rK   ZgensargsFoptexcr   r   r   r     s    br   )r   r   NT)r   F)r   F)r   F)r   F)r   F)r   F).__doc__collectionsr   r7   Zsympy.core.symbolr   r   Zsympy.ntheory.primetestr   Zsympy.polys.domainsr   Zsympy.polys.densebasicr   Zsympy.polys.densetoolsr	   Zsympy.polys.euclidtoolsr
   Zsympy.polys.factortoolsr   r   Z*sympy.polys.numberfields.galois_resolventsr   r   r   r   Z"sympy.polys.numberfields.utilitiesr   Zsympy.polys.polytoolsr   r   r   r   Zsympy.polys.sqfreetoolsr   Zsympy.utilitiesr   r   rE   rG   rL   rj   rv   r   r   r   r   r   r   r   r   <module>   s6     
k

W
+
Q
-
]