o
    2h3                     @   s  d Z ddlZddlmZmZmZmZmZmZ ddl	m
Z
mZ g dZdZdedefd	d
ZdedefddZdedefddZdededee fddZdedefddZdedefddZdedefddZdee dee dedefd d!ZeeeeeefZdedefd"d#Zdedefd$d%Zd&ee d'eeef defd(d)Zd*ee deeeed+f f fd,d-Z d1d*ededeeeee
 f fd/d0Z!dS )2zBA functionally equivalent parser of the numpy.einsum input parser.    N)AnyDictIteratorListSequenceTuple)	ArrayTypeTensorShapeType)is_valid_einsum_charhas_valid_einsum_chars_only
get_symbol	get_shapegen_unused_symbolsconvert_to_valid_einsum_charsalpha_canonicalizefind_output_strfind_output_shapepossibly_convert_to_numpyparse_einsum_input4abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZxreturnc                 C   s   | t v p| dv S )u   Check if the character ``x`` is valid for numpy einsum.

    **Examples:**

    ```python
    is_valid_einsum_char("a")
    #> True

    is_valid_einsum_char("Ǵ")
    #> False
    ```
    z,->.)_einsum_symbols_base)r    r   L/var/www/html/chatgem/venv/lib/python3.10/site-packages/opt_einsum/parser.pyr
      s   r
   
einsum_strc                 C   s   t tt| S )u   Check if ``einsum_str`` contains only valid characters for numpy einsum.

    **Examples:**

    ```python
    has_valid_einsum_chars_only("abAZ")
    #> True

    has_valid_einsum_chars_only("Över")
    #> False
    ```
    )allmapr
   )r   r   r   r   r   )   s   r   ic                 C   s0   | dk rt |  S | dkrt| d S t| d S )u<  Get the symbol corresponding to int ``i`` - runs through the usual 52
    letters before resorting to unicode characters, starting at ``chr(192)`` and skipping surrogates.

    **Examples:**

    ```python
    get_symbol(2)
    #> 'c'

    get_symbol(200)
    #> 'Ŕ'

    get_symbol(20000)
    #> '京'
    ```
    4   i   i      )r   chr)r   r   r   r   r   9   s
   r   usednc                 c   sJ    d }}||k r#t |}|d7 }|| v rq|V  |d7 }||k s	dS dS )zGenerate ``n`` symbols that are not already in ``used``.

    **Examples:**
    ```python
    list(oe.parser.gen_unused_symbols("abd", 2))
    #> ['c', 'e']
    ```
    r      Nr   )r"   r#   r   cntsr   r   r   r   S   s   	r   c                    s>   t t| td }dd t|D  d fdd| D S )u  Convert the str ``einsum_str`` to contain only the alphabetic characters
    valid for numpy einsum. If there are too many symbols, let the backend
    throw an error.

    Examples:
    --------
    >>> oe.parser.convert_to_valid_einsum_chars("Ĥěļļö")
    'cbdda'
    z,->c                 S      i | ]	\}}|t |qS r   r%   ).0r   r   r   r   r   
<dictcomp>q       z1convert_to_valid_einsum_chars.<locals>.<dictcomp> c                 3       | ]	}  ||V  qd S Ngetr)   r   replacerr   r   	<genexpr>r       z0convert_to_valid_einsum_chars.<locals>.<genexpr>)sortedset	enumeratejoin)r   symbolsr   r2   r   r   f   s   
r   equationc                    sH   i  | D ]}|dv rq| vrt t  |< qd fdd| D S )u   Alpha convert an equation in an order-independent canonical way.

    Examples:
    --------
    >>> oe.parser.alpha_canonicalize("dcba")
    'abcd'

    >>> oe.parser.alpha_canonicalize("Ĥěļļö")
    'abccd'
    z.,->r,   c                 3   r-   r.   r/   r1   renamer   r   r4      r5   z%alpha_canonicalize.<locals>.<genexpr>)r   lenr9   )r;   namer   r<   r   r   u   s   r   
subscriptsc                    s,   |  dd d fddtt D S )aU  Find the output string for the inputs ``subscripts`` under canonical einstein summation rules.
    That is, repeated indices are summed over by default.

    Examples:
    --------
    >>> oe.parser.find_output_str("ab,bc")
    'ac'

    >>> oe.parser.find_output_str("a,b")
    'ab'

    >>> oe.parser.find_output_str("a,a,b,b")
    ''
    ,r,   c                 3   s"    | ]}  |d kr|V  qdS )r$   N)count)r)   r'   tmp_subscriptsr   r   r4      s     z"find_output_str.<locals>.<genexpr>)replacer9   r6   r7   )r@   r   rC   r   r      s    r   inputsshapesoutputc                    s   t  fdd|D S )aP  Find the output shape for given inputs, shapes and output string, taking
    into account broadcasting.

    Examples:
    --------
    >>> oe.parser.find_output_shape(["ab", "bc"], [(2, 3), (3, 4)], "ac")
    (2, 4)

    # Broadcasting is accounted for
    >>> oe.parser.find_output_shape(["a", "a"], [(4, ), (1, )], "a")
    (4,)
    c                 3   s6    | ] t d d t fddD D V  qdS )c                 s   s$    | ]\}}|d kr|| V  qdS )r   Nr   )r)   shapelocr   r   r   r4      s   " z.find_output_shape.<locals>.<genexpr>.<genexpr>c                    s   g | ]}|  qS r   )findr1   cr   r   
<listcomp>   s    z/find_output_shape.<locals>.<genexpr>.<listcomp>N)maxzip)r)   rF   rG   rL   r   r4      s   4 z$find_output_shape.<locals>.<genexpr>)tuple)rF   rG   rH   r   rQ   r   r      s   r   c                 C   s   t | dr| jS t| trdS t| tr9g }t| tr5t| ts5|t|  | d } t| tr5t| tr t|S td|  d)a  Get the shape of the array-like object `x`. If `x` is not array-like, raise an error.

    Array-like objects are those that have a `shape` attribute, are sequences of BaseTypes, or are BaseTypes.
    BaseTypes are defined as `bool`, `int`, `float`, `complex`, `str`, and `bytes`.
    rI   r   r   zCannot determine the shape of z5, can only determine the shape of array-like objects.)	hasattrrI   
isinstance
_BaseTypesr   appendr>   rR   
ValueError)r   rI   r   r   r   r      s   


r   c                 C   s<   t | dszddl}W n ty   tdw || S | S )aU  Convert things without a 'shape' to ndarrays, but leave everything else.

    Examples:
    --------
    >>> oe.parser.possibly_convert_to_numpy(5)
    array(5)

    >>> oe.parser.possibly_convert_to_numpy([5, 3])
    array([5, 3])

    >>> oe.parser.possibly_convert_to_numpy(np.array([5, 3]))
    array([5, 3])

    # Any class with a shape is passed through
    >>> class Shape:
    ...     def __init__(self, shape):
    ...         self.shape = shape
    ...

    >>> myshape = Shape((5, 5))
    >>> oe.parser.possibly_convert_to_numpy(myshape)
    <__main__.Shape object at 0x10f850710>
    rI   r   Nzinumpy is required to convert non-array objects to arrays. This function will be deprecated in the future.)rS   numpyModuleNotFoundError
asanyarray)r   npr   r   r   r      s   

r   old_sub
symbol_mapc                 C   s0   d}| D ]}|t u r|d7 }q||| 7 }q|S )a  Convert user custom subscripts list to subscript string according to `symbol_map`.

    Examples:
    --------
    >>>  oe.parser.convert_subscripts(['abc', 'def'], {'abc':'a', 'def':'b'})
    'ab'
    >>> oe.parser.convert_subscripts([Ellipsis, object], {object:'a'})
    '...a'
    r,   ...)Ellipsis)r\   r]   new_subr'   r   r   r   convert_subscripts   s   

ra   operands.c                    s   t | }g }g }tt| d D ]}||d ||d qt|r+|d nd}zttj|}|	t
 dd tt|D  W n tyR   tdw d fd	d
|D }|durn|d7 }|t| 7 }|t|fS )z5Convert 'interleaved' input to standard einsum input.   r   Nc                 S   r(   r   r%   )r)   idxsymbolr   r   r   r*     r+   z-convert_interleaved_input.<locals>.<dictcomp>ziFor this input type lists must contain either Ellipsis or hashable and comparable object (e.g. int, str).rA   c                 3   s    | ]}t | V  qd S r.   )ra   )r)   subr]   r   r   r4         z,convert_interleaved_input.<locals>.<genexpr>->)listranger>   rV   popr7   	itertoolschainfrom_iterablediscardr_   r8   r6   	TypeErrorr9   ra   rR   )rb   tmp_operandsoperand_listsubscript_list_output_list
symbol_setr@   r   rh   r   convert_interleaved_input   s*   
ry   Fc                 C   s6  t | dkr
tdt| d tr3| d dd}|r,tdd | dd D r,td	| dd } nt| \}} |r>| }nd
d | D }d|v sMd|v rh|ddkpZ|ddk}|sd|ddkrhtdd|v rA|dddddd}dt	|t
dd |D }d}d|v r|d\}}	|d}
d}n|d}
d}t|
D ][\}}d|v r|ddks|ddkrtd|| dkrd}nt
t || dt |d  }||kr|}|dk rtd|dkr|dd|
|< q|d|| d |
|< qd|
}|dkrd}n|| d }|r(|d|	d| 7 }nt|}dtt|t| }|d| | 7 }d|v rN|d\}}n|t|}}|D ] }||dkritd| d||vrvtd| dqWt |dt | krtdt |d dt |  d||| fS )ay  A reproduction of einsum c side einsum parsing in python.

    Parameters:
        operands: Intakes the same inputs as `contract_path`, but NOT the keyword args. The only
            supported keyword argument is:
        shapes: Whether ``parse_einsum_input`` should assume arrays (the default) or
            array shapes have been supplied.

    Returns:
        input_strings: Parsed input strings
        output_string: Parsed output string
        operands: The operands to use in the numpy contraction

    Examples:
        The operand list is simplified to reduce printing:

        ```python
        >>> a = np.random.rand(4, 4)
        >>> b = np.random.rand(4, 4, 4)
        >>> parse_einsum_input(('...a,...a->...', a, b))
        ('za,xza', 'xz', [a, b])

        >>> parse_einsum_input((a, [Ellipsis, 0], b, [Ellipsis, 0]))
        ('za,xza', 'xz', [a, b])
        ```
    r   zNo input operands r,   c                 s   s    | ]}t |d V  qdS )rI   N)rS   r)   or   r   r   r4   B  ri   z%parse_einsum_input.<locals>.<genexpr>r$   Nzwshapes is set to True but given at least one operand looks like an array (at least one operand has a shape attribute). c                 S   s   g | ]}t |qS r   )r   r{   r   r   r   rN   N  s    z&parse_einsum_input.<locals>.<listcomp>->rj   z%Subscripts can only contain one '->'..rA   c                 s   s    | ]}t |V  qd S r.   )r>   r1   r   r   r   r4   Y  s    TF   r^   zInvalid Ellipses.r   zEllipses lengths do not match.zOutput character 'z(' appeared more than once in the output.z' did not appear in the inputzNumber of einsum subscripts, z+, must be equal to the number of operands, )r>   rW   rT   strrE   anyry   rB   r9   r   rO   splitr8   r   r6   r7   )rb   rG   r@   operand_shapesinvalidr"   ellipse_indslongest	input_tmp
output_subsplit_subscriptsout_subnumrg   ellipse_countout_ellipseoutput_subscriptnormal_indsinput_subscriptscharr   r   r   r   !  s   








r   )F)"__doc__rn   typingr   r   r   r   r   r   opt_einsum.typingr   r	   __all__r   r   boolr
   r   intr   r   r   r   r   r   floatcomplexbytesrU   r   r   ra   ry   r   r   r   r   r   <module>   s(     ""%&*%