def _partition_mat(M):
    """
    partition the schur form matrix into several blocks,
    then return the block slices.

    this function is inspired by ilayn/harold
    https://github.com/ilayn/harold

    :param M: the schur form matrix
    :type M: np.ndarray
    :return: block indices
    :rtype: List[List[Tuple[slice, slice]]]
    """
    n = M.shape[0]
    i = 0
    diagnose_indices = []
    while i < n:
        if i + 1 == n or M[i + 1, i] == 0:
            part = (slice(i, i + 1), slice(i, i + 1))
            i += 1
        else:
            part = (slice(i, i + 2), slice(i, i + 2))
            i += 2
        diagnose_indices.append(part)

    indices = [[] for _ in diagnose_indices]
    for i, (m, _) in enumerate(diagnose_indices):
        indices[i].append((m, m))
        for j, (n, _) in enumerate(diagnose_indices[i + 1:], i + 1):
            indices[i].append((m, n))
            indices[j].append((n, m))
    return indices