U
    /e#                     @   sn   d dl Zd dlmZ d dlmZmZmZ d dlm	Z	 dZ
ee
Zdd Zdd	 Ze	edd
ddddZdS )    N)
basestring)asarray	blockwiseeinsum_lookup)derived_from4abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZc                  O   s\   | d}| d}| d}tt| d }||f| d|i|}||jd|  S )N
subscriptsncontract_indskernel_dtyper   dtype   )popr   dispatchtypeZreshapeshape)operandskwargsr   r	   r   einsumchunk r   :/tmp/pip-unpacked-wheel-dbjnr7gq/dask/array/einsumfuncs.pychunk_einsum   s    


r   c                 C   s  t | dkrtdt| d trt| d dd}dd | dd D } |D ]"}|d	krZqL|tkrLtd
| qLn0t| }g }g }tt | d D ]$}||	d ||	d qt |r|d nd}dd |D } d}t |d }t
|D ]Z\}	}
|
D ]<}|tkr|d7 }n"t|tr2|t| 7 }ntdq |	|kr|d7 }q|dk	r|d7 }|D ]<}|tkr~|d7 }n"t|tr|t| 7 }ntdqfd|ksd|kr|ddkp|ddk}|s|ddkrtdd|kr|dddddd}ttt| }d|}d}d|kr`|d\}}|d}d}n|d}d}t
|D ]\}	}
d|
krv|
ddks|
ddkrtd| |	 jdkrd}n t| |	 jd}|t |
d 8 }||kr|}|dk rtdn:|dkr$|
dd||	< n|| d }|
d|||	< qvd|}|dkr`d}n|| d }|r|d|d| 7 }n|d}|dd}tt|D ]4}|tkrtd
| ||dkr||7 }qdtt|t| }|d| | 7 }d|kr |d\}}nV|}|dd}d}tt|D ]4}|tkrZtd
| ||dkr@||7 }q@|D ]}||krztd| qzt |dt | krtd||| fS )a  
    A reproduction of numpy's _parse_einsum_input()
    which in itself is a reproduction of
    c side einsum parsing in python.

    Returns
    -------
    input_strings : str
        Parsed input strings
    output_string : str
        Parsed output string
    operands : list of array_like
        The operands to use in the numpy contraction
    Examples
    --------
    The operand list is simplified to reduce printing:
    >> 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])
    r   zNo input operands  c                 S   s   g | ]}t |qS r   r   .0or   r   r   
<listcomp>8   s     z&parse_einsum_input.<locals>.<listcomp>r   Nz.,->z#Character %s is not a valid symbol.   c                 S   s   g | ]}t |qS r   r   )r   vr   r   r   r   J   s     z...z=For this input type lists must contain either int or Ellipsis,->->z%Subscripts can only contain one '->'..TF   zInvalid Ellipses.r   zEllipses lengths do not match.z/Output character %s did not appear in the inputzDNumber of einsum subscripts must be equal to the number of operands.)len
ValueError
isinstancer   replaceeinsum_symbols_setlistrangeappendr   	enumerateEllipsisinteinsum_symbols	TypeErrorcountsetjoinsplitr   maxndimsorted)r   r   sZtmp_operandsZoperand_listZsubscript_list_Zoutput_listlastnumsubinvalidusedZunusedZellipse_indslongestZ	input_tmpZ
output_subZsplit_subscriptsZout_subZellipse_countZrep_indsZout_ellipseZoutput_subscriptZtmp_subscriptsZnormal_indsZinput_subscriptscharr   r   r   parse_einsum_input   s    











 









rF   F)r   optimizesplit_everyc              	   O   s  | }t |\}}}d||f}	| dkr<tjdd |D  } |dk	rldd |D }
tj|	f|
d|i\}}dd |d	D }d
d |D }|t| }t|}tt	t
|t
| fdd t||D dd |D | |	|||d|}|dkrt|}|jtt||| |dS |S )a  Dask added an additional keyword-only argument ``split_every``.

    split_every: int >= 2 or dict(axis: int), optional
        Determines the depth of the recursive aggregation.
        Deafults to ``None`` which would let dask heuristically
        decide a good default.
    r$   Nc                 S   s   g | ]
}|j qS r   )r   r   r   r   r   r      s     zeinsum.<locals>.<listcomp>Fc                 S   s$   g | ]}t j|jd |jdqS )r   )r   )npZbroadcast_tor   r   r   r   r   r   r   r      s     rG   c                 S   s   g | ]}t |qS r   )tuple)r   ir   r   r   r      s     r#   c                 S   s   h | ]}|D ]}|qqS r   r   )r   rK   ar   r   r   	<setcomp>   s       zeinsum.<locals>.<setcomp>c                 s   s   | ]}|D ]
}|V  q
qd S )Nr   )r   ZaprL   r   r   r   	<genexpr>   s       zeinsum.<locals>.<genexpr>c                 S   s   i | ]
}|d qS r   r   )r   indr   r   r   
<dictcomp>   s      zeinsum.<locals>.<dictcomp>)Zadjust_chunksr   r   r
   r	   rG   r   )ZaxisrH   )rF   r8   rI   Zresult_typeZeinsum_pathr9   r7   r)   r   r   rJ   zipsumr.   r/   )r   rG   rH   r   r   Zeinsum_dtypeinputsoutputsopsr   Zfake_opsr>   Zall_indsZcontract_indsr	   resultsizer   r   r   r      sD    

 r   )ZnumpyrI   Znumpy.compatr   Zdask.array.corer   r   r   Z
dask.utilsr   r4   r7   r-   r   rF   r   r   r   r   r   <module>   s    +