o
    h|.                     @   s<   d dl Zdd Zdd Zdd Zdd	 Zd
d Zdd ZdS )    Nc                    s   t  t  t jtdt dg g fdd fddfdd}ttD ]}| d	krL|| q@S )
a  Finds the cycles in a dependency graph

    The input should be a numpy array of integers,
    where in the standard use case,
    tree[i] is the head of node i.

    tree[0] == 0 to represent the root

    so for example, for the English sentence "This is a test",
    the input is

    [0 4 4 4 0]

    "Arthritis makes my hip hurt"

    [0 2 0 4 2 2]

    The return is a list of cycles, where in cycle has True if the
    node at that index is participating in the cycle.
    So, for example, the previous examples both return empty lists,
    whereas an input of
      np.array([0, 3, 1, 2])
    has an output of
      [np.array([False,  True,  True,  True])]
    dtyper   c                    s   |  |  kr@t jtd}d | kr' }d|< d||< d | ks  d| < d|| < | dkrB | d S d S d S )Nr   FT   )np
zeros_likeboolpopsumappend)icyclej)cyclesindiceslowlinksonstackstack ^/var/www/html/env_mimamsha/lib/python3.10/site-packages/stanza/models/common/chuliu_edmonds.pymaybe_pop_cycle&   s   
ztarjan.<locals>.maybe_pop_cyclec                    sB    d  d7  <  d }|d  | < | <  |  d| < d S )Nr   r   r   T)r   )r   index)_indexr   r   r   r   r   r   initialize_strong_connect4   s
   
z)tarjan.<locals>.initialize_strong_connectc                    s   | d d fg}t |dkrl| \} }}|d u r)|  ttt| d }nt|  | | < |D ])} | dkrP|| ||f ||d d f  n| r_t|   | | < q6|  t |dksd S d S )Nr   r   )lenr	   iterr   whereequalminr   )r   
call_stackdependents_iteratorr   )r   r   r   r   r   treer   r   strong_connect;   s"   ztarjan.<locals>.strong_connectr   )r   	ones_liker   r   listranger   )r!   r"   r   r   )	r   r   r   r   r   r   r   r   r!   r   tarjan   s   =r&   c                 C   s  t |d }| | }|||f }| }t |}t |d }|| dd|f |dddf  | }	|| dd|f }
t j|	dd}t j|
dd}|| dd|f }t |dd}|	|t t|f |dddf< |
t t||f |dddf< |||||fS )z2
    Build a subproblem with one cycle broken
    r   Naxisr   )r   r   r)   constantr   )r   r   r
   logical_notargmaxpadaranger   )r!   r   scores
cycle_locscycle_subtreecycle_scorescycle_scorenoncyclenoncycle_locsmetanode_head_scoresmetanode_dep_scoresmetanode_headsmetanode_deps	subscoresr   r   r   process_cycle}   s   
(""r;   c           
      C   s   |d }|dd }t |  }|t|k }|||  ||| < t |}|||  ||| < | | ||< || }	|| |||	 < |S )z
    Given a partially solved tree with a cycle and a solved subproblem
    for the cycle, build a larger solution without the cycle
    r   N)r   r#   r   r+   )
r!   contracted_treer0   r5   r8   r9   
cycle_headnew_treecontracted_subtree
cycle_rootr   r   r   expand_contracted_tree   s   
rA   c                 C   s,   t | td  td | d< d| d< dS )zI
    Alter the scores matrix to avoid self loops and handle the root
    infr   )r   r   N)r   fill_diagonalfloat)r/   r   r   r   prepare_scores   s   rE   c           
   
   C   s   g }t |  tj| dd}t|}|r@t|| | \}}}}}|||| |||||f |} t |  tj| dd}t|}|st|dkrc|}	| \}}} }}}}}t||	||||}t|dksF|S )Nr   r'   r   )	rE   r   r,   r&   r;   r	   r   r   rA   )
r/   subtree_stackr!   r   r:   r0   r5   r8   r9   r<   r   r   r   chuliu_edmonds   s$   rG   c                 C   s6  |  tj} t| }tt|dd dd d }t|dkr#|S dd }tj d}}|D ]2}|| |\}}t|}	|tt||	f }
|
tj k	 rV|

 | ntj }||krb|}|	}q0z	|dusjJ W |S    tdd}|d|| | |d	|	||
| W d    1 sw   Y   )
 r   Nr   c                 S   sN   | |df }t | } td | dd df< td | |< d| |df< | |fS )Nr   rB   r   )r   arrayrD   )r/   root
root_scorer   r   r   set_root   s   
z)chuliu_edmonds_one_root.<locals>.set_rootz	debug.logwz{}: {}, {}
z{}: {}, {}, {}
)astyper   float64rG   r   r   r   rB   r.   allr
   openwriteformat)r/   r!   roots_to_tryrL   
best_score	best_treerJ   _scoresrK   _tree
tree_probs
tree_scorefr   r   r   chuliu_edmonds_one_root   s6   "	$
r\   )numpyr   r&   r;   rA   rE   rG   r\   r   r   r   r   <module>   s   x'!	(