
    iΉ                     J   S r SSKJr  SSKJr  SSKrSSKJrJ	r	J
r
JrJrJr  / SQr " S S	\5      rS
 r1 SkrS r\R(                  S 5       rS r\R.                  SS j5       r\R2                  SS j5       rS rS rS rSS jrS r " S S5      r \" SS/5      r!S r"S r#g)z=
Contains the primary optimization and contraction routines.
    )
namedtuple)DecimalN   )backendsblashelpersparserpathssharing)contract_pathcontractformat_const_einsum_strContractExpression
shape_onlyc                   $    \ rS rSrSrS rS rSrg)PathInfo   a~  A printable object to contain information about a contraction path.

Attributes
----------
naive_cost : int
    The estimate FLOP cost of a naive einsum contraction.
opt_cost : int
    The estimate FLOP cost of this optimized contraction path.
largest_intermediate : int
    The number of elements in the largest intermediate array that will be
    produced during the contraction.
c                   ^
 Xl         X l        X0l        XPl        X@l        X`l        [        U5      U l        [        U5      U l        U R                  U R                  -  U l	        Xl
        T
U l        UR                  S5       Vs/ s H  n[        U
4S jU 5       5      PM     snU l        SR                  X#5      U l        [        [#        U	5      5      U l        g s  snf )N,c              3   .   >#    U  H
  nTU   v   M     g 7fN ).0k	size_dicts     S/var/www/html/banglarbhumi/venv/lib/python3.13/site-packages/opt_einsum/contract.py	<genexpr>$PathInfo.__init__.<locals>.<genexpr>*   s     62aYq\2s   z{}->{})contraction_listinput_subscriptsoutput_subscriptpathindices
scale_listr   
naive_costopt_costspeedup	size_listr   splittupleshapesformateqmaxlargest_intermediate)selfr   r    r!   r#   r"   r$   r%   r&   r(   r   kss             ` r   __init__PathInfo.__init__   s     0 0 0	$!*-)6""AQAWAWX[A\]A\2u6266A\]//"2E$+C	N$;! ^s   Cc                    SnSR                  U R                  5      SR                  [        U R                  5      5      SR                  [	        U R
                  5      5      SR                  U R                  5      SR                  U R                  5      SR                  U R                  5      SR                  U R                  5      S	S
R                   " U6 S/
n[        U R                  5       H  u  p4Uu  pVpxn	Ub"  SR                  U5      S-   U R                  -   n
OSn
[	        SS[	        S[        U5      5      -
  5      nU R
                  U   XX4nUR                  SR                   " U6 5        M     SR                  U5      $ )N)scalingBLAScurrent	remainingz  Complete contraction:  {}
z         Naive scaling:  {}
z     Optimized scaling:  {}
z       Naive FLOP count:  {:.3e}
z   Optimized FLOP count:  {:.3e}
z    Theoretical speedup:  {:.3e}
z)  Largest intermediate:  {:.3e} elements
zQ--------------------------------------------------------------------------------
z{:>6} {:>11} {:>22} {:>37}
zP--------------------------------------------------------------------------------r   ->z...r   8      z
{:>4} {:>14} {:>22}    {:>{}} )r,   r-   lenr#   r.   r$   r%   r&   r'   r/   	enumerater   joinr!   append)r0   header
path_printncontractionindsidx_rm
einsum_strr8   do_blasremaining_strsize_remainingpath_runs                r   __repr__PathInfo.__repr__.   s_   < ,22477;=\=c=cdghlhthtdu=v+223t3GHJmJtJtK!"E"L"LT]]"[/66t||D8??@Y@YZ\k*116:H

 ((=(=>NA;F8D*$ # 3d :T=R=R R % BRZ)A$ABN*G_H?FFQR ? wwz""    )r   r-   r#   r    r/   r%   r&   r!   r"   r$   r+   r   r(   r'   N)__name__
__module____qualname____firstlineno____doc__r2   rL   __static_attributes__r   rN   r   r   r      s    <$#rN   r   c                 r    U S:X  a  [        U5      $ U c  g U S:  a  U S:X  a  g [        S5      e[        U 5      $ )N	max_inputr   z)Memory limit must be larger than 0, or -1)r.   
ValueErrorint)memory_limitr(   s     r   _choose_memory_argr[   J   sG    {"9~a2HII|rN   >   r"   r+   optimizeuse_blaseinsum_callrZ   c                  b
   [        U5      [        -
  n[        U5      (       a  [        SR	                  U5      5      eUR                  SS5      nUR                  SS5      nUR                  SS5      nUR                  SS5      nUR                  S	S
5      n[        R                  " U 5      u  pn UR                  S5      n
U
 Vs/ s H  n[        U5      PM     nnU(       a  U nOU  Vs/ s H  oR                  PM     nn[        U	5      n[        UR                  SS5      5      n0 n[        U
5       H  u  nnUU   n[        U5      [        U5      :w  a  [        SR	                  U
U   U5      5      e[        U5       H\  u  nn[        UU   5      nUU;   a=  UU   S:X  a  UUU'   M*  USUU   4;  a   [        SR	                  UUUU   U5      5      eMW  UUU'   M^     M     X/-    Vs/ s H  n[        R                  " UU5      PM     nn[!        UU5      n[        U
5      n[#        S U 5       5      [        U5      -
  S:  n[        R$                  " UUUU5      n['        U[(        [*        R,                  45      (       d  UnOfUS::  a  [/        [1        U5      5      /nOJ['        U[*        R,                  5      (       a  U" XUU5      nO [*        R2                  " U5      nU" XUU5      n/ n/ n/ n/ n [        U5       GH  u  nn![/        [5        [7        U!5      S
S95      n![        R8                  " U!X5      n"U"u  n#nn$n%[        R$                  " U%U$[        U!5      U5      n&UR;                  U&5        UR;                  [        U%5      5        UR;                  [        R                  " U#U5      5        U! Vs/ s H  oR                  U5      PM     n'nU! Vs/ s H  oR                  U5      PM     n(nU(       a  [<        R>                  " U'U#U$U(5      n)OSn)U[        U5      -
  S:X  a  U	n*O4SRA                  U'5      n+SRA                  [5        U#U+RB                  S95      n*[        RD                  " U'U(U*5      n,U
R;                  U*5        UR;                  U,5        SRA                  U'5      S-   U*-   n-[        U
5      S::  a  [/        U
5      n.OSn.U!U$U-U.U)4n/U R;                  U/5        GM     [#        U5      n0U(       a  U U 4$ [G        U XUUUUU0UU5
      n1UU14$ s  snf s  snf s  snf s  snf s  snf )a2  
Find a contraction order 'path', without performing the contraction.

Parameters
----------
subscripts : str
    Specifies the subscripts for summation.
*operands : list of array_like
    These are the arrays for the operation.
optimize : str, list or bool, optional (default: ``auto``)
    Choose the type of path.

    - if a list is given uses this as the path.
    - ``'optimal'`` An algorithm that explores all possible ways of
      contracting the listed tensors. Scales factorially with the number of
      terms in the contraction.
    - ``'branch-all'`` An algorithm like optimal but that restricts itself
      to searching 'likely' paths. Still scales factorially.
    - ``'branch-2'`` An even more restricted version of 'branch-all' that
      only searches the best two options at each step. Scales exponentially
      with the number of terms in the contraction.
    - ``'greedy'`` An algorithm that heuristically chooses the best pair
      contraction at each step.
    - ``'auto'`` Choose the best of the above algorithms whilst aiming to
      keep the path finding time below 1ms.

use_blas : bool
    Use BLAS functions or not
memory_limit : int, optional (default: None)
    Maximum number of elements allowed in intermediate arrays.
shapes : bool, optional
    Whether ``contract_path`` should assume arrays (the default) or array
    shapes have been supplied.

Returns
-------
path : list of tuples
    The einsum path
PathInfo : str
    A printable object containing various information about the path found.

Notes
-----
The resulting path indicates which terms of the input contraction should be
contracted first, the result of this contraction is then appended to the end of
the contraction list.

Examples
--------

We can begin with a chain dot example. In this case, it is optimal to
contract the b and c tensors represented by the first element of the path (1,
2). The resulting tensor is added to the end of the contraction and the
remaining contraction, ``(0, 1)``, is then executed.

>>> a = np.random.rand(2, 2)
>>> b = np.random.rand(2, 5)
>>> c = np.random.rand(5, 2)
>>> path_info = opt_einsum.contract_path('ij,jk,kl->il', a, b, c)
>>> print(path_info[0])
[(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 = oe.contract_path('ea,fb,abcd,gc,hd->efgh', C, C, I, C, C)

>>> print(path_info[0])
[(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
z8einsum_path: Did not understand the following kwargs: {}r\   autorZ   Nr+   Fr^   r]   Tr   r<   zZEinstein sum subscript '{}' does not contain the correct number of indices for operand {}.r   zJSize of label '{}' for operand {} ({}) does not match previous terms ({}).c              3   8   #    U  H  n[        U5      v   M     g 7fr   )r=   r   xs     r   r    contract_path.<locals>.<genexpr>   s     4AQs   r      )reverserW   )keyr9      )$set_VALID_CONTRACT_KWARGSr=   	TypeErrorr,   popr	   parse_einsum_inputr)   shapereplacer>   rX   rY   r   compute_size_by_dictr[   sum
flop_count
isinstancestrr
   PathOptimizerr*   rangeget_path_fnsortedlistfind_contractionr@   r   can_blasr?   findfind_output_shaper   )2operandskwargsunknown_kwargs	path_typerZ   r+   einsum_call_argr]   r    r!   
input_listrc   
input_sets
input_shps
output_setr#   r   tnumtermshcnumchardimr(   
memory_argnum_opsinner_productr%   r"   path_optimizer	cost_listr$   r   contract_indscontract_tupleout_indsidx_removedidx_contractcost
tmp_inputs
tmp_shapesrH   
idx_resultall_input_inds
shp_resultrG   r8   rD   r&   rB   s2                                                     r   r   r   ]   s   N [#99N
>RYYZhijj

:v.I::nd3LZZ%(F jj6Ozz*d+H 4:3L3LX3V0 "'',J",-*Q#a&*J-
'/0x!ggx
0%&J"**334G I
+
dr7c$i IIOPZ[_P`bfIgi i#D/JD$bh-Cy T?a'&)IdOIdO 44$ &3396$iPToWZ3[] ] 5 #&	$ * ,( LVXjKjkKj4--dI>KjIk#L)<J*oG 444s7|CqHM##G]GYOJ i#u':':!;<<	AeGn%&	Iu22	3	3JG**95jiLIJI  )mfT-%8$GH 11-X:H7*k< !!,S=OQZ[#l+,55h	JK1>?AnnQ'
?1>?AnnQ'
?mmJ+zRGG 3t9#)J  WWZ0Nn6I6I!JKJ--j*jQ
*%*%XXj)D0:=
 z?b j)II$k:y'R,Y  /\ 9~H)))*,<PWY]_iku"Iy:J i . 14 lZ @?s   T*T+!T"8T'T,c                  `   [         R                  " SUR                  SS5      5      n[        U S   [        5      (       d  U" U 0 UD6$ U S   U SS p[
        R                  " U5      (       d8  SU;  a  US[
        R                  " U5      -   -  n[
        R                  " U5      nU" U/U Q70 UD6$ )zOBase einsum, but with pre-parse for valid characters if a string is given.
    einsumbackendnumpyr   r   Nr9   )	r   get_funcrl   rs   rt   r	   has_valid_einsum_chars_onlyfind_output_strconvert_to_valid_einsum_chars)r~   r   fnrG   s       r   _einsumr   M  s     
		8VZZ	7%C	DBhqk3''8&v&&#A; --j99 z!$!7!7
!CCCJ99*E
j.8.v..rN   c                 $    U R                  U5      $ r   )	transpose)rc   axess     r   _default_transposer   d  s    ;;trN   c                 J    [         R                  " SU[        5      nU" X5      $ )zBase transpose.
    r   )r   r   r   )rc   r   r   r   s       r   
_transposer   i  s#     
		;1C	DBa;rN   c                 >    [         R                  " SU5      nU" XUS9$ )zBase tensordot.
    	tensordot)r   )r   r   )rc   yr   r   r   s        r   
_tensordotr   q  s#     
		;	0BarN   c                     UR                  SS5      nUSL a  Sn/ SQnUR                  5        VVs0 s H  u  pEXC;   d  M  XE_M     nnnUSL a  [        U 0 UD6$ UR                  SS5      nUR                  SS5      nUR                  S	S5      n	UR                  S
S5      n
UR                  S0 5      nUR                  5        VVs/ s H  u  pEXC;  d  M  UPM     nnn[        U5      (       a  [	        SR                  U5      5      eU
(       a  U S   n[        U UUSUS.6u  pU
(       a  [        WX40 UD6$ [        X4S	U	0UD6$ s  snnf s  snnf )a  
contract(subscripts, *operands, out=None, dtype=None, order='K', casting='safe', use_blas=True, optimize=True, memory_limit=None, backend='numpy')

Evaluates the Einstein summation convention on the operands. A drop in
replacement for NumPy's einsum function that optimizes the order of contraction
to reduce overall scaling at the cost of several intermediate arrays.

Parameters
----------
subscripts : str
    Specifies the subscripts for summation.
*operands : list of array_like
    These are the arrays for the operation.
out : array_like
    A output array in which set the resulting output.
dtype : str
    The dtype of the given contraction, see np.einsum.
order : str
    The order of the resulting contraction, see np.einsum.
casting : str
    The casting procedure for operations of different dtype, see np.einsum.
use_blas : bool
    Do you use BLAS for valid operations, may use extra memory for more intermediates.
optimize : str, list or bool, optional (default: ``auto``)
    Choose the type of path.

    - if a list is given uses this as the path.
    - ``'optimal'`` An algorithm that explores all possible ways of
      contracting the listed tensors. Scales factorially with the number of
      terms in the contraction.
    - ``'dp'`` A faster (but essentially optimal) algorithm that uses
      dynamic programming to exhaustively search all contraction paths
      without outer-products.
    - ``'greedy'`` An cheap algorithm that heuristically chooses the best
      pairwise contraction at each step. Scales linearly in the number of
      terms in the contraction.
    - ``'random-greedy'`` Run a randomized version of the greedy algorithm
      32 times and pick the best path.
    - ``'random-greedy-128'`` Run a randomized version of the greedy
      algorithm 128 times and pick the best path.
    - ``'branch-all'`` An algorithm like optimal but that restricts itself
      to searching 'likely' paths. Still scales factorially.
    - ``'branch-2'`` An even more restricted version of 'branch-all' that
      only searches the best two options at each step. Scales exponentially
      with the number of terms in the contraction.
    - ``'auto'`` Choose the best of the above algorithms whilst aiming to
      keep the path finding time below 1ms.
    - ``'auto-hq'`` Aim for a high quality contraction, choosing the best
      of the above algorithms whilst aiming to keep the path finding time
      below 1sec.

memory_limit : {None, int, 'max_input'} (default: None)
    Give the upper bound of the largest intermediate tensor contract will build.

    - None or -1 means there is no limit
    - 'max_input' means the limit is set as largest input tensor
    - a positive integer is taken as an explicit limit on the number of elements

    The default is None. Note that imposing a limit can make contractions
    exponentially slower to perform.
backend : str, optional (default: ``auto``)
    Which library to use to perform the required ``tensordot``, ``transpose``
    and ``einsum`` calls. Should match the types of arrays supplied, See
    :func:`contract_expression` for generating expressions which convert
    numpy arrays to and from the backend library automatically.

Returns
-------
out : array_like
    The result of the einsum expression.

Notes
-----
This function should produce a result identical to that of NumPy's einsum
function. The primary difference is ``contract`` will attempt to form
intermediates which reduce the overall scaling of the given einsum contraction.
By default the worst intermediate formed will be equal to that of the largest
input array. For large einsum expressions with many input arrays this can
provide arbitrarily large (1000 fold+) speed improvements.

For contractions with just two tensors this function will attempt to use
NumPy's built-in BLAS functionality to ensure that the given operation is
preformed optimally. When NumPy is linked to a threaded BLAS, potential
speedups are on the order of 20-100 for a six core machine.

Examples
--------

See :func:`opt_einsum.contract_path` or :func:`numpy.einsum`

r\   Tr`   )outdtypeordercastingFr]   rZ   Nr   _gen_expression_constants_dictz+Did not understand the following kwargs: {}r   )r\   rZ   r^   r]   )	rl   itemsr   r=   rk   r,   r   r   _core_contract)r~   r   optimize_argvalid_einsum_kwargsr   veinsum_kwargsr]   rZ   r   gen_expressionconstants_dictr   full_strr   s                  r   r   r   z  se   x ::j$/Lt>(.Sfq!:RTQTMS u2M22 zz*d+H::nd3LjjF+GZZ 159NZZ 126N '-llnUnFQ8TanNU
>ELL^\]]A; "/8D<H;?8@	"BH !(,<^P]^^(WgWWWA T Vs   E EEEc                 R    U R                   R                  R                  S5      S   $ )N.r   )	__class__rP   r)   )rc   s    r   infer_backendr     s"    ;;!!'',Q//rN   c                 j    US:w  a  U$ [        U S   5      n[        R                  " U5      (       d  gU$ )zmFind out what backend we should use, dipatching based on the first
array if ``backend='auto'`` is specified.
r`   r   r   )r   r   has_tensordot)arraysr   s     r   parse_backendr     s:     &F1I&G !!'**NrN   c                   ^ ^ UR                  SS5      nUSLn[        T U5      n[        R                  " U5      (       + n[	        U5       GH  u  pU	u  n
mpnU(       a"  [        U 4S jU
 5       5      (       a  T XS 4s  $ U
 Vs/ s H  nT R                  U5      PM     nnU=(       a    US-   [        U5      :H  nU(       Ga  SU;  d  U(       a  UR                  S5      u  nnUR                  S5      u  nnSR                  U4S	 jUU-    5       5      n/ / nnT HC  nUR                  UR                  U5      5        UR                  UR                  U5      5        ME     [        U[        U5      [        U5      4US
.6nUU:w  d  U(       a6  [        [        UR                  U5      5      n[        UUUS
9nU(       a  UUSS& OU(       a  XTS'   [!        U/UQ7SU0UD6nT R                  U5        AAGM     U(       a  U$ T S   $ s  snf )zxInner loop used to perform an actual contraction given the output
from a ``contract_path(..., einsum_call=True)`` call.
r   Nc              3   2   >#    U  H  nTU   S L v   M     g 7fr   r   )r   rc   r~   s     r   r   !_core_contract.<locals>.<genexpr>%  s     %H4ahqkT&94s   r   EINSUMr9   r   r<   c              3   6   >#    U  H  oT;  d  M
  Uv   M     g 7fr   r   )r   srF   s     r   r   r   4  s     #[/G!TZ?AA/Gs   		)r   r   r   r   )rl   r   r   
has_einsumr>   anyr=   r)   r?   r@   r|   r   r*   mapindexr   r   )r~   r   r   evaluate_constantsr   	out_arrayspecified_out	no_einsumnumrD   rE   rG   _	blas_flagrc   tmp_operands
handle_out	input_strresults_index
input_leftinput_righttensor_resultleft_pos	right_posr   new_viewr   rF   s   `                          @r   r   r     s    !!%.IT)MHg.G ''00I &&671<.fjY #%H4%H"H"H-d333156AQ6 #KqS9I5J(J
 ()3y (2'7'7'=$I}&/ooc&:#JGG#[zK/G#[[M #%biH
 23  !1!1!!45 
 "<uXiHX6YcjkH .:!#m&9&9="IJ	%hYP#+IaL
 '0e$ z[L['[][H 	!(g 8j {a 7s   H
c                 T   U(       d  U $ SU ;   a  U R                  S5      u  p#SnOU SSpCn[        UR                  S5      5       VVs/ s H  u  pVXQ;   a  SR                  U5      OUPM     nnnSR                  SR                  U5      XC5      nUR	                  SS5      nU$ s  snnf )zAdd brackets to the constant terms in ``einsum_str``. For example:

    >>> format_const_einsum_str('ab,bc,cd->ad', [0, 2])
    'bc,[ab,cd]->ad'

No-op if there are no constants.
r9   r<   r   z[{}]z{}{}{}z],[)r)   r>   r,   r?   ro   )	rG   	constantslhsrhsarrowitwrapped_termsformatted_einsum_strs	            r   r   r   [  s     z##D)$b"%KTUXU^U^_bUcKdeKd41V]]1%Q>KdMe#??388M+BEO 077sC fs   $B$c                   Z    \ rS rSrSrS rSS jrS rS rSS jr	SS	 jr
S
 rS rS rSrg)r   iu  zHelper class for storing an explicit ``contraction_list`` which can
then be repeatedly called solely with the array arguments.
c                     X l         X@l        [        XR                  5       5      U l        UR                  S5      S-   U l        U R                  [        U5      -
  U l        X l	        X0l
        0 U l        0 U l        g )Nr   r   )r   r   r   keysrD   count_full_num_argsr=   num_args_full_contraction_listr   _evaluated_constants_backend_expressions)r0   rD   r   r   r   s        r   r2   ContractExpression.__init__y  ss     0*2;@S@S@UV *//4q8++c..AA '7#-$&!$&!rN   c                 0   [        U R                  5       Vs/ s H  o R                  R                  US5      PM      nn[	        X15      n [
        R                  " XU 5      u  pEX@R                  U'   XPl	        gs  snf ! [         a    U " X1SS.6u  pE N0f = f)a  Convert any constant operands to the correct backend form, and
perform as many contractions as possible to create a new list of
operands, stored in ``self._evaluated_constants[backend]``. This also
makes sure ``self.contraction_list`` only contains the remaining,
non-const operations.
NT)r   r   )
rv   r   r   getr   r   r   KeyErrorr   r   )r0   r   r   tmp_const_opsnew_opsnew_contraction_lists         r   r   %ContractExpression.evaluate_constants  s     EJ$J]J]D^_D^q--11!T:D^_7	k,4,G,G`d,e)G .5!!'* 4 `  	k,0-ei,j)G)	ks   %A9A> >BBc                      U R                   U   $ ! [         a#    U R                  U5        U R                   U   s $ f = f)zRetrieve or generate the cached list of constant operators (mixed
in with None representing non-consts) and the remaining contraction
list.
)r   r   r   )r0   r   s     r   _get_evaluated_constants+ContractExpression._get_evaluated_constants  sF    
	6,,W55 	6##G,,,W55	6s    *>>c                      U R                   U   $ ! [         a*    [        R                  " X!U 5      nX0R                   U'   Us $ f = fr   )r   r   r   build_expression)r0   r   r   r   s       r   _get_backend_expression*ContractExpression._get_backend_expression  sL    	,,W55 	**7DAB13%%g.I	s    1AANc                     U(       a  U R                   OU R                  n[        [        U5      U4UUUS.U R                  D6$ )z&The normal, core contraction.
        )r   r   r   )r   r   r   ry   r   )r0   r   r   r   r   r   s         r   	_contractContractExpression._contract  sP     ;M466RVRgRgd6l.4"%&-1C	4
 !% 2 24 	4rN   c                 |    U(       a  [         R                  " X1U 5      $ U R                  X5      " U6 nUb  XRS'   U$ U$ )a[  Special contraction, i.e., contraction with a different backend
but converting to and from that backend. Retrieves or generates a
cached expression using ``arrays`` as templates, then calls it
with ``arrays``.

If ``evaluate_constants=True``, perform a partial contraction that
prepares the constant tensors and operations with the right backend.
r   )r   r   r  )r0   r   r   r   r   results         r   _contract_with_conversion,ContractExpression._contract_with_conversion  sE     ..wEE--f>G?GJrN   c                 ~   UR                  SS5      nUR                  SS5      n[        X5      nUR                  SS5      nU(       a  [        SR                  U5      5      eU(       a  U R                  OU R
                  n[        U5      U:w  a.  [        SR                  U R
                  [        U5      5      5      eU R                  (       aB  U(       d;  [        U5      U R                  U5      pU V	s/ s H  oc  [        U5      OU	PM     n
n	OUn
 [        R                  " U5      (       a'  [        S	 U 5       5      (       a  U R                  XXES
9$ U R                  XXES
9$ s  sn	f ! [         aF  nUR                   (       a  [#        UR                   5      OSnSR                  U5      4nXl        e SnAff = f)a  Evaluate this expression with a set of arrays.

Parameters
----------
arrays : seq of array
    The arrays to supply as input to the expression.
out : array, optional (default: ``None``)
    If specified, output the result into this array.
backend : str, optional  (default: ``numpy``)
    Perform the contraction with this backend library. If numpy arrays
    are supplied then try to convert them to and from the correct
    backend array type.
r   Nr   r`   r   FzbThe only valid keyword arguments to a `ContractExpression` call are `out=` or `backend=`. Got: {}.zKThis `ContractExpression` takes exactly {} array arguments but received {}.c              3   V   #    U  H  n[        U[        R                  5      v   M!     g 7fr   )rs   npndarrayrb   s     r   r   .ContractExpression.__call__.<locals>.<genexpr>  s!     4_X^STZ2::5N5NX^s   '))r   r<   zInternal error while evaluating `ContractExpression`. Note that few checks are performed - the number and rank of the array arguments must match the original expression. The internal error was: '{}')rl   r   rX   r,   r   r   r=   r   iterr   nextr   has_backendallr
  r  argsrt   )r0   r   r   r   r   r   correct_num_argsops_var	ops_constopopserroriginal_msgmsgs                 r   __call__ContractExpression.__call__  s    jj%**Y/0#ZZ(<eD GGMvf~W W 3E4..$--v;** 006t}}c&k0RT T (:!%ft/L/LW/UYAJK2J4=B6CKCC	 ##G,,4_X^4_1_1_55c5oo>>#G>[[ L  	,/HH3sxx="L228&2FJC H	s&   6E'AE, E, ,
F<6AF77F<c                     U R                   (       a%  SR                  [        U R                   5      5      nOSnSR                  U R                  U5      $ )Nz, constants={}r<   z<ContractExpression('{}'{})>)r   r,   rx   rD   )r0   constants_reprs     r   rL   ContractExpression.__repr__  sD    -44VD<P<P5QRNN-44T5E5E~VVrN   c                    U R                  5       /n[        U R                  5       Hl  u  p#UR                  SR	                  US-   5      5        UR                  SR	                  US   5      US   (       a  SR	                  US   5      OS-   5        Mn     U R
                  (       a*  UR                  SR	                  U R
                  5      5        SR                  U5      $ )	Nz
  {}.  r   z'{}'re   rW   z [{}]r<   z
einsum_kwargs={})rL   r>   r   r@   r,   r   r?   )r0   r   r   cs       r   __str__ContractExpression.__str__  s    ]]_d334DAHH[''A./HHV]]1Q4(QrUGNN1R5,APRST 5 HH)001C1CDEwwqzrN   )	r   r   r   r   r   rD   r   r   r   )r`   )Nr`   F)F)rO   rP   rQ   rR   rS   r2   r   r   r  r  r
  r  rL   r%  rT   r   rN   r   r   r   u  s6    ' 5(	6
4*2hWrN   r   Shapedrn   c                     [        U 5      $ )zVDummy ``numpy.ndarray`` which has a shape only - for generating
contract expressions.
)r'  )rn   s    r   r   r     s     %=rN   c                    UR                  SS5      (       d  [        S5      eS H0  nUR                  US5      c  M  [        SR                  U5      5      e   [        U [        5      (       d  [
        R                  " U 4U-   5      u  pSUS'   UR                  SS	5      nU Vs0 s H  oUX   _M	     nnXbS
'   [        U5       VVs/ s H  u  pWXT;   a  UO
[        U5      PM     nnn[        U /UQ70 UD6$ s  snf s  snnf )a  Generate a reusable expression for a given contraction with
specific shapes, which can, for example, be cached.

Parameters
----------
subscripts : str
    Specifies the subscripts for summation.
shapes : sequence of integer tuples
    Shapes of the arrays to optimize the contraction for.
constants : sequence of int, optional
    The indices of any constant arguments in ``shapes``, in which case the
    actual array should be supplied at that position rather than just a
    shape. If these are specified, then constant parts of the contraction
    between calls will be reused. Additionally, if a GPU-enabled backend is
    used for example, then the constant tensors will be kept on the GPU,
    minimizing transfers.
kwargs :
    Passed on to ``contract_path`` or ``einsum``. See ``contract``.

Returns
-------
expr : ContractExpression
    Callable with signature ``expr(*arrays, out=None, backend='numpy')``
    where the array's shapes should match ``shapes``.

Notes
-----
- The `out` keyword argument should be supplied to the generated expression
  rather than this function.
- The `backend` keyword argument should also be supplied to the generated
  expression. If numpy arrays are supplied, if possible they will be
  converted to and back from the correct backend array type.
- The generated expression will work with any arrays which have
  the same rank (number of dimensions) as the original shapes, however, if
  the actual sizes are different, the expression may no longer be optimal.
- Constant operations will be computed upon the first call with a particular
  backend, then subsequently reused.

Examples
--------

Basic usage:

    >>> expr = contract_expression("ab,bc->ac", (3, 4), (4, 5))
    >>> a, b = np.random.rand(3, 4), np.random.rand(4, 5)
    >>> c = expr(a, b)
    >>> np.allclose(c, a @ b)
    True

Supply ``a`` as a constant:

    >>> expr = contract_expression("ab,bc->ac", a, (4, 5), constants=[0])
    >>> expr
    <ContractExpression('[ab],bc->ac', constants=[0])>

    >>> c = expr(b)
    >>> np.allclose(c, a @ b)
    True

r\   Tz9Can only generate expressions for optimized contractions.)r   r   NzX'{}' should only be specified when calling a `ContractExpression`, not when building it.r   r   r   r   )r   rX   r,   rs   rt   r	   convert_interleaved_inputrl   r>   r   r   )	
subscriptsr+   r   argr   r   r   r   dummy_arrayss	            r   contract_expressionr.     s   z ::j$''TUU!::c4 , KKQ6RU;X X "
 j#&&#==znv>UV
 $F 

;+I,56IqlIN6 . HQQWGXYGXtqAZ]:GXLYJ8888 7 Zs   %C7C<)r   )r`   F)$rS   collectionsr   decimalr   r   r  r<   r   r   r   r	   r
   r   __all__objectr   r[   rj   r   einsum_cache_wrapr   r   transpose_cache_wrapr   tensordot_cache_wrapr   r   r   r   r   r   r   r'  r   r.  r   rN   r   <module>r6     s    #   = =
f8#v 8#v  c m` 	/ /,
 	  	 AXH0 FR 4^ ^B 
Hwi	(R9rN   