o
    FZhI                     @   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   P/var/www/auris/lib/python3.10/site-packages/sympy/combinatorics/homomorphisms.py__init__   s   
zGroupHomomorphism.__init__c           
      C   s   |   }i }t| j D ]}| j| }||v s|js|||< qt| jtr*|j}n|j	}|D ]?}||v s8|jr9q/| j
j}t| jtrN|j| ddd }n|}|D ]}	|	|v r_|||	  }qR|||	d  d  }qR|||< 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   s2   

zGroupHomomorphism._invsc           	         s   ddl m} ddlm} t|||frot jtr j|} jdu r) 	  _ 
 } jj}t jtrB||ddd }n|}tt|D ]"}|| }|jrTqJ| jv ra| j|  }qJ| j|d  d  }qJ|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                       g | ]}  |qS r   )invert.0er   r   r   
<listcomp>k       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u 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u rtdg }t|trt|j}nt||dd}| 	  }| | |krc|
 }|| | |d  }||vr[|| t|trTt|}nt||dd}| | |ks2|S )Nz9Kernel computation is not implemented for infinite groupsT)normalr   )r   orderr	   InfinityNotImplementedErrorr   r   r   r   r   randomr*   append)r   GZG_orderr    Kr7   rr   r   r   r   r8   v   s*   




	z!GroupHomomorphism._compute_kernelc                 C   sP   | j du r%tt| j }t| jtr| j|| _ | j S t	| j|| _ | j S )z/
        Compute the image of `self`.

        N)
r   r   setr   valuesr   r   r   Zsubgroupr   )r   rD   r   r   r   r      s   
zGroupHomomorphism.imagec           	         s   | j vrt|ttfr fdd|D S td|jr  jjS  j} jj}t j t	rR j j
|dd}|D ]}| jv rE|| | }q7||d  d | }q7|S d}|jD ]!\}}|dk rf|| d }n|| }||| |  }|t|7 }qW|S )z*
        Apply `self` to `elem`.

        c                    r)   r   _applyr+   r.   r   r   r/      r0   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   r4   
array_formabs)	r   elemr   valuer    r!   r7   _pr   r.   r   rF      s.   


zGroupHomomorphism._applyc                 C   s
   |  |S r   rE   )r   rL   r   r   r   __call__   s   
zGroupHomomorphism.__call__c                 C      |    dkS )z9
        Check if the homomorphism is injective

           )r9   r;   r.   r   r   r   is_injective      zGroupHomomorphism.is_injectivec                 C   s6   |    }| j }|tju r|tju rdS ||kS )z:
        Check if the homomorphism is surjective

        N)r   r;   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.

        )rS   rU   r.   r   r   r   is_isomorphism   rT   z GroupHomomorphism.is_isomorphismc                 C   rQ   )zs
        Check is `self` is a trivial homomorphism, i.e. all elements
        are mapped to the identity.

        rR   )r   r;   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>       z-GroupHomomorphism.compose.<locals>.<dictcomp>)r   is_subgroupr   rI   r   r
   r   )r   rZ   r   r   rY   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   rX   r.   r   r   r[      r0   z1GroupHomomorphism.restrict_to.<locals>.<dictcomp>)r   r   r]   r   rI   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 ]-}| |}||vr+|| t|}|  jD ]}|| |vrC|||  t|}q0q|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)	r]   r   rI   r   r   r   r*   r?   r9   )r   r_   r    PhZh_ir   r   r   r   invert_subgroup   s    


z!GroupHomomorphism.invert_subgroupN)__name__
__module____qualname____doc__r   r%   r*   r9   r8   r   rF   rP   rS   rU   rV   rW   r^   r`   rc   r   r   r   r   r
   	   s"    
#.	 r
   r   Tc                    s  t | tttfstdt  tttfstd| jtfddD s*tdt fdd|D s9td|rGt|tkrGt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       | ]}| v V  qd S r   r   rX   )r   r   r   	<genexpr>#      zhomomorphism.<locals>.<genexpr>zCThe supplied generators must be a subset of the domain's generatorsc                 3   rh   r   r   rX   )r   r   r   ri   %  rj   z+The images must be elements of the codomainz>The number of images must be equal to the number of generatorsc                    s   g | ]}| vr|qS r   r   rX   )r    r   r   r/   /  s    z homomorphism.<locals>.<listcomp>z-The given images do not define a homomorphism)r   r   r   r   	TypeErrorr   allrI   r6   r   extendr   dictzip_check_homomorphismr
   )r   r   r    r   checkr   )r   r   r    r   homomorphism  s&   rr   c                    s   t | dr| n|  }|j}|j}dd |D }tt|| j|j  fdd}|D ]4}t|trW|	|| }	|	du rV|
 }
|	|| }	|	du rV|
sVtdn||j}	|	sa dS q-d	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_reprX   r   r   r   r/   F  r0   z'_check_homomorphism.<locals>.<listcomp>c                    s0    }| j D ]\}}| }|| | 9 }q|S r   )rJ   )rB   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presentationrs   r   rn   ro   r   r   r   equalsZmake_confluentRuntimeErrorr   )r   r   r   ZpresZrelsr    symbolsr   rB   r$   successr   rv   r   rp   6  s*   

rp   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rD| j
t |_|S 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  r\   z1orbit_homomorphism.<locals>.<dictcomp>.<listcomp>r   r,   r'   r   r   r!   r   r[   r  s   * z&orbit_homomorphism.<locals>.<dictcomp>)base)r1   r'    sympy.combinatorics.named_groupsr}   r6   r   r   r   Z_schreier_simsr
   Zbasic_stabilizersr   r   )groupr   r}   r   r   r_   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r2| ||< |d7 }qt|D ]
}||  |< q7||}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&   r|   NrR   c                    s(   i | ]   fd dD qS )c                    s   g | ]
} | A  qS r   r   )r,   r7   )br!   rO   r   r   r/     s    z1block_homomorphism.<locals>.<dictcomp>.<listcomp>r   r   r'   r   r   rO   r   r   r[     s   ( z&block_homomorphism.<locals>.<dictcomp>)	r1   r'   r   r}   r6   r5   r?   r   r
   )	r   blocksr}   nmr7   r   r   r_   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rGt |trGt| } t|}| j|jkrG| j |j krG|s<dS dt| || j|jfS |}| 	 }|	 }|t
ju rZtdt |trn|t
ju rhtd| \}}||ksx| j|jkr~|s|dS dS |s|}t|t|dkrdS t| j}t|t|D ]F}	t|	}
|
|jgt| jt|
   tt||
}t| ||rt |tr||
}
t| || j|
dd}| r|s dS d|f  S q|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)FNrR   )rq   )r   r   r   rk   r   r   rs   sortrr   r;   r	   r<   r=   Z_to_perm_groupZ
is_abelianr   r   r   	itertoolspermutationsr6   rm   r   rn   ro   rp   r*   rV   )r@   r_   isomorphismZ_HZg_orderZh_orderZh_isomorphismr   r    Zsubsetr   Z_imagesTr   r   r   group_isomorphism  sZ   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@   r_   r   r   r   is_isomorphic  s   r   )r   T)T)r   Zsympy.combinatorics.fp_groupsr   r   r   r2   r   Zsympy.combinatorics.perm_groupsr   Zsympy.core.intfuncr   Z%sympy.functions.combinatorial.numbersr   Zsympy.core.singletonr	   r
   rr   rp   r   r   r   r   r   r   r   r   <module>   s       
)1
$t