U
    -eI                     @   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   b/var/www/html/Darija-Ai-Train/env/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rt jtr> j|} jdkrR 	  _ 
 } jj}t jtr||ddd }n|}tt|D ]D}|| }|jrq| 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rt|}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|rt|tkrtdt	t	|}|
 jgtt|   
fd	d
D  tt|}|rt|  |st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|
st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>._imageNzCan'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rt |trt| } t|}| j|jkr| j |j kr|sxdS dt| || j|jfS |}| 	 }|	 }|t
jkrtdt |tr|t
jkrtd| \}}||ks| j|jkr|sd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|sd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.numbersr   Zsympy.ntheory.factor_r   Zsympy.core.singletonr	   r
   rk   ri   r   r   r   r   r   r   r   r   <module>   s     
)1$
t