
    ggS                     n    d dl mZ d dlmZ d dlmZ d dlmZ  G d de          Z G d de          Z	d	S )
    isprime)PermutationGroup)DefaultPrinting)
free_groupc                   *    e Zd ZdZdZddZd Zd ZdS )PolycyclicGroupTNc                 n    || _         || _        || _        |st          | j         ||          n|| _        dS )a  

        Parameters
        ==========

        pc_sequence : list
            A sequence of elements whose classes generate the cyclic factor
            groups of pc_series.
        pc_series : list
            A subnormal sequence of subgroups where each factor group is cyclic.
        relative_order : list
            The orders of factor groups of pc_series.
        collector : Collector
            By default, it is None. Collector class provides the
            polycyclic presentation with various other functionalities.

        N)pcgs	pc_seriesrelative_order	Collector	collector)selfpc_sequencer   r   r   s        Y/var/www/html/ai-engine/env/lib/python3.11/site-packages/sympy/combinatorics/pc_groups.py__init__zPolycyclicGroup.__init__   s>    $  	",PYh49iHHH_h    c                 >    t          d | j        D                       S )Nc              3   4   K   | ]}t          |          V  d S Nr   ).0orders     r   	<genexpr>z1PolycyclicGroup.is_prime_order.<locals>.<genexpr>$   s(      CCe75>>CCCCCCr   )allr   r   s    r   is_prime_orderzPolycyclicGroup.is_prime_order#   s"    CCt/BCCCCCCr   c                 *    t          | j                  S r   )lenr   r   s    r   lengthzPolycyclicGroup.length&   s    49~~r   r   )__name__
__module____qualname__is_groupis_solvabler   r   r     r   r   r	   r	      sW        HKi i i i.D D D    r   r	   c                   b    e Zd ZdZddZd Zd Zd Zd Zd Z	d	 Z
d
 Zd Zd Zd Zd Zd ZdS )r   z
    References
    ==========

    .. [1] Holt, D., Eick, B., O'Brien, E.
           "Handbook of Computational Group Theory"
           Section 8.1.3
    Nc                 .   || _         || _        || _        |s5t          d                    t          |                              d         n|| _        d t          | j        j                  D             | _        | 	                                | _
        dS )a  

        Most of the parameters for the Collector class are the same as for PolycyclicGroup.
        Others are described below.

        Parameters
        ==========

        free_group_ : tuple
            free_group_ provides the mapping of polycyclic generating
            sequence with the free group elements.
        pc_presentation : dict
            Provides the presentation of polycyclic groups with the
            help of power and conjugate relators.

        See Also
        ========

        PolycyclicGroup

        zx:{}r   c                     i | ]\  }}||	S r&   r&   )r   iss      r   
<dictcomp>z&Collector.__init__.<locals>.<dictcomp>O   s    JJJtq!aJJJr   N)r   r   r   r   formatr   	enumeratesymbolsindexpc_relatorspc_presentation)r   r   r   r   free_group_r2   s         r   r   zCollector.__init__5   s    , 	",ITe*V]]3t99%=%=>>qAAZeJJy1H'I'IJJJ
#//11r   c                    |sdS |j         }| j        }| j        }t          t	          |                    D ]=}||         \  }}|||                  r"|dk     s||||                  dz
  k    r||ffc S >t          t	          |          dz
            D ]A}||         \  }}||dz            \  }}	||         ||         k    r|	dk    rdnd}
||f||
ffc S BdS )a  
        Returns the minimal uncollected subwords.

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

        A word ``v`` defined on generators in ``X`` is a minimal
        uncollected subword of the word ``w`` if ``v`` is a subword
        of ``w`` and it has one of the following form

        * `v = {x_{i+1}}^{a_j}x_i`

        * `v = {x_{i+1}}^{a_j}{x_i}^{-1}`

        * `v = {x_i}^{a_j}`

        for `a_j` not in `\{1, \ldots, s-1\}`. Where, ``s`` is the power
        exponent of the corresponding generator.

        Examples
        ========

        >>> from sympy.combinatorics.named_groups import SymmetricGroup
        >>> from sympy.combinatorics import free_group
        >>> G = SymmetricGroup(4)
        >>> PcGroup = G.polycyclic_group()
        >>> collector = PcGroup.collector
        >>> F, x1, x2 = free_group("x1, x2")
        >>> word = x2**2*x1**7
        >>> collector.minimal_uncollected_subword(word)
        ((x2, 2),)

        Nr      )
array_formr   r0   ranger   )r   wordarrayrer0   r*   s1e1s2e2es              r   minimal_uncollected_subwordz%Collector.minimal_uncollected_subwordR   s   F  	4 
s5zz"" 	$ 	$A1XFB%)} $"q&&BE"Iq,@,@R|###s5zz!|$$ 	+ 	+A1XFB1Q3ZFBRy59$$aAARR2q'**** % tr   c                     i }i }| j                                         D ](\  }}t          |j                  dk    r|||<   #|||<   )||fS )a  
        Separates the given relators of pc presentation in power and
        conjugate relations.

        Returns
        =======

        (power_rel, conj_rel)
            Separates pc presentation into power and conjugate relations.

        Examples
        ========

        >>> from sympy.combinatorics.named_groups import SymmetricGroup
        >>> G = SymmetricGroup(3)
        >>> PcGroup = G.polycyclic_group()
        >>> collector = PcGroup.collector
        >>> power_rel, conj_rel = collector.relations()
        >>> power_rel
        {x0**2: (), x1**3: ()}
        >>> conj_rel
        {x0**-1*x1*x0: x1**2}

        See Also
        ========

        pc_relators

        r5   )r2   itemsr   r7   )r   power_relatorsconjugate_relatorskeyvalues        r   	relationszCollector.relations   sm    < .4466 	0 	0JC3>""a''&+s##*/"3''111r   c                    d}d}t          t          |          t          |          z
  dz             D ]B}|                    ||t          |          z             |k    r|}|t          |          z   } nC||cxk    rdk    rn ndS ||fS )a  
        Returns the start and ending index of a given
        subword in a word.

        Parameters
        ==========

        word : FreeGroupElement
            word defined on free group elements for a
            polycyclic group.
        w : FreeGroupElement
            subword of a given word, whose starting and
            ending index to be computed.

        Returns
        =======

        (i, j)
            A tuple containing starting and ending index of ``w``
            in the given word.

        Examples
        ========

        >>> from sympy.combinatorics.named_groups import SymmetricGroup
        >>> from sympy.combinatorics import free_group
        >>> G = SymmetricGroup(4)
        >>> PcGroup = G.polycyclic_group()
        >>> collector = PcGroup.collector
        >>> F, x1, x2 = free_group("x1, x2")
        >>> word = x2**2*x1**7
        >>> w = x2**2*x1
        >>> collector.subword_index(word, w)
        (0, 3)
        >>> w = x1**7
        >>> collector.subword_index(word, w)
        (2, 9)

        r6   r5   )r6   r6   )r8   r   subword)r   r9   wlowhighr*   s         r   subword_indexzCollector.subword_index   s    P s4yyQ')** 	 	A||AqQx((A--Qx . $"6Dyr   c                     |j         }|d         d         }|d         d         }|df|df|dff}| j                            |          }| j        |         S )a  
        Return a conjugate relation.

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

        Given a word formed by two free group elements, the
        corresponding conjugate relation with those free
        group elements is formed and mapped with the collected
        word in the polycyclic presentation.

        Examples
        ========

        >>> from sympy.combinatorics.named_groups import SymmetricGroup
        >>> from sympy.combinatorics import free_group
        >>> G = SymmetricGroup(3)
        >>> PcGroup = G.polycyclic_group()
        >>> collector = PcGroup.collector
        >>> F, x0, x1 = free_group("x0, x1")
        >>> w = x1*x0
        >>> collector.map_relation(w)
        x1**2

        See Also
        ========

        pc_presentation

        r   r5   r6   )r7   r   dtyper2   )r   rK   r:   r<   r>   rF   s         r   map_relationzCollector.map_relation   s`    > 1Xa[1Xa[Bx"a2q'*o##C((#C((r   c                    | j         }	 |                     |          }|snf|                     | |j        |                    \  }}|dk    rH|d         \  }}t	          |          dk    r| j        | j        |                  }||z  }	||	|z  z
  }
|d         d         |ff} |j        |          }| j        |         rE| j        |         j        }|d         \  }}|d         d         |
f||	|z  ff} |j        |          }n*|
dk    r"|d         d         |
ff} |j        |          }nd}|	                     |j        |          |          }t	          |          dk    r|d         d         dk    rs|d         \  }}|dff} |j        |          }| 
                     |j        |                    }|||z  z  } |j        |          }|                    |||          }nt	          |          dk    r|d         d         dk     ru|d         \  }}|dff} |j        |          }| 
                     |j        |                    }|dz  ||z  z  } |j        |          }|                    |||          }|S )a  
        Return the collected form of a word.

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

        A word ``w`` is called collected, if `w = {x_{i_1}}^{a_1} * \ldots *
        {x_{i_r}}^{a_r}` with `i_1 < i_2< \ldots < i_r` and `a_j` is in
        `\{1, \ldots, {s_j}-1\}`.

        Otherwise w is uncollected.

        Parameters
        ==========

        word : FreeGroupElement
            An uncollected word.

        Returns
        =======

        word
            A collected word of form `w = {x_{i_1}}^{a_1}, \ldots,
            {x_{i_r}}^{a_r}` with `i_1, i_2, \ldots, i_r` and `a_j \in
            \{1, \ldots, {s_j}-1\}`.

        Examples
        ========

        >>> from sympy.combinatorics.named_groups import SymmetricGroup
        >>> from sympy.combinatorics.perm_groups import PermutationGroup
        >>> from sympy.combinatorics import free_group
        >>> G = SymmetricGroup(4)
        >>> PcGroup = G.polycyclic_group()
        >>> collector = PcGroup.collector
        >>> F, x0, x1, x2, x3 = free_group("x0, x1, x2, x3")
        >>> word = x3*x2*x1*x0
        >>> collected_word = collector.collected_word(word)
        >>> free_to_perm = {}
        >>> free_group = collector.free_group
        >>> for sym, gen in zip(free_group.symbols, collector.pcgs):
        ...     free_to_perm[sym] = gen
        >>> G1 = PermutationGroup()
        >>> for w in word:
        ...     sym = w[0]
        ...     perm = free_to_perm[sym]
        ...     G1 = PermutationGroup([perm] + G1.generators)
        >>> G2 = PermutationGroup()
        >>> for w in collected_word:
        ...     sym = w[0]
        ...     perm = free_to_perm[sym]
        ...     G2 = PermutationGroup([perm] + G2.generators)

        The two are not identical, but they are equivalent:

        >>> G1.equals(G2), G1 == G2
        (True, False)

        See Also
        ========

        minimal_uncollected_subword

        Tr6   r   r5   N   )r   rA   rN   rP   r   r   r0   r2   r7   eliminate_wordrQ   substituted_word)r   r9   r   rK   rL   rM   r<   r=   r;   qrrF   presentationsymexpword_r>   r?   s                     r   collected_wordzCollector.collected_word  s   B _
.	?0066A **41A1A!1D1DEEICbyyqTFB1vv{{(B8"HqtG!Q}'&j&s++', 
%#'#7#<#GL+AHCd1gq\C3<8E,J,U33EEAvv"#A$q'1 0 0
 0 7 7 $**+;:+;A+>+>FF1vv{{qtAw{{1B1g[%Z%b))))*:**:1*=*=>>5"9(
(//,,S$>>Q11a11B1g[%Z%b))))*:**:1*=*=>>Buby((
(//,,S$>>].	?` r   c                    | j         }| j        }i }i }| j        }t          ||j                  D ]\  }}|dz  ||dz  <   |||<   |ddd         }| j        ddd         }|ddd         }g }	t          |          D ]\  }
}||
         }||         |z  }||
         }|                    ||z  d          }|                                 |j	        }|D ]}|||         z  }| 
                    |          }|r|nd||<   || _        |	                    |           t          |	          dk    r|	t          |	          dz
           }||         }t          t          |	          dz
            D ]}||	|                  }|dz  |z  |z  }|dz  |	|         z  |z  }|                    |d          }|                                 |j	        }|D ]}|||         z  }| 
                    |          }|r|nd||<   || _        |S )aM  
        Return the polycyclic presentation.

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

        There are two types of relations used in polycyclic
        presentation.

        * Power relations : Power relators are of the form `x_i^{re_i}`,
          where `i \in \{0, \ldots, \mathrm{len(pcgs)}\}`, ``x`` represents polycyclic
          generator and ``re`` is the corresponding relative order.

        * Conjugate relations : Conjugate relators are of the form `x_j^-1x_ix_j`,
          where `j < i \in \{0, \ldots, \mathrm{len(pcgs)}\}`.

        Returns
        =======

        A dictionary with power and conjugate relations as key and
        their collected form as corresponding values.

        Notes
        =====

        Identity Permutation is mapped with empty ``()``.

        Examples
        ========

        >>> from sympy.combinatorics.named_groups import SymmetricGroup
        >>> from sympy.combinatorics.permutations import Permutation
        >>> S = SymmetricGroup(49).sylow_subgroup(7)
        >>> der = S.derived_series()
        >>> G = der[len(der)-2]
        >>> PcGroup = G.polycyclic_group()
        >>> collector = PcGroup.collector
        >>> pcgs = PcGroup.pcgs
        >>> len(pcgs)
        6
        >>> free_group = collector.free_group
        >>> pc_resentation = collector.pc_presentation
        >>> free_to_perm = {}
        >>> for s, g in zip(free_group.symbols, pcgs):
        ...     free_to_perm[s] = g

        >>> for k, v in pc_resentation.items():
        ...     k_array = k.array_form
        ...     if v != ():
        ...        v_array = v.array_form
        ...     lhs = Permutation()
        ...     for gen in k_array:
        ...         s = gen[0]
        ...         e = gen[1]
        ...         lhs = lhs*free_to_perm[s]**e
        ...     if v == ():
        ...         assert lhs.is_identity
        ...         continue
        ...     rhs = Permutation()
        ...     for gen in v_array:
        ...         s = gen[0]
        ...         e = gen[1]
        ...         rhs = rhs*free_to_perm[s]**e
        ...     assert lhs == rhs

        r6   NToriginalr&   r5   )r   r   r   zip
generatorsr   r.   generator_productreverseidentityr\   r2   appendr   r8   )r   r   	rel_orderr1   perm_to_freer   genr+   seriescollected_gensr*   r;   relationGlr9   gconj
conjugatorj
conjugatedgenss                         r   r1   zCollector.pc_relators  s{   F _
'	y$
 566 	" 	"FC$%rELb! !LDDbDz"%dddO	oo #	7 #	7FAs1B#C(",Hq	A##CG#==AIIKKK&D , ,LO+&&t,,D,0$8DDbK!#.D !!#&&&>""Q&&%c.&9&9!&;<)$/
s>221455 7 7A!-nQ.?!@J)2~j8CH8N1$55d:D++DT+BBAIIKKK%.D 4 4#LO3..t44D48,@DDbK)+6D((r   c                     | j         }t                      }| j        D ]}t          |g|j        z             }|                    |d          }|                                 i }t          |j        | j                  D ]\  }}|dz  ||dz  <   |||<   |j        }|D ]}|||         z  }|                     |          }	| j	        }
dgt          |          z  }|	j        }	|	D ]}|d         ||
|d                  <   |S )aJ  
        Return the exponent vector of length equal to the
        length of polycyclic generating sequence.

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

        For a given generator/element ``g`` of the polycyclic group,
        it can be represented as `g = {x_1}^{e_1}, \ldots, {x_n}^{e_n}`,
        where `x_i` represents polycyclic generators and ``n`` is
        the number of generators in the free_group equal to the length
        of pcgs.

        Parameters
        ==========

        element : Permutation
            Generator of a polycyclic group.

        Examples
        ========

        >>> from sympy.combinatorics.named_groups import SymmetricGroup
        >>> from sympy.combinatorics.permutations import Permutation
        >>> G = SymmetricGroup(4)
        >>> PcGroup = G.polycyclic_group()
        >>> collector = PcGroup.collector
        >>> pcgs = PcGroup.pcgs
        >>> collector.exponent_vector(G[0])
        [1, 0, 0, 0]
        >>> exp = collector.exponent_vector(G[1])
        >>> g = Permutation()
        >>> for i in range(len(exp)):
        ...     g = g*pcgs[i]**exp[i] if exp[i] else g
        >>> assert g == G[1]

        References
        ==========

        .. [1] Holt, D., Eick, B., O'Brien, E.
               "Handbook of Computational Group Theory"
               Section 8.1.1, Definition 8.4

        Tr^   r6   r   r5   )r   r   r   ra   rb   rc   r`   rd   r\   r0   r   r7   )r   elementr   rl   rn   rs   rg   rY   rK   r9   r0   
exp_vectorts                r   exponent_vectorzCollector.exponent_vector  s1   Z _
 	5 	5A !q|!344AA""7t"<<*/;; 	" 	"FC"%r'LB!LOO 	" 	"A,q/!AA""1%%
SZ(
 	+ 	+A&'dJuQqT{##r   c                     |                      |          }t          d t          |          D             t          | j                  dz             S )a  
        Return the depth of a given element.

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

        The depth of a given element ``g`` is defined by
        `\mathrm{dep}[g] = i` if `e_1 = e_2 = \ldots = e_{i-1} = 0`
        and `e_i != 0`, where ``e`` represents the exponent-vector.

        Examples
        ========

        >>> from sympy.combinatorics.named_groups import SymmetricGroup
        >>> G = SymmetricGroup(3)
        >>> PcGroup = G.polycyclic_group()
        >>> collector = PcGroup.collector
        >>> collector.depth(G[0])
        2
        >>> collector.depth(G[1])
        1

        References
        ==========

        .. [1] Holt, D., Eick, B., O'Brien, E.
               "Handbook of Computational Group Theory"
               Section 8.1.1, Definition 8.5

        c              3   *   K   | ]\  }}||d z   V  dS )r5   Nr&   )r   r*   xs      r   r   z"Collector.depth.<locals>.<genexpr>`  s/      @@TQa@QqS@@@@@@r   r5   )rx   nextr.   r   r   )r   ru   rv   s      r   depthzCollector.depth@  sL    > ))'22
@@Yz%:%:@@@#di..QRBRSSSr   c                     |                      |          }|                     |          }|t          | j                  dz   k    r||dz
           S dS )a  
        Return the leading non-zero exponent.

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

        The leading exponent for a given element `g` is defined
        by `\mathrm{leading\_exponent}[g]` `= e_i`, if `\mathrm{depth}[g] = i`.

        Examples
        ========

        >>> from sympy.combinatorics.named_groups import SymmetricGroup
        >>> G = SymmetricGroup(3)
        >>> PcGroup = G.polycyclic_group()
        >>> collector = PcGroup.collector
        >>> collector.leading_exponent(G[1])
        1

        r5   N)rx   r}   r   r   )r   ru   rv   r}   s       r   leading_exponentzCollector.leading_exponentb  sT    * ))'22


7##C	NN1$$$eAg&&tr   c                    |}|                      |          }|t          | j                  k     r||dz
           dk    r||dz
           }|                     |          |                     |          dz  z  }|| j        |dz
           z  }|| z  |z  }|                      |          }|t          | j                  k     r||dz
           dk    |S )Nr5   r6   )r}   r   r   r   r   )r   zrn   hdkr@   s          r   _siftzCollector._sift}  s    JJqMM#di..  QqsVq[[!A#A%%a(($*?*?*B*BR)GGAD'!,,AA2aA

1A #di..  QqsVq[[ r   c                 x   dgt          | j                  z  }|}|r|                    d          }|                     ||          }|                     |          }|t          | j                  k     r7|D ],}|dk    r$|                    |dz  |dz  z  |z  |z             -|||dz
  <   |d |D             }|S )a8  

        Parameters
        ==========

        gens : list
            A list of generators on which polycyclic subgroup
            is to be defined.

        Examples
        ========

        >>> from sympy.combinatorics.named_groups import SymmetricGroup
        >>> S = SymmetricGroup(8)
        >>> G = S.sylow_subgroup(2)
        >>> PcGroup = G.polycyclic_group()
        >>> collector = PcGroup.collector
        >>> gens = [G[0], G[1]]
        >>> ipcgs = collector.induced_pcgs(gens)
        >>> [gen.order() for gen in ipcgs]
        [2, 2, 2]
        >>> G = S.sylow_subgroup(3)
        >>> PcGroup = G.polycyclic_group()
        >>> collector = PcGroup.collector
        >>> gens = [G[0], G[1]]
        >>> ipcgs = collector.induced_pcgs(gens)
        >>> [gen.order() for gen in ipcgs]
        [3]

        r5   r   r6   c                     g | ]
}|d k    |S )r5   r&   )r   rh   s     r   
<listcomp>z*Collector.induced_pcgs.<locals>.<listcomp>  s    ***SSr   )r   r   popr   r}   re   )r   rs   r   rl   rn   r   r   rh   s           r   induced_pcgszCollector.induced_pcgs  s    > CDI 	aA

1a  A

1A3ty>>!! 6 6CaxxBsBwq!4555!A#  	 +*A***r   c                    dgt          |          z  }|}|                     |          }t          |          D ]\  }}|                     |          |k    rz|                     |          |                     |          z  }|| j        |dz
           z  }|| z  |z  }|||<   |                     |          }|                     |          |k    z|dk    r|S dS )z>
        Return the exponent vector for induced pcgs.
        r   r5   F)r   r}   r.   r   r   )	r   ipcgsrn   r@   r   r   r*   rh   fs	            r   constructive_membership_testz&Collector.constructive_membership_test  s     CE

NJJqMM&& 	" 	"FAs**S//Q&&))!,,T-B-B3-G-GG+AaC001"IaK!JJqMM **S//Q&& 66Hur   )NN)r!   r"   r#   __doc__r   rA   rH   rN   rQ   r\   r1   rx   r}   r   r   r   r   r&   r   r   r   r   *   s         2 2 2 2:8 8 8t%2 %2 %2N1 1 1f$) $) $)Nr r rjw w wrC C CJ T  T  TD  6	 	 	+ + +Z    r   r   N)
sympy.ntheory.primetestr   sympy.combinatorics.perm_groupsr   sympy.printing.defaultsr   sympy.combinatorics.free_groupsr   r	   r   r&   r   r   <module>r      s    + + + + + + < < < < < < 3 3 3 3 3 3 6 6 6 6 6 6         o      F[
 [
 [
 [
 [
 [
 [
 [
 [
 [
r   