o
    ٷi                  
   @   s   d dl mZ d dlmZmZmZmZmZ d dlm	Z	 d dl
mZ d dlmZ edZeeedf ee f Zedd	d
ededeeeef fddZdee d
edeeee f fddZdedefddZdedee d
edee fddZdS )    )	lru_cache)ListSequenceTupleTypeVarUnion)EinopsError)get_backend)ParsedExpressionTensor.   )maxsizepatternopnamereturnc           
   	   C   s   |   }t|}t|t|krtd| d|  dd|vr*td| d|  d|D ]}|dkrIt|\}}|sItd| d| d|  dq,|d}t|| d }|| }	|||	fS )	NzDuplicates in axes names in z(..., "z")*zNo *-axis in zInvalid axis name z in    )splitsetlenr   r
   check_axis_name_return_reasonindex)
r   r   axesaxes_setaxisis_validreasonn_axes_beforen_axes_aftermin_axes r    B/home/ubuntu/.local/lib/python3.10/site-packages/einops/packing.pyanalyze_pattern   s    

r"   tensorsc                 C   s   t |d\}}}t| d }g }g }t| D ]G\}}	||	}
t|
|k r6td| d|
 d| d| d	t|
| }||
||  |||	g |
d| d	|
|d R  q|j||d
|fS )a  
    Packs several tensors into one.
    See einops tutorial for introduction into packing (and how it replaces stack and concatenation).

    Parameters:
        tensors: tensors to be packed, can be of different dimensionality
        pattern: pattern that is shared for all inputs and output, e.g. "i j * k" or "batch seq *"

    Returns:
        (packed_tensor, packed_shapes aka PS)

    Example:
    ```python
    >>> from numpy import zeros as Z
    >>> inputs = [Z([2, 3, 5]), Z([2, 3, 7, 5]), Z([2, 3, 7, 9, 5])]
    >>> packed, ps = pack(inputs, 'i j * k')
    >>> packed.shape, ps
    ((2, 3, 71, 5), [(), (7,), (7, 9)])
    ```

    In this example, axes were matched to: i=2, j=3, k=5 based on order (first, second, and last).
    All other axes were 'packed' and concatenated.
    PS (packed shapes) contains information about axes that were matched to '*' in every input.
    Resulting tensor has as many elements as all inputs in total.

    Packing can be reversed with unpack, which additionally needs PS (packed shapes) to reconstruct order.

    ```python
    >>> inputs_unpacked = unpack(packed, ps, 'i j * k')
    >>> [x.shape for x in inputs_unpacked]
    [(2, 3, 5), (2, 3, 7, 5), (2, 3, 7, 9, 5)]
    ```

    Read the tutorial for introduction and application scenarios.
    packr   zpacked tensor #z' (enumeration starts with 0) has shape z, while pattern z assumes at least z axesN)r   )	r"   r	   	enumerateshaper   r   appendreshapeconcat)r#   r   r   r   r   backendreshaped_tensorspacked_shapesitensorr'   axis_after_packed_axesr    r    r!   r$   !   s$   $
2r$   xc                 C   s   d}| D ]}||9 }q|S )Nr   r    )r1   resultr.   r    r    r!   prodZ   s   
r3   r/   r-   c              
      s  t |dd\}}}t  }t||d | kr&td| d| |}dd |D }tdd	 |D }	|	dkrGtd| d
| ddgt| || g |	dkrot|dd D ]\}
}|
 | |
d < q_n5|d}t|D ]}
|
 ||
  |
d < qxt|d t|ddd D ]}|d  ||  |< q|d| ||d d t	ddf| z fddt|D W S  t
y } ztd| dd  d| |d}~ww )a8  
    Unpacks a single tensor into several by splitting over a selected axes.
    See einops tutorial for introduction into packing (and how it replaces stack and concatenation).

    Parameters:
        tensor: tensor to be unpacked
        packed_shapes: packed_shapes (aka PS) is a list of shapes that take place of '*' in each output.
            output will contain a single tensor for every provided shape
        pattern: pattern that is shared for input and all outputs, e.g. "i j * k" or "batch seq *",
            where * designates an axis to be unpacked

    Returns:
        list of tensors

    If framework supports views, results are views to the original tensor.

    Example:
    ```python
    >>> from numpy import zeros as Z
    >>> inputs = [Z([2, 3, 5]), Z([2, 3, 7, 5]), Z([2, 3, 7, 9, 5])]
    >>> packed, ps = pack(inputs, 'i j * k')
    >>> packed.shape, ps
    ((2, 3, 71, 5), [(), (7,), (7, 9)])
    ```

    In this example, axes were matched to: i=2, j=3, k=5 based on order (first, second, and last).
    All other axes were 'packed' and concatenated.
    PS (packed shapes) contains information about axes that were matched to '*' in every input.
    Resulting tensor has as many elements as all inputs in total.

    Packing can be reversed with unpack, which additionally needs PS (packed shapes) to reconstruct order.

    ```python
    >>> inputs_unpacked = unpack(packed, ps, 'i j * k')
    >>> [x.shape for x in inputs_unpacked]
    [(2, 3, 5), (2, 3, 7, 5), (2, 3, 7, 9, 5)]
    ```

    Read the tutorial for introduction and application scenarios.
    unpack)r   r   zunpack(..., z)) received input of wrong dim with shape c                 S   s    g | ]}d |v r
d nt |qS )r%   )r3   ).0p_shaper    r    r!   
<listcomp>   s     zunpack.<locals>.<listcomp>c                 s   s    | ]	}t |d kV  qdS )r%   N)int)r5   r1   r    r    r!   	<genexpr>   s    zunpack.<locals>.<genexpr>z) received more than one -1 in z and can't infer dimensionsr   Nr%   c                    sJ   g | ]!\}}  g t| |d   R  g |R qS )r   )r)   slice)r5   r.   element_shaper+   	shape_endshape_startslice_fillersplit_positionsr/   r    r!   r7      s    "zError during unpack(..., "z!"): could not split axis of size z into requested )r"   r	   r'   r   r   sumr&   r   ranger:   	Exception)r/   r-   r   r   r   r   input_shapeunpacked_axislengths_of_composed_axesn_unknown_composed_axesr.   r1   unknown_composed_axisjer    r<   r!   r4   a   sN   )


 r4   N)	functoolsr   typingr   r   r   r   r   einopsr   einops._backendsr	   einops.parsingr
   r   r8   Shapestrr"   r$   r3   r4   r    r    r    r!   <module>   s    "&9&