o
    Gip%                  	   @   s   d dl mZ d dl mZ d dl mZ d dlZd dlZd dlZddlmZ G dd dej	j
Z	 dd	ejd
ejdedejfddZd
ejdejdejddfddZd	edejdefddZdee defddZdejdejdejfddZdS )    )List)Tuple)UnionN   )Fsac                	   @   sL   e Zd ZedejdejdedejfddZedeejdf fdd	Z	dS )
_IndexSelectFunctionsrcindexdefault_valuereturnc                 C   s   |  || t|||S )a  Returns a new tensor which indexes the input tensor along dimension 0
        using the entries in `index`.

        If the entry in `index` is -1, then the corresponding entry in the
        returned tensor is 0.

        Caution:
          `index.dtype == torch.int32` and `index.ndim == 1`.

        Args:
          src:
            The input tensor. Either 1-D or 2-D with dtype torch.int32 or
            torch.float32.
          index:
            1-D tensor of dtype torch.int32 containing the indexes.
            If an entry is -1, the corresponding entry in the returned value
            is 0. The elements of `index` should be in the range
            `[-1..src.shape[0]-1]`.
          default_value:
            Used only when `src` is a 1-D tensor. It sets ans[i] to
            default_value if index[i] is -1.

        Returns:
          A tensor with shape (index.numel(), *src.shape[1:]) and dtype the
          same as `src`, e.g. if `src.ndim == 1`, ans.shape would be
          (index.shape[0],); if `src.ndim == 2`, ans.shape would be
          (index.shape[0], src.shape[1]).
          Will satisfy `ans[i] == src[index[i]]` if `src.ndim == 1`,
          or `ans[i,j] == src[index[i],j]` if `src.ndim == 2`, except for
          entries where `index[i] == -1` which will be zero.
        )save_for_backward_k2index_select)ctxr   r	   r
    r   :/home/ubuntu/.local/lib/python3.10/site-packages/k2/ops.pyforward   s   "z_IndexSelectFunction.forwardNc                 C   s:   | j \}}tj|j|j|jdd}t||| |d d fS )NF)dtypedevicerequires_grad)saved_tensorstorchzerosshaper   r   r   	index_add)r   out_gradr   r	   ansr   r   r   backwardB   s   
z_IndexSelectFunction.backward)
__name__
__module____qualname__staticmethodr   Tensorfloatr   r   r   r   r   r   r   r      s    $r   r   r	   r
   r   c                 C   s   t | ||}|S )a  Returns a new tensor which indexes the input tensor along dimension 0
    using the entries in `index`.

    If the entry in `index` is -1, then the corresponding entry in the
    returned tensor is 0.

    Caution:
      `index.dtype == torch.int32` and `index.ndim == 1`.

    Args:
      src:
        The input tensor. Either 1-D or 2-D with dtype `torch.int32`,
        `torch.int64`, `torch.float32`, or `torch.float64`.
      index:
        1-D tensor of dtype `torch.int32` containing the indexes.
        If an entry is -1, the corresponding entry in the returned value
        is 0. The elements of `index` should be in the range
        `[-1..src.shape[0]-1]`.
      default_value:
        Used only when `src` is a 1-D tensor. It sets ans[i] to default_value
        if index[i] is -1.

    Returns:
      A tensor with shape ``(index.numel(), *src.shape[1:])`` and dtype the
      same as `src`, e.g. if `src.ndim == 1`, `ans.shape` would be
      `(index.shape[0],)`; if `src.ndim == 2`, `ans.shape` would be
      `(index.shape[0], src.shape[1])`.
      Will satisfy `ans[i] == src[index[i]]` if `src.ndim == 1`,
      or `ans[i, j] == src[index[i], j]` if `src.ndim == 2`, except for
      entries where `index[i] == -1` which will be zero.
    )r   apply)r   r	   r
   r   r   r   r   r   S   s   "r   valuein_outc                 C   s   t | || dS )a  It implements in_out[index[i]] += value[i].

    Caution:
      It has similar semantics with `torch.Tensor.index_add_` except
      that:

        - `index.dtype == torch.int32`
        - `-1 <= index[i] < in_out.shape[0]`
        - `index[i] == -1` is ignored.
        - `index` has to be a 1-D **contiguous** tensor.

    Caution:
      `in_out` is modified **in-place**.

    Caution:
      This functions does NOT support autograd.

    Args:
      index:
        A 1-D **contiguous** tensor with dtype `torch.int32`.
        Must satisfy `-1 <= index[i] < in_out.shape[0]`
      value:
        A 1-D or 2-D tensor with dtype `torch.int32`, `torch.float32`,
        or `torch.float64`.
        Must satisfy `index.shape[0] == value.shape[0]`
      in_out:
        A 1-D or 2-D tensor with the same dtype as `value`. It satisfies
        `in_out.shape[1] == value.shape[1]` if it is a 2-D tensor.

    Returns:
      Return None.
    N)r   r   )r	   r%   r&   r   r   r   r   y   s   #r   indexesc           	      C   s   t j| jd|dd\}}t|}|  D ]6\}}t|tjr*t||t	j
|| qt|t	js2J |jtjks:J |j|ddd\}}t||| q|  D ]
\}}t||| qO|S )a*  Select a list of FSAs from `src` with a 1-D tensor.

    Args:
      src:
        An FsaVec.
      indexes:
        A 1-D `torch.Tensor` of dtype `torch.int32` containing
        the ids of FSAs to select.

    Returns:
      Return an FsaVec containing only those FSAs specified by `indexes`.
    r   T)axisr'   need_value_indexesF)r(   r)   )r   r	   arcsr   named_tensor_attr
isinstancer   r"   setattrk2opsr   RaggedTensorr   int32named_non_tensor_attr)	r   r'   
ragged_arcvalue_indexesout_fsanamer%   ragged_value_r   r   r   	index_fsa   s&   

r9   srcsc                    s  | D ]}t |jdksJ d|j qdd | D }tj|dd}t|}dd | D }tjt| }|D ]1  fd	d| D }t|d t	j
rOt	|}nt|d tjsYJ tjj|dd}t| | q6| D ]}| D ]\ }t| st| | qpqj|S )
a  Concatenate a list of FsaVec into a single FsaVec.

    Caution:
      Only common tensor attributes are kept in the output FsaVec.
      For non-tensor attributes, only one copy is kept in the output
      FsaVec. We choose the first copy of the FsaVec that has the
      lowest index in `srcs`.

    Args:
      srcs:
        A list of FsaVec. Each element MUST be an FsaVec.
    Returns:
      Return a single FsaVec concatenated from the input FsaVecs.
       zExpect an FsaVec. Given: c                 S   s   g | ]}|j qS r   )r*   ).0fsar   r   r   
<listcomp>   s    zcat.<locals>.<listcomp>r   )r(   c                 s   s$    | ]}t t|  V  qd S )N)setdictr+   keysr<   r   r   r   r   	<genexpr>   s    
zcat.<locals>.<genexpr>c                    s   g | ]}t | qS r   )getattrrB   r6   r   r   r>      s    )lenr   r   catr   r?   intersectionlistr,   r   r"   r.   r0   raggedr-   r2   hasattr)r:   r   src_ragged_arcsans_ragged_arcsr5   common_tensor_attributesvaluesr%   r   rE   r   rG      s2    
rG   step1_arc_mapstep2_arc_mapc                 C   sL   | j dksJ | jtjksJ |j dksJ |jtjksJ tj| |ddS )a  Compose arc maps from two Fsa operations.

    It implements:

        - ans_arc_map[i] = step1_arc_map[step2_arc_map[i]] if
          step2_arc_map[i] is not -1
        - ans_arc_map[i] = -1 if step2_arc_map[i] is -1

    for i in 0 to `step2_arc_map.numel() - 1`.

    Args:
      step1_arc_map:
        A 1-D tensor with dtype torch.int32 from the first Fsa operation.
      step2_arc_map:
        A 1-D tensor with dtype torch.int32 from the second Fsa operation.
    Returns:
      Return a 1-D tensor with dtype torch.int32. It has the same number
      of elements as step2_arc_map. That is,
      ans_arc_map.shape == step2_arc_map.shape.
    r   )r
   )ndimr   r   r1   r   r   )rP   rQ   r   r   r   compose_arc_maps   s
   rT   )r   )typingr   r   r   r   r.   r   r=   r   autogradFunctionr   r"   r#   r   r   r9   rG   rT   r   r   r   r   <module>   s8   :

&
&'2