o
    hX                     @   s   d Z ddlmZmZ ddlmZ ddlZddlZddlm	Z	 ddl
mZ ddlmZmZ ddlmZ dd	lmZ dd
lmZ ddlmZmZ dZedZG dd deZG dd deZdS )a  
The BaseModel is passed to the transitions so that the transitions
can operate on a parsing state without knowing the exact
representation used in the model.

For example, a SimpleModel simply looks at the top of the various stacks in the state.

A model with LSTM representations for the different transitions may
attach the hidden and output states of the LSTM to the word /
constituent / transition stacks.

Reminder: the parsing state is a list of words to parse, the
transitions used to build a (possibly incomplete) parse, and the
constituent(s) built so far by those transitions.  Each of these
components are represented using stacks to improve the efficiency
of operations such as "combine the most recent 4 constituents"
or "turn the next input word into a constituent"
    )ABCabstractmethod)defaultdictN)utils)transition_sequence)TransitionSchemeCloseConstituentTree)State	TreeStack)ParseResult
ScoredTree   zstanza.constituency.trainerc                       s^  e Zd ZdZ fddZedd Zedd Zedd	 Zed
d Z	edd Z
edd Zedd Zedd Zedd Zedd Zedd Zedd Zdd Zdd Zd d! Zed"d# Zed$d% ZdEd'd(Zd)d* ZdEd+d,Zd-d. Zd/d0 ZdFd2d3Zd4d5 Zd6d7 Zd8d9 Z dGd;d<Z!dGd=d>Z"dHd?d@Z#dAdB Z$dIdCdDZ%  Z&S )J	BaseModelas  
    This base class defines abstract methods for manipulating a State.

    Applying transitions may change important metadata about a State
    such as the vectors associated with LSTM hidden states, for example.

    The constructor forwards all unused arguments to other classes in the
    constructor sequence, so put this before other classes such as nn.Module
    c                    s\   t  j|i | || _|| _|| _tt|| _| jtj	u p*| jtj
u p*| jtju | _d S N)super__init___transition_scheme_unary_limit_reverse_sentencesortedlist_root_labelsr   TOP_DOWNTOP_DOWN_UNARYTOP_DOWN_COMPOUND_is_top_down)selftransition_schemeunary_limitreverse_sentenceroot_labelsargskwargs	__class__ `/var/www/html/env_mimamsha/lib/python3.10/site-packages/stanza/models/constituency/base_model.pyr   1   s   

zBaseModel.__init__c                 C      dS )z
        For each list of tagged words, builds a TreeStack of word nodes

        The word lists should be backwards so that the first word is the last word put on the stack (LIFO)
        Nr(   )r   tagged_word_listsr(   r(   r)   initial_word_queues=       zBaseModel.initial_word_queuesc                 C   r*   )zh
        Builds an initial transition stack with whatever values need to go into first position
        Nr(   r   r(   r(   r)   initial_transitionsE   r-   zBaseModel.initial_transitionsc                 C   r*   )zi
        Builds an initial constituent stack with whatever values need to go into first position
        Nr(   r.   r(   r(   r)   initial_constituentsK   r-   zBaseModel.initial_constituentsc                 C   r*   )zO
        Get the word corresponding to this position in the word queue
        Nr(   r   	word_noder(   r(   r)   get_wordQ   r-   zBaseModel.get_wordc                 C   r*   )zj
        Transform the top node of word_queue to something that can push on the constituent stack
        Nr(   r   stater(   r(   r)   transform_word_to_constituentW   r-   z'BaseModel.transform_word_to_constituentc                 C   r*   )zg
        When using a dummy node as a sentinel, transform it to something usable by this model
        Nr(   r   dummyr(   r(   r)   dummy_constituent]   r-   zBaseModel.dummy_constituentc                 C   r*   )zj
        Build multiple constituents at once.  This gives the opportunity for batching operations
        Nr(   )r   labelschildren_listsr(   r(   r)   build_constituentsc   r-   zBaseModel.build_constituentsc                 C   r*   )z
        Add a multiple constituents to multiple constituent_stacks

        Useful to factor this out in case batching will help
        Nr(   r   constituent_stacksconstituentsr(   r(   r)   push_constituentsi   r-   zBaseModel.push_constituentsc                 C   r*   )z
        Get the first constituent from the constituent stack

        For example, a model might want to remove embeddings and LSTM state vectors
        Nr(   r   r?   r(   r(   r)   get_top_constituentq   r-   zBaseModel.get_top_constituentc                 C   r*   )z
        Add a multiple transitions to multiple transition_stacks

        Useful to factor this out in case batching will help
        Nr(   r   transition_stackstransitionsr(   r(   r)   push_transitionsy   r-   zBaseModel.push_transitionsc                 C   r*   )z
        Get the first transition from the transition stack

        For example, a model might want to remove transition embeddings before returning the transition
        Nr(   r   rE   r(   r(   r)   get_top_transition   r-   zBaseModel.get_top_transitionc                 C      | j S )zt
        Return ROOT labels for this model.  Probably ROOT, TOP, or both

        (Danish uses 's', though)
        )r   r.   r(   r(   r)   r#      s   zBaseModel.root_labelsc                 C   rI   )zF
        Limit on the number of consecutive unary transitions
        )r   r.   r(   r(   r)   r!         zBaseModel.unary_limitc                 C   rI   )z@
        Transition scheme used - see parse_transitions
        )r   r.   r(   r(   r)   r       rJ   zBaseModel.transition_schemec                 C   s   | j tju S )z^
        Whether or not this model uses unary transitions, based on transition_scheme
        )r   r   r   r.   r(   r(   r)   has_unary_transitions   s   zBaseModel.has_unary_transitionsc                 C   rI   )z7
        Whether or not this model is TOP_DOWN
        )r   r.   r(   r(   r)   is_top_down      zBaseModel.is_top_downc                 C   rI   )zG
        Whether or not this model is built to parse backwards
        )r   r.   r(   r(   r)   r"      rM   zBaseModel.reverse_sentenceTc                 C      t d)Nz-LSTMModel can predict, but SimpleModel cannotNotImplementedError)r   statesis_legalr(   r(   r)   predict      zBaseModel.predictc                 C   rN   )Nz5LSTMModel can weighted_choice, but SimpleModel cannotrO   )r   rQ   r(   r(   r)   weighted_choice   rT   zBaseModel.weighted_choicec                 C   sV   dd |D }|r&t ||D ]\}}||| s%td|j||j|jqd|dfS )zK
        For each State, return the next item in the gold_sequence
        c                 S   s   g | ]}|j |j qS r(   )gold_sequencenum_transitions).0yr(   r(   r)   
<listcomp>       z*BaseModel.predict_gold.<locals>.<listcomp>zZTransition {}:{} was not legal in a transition sequence:
Original tree: {}
Transitions: {}N)ziprR   RuntimeErrorformatrW   	gold_treerV   )r   rQ   rR   rE   transr5   r(   r(   r)   predict_gold   s   
zBaseModel.predict_goldc                    sf   |  |}|  |    fddt|D }|r%dd t||D }|r1dd t||D }|S )zL
        what is passed in should be a list of list of preterminals
        c                    s2   g | ]\}}t t|d  d|dd ddd	qS )   r   Ng        )	sentence_length	num_opens
word_queuer_   rV   rE   r?   word_positionscore)r   len)rX   idxwqr?   rE   r(   r)   rZ      s    	
z=BaseModel.initial_state_from_preterminals.<locals>.<listcomp>c                 S      g | ]
\}}|j |d qS )r_   _replace)rX   r_   r5   r(   r(   r)   rZ          c                 S   rl   )rV   rn   )rX   rV   r5   r(   r(   r)   rZ      rp   )r,   r/   r0   	enumerater\   )r   preterminal_lists
gold_treesgold_sequencesword_queuesrQ   r(   rk   r)   initial_state_from_preterminals   s   
	
z)BaseModel.initial_state_from_preterminalsc                 C   s   dd |D }| j |d d dS )Nc                 S   s   g | ]	}d d |D qS )c                 S   s   g | ]\}}t |t |qS r(   r	   )rX   wordtagr(   r(   r)   rZ      s    zABaseModel.initial_state_from_words.<locals>.<listcomp>.<listcomp>r(   )rX   wordsr(   r(   r)   rZ      s    z6BaseModel.initial_state_from_words.<locals>.<listcomp>rt   ru   rw   )r   
word_listsrs   r(   r(   r)   initial_state_from_words   s   z"BaseModel.initial_state_from_wordsNc                 C   s   dd |D }| j |||dS )Nc                 S   s   g | ]}d d |  D qS )c                 S   s$   g | ]}t |jt |jd  jqS r   )r
   labelchildren)rX   ptr(   r(   r)   rZ      s    zFBaseModel.initial_state_from_gold_trees.<locals>.<listcomp>.<listcomp>)yield_preterminalsrX   treer(   r(   r)   rZ      s
    
z;BaseModel.initial_state_from_gold_trees.<locals>.<listcomp>r{   r|   )r   treesru   rs   r(   r(   r)   initial_state_from_gold_trees   s   z'BaseModel.initial_state_from_gold_treesc                 C   L   g }t |D ]}t|d}|du r n|| qt|dkr$| |}|S )zd
        Read from the data_iterator batch_size trees and turn them into new parsing states
        Nr   )rangenextappendrh   r   )r   
batch_sizedata_iteratorstate_batch_r_   r(   r(   r)   build_batch_from_trees   s   

z BaseModel.build_batch_from_treesc                 C   sR   |  ||}t|dkr|S tdd |D |  | j}dd t||D }|S )z
        Same as build_batch_from_trees, but use the model parameters to turn the trees into gold sequences and include the sequence
        r   c                 S      g | ]}|j qS r(   rm   )rX   r5   r(   r(   r)   rZ          zGBaseModel.build_batch_from_trees_with_gold_sequence.<locals>.<listcomp>c                 S   s   g | ]
\}}|j |d qS rq   rn   )rX   r5   sequencer(   r(   r)   rZ      rp   )r   rh   r   build_treebankr    r"   r\   )r   r   r   r   ru   r(   r(   r)   )build_batch_from_trees_with_gold_sequence   s   z3BaseModel.build_batch_from_trees_with_gold_sequencec                 C   r   )z
        Read from the data_iterator batch_size tagged sentences and turn them into new parsing states

        Expects a list of list of (word, tag)
        Nr   )r   r   r   rh   r~   )r   r   r   r   r   sentencer(   r(   r)   build_batch_from_tagged_words  s   

z'BaseModel.build_batch_from_tagged_wordsFc              
      s
  g }g }	|||}
t tt|
}tg }|rtt }t|
dkr||
\}}}|r8|dur8dd t|
|D }
| |
|}
|r\t|D ]\}}t|t	r[|||  
|
| jjj qDt  t|
D ]?\}}|| r|| }| jrx| }|j}|
t|t||jg|r|nd|r|||  nd |	
||   | qct dkr fddt|
D }
 fddt|D }t|t|
 D ]/}t|d}|s|||}t|dkr nt|}t|d}|

| |
t|t|
  qt|
dks!t||	}|S )ag  
        Repeat transitions to build a list of trees from the input batches.

        The data_iterator should be anything which returns the data for a parse task via next()
        build_batch_fn is a function that turns that data into State objects
        This will be called to generate batches of size batch_size until the data is exhausted

        The return is a list of tuples: (gold_tree, [(predicted, score) ...])
        gold_tree will be left blank if the data did not include gold trees
        if keep_scores is true, the score will be the sum of the values
          returned by the model for each transition

        transition_choice: which method of the model to use for choosing the next transition
          predict for predicting the transition based on the model
          predict_gold to just extract the gold transition from the sequence
        r   Nc                 S   s"   g | ]\}}|j |j| d qS ))rg   )ro   rg   )rX   r5   rg   r(   r(   r)   rZ   3  s   " z-BaseModel.parse_sentences.<locals>.<listcomp>c                       g | ]
\}}| vr|qS r(   r(   )rX   ri   r5   remover(   r)   rZ   J  rp   c                    r   r(   r(   )rX   ri   	batch_idxr   r(   r)   rZ   K  rp   )r   r   rh   iterr   r\   
bulk_applyrr   
isinstancer   r   r?   valuesetfinishedget_treer"   reverser_   r   r   rg   addr   r   unsort)r   r   build_batch_fnr   transition_choice
keep_statekeep_constituentskeep_scorestreebanktreebank_indicesr   batch_indiceshorizon_iteratorr?   pred_scoresrE   scorest_idx
transitionri   r5   predicted_treer_   r   horizon_statehorizon_batchr(   r   r)   parse_sentences  sX   



6




)zBaseModel.parse_sentencesc              
   C   sB   t   | |||||||W  d   S 1 sw   Y  dS )z
        Given an iterator over the data and a method for building batches, returns a list of parse trees.

        no_grad() is so that gradients aren't kept, which makes the model
        run faster and use less memory at inference time
        N)torchno_gradr   )r   r   r   r   r   r   r   r   r(   r(   r)   parse_sentences_no_grad\  s   
$z!BaseModel.parse_sentences_no_gradc              	   C   s:   |du r	| j d }t|}| j|| j|| j|||d}|S )ai  
        Return a ParseResult for each tree in the trees list

        The transitions run will be the transitions represented by the tree
        The output layers will be available in result.state for each result

        keep_state=True as a default here as a method which keeps the grad
        is likely to want to keep the resulting state as well
        Neval_batch_size)r   )r$   r   r   r   ra   )r   r   r   r   r   r   tree_iteratorr   r(   r(   r)   analyze_treesf  s
   

zBaseModel.analyze_treesc                 C   sL   t dt| |   t|}| j|| j|| jddd}dd |D }|S )a}  
        This parses tagged words and returns a list of trees.

        `parse_tagged_words` is useful at Pipeline time -
          it takes words & tags and processes that into trees.

        The tagged words should be represented:
          one list per sentence
            each sentence is a list of (word, tag)
        The return value is a list of ParseTree objects
        zProcessing %d sentencesF)r   r   c                 S   s   g | ]}|j d  jqS r   )predictionsr   )rX   tr(   r(   r)   rZ     r[   z0BaseModel.parse_tagged_words.<locals>.<listcomp>)loggerdebugrh   evalr   r   r   rS   )r   rz   r   sentence_iteratorr   resultsr(   r(   r)   parse_tagged_wordsw  s   zBaseModel.parse_tagged_wordsc                    s  t  g }g }g  tt}tt||D ]z\}\}}	|	s7d|j|| }
|r,t|
t	
|
 | q|jt|jd krh|jrOd|j|| }
nd|| }
|r]t|
t	
|
 | q|	|| \}}}}|| ||  | |r|| t d  q| D ]!\}} fdd|D }|| |}t||D ]\}}| |< qqtdkrчfd	dt|D }fd
dt|D }t|dkr|S | dd |D |}| |  dd t|||| D }|S )ai  
        Apply the given list of Transitions to the given list of States, using the model as a reference

        model: SimpleModel, LSTMModel, or any other form of model
        state_batch: list of States
        transitions: list of transitions, one per state
        fail: throw an exception on a failed transition, as opposed to skipping the tree
        z^Got stuck and couldn't find a legal transition on the following gold tree:
{}

Final state:
{}   z=Went infinite on the following gold tree:
{}

Final state:
{}zWent infinite!:
Final state:
{}   c                    s   g | ]} | qS r(   r(   )rX   x)new_constituentsr(   r)   rZ     s    z(BaseModel.bulk_apply.<locals>.<listcomp>r   c                    r   r(   r(   )rX   ri   r   r   r(   r)   rZ     rp   c                    r   r(   r(   )rX   ri   r`   r   r(   r)   rZ     rp   c                 S   r   r(   )rE   r   r(   r(   r)   rZ     r   c                 S   s2   g | ]\}}}}}|j |j|  |||d qS ))rd   rf   rE   r?   )ro   rd   delta_opens)rX   r5   r   rf   transition_stackr?   r(   r(   r)   rZ     s    
)r   r   r   rr   r\   r^   r_   	to_string
ValueErrorr   errorr   rW   rh   re   update_stater   itemsr<   rF   r@   )r   r   rE   failword_positionsr?   	callbacksri   r   r   r   rj   cnccallbackkeyidxsdatacallback_constituentsconstituentnew_transitionsr(   )r   r   r)   r     s\   	







zBaseModel.bulk_apply)Tr   )FFF)NTTT)F)'__name__
__module____qualname____doc__r   r   r,   r/   r0   r3   r6   r9   r<   r@   rB   rF   rH   propertyr#   r!   r    rK   rL   r"   rS   rU   ra   rw   r~   r   r   r   r   r   r   r   r   r   __classcell__r(   r(   r&   r)   r   '   s`    	


















H

r   c                       s   e Zd ZdZejeddf fdd	Zdd Zdd	 Z	d
d Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Z  ZS )SimpleModelab  
    This model allows pushing and popping with no extra data

    This class is primarily used for testing various operations which
    don't need the NN's weights

    Also, for rebuilding trees from transitions when verifying the
    transitions in situations where the NN state is not relevant,
    as this class will be faster than using the NN
    F)ROOTc                    s   t  j||||d d S )N)r    r!   r"   r#   )r   r   )r   r    r!   r"   r#   r&   r(   r)   r     s   zSimpleModel.__init__c                 C   sL   g }|D ]}d g}|dd |D 7 }| d  | jr|  | | q|S )Nc                 S   s   g | ]}|qS r(   r(   )rX   tag_noder(   r(   r)   rZ     s    z3SimpleModel.initial_word_queues.<locals>.<listcomp>)r   r"   r   )r   r+   rv   tagged_wordsre   r(   r(   r)   r,     s   
zSimpleModel.initial_word_queuesc                 C      t d d ddS Nr   )r   parentlengthr   r.   r(   r(   r)   r/        zSimpleModel.initial_transitionsc                 C   r   r   r   r.   r(   r(   r)   r0     r   z SimpleModel.initial_constituentsc                 C      |S r   r(   r1   r(   r(   r)   r3        zSimpleModel.get_wordc                 C   s   | |jS r   )r3   rf   r4   r(   r(   r)   r6     s   z)SimpleModel.transform_word_to_constituentc                 C   r   r   r(   r7   r(   r(   r)   r9     r   zSimpleModel.dummy_constituentc                 C   sP   g }t ||D ]\}}t|tr|f}t|D ]}t||d}q|| q|S )N)r   r   )r\   r   strreversedr
   r   )r   r:   r;   r?   r   r   r   r(   r(   r)   r<      s   
zSimpleModel.build_constituentsc                 C      dd t ||D S )Nc                 S      g | ]	\}}| |qS r(   push)rX   stackr   r(   r(   r)   rZ         z1SimpleModel.push_constituents.<locals>.<listcomp>r\   r=   r(   r(   r)   r@   
     zSimpleModel.push_constituentsc                 C      |j S r   r   rA   r(   r(   r)   rB        zSimpleModel.get_top_constituentc                 C   r   )Nc                 S   r   r(   r   )rX   r   r   r(   r(   r)   rZ     r   z0SimpleModel.push_transitions.<locals>.<listcomp>r   rC   r(   r(   r)   rF     r   zSimpleModel.push_transitionsc                 C   r   r   r   rG   r(   r(   r)   rH     r   zSimpleModel.get_top_transition)r   r   r   r   r   r   UNARY_LIMITr   r,   r/   r0   r3   r6   r9   r<   r@   rB   rF   rH   r   r(   r(   r&   r)   r     s    

r   )r   abcr   r   collectionsr   loggingr   stanza.models.commonr   stanza.models.constituencyr   ,stanza.models.constituency.parse_transitionsr   r   %stanza.models.constituency.parse_treer
    stanza.models.constituency.stater   %stanza.models.constituency.tree_stackr   stanza.server.parser_evalr   r   r   	getLoggerr   r   r   r(   r(   r(   r)   <module>   s&    
   4