o
    ohI                     @   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   u/var/www/html/construction_image-detection-poc/venv/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   strong_gens
generatorsr   identity_strong_gens_slp)
r   r   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   r1   r   r-   ?   s.   



zGroupHomomorphism.invertc                 C   s   | j du r
|  | _ | j S )z0
        Compute the kernel of `self`.

        N)r   _compute_kernelr1   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   GG_orderr#   Kr:   rr!   r   r   r   r;   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   subgroupr   )r   rH   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.   r1   r   r   r2      r3   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   r7   
array_formabs)	r   elemr   valuer#   r$   r:   _pr   r1   r   rK      s.   


zGroupHomomorphism._applyc                 C   s
   |  |S r   rJ   )r   rQ   r   r   r   __call__   s   
zGroupHomomorphism.__call__c                 C      |    dkS )z9
        Check if the homomorphism is injective

           )r<   r>   r1   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   imothr   r   r   is_surjective   s
   
zGroupHomomorphism.is_surjectivec                 C   s   |   o|  S )z5
        Check if `self` is an isomorphism.

        )rX   r\   r1   r   r   r   is_isomorphism   rY   z GroupHomomorphism.is_isomorphismc                 C   rV   )zs
        Check is `self` is a trivial homomorphism, i.e. all elements
        are mapped to the identity.

        rW   )r   r>   r1   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   rN   r   r
   r   )r   ra   r   r   r`   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   r_   r1   r   r   rb      r3   z1GroupHomomorphism.restrict_to.<locals>.<dictcomp>)r   r   rd   r   rN   r   r
   r   )r   Hr   r   r   r1   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)	rd   r   rN   r   r   r   r-   rB   r<   )r   rf   r#   Phh_ir!   r   r   r   invert_subgroup   s    


z!GroupHomomorphism.invert_subgroupN)__name__
__module____qualname____doc__r   r(   r-   r<   r;   r   rK   rU   rX   r\   r]   r^   re   rg   rk   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   r_   )r   r   r   	<genexpr>#      zhomomorphism.<locals>.<genexpr>zCThe supplied generators must be a subset of the domain's generatorsc                 3   rp   r   r   r_   )r   r   r   rq   %  rr   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   r_   )r#   r   r   r2   /  s    z homomorphism.<locals>.<listcomp>z-The given images do not define a homomorphism)r   r   r   r   	TypeErrorr   allrN   r9   r   extendr   dictzip_check_homomorphismr
   )r   r   r#   r   checkr   )r   r   r#   r   homomorphism  s&   rz   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   )ext_repr_   r   r   r   r2   F  r3   z'_check_homomorphism.<locals>.<listcomp>c                    s0    }| j D ]\}}| }|| | 9 }q|S r   )rO   )rF   r%   symbolpowerr$   r   r   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)hasattrpresentationr{   r   rv   rw   r   r   r   equalsmake_confluentRuntimeErrorr   )r   r   r   presrelsr#   symbolsr   rF   r'   successr   r   r   rx   6  s*   

rx   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   r2   r  rc   z1orbit_homomorphism.<locals>.<dictcomp>.<listcomp>r   r/   r*   r   r   r$   r   rb   r  s   * z&orbit_homomorphism.<locals>.<dictcomp>)base)r4   r*    sympy.combinatorics.named_groupsr   r9   r   r   r   _schreier_simsr
   basic_stabilizersr   r   )groupr   r   r   r   rf   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   NrW   c                    s(   i | ]   fd dD qS )c                    s   g | ]
} | A  qS r   r   )r/   r:   )br$   rT   r   r   r2     s    z1block_homomorphism.<locals>.<dictcomp>.<listcomp>r   r   r*   r   r   rT   r   r   rb     s   ( z&block_homomorphism.<locals>.<dictcomp>)	r4   r*   r   r   r9   r8   rB   r   r
   )	r   blocksr   nmr:   r   r   rf   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)FNrW   )ry   )r   r   r   rs   r   r   r{   sortrz   r>   r	   r?   r@   _to_perm_group
is_abelianr   r   r   	itertoolspermutationsr9   ru   r   rv   rw   rx   r-   r]   )rC   rf   isomorphism_Hg_orderh_orderh_isomorphismr   r#   subsetr   _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   )rC   rf   r   r   r   is_isomorphic  s   r   )r   T)T)r   sympy.combinatorics.fp_groupsr   r   r   r5   r   sympy.combinatorics.perm_groupsr   sympy.core.intfuncr   %sympy.functions.combinatorial.numbersr   sympy.core.singletonr	   r
   rz   rx   r   r   r   r   r   r   r   r   <module>   s       
)1
$t