from typing import List

import numpy as np

def get_copyable_spans(input: List[str], output: List[str]) -> np.ndarray:
    """
    Return a 3D tensor copy_mask[k, i, j] that for a given location k shows the all the possible
       spans that can be copied.

       All valid start locations can be obtained at point k by diag(copy_masks[k])

       All the possible end positions at position k, given a starting span i are given by copy_mask[k, i]
    """
    copy_masks = np.zeros((len(output), len(input), len(input)), dtype=np.bool)  # out-len x start_pos x end_pos
    for k in range(len(output)-1, -1, -1):
        for i in range(len(input)):
            if input[i] == output[k]:
                if k + 1 < len(output) and i + 1 < len(input):
                    # Everything valid end point at k+1 is also valid here
                    copy_masks[k, i] = copy_masks[k+1, i+1]
                copy_masks[k, i, i] = True

    return copy_masks

from typing import List

import numpy as np

def get_copyable_spans(input: List[str], output: List[str]) -> np.ndarray:
    """
    Return a 3D tensor copy_mask[k, i, j] that for a given location k shows the all the possible
       spans that can be copied.

       All valid start locations can be obtained at point k by diag(copy_masks[k])

       All the possible end positions at position k, given a starting span i are given by copy_mask[k, i]
    """
    copy_masks = np.zeros((len(output), len(input), len(input)), dtype=np.bool)  # out-len x start_pos x end_pos
    for k in range(len(output)-1, -1, -1):
        for i in range(len(input)):
            if input[i] == output[k]:
                if k + 1 < len(output) and i + 1 < len(input):
                    # Everything valid end point at k+1 is also valid here
                    copy_masks[k, i] = copy_masks[k+1, i+1]
                copy_masks[k, i, i] = True

    return copy_masks

Return a 3D tensor copy_mask[k, i, j] that for a given location k shows the all the possible
        spans that can be copied.
 
        All valid start locations can be obtained at point k by diag(copy_masks[k])
 
        All the possible end positions at position k, given a starting span i are given by copy_mask[k, i] # out-len x start_pos x end_pos # Everything valid end point at k+1 is also valid here