a
    d9                      @   sf   d dl mZmZ d dlmZ d dlmZ d dlZd dlZddlm	Z	 e
eddd	ZG d
d dZdS )    )OptionalDict)EinopsError)ParsedExpressionN   )_productaxesZreport_messagec                 C   s   t | dkrt|| d S )Nr   )lenr   formatr    r   ^/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/einops/layers/_einmix.py_report_axes
   s    r   c                       sR   e Zd Zd fdd	Zee ee ee ee dddZdd Zd	d
 Z	  Z
S )_EinmixMixinNc                    sf  t    || _|| _|| _ | _|d\}}t|}t|t|}tt	
jh |j|jd |jszjsz|jrtdtdd ||fD rtdd|v sd|v rtd	| d
}	d
}
d
}tdd |jD r*g |jD ]}|7 qd}| d| }	fdd| j D }
tdd jD rrg jD ]}|7 qJd}| d| }| |	|
|i  |jD ]}| vrtd|qtt	
t	 h |j|jd tt	
|jh |jjd t|jdkrtd  fdd|jD }t fdd|jD }|d
urt|tsPtdt|}tt	
|jjd tt	
|jt	 d g }jD ]8}|D ],}||jv r| |  n
|d qqnd
}d
}d| d }d| d }| |||| h |jj|jdd ttjD tdfd d!}d"||  ||  |  | _!d
S )#a  
        EinMix - Einstein summation with automated tensor management and axis packing/unpacking.

        EinMix is an advanced tool, helpful tutorial:
        https://github.com/arogozhnikov/einops/blob/master/docs/3-einmix-layer.ipynb

        Imagine taking einsum with two arguments, one of each input, and one - tensor with weights
        >>> einsum('time batch channel_in, channel_in channel_out -> time batch channel_out', input, weight)

        This layer manages weights for you, syntax highlights separate role of weight matrix
        >>> EinMix('time batch channel_in -> time batch channel_out', weight_shape='channel_in channel_out')
        But otherwise it is the same einsum under the hood.

        Simple linear layer with bias term (you have one like that in your framework)
        >>> EinMix('t b cin -> t b cout', weight_shape='cin cout', bias_shape='cout', cin=10, cout=20)
        There is restriction to mix the last axis. Let's mix along height
        >>> EinMix('h w c-> hout w c', weight_shape='h hout', bias_shape='hout', h=32, hout=32)
        Channel-wise multiplication (like one used in normalizations)
        >>> EinMix('t b c -> t b c', weight_shape='c', c=128)
        Separate dense layer within each head, no connection between different heads
        >>> EinMix('t b (head cin) -> t b (head cout)', weight_shape='head cin cout', ...)

        ... ah yes, you need to specify all dimensions of weight shape/bias shape in parameters.

        Use cases:
        - when channel dimension is not last, use EinMix, not transposition
        - patch/segment embeddings
        - when need only within-group connections to reduce number of weights and computations
        - perfect as a part of sequential models
        - next-gen MLPs (follow tutorial to learn more)

        Uniform He initialization is applied to weight tensor and encounters for number of elements mixed.

        Parameters
        :param pattern: transformation pattern, left side - dimensions of input, right side - dimensions of output
        :param weight_shape: axes of weight. Tensor od this shape is created, stored, and optimized in a layer
        :param bias_shape: axes of bias added to output.
        :param axes_lengths: dimensions of weight tensor
        z->z7Unrecognized identifiers on the right side of EinMix {}z/Ellipsis is not supported in EinMix (right now)c                 s   s   | ]}|j V  qd S N)Zhas_non_unitary_anonymous_axes).0xr   r   r   	<genexpr>I       z(_EinmixMixin.__init__.<locals>.<genexpr>z2Anonymous axes (numbers) are not allowed in EinMix()z,Parenthesis is not allowed in weight shape: Nc                 s   s   | ]}t |d kV  qdS    Nr
   r   groupr   r   r   r   Q   r    c                    s   i | ]\}}| v r||qS r   r   )r   namelength)namesr   r   
<dictcomp>W   r   z)_EinmixMixin.__init__.<locals>.<dictcomp>c                 s   s   | ]}t |d kV  qdS r   r   r   r   r   r   r   Y   r   z*Dimension {} of weight should be specifiedzAxes {} are not used in patternzWeight axes {} are redundantr   zCEinMix: weight has no dimensions (means multiplication by a number)c                    s   g | ]\} | qS r   r   r   axis)axes_lengthsr   r   
<listcomp>p   r   z)_EinmixMixin.__init__.<locals>.<listcomp>c                    s    g | ]\}|j vr | qS r   )identifiersr!   )r#   rightr   r   r$   r   r   zAbias shape should be string specifying which axes bias depends onz"Bias axes {} not present in outputz#Sizes not provided for bias axes {}r      g      ?c                 S   s   i | ]\}}||qS r   r   )r   letterkr   r   r   r       r   r	   c                    s   d  fdd| D S )N c                 3   s   | ]} | V  qd S r   r   r!   mapping2lettersr   r   r      r   z<_EinmixMixin.__init__.<locals>.write_flat.<locals>.<genexpr>)joinr*   r,   r   r   
write_flat   s    z)_EinmixMixin.__init__.<locals>.write_flatz	{},{}->{})"super__init__patternweight_shape
bias_shaper#   splitr   r   set
differencer%   Zhas_ellipsisr   anycompositionr.   items_create_rearrange_layersr   r
   warningswarnr   
isinstancestrappend_create_parameterszipstringascii_lowercaselistZflat_axes_orderZeinsum_pattern)selfr2   r3   r4   r#   Zleft_patternZright_patternleftZweightpre_reshape_patternpre_reshape_lengthspost_reshape_patternr   r9   r"   Z_weight_shapeZ_fan_inZbiasZ_bias_shaper	   Z_bias_input_sizeweight_bound
bias_boundr/   	__class__)r#   r-   r   r&   r   r1      s    (













z_EinmixMixin.__init__)rH   rI   rJ   post_reshape_lengthsc                 C   s   t dd S )N.Should be defined in framework implementationsNotImplementedError)rF   rH   rI   rJ   rO   r   r   r   r;      s    z%_EinmixMixin._create_rearrange_layersc                 C   s   t ddS )z Shape and implementations rP   NrQ   )rF   r3   rK   r4   rL   r   r   r   rA      s    z_EinmixMixin._create_parametersc                 C   sl   t | j}|d| j d7 }| jd ur8|d| j d7 }| j D ]\}}|d||7 }qBd| jj|S )Nz, ''z, {}={}z{}({}))	reprr2   r3   r4   r#   r:   r   rN   __name__)rF   paramsr"   r   r   r   r   __repr__   s    

z_EinmixMixin.__repr__)N)rU   
__module____qualname__r1   r   r?   r   r;   rA   rW   __classcell__r   r   rM   r   r      s    r   )typingr   r   Zeinopsr   Zeinops.parsingr   r<   rC   r   r6   r?   r   r   r   r   r   r   <module>   s   