o
    Ein1                     @   s  d dl Z ddlmZ d dlZd dlmZ d dlmZm	Z	m
Z
mZ d dlmZ ddgZe jdd	 d
d$ddZe jddddZe jje jdd	 d
ddi ddede jdede
e jedf dede	dejfddZee_e jj		d%dede jde
e jedf dedejf
ddZe jj		d%dede jde
eee f de
e jedf dedejfddZe jj		d%dede jde
e jedf dedejf
d d!Ze jj		d%dede jde
e jedf dedejf
d"d#ZdS )&    N   )util)partial)CallableMappingUnionTuplerollflipc                    s   i d f fdd	S )Nc                    s    | fdd|D |||S )Nc                       g | ]} |qS  r   .0xtr   S/home/ubuntu/veenaModal/venv/lib/python3.10/site-packages/einx/op/vmap_with_axis.py
<listcomp>       .<lambda>.<locals>.<lambda>.<locals>.<listcomp>r   )exprs_in
tensors_in	exprs_outopkwargsbackendcr   r   r   <lambda>   s    <lambda>.<locals>.<lambda>r   r   r   r   r   r   r      r   r   )tracec                    s  |d u ri }t | t |krtdt |  dt | t t|dkr(tdt| t| D ]}| D ]}t|tjjj	rDtdq6q0t |dkrPtdtdd |D r]td	i |}fd
dt
|| D }|}tj| |d\} }dd | D fddt|}fdd|D t | dk}	dd fddt| t D }
t| t D ]}|D ]}|j|
v |krtd|j dqqdd | D 	dd D }|	rtd|	r'	|krtdfddt
| |D }dd |D }dd |D } t dd | D dksJ dd | D 	nt | dks0J | d  fd!d"

fd#dD |	rVt	fd$dtd  D }nd%d | D  t 	fd&dtt  d  D }t |d krt |dkr|n|d  |d'< t|trt|}nt|tjjs|fd(d)}||i |}t|ttfs|f}t |t krtdt  d*t | fd+dt
||D }tj|||d}||fS ),N	Expected z input tensor(s), got r   z'All output expressions must be the samezConcatenation not allowedzOnly one output tensor allowedc                 s   s    | ]	}t j|V  qd S N)einxtracer	is_scalarr   tensorr   r   r   	<genexpr>   s    z(vmap_with_axis_stage3.<locals>.<genexpr>z.At least one input tensor must be a non-scalarc                    s$   g | ]\}}t jj||j d qS )r   )r$   r%   call_factoryshape)r   r(   exprr*   r   r   r   "   s    z)vmap_with_axis_stage3.<locals>.<listcomp>r*   c                 S   s   h | ]
}|D ]}|j qqS r   name)r   r-   axisr   r   r   	<setcomp>*   s    z(vmap_with_axis_stage3.<locals>.<setcomp>c                    s   t | tjjjo| j vS r#   
isinstancer$   r-   stage3Axisr/   r-   )in_axis_namesr   r   is_broadcast_axis,   s   z0vmap_with_axis_stage3.<locals>.is_broadcast_axisc                    s   g | ]
}t jj| qS r   )r$   r-   r4   remover   r-   )r8   r   r   r   0   s    c                 S   s   t jj|  S r#   )r$   r-   r4   	is_markedr6   r   r   r   
is_vmapped7   s   z)vmap_with_axis_stage3.<locals>.is_vmappedc                    s$   h | ]}|D ]	} |r|j qqS r   r.   )r   rootv)r<   r   r   r1   :   s    zAxis z( appears both as vmapped and non-vmappedc                 S   >   h | ]}|  D ]}t|tjjjrtjj|r|jqqS r   allr3   r$   r-   r4   r5   r;   r/   r   expr_inr0   r   r   r   r1   E       c                 S   r?   r   r@   )r   expr_outr0   r   r   r   r1   K   rD   z8Marked output axes must be a subset of marked input axeszMWhen using multiple input tensors the same axes must be marked in all tensorsc              	      s<   g | ]\}}t j|r||fntj||d  d dqS )r   F)	broadcastr   )r$   r%   r&   r   transpose_broadcast)r   rC   	tensor_in)r    exprs_out_flat_without_broadcastr   r   r   Z   s    


c                 S      g | ]}|d  qS r   r   r   r   r   r   r   f   r   c                 S   rJ   )r   r   r   r   r   r   r   g   r   c                 S   s    h | ]}t |d krt |qS rK   )lenr:   r   r   r   r1   h   s     c                 S   r?   r   r@   rB   r   r   r   r1   i   rD   r   c                    sp   dd |   D }g }   D ] }t|tjjjr/|j|v r/t|jtjjjr*|j}|	| qtjjj
|S )Nc                 S   s"   h | ]}t |tjjjr|jqS r   r2   )r   r0   r   r   r   r1   u   s    z>vmap_with_axis_stage3.<locals>.to_op_output.<locals>.<setcomp>)rA   r3   r$   r-   r4   r5   r/   parentMarkerappendListmaybe)expr_out_flat_wb
axis_namesnew_axesr0   )rC   r   r   to_op_outputt   s   
z+vmap_with_axis_stage3.<locals>.to_op_outputc                    r   r   r   )r   rR   )rU   r   r   r      s    c                 3   s"    | ]\}}|j  v r|V  qd S r#   r.   )r   ir0   )marked_input_axesr   r   r)      s    
c                 S   s   g | ]}t |qS r   )listr:   r   r   r   r      r   c                 3   s,    | ] t  fd dD r V  qdS )c                 3   s    | ]
}|  j v V  qd S r#   r.   )r   axes_in)rV   rW   r   r   r)      s    z2vmap_with_axis_stage3.<locals>.<genexpr>.<genexpr>N)any)r   )rY   rW   )rV   r   r)      s    
r0   c                     s@   t jj | |tdkrdd D dS t jd jdS )Nr   c                 S   s   g | ]	}t j|jqS r   )r$   r%   Tensorr,   r:   r   r   r   r      s    z;vmap_with_axis_stage3.<locals>.<lambda>.<locals>.<listcomp>r   )argsr   output)r$   r%   applyrL   r[   r,   )r\   r   )concrete_opexprs_op_outputr   r   r      s    z'vmap_with_axis_stage3.<locals>.<lambda>z output tensor(s), got c                    s(   g | ]\}}}t j||| d d qS )r*   r   )r   rG   )r   rC   
tensor_outrE   r*   r   r   r      s    )rL   
ValueErrorsetrX   rA   r3   r$   r-   r4   Concatenationzipall_to_tensorr   flattenr/   
differencetuple	enumeraterangestrgetattrr%   Tracer	unflatten)r   r   r   r   r   r   r=   r-   exprs_out_flattranspose_firstvmapped_axis_namesr>   marked_output_axesr   axis_indicestensors_outr   )rY   r   r_   rC   r`   rI   r7   r8   r<   rW   rU   r   vmap_with_axis_stage3   s   









	

rv   T)csec                O   s  t jj| |\} }t jj| }t|dkr&t jj|d |d 	 g}t|d t|kr@t
dt|d  dt| t jjdd t|d |D dd |d D  dd | D  |d	d
d t|d t|d   }|d t|d  |t|d d  }}||fS )Nr   r   r"   z input tensors, but got c                 S   s   g | ]\}}t j||qS r   r$   r-   Equation)r   rC   tensor_shaper   r   r   r      s    zparse.<locals>.<listcomp>c                 S      g | ]}t j|qS r   rx   )r   rE   r   r   r   r          c                 S   s4   g | ]\}}t jj|t|d tjf dddqS ).N)depth1depth2)r$   r-   ry   npasarraynewaxis)r   kr>   r   r   r   r      s    "F)rw   
cse_concat)r$   r   r   !_clean_description_and_parametersr-   stage1parse_oprL   Op__deepcopy__rb   solvere   items)descriptionrw   tensor_shapes
parametersr   exprsr   r   r   r   r   parse   s8   
 	*r   c                    s   d d fdd
S )Nr*   c                   s$    | gfdd|D R i |S )Nc                    r   r   r   r   r   r   r   r      r   r   r   )r   r   tensorsr   r   r   r   r      s    r   r   r    r   r   r   r      r   )r   rw   r   r   r   r   r   rw   r   r   c          	      O   sX   t | gdd |D R d|i|\}}t||||||d\}}t|dkr*|d S |S )a  Applies a function to the marked axes of the input tensors by passing the ``axis``
    argument and relying on implicit broadcasting rules.

    The function ``op`` must accept input tensors and an ``axis`` argument specifying the
    indices of the axes along which the operation is applied. When the function is applied on
    scalars, the ``axis`` argument is not passed. For multiple input tensors, the function
    must follow
    `Numpy broadcasting rules <https://numpy.org/doc/stable/user/basics.broadcasting.html>`_.

    Args:
        description: Description string for the operation in einx notation.
        tensors: Input tensors or tensor factories matching the description string.
        op: Backend operation. Is called with ``op(tensor, axis=...)``. If ``op`` is a string,
            retrieves the attribute of ``backend`` with the same name.
        kwargs: Additional keyword arguments that are passed to ``op``.
        backend: Backend to use for all operations. If None, determines the backend from the input
            tensors. Defaults to None.
        cse: Whether to apply common subexpression elimination to the expressions. Defaults to True.
        graph: Whether to return the graph representation of the operation instead of computing the
            result. Defaults to False.
        **parameters: Additional parameters that specify values for single axes, e.g. ``a=4``.

    Returns:
        The result of the operation if ``graph=False``, otherwise the graph
        representation of the operation.

    Examples:
        Reverse order of elements along an axis:

        >>> x = np.random.uniform(size=(16, 20))
        >>> einx.vmap_with_axis("a [b] -> a [b]", x, op=np.flip).shape
        (16, 20)

        Roll elements along two axes:

        >>> x = np.random.uniform(size=(16, 20))
        >>> einx.vmap_with_axis(
        ...     "a ([b c]) -> a ([b c])",
        ...     x,
        ...     op=partial(np.roll, shift=(2, 2)),
        ...     b=2,
        ... ).shape
        (16, 20)

        Compute sum along axis:

        >>> x = np.random.uniform(size=(16, 20))
        >>> einx.vmap_with_axis("a ([b] c) -> c a", x, op=np.sum, b=2).shape
        (16, 20)
    c                 S   r{   r   )r$   r%   	get_shaper'   r   r   r   r   !  r|   z"vmap_with_axis.<locals>.<listcomp>rw   )r   r   r   r   r   )r   rv   rL   )	r   r   r   rw   r   r   r   r   r   r   r   r   vmap_with_axis   s   A

r   r(   c                 K      t | |fd||d|S )zASpecialization of :func:`einx.vmap_with_axis` with ``op="flip"``.r
   r   r   rw   r   r   r(   r   rw   r   r   r   r   r
   ,     	shiftc                 K   s    t | |fd|d|i|d|S )zjSpecialization of :func:`einx.vmap_with_axis` with ``op="roll"`` and
    ``kwargs={"shift": shift}``.
    r	   r   )r   r   r   rw   r   )r   r(   r   r   rw   r   r   r   r   r	   8  s   c                 K   r   )zCSpecialization of :func:`einx.vmap_with_axis` with ``op="softmax"``softmaxr   r   r   r   r   r   r   O  r   r   c                 K   r   )zGSpecialization of :func:`einx.vmap_with_axis` with ``op="log_softmax"``log_softmaxr   r   r   r   r   r   r   [  s   	r   )NN)NT) r$    r   numpyr   	functoolsr   typingr   r   r   r   numpy.typingnpt	_op_namesjitrv   	lru_cacher   traceback_utilfilterrl   r[   Backendbool	ArrayLiker   r
   intr	   r   r   r   r   r   r   <module>   s     ,#	D