a
    dl                     @   s6  U d dl Z d dlZd dlZd dlmZ d dlmZmZmZmZm	Z	m
Z
mZ ejrXd dlZddlmZ ddlmZ ddlmZmZmZ edZe	eee gef Zeeef Zd	Zd
gZee ed< dZee e dddZ!ee edddZ"eee dddZ#dd Z$eee ee ee eeef ee f Z%G dd dZ&e&ee e%dddZ'e (de'Z)e&eeeddd Z*e (d!eeeed"f e&d#d$d%Z+eeeeed&d'd(Z,ej-eeeed)d*d+Z.ej-ee eeed,d-d+Z.ed.d/d+Z.eeed0d1d2Z/ed.d3d4Z0d5d6 Z1d7d8d9d:Z2dS );    N)OrderedDict)TupleListDictUnionCallableOptionalTypeVar   )EinopsError)get_backend)ParsedExpression	_ellipsisAnonymousAxisTensor)minmaxsummeanprod_ellipsis_not_in_parenthesisi)groupreturnc                 C   s   t | dkrdS | d dkS )Nr
   Fr   r   )len)r    r   V/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/einops/einops.pyis_ellipsis_not_in_parenthesis   s    r   )sequencer   c                 C   s   d}| D ]}||9 }q|S )zU minimalistic product that works both with numbers and symbols. Supports empty lists r
   r   )r   resultelementr   r   r   _product   s    
r!   )reduction_typereduced_axesc                 C   sb   t |}t|r|| |S t|dkr*| S |tv s6J |dkrP|| sPtd|| ||S d S )Nr   r   z5reduce_mean is not available for non-floating tensors)tuplecallabler   _reductionsZis_float_typeNotImplementedErrorreduce)tensorr"   r#   backendr   r   r   _reduce_axes%   s    

r+   c                    s  t  t  t ksJ tttt d d d d D ]}| d |d  krB|d   }d  d d   d   |9  < d |d  tdd |d d  D  qB fdd}| }tt d d d d D ]}|| d u rq||d  d u r0q|| d ||d  kr|d  }tfddtD }	tfd	dD d  d d   d   |9  <  }
g  |
D ]6}||	krn$||	k r | n |d  q| }q |fS )
Nr
   c                 s   s   | ]}|d  V  qdS r
   Nr   .0axisr   r   r   	<genexpr>B       z+_optimize_transformation.<locals>.<genexpr>   c                     sT   i } t tD ]>}|v r&d | |< qtdd |  D }t || |< q| S )Nc                 s   s   | ]}|d uV  qd S Nr   r/   xr   r   r   r1   K   r2   zB_optimize_transformation.<locals>.build_mapping.<locals>.<genexpr>)ranger   r   valueslistindex)Zinit_to_finalr0   Zafter_reduction)axes_reorderinginit_shapesr#   r   r   build_mappingE   s    
z/_optimize_transformation.<locals>.build_mappingc                 3   s   | ]}| vV  qd S r4   r   r5   )r#   r   r   r1   Y   r2   c                 3   s"   | ]}| k r|n|d  V  qdS r-   r   r.   )removed_axisr   r   r1   [   r2   )r   r$   sortedr7   r   append)r<   r#   r;   final_shapesiZremoved_lengthr=   Zinit_axis_to_final_axisZ	init_axisZremoved_axis_after_reductionZold_reorderingr0   r   )r;   r<   r#   r>   r   _optimize_transformation5   sB    0
 


rC   c                	   @   s`   e Zd ZdZdee eeee ee f  ee ee eeef eee  ee dddZ	dS )TransformRecipezi
    Recipe describes actual computation pathway.
    Recipe can be applied to a tensor or variable.
    Nelementary_axes_lengthsinput_composite_axesreduced_elementary_axesaxes_permutation
added_axesoutput_composite_axesellipsis_position_in_lhsc                 C   s:   || _ || _|| _|| _|| _|| _|d ur0|nd| _d S )N'  )rF   rG   rK   rI   rJ   rH   rL   )selfrF   rG   rH   rI   rJ   rK   rL   r   r   r   __init__w   s    zTransformRecipe.__init__)N)
__name__
__module____qualname____doc__r   intr   r   r   rO   r   r   r   r   rD   o   s    

rD   )rN   shaper   c                    s~  t | j | jdkrJt|t| jd k rvtdt| jd t|n,t|t| jkrvtdt| jt|g }t| jD ]Z\}\}}|}|t| t| j }|| jkrt|dkrt|dksJ |\}|||d  }|D ]}	|	du rtdqt|}
|
 |< q|| jk r,|| }n|| }d}|D ]}| | 9 }q<t|dkrt	|t
rt	|t
r||krtd||qt	|t
rt	|t
r|| dkrtd	|||d }|| }| |< q dt t| j  }g }t| jD ]@\}}t|r(|| n  fd
d|D }|t| q
| j}| j} fdd| j D }|||||fS )z
    Reconstruct all actual parameters using shape.
    Shape is a tuple that may contain integers, shape symbols (tf, keras, theano) and UnknownSize (keras, mxnet)
    known axes can be integers or symbols, but not Nones.
    rM   r
   z'Expected at least {} dimensions, got {}zExpected {} dimensions, got {}r   NzACouldn't infer shape for one or more axes represented by ellipsiszShape mismatch, {} != {}z>Shape mismatch, can't divide axis of length {} in chunks of {}c                    s   g | ]} | qS r   r   )r/   elementary_axisaxes_lengthsr   r   
<listcomp>   r2   z4_reconstruct_from_shape_uncached.<locals>.<listcomp>c                    s   i | ]\}}| | qS r   r   )r/   posZpos_in_elementaryrW   r   r   
<dictcomp>   s   z4_reconstruct_from_shape_uncached.<locals>.<dictcomp>)r9   rF   rL   r   rG   r   format	enumerater!   
isinstancerT   rJ   rK   r   extendr@   rH   rI   items)rN   rU   Zellipsis_shapeZ
input_axisZ
known_axesZunknown_axesZbefore_ellipsisZafter_ellipsisZunknown_axisdZtotal_dim_sizelengthZknown_productr0   Zinferred_lengthr<   rA   Zoutput_axisgroupinglengthsr#   r;   rJ   r   rW   r    _reconstruct_from_shape_uncached   sd    




"&


re   i   )reciper)   r"   r   c           	      C   s~   t |}t| ||\}}}}}|||}t||||d}|||}t|dkrr|j|t|t| |d}|||S )N)r"   r#   r*   r   )Zn_axesZpos2len)r   _reconstruct_from_shaperU   reshaper+   Z	transposer   Zadd_axes)	rf   r)   r"   r*   r<   r#   r;   rJ   rA   r   r   r   _apply_recipe   s    ri      .)pattern	operationrX   r   c              	      s  |  d\ttjs8jr8td| jrRjrRtd| |dkrtjj}j	svj	r~tdt
|dkrtd|n|dkrtjj}t
|dkrtd	|td
d jD h jdd |D }t
|dkrltd|nT|tv s,t|r\tjj}t
|dkrltd||ntd|tt  jD ]2}|D ]&}t|tr|j |< nt |< qqxg }jD ]:}| vrt|tr|j |< nt |< || qdd t D fdd D }tt|}|D ]@\}	}
t|	sHtd|	|	 vr`td|	|
 |	< q*g }jD ]} fdd|D } fdd|D }t
|dkrtd|t
|t
| t
|ksJ |fdd|D fdd|D f qvi tjj D ]}|jv rt
|< qg }jD ]4}|tkrZ|t n|fdd|D  q@ttjj }fdd|D }fddt|D }tjvrd n
jt}tt   ||||||d!S )"z Perform initial parsing of pattern and provided supplementary info
    axes_lengths is a tuple of tuples (axis_name, axis_length)
    z->z?Ellipsis found in left side, but not right side of a pattern {}z;Ellipsis is parenthesis in the left side is not allowed: {}	rearrangezQNon-unitary anonymous axes are not supported in rearrange (exception is length 1)r   zBIdentifiers only on one side of expression (should be on both): {}repeatz5Unexpected identifiers on the left side of repeat: {}c                 S   s   h | ]}t |ts|qS r   )r^   r   )r/   axr   r   r   	<setcomp>  r2   z1_prepare_transformation_recipe.<locals>.<setcomp>c                 s   s   | ]\}}|V  qd S r4   r   )r/   ro   _r   r   r   r1     r2   z1_prepare_transformation_recipe.<locals>.<genexpr>z(Specify sizes for new axes in repeat: {}z9Unexpected identifiers on the right side of reduce {}: {}z'Unknown reduction {}. Expect one of {}.c                 S   s   i | ]\}}||qS r   r   )r/   positionnamer   r   r   r[   +  r2   z2_prepare_transformation_recipe.<locals>.<dictcomp>c                    s   g | ]\}}| j vr|qS r   identifiers)r/   r0   rr   )rghtr   r   rY   ,  s   
z2_prepare_transformation_recipe.<locals>.<listcomp>zInvalid name for an axisz Axis {} is not used in transformc                    s   h | ]} | t kr|qS r   _unknown_axis_lengthr.   axis_name2known_lengthr   r   rp   :  r2   c                    s   h | ]} | t kr|qS r   rw   r.   ry   r   r   rp   ;  r2   r
   zCould not infer sizes for {}c                    s   g | ]} | qS r   r   r.   axis_name2positionr   r   rY   @  r2   c                    s   g | ]} | qS r   r   r.   r{   r   r   rY   A  r2   c                    s   g | ]} | qS r   r   r.   r{   r   r   rY   N  r2   c                    s   g | ]}|j v r | qS r   rt   r.   )axis_position_after_reductionleftr   r   rY   Q  s   c                    s$   i | ]\}}|j vr| | qS r   rt   )r/   rB   	axis_name)r|   r~   r   r   r[   S  s   
NrE   )!splitr   has_ellipsisr   r\   Zhas_ellipsis_parenthesizedsetsymmetric_differenceru   Zhas_non_unitary_anonymous_axesr   
differencer&   r%   r   compositionr^   r   valuerx   r@   r]   r`   r9   r?   Zcheck_axis_name	itertoolschainr   r   r:   rD   r8   )rk   rl   rX   r   Zaxes_without_sizeZcomposite_axisr   Zrepeat_axes_namesr#   rV   axis_lengthZinput_axes_known_unknownZknownunknownZresult_axes_groupingZordered_axis_rightrI   rJ   Zellipsis_leftr   )rz   r|   r}   r~   rv   r   _prepare_transformation_recipe   s    









r   )r)   rk   	reductionrX   r   c              
   K   s   z.t t| }t|||d}t|| |dW S  ty } zdd||}t| tsn|dt	| 
| 7 }n|d7 }|d|7 }t|d| W Y d}~n
d}~0 0 dS )	a  
    einops.reduce provides combination of reordering and reduction using reader-friendly notation.

    Examples for reduce operation:

    ```python
    >>> x = np.random.randn(100, 32, 64)

    # perform max-reduction on the first axis
    >>> y = reduce(x, 't b c -> b c', 'max')

    # same as previous, but with clearer axes meaning
    >>> y = reduce(x, 'time batch channel -> batch channel', 'max')

    >>> x = np.random.randn(10, 20, 30, 40)

    # 2d max-pooling with kernel size = 2 * 2 for image processing
    >>> y1 = reduce(x, 'b c (h1 h2) (w1 w2) -> b c h1 w1', 'max', h2=2, w2=2)

    # if one wants to go back to the original height and width, depth-to-space trick can be applied
    >>> y2 = rearrange(y1, 'b (c h2 w2) h1 w1 -> b c (h1 h2) (w1 w2)', h2=2, w2=2)
    >>> assert parse_shape(x, 'b _ h w') == parse_shape(y2, 'b _ h w')

    # Adaptive 2d max-pooling to 3 * 4 grid
    >>> reduce(x, 'b c (h1 h2) (w1 w2) -> b c h1 w1', 'max', h1=3, w1=4).shape
    (10, 20, 3, 4)

    # Global average pooling
    >>> reduce(x, 'b c h w -> b c', 'mean').shape
    (10, 20)

    # Subtracting mean over batch for each channel
    >>> y = x - reduce(x, 'b c h w -> () c () ()', 'mean')

    # Subtracting per-image mean for each channel
    >>> y = x - reduce(x, 'b c h w -> b c () ()', 'mean')

    ```

    Parameters:
        tensor: tensor: tensor of any supported library (e.g. numpy.ndarray, tensorflow, pytorch, mxnet.ndarray).
            list of tensors is also accepted, those should be of the same type and shape
        pattern: string, reduction pattern
        reduction: one of available reductions ('min', 'max', 'sum', 'mean', 'prod'), case-sensitive
            alternatively, a callable f(tensor, reduced_axes) -> tensor can be provided.
            This allows using various reductions, examples: np.max, tf.reduce_logsumexp, torch.var, etc.
        axes_lengths: any additional specifications for dimensions

    Returns:
        tensor of the same type as input
    rW   )r"   z2 Error while processing {}-reduction pattern "{}".z
 Input tensor shape: {}. z
 Input is list. zAdditional info: {}.z
 {}N)r$   r?   r`   r   ri   r   r\   r^   r9   r   rU   )r)   rk   r   rX   Zhashable_axes_lengthsrf   emessager   r   r   r(   c  s    4
r(   )r)   rk   axes_lengthr   c                 K   s   d S r4   r   )r)   rk   r   r   r   r   rm     s    rm   )r)   rk   rX   r   c                 K   s   d S r4   r   r)   rk   rX   r   r   r   rm     s    )rk   c                 K   sF   t | tr0t| dkrtdt| d | } t| |fddi|S )a(  
    einops.rearrange is a reader-friendly smart element reordering for multidimensional tensors.
    This operation includes functionality of transpose (axes permutation), reshape (view), squeeze, unsqueeze,
    stack, concatenate and other operations.

    Examples for rearrange operation:

    ```python
    # suppose we have a set of 32 images in "h w c" format (height-width-channel)
    >>> images = [np.random.randn(30, 40, 3) for _ in range(32)]

    # stack along first (batch) axis, output is a single array
    >>> rearrange(images, 'b h w c -> b h w c').shape
    (32, 30, 40, 3)

    # concatenate images along height (vertical axis), 960 = 32 * 30
    >>> rearrange(images, 'b h w c -> (b h) w c').shape
    (960, 40, 3)

    # concatenated images along horizontal axis, 1280 = 32 * 40
    >>> rearrange(images, 'b h w c -> h (b w) c').shape
    (30, 1280, 3)

    # reordered axes to "b c h w" format for deep learning
    >>> rearrange(images, 'b h w c -> b c h w').shape
    (32, 3, 30, 40)

    # flattened each image into a vector, 3600 = 30 * 40 * 3
    >>> rearrange(images, 'b h w c -> b (c h w)').shape
    (32, 3600)

    # split each image into 4 smaller (top-left, top-right, bottom-left, bottom-right), 128 = 32 * 2 * 2
    >>> rearrange(images, 'b (h1 h) (w1 w) c -> (b h1 w1) h w c', h1=2, w1=2).shape
    (128, 15, 20, 3)

    # space-to-depth operation
    >>> rearrange(images, 'b (h h1) (w w1) c -> b h w (c h1 w1)', h1=2, w1=2).shape
    (32, 15, 20, 12)

    ```

    When composing axes, C-order enumeration used (consecutive elements have different last axis)
    Find more examples in einops tutorial.

    Parameters:
        tensor: tensor of any supported library (e.g. numpy.ndarray, tensorflow, pytorch, mxnet.ndarray).
                list of tensors is also accepted, those should be of the same type and shape
        pattern: string, rearrangement pattern
        axes_lengths: any additional specifications for dimensions

    Returns:
        tensor of the same type as input. If possible, a view to the original tensor is returned.

    r   z+Rearrange can't be applied to an empty listr   rm   )r^   r9   r   	TypeErrorr   Zstack_on_zeroth_dimensionr(   r   r   r   r   rm     s
    7
)r)   rk   r   c                 K   s   t | |fddi|S )a  
    einops.repeat allows reordering elements and repeating them in arbitrary combinations.
    This operation includes functionality of repeat, tile, broadcast functions.

    Examples for repeat operation:

    ```python
    # a grayscale image (of shape height x width)
    >>> image = np.random.randn(30, 40)

    # change it to RGB format by repeating in each channel
    >>> repeat(image, 'h w -> h w c', c=3).shape
    (30, 40, 3)

    # repeat image 2 times along height (vertical axis)
    >>> repeat(image, 'h w -> (repeat h) w', repeat=2).shape
    (60, 40)

    # repeat image 2 time along height and 3 times along width
    >>> repeat(image, 'h w -> h (repeat w)', repeat=3).shape
    (30, 120)

    # convert each pixel to a small square 2x2. Upsample image by 2x
    >>> repeat(image, 'h w -> (h h2) (w w2)', h2=2, w2=2).shape
    (60, 80)

    # pixelate image first by downsampling by 2x, then upsampling
    >>> downsampled = reduce(image, '(h h2) (w w2) -> h w', 'mean', h2=2, w2=2)
    >>> repeat(downsampled, 'h w -> (h h2) (w w2)', h2=2, w2=2).shape
    (30, 40)

    ```

    When composing axes, C-order enumeration used (consecutive elements have different last axis)
    Find more examples in einops tutorial.

    Parameters:
        tensor: tensor of any supported library (e.g. numpy.ndarray, tensorflow, pytorch, mxnet.ndarray).
            list of tensors is also accepted, those should be of the same type and shape
        pattern: string, rearrangement pattern
        axes_lengths: any additional specifications for dimensions

    Returns:
        Tensor of the same type as input. If possible, a view to the original tensor is returned.

    r   rn   )r(   r   r   r   r   rn     s    /rn   c           	      C   s  t |dd}t| | }| r4tdj||dt|t|jkr|jrvt|t|jd k rtdj||dntdj||d|jr|j	t
}|jd| d	gt|t|j d   |j|d d  }n|j}i }t||D ]\\}}|d	kr|||< q|S )
a  
    Parse a tensor shape to dictionary mapping axes names to their lengths.

    ```python
    # Use underscore to skip the dimension in parsing.
    >>> x = np.zeros([2, 3, 5, 7])
    >>> parse_shape(x, 'batch _ h w')
    {'batch': 2, 'h': 5, 'w': 7}

    # `parse_shape` output can be used to specify axes_lengths for other operations:
    >>> y = np.zeros([700])
    >>> rearrange(y, '(b c h w) -> b c h w', **parse_shape(x, 'b _ h w')).shape
    (2, 10, 5, 7)

    ```

    For symbolic frameworks may return symbols, not integers.

    Parameters:
        x: tensor of any of supported frameworks
        pattern: str, space separated names for axes, underscore means skip axis

    Returns:
        dict, maps axes names to their lengths
    T)Zallow_underscorez8Can't parse shape with composite axes: {pattern} {shape})rk   rU   r
   zCCan't parse shape with this number of dimensions: {pattern} {shape}zHCan't parse shape with different number of dimensions: {pattern} {shape}Nrq   )r   r   rU   Zhas_composed_axesRuntimeErrorr\   r   r   r   r:   r   zip)	r6   rk   exprU   Zellipsis_idxr   r   r   r   r   r   r   parse_shape  s8    

r   c              	   C   s\   t | }|| }g }t|D ]8\}}dgt| }|||< |||d|| q|S )aa  
    For an n-dimensional tensor, returns tensors to enumerate each axis.
    ```python
    x = np.zeros([2, 3, 4]) # or any other tensor
    i, j, k = _enumerate_directions(x)
    result = i + 2*j + 3*k
    ```

    `result[i, j, k] = i + 2j + 3k`, and also has the same shape as result
    Works very similarly to numpy.ogrid (open indexing grid)
    r
   r   )r   rU   r]   r   r@   rh   Zarange)r6   r*   rU   r   Zaxis_idr   r   r   r   _enumerate_directionsR  s    
r   znumpy.ndarray)r   c                 C   s   t | | S )z
    Convert a tensor of an imperative framework (i.e. numpy/cupy/torch/gluon/etc.) to `numpy.ndarray`

    Parameters:
        tensor: tensor of any of known imperative framework

    Returns:
        `numpy.ndarray`, converted to numpy
    )r   Zto_numpy)r)   r   r   r   asnumpyh  s    
r   )3	functoolsr   typingcollectionsr   r   r   r   r   r   r   r	   TYPE_CHECKINGnumpynp r   Z	_backendsr   Zparsingr   r   r   r   rT   ZReductionCallablestrZ	Reductionr&   r   __annotations__rx   boolr   r!   r+   rC   ZCookedReciperD   re   	lru_cacherg   ri   r   r(   overloadrm   rn   r   r   r   r   r   r   r   <module>   sN   
$7*'LpC>26