ó 2ÄÈ[c@`sûdZddlmZmZmZddlZddlmZddlm Z ddl m Z m Z m Z mZmZddgZd ZeeƒZd „Zd „Zd „Zd „Zd„Zd„Zd„Zd„Zd„Zd„Zd„ZdS(s& Implementation of optimized einsum. i(tdivisiontabsolute_importtprint_functionN(t basestring(tc_einsum(tasarrayt asanyarrayt result_typet tensordottdotteinsumt einsum_patht4abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZcC`s=t||ƒ}td|dƒ}|r5|d7}n||S(sœ 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 i(t_compute_size_by_dicttmax(tidx_contractiontinnert num_termstsize_dictionaryt overall_sizet op_factor((s4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pyt _flop_counts  cC`s)d}x|D]}|||9}q W|S(s  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 i((tindicestidx_dicttretti((s4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pyR 9s c C`s™tƒ}|jƒ}g}xJt|ƒD]<\}}||krM||O}q(|j|ƒ||O}q(W||@}||} |j|ƒ||| |fS(s  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'}) (tsettcopyt enumeratetappend( t positionst input_setst output_sett idx_contractt idx_remaint remainingtindtvaluet new_resultt idx_removed((s4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pyt_find_contractionVs+        c C`s¤dg|fg}xGtt|ƒdƒD]/}g}xÑ|D]É}|\}} } x±tjtt|ƒ|ƒdƒD]} t| | |ƒ} | \} }}}t| |ƒ}||kr¿qtn|t||t| ƒ|ƒ}| | g}|j|||fƒqtWq<W|r|}q)t|dd„ƒd}|t tt|ƒ|ƒƒg7}|Sq)Wt|ƒdkr‡t tt|ƒƒƒgSt|dd„ƒd}|S(s§ 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} >>> _path__optimal_path(isets, oset, idx_sizes, 5000) [(0, 2), (0, 1)] iiitkeycS`s|dS(Ni((tx((s4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pytÍscS`s|dS(Ni((R*((s4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pyR+Õs( trangetlent itertoolst combinationsR(R RRtminttuple(RR Rt memory_limitt full_resultst iterationt iter_resultstcurrtcostRR#tcontcontR&tnew_input_setsR'R!tnew_sizet total_costtnew_postpath((s4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pyt _optimal_path’s. )   #c`sµt|ˆ|ƒ}|\}} } } t|ˆƒ} | |krCdS‡‡fd†|Dƒ} t| ƒ| }t| | t|ƒˆƒ}| |f}|||kr¨dS||| gS(sá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. c3`s"|]}tˆ|ˆƒVqdS(N(R (t.0tp(RR(s4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pys sN(R(R tNonetsumRR-(RRR RR2t path_costt naive_costtcontractt idx_resultR:R'R!R;t old_sizest removed_sizeR7tsort((RRs4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pyt_parse_possible_contractionØs!  c C`s&|d}|\}}g}x|D]û\}\}}} ||ks#||krVq#n| |t||kƒt||kƒ=| |t||kƒt||kƒ=| jd|ddƒ|t||kƒt||kƒ|t||kƒt||kƒf} |j|| | fƒq#W|S(sUpdate 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 modifed results, updated with outcome of ``best`` contraction. iiÿÿÿÿi(tinttinsertR( tresultstbesttbest_contbxtbyt mod_resultsR7R*tytcon_setstmod_con((s4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pyt_update_other_resultss  ''Lc `slt|ƒdkrdgSt|ƒdkr2dgSttt|ƒƒ||ƒ}|\}}}}t||t|ƒ|ƒ} tjtt|ƒƒdƒ} g} d} g} x¸tt|ƒdƒD] }xm| D]e}||dj||dƒrüqÑnt|||||| | ƒ}|d k rÑ| j |ƒqÑqÑWt| ƒdkrçx`tjtt|ƒƒdƒD]@}t|||||| | ƒ}|d k rk| j |ƒqkqkWt| ƒdkrç| j t tt|ƒƒƒƒPqçnt | dd„ƒ}t | |ƒ} |d}t|ƒd‰‡fd†tˆƒDƒ} | j |dƒ| |dd7} qÄW| S( sµ 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} >>> _path__greedy_path(isets, oset, idx_sizes, 5000) [(0, 2), (0, 1)] iiiR)cS`s|dS(Ni((R*((s4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pyR+Œsc3`s|]}|ˆfVqdS(N((R@R(tnew_tensor_pos(s4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pys •s(i(iiN( R-R(R,RR.R/t isdisjointRKRBRR1R0RW(RR RR2RFRGR:R'R!REt comb_itertknown_contractionsRDR>R4RtresultRO((RXs4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pyt _greedy_path9sH$   %   c C`s”t|ƒdkrtSt|ƒdkr,tS|\}}x‡t||ƒD]u}|j|ƒ|j|ƒ}}|dks–|dks–||dkrštS||dt||kƒkrItSqIWt|ƒ}t|ƒ} ||} | |} t|ƒ} ||kr tS|| krtS|| || kr3tS|| || krLtS|| || krftS|| || kr~tS| sŒ| rtStS(s¸ Checks if we can use BLAS (np.tensordot) call and its beneficial to do so. Parameters ---------- inputs : list of str Specifies the subscripts for summation. result : str Resulting summation. idx_removed : set Indices that are removed in the summation Returns ------- type : bool Returns true if BLAS should and can be used, else False Notes ----- If the operations is BLAS level 1 or 2 and is not already aligned we default back to einsum as the memory movement to copy is more costly than the operation itself. Examples -------- # Standard GEMM operation >>> _can_dot(['ij', 'jk'], 'ik', set('j')) True # Can use the standard BLAS, but requires odd data movement >>> _can_dot(['ijj', 'jk'], 'ik', set('j')) False # DDOT where the memory is not aligned >>> _can_dot(['ijk', 'ikj'], '', set('ijk')) False iii(R-tFalseRtcountRLtTrue( tinputsR\R't input_leftt input_righttctnltnrtset_leftt set_rightt keep_leftt keep_righttrs((s4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pyt_can_dotžs>, (        cC`s±t|ƒdkr!tdƒ‚nt|dtƒr²|djddƒ}g|dD]}t|ƒ^qU}xó|D]7}|dkrŒqtn|tkrttd|ƒ‚qtqtWn±t|ƒ}g}g}xJtt|ƒdƒD]2}|j |j dƒƒ|j |j dƒƒqáWt|ƒr-|d nd}g|D]}t|ƒ^q:}d}t|ƒd} x‰t |ƒD]{\} } xS| D]K}|t kr§|d 7}qˆt|tƒrÇ|t|7}qˆtd ƒ‚qˆW| | kru|d 7}ququW|dk rc|d 7}xV|D]K}|t kr0|d 7}qt|tƒrP|t|7}qtd ƒ‚qWnd|ks{d|krÒ|jdƒdkp¢|jdƒdk} | sÀ|jd ƒdkrÒtdƒ‚qÒnd|kr¤|jddƒjd dƒjd dƒ} ttt| ƒƒ}dj|ƒ}d}d |krl|jd ƒ\}}|jd ƒ}t}n|jd ƒ}t}xt |ƒD]\} } d| krŽ| jdƒdksÐ| jd ƒdkrßtdƒ‚n|| jdkrûd}n*t|| jdƒ}|t| ƒd8}||kr:|}n|dkrUtdƒ‚qž|dkrz| jd dƒ|| >> 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]) isNo input operandst tis.,->s#Character %s is not a valid symbol.iiÿÿÿÿs...s=For this input type lists must contain either int or Ellipsist,s->t-t>s%Subscripts can only contain one '->'.t.isInvalid Ellipses.sEllipses lengths do not match.s/Output character %s did not appear in the inputsDNumber of einsum subscripts must be equal to the number of operands.N((R-t ValueErrort isinstanceRtreplaceRteinsum_symbolstlistR,RtpopRBRtEllipsisRLt TypeErrorR_teinsum_symbols_setRtjointsplitR`R^tshapeRtndimtsorted(toperandst subscriptstvtst tmp_operandst operand_listtsubscript_listRAt output_listtlasttnumtsubtinvalidtusedtunusedt ellipse_indstlongestt input_tmpt output_subtsplit_subscriptstout_subt ellipse_counttrep_indst out_ellipsetoutput_subscriptttmp_subscriptst normal_indstinput_subscriptstchar((s4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pyt_parse_einsum_input sÊ#             * *   *              !c>O`sddg}g|jƒD]\}}||kr|^q}t|ƒr\td|ƒ‚n|jdtƒ}|tkrƒd}n|d#kr˜t}nd#}|tksLt|tƒr¼nt|ƒrÛ|ddkrÛnqt|ƒdkr6t|dtƒr6t|dt t fƒr6t |dƒ}|d}ntd t |ƒƒ‚|jdtƒ}t |ƒ\} } }| d | } | j d ƒ} g| D]} t| ƒ^q—}t| ƒ}t| jd d ƒƒ}i}gtt| ƒƒD] } g^qì}xt| ƒD] \}}||j}t|ƒt|ƒkrYtd | ||fƒ‚nx¹t|ƒD]«\}}||}|dkrœ||j|ƒn||jƒkr||dkrË|||>> a = np.random.rand(2, 2) >>> b = np.random.rand(2, 5) >>> c = np.random.rand(5, 2) >>> path_info = np.einsum_path('ij,jk,kl->il', a, b, c, optimize='greedy') >>> print(path_info[0]) ['einsum_path', (1, 2), (0, 1)] >>> print(path_info[1]) Complete contraction: ij,jk,kl->il Naive scaling: 4 Optimized scaling: 3 Naive FLOP count: 1.600e+02 Optimized FLOP count: 5.600e+01 Theoretical speedup: 2.857 Largest intermediate: 4.000e+00 elements ------------------------------------------------------------------------- scaling current remaining ------------------------------------------------------------------------- 3 kl,jk->jl ij,jl->il 3 jl,ij->il il->il A more complex index transformation example. >>> I = np.random.rand(10, 10, 10, 10) >>> C = np.random.rand(10, 10) >>> path_info = np.einsum_path('ea,fb,abcd,gc,hd->efgh', C, C, I, C, C, optimize='greedy') >>> print(path_info[0]) ['einsum_path', (0, 2), (0, 3), (0, 2), (0, 1)] >>> print(path_info[1]) Complete contraction: ea,fb,abcd,gc,hd->efgh Naive scaling: 8 Optimized scaling: 5 Naive FLOP count: 8.000e+08 Optimized FLOP count: 8.000e+05 Theoretical speedup: 1000.000 Largest intermediate: 1.000e+04 elements -------------------------------------------------------------------------- scaling current remaining -------------------------------------------------------------------------- 5 abcd,ea->bcde fb,gc,hd,bcde->efgh 5 bcde,fb->cdef gc,hd,cdef->efgh 5 cdef,gc->defg hd,defg->efgh 5 defg,hd->efgh efgh->efgh toptimizet einsum_calls+Did not understand the following kwargs: %stgreedyiR iisDid not understand the path: %ss->RoRnsXEinstein sum subscript %s does not contain the correct number of indices for operand %d.sJSize of label '%s' for operand %d (%d) does not match previous terms (%d).cs`s|]}t|ƒVqdS(N(R-(R@R*((s4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pys zstoptimalsPath name %s not foundtreverseiÿÿÿÿtscalingtcurrentR#s Complete contraction: %s s Naive scaling: %d s Optimized scaling: %d s Naive FLOP count: %.3e s Optimized FLOP count: %.3e s Theoretical speedup: %3.3f s' Largest intermediate: %.3e elements RpiJs s%6s %24s %40s s %4d %24s %40sN(ii(R£R¤R#(#titemsR-RzRxR`RBR^RtRRLtfloattstrRR}RRuR,RR~RsRtkeysR RRCRR1R]R?tKeyErrorR€RwR(RlR|(>Rtkwargstvalid_contract_kwargstkRƒtunknown_kwargst path_typeR2teinsum_call_argR›R˜R‚t input_listR*RR Rtdimension_dicttbroadcast_indicesttnumttermtshtcnumRœtdimt size_listtmax_sizet memory_argt inner_productRER>t cost_listt scale_listtcontraction_listt contract_indsRFtout_indsR'R!R7tbcastt tmp_inputstnew_bcast_indstdo_blasRGR$t sort_resultt einsum_strt contractiontopt_costtoverall_contractiontheadertspeeduptmax_it path_printtntindstidx_rmR#tblast remaining_strtpath_run((s4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pyR ³sèn       %  %        &*        #,       c`sà|jdtƒ}|tkr+t||ŽSddddg‰‡fd†|jƒDƒ}dgˆ}g|jƒD]\}}||krs|^qs}t|ƒr¶td|ƒ‚nt}|jddƒ} | dk rãt}ntd|dt|Œ\}} t} xÀt | ƒD]²\} } | \}}}}}g}x$|D]}|j |j|ƒƒqBW|o{| d t| ƒk} |rŽ|j d ƒ\}}|j d ƒ\}}||}x |D]}|j |d ƒ}q¿Wgg}}x:|D]2}|j |j |ƒƒ|j |j |ƒƒqïWtd t|ƒt|ƒf|Œ}||ks[| r³| rn| |d', a)`` is like ``np.sum(a, axis=-1)``, and ``np.einsum('ii->i', a)`` is like ``np.diag(a)``. The difference is that `einsum` does not allow broadcasting by default. To enable and control broadcasting, use an ellipsis. Default NumPy-style broadcasting is done by adding an ellipsis to the left of each term, like ``np.einsum('...ii->...i', a)``. To take the trace along the first and last axes, you can do ``np.einsum('i...i', a)``, or to do a matrix-matrix product with the left-most indices instead of rightmost, you can do ``np.einsum('ij...,jk...->ik...', a, b)``. When there is only one operand, no axes are summed, and no output parameter is provided, a view into the operand is returned instead of a new array. Thus, taking the diagonal as ``np.einsum('ii->i', a)`` produces a view. An alternative way to provide the subscripts and operands is as ``einsum(op0, sublist0, op1, sublist1, ..., [sublistout])``. The examples below have corresponding `einsum` calls with the two parameter methods. .. versionadded:: 1.10.0 Views returned from einsum are now writeable whenever the input array is writeable. For example, ``np.einsum('ijk...->kji...', a)`` will now have the same effect as ``np.swapaxes(a, 0, 2)`` and ``np.einsum('ii->i', a)`` will return a writeable view of the diagonal of a 2D array. .. versionadded:: 1.12.0 Added the ``optimize`` argument which will optimize the contraction order of an einsum expression. For a contraction with three or more operands this can greatly increase the computational efficiency at the cost of a larger memory footprint during computation. See ``np.einsum_path`` for more details. Examples -------- >>> a = np.arange(25).reshape(5,5) >>> b = np.arange(5) >>> c = np.arange(6).reshape(2,3) >>> np.einsum('ii', a) 60 >>> np.einsum(a, [0,0]) 60 >>> np.trace(a) 60 >>> np.einsum('ii->i', a) array([ 0, 6, 12, 18, 24]) >>> np.einsum(a, [0,0], [0]) array([ 0, 6, 12, 18, 24]) >>> np.diag(a) array([ 0, 6, 12, 18, 24]) >>> np.einsum('ij,j', a, b) array([ 30, 80, 130, 180, 230]) >>> np.einsum(a, [0,1], b, [1]) array([ 30, 80, 130, 180, 230]) >>> np.dot(a, b) array([ 30, 80, 130, 180, 230]) >>> np.einsum('...j,j', a, b) array([ 30, 80, 130, 180, 230]) >>> np.einsum('ji', c) array([[0, 3], [1, 4], [2, 5]]) >>> np.einsum(c, [1,0]) array([[0, 3], [1, 4], [2, 5]]) >>> c.T array([[0, 3], [1, 4], [2, 5]]) >>> np.einsum('..., ...', 3, c) array([[ 0, 3, 6], [ 9, 12, 15]]) >>> np.einsum(',ij', 3, C) array([[ 0, 3, 6], [ 9, 12, 15]]) >>> np.einsum(3, [Ellipsis], c, [Ellipsis]) array([[ 0, 3, 6], [ 9, 12, 15]]) >>> np.multiply(3, c) array([[ 0, 3, 6], [ 9, 12, 15]]) >>> np.einsum('i,i', b, b) 30 >>> np.einsum(b, [0], b, [0]) 30 >>> np.inner(b,b) 30 >>> np.einsum('i,j', np.arange(2)+1, b) array([[0, 1, 2, 3, 4], [0, 2, 4, 6, 8]]) >>> np.einsum(np.arange(2)+1, [0], b, [1]) array([[0, 1, 2, 3, 4], [0, 2, 4, 6, 8]]) >>> np.outer(np.arange(2)+1, b) array([[0, 1, 2, 3, 4], [0, 2, 4, 6, 8]]) >>> np.einsum('i...->...', a) array([50, 55, 60, 65, 70]) >>> np.einsum(a, [0,Ellipsis], [Ellipsis]) array([50, 55, 60, 65, 70]) >>> np.sum(a, axis=0) array([50, 55, 60, 65, 70]) >>> a = np.arange(60.).reshape(3,4,5) >>> b = np.arange(24.).reshape(4,3,2) >>> np.einsum('ijk,jil->kl', a, b) array([[ 4400., 4730.], [ 4532., 4874.], [ 4664., 5018.], [ 4796., 5162.], [ 4928., 5306.]]) >>> np.einsum(a, [0,1,2], b, [1,0,3], [2,3]) array([[ 4400., 4730.], [ 4532., 4874.], [ 4664., 5018.], [ 4796., 5162.], [ 4928., 5306.]]) >>> np.tensordot(a,b, axes=([1,0],[0,1])) array([[ 4400., 4730.], [ 4532., 4874.], [ 4664., 5018.], [ 4796., 5162.], [ 4928., 5306.]]) >>> a = np.arange(6).reshape((3,2)) >>> b = np.arange(12).reshape((4,3)) >>> np.einsum('ki,jk->ij', a, b) array([[10, 28, 46, 64], [13, 40, 67, 94]]) >>> np.einsum('ki,...k->i...', a, b) array([[10, 28, 46, 64], [13, 40, 67, 94]]) >>> np.einsum('k...,jk', a, b) array([[10, 28, 46, 64], [13, 40, 67, 94]]) >>> # since version 1.10.0 >>> a = np.zeros((3, 3)) >>> np.einsum('ii->i', a)[:] = 1 >>> a array([[ 1., 0., 0.], [ 0., 1., 0.], [ 0., 0., 1.]]) Ržtouttdtypetordertcastingc`s+i|]!\}}|ˆkr||“qS(((R@R¬Rƒ(tvalid_einsum_kwargs(s4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pys Ïs s+Did not understand the following kwargs: %sRŸis->RoRntaxesiN(RxR^RR¥R-RzRBR`R RRR}RutfindRR1(RRªt optimize_argt einsum_kwargsR«R¬RƒR­t specified_outt out_arrayR¾t handle_outRŠRÇRÏRÐRÆR#RÑR…R*t input_strt results_indexRbRct tensor_resultR„tleft_post right_postnew_view((RØs4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pyR ×s^ñ             $     (t__doc__t __future__RRRR.t numpy.compatRtnumpy.core.multiarrayRtnumpy.core.numericRRRRR t__all__RvRR{RR R(R?RKRWR]RlRR R (((s4/tmp/pip-build-fiC0ax/numpy/numpy/core/einsumfunc.pyts( (   &  < F : ' e m ¨ ÿ%