U
    ZÊ¹jœI  ã                   @   sž   d dl Z d dlmZ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 G dd	„ d	ƒZddd„Zdd„ Zdd„ Zdd„ Zddd„Zdd„ ZdS )é    N)ÚFpGroupÚ
FpSubgroupÚsimplify_presentation)Ú	FreeGroup)ÚPermutationGroup)Úigcd)Útotient)ÚSc                   @   sˆ   e Zd ZdZdd„ Zdd„ Zdd„ Zdd	„ Zd
d„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zd S )!ÚGroupHomomorphismzÖ
    A class representing group homomorphisms. Instantiate using `homomorphism()`.

    References
    ==========

    .. [1] Holt, D., Eick, B. and O'Brien, E. (2005). Handbook of computational group theory.

    c                 C   s(   || _ || _|| _d | _d | _d | _d S ©N)ÚdomainÚcodomainÚimagesÚ	_inversesÚ_kernelÚ_image)Úselfr   r   r   © r   ú`/var/www/html/bwave/python/venv/lib/python3.8/site-packages/sympy/combinatorics/homomorphisms.pyÚ__init__   s    zGroupHomomorphism.__init__c           
      C   sâ   |   ¡ }i }t| j ¡ ƒD ]$}| j| }||ks|js|||< qt| jtƒrT|j}n|j	}|D ]~}||ks^|jrrq^| j
j}t| jtƒrœ|j| ddd… }n|}|D ].}	|	|kr¾|||	  }q¤|||	d  d  }q¤|||< q^|S )zÚ
        Return a dictionary with `{gen: inverse}` where `gen` is a rewriting
        generator of `codomain` (e.g. strong generator for permutation groups)
        and `inverse` is an element of its preimage

        Néÿÿÿÿ)ÚimageÚlistr   ÚkeysÚis_identityÚ
isinstancer   r   Zstrong_gensÚ
generatorsr   ÚidentityZ_strong_gens_slp)
r   r   ZinversesÚkÚvÚgensÚgÚwÚpartsÚsr   r   r   Ú_invs   s0    
ÿ

zGroupHomomorphism._invsc           	         sþ   ddl m} ddlm} t|||fƒrÞtˆ jtƒr>ˆ j |¡}ˆ jdkrRˆ  	¡ ˆ _ˆ  
¡ }ˆ jj}tˆ jtƒr„| |¡ddd… }n|}tt|ƒƒD ]D}|| }|jr¨q”|ˆ jkrÂ|ˆ j|  }q”|ˆ j|d  d  }q”|S t|tƒrú‡ fdd„|D ƒS dS )aÏ  
        Return an element of the preimage of ``g`` or of each element
        of ``g`` if ``g`` is a list.

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

        If the codomain is an FpGroup, the inverse for equal
        elements might not always be the same unless the FpGroup's
        rewriting system is confluent. However, making a system
        confluent can be time-consuming. If it's important, try
        `self.codomain.make_confluent()` first.

        r   ©ÚPermutation)ÚFreeGroupElementNr   c                    s   g | ]}ˆ   |¡‘qS r   )Úinvert©Ú.0Úe©r   r   r   Ú
<listcomp>k   s     z,GroupHomomorphism.invert.<locals>.<listcomp>)Úsympy.combinatoricsr'   Úsympy.combinatorics.free_groupsr(   r   r   r   Úreducer   r%   r   r   r   r   Úgenerator_productÚrangeÚlenr   r   )	r   r!   r'   r(   r   r"   r    Úir$   r   r-   r   r)   ?   s,    



zGroupHomomorphism.invertc                 C   s   | j dkr|  ¡ | _ | j S )z0
        Compute the kernel of `self`.

        N)r   Ú_compute_kernelr-   r   r   r   Úkernelm   s    

zGroupHomomorphism.kernelc                 C   s¼   | j }| ¡ }|tjkr tdƒ‚g }t|tƒr:t|jƒ}nt||dd�}|  	¡  ¡ }| ¡ | |kr¸| 
¡ }||  | |ƒ¡d  }||krT| |¡ t|tƒr¨t|ƒ}qTt||dd�}qT|S )Nz9Kernel computation is not implemented for infinite groupsT)Únormalr   )r   Úorderr	   ÚInfinityÚNotImplementedErrorr   r   r   r   r   Úrandomr)   Úappend)r   ÚGZG_orderr    ÚKr5   Úrr   r   r   r   r6   v   s(    
ÿ



z!GroupHomomorphism._compute_kernelc                 C   sL   | j dkrFtt| j ¡ ƒƒ}t| jtƒr8| j |¡| _ nt	| j|ƒ| _ | j S )z/
        Compute the image of `self`.

        N)
r   r   Úsetr   Úvaluesr   r   r   Zsubgroupr   )r   rB   r   r   r   r   �   s    
zGroupHomomorphism.imagec           	         sô   |ˆ j kr2t|ttfƒr*‡ fdd„|D ƒS tdƒ‚|jr@ˆ jjS ˆ j}ˆ jj}tˆ j t	ƒr¢ˆ j j
|dd�}|D ]0}|ˆ jkrŠ|| | }qn||d  d | }qnnNd}|jD ]B\}}|dk rÊ|| d }n|| }||| |  }|t|ƒ7 }q¬|S )z*
        Apply `self` to `elem`.

        c                    s   g | ]}ˆ   |¡‘qS r   ©Ú_applyr*   r-   r   r   r.   ¡   s     z,GroupHomomorphism._apply.<locals>.<listcomp>z2The supplied element does not belong to the domainT)Úoriginalr   r   )r   r   r   ÚtupleÚ
ValueErrorr   r   r   r   r   r2   Ú
array_formÚabs)	r   Úelemr   Úvaluer    r!   r5   Ú_Úpr   r-   r   rD   š   s,    

zGroupHomomorphism._applyc                 C   s
   |   |¡S r   rC   )r   rJ   r   r   r   Ú__call__º   s    zGroupHomomorphism.__call__c                 C   s   |   ¡  ¡ dkS )z9
        Check if the homomorphism is injective

        é   )r7   r9   r-   r   r   r   Úis_injective½   s    zGroupHomomorphism.is_injectivec                 C   s:   |   ¡  ¡ }| j ¡ }|tjkr.|tjkr.dS ||kS dS )z:
        Check if the homomorphism is surjective

        N)r   r9   r   r	   r:   )r   ZimZothr   r   r   Úis_surjectiveÄ   s
    
zGroupHomomorphism.is_surjectivec                 C   s   |   ¡ o|  ¡ S )z5
        Check if `self` is an isomorphism.

        )rP   rQ   r-   r   r   r   Úis_isomorphismÐ   s    z GroupHomomorphism.is_isomorphismc                 C   s   |   ¡  ¡ dkS )zs
        Check is `self` is a trivial homomorphism, i.e. all elements
        are mapped to the identity.

        rO   )r   r9   r-   r   r   r   Ú
is_trivial×   s    zGroupHomomorphism.is_trivialc                    s>   ˆ   ¡  ˆj¡stdƒ‚‡ ‡fdd„ˆ jD ƒ}tˆ jˆj|ƒS )z°
        Return the composition of `self` and `other`, i.e.
        the homomorphism phi such that for all g in the domain
        of `other`, phi(g) = self(other(g))

        z?The image of `other` must be a subgroup of the domain of `self`c                    s   i | ]}|ˆˆ |ƒƒ“qS r   r   ©r+   r!   ©Úotherr   r   r   Ú
<dictcomp>é   s      z-GroupHomomorphism.compose.<locals>.<dictcomp>)r   Úis_subgroupr   rG   r   r
   r   )r   rV   r   r   rU   r   Úcomposeß   s    zGroupHomomorphism.composec                    sD   t |tƒr| ˆ j¡stdƒ‚|}‡ fdd„|jD ƒ}t|ˆ j|ƒS )zh
        Return the restriction of the homomorphism to the subgroup `H`
        of the domain.

        z'Given H is not a subgroup of the domainc                    s   i | ]}|ˆ |ƒ“qS r   r   rT   r-   r   r   rW   õ   s      z1GroupHomomorphism.restrict_to.<locals>.<dictcomp>)r   r   rX   r   rG   r   r
   r   )r   ÚHr   r   r   r-   r   Úrestrict_toì   s
    zGroupHomomorphism.restrict_toc                 C   sŽ   |  |  ¡ ¡stdƒ‚g }t|  ¡ jƒ}|jD ]Z}|  |¡}||krV| |¡ t|ƒ}|  ¡ jD ]&}|| |kr`| || ¡ t|ƒ}q`q.|S )z†
        Return the subgroup of the domain that is the inverse image
        of the subgroup ``H`` of the homomorphism image

        z&Given H is not a subgroup of the image)	rX   r   rG   r   r   r   r)   r=   r7   )r   rZ   r    ÚPÚhZh_ir   r   r   r   Úinvert_subgroupø   s    


z!GroupHomomorphism.invert_subgroupN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r%   r)   r7   r6   r   rD   rN   rP   rQ   rR   rS   rY   r[   r^   r   r   r   r   r
   	   s    
#.	 r
   r   Tc                    s  t | tttfƒstdƒ‚t ˆ tttfƒs0tdƒ‚| j‰t‡fdd„ˆD ƒƒsTtdƒ‚t‡ fdd„|D ƒƒsrtdƒ‚|rŽt|ƒtˆƒkrŽtdƒ‚t	ˆƒ‰t	|ƒ}| 
ˆ jgtˆƒt|ƒ  ¡ ˆ 
‡fd	d
„ˆD ƒ¡ ttˆ|ƒƒ}|rút| ˆ |ƒsútdƒ‚t| ˆ |ƒS )aŠ  
    Create (if possible) a group homomorphism from the group ``domain``
    to the group ``codomain`` defined by the images of the domain's
    generators ``gens``. ``gens`` and ``images`` can be either lists or tuples
    of equal sizes. If ``gens`` is a proper subset of the group's generators,
    the unspecified generators will be mapped to the identity. If the
    images are not specified, a trivial homomorphism will be created.

    If the given images of the generators do not define a homomorphism,
    an exception is raised.

    If ``check`` is ``False``, do not check whether the given images actually
    define a homomorphism.

    zThe domain must be a groupzThe codomain must be a groupc                 3   s   | ]}|ˆ kV  qd S r   r   rT   )r   r   r   Ú	<genexpr>#  s     zhomomorphism.<locals>.<genexpr>zCThe supplied generators must be a subset of the domain's generatorsc                 3   s   | ]}|ˆ kV  qd S r   r   rT   )r   r   r   rc   %  s     z+The images must be elements of the codomainz>The number of images must be equal to the number of generatorsc                    s   g | ]}|ˆ kr|‘qS r   r   rT   )r    r   r   r.   /  s      z homomorphism.<locals>.<listcomp>z-The given images do not define a homomorphism)r   r   r   r   Ú	TypeErrorr   ÚallrG   r4   r   Úextendr   ÚdictÚzipÚ_check_homomorphismr
   )r   r   r    r   Úcheckr   )r   r   r    r   Úhomomorphism  s&    rk   c                    sÈ   t | dƒr| n|  ¡ }|j}|j}dd„ |D ƒ}tt|| jƒƒ‰|j‰ ‡ ‡‡fdd„}|D ]h}t|tƒr®| 	||ƒˆ ¡}	|	dkr¸| 
¡ }
| 	||ƒˆ ¡}	|	dkr¸|
s¸tdƒ‚n
||ƒj}	|	sZ dS qZd	S )
a]  
    Check that a given mapping of generators to images defines a homomorphism.

    Parameters
    ==========
    domain : PermutationGroup, FpGroup, FreeGroup
    codomain : PermutationGroup, FpGroup, FreeGroup
    images : dict
        The set of keys must be equal to domain.generators.
        The values must be elements of the codomain.

    Úrelatorsc                 S   s   g | ]}|j d  ‘qS )r   )Zext_reprT   r   r   r   r.   F  s     z'_check_homomorphism.<locals>.<listcomp>c                    s0   ˆ }| j D ] \}}ˆ| }|ˆ| | 9 }q
|S r   )rH   )r@   r"   ÚsymbolÚpowerr!   ©r   r   Zsymbols_to_domain_generatorsr   r   r   J  s
    z#_check_homomorphism.<locals>._imageNzÖCan't determine if the images define a homomorphism. Try increasing the maximum number of rewriting rules (group._rewriting_system.set_max(new_value); the current value is stored in group._rewriting_system.maxeqns)FT)ÚhasattrZpresentationrl   r   rg   rh   r   r   r   ÚequalsZmake_confluentÚRuntimeErrorr   )r   r   r   ZpresZrelsr    Úsymbolsr   r@   r$   Úsuccessr   ro   r   ri   6  s&    


ri   c                    s˜   ddl m‰  ddlm} |tˆƒƒ}|j‰tˆƒ‰‡ ‡‡fdd„| jD ƒ}| jˆd� t	| ||ƒ}t| j
ƒtˆƒkr†| j
tˆƒ |_nt| jgƒ|_|S )z•
    Return the homomorphism induced by the action of the permutation
    group ``group`` on the set ``omega`` that is closed under the action.

    r   r&   ©ÚSymmetricGroupc                    s*   i | ]"‰ ˆ ˆˆ‡ ‡fd d„ˆD ƒƒ “qS )c                    s   g | ]}ˆ  |ˆ A ¡‘qS r   )Úindex)r+   Úo)r!   Úomegar   r   r.   r  s     z1orbit_homomorphism.<locals>.<dictcomp>.<listcomp>r   ©r+   ©r'   r   ry   ©r!   r   rW   r  s      z&orbit_homomorphism.<locals>.<dictcomp>)Úbase)r/   r'   Ú sympy.combinatorics.named_groupsrv   r4   r   r   r   Z_schreier_simsr
   Zbasic_stabilizersr   r   )Úgroupry   rv   r   r   rZ   r   r{   r   Úorbit_homomorphismg  s    r€   c           	         s¾   ddl m‰  ddlm} t|ƒ}d}g ‰dg| ‰t|ƒD ]*}|| |kr:ˆ |¡ |ˆ|< |d7 }q:t|ƒD ]}ˆ||  ˆ|< qn||ƒ}t|ƒ‰‡ ‡‡‡fdd„| jD ƒ}t| ||ƒ}|S )ab  
    Return the homomorphism induced by the action of the permutation
    group ``group`` on the block system ``blocks``. The latter should be
    of the same form as returned by the ``minimal_block`` method for
    permutation groups, namely a list of length ``group.degree`` where
    the i-th entry is a representative of the block i belongs to.

    r   r&   ru   NrO   c                    s(   i | ] ‰ ˆ ˆ‡‡ ‡fd d„ˆD ƒƒ“qS )c                    s   g | ]}ˆ ˆ| ˆA  ‘qS r   r   )r+   r5   )Úbr!   rM   r   r   r.   ›  s     z1block_homomorphism.<locals>.<dictcomp>.<listcomp>r   rz   ©r'   r�   r   rM   r|   r   rW   ›  s      z&block_homomorphism.<locals>.<dictcomp>)	r/   r'   r~   rv   r4   r3   r=   r   r
   )	r   Úblocksrv   ÚnÚmr5   r   r   rZ   r   r‚   r   Úblock_homomorphism{  s$    	


r†   c                 C   sÞ  t | ttfƒstdƒ‚t |ttfƒs,tdƒ‚t | tƒrŽt |tƒrŽt| ƒ} t|ƒ}| j|jkrŽ| j ¡ |j ¡ krŽ|sxdS dt| || j|jƒfS |}|  	¡ }| 	¡ }|t
jkr´tdƒ‚t |tƒrÜ|t
jkrÐtdƒ‚| ¡ \}}||ksð| j|jkrü|sødS dS |�s|}t|t|ƒƒdk�rdS t| jƒ}t |t|ƒ¡D ]–}	t|	ƒ}
|
 |jgt| jƒt|
ƒ  ¡ tt||
ƒƒ}t| ||ƒ�r8t |tƒ�r–| |
¡}
t| || j|
dd�}| ¡ �r8|�sÀ dS d|f  S �q8|�sÚdS dS )aE  
    Compute an isomorphism between 2 given groups.

    Parameters
    ==========

    G : A finite ``FpGroup`` or a ``PermutationGroup``.
        First group.

    H : A finite ``FpGroup`` or a ``PermutationGroup``
        Second group.

    isomorphism : bool
        This is used to avoid the computation of homomorphism
        when the user only wants to check if there exists
        an isomorphism between the groups.

    Returns
    =======

    If isomorphism = False -- Returns a boolean.
    If isomorphism = True  -- Returns a boolean and an isomorphism between `G` and `H`.

    Examples
    ========

    >>> from sympy.combinatorics import free_group, Permutation
    >>> from sympy.combinatorics.perm_groups import PermutationGroup
    >>> from sympy.combinatorics.fp_groups import FpGroup
    >>> from sympy.combinatorics.homomorphisms import group_isomorphism
    >>> from sympy.combinatorics.named_groups import DihedralGroup, AlternatingGroup

    >>> D = DihedralGroup(8)
    >>> p = Permutation(0, 1, 2, 3, 4, 5, 6, 7)
    >>> P = PermutationGroup(p)
    >>> group_isomorphism(D, P)
    (False, None)

    >>> F, a, b = free_group("a, b")
    >>> G = FpGroup(F, [a**3, b**3, (a*b)**2])
    >>> H = AlternatingGroup(4)
    >>> (check, T) = group_isomorphism(G, H)
    >>> check
    True
    >>> T(b*a*b**-1*a**-1*b**-1)
    (0 2 3)

    Notes
    =====

    Uses the approach suggested by Robert Tarjan to compute the isomorphism between two groups.
    First, the generators of ``G`` are mapped to the elements of ``H`` and
    we check if the mapping induces an isomorphism.

    z2The group must be a PermutationGroup or an FpGroupTz<Isomorphism methods are not implemented for infinite groups.F)FNrO   )rj   )r   r   r   rd   r   r   rl   Úsortrk   r9   r	   r:   r;   Z_to_perm_groupZ
is_abelianr   r   r   Ú	itertoolsÚpermutationsr4   rf   r   rg   rh   ri   r)   rR   )r>   rZ   ÚisomorphismZ_HZg_orderZh_orderZh_isomorphismr„   r    Zsubsetr   Z_imagesÚTr   r   r   Úgroup_isomorphismŸ  sX    8 



 

rŒ   c                 C   s   t | |dd�S )a  
    Check if the groups are isomorphic to each other

    Parameters
    ==========

    G : A finite ``FpGroup`` or a ``PermutationGroup``
        First group.

    H : A finite ``FpGroup`` or a ``PermutationGroup``
        Second group.

    Returns
    =======

    boolean
    F)rŠ   )rŒ   )r>   rZ   r   r   r   Úis_isomorphic  s    r�   )r   T)T)rˆ   Zsympy.combinatorics.fp_groupsr   r   r   r0   r   Zsympy.combinatorics.perm_groupsr   Zsympy.core.intfuncr   Z%sympy.functions.combinatorial.numbersr   Zsympy.core.singletonr	   r
   rk   ri   r€   r†   rŒ   r�   r   r   r   r   Ú<module>   s     
)1$
t