o
    ohP                     @   sD  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 )+z
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   y/var/www/html/construction_image-detection-poc/venv/lib/python3.10/site-packages/sympy/polys/numberfields/galoisgroups.pyr   #   s    r   
      Tc                    sN  t d}|  }|du rt }|| j |ri  d}d} fdd}	t|D ]}}
|rh|	|}t|}tdd |D }|| |kr[|dkrO|d	7 }|d	 }n|d	8 }|	|}t|}td	gd
d |D  }nt	|
d d	 |}t
d|d	 }t|| |t}t|| j}t| || |}|j|vrt|j tr||f  S q't)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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&   	resultantr   to_listr   )T	max_coeff	max_trieshistoryfixed_orderr    ndeg_coeff_sumcurrent_degreer)   ir&   coeffsmaCdAUr   r'   r   tschirnhausen_transformation'   s@   1
rL   c                 C   s$   t | tr	|  nt| t}t|S )z?Convenience to check if a Poly or dup has square discriminant. )
isinstancer   discriminantr
   r   r   )r<   rI   r   r   r   has_square_disc   s   rO   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.galoisrP   rO   A3S3)r<   r>   	randomizerP   r   r   r   _galois_group_degree_3   s   
rU   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rt| ||| d\}} |j	| d	d
\}}}t
|tsqqt| }|du r|r|jd	f  S |jdf  S |r|jd	f  S ||  |	jt| |d	d} fdd|
D }t|||}|	| \}}}t|t}|dkrqqt|r|jdf  S |jdf  S t)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)find_integer_rootNFsimultaneousc                       g | ]} |   qS r   r   r,   tausigmar   r   r/          z6_galois_group_degree_4_root_approx.<locals>.<listcomp>) sympy.combinatorics.permutationsrW   rQ   rY   r   r   r1   r4   rL   eval_for_polyr   r   rO   A4S4Vsubszipr
   r   C4D4r   )r<   r>   rT   rW   rY   r    F1s1R1F2_pres2_prer?   rD   _R_dupi0sq_discF2s2R2rI   r   ra   r   "_galois_group_degree_4_root_approx   sT   
 P


ry   c           
      C   s   ddl m} t }t|D ]}t| d}t|tr nt| ||| d\}} qtt	|t}t
tdd |d D g }	|	dgkrOt| rJ|jdfS |jd	fS |	g d
krZ|jd	fS |	g dkre|jdfS |	ddgksmJ |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   rX   rZ   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#   r#      )r"   r"   r"   r"   r   )rQ   rY   r1   r4   r   r   r   rL   r   r   sortedsumrO   rf   rg   rk   rh   rl   )
r<   r>   rT   rY   r?   rD   rs   rr   flLr   r   r   _galois_group_degree_4_lookup   s6   








r   c                    s   ddl m} ddlm} td}t }|d \}}}	|j| }t|||	}
t }d}t	|D ]}|dkr?t
| ||| d\}} t| d}t|tsJq.|snt| }t|tre|r^|jd	f  S |jdf  S |sn|jdf  S d	}|
| }| D ]\}}t||ts nqy|}|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 t)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   S5TransitiveSubgroupsrV   zX0,X1,X2,X3,X4)r0   r#   FrZ   r#   Tr"   r!   r   r\   c                    r^   r   r   r_   ra   r   r   r/   k  rc   z1_galois_group_degree_5_hybrid.<locals>.<listcomp>)rQ   r   rd   rW   r   r   as_exprr   r1   r4   rL   r   r   r   rO   r   A5S5M20 round_roots_to_integers_for_polyitemsr	   ri   rj   re   r
   r   C5D5r   )r<   r>   rT   r   rW   X5resF51rr   s51R51r?   reached_second_stagerD   R51_dupru   rounded_rootspermutation_indexcandidate_rootr    rp   rq   rt   rv   rw   rx   rs   rI   r   ra   r   _galois_group_degree_5_hybrid)  sd   





d

r   c                 C   s   ddl m} | }t }t|D ]}t| d}t|tr nt| ||| d\}} qtt	| }	t
|tr@|	r;|jdfS |jdfS |	sG|jdfS t|t|d d }
t|
dkr_|jdfS |jdf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   r   r#   rZ   TF)domainr0   )rQ   r   r1   r4   r   r   r   rL   r   rO   r   r   r   r   r   alg_field_from_polyfactor_listr{   r   r   )r<   r>   rT   r   _Tr?   rD   rs   rr   ru   r   r   r   r   (_galois_group_degree_5_lookup_ext_factorz  s.   





r   c                 C   s`  ddl m} t }t|D ]}t| d}t|tr nt| ||| d\}} qtt	|t}t
t}	|d D ]\}
}|	t|
d  |
 q6ttdd |	 D g }t| }|g dkrr|	d d }t|rm|jd	fS |jd	fS |ddgkr|	d \}}t|pt|}|r|jd	fS |jd	fS |d
dgkr|r|jdfS |	d d }t|r|jd	fS |jd	fS |g d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 |g dkr|jd	fS |dgksJ t }t|D ]}t| d
}t|tr nt| ||| d\}} qtt| }t|tr#|r|jdfS |j d	fS |r+|j!dfS |j"d	f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#   rZ   c                 S   s   g | ]\}}|gt | qS r   rz   )r,   rI   ffr   r   r   r/     s    z1_galois_group_degree_6_lookup.<locals>.<listcomp>)r#   r"   r!   r!   Fr"   r   Tr   r0   )r#   r#   r#   r!   r~   )#rQ   r   r1   r4   r   r   r   rL   r   r   r   listr{   appendr   r   r   rO   C6D6G18G36mS4pA4xC2S4xC2rf   S4mPSL2F5PGL2F5rS   r   A6S6G36pG72)r<   r>   rT   r   r?   rD   rs   rr   r   factors_by_degr|   r   T_has_sq_discf1f2
any_squarer   r   r   _galois_group_degree_6_lookup  s   








r   by_namer>   rT   c          	   
   O   sd   |pg }|pi }zt | g|R i |\}}W n ty) } ztdd|d}~ww |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>   rT   gensargsFoptexcr   r   r   r     s   br   )r   r   NT)r   F).__doc__collectionsr   r8   sympy.core.symbolr   r   sympy.ntheory.primetestr   sympy.polys.domainsr   sympy.polys.densebasicr   sympy.polys.densetoolsr	   sympy.polys.euclidtoolsr
   sympy.polys.factortoolsr   r   *sympy.polys.numberfields.galois_resolventsr   r   r   r   "sympy.polys.numberfields.utilitiesr   sympy.polys.polytoolsr   r   r   r   sympy.polys.sqfreetoolsr   sympy.utilitiesr   r   rL   rO   rU   ry   r   r   r   r   r   r   r   r   r   <module>   s8    
k


W
+
Q
-]