
    wg7                       U d dl mZ d dlmZ d dlmZ d dlmZmZ	 d dl
mZ d dlmZ d dlmZ d dlmZmZ d d	lmZ d d
lmZ ed        Zed        Zed        Zd Zi Zded<    G d de      Z G d deee      Zd Z d Z!y)    )annotations)S)Expr)Symbolsymbols)CantSympify)DefaultPrinting)public)flattenis_sequence)pollute)as_intc                J    t        |       }|ft        |j                        z   S )a  Construct a free group returning ``(FreeGroup, (f_0, f_1, ..., f_(n-1))``.

    Parameters
    ==========

    symbols : str, Symbol/Expr or sequence of str, Symbol/Expr (may be empty)

    Examples
    ========

    >>> from sympy.combinatorics import free_group
    >>> F, x, y, z = free_group("x, y, z")
    >>> F
    <free group on the generators (x, y, z)>
    >>> x**2*y**-1
    x**2*y**-1
    >>> type(_)
    <class 'sympy.combinatorics.free_groups.FreeGroupElement'>

    )	FreeGrouptuple
generatorsr   _free_groups     d/home/mcse/projects/flask/flask-venv/lib/python3.12/site-packages/sympy/combinatorics/free_groups.py
free_groupr      s&    , G$K>E+"8"8999    c                4    t        |       }||j                  fS )a  Construct a free group returning ``(FreeGroup, (f_0, f_1, ..., f_(n-1)))``.

    Parameters
    ==========

    symbols : str, Symbol/Expr or sequence of str, Symbol/Expr (may be empty)

    Examples
    ========

    >>> from sympy.combinatorics.free_groups import xfree_group
    >>> F, (x, y, z) = xfree_group("x, y, z")
    >>> F
    <free group on the generators (x, y, z)>
    >>> y**2*x**-2*z**-1
    y**2*x**-2*z**-1
    >>> type(_)
    <class 'sympy.combinatorics.free_groups.FreeGroupElement'>

    )r   r   r   s     r   xfree_groupr   '   s    , G$K//00r   c                    t        |       }t        |j                  D cg c]  }|j                   c}|j                         |S c c}w )a  Construct a free group and inject ``f_0, f_1, ..., f_(n-1)`` as symbols
    into the global namespace.

    Parameters
    ==========

    symbols : str, Symbol/Expr or sequence of str, Symbol/Expr (may be empty)

    Examples
    ========

    >>> from sympy.combinatorics.free_groups import vfree_group
    >>> vfree_group("x, y, z")
    <free group on the generators (x, y, z)>
    >>> x**2*y**-2*z # noqa: F821
    x**2*y**-2*z
    >>> type(_)
    <class 'sympy.combinatorics.free_groups.FreeGroupElement'>

    )r   r   r   namer   )r   r   syms      r   vfree_groupr   @   s>    , G$K!4!45#SXX5{7M7MN 6s   Ac                   | syt        | t              rt        | d      S t        | t        t        f      r| fS t        |       r1t        d | D              rt        |       S t        d | D              r| S t        d      )N T)seqc              3  <   K   | ]  }t        |t                y wN)
isinstancestr.0ss     r   	<genexpr>z!_parse_symbols.<locals>.<genexpr>c   s     3az!S!3   c              3  <   K   | ]  }t        |t                y wr"   )r#   r   r%   s     r   r(   z!_parse_symbols.<locals>.<genexpr>e   s     6At$6r)   zjThe type of `symbols` must be one of the following: a str, Symbol/Expr or a sequence of one of these types)r#   r$   _symbolsr   FreeGroupElementr   all
ValueErrorr   s    r   _parse_symbolsr0   [   s}    '3T**	Gd$45	6z	W	3733G$$6g66N
 * + +r   zdict[int, FreeGroup]_free_group_cachec                      e Zd ZU dZdZdZdZdZg Zde	d<   d Z
d Zdd	Zd
 Zd Zd Zd ZeZd Zd Zd Zd Zed        Zed        Zed        Zed        Zd Zd Zy)r   a  
    Free group with finite or infinite number of generators. Its input API
    is that of a str, Symbol/Expr or a sequence of one of
    these types (which may be empty)

    See Also
    ========

    sympy.polys.rings.PolyRing

    References
    ==========

    .. [1] https://www.gap-system.org/Manuals/doc/ref/chap37.html

    .. [2] https://en.wikipedia.org/wiki/Free_group

    TFz
list[Expr]relatorsc                V   t        t        |            }t        |      }t        | j                  ||f      }t
        j                  |      }|t        j                  |       }||_	        ||_
        t        dt        fd|i      |_        ||_        |j                         |_        t#        |j                         |_        t'        |j                  |j                         D ]<  \  }}t)        |t*              s|j,                  }t/        ||      s0t1        |||       > |t
        |<   |S )Nr,   group)r   r0   lenhash__name__r1   getobject__new___hash_ranktyper,   dtyper   _generatorsr   set	_gens_setzipr#   r   r   hasattrsetattr)clsr   rankr<   objsymbol	generatorr   s           r   r;   zFreeGroup.__new__   s    w/07|cllGT23##E*;..%CCICI/2B1DwPSnUCI!CK __.CN/CM%(cnn%E 6!	ff-!;;DsD)T95	6 (+e$
r   c                    g }| j                   D ]'  }|dff}|j                  | j                  |             ) t        |      S )zReturns the generators of the FreeGroup.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> F, x, y, z = free_group("x, y, z")
        >>> F.generators
        (x, y, z)

           )r   appendr?   r   )r5   gensr   elms       r   r@   zFreeGroup._generators   sH     == 	*C8+CKKC()	* T{r   Nc                @    | j                  |xs | j                        S r"   )	__class__r   )selfr   s     r   clonezFreeGroup.clone   s    ~~g566r   c                F    t        |t              sy|j                  }| |k(  S )z/Return True if ``i`` is contained in FreeGroup.Fr#   r,   r5   )rR   ir5   s      r   __contains__zFreeGroup.__contains__   s#    !-.u}r   c                    | j                   S r"   )r<   rR   s    r   __hash__zFreeGroup.__hash__   s    zzr   c                    | j                   S r"   rG   rY   s    r   __len__zFreeGroup.__len__   s    yyr   c                    | j                   dkD  rd| j                   z  }|S d}| j                  }|t        |      dz   z  }|S )N   z<free group with %s generators>z<free group on the generators >)rG   r   r$   )rR   str_formrN   s      r   __str__zFreeGroup.__str__   sI    99r>8499DH
  8H??DD	C'Hr   c                D    | j                   |   }| j                  |      S )Nr/   )r   rS   )rR   indexr   s      r   __getitem__zFreeGroup.__getitem__   s!    ,,u%zz'z**r   c                
    | |u S )z@No ``FreeGroup`` is equal to any "other" ``FreeGroup``.
        r   rR   others     r   __eq__zFreeGroup.__eq__   s     u}r   c                    t        || j                        r| j                  j                  |      S t	        d| d|      )a  Return the index of the generator `gen` from ``(f_0, ..., f_(n-1))``.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> F, x, y = free_group("x, y")
        >>> F.index(y)
        1
        >>> F.index(x)
        0

        z#expected a generator of Free Group z, got )r#   r?   r   rd   r.   rR   gens     r   rd   zFreeGroup.index   s9     c4::&??((--PTVYZ[[r   c                `    | j                   dk(  rt        j                  S t        j                  S )a  Return the order of the free group.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> F, x, y = free_group("x, y")
        >>> F.order()
        oo

        >>> free_group("")[0].order()
        1

        r   )rG   r   OneInfinityrY   s    r   orderzFreeGroup.order   s"     99>55L::r   c                P    | j                   dk(  r| j                  hS t        d      )z
        Return the elements of the free group.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> (z,) = free_group("")
        >>> z.elements
        {<identity>}

        r   zDGroup contains infinitely many elements, hence cannot be represented)rG   identityr.   rY   s    r   elementszFreeGroup.elements  s-     99>MM?" < = =r   c                    | j                   S )a  
        In group theory, the `rank` of a group `G`, denoted `G.rank`,
        can refer to the smallest cardinality of a generating set
        for G, that is

        \operatorname{rank}(G)=\min\{ |X|: X\subseteq G, \left\langle X\right\rangle =G\}.

        )r=   rY   s    r   rG   zFreeGroup.rank  s     zzr   c                    | j                   dv S )zReturns if the group is Abelian.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, x, y, z = free_group("x y z")
        >>> f.is_abelian
        False

        )r   rL   r\   rY   s    r   
is_abelianzFreeGroup.is_abelian"  s     yyF""r   c                "    | j                         S )z+Returns the identity element of free group.)r?   rY   s    r   rr   zFreeGroup.identity1  s     zz|r   c                F    t        |t              sy| |j                  k7  ryy)ai  Tests if Free Group element ``g`` belong to self, ``G``.

        In mathematical terms any linear combination of generators
        of a Free Group is contained in it.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, x, y, z = free_group("x y z")
        >>> f.contains(x**3*y**2)
        True

        FTrU   )rR   gs     r   containszFreeGroup.contains6  s#     !-.QWW_r   c                    | j                   hS )z,Returns the center of the free group `self`.)rr   rY   s    r   centerzFreeGroup.centerL  s    r   r"   )r8   
__module____qualname____doc__is_associativeis_groupis_FreeGroupis_PermutationGroupr3   __annotations__r;   r@   rS   rW   rZ   r]   rb   __repr__re   ri   rd   rp   propertyrs   rG   rv   rr   rz   r|   r   r   r   r   r   r   s    $ NHLHj2$7 H+
\&( = =( 	 	 # #  ,r   r   c                  r   e Zd ZdZdZd ZdZd Zd Ze	d        Z
e	d        Ze	d	        Zd
 Zd Ze	d        Ze	d        Zd Zd ZeZd Zd Zd Zd Zd Zd Zd Zd Zd3dZd4dZd Zd Zd Z d Z!d Z"d Z#d  Z$d! Z%d5d"Z&d6d#Z'd$ Z(d% Z)d& Z*d' Z+d( Z,d) Z-d* Z.d+ Z/d, Z0d- Z1d. Z2d/ Z3d0 Z4d7d1Z5d2 Z6y)8r,   zUsed to create elements of FreeGroup. It cannot be used directly to
    create a free group element. It is called by the `dtype` method of the
    `FreeGroup` class.

    Tc                $    | j                  |      S r"   )rQ   )rR   inits     r   newzFreeGroupElement.new^  s    ~~d##r   Nc                    | j                   }|0t        | j                  t        t	        |             f      x| _         }|S r"   )r<   r7   r5   	frozensetr   )rR   r<   s     r   rZ   zFreeGroupElement.__hash__c  s8    

=!%tzz9U4[3I&J!KKDJr   c                $    | j                  |       S r"   )r   rY   s    r   copyzFreeGroupElement.copyi  s    xx~r   c                $    | j                   dk(  ryy)Nr   TF
array_formrY   s    r   is_identityzFreeGroupElement.is_identityl  s    ??b r   c                    t        |       S )a  
        SymPy provides two different internal kinds of representation
        of associative words. The first one is called the `array_form`
        which is a tuple containing `tuples` as its elements, where the
        size of each tuple is two. At the first position the tuple
        contains the `symbol-generator`, while at the second position
        of tuple contains the exponent of that generator at the position.
        Since elements (i.e. words) do not commute, the indexing of tuple
        makes that property to stay.

        The structure in ``array_form`` of ``FreeGroupElement`` is of form:

        ``( ( symbol_of_gen, exponent ), ( , ), ... ( , ) )``

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, x, y, z = free_group("x y z")
        >>> (x*z).array_form
        ((x, 1), (z, 1))
        >>> (x**2*z*y*x**2).array_form
        ((x, 2), (z, 1), (y, 1), (x, 2))

        See Also
        ========

        letter_repr

        )r   rY   s    r   r   zFreeGroupElement.array_forms  s    @ T{r   c           
         t        t        | j                  D cg c]  \  }}|dkD  r|f|z  n| f| z   c}}            S c c}}w )a  
        The letter representation of a ``FreeGroupElement`` is a tuple
        of generator symbols, with each entry corresponding to a group
        generator. Inverses of the generators are represented by
        negative generator symbols.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, a, b, c, d = free_group("a b c d")
        >>> (a**3).letter_form
        (a, a, a)
        >>> (a**2*d**-2*a*b**-4).letter_form
        (a, a, -d, -d, a, -b, -b, -b, -b)
        >>> (a**-2*b**3*d).letter_form
        (-a, -a, b, b, b, d)

        See Also
        ========

        array_form

        r   r   r   r   )rR   rV   js      r   letter_formzFreeGroupElement.letter_form  sV    4 W $11 )*Aqd1fQB51":= 1 2 3 	3 1s   Ac                    | j                   }| j                  |   }|j                  r|j                  |dff      S |j                  | dff      S )NrL   r5   r   	is_Symbolr?   )rR   rV   r5   rs       r   re   zFreeGroupElement.__getitem__  sN    

Q;;;;Ay));;!R{++r   c                    t        |      dk7  r
t               | j                  j                  |j                  d         S )NrL   r   )r6   r.   r   rd   rk   s     r   rd   zFreeGroupElement.index  s5    s8q=,  ''(:;;r   c                    | j                   }| j                  }|D cg c]7  }|j                  r|j                  |dff      n|j                  | dff      9 c}S c c}w )z	
        rL   r   r   )rR   r5   r   rO   s       r   letter_form_elmz FreeGroupElement.letter_form_elm  sf     

:;=36 ,/==c!WJ'[[C4)./ = 	= =s   <Ac                >    t        t        | j                              S )zKThis is called the External Representation of ``FreeGroupElement``
        r   rY   s    r   ext_repzFreeGroupElement.ext_rep  s     WT__-..r   c                |    |j                   d   d   t        | j                   D cg c]  }|d   	 c}      v S c c}w )Nr   )r   r   )rR   rl   r   s      r   rW   zFreeGroupElement.__contains__  s6    ~~a #uDOO-Lqad-L'MMM-Ls   9
c                   | j                   ryd}| j                  }t        t        |            D ]  }|t        |      dz
  k(  rJ||   d   dk(  r|t	        ||   d         z  }4|t	        ||   d         dz   t	        ||   d         z   z  }^||   d   dk(  r|t	        ||   d         dz   z  }|t	        ||   d         dz   t	        ||   d         z   dz   z  } |S )Nz
<identity> rL   r   z***)r   r   ranger6   r$   )rR   ra   r   rV   s       r   rb   zFreeGroupElement.__str__  s$   __
s:' 	GAC
Oa''a=#q(JqM!$4 55HJqM!$4 5$(!)+.z!}Q/?+@!A AH a=#q(JqM!$4 5 ;;HJqM!$4 5$(!)+.z!}Q/?+@!ACF!G GH	G r   c                    t        |      }| j                  j                  }|dk(  r|S |dk  r| }| j                         }n| }	 |dz  r||z  }|dz  }|s	 |S ||z  })Nr      rL   )r   r5   rr   inverse)rR   nresultxs       r   __pow__zFreeGroupElement.__pow__  s{    1I$$6Mq5AAA1u!!GA FA r   c                P   | j                   }t        ||j                        st        d      | j                  r|S |j                  r| S t        | j                  |j                  z         }t        |t        | j                        dz
         |j                  t        |            S )aU  Returns the product of elements belonging to the same ``FreeGroup``.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, x, y, z = free_group("x y z")
        >>> x*y**2*y**-4
        x*y**-2
        >>> z*y**-2
        z*y**-2
        >>> x**2*y*y**-1*x**-2
        <identity>

        ;only FreeGroup elements of same FreeGroup can be multipliedrL   )
r5   r#   r?   	TypeErrorr   listr   zero_mul_simpr6   r   )rR   rh   r5   r   s       r   __mul__zFreeGroupElement.__mul__  s      

%- $ % %LK5#3#334aT__-12{{58$$r   c                    | j                   }t        ||j                        st        d      | |j	                         z  S Nr   r5   r#   r?   r   r   rR   rh   r5   s      r   __truediv__zFreeGroupElement.__truediv__  s<    

%- $ % %U]]_%%r   c                    | j                   }t        ||j                        st        d      || j	                         z  S r   r   r   s      r   __rtruediv__zFreeGroupElement.__rtruediv__  s<    

%- $ % %dlln%%r   c                    t         S r"   )NotImplementedrg   s     r   __add__zFreeGroupElement.__add__%  s    r   c                    | j                   }t        | j                  ddd   D cg c]
  \  }}|| f c}}      }|j                  |      S c c}}w )a&  
        Returns the inverse of a ``FreeGroupElement`` element

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, x, y, z = free_group("x y z")
        >>> x.inverse()
        x**-1
        >>> (x*y).inverse()
        y**-1*x**-1

        Nr   )r5   r   r   r?   )rR   r5   rV   r   r   s        r   r   zFreeGroupElement.inverse(  sL     

ttt'<=tq!Ar7=>{{1~ >s   A
c                Z    | j                   rt        j                  S t        j                  S )zFind the order of a ``FreeGroupElement``.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, x, y = free_group("x y")
        >>> (x**2*y*y**-1*x**-2).order()
        1

        )r   r   rn   ro   rY   s    r   rp   zFreeGroupElement.order;  s      55L::r   c                    | j                   }t        ||j                        st        d      | j	                         |j	                         z  | z  |z  S )zO
        Return the commutator of `self` and `x`: ``~x*~self*x*self``

        z@commutator of only FreeGroupElement of the same FreeGroup exists)r5   r#   r?   r.   r   r   s      r   
commutatorzFreeGroupElement.commutatorL  sP    
 

%- ' ( ( <<>%--/1$6u<<r   c                    d}| }t        |t              r2|r.d}|D ]$  }|}|j                  |||   ||      }||k7  s#d}& |r.|S |r*d}|D ]   }|}|j                  |||      }||k7  sd}" |r*|S )z
        Replace each subword from the dictionary `words` by words[subword].
        If words is a list, replace the words by the identity.

        TF_allr   )r#   dicteliminate_word)rR   wordsr   r   againr   subprevs           r   eliminate_wordsz FreeGroupElement.eliminate_wordsX  s     eT"  %CD,,S%*4QX,YCd{ $	%  
   %CD,,StW,MCd{ $	%  
r   c                   || j                   j                  }| j                  |      s||k(  r| S || k(  r|S |dz  |k(  rd}| }t        |      }	 |j	                  |      }d}|j                  d|      ||z  z  |j                  ||z   t        |            j                  ||      z  }|r|j                  ||d|      S |S # t
        $ r4 |s|cY S 	 |j	                  |dz        }d}n# t
        $ r |cY cY S w xY wY w xY w)a  
        For an associative word `self`, a subword `gen`, and an associative
        word `by` (identity by default), return the associative word obtained by
        replacing each occurrence of `gen` in `self` by `by`. If `_all = True`,
        the occurrences of `gen` that may appear after the first substitution will
        also be replaced and so on until no occurrences are found. This might not
        always terminate (e.g. `(x).eliminate_word(x, x**2, _all=True)`).

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, x, y = free_group("x y")
        >>> w = x**5*y*x**2*y**-4*x
        >>> w.eliminate_word( x, x**2 )
        x**10*y*x**4*y**-4*x**2
        >>> w.eliminate_word( x, y**-1 )
        y**-11
        >>> w.eliminate_word(x**5)
        y*x**2*y**-4*x
        >>> w.eliminate_word(x*y, y)
        x**4*y*x**2*y**-4*x

        See Also
        ========
        substituted_word

        r   FrL   r   Tr   )r5   rr   is_independentr6   subword_indexr.   subwordr   )	rR   rl   byr   r   wordlrV   ks	            r   r   zFreeGroupElement.eliminate_wordr  s)   : :$$Bs#sbyK$;I7b=DH
	""3'AA ||Aq!"a%'QqS#d)(D(S(STWY[(\\&&sBT7&KKK  	&&sBw/  	s6   C D C*)D *C:5D 9C::D ?D c                &    t        d | D              S )a^  
        For an associative word `self`, returns the number of letters in it.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, a, b = free_group("a b")
        >>> w = a**5*b*a**2*b**-4*a
        >>> len(w)
        13
        >>> len(a**17)
        17
        >>> len(w**0)
        0

        c              3  8   K   | ]  \  }}t        |        y wr"   abs)r&   rV   r   s      r   r(   z+FreeGroupElement.__len__.<locals>.<genexpr>  s     -fq!3q6-s   )sumrY   s    r   r]   zFreeGroupElement.__len__  s    $ ----r   c                t    | j                   }t        ||j                        syt        j	                  | |      S )a  
        Two  associative words are equal if they are words over the
        same alphabet and if they are sequences of the same letters.
        This is equivalent to saying that the external representations
        of the words are equal.
        There is no "universal" empty word, every alphabet has its own
        empty word.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, swapnil0, swapnil1 = free_group("swapnil0 swapnil1")
        >>> f
        <free group on the generators (swapnil0, swapnil1)>
        >>> g, swap0, swap1 = free_group("swap0 swap1")
        >>> g
        <free group on the generators (swap0, swap1)>

        >>> swapnil0 == swapnil1
        False
        >>> swapnil0*swapnil1 == swapnil1/swapnil1*swapnil0*swapnil1
        True
        >>> swapnil0*swapnil1 == swapnil1*swapnil0
        False
        >>> swapnil1**0 == swap0**0
        False

        F)r5   r#   r?   r   ri   r   s      r   ri   zFreeGroupElement.__eq__  s/    < 

%-||D%((r   c                   | j                   }t        ||j                        st        d      t	        |       }t	        |      }||k  ry||kD  ryt        |      D ]  }| |   j                  d   }||   j                  d   }|j                  j                  |d         }|j                  j                  |d         }	||	k  r y||	kD  r y|d   |d   k  r y|d   |d   kD  s y y)a,  
        The  ordering  of  associative  words is defined by length and
        lexicography (this ordering is called short-lex ordering), that
        is, shorter words are smaller than longer words, and words of the
        same length are compared w.r.t. the lexicographical ordering induced
        by the ordering of generators. Generators  are  sorted  according
        to the order in which they were created. If the generators are
        invertible then each generator `g` is larger than its inverse `g^{-1}`,
        and `g^{-1}` is larger than every generator that is smaller than `g`.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, a, b = free_group("a b")
        >>> b < a
        False
        >>> a < a.inverse()
        False

        9only FreeGroup elements of same FreeGroup can be comparedTFr   rL   )	r5   r#   r?   r   r6   r   r   r   rd   )
rR   rh   r5   r   mrV   abpqs
             r   __lt__zFreeGroupElement.__lt__  s    , 

%- + , ,IJq5Uq 	AQ""1%Aa##A&A##AaD)A##AaD)A1uQ1!1!	 r   c                    | |k(  xs | |k  S r"   r   rg   s     r   __le__zFreeGroupElement.__le__  s    -.r   c                h    | j                   }t        ||j                        st        d      | |k   S )a  

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, x, y, z = free_group("x y z")
        >>> y**2 > x**2
        True
        >>> y*z > z*y
        False
        >>> x > x.inverse()
        True

        r   )r5   r#   r?   r   r   s      r   __gt__zFreeGroupElement.__gt__  s:      

%- + , ,5=  r   c                    | |k   S r"   r   rg   s     r   __ge__zFreeGroupElement.__ge__-  s    %<r   c                    t        |      dk7  rt        d      |j                  d   d   t        fd| j                  D              z  S )a  
        For an associative word `self` and a generator or inverse of generator
        `gen`, ``exponent_sum`` returns the number of times `gen` appears in
        `self` minus the number of times its inverse appears in `self`. If
        neither `gen` nor its inverse occur in `self` then 0 is returned.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> F, x, y = free_group("x, y")
        >>> w = x**2*y**3
        >>> w.exponent_sum(x)
        2
        >>> w.exponent_sum(x**-1)
        -2
        >>> w = x**2*y**4*x**-3
        >>> w.exponent_sum(x)
        -1

        See Also
        ========

        generator_count

        rL   z1gen must be a generator or inverse of a generatorr   c              3  @   K   | ]  }|d    d    k(  s|d     ywr   rL   Nr   r&   rV   r'   s     r   r(   z0FreeGroupElement.exponent_sum.<locals>.<genexpr>N  s#     F11!Fs   
)r6   r.   r   r   rR   rl   r'   s     @r   exponent_sumzFreeGroupElement.exponent_sum0  sH    6 s8q=PQQNN1tCFdooFFFFr   c                    t        |      dk7  s|j                  d   d   dk  rt        d      |j                  d   d   t        fd| j                  D              z  S )a  
        For an associative word `self` and a generator `gen`,
        ``generator_count`` returns the multiplicity of generator
        `gen` in `self`.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> F, x, y = free_group("x, y")
        >>> w = x**2*y**3
        >>> w.generator_count(x)
        2
        >>> w = x**2*y**4*x**-3
        >>> w.generator_count(x)
        5

        See Also
        ========

        exponent_sum

        rL   r   zgen must be a generatorc              3  R   K   | ]  }|d    d    k(  st        |d            ywr   r   r   s     r   r(   z3FreeGroupElement.generator_count.<locals>.<genexpr>k  s'     KaadadlAaD	Ks   '')r6   r   r.   r   r   s     @r   generator_countz FreeGroupElement.generator_countP  s]    0 s8q=CNN1-a014677NN1tCK4??KKKKr   c                   | j                   }|s!t        |d      }t        t        |       |      }|dk  s|t        |       kD  rt	        d      ||k  r|j
                  S | j                  || }t        ||      }|j                  |      S )a  
        For an associative word `self` and two positive integers `from_i` and
        `to_j`, `subword` returns the subword of `self` that begins at position
        `from_i` and ends at `to_j - 1`, indexing is done with origin 0.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, a, b = free_group("a b")
        >>> w = a**5*b*a**2*b**-4*a
        >>> w.subword(2, 6)
        a**3*b

        r   zT`from_i`, `to_j` must be positive and no greater than the length of associative word)	r5   maxminr6   r.   rr   r   letter_form_to_array_formr?   )rR   from_ito_jstrictr5   r   r   s          r   r   zFreeGroupElement.subwordm  s      

^Fs4y$'DA:D	) 5 6 66>>>!**648K2;FJ;;z**r   c                    t        |      }| j                  }|j                  }d}t        |t        |      |z
  dz         D ]  }||||z    |k(  s|} n ||S t        d      )a  
        Find the index of `word` in `self`.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, a, b = free_group("a b")
        >>> w = a**2*b*a*b**3
        >>> w.subword_index(a*b*a*b)
        1

        NrL   z'The given word is not a subword of self)r6   r   r   r.   )rR   r   startr   self_lfword_lfrd   rV   s           r   r   zFreeGroupElement.subword_index  s~     I""""uS\!^A-. 	Aq1~(	 LFGGr   c                    	 | j                  |      duS # t        $ r Y nw xY w	 | j                  |dz        duS # t        $ r Y yw xY w)a  
        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> F, x, y = free_group("x, y")
        >>> (x**4*y**-3).is_dependent(x**4*y**-2)
        True
        >>> (x**2*y**-1).is_dependent(x*y)
        False
        >>> (x*y**2*x*y**2).is_dependent(x*y**2)
        True
        >>> (x**12).is_dependent(x**-4)
        True

        See Also
        ========

        is_independent

        Nr   F)r   r.   rR   r   s     r   is_dependentzFreeGroupElement.is_dependent  s`    ,	%%d+477 			%%dBh/t;; 		s    	!!; 	AAc                &    | j                  |       S )zC

        See Also
        ========

        is_dependent

        )r   r   s     r   r   zFreeGroupElement.is_independent  s     $$T***r   c                    | j                   }| j                  D ch c]  }|j                  |d   dff       }}|S c c}w )a  
        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> F, x, y, z = free_group("x, y, z")
        >>> (x**2*y**-1).contains_generators()
        {x, y}
        >>> (x**3*z).contains_generators()
        {x, z}

        r   rL   )r5   r   r?   )rR   r5   syllablerN   s       r   contains_generatorsz$FreeGroupElement.contains_generators  sD     

AEQXhqk1-/0QQ Rs   =c                2   | j                   }t        |       }| j                  }t        ||z        }||k\  r|||z  z  }|||z  z  }||z
  }||| }t        ||z        dz
  }	|||	z  |d ||z
  |z   ||	z  z
   z   z  }t	        ||      }|j                  |      S )NrL   )r5   r6   r   intr   r?   )
rR   r   r   r5   r   r   period1diffr   period2s
             r   cyclic_subwordzFreeGroupElement.cyclic_subword  s    

I&&fQh-Q;aiFAgIDf}64(d1f+/G#k2J46&=73J&KKK(u5{{4  r   c           
         t        t        |             D ch c]   }| j                  ||t        |       z         " c}S c c}w )a  Returns a words which are cyclic to the word `self`.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> F, x, y = free_group("x, y")
        >>> w = x*y*x*y*x
        >>> w.cyclic_conjugates()
        {x*y*x**2*y, x**2*y*x*y, y*x*y*x**2, y*x**2*y*x, x*y*x*y*x}
        >>> s = x*y*x**2*y*x
        >>> s.cyclic_conjugates()
        {x**2*y*x**2*y, y*x**2*y*x**2, x*y*x**2*y*x}

        References
        ==========

        .. [1] https://planetmath.org/cyclicpermutation

        )r   r6   r  rR   rV   s     r   cyclic_conjugatesz"FreeGroupElement.cyclic_conjugates  s7    * >C3t9=MN##AqT{3NNNs   %?c                j   t        |       }t        |      }||k7  ry| j                         }|j                         }|j                  }|j                  }dj                  t	        t
        |            }dj                  t	        t
        |            }	t        |      t        |	      k7  ry||	dz   |	z   v S )a  
        Checks whether words ``self``, ``w`` are cyclic conjugates.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> F, x, y = free_group("x, y")
        >>> w1 = x**2*y**5
        >>> w2 = x*y**5*x
        >>> w1.is_cyclic_conjugate(w2)
        True
        >>> w3 = x**-1*y**5*x**-1
        >>> w3.is_cyclic_conjugate(w2)
        False

        F )r6   identity_cyclic_reductionr   joinmapr$   )
rR   wl1l2w1w2letter1letter2str1str2s
             r   is_cyclic_conjugatez$FreeGroupElement.is_cyclic_conjugate  s    $ YV8++-((*....xxC)*xxC)*t9D	!tczD(((r   c                ,    t        | j                        S )a5  Returns the number of syllables of the associative word `self`.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, swapnil0, swapnil1 = free_group("swapnil0 swapnil1")
        >>> (swapnil1**3*swapnil0*swapnil1**-1).number_syllables()
        3

        )r6   r   rY   s    r   number_syllablesz!FreeGroupElement.number_syllables(  s     4??##r   c                &    | j                   |   d   S )a<  
        Returns the exponent of the `i`-th syllable of the associative word
        `self`.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, a, b = free_group("a b")
        >>> w = a**5*b*a**2*b**-4*a
        >>> w.exponent_syllable( 2 )
        2

        rL   r   r
  s     r   exponent_syllablez"FreeGroupElement.exponent_syllable6       q!!$$r   c                &    | j                   |   d   S )a[  
        Returns the symbol of the generator that is involved in the
        i-th syllable of the associative word `self`.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, a, b = free_group("a b")
        >>> w = a**5*b*a**2*b**-4*a
        >>> w.generator_syllable( 3 )
        b

        r   r   r
  s     r   generator_syllablez#FreeGroupElement.generator_syllableG  r  r   c                    t        |t              rt        |t              st        d      | j                  }||k  r|j                  S t        | j                  ||       }|j                  |      S )a  
        `sub_syllables` returns the subword of the associative word `self` that
        consists of syllables from positions `from_to` to `to_j`, where
        `from_to` and `to_j` must be positive integers and indexing is done
        with origin 0.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> f, a, b = free_group("a, b")
        >>> w = a**5*b*a**2*b**-4*a
        >>> w.sub_syllables(1, 2)
        b
        >>> w.sub_syllables(3, 3)
        <identity>

        z!both arguments should be integers)r#   r  r.   r5   rr   r   r   r?   )rR   r   r   r5   r   s        r   sub_syllableszFreeGroupElement.sub_syllablesX  s`    & &#&js.C@AA

6>>>!doofd34A;;q>!r   c                   t        |       }||k\  s
||kD  s||kD  rt        d      |dk(  r||k(  r|S |dk(  r|| j                  ||      z  S ||k(  r| j                  d|      |z  S | j                  d|      |z  | j                  ||      z  S )a  
        Returns the associative word obtained by replacing the subword of
        `self` that begins at position `from_i` and ends at position `to_j - 1`
        by the associative word `by`. `from_i` and `to_j` must be positive
        integers, indexing is done with origin 0. In other words,
        `w.substituted_word(w, from_i, to_j, by)` is the product of the three
        words: `w.subword(0, from_i)`, `by`, and
        `w.subword(to_j len(w))`.

        See Also
        ========

        eliminate_word

        zvalues should be within boundsr   )r6   r.   r   )rR   r   r   r   lws        r   substituted_wordz!FreeGroupElement.substituted_wordt  s      YT>Vb[D2I=>>
 Q;42:Iq[dll4,,,RZ<<6*2--<<6*2-dll4.DDDr   c                $    | sy| d   | d   dz  k7  S )a  Returns whether the word is cyclically reduced or not.
        A word is cyclically reduced if by forming the cycle of the
        word, the word is not reduced, i.e a word w = `a_1 ... a_n`
        is called cyclically reduced if `a_1 \ne a_n^{-1}`.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> F, x, y = free_group("x, y")
        >>> (x**2*y**-1*x**-1).is_cyclically_reduced()
        False
        >>> (y*x**2*y**2).is_cyclically_reduced()
        True

        Tr   r   r   rY   s    r   is_cyclically_reducedz&FreeGroupElement.is_cyclically_reduced  s!    " Aw$r(B,&&r   c                   | j                         }| j                  }|j                         s|j                  d      }|j                  d      }||z   }|dk(  r!|j                  d|j                         dz
   }n8|j                  d      ||z   ff|j                  d|j                         dz
   z   }|j                  |      }|j                         s|S )a  Return a unique cyclically reduced version of the word.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> F, x, y = free_group("x, y")
        >>> (x**2*y**2*x**-1).identity_cyclic_reduction()
        x*y**2
        >>> (x**-3*y**-1*x**5).identity_cyclic_reduction()
        x**2*y**-1

        References
        ==========

        .. [1] https://planetmath.org/cyclicallyreduced

        r   r   rL   )r   r5   r(  r  r   r  r!  r?   )rR   r   r5   exp1exp2r   reps          r   r  z*FreeGroupElement.identity_cyclic_reduction  s    & yy{

,,.))!,D))"-DtAAvooa)>)>)@1)DE//2D4K@B4+@+@+BQ+FGH;;s#D ,,. r   c                   | j                         }| j                  j                  }|j                         st	        |j                  d            }t	        |j                  d            }t        ||      }|d   t	        |      z  }|d   t	        |      z  }|dz  |z  |dz  z  }||z  }|j                         s|r||fS |S )a/  Return a cyclically reduced version of the word. Unlike
        `identity_cyclic_reduction`, this will not cyclically permute
        the reduced word - just remove the "unreduced" bits on either
        side of it. Compare the examples with those of
        `identity_cyclic_reduction`.

        When `removed` is `True`, return a tuple `(word, r)` where
        self `r` is such that before the reduction the word was either
        `r*word*r**-1`.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> F, x, y = free_group("x, y")
        >>> (x**2*y**2*x**-1).cyclic_reduction()
        x*y**2
        >>> (x**-3*y**-1*x**5).cyclic_reduction()
        y**-1*x**2
        >>> (x**-3*y**-1*x**5).cyclic_reduction(removed=True)
        (y**-1*x**2, x**-3)

        r   r   )r   r5   rr   r(  r   r  r   )	rR   removedr   ry   r*  r+  expr   ends	            r   cyclic_reductionz!FreeGroupElement.cyclic_reduction  s    0 yy{JJ,,.t--a01Dt--b12DdD/CGSX%Er(CH$C"9T>#r')D%A ,,. 7Nr   c                   | j                   ryt        |      }|dk(  r/| j                         }||v xs |dz  |v }t        |      dk(  xr |S | j                  d      \  }}|j                   s,|j                  d      \  }}||k(  r|j	                  |      S yt        |       |k  st        |       |z  ry| j                  d|      }||k(  s|dz  |k(  r,| j                  |t        |             }	|	j	                  |      S y)a;  
        Check if `self == other**n` for some integer n.

        Examples
        ========

        >>> from sympy.combinatorics import free_group
        >>> F, x, y = free_group("x, y")
        >>> ((x*y)**2).power_of(x*y)
        True
        >>> (x**-3*y**-2*x**3).power_of(x**-3*y*x**3)
        True

        TrL   r   )r.  Fr   )r   r6   r  r1  power_ofr   )
rR   rh   r   rN   r'   reducedr1r2prefixrests
             r   r3  zFreeGroupElement.power_of  s
    J6++-D2d!2At9>'a'
 ++D+9~~..t.<IE2Rx''..t9q=CIMa#U?fbjE1<<3t9-D==''r   )FT)NFT)T)r   )F)7r8   r}   r~   r   is_assoc_wordr   r<   rZ   r   r   r   r   r   re   rd   r   r   rW   rb   r   r   r   r   r   r   r   rp   r   r   r   r]   ri   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r  r  r!  r#  r&  r(  r  r1  r3  r   r   r   r,   r,   V  sa   
 M$ E    B 3 38,<
 = = / /
N* H&%8&&&"
=49v.(!)F.`/!, G@L:+<H6>	+"!O.)B$%"%""8E@'*B$L*r   r,   c                @   t        | dd       }g }d}|j                  }t        t        |            D ]  }|t        |      dz
  k(  r||   ||dz
     k(  r>||    |v r|j	                  ||    | f       |c S |j	                  ||   |f       |c S ||    |v r|j	                  ||    df       |c S |j	                  ||   df       |c S ||   ||dz      k(  r|dz  }||    |v r|j	                  ||    | f       n|j	                  ||   |f       d} y)a`  
    This method converts a list given with possible repetitions of elements in
    it. It returns a new list such that repetitions of consecutive elements is
    removed and replace with a tuple element of size two such that the first
    index contains `value` and the second index contains the number of
    consecutive repetitions of `value`.

    NrL   r   )r   r   r   r6   rM   )r   r5   r   	new_arrayr   r   rV   s          r   r   r     s]    	Z]AI	AmmG3q6] A
?tqQxqTEg%$$qteaR[1  $$adAY/ 	 qTEg%$$qteR[1  $$adAY/qTQq1uXFA1'!  1Q4%!-  !A$+A)r   c                0   |dk\  r|t        |       dz
  k  r| |   d   | |dz      d   k(  rj| |   d   | |dz      d   z   }| |   d   }||f| |<   | |dz   = | |   d   dk(  r| |= |dz  }|dk\  r(|t        |       dz
  k  r| |   d   | |dz      d   k(  rgyyyyyy)z"Used to combine two reduced words.r   rL   N)r6   )r   rd   r/  bases       r   r   r   A  s    
!)A
*qx{a	l1o/MhqkAeaiLO+x{#;%eaiLU8A;!%QJE !)A
*qx{a	l1o/M*)/M*)r   N)"
__future__r   
sympy.corer   sympy.core.exprr   sympy.core.symbolr   r   r+   sympy.core.sympifyr   sympy.printing.defaultsr	   sympy.utilitiesr
   sympy.utilities.iterablesr   r   sympy.utilities.magicr   sympy.utilities.miscr   r   r   r   r0   r1   r   r   r   r,   r   r   r   r   r   <module>rH     s    "    9 * 3 " : ) ' : :0 1 10  4+* +- ' ,\ \HD{OU DN!H	r   