def precision(relevant_ranks: list) -> list:
    """
    A function to return the precision as a function of rank.
    The function must be passed a list of the rank positions of
    relevant documents.
    """
    n = max(relevant_ranks)
    results = [0.]*n
    n_retrieved = 0
    n_relevant = 0
    for i in range(n):
        rank = i + 1
        if rank in relevant_ranks:
            n_relevant += 1
        n_retrieved += 1
        results[i] = n_relevant/n_retrieved
    return results


def recall(relevant_ranks: list) -> list:
    """
    A function to return the recall as a function of rank.
    The function must be passed a list of the rank positions of
    relevant documents.
    """
    n = max(relevant_ranks)
    results = [0.]*n
    total_relevant = len(relevant_ranks)
    n_relevant = 0
    for i in range(n):
        rank = i + 1
        if rank in relevant_ranks:
            n_relevant += 1
        results[i] = n_relevant/total_relevant
    return results


def interpolate_precision(recall: list, precision: list) -> list:
    """
    A function to interpolate precision values.  The function
    returns a tuple of the interpolated recall and precision.
    """
    if len(recall) == 0 or len(precision) == 0:
        return ([], [])

    # Interpolate to the right.
    n = len(precision)
    int_precision = [0.] * n
    for i in range(n):
        int_precision[i] = max(precision[i:])

    # Interpolate back to recall = 0.
    int_recall = recall.copy()
    if int_recall[0] != 0:
        int_recall = [0] + int_recall
        int_precision = [int_precision[0]] + int_precision

    return (int_recall, int_precision)


def average_precision(relevant_ranks: list, precision: list) -> list:
    """
    A function to calculate the average precision at
    each rank.
    """
    n = len(precision)
    ranks = list(range(1, n+1))
    results = [0.] * n
    n_relevant = [0] * n
    for i in range(n):
        if i > 0:
            results[i] += results[i - 1]
            n_relevant[i] += n_relevant[i - 1]
        if ranks[i] in relevant_ranks:
            results[i] += precision[i]
            n_relevant[i] += 1
    for i in range(n):
        results[i] /= n_relevant[i]
    return results