
    `i5                     8    d dl Z d Zd Zd Zd Zd Zd Zd ZdS )	    Nc                 `    t          | |          }t          d|dz
            }|r|dz  }||z  S )a  Copied from _flop_count in numpy/core/einsumfunc.py

    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

       )_compute_size_by_dictmax)idx_contractioninner	num_termssize_dictionaryoverall_size	op_factors         k/home/jaya/work/projects/VOICE-AGENT/VIET/agent-env/lib/python3.11/site-packages/cupy/linalg/_einsum_opt.py_flop_countr      sC    @ )/JJLAy1}%%I Q	)##    c                 *    d}| D ]}|||         z  }|S )a  Copied from _compute_size_by_dict in numpy/core/einsumfunc.py

    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    )indicesidx_dictretis       r   r   r   ,   s-    0 C  x{Jr   c                    t                      }|                                }g }t          |          D ])\  }}|| v r||z  }|                    |           ||z  }*||z  }||z
  }	|                    |           |||	|fS )aD  Copied from _find_contraction in numpy/core/einsumfunc.py

    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'})
    )setcopy	enumerateappend)
	positions
input_sets
output_setidx_contract
idx_remain	remainingindvalue
new_resultidx_removeds
             r   _find_contractionr%   J   s    X 55L""JI
++    
U)E!LLU###%JJl*J*,KZ   	;==r   c                    dg | fg}t          t          |           dz
            D ]}g }|D ]}|\  }}	}
t          j        t          t          |           |z
            d          D ]q}t	          ||
|          }|\  }}}}t          ||          }||k    r1|t          ||t          |          |          z   }|	|gz   }|                    |||f           r|r|}t          |d           d         }|t          t          t          |           |z
                      gz  }|c S t          |          dk    r*t          t          t          |                               gS t          |d           d         }|S )a  Copied from _optimal_path in numpy/core/einsumfunc.py

    Computes all possible pair contractions, sieves the results based
    on ``memory_limit`` and returns the lowest cost path. This algorithm
    scales factorial with respect to the elements in the list ``input_sets``.

    Parameters
    ----------
    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
    idx_dict : dictionary
        Dictionary of index sizes
    memory_limit : int
        The maximum number of elements in a temporary array

    Returns
    -------
    path : list
        The optimal contraction order within the memory limit constraint.

    Examples
    --------
    >>> isets = [set('abd'), set('ac'), set('bdc')]
    >>> oset = set('')
    >>> idx_sizes = {'a': 1, 'b':2, 'c':3, 'd':4}
    >>> _optimal_path(isets, oset, idx_sizes, 5000)
    [(0, 2), (0, 1)]
    r   r      c                     | d         S Nr   r   xs    r   <lambda>z_optimal_path.<locals>.<lambda>   s
    1Q4 r   keyc                     | d         S r)   r   r*   s    r   r,   z_optimal_path.<locals>.<lambda>   s
    1Q4 r   )
rangelen	itertoolscombinationsr%   r   r   r   mintuple)r   r   r   memory_limitfull_results	iterationiter_resultscurrcostr   r    concontr#   new_input_setsr$   r   new_size
total_costnew_pospaths                        r   _optimal_pathrC      s   @ J'(L3z??Q.//  	 ! 	K 	KD)-&D)Y -eC
OOi4O.P.PRSTT K K )iDDHLE
NK 1XFFl** "k3s88XNNO
#se+##Z.$IJJJJK&  	'LL|888;DU5Z9!<==>>??DKKK <AeC
OO,,--..|0003DKr   c                    t          | |          }|\  }}	}
}t          |          }||k    rdS fd| D             }t          |          |z
  }t          ||
t	          |                     }| |f}||z   |k    rdS || |	gS )a*  Copied from _parse_possible_contraction in numpy/core/einsumfunc.py

    Compute the cost (removed size + flops) and resultant indices for
    performing the contraction specified by ``positions``.

    Parameters
    ----------
    positions : tuple of int
        The locations of the proposed tensors to contract.
    input_sets : list of sets
        The indices found on each tensors.
    output_set : set
        The output indices of the expression.
    idx_dict : dict
        Mapping of each index to its size.
    memory_limit : int
        The total allowed size for an intermediary tensor.
    path_cost : int
        The contraction cost so far.
    naive_cost : int
        The cost of the unoptimized expression.

    Returns
    -------
    cost : (int, int)
        A tuple containing the size of any indices removed, and the flop cost.
    positions : tuple of int
        The locations of the proposed tensors to contract.
    new_input_sets : list of sets
        The resulting new list of indices if this proposed contraction is performed.

    Nc              3   D   K   | ]}t          |                   V  d S N)r   ).0pr   r   s     r   	<genexpr>z._parse_possible_contraction.<locals>.<genexpr>   sJ       5 5%& '1x! ! 5 5 5 5 5 5r   )r%   r   sumr   r1   )r   r   r   r   r6   	path_cost
naive_costcontract
idx_resultr>   r$   r   r?   	old_sizesremoved_sizer;   sorts    ` `             r   _parse_possible_contractionrR      s    F !J
CCH<D9J\ %Z::H,t5 5 5 5 5*35 5 5Iy>>H,L |[#i..(KKDM4 D 	DJ&&t )^,,r   c                    |d         }|\  }}g }| D ]\  }\  }}}	||v s||v r|	|t          ||k              z
  t          ||k              z
  = |	|t          ||k              z
  t          ||k              z
  = |	                    d|d         d                    |t          ||k              z
  t          ||k              z
  |t          ||k              z
  t          ||k              z
  f}
|                    ||
|	f           |S )aX  Copied from _update_other_results in numpy/core/einsumfunc.py

    Update the positions and provisional input_sets of ``results`` based on
    performing the contraction result ``best``. Remove any involving the tensors
    contracted.

    Parameters
    ----------
    results : list
        List of contraction results produced by ``_parse_possible_contraction``.
    best : list
        The best contraction of ``results`` i.e. the one that will be performed.

    Returns
    -------
    mod_results : list
        The list of modified results, updated with outcome of ``best`` contraction.
    r   r'   )intinsertr   )resultsbestbest_conbxbymod_resultsr;   r+   ycon_setsmod_cons              r   _update_other_resultsr`     s   ( AwHFBK") 6 6fq!h ==AMM R#b1f++%BF34R#b1f++%BF34DGBK((( c!b&kk/CBKK/SR[[3q2v;;1NND'845555r   c                    t          |           dk    rdgS t          |           dk    rdgS t          t          t          |                     | |          }|\  }}}}t          ||t          |           |          }	t	          j        t          t          |                     d          }
g }d}g }t          t          |           dz
            D ]}|
D ]\}| |d                                      | |d                            r0t          || |||||	          }||                    |           ]t          |          dk    rt	          j        t          t          |                     d          D ].}t          || |||||	          }||                    |           /t          |          dk    r>|                    t          t          t          |                                           nt          |d           }t          ||          }|d         } t          |           dz
  fd	t                    D             }
|                    |d                    ||d         d         z  }|S )
a  Copied from _greedy_path in numpy/core/einsumfunc.py

    Finds the path by contracting the best pair until the input list is
    exhausted. The best pair is found by minimizing the tuple
    ``(-prod(indices_removed), cost)``.  What this amounts to is prioritizing
    matrix multiplication or inner product operations, then Hadamard like
    operations, and finally outer operations. Outer products are limited by
    ``memory_limit``. This algorithm scales cubically with respect to the
    number of elements in the list ``input_sets``.

    Parameters
    ----------
    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
    idx_dict : dictionary
        Dictionary of index sizes
    memory_limit_limit : int
        The maximum number of elements in a temporary array

    Returns
    -------
    path : list
        The greedy contraction order within the memory limit constraint.

    Examples
    --------
    >>> isets = [set('abd'), set('ac'), set('bdc')]
    >>> oset = set('')
    >>> idx_sizes = {'a': 1, 'b':2, 'c':3, 'd':4}
    >>> _greedy_path(isets, oset, idx_sizes, 5000)
    [(0, 2), (0, 1)]
    r   )r   r'   )r   r   r   Nc                     | d         S r)   r   r*   s    r   r,   z_greedy_path.<locals>.<lambda>  s
    QqT r   r-   c              3       K   | ]}|fV  	d S rF   r   )rG   r   new_tensor_poss     r   rI   z_greedy_path.<locals>.<genexpr>  s(      HHQa(HHHHHHr   )r1   r%   r0   r   r2   r3   
isdisjointrR   r   r5   r4   r`   )r   r   r   r6   rM   rN   r>   r$   r   rL   	comb_iterknown_contractionsrK   rB   r8   r   resultrX   rd   s                     @r   _greedy_pathri   7  s   J :!v	ZA		x !c*oo
J8 8H<D9J\\; __h8 8J &uS__'='=qAAIID3z??Q.// +  + 	 # 		2 		2I )A,'22:il3KLL 0J
T\^jlu1;= =F!"))&111 !""a'' '3E#j//4J4JANN 6 6	4Y
JX`bn5>
L L%&--f555 %&&!++E%J"8"899::: %>>::: 33EtLL !W
Z1,HHHH%2G2GHHH	 	DGT!WQZ		Kr   )r2   r   r   r%   rC   rR   r`   ri   r   r   r   <module>rj      s       %$ %$ %$P  <:> :> :>zF F FR:- :- :-z' ' 'Te e e e er   