a
    Sic)                     @   s   d Z ddlZddlmZ ddlZg dZdZdd Zdd	 Z	d
d Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd ZdS )zC
A functionally equivalent parser of the numpy.einsum input parser
    N)OrderedDict)
is_valid_einsum_charhas_valid_einsum_chars_only
get_symbolgen_unused_symbolsconvert_to_valid_einsum_charsalpha_canonicalizefind_output_strfind_output_shapepossibly_convert_to_numpyparse_einsum_input4abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZc                 C   s   | t v p| dv S )u   Check if the character ``x`` is valid for numpy einsum.

    Examples
    --------
    >>> is_valid_einsum_char("a")
    True

    >>> is_valid_einsum_char("Ǵ")
    False
    z,->.)_einsum_symbols_basex r   M/var/www/html/django/DPS/env/lib/python3.9/site-packages/opt_einsum/parser.pyr      s    r   c                 C   s   t tt| S )u   Check if ``einsum_str`` contains only valid characters for numpy einsum.

    Examples
    --------
    >>> has_valid_einsum_chars_only("abAZ")
    True

    >>> has_valid_einsum_chars_only("Över")
    False
    )allmapr   )
einsum_strr   r   r   r   #   s    r   c                 C   s   | dk rt |  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)``.

    Examples
    --------
    >>> get_symbol(2)
    'c'

    >>> get_symbol(200)
    'Ŕ'

    >>> get_symbol(20000)
    '京'
    4      )r   chr)ir   r   r   r   1   s    r   c                 c   s>   d }}||k r:t |}|d7 }|| v r*q|V  |d7 }qdS )zGenerate ``n`` symbols that are not already in ``used``.

    Examples
    --------
    >>> list(oe.parser.gen_unused_symbols("abd", 2))
    ['c', 'e']
    r      Nr   )usednr   cntsr   r   r   r   E   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   s   i | ]\}}|t |qS r   r   ).0r   r   r   r   r   
<dictcomp>b       z1convert_to_valid_einsum_chars.<locals>.<dictcomp> c                 3   s   | ]}  ||V  qd S Ngetr    r   replacerr   r   	<genexpr>c   r"   z0convert_to_valid_einsum_chars.<locals>.<genexpr>)sortedset	enumeratejoin)r   symbolsr   r(   r   r   W   s    
r   c                    sJ   t   | 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   s   | ]}  ||V  qd S r$   r%   r'   renamer   r   r*   w   r"   z%alpha_canonicalize.<locals>.<genexpr>)r   r   lenr.   )equationnamer   r0   r   r   f   s    r   c                    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   r*      r"   z"find_output_str.<locals>.<genexpr>)replacer.   r+   r,   )
subscriptsr   r7   r   r	   z   s    r	   c                    s   t  fdd|D S )aO  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   s4   | ], 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   r*      r"   z.find_output_shape.<locals>.<genexpr>.<genexpr>c                    s   g | ]}|  qS r   )findr'   cr   r   
<listcomp>   r"   z/find_output_shape.<locals>.<genexpr>.<listcomp>N)maxzip)r    inputsshapesr>   r   r*      s   z$find_output_shape.<locals>.<genexpr>)tuple)rD   rE   outputr   rC   r   r
      s    r
   c                 C   s   t | dst| S | S dS )aT  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>
    r;   N)hasattrnp
asanyarrayr   r   r   r   r      s    

r   c                 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)Zold_sub
symbol_mapZnew_subr   r   r   r   convert_subscripts   s    

rN   c                    s   t | }g }g }tt| d D ]$}||d ||d q t|rV|d nd}dd |D } z4ttj|}|	t
 dd tt|D  W n ty   td	Y n0 d
 fdd|D }|dur|d7 }|t| 7 }|| fS )z:Convert 'interleaved' input to standard einsum input.
       r   Nc                 S   s   g | ]}t |qS r   r   r'   r   r   r   r@      r"   z-convert_interleaved_input.<locals>.<listcomp>c                 S   s   i | ]\}}|t |qS 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).r5   c                 3   s   | ]}t | V  qd S r$   )rN   )r    subrM   r   r   r*      r"   z,convert_interleaved_input.<locals>.<genexpr>->)listranger2   appendpopr,   	itertoolschainfrom_iterablediscardrL   r-   r+   	TypeErrorr.   rN   )operandstmp_operandsoperand_listsubscript_listpoutput_listZ
symbol_setr:   r   rU   r   convert_interleaved_input   s&    
rf   c                 C   s  t | dkrtdt| d trJ| d dd}dd | dd D } nt| \}} d	|v sfd
|v r|d	dkp|d
dk}|s|ddkrtdd|v rd|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sT|ddkr\td| |
 jdkrrd}n t	t | |
 jdt |d  }||kr|}|dk rtdn6|dkr|dd||
< n|d|| d ||
< q"d|}|dkrd}n|| d }|	r2|d|d| 7 }n2t|}dtt|t| }|d| | 7 }d|v r~|
d\}}n|t| }}|D ]}||vrtd|qt |
dt | krtd||| fS )af  
    A reproduction of einsum c side einsum parsing in python.

    Returns
    -------
    input_strings : str
        Parsed input strings
    output_string : str
        Parsed output string
    operands : list of array_like
        The operands to use in the numpy contraction

    Examples
    --------
    The operand list is simplified to reduce printing:

    >>> 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   g | ]}t |qS r   rQ   r'   r   r   r   r@     r"   z&parse_einsum_input.<locals>.<listcomp>r   N->rV   z%Subscripts can only contain one '->'..r5   c                 s   s   | ]}t |jV  qd S r$   )r2   r;   r'   r   r   r   r*   #  r"   z%parse_einsum_input.<locals>.<genexpr>TF   rK   zInvalid Ellipses.r   zEllipses lengths do not match.z1Output character '{}' did not appear in the inputzDNumber of einsum subscripts must be equal to the number of operands.)r2   
ValueError
isinstancestrr9   rf   r6   r.   r   rA   splitr-   r;   r	   r+   r,   format)r`   r:   invalidr   ellipse_indslongest	input_tmp
output_subsplit_subscriptsout_subnumrT   ellipse_countout_ellipseoutput_subscriptnormal_indsinput_subscriptscharr   r   r   r      sh    




  







r   )__doc__r[   collectionsr   numpyrI   __all__r   r   r   r   r   r   r   r	   r
   r   rN   rf   r   r   r   r   r   <module>   s"   %