o
    e                     @   s   d Z ddlmZ ddlZddlmZ g dZdZe	g dZ
d	d
 eee
D ZdddZdd Zdd Zdd ZdddZdS )z:
Contains helper functions for opt_einsum testing scripts
    )OrderedDictN   )
get_symbol)build_viewscompute_size_by_dictfind_contraction
flop_countZabcdefghijklmopqABC)            r   r
   r	      r   r   r
   r	   r      r   r
   r	   r
   r   c                 C   s   i | ]\}}||qS  r   ).0csr   r   BD:\Projects\ConvertPro\env\Lib\site-packages\opt_einsum/helpers.py
<dictcomp>   s    r   c                    sV    du rt  g }| dd d}|D ]} fdd|D }|tjj|  q|S )a  
    Builds random numpy arrays for testing.

    Parameters
    ----------
    string : list of str
        List of tensor strings to build
    dimension_dict : dictionary
        Dictionary of index _sizes

    Returns
    -------
    ret : list of np.ndarry's
        The resulting views.

    Examples
    --------
    >>> view = build_views(['abbc'], {'a': 2, 'b':3, 'c':5})
    >>> view[0].shape
    (2, 3, 3, 5)

    Nz->r   ,c                    s   g | ]} | qS r   r   )r   xdimension_dictr   r   
<listcomp>0   s    zbuild_views.<locals>.<listcomp>)_default_dim_dictsplitappendnprandomZrand)stringr   ZviewsZtermstermdimsr   r   r   r      s   r   c                 C   s   d}| D ]}||| 9 }q|S )a  
    Computes the product of the elements in indices based on the dictionary
    idx_dict.

    Parameters
    ----------
    indices : iterable
        Indices to base the product on.
    idx_dict : dictionary
        Dictionary of index _sizes

    Returns
    -------
    ret : int
        The resulting product.

    Examples
    --------
    >>> compute_size_by_dict('abbc', {'a': 2, 'b':3, 'c':5})
    90

    r   r   )indicesZidx_dictretir   r   r   r   5   s   r   c                    s\   t |  fddt| ddD }tj| }|j  }||@ }|| } | | ||fS )a  
    Finds the contraction for a given set of input and output sets.

    Parameters
    ----------
    positions : iterable
        Integer positions of terms used in the contraction.
    input_sets : list
        List of sets that represent the lhs side of the einsum subscript
    output_set : set
        Set that represents the rhs side of the overall einsum subscript

    Returns
    -------
    new_result : set
        The indices of the resulting contraction
    remaining : list
        List of sets that have not been contracted, the new set is appended to
        the end of this list
    idx_removed : set
        Indices removed from the entire contraction
    idx_contraction : set
        The indices used in the current contraction

    Examples
    --------

    # A simple dot product test case
    >>> pos = (0, 1)
    >>> isets = [set('ab'), set('bc')]
    >>> oset = set('ac')
    >>> find_contraction(pos, isets, oset)
    ({'a', 'c'}, [{'a', 'c'}], {'b'}, {'a', 'b', 'c'})

    # A more complex case with additional terms in the contraction
    >>> pos = (0, 2)
    >>> isets = [set('abd'), set('ac'), set('bdc')]
    >>> oset = set('ac')
    >>> find_contraction(pos, isets, oset)
    ({'a', 'c'}, [{'a', 'c'}, {'a', 'c'}], {'b', 'd'}, {'a', 'b', 'c', 'd'})
    c                 3   s    | ]}  |V  qd S N)popr   r$   	remainingr   r   	<genexpr>~   s    z#find_contraction.<locals>.<genexpr>T)reverse)listsortedsetunionr   )Z	positionsZ
input_setsZ
output_setinputsZidx_contractZ
idx_remainZ
new_resultZidx_removedr   r(   r   r   R   s   +


r   c                 C   s,   t | |}td|d }|r|d7 }|| S )a  
    Computes the number of FLOPS in the contraction.

    Parameters
    ----------
    idx_contraction : iterable
        The indices involved in the contraction
    inner : bool
        Does this contraction require an inner product?
    num_terms : int
        The number of terms in a contraction
    size_dictionary : dict
        The size of each of the indices in idx_contraction

    Returns
    -------
    flop_count : int
        The total number of FLOPS required for the contraction.

    Examples
    --------

    >>> flop_count('abc', False, 1, {'a': 2, 'b':3, 'c':5})
    90

    >>> flop_count('abc', True, 2, {'a': 2, 'b':3, 'c':5})
    270

    r   )r   max)Zidx_contractioninnerZ	num_termsZsize_dictionaryZoverall_sizeZ	op_factorr   r   r   r      s
   
r   r	   	   Fc                    s|  |dur
t j| | | d  }dd t| D }	g t fddt|D fdd}
tt jt|
 D ]3\}}|| k rO|	|  |7  < q>t jd	| }||	| v rit jd	| }||	| v s\|	|  |7  < q>|rt	|}t j d
 |< t| D ]
}|	|  |7  < q|7 d
t jdd
|	}fdd|	D }||f}|r|f7 }|S )a  Generate a random contraction and shapes.

    Parameters
    ----------
    n : int
        Number of array arguments.
    reg : int
        'Regularity' of the contraction graph. This essentially determines how
        many indices each tensor shares with others on average.
    n_out : int, optional
        Number of output indices (i.e. the number of non-contracted indices).
        Defaults to 0, i.e., a contraction resulting in a scalar.
    d_min : int, optional
        Minimum dimension size.
    d_max : int, optional
        Maximum dimension size.
    seed: int, optional
        If not None, seed numpy's random generator with this.
    global_dim : bool, optional
        Add a global, 'broadcast', dimension to every operand.
    return_size_dict : bool, optional
        Return the mapping of indices to sizes.

    Returns
    -------
    eq : str
        The equation string.
    shapes : list[tuple[int]]
        The array shapes.
    size_dict : dict[str, int]
        The dict of index sizes, only returned if ``return_size_dict=True``.

    Examples
    --------
    >>> eq, shapes = rand_equation(n=10, reg=4, n_out=5, seed=42)
    >>> eq
    'oyeqn,tmaq,skpo,vg,hxui,n,fwxmr,hitplcj,kudlgfv,rywjsb->cebda'

    >>> shapes
    [(9, 5, 4, 5, 4),
     (4, 4, 8, 5),
     (9, 4, 6, 9),
     (6, 6),
     (6, 9, 7, 8),
     (4,),
     (9, 3, 9, 4, 9),
     (6, 8, 4, 6, 8, 6, 3),
     (4, 7, 8, 8, 6, 9, 6),
     (9, 5, 3, 3, 9, 5)]
    Nr	   c                 S   s   g | ]}d qS ) r   )r   _r   r   r   r      s    z!rand_equation.<locals>.<listcomp>c                 3   s*    | ]}t |tj d  fV  qdS )r   N)r   r   r   randintr'   )d_maxd_minr   r   r*      s   ( z rand_equation.<locals>.<genexpr>c                  3   s>    t D ]\} }|  k r| |V  q|V  |V  qd S r%   )	enumerater   )r$   ix)n_outoutput	size_dictr   r   gen   s   
zrand_equation.<locals>.genr   r   r4   z{}->{}r   c                    s"   g | ]}t  fd d|D qS )c                 3   s    | ]} | V  qd S r%   r   )r   r:   r=   r   r   r*     s    z+rand_equation.<locals>.<listcomp>.<genexpr>)tuple)r   opr?   r   r   r     s   " )r   r   seedranger   r9   Zpermutationr,   r6   r   joinformat)nregr;   r8   r7   rB   Z
global_dimZreturn_size_dictZnum_indsr0   r>   r$   r:   whereZgdimeqZshapesr#   r   )r7   r8   r;   r<   r=   r   rand_equation   s8   4
rJ   r%   )r   r	   r3   NFF)__doc__collectionsr   numpyr   parserr   __all__Z_valid_charsarrayZ_sizeszipr   r   r   r   r   rJ   r   r   r   r   <module>   s    
#7'