o
    `i!                     @   sp   d dl mZmZ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 dedefd	d
ZG dd dZdS )    )AnyListOptionalDict)EinopsError)ParsedExpressionN   )_productaxesreport_messagec                 C   s   t | dkrt|| d S )Nr   )lenr   format)r
   r    r   S/home/ubuntu/SoloSpeech/.venv/lib/python3.10/site-packages/einops/layers/_einmix.py_report_axes
   s   r   c                	       s   e Zd Zddededee def fddZdededee defdd	Zd
ee dee	 dee dee	 fddZ
dd Zdd Z  ZS )_EinmixMixinNpatternweight_shape
bias_shapeaxes_lengthsc                    s8   t    || _|| _|| _|| _| j||||d dS )a7	  
        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 no 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)
        Multi-head linear layer (each head is own linear layer):
        >>> EinMix('t b (head cin) -> t b (head cout)', weight_shape='head cin cout', ...)

        ... and 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. This accounts 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. A tensor of this shape is created, stored, and optimized in a layer
        :param bias_shape: axes of bias added to output. Weights of this shape are created and stored. If `None` (the default), no bias is added.
        :param axes_lengths: dimensions of weight tensor
        )r   r   r   r   N)super__init__r   r   r   r   initialize_einmix)selfr   r   r   r   	__class__r   r   r      s   
(
z_EinmixMixin.__init__c                    s4  | d\}}t|}t|t|}ttjh |j|jd |js,js,|jr0tdtdd ||fD r@tdd|v sHd|v rOtd	| d }	d }
d }td
d |j	D rg |j	D ]}|7 qdd
}| d| }	fdd  D }
tdd j	D rg j	D ]}|7 qd
}| 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rtd  fdd|j	D }t fdd|j	D }|d urOt|tstdt|}tt|jjd tt|jt d g }j	D ]}|D ]}||jv rE| |  q4|d q4q0nd }d| d }d| d }| |||| h |jj|j}dd ttj|D dtffdd }d!|| || | | _d S )"Nz->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)has_non_unitary_anonymous_axes).0xr   r   r   	<genexpr>M   s    z1_EinmixMixin.initialize_einmix.<locals>.<genexpr>z2Anonymous axes (numbers) are not allowed in EinMix()z,Parenthesis is not allowed in weight shape: c                 s       | ]	}t |d kV  qdS    Nr   r   groupr   r   r   r    U        c                    s   i | ]\}}| v r||qS r   r   )r   namelength)namesr   r   
<dictcomp>[   s    z2_EinmixMixin.initialize_einmix.<locals>.<dictcomp>c                 s   r#   r$   r&   r'   r   r   r   r    ]   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)r   r   r   
<listcomp>s       z2_EinmixMixin.initialize_einmix.<locals>.<listcomp>c                    s    g | ]\}|j vr | qS r   )identifiersr/   )r   rightr   r   r1   u   s     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.      r2   r
   c                    s   d  fdd| D S )N c                 3   s    | ]} | V  qd S r   r   r/   mapping2lettersr   r   r       s    zE_EinmixMixin.initialize_einmix.<locals>.write_flat.<locals>.<genexpr>)join)r
   r9   r   r   
write_flat   s   z2_EinmixMixin.initialize_einmix.<locals>.write_flatz	{},{}->{})splitr   r   set
differencer3   has_ellipsisr   anycompositionr;   items_create_rearrange_layersr   r   warningswarnr	   
isinstancestrappend_create_parameterszipstringascii_lowercaselistflat_axes_ordereinsum_pattern)r   r   r   r   r   left_patternright_patternleftweightpre_reshape_patternpre_reshape_lengthspost_reshape_patternr(   rB   r0   _weight_shape_fan_inbias_bias_shaper
   weight_bound
bias_boundmapped_identifiersr<   r   )r   r:   r-   r4   r   r   A   s   













z_EinmixMixin.initialize_einmixrU   rV   rW   post_reshape_lengthsc                 C      t d)N.Should be defined in framework implementationsNotImplementedError)r   rU   rV   rW   r_   r   r   r   rD      s   z%_EinmixMixin._create_rearrange_layersc                 C   r`   )zShape and implementationsra   rb   )r   r   r\   r   r]   r   r   r   rJ      s   z_EinmixMixin._create_parametersc                 C   sl   t | j}|d| j d7 }| jd ur|d| j d7 }| j D ]\}}|d||7 }q!d| jj|S )Nz, ''z, {}={}z{}({}))	reprr   r   r   r   rC   r   r   __name__)r   paramsr0   r,   r   r   r   __repr__   s   

z_EinmixMixin.__repr__r   )rf   
__module____qualname__rH   r   r   r   dictr   r   rD   rJ   rh   __classcell__r   r   r   r   r      s    $1[
	r   )typingr   r   r   r   einopsr   einops.parsingr   rE   rL   r	   r>   rH   r   r   r   r   r   r   <module>   s    