def longest_proper_prefix(P):
    """Solution to exercise R-13.2.

    What is the longest (proper) prefix of the string "cgtacgttcgtacg" that
    is also a suffix of this string?

    ---------------------------------------------------------------------------
    Solution:
    ---------------------------------------------------------------------------
    For a string S of length n:
    1. A prefix is a substring of S of the form S[0:k] for 0 <= k <= n.
    2. A suffix is a substring of S of the form S[j:n] for 0 <= j <= n.

    A proper prefix of a string is a prefix that is not equal to the string
    itself; S[0:k] for 0 <= k < n.

    The string "cgtacgttcgtacg" has length n = 14, and thus will have n + 1
    suffixes and n proper prefixes.  The '' symbol represents the null string
    of length 0.

    The proper prefixes of P for all valid values of k are:
    k =  0, 1,  2,   3,    4,     5,      6,       7,        8,         9,
        '', c, cg, cgt, cgta, cgtac, cgtacg, cgtacgt, cgtacgtt, cgtacgttc,

                10,          11,           12,            13
        cgtacgttcg, cgtacgttcgt, cgtacgttcgta, cgtacgttcgtac

    The suffixes of P for all valid values of j are:
    j =              0,             1,            2,           3,          4,
        cgtacgttcgtacg, cgtacgttcgtac, cgtacgttcgta, cgtacgttcgt, cgtacgttcg,

                5,        6,       7,      8,     9,   10,  11, 12, 13, 14
        cgtacgttc, cgtacgtt, cgtacgt, cgtacg, cgtac, cgta, cgt, cg,  t, ''


    The longest common substring is "cgtacgttcgtac", which is 13 characters
    long.
    """
    n = len(P)
    prefixes = set()
    suffixes = set()
    for k in range(n):
        prefixes.add(P[0:k])        # Only proper prefixes k < n
    for j in range(n+1):
        suffixes.add(P[j:n+1])      # No restrictions on suffixes, j <= n
    common = prefixes & suffixes
    return max(common, key=len)     # Longest common prefix and suffix string