def farthest_point_idx(sampled_points, initial_points, num_points):
    curr_points = np.empty(num_points, dtype=np.int64)
    dists = np.full(len(sampled_points), np.inf)

    if initial_points is None:
        dists = np.minimum(
            dists, norm(sampled_points - sampled_points[0].reshape((1, -1))))
        curr_points[0] = 0
        start_idx = 1
    else:
        for i in range(len(initial_points)):
            dists = np.minimum(
                dists,
                norm(sampled_points - initial_points[i].reshape((1, -1))))

        start_idx = 0

    for i in range(start_idx, num_points):
        curr_points[i] = np.argmax(dists)
        dists = np.minimum(
            dists,
            norm(sampled_points -
                 sampled_points[curr_points[i]].reshape((1, -1))))

    return curr_points
def sample_on_line_segments(x, x_perturb, sigma):
    small_perturb = 0.003
    norms = norm(x_perturb - x)
    prefix = []

    for i in range(len(norms)):
        if i == 0:
            prefix.append(norms[i])
        else:
            prefix.append(prefix[i - 1] + norms[i])

    total_prob = prefix[-1]
    count = np.zeros(len(norms))

    for i in range(sigma):
        rand = np.random.uniform(0.0, total_prob)
        idx = binary_search(prefix, rand)
        count[idx] += 1.0

    x_sample = np.empty((sigma, 3))
    idx = 0

    for i in range(len(norms)):
        for j in range(count[i]):
            x_sample[idx] = x[i] + (
                x_perturb[i] -
                x[i]) * j / count[i] + small_perturb * np.random.randn(3)
            idx += 1

    return x_sample