
    i                        S r SSKrSSKrSSKrSSKrSSKJrJrJr  SSK	r
SSKJr  / SQrSS\" S5      1r " S	 S
\5      rS rS rS rS rS8S jrS rS r\\S.rS rS rS r\\S.r " S S\5      rS8S jr\R@                  " \SS9r!\R@                  " \SS9r"\R@                  " \SS9r#S r$S r%S r&S r'S9S  jr(S:S! jr)S" r*S# r+S$ r,S% r-S& r.S' r/S( r0S) r1 " S* S+\5      r2S8S, jr30 r4\5" SS-5       H  r6\\4\6'   M
     \5" S-S.5       H  r6\!\4\6'   M
     \5" S.S/5       H  r6\"\4\6'   M
     \5" S/S05       H  r6\#\4\6'   M
     S8S1 jr70 r8\5" SS25       H  r6\\8\6'   M
     \5" S2S35       H  r6\3\8\6'   M
     S8S4 jr9\7\9\\!\"\#\)\)\)\3\3S5.r:S6 r;S7 r<g);zT
Contains the path technology behind opt_einsum in addition to several path helpers
    N)CounterOrderedDictdefaultdict   )helpers)	optimalBranchBoundbranchgreedyautoauto_hqget_path_fnDynamicProgrammingdynamic_programminginfc                   (    \ rS rSrSrS rSS jrSrg)PathOptimizer   a  Base class for different path optimizers to inherit from.

Subclassed optimizers should define a call method with signature::

    def __call__(self, inputs, output, size_dict, memory_limit=None):
        """
        Parameters
        ----------
        inputs : list[set[str]]
            The indices of each input array.
        outputs : set[str]
            The output indices
        size_dict : dict[str, int]
            The size of each index
        memory_limit : int, optional
            If given, the maximum allowed memory.
        """
        # ... compute path here ...
        return path

where ``path`` is a list of int-tuples specifiying a contraction order.
c                 p    XU4n[        U S5      (       d  X@l        gX@R                  :w  a  [        S5      eg)zyUtility that stateful optimizers can use to ensure they are not
called with different contractions across separate runs.
_first_call_argszThe arguments specifiying the contraction that this path optimizer instance was called with have changed - try creating a new instance.N)hasattrr   
ValueError)selfinputsoutput	size_dictargss        P/var/www/html/banglarbhumi/venv/lib/python3.13/site-packages/opt_einsum/paths.py_check_args_against_first_call,PathOptimizer._check_args_against_first_call/   sH     	*t/00$(!*** d e e +    Nc                     [         eN)NotImplementedError)r   r   r   r   memory_limits        r   __call__PathOptimizer.__call__;   s    !!r"   )r   r$   )__name__
__module____qualname____firstlineno____doc__r    r'   __static_attributes__ r"   r   r   r      s    .
e"r"   r   c           	        ^ [         R                  " S[        [        [        U 5      5      -   [         R                  S9m/ nU  H>  nUR                  [        U4S jU 5       5      5        U H  nTUS=== S-  sss& M     M@     U$ )z
Convert a path with static single assignment ids to a path with recycled
linear ids. For example::

    >>> ssa_to_linear([(0, 3), (2, 4), (1, 5)])
    [(0, 3), (1, 2), (0, 1)]
r   )dtypec              3   @   >#    U  H  n[        TU   5      v   M     g 7fr$   )int).0ssa_ididss     r   	<genexpr> ssa_to_linear.<locals>.<genexpr>J   s     Av#c&k**   N)nparangemaxmapint32appendtuple)ssa_pathpathssa_idsr5   r6   s       @r   ssa_to_linearrD   ?   sq     ))ACX.//rxx
@CDEAAABFLAL   Kr"   c                 f  ^ [        [        [        U 5      5      [        U 5      -
  S-   n[        [	        U5      5      m[
        R                  " U5      n/ nU  HU  nUR                  [        U4S jU 5       5      5        [        USS9 H  nTU	 M     TR                  [        U5      5        MW     U$ )z
Convert a path with recycled linear ids to a path with static single
assignment ids. For example::

    >>> linear_to_ssa([(0, 3), (1, 2), (0, 1)])
    [(0, 3), (2, 4), (1, 5)]
r   c              3   .   >#    U  H
  nTU   v   M     g 7fr$   r/   )r4   id_linear_to_ssas     r   r7    linear_to_ssa.<locals>.<genexpr>]   s     @CSmC0C   T)reverse)sumr=   lenlistrange	itertoolscountr?   r@   sortednext)rB   
num_inputsnew_idsrA   r6   rG   rH   s         @r   rH   rH   P   s     Sd^$s4y014Jz*+Mooj)GH@C@@A#t,Cc" -T']+	 
 Or"   c           	          X   X   pvXg-  nXg-  n	[         R                  " U/[        U R                  X#U1-
  5      Q76 n
X-  n[        R
                  " XU
-
  SU5      nX4$ )ay  
Calculate the resulting indices and flops for a potential pairwise
contraction - used in the recursive (optimal/branch) algorithms.

Parameters
----------
inputs : tuple[frozenset[str]]
    The indices of each tensor in this contraction, note this includes
    tensors unavaiable to contract as static single assignment is used ->
    contracted tensors are not removed from the list.
output : frozenset[str]
    The set of output indices for the whole contraction.
remaining : frozenset[int]
    The set of indices (corresponding to ``inputs``) of tensors still
    available to contract.
i : int
    Index of potential tensor to contract.
j : int
    Index of potential tensor to contract.
size_dict dict[str, int]
    Size mapping of all the indices.

Returns
-------
k12 : frozenset
    The resulting indices of the potential tensor.
cost : int
    Estimated flop count of operation.
   )	frozensetunionr=   __getitem__r   
flop_count)r   r   	remainingijr   k1k2eithersharedkeepk12costs                r   calc_k12_flopsrf   d   sk    < Y	WFWF??6PC(:(:IA<N$OPD
-CftmQ	BD9r"   c                     [         R                  " [        U R                  U5      6 nXB-
  n[	        U5      n[
        R                  " XEXc5      $ )z
Compute the flop count for a contraction of all remaining arguments. This
is used when a memory limit means that no pairwise contractions can be made.
)rX   rY   r=   rZ   rM   r   r[   )r   r\   r   r   idx_contractioninner	num_termss          r   _compute_oversize_flopsrk      sC    
  oos6+=+=y'IJO$EIIoiKKr"   c                 0  ^^^^^^^ [        [        [        U 5      5      n [        T5      m[        S5      [        [	        [        U 5      5      5      4S.m0 m0 mUUUUUUU4S jmT" SU [        [	        [        U 5      5      5      SS9  [        TS   5      $ )ar  
Computes all possible pair contractions in a depth-first recursive manner,
sieving results based on ``memory_limit`` and the best path found so far.
Returns the lowest cost path. This algorithm scales factoriallly with
respect to the elements in the list ``input_sets``.

Parameters
----------
inputs : list
    List of sets that represent the lhs side of the einsum subscript.
output : set
    Set that represents the rhs side of the overall einsum subscript.
size_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(isets, oset, idx_sizes, 5000)
[(0, 2), (0, 1)]
r   )flopsrA   c           
      >  > [        U5      S:X  a  UTS'   U TS'   g [        R                  " US5       H  u  pEXE:  a  XTpTX$   X%   4n TU   u  pxX8-   n	U	TS   :  a  M+  T[
        ;  a>   TU   n
U
T:  a2  U[        X!TT5      -   n	U	TS   :  a  U	TS'   U [        U5      4-   TS'   Ms  T" XU44-   X'4-   XU1-
  [        U5      1-  U	S9  M     g ! [         a    [	        UTXUT5      =u  pxTU'    Nf = f! [         a    [        R                  " UT5      =n
TU'    Nf = f)Nr   rm   rA   rW   rB   r   r\   rm   )
rM   rP   combinationsKeyErrorrf   _UNLIMITED_MEMr   compute_size_by_dictrk   r@   )rB   r\   r   rm   r]   r^   keyrd   flops12	new_flopssize12_optimal_iteratebestr&   r   result_cache
size_cacher   s              r   rx   !optimal.<locals>._optimal_iterate   s    y>Q!DM#D **9a8DAu19fi(Cn+C0
 IDM) >1\'_F
 L( %(?SY[d(e eI 4=0(1W+/53C2F+FZ( $a&"3$*W$4'0q6'9S[M'I#,.= 9  n3A&&R[`acl3mm|C0n   \/6/K/KCQZ/[[FZ_\s$   C)C3 C0/C03&DDr/   r   ro   rA   )r@   r=   rX   floatrO   rM   setrD   )r   r   r   r&   rx   ry   rz   r{   s    ```@@@@r   r   r      s    > 3y&)*FvF5\eCK6H0I/LMDJL*. *.X "Vs5V;M7NVWXj)**r"   c                     X4X#4:  $ r$   r/   rm   size
best_flops	best_sizes       r   better_flops_firstr      s    =J222r"   c                     X4X24:  $ r$   r/   r   s       r   better_size_firstr      s    =I222r"   rm   r   c                     [         U    $ r$   )_BETTER_FNSrt   s    r   get_better_fnr      s    sr"   c                     X-
  U-
  $ )zhThe default heuristic cost, corresponding to the total reduction in
memory of performing a contraction.
r/   rw   size1size2rd   r_   r`   s         r   cost_memory_removedr     s     >E!!r"   c                 @    [         R                  " SS5      X-
  U-
  -  $ )zqLike memory-removed, but with a slight amount of noise that breaks ties
and thus jumbles the contractions a bit.
g      ?g{Gz?)randomgaussr   s         r   cost_memory_removed_jitterr     s!     <<T"fnu&<==r"   )memory-removedzmemory-removed-jitterc                   <    \ rS rSrSrSS jr\S 5       rS	S jrSr	g)
r	   i  aw  
Explores possible pair contractions in a depth-first recursive manner like
the ``optimal`` approach, but with extra heuristic early pruning of branches
as well sieving by ``memory_limit`` and the best path found so far. Returns
the lowest cost path. This algorithm still scales factorially with respect
to the elements in the list ``input_sets`` if ``nbranch`` is not set, but it
scales exponentially like ``nbranch**len(input_sets)`` otherwise.

Parameters
----------
nbranch : None or int, optional
    How many branches to explore at each contraction step. If None, explore
    all possible branches. If an integer, branch into this many paths at
    each step. Defaults to None.
cutoff_flops_factor : float, optional
    If at any point, a path is doing this much worse than the best path
    found so far was, terminate it. The larger this is made, the more paths
    will be fully explored and the slower the algorithm. Defaults to 4.
minimize : {'flops', 'size'}, optional
    Whether to optimize the path with regard primarily to the total
    estimated flop-count, or the size of the largest intermediate. The
    option not chosen will still be used as a secondary criterion.
cost_fn : callable, optional
    A function that returns a heuristic 'cost' of a potential contraction
    with which to sort candidates. Should have signature
    ``cost_fn(size12, size1, size2, k12, k1, k2)``.
Nc                     Xl         X l        X0l        [        R	                  XD5      U l        [        U5      U l        [        S5      [        S5      S.U l	        [        S 5      U l        g )Nr   r   c                      [        S5      $ )Nr   )r}   r/   r"   r   <lambda>&BranchBound.__init__.<locals>.<lambda>?  s    ur"   )nbranchcutoff_flops_factorminimize	_COST_FNSgetcost_fnr   betterr}   ry   r   best_progress)r   r   r   r   r   s        r   __init__BranchBound.__init__7  sP    #6   }}W6#H-#ElE%LA	()=>r"   c                 2    [        U R                  S   5      $ )NrA   )rD   ry   )r   s    r   rB   BranchBound.pathA  s    TYYz233r"   c                 V  ^ ^^^^^^ T R                  UTT5        [        [        [        U5      5      n[        T5      mU Vs0 s H  oU[        R
                  " UT5      _M     snm0 mUUUUU UU4S jmT" SU[        [        [        U5      5      5      SSS9  T R                  $ s  snf )a^  

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 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(isets, oset, idx_sizes, 5000)
[(0, 2), (0, 1)]
c                 x  >^ ^^^^ [        T5      S:X  a.  TTR                  S'   TTR                  S'   T TR                  S'   g UUUUU UUUUUU4S jn/ n[        R                  " TS5       HU  u  pxXx:  a  XpTU   TU   pU	R	                  U
5      (       a  M-  U" XXx5      nU(       d  M?  [
        R                  " Xk5        MW     U(       dX  [        R                  " TS5       H=  u  pxXx:  a  XpTU   TU   pU" XXx5      nU(       d  M'  [
        R                  " Xk5        M?     SnTR                  b  UTR                  :  aw  U(       ao  [
        R                  " U5      u    pnu  pxnT" T Xx44-   TU4-   TXx1-
  [        T5      1-  UUS9  US-  nTR                  b  UTR                  :  a
  U(       a  Mm  g g g g )	Nr   r   rm   rA   c           	      $  >  TX4   u  pE TU   nTU-   n[	        TU5      nTR                  XxTR                  S   TR                  S   5      (       d  g UTR                  [        T5         :  a  UTR                  [        T5      '   O*UTR                  TR                  [        T5         -  :  a  g T[        ;  aV  UT:  aP  T[        TTTT5      -   nUTR                  S   :  a+  UTR                  S'   T[        T5      4-   TR                  S'   g TTU      TTU      pTR                  XiXX5      nXXxX#4U4$ ! [          a    [        TTTX#T5      =u  pETX4'    GNVf = f! [          a     [        R                  " UT5      =nTU'    GN}f = f)Nrm   r   rA   )rq   rf   r   rs   r<   r   ry   r   rM   r   rr   rk   r@   r   )r_   r`   r]   r^   rd   ru   rw   rv   new_sizer   r   re   rm   r   r&   r   rB   r\   rz   r   r   r{   r   s               r   _assess_candidateHBranchBound.__call__.<locals>._branch_iterate.<locals>._assess_candidateq  s   u#/#7LC\'_F "GO	tV, {{9		'8JDIIV\L]^^ t11#f+>>6?D&&s6{3!9!9D<N<NsSY{<[![[ !6Vl=R %(?	SY[d(e eI 499W#55-6		'*04i8H7K0K		*-  *&)4j6Ku||F5rFiA63FFG   u:HQWYbdejs:ttLC<#7u
   \/6/K/KCQZ/[[FZ_\s"   D= E% =!E"!E"%&FFrW   r   rB   r   r\   rm   r   )	rM   ry   rP   rp   
isdisjointheapqheappushr   heappop)rB   r   r\   rm   r   r   
candidatesr]   r^   r_   r`   	candidatebi_rv   r   rd   _branch_iterater&   r   rz   r   r{   r   s   `````            r   r   -BranchBound.__call__.<locals>._branch_iterateh  s    9~"$(		&!%*		'"(,		*%'G 'GT J!..y!<5qF1IB ==$$-ba;	9NN:9 = %229a@DAu 1#AYq	 1"! ?I yz= A B<<'2+<*9>z9R616A3TaVJ%6'-'7+4v+=#f+*N&/%-	/
 a <<'2+<**+<*+<r"   r/   r   r   )
r    r@   r=   rX   r   rs   r~   rO   rM   rB   )	r   r   r   r   r&   kr   rz   r{   s	   ` ``` @@@r   r'   BranchBound.__call__E  s    6 	++FFIFs9f-.6"MSTV55aCCVT
T	 T	l 	R#eCK>P:QYZabcyyw Us   !B&)ry   r   r   r   r   r   r   )N   rm   r   r$   )
r)   r*   r+   r,   r-   r   propertyrB   r'   r.   r/   r"   r   r	   r	     s&    6? 4 4{r"   r	   c                 *    [        S0 UD6nU" XX#5      $ Nr/   )r	   )r   r   r   r&   optimizer_kwargs	optimizers         r   r
   r
     s    /./IVY==r"   )r   rW   c                     XV-  nXV-  n	X-
  n
X-  XS   -  -  XS   -  -  nU" [         R                  " X5      X5   X6   XU5      nX%   nX&   nX:  a  XnX]4u  p]pnXU4nXXk4$ )N   rW   )r   rs   )r   sizesr\   
footprintsdim_ref_countsr_   r`   r   ra   twoonerd   re   id1id2s                  r   _get_candidater     s    WF
'C
,C?sA%66
73PQAR;R
SC7//;Z^Z^]`fhiD
-C
-C
yB+c>DRr"   c
                    ^ ^^^^^^	 U	UUUU UU4S jU 5       n
U(       a   U
 H  n[         R                  " X{5        M     g [         R                  " U[        U
5      5        g )Nc              3   H   >#    U  H  n[        TTTTTTUT5      v   M     g 7fr$   )r   )	r4   r`   r   r   r   r_   r   r\   r   s	     r   r7   "_push_candidate.<locals>.<genexpr>  s-     vruln.	:~WY[]_fggrus   ")r   r   min)r   r   r\   r   r   r_   k2squeuepush_allr   r   r   s   ``````   `  r   _push_candidater     s>    vvruvJ#INN5, $ 	uc*o.r"   c                 @   U H  n[        X   5      nUS::  a*  US   R                  U5        US   R                  U5        M@  US:X  a*  US   R                  U5        US   R                  U5        Mp  US   R                  U5        US   R                  U5        M     g )Nr   rW   r   )rM   discardadd)dim_to_keysr   dimsdimrQ   s        r   _update_ref_countsr     s    K$%A:1%%c*1%%c*aZ1!!#&1%%c*1!!#&1!!#& r"   c                 R    [         R                  " U 5      u  p#pEX1;  d  XA;  a  gX#XE4$ )zKDefault contraction chooser that simply takes the minimum cost option.
    N)r   r   )r   r\   re   r_   r`   rd   s         r   _simple_chooserr     s0     e,Db	b1Rr"   c                 |  ^^ [        U 5      S:X  a  S/$ [        R                  XD5      nUc	  [        nSnOSn[	        [        [        U 5      5      n [        U5      [        R                  " U 6 -  n0 n[        R                  " [        U 5      5      n/ n[        U 5       H2  u  pX;   a$  UR                  Xj   U	45        [        U5      Xj'   M.  XU
'   M4     [        [        5      mU H"  n
X-
   H  nTU   R                  U
5        M     M$     S V^s0 s H*  mT[        U4S jTR!                  5        5       5      U-
  _M,     nnU V
s0 s H  o["        R$                  " X5      _M     nn
/ nTR!                  5        HK  u  nn['        UUR(                  S9n[        USS	 5       H  u  nnUSU-   S n[+        XXnUUUXU5
        M!     MM     U(       GaT  U" X5      nUc  M  Uu  nnnnUR-                  U5      nUR-                  U5      nUU-
   H  nTU   R/                  U5        M     UU-
   H  nTU   R/                  U5        M     UR                  UU45        UU;   a   UR                  UU   [        U5      45        O UU-
   H  nTU   R                  U5        M     [        U5      UU'   [1        TUUUU-
  -  5        ["        R$                  " UU5      UU'   Un[        U4S
 jU 5       5      nUR3                  U5        U(       a  [+        XXnUUUXU5
        U(       a  GMT  UR!                  5        V
V	s/ s H   u  p["        R$                  " X-  U5      X4PM"     nn
n	[4        R6                  " U5        [4        R8                  " U5      u  nnnU(       a  [4        R8                  " U5      u  nnnUR                  [;        UU5      [=        UU5      45        UU-  U-  n["        R$                  " UU5      n[        U5      n[4        R>                  " UUUU45      u  nnnU(       a  M  U$ s  snf s  sn
f s  sn	n
f )z
This is the core function for :func:`greedy` but produces a path with
static single assignment ids rather than recycled linear ids.
SSA ids are cheaper to work with and easier to reason about.
r   )r   NFT)rW   r   c              3   N   >#    U  H  u  p[        U5      T:  d  M  Uv   M     g 7fr$   )rM   )r4   r   keysrQ   s      r   r7   &ssa_greedy_optimize.<locals>.<genexpr>-  s"     R(;93s4yE?Q33(;s   %	%r   r   c              3   @   >#    U  H  nTU     H  o"v   M     M     g 7fr$   r/   )r4   r   r`   r   s      r   r7   r   V  s     >[-=r"-="r9   ) rM   r   r   r   rN   r=   rX   intersectionrP   rQ   	enumerater?   rS   r   r~   r   itemsr   rs   rR   rZ   r   popremover   r   r   heapifyr   r   r<   heappushpop)r   r   r   	choose_fnr   r   r\   rC   rA   r5   rt   r   rQ   r   r   r   r   r]   r_   r   conre   r`   rd   ssa_id1ssa_id2r   ssa_id12r   s               `               @r   ssa_greedy_optimizer     s     6{aw mmG-G #	  #i()Fv!7!7!@@F Iooc&k*GH (OOY^V45!']IN#cN ) c"K<C  %    E 	sR(9(9(;RRU[[[   LUU9Cw33C??9JU E &&(	Td	 5 56tCRy)EArq1uv,CF9.RTVY[`lst * ) );b"c--#--#;C##B' ;C##B' '*+)OOYs^T'];<V|C $$S) $g	#;R&[8HI!66sEB
3 >>>BF9.RTVY[`lst9 %> bkapaparsarR]RUg**3<?MarEs	MM%]]5)NAw
u-7BWg.GW0EFGBw& ++C7=**5432GH7B % Ow VT ts   1P. P39'P8c           	      Z    U[         ;  a  [        XX#SUS9$ [        XX%US9n[        U5      $ )a%  
Finds the path by a three stage algorithm:

1. Eagerly compute Hadamard products.
2. Greedily compute contractions to maximize ``removed_size``
3. Greedily compute outer products.

This algorithm scales quadratically with respect to the
maximum number of elements sharing a common dim.

Parameters
----------
inputs : list
    List of sets that represent the lhs side of the einsum subscript
output : set
    Set that represents the rhs side of the overall einsum subscript
size_dict : dictionary
    Dictionary of index sizes
memory_limit : int
    The maximum number of elements in a temporary array
choose_fn : callable, optional
    A function that chooses which contraction to perform from the queu
cost_fn : callable, optional
    A function that assigns a potential contraction a cost.

Returns
-------
path : list
    The contraction order (a list of tuples of ints).

Examples
--------
>>> isets = [set('abd'), set('ac'), set('bdc')]
>>> oset = set('')
>>> idx_sizes = {'a': 1, 'b':2, 'c':3, 'd':4}
>>> greedy(isets, oset, idx_sizes)
[(0, 2), (0, 1)]
r   )r   r   )r   r   )rr   r
   r   rD   )r   r   r   r&   r   r   rA   s          r   r   r   j  s9    N >)fiqRYZZ"69YbcH""r"   c                   ^ [        U 5      [        :X  a  / $ U /n / n/ n[        U 5      S:  Ga  U R                  S5      nUR	                  S[        5       5        [        U Vs/ s H  n[        U5      [        :X  d  M  UPM     sn5       H<  mUS==   [        U4S jU 5       5      4-  ss'   UR	                  US   S   T5        M>     U Vs/ s H  n[        U5      [        :w  d  M  UPM     sn H7  mUS==   [        U5      [        U 5      -   4-  ss'   U R                  T5        M9     [        U 5      S:  a  GM  U$ s  snf s  snf )aZ  
Converts a contraction tree to a contraction path as it has to be
returned by path optimizers. A contraction tree can either be an int
(=no contraction) or a tuple containing the terms to be contracted. An
arbitrary number (>= 1) of terms can be contracted at once. Note that
contractions are commutative, e.g. (j, k, l) = (k, l, j). Note that in
general, solutions are not unique.

Parameters
----------
c : tuple or int
    Contraction tree

Returns
-------
path : list[set[int]]
    Contraction path

Examples
--------
>>> _tree_to_sequence(((1,2),(0,(4,5,3))))
[(1, 2), (1, 2, 3), (0, 2), (0, 1)]
r   r   c              3   6   >#    U  H  oT:  d  M
  S v   M     g7fr   Nr/   )r4   qr]   s     r   r7   $_tree_to_sequence.<locals>.<genexpr>  s     /AqQAs   		)	typer3   rM   r   insertr@   rR   rL   r?   )ctsr^   r]   s       `r   _tree_to_sequencer     s   H Aw#~		
A
A
A
a&1*EE"I	EGA8AqaCA89AaDS/A//22DHHQqT"Xq! : 1Q$q'S.!Q1AaDSVc!f_''DHHQK 2 a&1* H 9 2s   "E=EE)Ec                 6   / n[        [        [        U 5      5      5      n[         R                  " U 6 U-
  n[        U5      S:  a  [        5       nUR	                  5       /n[        U5      S:  a  UR	                  5       nUR                  U5        X@U   -  nU V	s1 s H  n	[        XU	   -  5      S:  d  M  U	iM     n
n	UR                  U
5        UR                  U
5        [        U5      S:  a  M  UR                  U5        [        U5      S:  a  M  U$ s  sn	f )a  
Finds disconnected subgraphs in the given list of inputs. Inputs are
connected if they share summation indices. Note: Disconnected subgraphs
can be contracted independently before forming outer products.

Parameters
----------
inputs : list[set]
    List of sets that represent the lhs side of the einsum subscript
output : set
    Set that represents the rhs side of the overall einsum subscript

Returns
-------
subgraphs : list[set[int]]
    List containing sets of indices for each subgraph

Examples
--------
>>> _find_disconnected_subgraphs([set("ab"), set("c"), set("ad")], set("bd"))
[{0, 2}, {1}]

>>> _find_disconnected_subgraphs([set("ab"), set("c"), set("ad")], set("abd"))
[{0}, {1}, {2}]
r   )	r~   rO   rM   rY   r   r   extenddifference_updater?   )r   r   	subgraphsunused_inputsi_sumgr   r^   i_tmpr   ns              r   _find_disconnected_subgraphsr    s    6 Ic&k*+MIIv'E
m
q
 E !!fqjAEE!H1I%E)HMqS1B-Ca-GMAHHHQK++A. !fqj 	 m
q
   Is   D7Dc                 F    S [        U[        U 5      SSS2   5       5       $ )zSelect elements of ``seq`` which are marked by the bitmap set ``s``.

E.g.:

    >>> list(_bitmap_select(0b11010, ['A', 'B', 'C', 'D', 'E']))
    ['B', 'D', 'E']
c              3   :   #    U  H  u  pUS :X  d  M  Uv   M     g7f)1Nr/   )r4   xbs      r   r7   !_bitmap_select.<locals>.<genexpr>
  s     >1$!Q#XAA1s   	Nr   r   )zipbin)r   seqs     r   _bitmap_selectr    s$     ?#c3q6%1R%=1>>r"   c                 |    XU-  -  nU(       a  [         R                  " [        Xc5      6 nO
[        5       nXG-
  nXX-
  $ )zgCalculates the effective outer indices of the intermediate tensor
corresponding to the subgraph ``s``.
)r~   rY   r  )	r   all_tensorsr   r   i1_cut_i2_wo_outputi1_union_i2ri_r
i_contracts	            r   _dp_calc_legsr    s>    
 	
1_Aii23e$*J##r"   c                     X-   [         R                  " X#5      -   nX::  aO  XV-  nUU;  d  XU   S   :  a9  [        XUXU5      n[         R                  " UU5      nUb  UU::  a
  UXU44UU'   gggg)a  Performs the inner comparison of whether the two subgraphs (the bitmaps
``s1`` and ``s2``) should be merged and added to the dynamic programming
search. Will skip for a number of reasons:

1. If the number of operations to form ``s = s1 | s2`` including previous
   contractions is above the cost-cap.
2. If we've already found a better way of making ``s``.
3. If the intermediate tensor corresponding to ``s`` is going to break the
   memory limit.
r   N)r   rs   r  )cost1cost2r  r   cost_caps1s2xnr   r  r   r  r&   cntrct1cntrct2re   r   r]   mems                      r   _dp_compare_flopsr    s     =777OODGB;$Aq/aakZA..q)<C#sl':DG"451 (; * r"   c                     XV-  n[        XXX5      n[        R                  " UU5      n[        XU5      nUU::  a$  X;  d  UX   S   :  a  Ub  UU::  a	  UUX44X'   gggg)zLike ``_dp_compare_flops`` but sieves the potential contraction based
on the size of the intermediate tensor created, rather than the number of
operations, and so calculates that first.
r   N)r  r   rs   r<   )r  r  r  r   r  r  r  r  r   r  r   r  r&   r  r  r   r]   r  re   s                      r   _dp_compare_sizer!  3  s~     	Aaa1DRA

&
&q)
4CuS!Dx;$q/#sl':D7"45 (; * r"   c                 2    [         R                  " S U 5      $ )zqMake a simple left to right binary tree out of iterable ``seq``.

>>> tuple_nest([1, 2, 3, 4])
(((1, 2), 3), 4)

c                     X4$ r$   r/   r  ys     r   r   #simple_tree_tuple.<locals>.<lambda>J  s    !r"   )	functoolsreduce)r  s    r   simple_tree_tupler)  C  s     /55r"   c                 ,   [        U5       VVs1 s H  u  p4X$   S:X  d  M  UiM     nnn/ / / pn[        U 5       HN  u  pX5-
  n
U
(       d  UR                  U	45        M$  UR                  U
5        UR                  X:w  a  U	4OU	5        MP     XgU4$ s  snnf )aA  Take ``inputs`` and parse for single term index operations, i.e. where
an index appears on one tensor and nowhere else.

If a term is completely reduced to a scalar in this way it can be removed
to ``inputs_done``. If only some indices can be summed then add a 'single
term contraction' that will perform this summation.
r   )r   r?   )r   all_inds
ind_countsr]   r   i_singleinputs_parsedinputs_doneinputs_contractionsr^   	i_reduceds              r   _dp_parse_out_single_term_opsr2  M  s     (1H1daZ]a5G1HH68"b 3M&!L	u%   +&&	uAF " '::: Is
   BBc                   ,    \ rS rSrSrSS jrSS jrSrg)	r   id  aU  
Finds the optimal path of pairwise contractions without intermediate outer
products based a dynamic programming approach presented in
Phys. Rev. E 90, 033315 (2014) (the corresponding preprint is publically
available at https://arxiv.org/abs/1304.6112). This method is especially
well-suited in the area of tensor network states, where it usually
outperforms all the other optimization strategies.

This algorithm shows exponential scaling with the number of inputs
in the worst case scenario (see example below). If the graph to be
contracted consists of disconnected subgraphs, the algorithm scales
linearly in the number of disconnected subgraphs and only exponentially
with the number of inputs per subgraph.

Parameters
----------
minimize : {'flops', 'size'}, optional
    Whether to find the contraction that minimizes the number of
    operations or the size of the largest intermediate tensor.
cost_cap : {True, False, int}, optional
    How to implement cost-capping:

        * True - iteratively increase the cost-cap
        * False - implement no cost-cap at all
        * int - use explicit cost cap

search_outer : bool, optional
    In rare circumstances the optimal contraction may involve an outer
    product, this option allows searching such contractions but may well
    slow down the path finding considerably on all but very small graphs.
c                     Xl         [        [        S.U R                      U l        X0l        S S S.U R                     U l        X l        g )Nr   c                     U $ r$   r/   r  s    r   r   -DynamicProgramming.__init__.<locals>.<lambda>  s    Qr"   c                     g)NTr/   r6  s    r   r   r7    s    Dr"   )FT)r   r  r!  _check_contractionsearch_outer_check_outerr  )r   r   r  r:  s       r   r   DynamicProgramming.__init__  sV     !&$#
 --# ) 
 


 !r"   Nc                   ^^%^& [        [        R                  " / TQUP76 5      n[        U5      n[	        U5       VVs0 s H  u  pxX_M	     snnm&T V	s/ s H  n	[        U&4S jU	 5       5      PM     sn	m[        U&4S jU 5       5      nUR                  5        VV
s0 s H  u  pUT&;   d  M  T&U   U
_M     nnn
[        [        U5      5       Vs/ s H  osU   PM	     nn[        TXe5      u  mnm%T(       d  [        [        U5      5      $ UnS/[        U5      -  nU R                  (       a  [        [        [        T5      5      5      /nO[        TU5      nS[        T5      -  S-
  nU GHv  nS/S-  [        [        U5      S-
  5       Vs/ s H  n[        5       PM     sn-   n[        UU%4S jU 5       5      US'   [         R"                  " S S U 5       5      n[
        R$                  " ['        UT5      6 nU R(                  S	L a  [*        R,                  " UU-  U5      nO'U R(                  S
L a  [/        S5      nOU R(                  n[1        [3        [5        UR6                  U5      5      S5      n[        US   5      S:X  Ga   [        S[        US   5      S-   5       H  nUU   n[        SUS-  S-   5       H  nUU   R                  5        H  u  nu  nnnUUU-
     R                  5        Hk  u  nu  nnnUU-  (       a  M  UUU-
  :w  d  UU:  d  M'  UU-  U-
  n U R9                  U 5      (       d  MG  UU-  n!U R;                  UUU!UUUUUUUTU UUU5        Mm     M     M     M     UU-  n[        US   5      S:X  a  GM   [=        US   R?                  5       5      S   u  n	n"n#URA                  U#5        URA                  [*        R,                  " X5      5        GMy     [C        [        [        U5      5      UR6                  S9 Vs/ s H  nX   PM	     nn[        U5      n$[        U$5      $ s  snnf s  sn	f s  sn
nf s  snf s  snf s  snf )a|  
Parameters
----------
inputs : list
    List of sets that represent the lhs side of the einsum subscript
output : set
    Set that represents the rhs side of the overall einsum subscript
size_dict : dictionary
    Dictionary of index sizes
memory_limit : int
    The maximum number of elements in a temporary array

Returns
-------
path : list
    The contraction order (a list of tuples of ints).

Examples
--------
>>> n_in = 3  # exponential scaling
>>> n_out = 2 # linear scaling
>>> s = dict()
>>> i_all = []
>>> for _ in range(n_out):
>>>     i = [set() for _ in range(n_in)]
>>>     for j in range(n_in):
>>>         for k in range(j+1, n_in):
>>>             c = oe.get_symbol(len(s))
>>>             i[j].add(c)
>>>             i[k].add(c)
>>>             s[c] = 2
>>>     i_all.extend(i)
>>> o = DynamicProgramming()
>>> o(i_all, set(), s)
[(1, 2), (0, 4), (1, 2), (0, 2), (0, 1)]
c              3   .   >#    U  H
  nTU   v   M     g 7fr$   r/   r4   r   
symbol2ints     r   r7   .DynamicProgramming.__call__.<locals>.<genexpr>  s     /QjmQrJ   c              3   .   >#    U  H
  nTU   v   M     g 7fr$   r/   r?  s     r   r7   rA    s     3FqZ]FrJ   r   NrW   c              3   D   >#    U  H  nS U-  TU   STU   44v   M     g7f)r   r   Nr/   )r4   r^   r   r0  s     r   r7   rA    s.     [YZTUQA7J17M(NOYZs    c                 
    X-  $ r$   r/   r$  s     r   r   -DynamicProgramming.__call__.<locals>.<lambda>  s    aer"   c              3   ,   #    U  H
  nS U-  v   M     g7fr   r/   )r4   r^   s     r   r7   rA    s     5Haa1fas   TFr   r   r   r   )"r   rP   chainr@   r   r~   r   rO   rM   r2  r   r)  r:  r  dictr   r'  r(  rY   r  r  r   rs   r}   r<   r   r=   rZ   r;  r9  rN   valuesr?   rR   )'r   r   r   r   r&   r,  r+  r^   r   r]   vr/  subgraph_contractionssubgraph_contractions_sizer   r  r   r  subgraph_indsr  cost_incrementr  r  mr  i1r  r  r  i2r  r  r  r  re   contractiontreer0  r@  s'    `                                   @@r   r'   DynamicProgramming.__call__  s"   J Y__=f=f=>
$ (1':;':tqad':;
9?@A#/Q//@3F332;//2CW2C$!qJ%Z]A%2C	W+0Y+@A+@aq\+@	A3PQWYa3n00$%6{%CDD !,&'S3{+;%;"U3v;/01I4VVDI
 CK'1,A 
eCFQJ.?@.?df.?@@A[YZ[[AaD   !35Ha5HIA  II~a'@AM}}$"778NPYZ%' <== S)>)>%N!OQRSNae*/q#ad)a-0A1B #1a1fqj189!

4B 4UG<=a!eHNN<L 8$8R )+Ra1q5jBG;=7f:L$7 (,'8'89L'M'M682g(,(?(?uk[dfnprtv@BA{TZ\o@LgW^)` =M 9E 2	 1, *H4/ ae*/2 $("#7#: At[!((5&--g.J.J1.XYm z E#&@"ABHbHnHno!
o "$o 	 !
 !!67 &&} <@WA> Ah!
s)   P5P;Q .
Q QQQ)r9  r;  r  r   r:  )rm   TFr$   )r)   r*   r+   r,   r-   r   r'   r.   r/   r"   r   r   r   d  s    >!$G'r"   r   c                 *    [        S0 UD6nU" XX#5      $ r   )r   )r   r   r   r&   kwargsr   s         r   r   r      s    ",V,IVY==r"         	      c                 Z    [        U 5      n[        R                  U[        5      " XX#5      $ )zmFinds the contraction path by automatically choosing the method based on
how many input arguments there are.
)rM   _AUTO_CHOICESr   r   )r   r   r   r&   Ns        r   r   r   0  s'     	FAQ'	PPr"         c                 \    SSK Jn  [        U 5      n[        R	                  XT5      " XX#5      $ )zFinds the contraction path by automatically choosing the method based on
how many input arguments there are, but targeting a more generous
amount of search time than ``'auto'``.
r   )random_greedy_128)path_randomra  rM   _AUTO_HQ_CHOICESr   )r   r   r   r&   ra  r]  s         r   r   r   ?  s(    
 /FA5fi^^r"   )r   zauto-hqr   z
branch-allzbranch-2zbranch-1r   eageropportunisticdpzdynamic-programmingc                 z    U [         ;   a  [        SR                  U 5      5      eU[         U R                  5       '   g)zAAdd path finding function ``fn`` as an option with ``name``.
    z#Path optimizer '{}' already exists.N)_PATH_OPTIONSrq   formatlower)namefns     r   register_path_fnrm  Y  s3     }<CCDIJJ"$M$**,r"   c           	          U [         ;  a6  [        SR                  U [        [         R	                  5       5      5      5      e[         U    $ )zBGet the correct path finding function from str ``path_type``.
    z4Path optimizer '{}' not found, valid options are {}.)rh  rq   ri  r~   r   )	path_types    r   r   r   b  sG     %MTTs=--/02 3 	3 ##r"   r$   )Nr   )NNr   )=r-   r'  r   rP   r   collectionsr   r   r   numpyr:    r   __all__r}   rr   objectr   rD   rH   rf   rk   r   r   r   r   r   r   r   r   r	   r
   partial
branch_allbranch_2branch_1r   r   r   r   r   r   r   r  r  r  r  r!  r)  r2  r   r   r\  rO   r]   r   rc  r   rh  rm  r   r/   r"   r   <module>ry     s6       9 9  
 dE%L)%"F %"P"(&RLT+t33
  "> *7	e- eP>
 vt4
VQ/VQ//'k\+#\7t-`?$ 6,6 6;.y' y'x>
 	q!AM! 
	q!A!M! 
	q!AM! 
	q"AM! 
Q  	q!A!Q 
	q"A-Q 
_ 
.%$r"   