o
    h                     @   sT   d Z ddlmZ ddlZddlmZ ddlmZ edg dZG dd dej	Z
dS )	a5  
Keeps an LSTM in TreeStack form.

The TreeStack nodes keep the hx and cx for the LSTM, along with a
"value" which represents whatever the user needs to store.

The TreeStacks can be ppped to get back to the previous LSTM state.

The module itself implements three methods: initial_state, push_states, output
    )
namedtupleN)	TreeStackNode)valuelstm_hxlstm_cxc                       s6   e Zd Z fddZd
ddZdd Zdd	 Z  ZS )LSTMTreeStackc              
      s   t    || _|r| dtjdtj|dd  n| dt	|d| | dt	|d| tj
||||d| _|| _d	S )
a  
        Prepare LSTM and parameters

        input_size: dimension of the inputs to the LSTM
        hidden_size: LSTM internal & output dimension
        num_lstm_layers: how many layers of LSTM to use
        dropout: value of the LSTM dropout
        uses_boundary_vector: if set, learn a start_embedding parameter.  otherwise, use zeros
        input_dropout: an nn.Module to dropout inputs.  TODO: allow a float parameter as well
        start_embeddingg?T)requires_gradinput_zeros   hidden_zeros)
input_sizehidden_size
num_layersdropoutN)super__init__uses_boundary_vectorregister_parametertorchnn	Parameterrandnregister_bufferzerosLSTMlstminput_dropout)selfr   r   num_lstm_layersr   r   r   	__class__ e/var/www/html/env_mimamsha/lib/python3.10/site-packages/stanza/models/constituency/lstm_tree_stack.pyr      s   
$
zLSTMTreeStack.__init__Nc                 C   sf   | j r| jdd}| |\}\}}|ddddf }n	| j}| j}| j}tt|||dddS )aw  
        Return an initial state, either based on zeros or based on the initial embedding and LSTM

        Note that LSTM start operation is already batched, in a sense
        The subsequent batch built this way will be used for batch_size trees

        Returns a stack with None value, hx & cx either based on the
        start_embedding or zeros, and no parent.
        r   Nr   )r   parentlength)r   r	   	unsqueezer   r   r   r   r   )r   initial_valuestartoutputhxcxr#   r#   r$   initial_state0   s   
zLSTMTreeStack.initial_statec                    st   |  |}tjdd |D ddtjdd |D dd | | f\}\  fddtt||D }|S )z
        Starting from a list of current stacks, put the inputs through the LSTM and build new stack nodes.

        B = stacks.len() = values.len()

        inputs must be of shape 1 x B x input_size
        c                 S      g | ]}|j jqS r#   r   r   .0tr#   r#   r$   
<listcomp>N       z-LSTMTreeStack.push_states.<locals>.<listcomp>r   )axisc                 S   r.   r#   )r   r   r0   r#   r#   r$   r3   O   r4   c                    sZ   g | ])\}\}}| t|d d ||d d d f  d d ||d d d f qS )Nr   )pushr   )r1   istack
transitionr,   r+   r#   r$   r3   Q   s    
J)r   r   catr   	enumeratezip)r   stacksvaluesinputsr*   
new_stacksr#   r:   r$   push_statesD   s   
zLSTMTreeStack.push_statesc                 C   s   |j jddddf S )z
        Return the last layer of the lstm_hx as the output from a stack

        Refactored so that alternate structures have an easy way of getting the output
        r   Nr/   )r   r8   r#   r#   r$   r*   U   s   zLSTMTreeStack.output)N)__name__
__module____qualname__r   r-   rB   r*   __classcell__r#   r#   r!   r$   r      s
    
r   )__doc__collectionsr   r   torch.nnr   %stanza.models.constituency.tree_stackr   r   Moduler   r#   r#   r#   r$   <module>   s    