code: def cky(scores, mask):
      r"""
      The implementation of `Cocke-Kasami-Younger`_ (CKY) algorithm to parse constituency trees.
  
      References:
          - Yu Zhang, Houquan Zhou and Zhenghua Li. 2020.
            `Fast and Accurate Neural CRF Constituency Parsing`_.
  
      Args:
          scores (~torch.Tensor): ``[batch_size, seq_len, seq_len]``.
              Scores of all candidate constituents.
          mask (~torch.BoolTensor): ``[batch_size, seq_len, seq_len]``.
              The mask to avoid parsing over padding tokens.
              For each square matrix in a batch, the positions except upper triangular part should be masked out.
  
      Returns:
          Sequences of factorized predicted bracketed trees that are traversed in pre-order.
  
      Examples:
          >>> scores = torch.tensor([[[ 2.5659,  1.4253, -2.5272,  3.3011],
                                      [ 1.3687, -0.5869,  1.0011,  3.3020],
                                      [ 1.2297,  0.4862,  1.1975,  2.5387],
                                      [-0.0511, -1.2541, -0.7577,  0.2659]]])
          >>> mask = torch.tensor([[[False,  True,  True,  True],
                                    [False, False,  True,  True],
                                    [False, False, False,  True],
                                    [False, False, False, False]]])
          >>> cky(scores, mask)
          [[(0, 3), (0, 1), (1, 3), (1, 2), (2, 3)]]
  
      .. _Cocke-Kasami-Younger:
          https://en.wikipedia.org/wiki/CYK_algorithm
      .. _Fast and Accurate Neural CRF Constituency Parsing:
          https://www.ijcai.org/Proceedings/2020/560/
      """
  
      lens = mask[:, 0].sum(-1)
      scores = scores.permute(1, 2, 0)
      seq_len, seq_len, batch_size = scores.shape
      s = scores.new_zeros(seq_len, seq_len, batch_size)
      p = scores.new_zeros(seq_len, seq_len, batch_size).long()
  
      for w in range(1, seq_len):
          n = seq_len - w
          starts = p.new_tensor(range(n)).unsqueeze(0)
  
          if w == 1:
              s.diagonal(w).copy_(scores.diagonal(w))
              continue
          # [n, w, batch_size]
          s_span = stripe(s, n, w - 1, (0, 1)) + stripe(
              s, n, w - 1, (1, w), 0
          )
          # [batch_size, n, w]
          s_span = s_span.permute(2, 0, 1)
          # [batch_size, n]
          s_span, p_span = s_span.max(-1)
          s.diagonal(w).copy_(s_span + scores.diagonal(w))
          p.diagonal(w).copy_(p_span + starts + 1)
  
      def backtrack(p, i, j):
          if j == i + 1:
              return [(i, j)]
          split = p[i][j]
          ltree = backtrack(p, i, split)
          rtree = backtrack(p, split, j)
          return [(i, j)] + ltree + rtree
  
      p = p.permute(2, 0, 1).tolist()
      trees = [
          backtrack(p[i], 0, length)
          for i, length in enumerate(lens.tolist())
      ]
  
      return trees
  
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 7 for calling a global function with example usage: cky(scores, mask) and returns: trees, unknown, list