def check_distance_to_permuted_principal_subrows_lb(r_distribution, s_distribution, d):
    """
    For vectors r of size m and s, a row of some n×n distance matrix D,
    check if l∞-distance from r to the set P, comprised of permutations
    of those subvectors of s that are a row of some m×m principal
    submatrix of D, is ≥ d.

    Parameters
    ----------
    r_distribution: np.array (max_distance)
        Frequency distribution of r, positive integer vector.
    s_distribution: np.array (max_distance)
        Frequency distribution of s, positive integer vector no smaller
        in length than r;
    d: int
        Lower bound candidate for l∞-distance from r to P; d > 0.

    Returns
    --------
    d_is_distance_to_permuted_principal_subrows_lb: bool
        Whether l∞-distance from r to P is ≥ d.
    """
    def next_i_and_j(min_i, min_j):
        # Find reversed r distribution index of smallest r entries yet
        # to be assigned. Then find index in reversed s distribution of
        # smallest s entries to which the r entries can be assigned to.
        try:
            i = next(i for i in range(min_i, len(reversed_r_distribution))
                     if reversed_r_distribution[i] > 0)
        except StopIteration:
            # All r entries are assigned.
            i = None
            j = min_j
        else:
            j = next_j(i, max(i - (d - 1), min_j))

        return i, j

    def next_j(i, min_j):
        # Find reversed s distribution index of smallest s entries to
        # which r entries, corresponding to a given reversed r
        # distribution index, can be assigned to.
        try:
            j = next(j for j in range(min_j, min(i + (d - 1),
                                                 len(reversed_s_distribution) - 1) + 1)
                     if reversed_s_distribution[j] > 0)
        except StopIteration:
            # No s entries left to assign the particular r entries to.
            j = None

        return j

    # Copy to allow modifications and stay pure; reverse for the
    # frequencies of smaller entries to come first, to be compatible
    # even with distributions of different lengths.
    reversed_r_distribution = list(r_distribution[::-1])
    reversed_s_distribution = list(s_distribution[::-1])
    # Injectively assign r entries to s entries if their difference
    # is < d, going from smallest to largest entries in both r and s,
    # until all r entries are assigned or such assignment proves
    # unfeasible.
    i, j = next_i_and_j(0, 0)
    while i is not None and j is not None:
        if reversed_r_distribution[i] <= reversed_s_distribution[j]:
            reversed_s_distribution[j] -= reversed_r_distribution[i]
            reversed_r_distribution[i] = 0
            i, j = next_i_and_j(i, j)
        else:
            reversed_r_distribution[i] -= reversed_s_distribution[j]
            reversed_s_distribution[j] = 0
            j = next_j(i, j)

    # The assignment is feasible if and only if |r - p| < d for some
    # p ∈ P, and therefore infeasible if and only if l∞-distance from
    # r to P is ≥ d.
    d_is_distance_to_permuted_principal_subrows_lb = (j is None)

    return d_is_distance_to_permuted_principal_subrows_lb