code: def eisner(scores, mask):
      r"""
      First-order Eisner algorithm for projective decoding.
  
      References:
          - Ryan McDonald, Koby Crammer and Fernando Pereira. 2005.
            `Online Large-Margin Training of Dependency Parsers`_.
  
      Args:
          scores (~torch.Tensor): ``[batch_size, seq_len, seq_len]``.
              Scores of all dependent-head pairs.
          mask (~torch.BoolTensor): ``[batch_size, seq_len]``.
              The mask to avoid parsing over padding tokens.
              The first column serving as pseudo words for roots should be ``False``.
  
      Returns:
          ~torch.Tensor:
              A tensor with shape ``[batch_size, seq_len]`` for the resulting projective parse trees.
  
      Examples:
          >>> scores = torch.tensor([[[-13.5026, -18.3700, -13.0033, -16.6809],
                                      [-36.5235, -28.6344, -28.4696, -31.6750],
                                      [ -2.9084,  -7.4825,  -1.4861,  -6.8709],
                                      [-29.4880, -27.6905, -26.1498, -27.0233]]])
          >>> mask = torch.tensor([[False,  True,  True,  True]])
          >>> eisner(scores, mask)
          tensor([[0, 2, 0, 2]])
  
      .. _Online Large-Margin Training of Dependency Parsers:
          https://www.aclweb.org/anthology/P05-1012/
      """
  
      lens = mask.sum(1)
      batch_size, seq_len, _ = scores.shape
      scores = scores.permute(2, 1, 0)
      s_i = torch.full_like(scores, float("-inf"))
      s_c = torch.full_like(scores, float("-inf"))
      p_i = scores.new_zeros(seq_len, seq_len, batch_size).long()
      p_c = scores.new_zeros(seq_len, seq_len, batch_size).long()
      s_c.diagonal().fill_(0)
  
      for w in range(1, seq_len):
          n = seq_len - w
          starts = p_i.new_tensor(range(n)).unsqueeze(0)
          # ilr = C(i->r) + C(j->r+1)
          ilr = stripe(s_c, n, w) + stripe(s_c, n, w, (w, 1))
          # [batch_size, n, w]
          il = ir = ilr.permute(2, 0, 1)
          # I(j->i) = max(C(i->r) + C(j->r+1) + s(j->i)), i <= r < j
          il_span, il_path = il.max(-1)
          s_i.diagonal(-w).copy_(il_span + scores.diagonal(-w))
          p_i.diagonal(-w).copy_(il_path + starts)
          # I(i->j) = max(C(i->r) + C(j->r+1) + s(i->j)), i <= r < j
          ir_span, ir_path = ir.max(-1)
          s_i.diagonal(w).copy_(ir_span + scores.diagonal(w))
          p_i.diagonal(w).copy_(ir_path + starts)
  
          # C(j->i) = max(C(r->i) + I(j->r)), i <= r < j
          cl = stripe(s_c, n, w, (0, 0), 0) + stripe(s_i, n, w, (w, 0))
          cl_span, cl_path = cl.permute(2, 0, 1).max(-1)
          s_c.diagonal(-w).copy_(cl_span)
          p_c.diagonal(-w).copy_(cl_path + starts)
          # C(i->j) = max(I(i->r) + C(r->j)), i < r <= j
          cr = stripe(s_i, n, w, (0, 1)) + stripe(s_c, n, w, (1, w), 0)
          cr_span, cr_path = cr.permute(2, 0, 1).max(-1)
          s_c.diagonal(w).copy_(cr_span)
          s_c[0, w][lens.ne(w)] = float("-inf")
          p_c.diagonal(w).copy_(cr_path + starts + 1)
  
      def backtrack(p_i, p_c, heads, i, j, complete):
          if i == j:
              return
          if complete:
              r = p_c[i, j]
              backtrack(p_i, p_c, heads, i, r, False)
              backtrack(p_i, p_c, heads, r, j, True)
          else:
              r, heads[j] = p_i[i, j], i
              i, j = sorted((i, j))
              backtrack(p_i, p_c, heads, i, r, True)
              backtrack(p_i, p_c, heads, j, r + 1, True)
  
      preds = []
      p_c = p_c.permute(2, 0, 1).cpu()
      p_i = p_i.permute(2, 0, 1).cpu()
      for i, length in enumerate(lens.tolist()):
          heads = p_c.new_zeros(length + 1, dtype=torch.long)
          backtrack(p_i[i], p_c[i], heads, 0, length, True)
          preds.append(heads.to(mask.device))
  
      return pad(preds, total_length=seq_len).to(mask.device)
  
file_path: underthesea/underthesea/utils/sp_alg.py
imports: import torch
  from underthesea.utils.sp_fn import pad, stripe
label_desc: Use image node_id 5 for calling a global function with example usage: eisner(scores, mask) and returns: pad