
    \hS                     `    S SK Jr  S SKJr  S SKJr  S SKJr   " S S\5      r " S S\5      r	g	)
    isprime)PermutationGroup)DefaultPrinting)
free_groupc                   2    \ rS rSrSrSrSS jrS rS rSr	g)	PolycyclicGroup   TNc                 |    Xl         X l        X0l        U(       d  [        U R                   X#5      U l        gUU l        g)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        U/var/www/auris/envauris/lib/python3.13/site-packages/sympy/combinatorics/pc_groups.py__init__PolycyclicGroup.__init__   s/    $  	",PY499iH_h    c                 :    [        S U R                   5       5      $ )Nc              3   8   #    U  H  n[        U5      v   M     g 7fNr   ).0orders     r   	<genexpr>1PolycyclicGroup.is_prime_order.<locals>.<genexpr>$   s     C/Be75>>/Bs   )allr   r   s    r   is_prime_orderPolycyclicGroup.is_prime_order#   s    Ct/B/BCCCr   c                 ,    [        U R                  5      $ r   )lenr   r   s    r   lengthPolycyclicGroup.length&   s    499~r   )r   r   r   r   r   )
__name__
__module____qualname____firstlineno__is_groupis_solvabler   r    r$   __static_attributes__ r   r   r	   r	      s    HKi.Dr   r	   c                   j    \ rS rSrSrSS jrS rS rS rS r	S	 r
S
 rS rS rS rS rS rS rSrg)r   *   z
References
==========

.. [1] Holt, D., Eick, B., O'Brien, E.
       "Handbook of Computational Group Theory"
       Section 8.1.3
Nc                 8   Xl         X l        X0l        U(       d&  [        SR	                  [        U5      5      5      S   OUU l        [        U R                  R                  5       VVs0 s H  u  pgXv_M	     snnU l        U R                  5       U l
        gs  snnf )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   N)r   r   r   r   formatr#   	enumeratesymbolsindexpc_relatorspc_presentation)r   r   r   r   free_group_r6   iss           r   r   Collector.__init__5   sy    , 	",IT*V]]3t9%=>qAZe'01H1H'IJ'Itqad'IJ
#//1 Ks   )Bc                 ~   U(       d  gUR                   nU R                  nU R                  n[        [	        U5      5       H0  nX%   u  pgX4U      (       d  M  US:  d  XsXF      S-
  :  d  M,  Xg44s  $    [        [	        U5      S-
  5       H.  nX%   u  pgX%S-      u  pXF   XH   :  d  M  U	S:  a  SOSn
Xg4X44s  $    g)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   r4   ranger#   )r   wordarrayrer4   r8   s1e1s2e2es              r   minimal_uncollected_subword%Collector.minimal_uncollected_subwordR   s    F   

s5z"AXFB)}}"q&BEIq,@|#	 # s5z!|$AXFBQ3ZFBy59$aAR2'** % r   c                     0 n0 nU R                   R                  5        H(  u  p4[        UR                  5      S:X  a  XAU'   M$  XBU'   M*     X4$ )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

r<   )r6   itemsr#   r>   )r   power_relatorsconjugate_relatorskeyvalues        r   	relationsCollector.relations   sV    < ..446JC3>>"a'&+s#*/3'	 7
 11r   c                     SnSn[        [        U5      [        U5      -
  S-   5       H8  nUR                  XU[        U5      -   5      U:X  d  M&  UnU[        U5      -   n  X44$    X44$ )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. If not exists, (-1,-1) is returned.

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)
>>> w = x1**8
>>> collector.subword_index(word, w)
(-1, -1)

r=   r<   )r?   r#   subword)r   r@   wlowhighr8   s         r   subword_indexCollector.subword_index   sp    V s4yQ')*A||AQx(A-Qxy +
 yr   c                     UR                   nUS   S   nUS   S   nUS4US4US44nU R                  R                  U5      nU R                  U   $ )aW  
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   r<   r=   )r>   r   dtyper6   )r   rT   rA   rC   rE   rN   s         r   map_relationCollector.map_relation   sd    > 1Xa[1Xa[Bx"a2q'*oo##C(##C((r   c                    U R                   n U R                  U5      nU(       d   U$ U R                  XR                  " U5      5      u  pEUS:X  a  MG  US   u  pg[	        U5      S:X  a  U R
                  U R                  U      nXx-  n	XyU-  -
  n
US   S   U44nUR                  " U5      nU R                  U   (       aC  U R                  U   R                  nUS   u  pUS   S   U
4XU-  44nUR                  " U5      nO&U
S:w  a  US   S   U
44nUR                  " U5      nOSnUR                  UR                  " U5      U5      n[	        U5      S:X  ax  US   S   S:  al  US   u  nnUS44nUR                  " U5      nU R                  UR                  " U5      5      nUX-  -  nUR                  " U5      nUR                  XEU5      nO[	        U5      S:X  az  US   S   S:  an  US   u  nnUS44nUR                  " U5      nU R                  UR                  " U5      5      nUS-  X-  -  nUR                  " U5      nUR                  XEU5      nGMR  )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

r=   r   r<   N   )r   rH   rW   rZ   r#   r   r4   r6   r>   eliminate_wordr[   substituted_word)r   r@   r   rT   rU   rV   rC   rD   rB   qrrN   presentationsymexpword_rE   rF   s                     r   collected_wordCollector.collected_word  s   B __
006AZ W **41A1A!1DEICbyqTFB1v{((B8HtG!Q}' &&s+'',#'#7#7#<#G#GL+AHCd1gq\C3<8E&,,U3EAv"#A$q'1 0 * 0 0 7 $**:+;+;A+>F1v{qtAw{1B1g[%%b)))**:*:1*=>59"((/,,S>Q11a11B1g[%%b)))**:*:1*=>Buy("((/,,S>] r   c                    U R                   nU R                  n0 n0 nU R                  n[        XQR                  5       H  u  pgUS-  XFS-  '   XtU'   M     USSS2   nU R
                  SSS2   nUSSS2   n/ n	[        U5       GHM  u  pX*   nXF   U-  nX   nUR                  Xk-  SS9nUR                  5         UR                  nU H
  nXU   -  nM     U R                  U5      nU(       a  UOSX<'   X0l        U	R                  U5        [        U	5      S:  d  M  U	[        U	5      S-
     nUU   n[        [        U	5      S-
  5       H  nXIU      nUS-  U-  U-  nUS-  U	U   -  U-  nUR                  USS9nUR                  5         UR                  nU H
  nXU   -  nM     U R                  U5      nU(       a  UOSX<'   X0l        M     GMP     U$ )a  
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

r=   NToriginalr-   r<   )r   r   r   zip
generatorsr   r2   generator_productreverseidentityrg   r6   appendr#   r?   )r   r   	rel_orderr5   perm_to_freer   genr9   seriescollected_gensr8   rB   relationGlr@   gconj
conjugatorj
conjugatedgenss                         r   r5   Collector.pc_relators  s   F __
''	yy$ 5 56FC$%rELb! ! 7 DbDz"%ddO	oFAB#(",H	A##CG#=AIIK&&DO+  &&t,D,0DbK!#. !!#&>"Q&%c.&9!&;<)$/
s>2145A!-Q.?!@J)2~j8CH8N1$55d:D++DT+BAIIK%..D#O3   ..t4D48DbK)+6( 6+ &J r   c                    U R                   n[        5       nU R                   H  n[        U/UR                  -   5      nM     UR	                  USS9nUR                  5         0 n[        UR                  U R                  5       H  u  ptUS-  XdS-  '   XvU'   M     UR                  nU H
  nXU   -  nM     U R                  U5      n	U R                  n
S/[        U5      -  nU	R                  n	U	 H  nUS   XUS      '   M     U$ )a:  
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

Trj   r=   r   r<   )r   r   r   rm   rn   ro   rl   rp   rg   r4   r#   r>   )r   elementr   rx   rz   r   rs   rd   rT   r@   r4   
exp_vectorts                r   exponent_vectorCollector.exponent_vector  s   Z __
A !q||!34A ""7t"<*//;FC"%r'LB!O < Aq/!A  ""1%

SZ(
A&'dJQqT{# r   c                     U R                  U5      n[        S [        U5       5       [        U R                  5      S-   5      $ )ai  
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   B   #    U  H  u  pU(       d  M  US -   v   M     g7f)r<   Nr-   )r   r8   xs      r   r   "Collector.depth.<locals>.<genexpr>a  s     @%:TQaSQqS%:s   r<   )r   nextr2   r#   r   )r   r   r   s      r   depthCollector.depthA  s:    > ))'2
@Yz%:@#dii.QRBRSSr   c                     U R                  U5      nU R                  U5      nU[        U R                  5      S-   :w  a  X#S-
     $ g)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

r<   N)r   r   r#   r   )r   r   r   r   s       r   leading_exponentCollector.leading_exponentc  sG    * ))'2


7#C		N1$$Ag&&r   c                 t   UnU R                  U5      nU[        U R                  5      :  a  XS-
     S:w  a  XS-
     nU R                  U5      U R                  U5      S-  -  nX`R                  US-
     -  nXV* -  U-  nU R                  U5      nU[        U R                  5      :  a  XS-
     S:w  a  M  U$ )Nr<   r=   )r   r#   r   r   r   )r   zrz   hdkrG   s          r   _siftCollector._sift~  s    JJqM#dii. QsVq[A#A%%a($*?*?*BR)GGA''!,,A2aA

1A #dii. QsVq[ r   c                    S/[        U R                  5      -  nUnU(       a  UR                  S5      nU R                  X$5      nU R	                  U5      nU[        U R                  5      :  a8  U H+  nUS:w  d  M  UR                  US-  US-  -  U-  U-  5        M-     XRUS-
  '   U(       a  M  U Vs/ s H  owS:w  d  M
  UPM     nnU$ s  snf )ax  

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]

r<   r   r=   )r#   r   popr   r   rq   )r   r   r   rx   rz   r   r   rt   s           r   induced_pcgsCollector.induced_pcgs  s    > CDIIaA

1 A

1A3tyy>!CaxBsBwq!45  !A# a *ASSA* +s   4	CCc                    S/[        U5      -  nUnU R                  U5      n[        U5       H  u  pgU R                  U5      U:X  d  M  U R                  U5      U R                  U5      -  nXR                  US-
     -  nXx* -  U-  nXU'   U R                  U5      nU R                  U5      U:X  a  Mk  M     US:X  a  U$ g)z.
Return the exponent vector for induced pcgs.
r   r<   F)r#   r   r2   r   r   )	r   ipcgsrz   rG   r   r   r8   rt   fs	            r   constructive_membership_test&Collector.constructive_membership_test  s     CE
NJJqM&FA**S/Q&))!,T-B-B3-GG++AaC00"IaK!JJqM **S/Q& ' 6Hr   )r   r4   r6   r   r   r   )NN)r&   r'   r(   r)   __doc__r   rH   rP   rW   r[   rg   r5   r   r   r   r   r   r   r,   r-   r   r   r   r   *   sU    2:8t%2N2h$)NrjwrCJ 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 6 o  F\
 \
r   