<jupyter_start><jupyter_text>The CAMEOS algorithm The CAMEOS algorithm considers first-order and second-order aspects of protein sequence. First-order sequence likelihoods can be derived from observations in a single column of a multiple sequence alignment. Second-order terms define dependencies between amino acids, which can arise from long-range contacts between amino acids in a protein’s folded 3-D state.  PreludeThe first stage of the CAMEOS algorithm utilizes [dynamic programming](https://en.wikipedia.org/wiki/Dynamic_programming) to find a globally optimal encoding solution based on first-order protein sequence information. The solution depends on designing the overlapping sequence through a combination of optimal solutions to tractable sub-problems and can be demonstrated without recursion in approximately ~150 lines of python code which we provide below.We consider encoding two protein sequences, "alpha" and "beta", on a single piece of DNA. For this example, we consider a +1 encoding, meaning that the first nucleotide of each of beta’s codons immediately follow the first nucleotide of each of alpha’s codons. ~~~~  +1:   H  K  T  S  T  E   <- "alpha"  CATAACACAAGCACCGAA    I  T  Q  A  P     <- "beta"~~~~Completely synonymous double-encoding solutions are unlikely to occur, and for simplicity of exposition we consider a [BLOSUM62 penalty](https://en.wikipedia.org/wiki/BLOSUM) for mutations to amino acids. Later, we will describe how the algorithm can be further generalized to work in all frames and extend our substitution score to one that uses a HMM statistical parameterization.  Codon tables and substitution scoringTo start, we introduce some basic code to keep track of codons and their translations. We can use Biopython to import the BLOSUM62 matrix. We also define codons that begin and end with specific nucleotides, for later convenience. We further define our targets to be the E. coli proteins infA and ribF.<jupyter_code>#BLOSUM62 matrix. Accessed through Biopython: from Bio.SubsMat import MatrixInfo; blosum62 = MatrixInfo.blosum62
blosum62 = {('B', 'N'): 3, ('W', 'L'): -2, ('G', 'G'): 6, ('X', 'S'): 0, ('X', 'D'): -1, ('K', 'G'): -2, ('S', 'E'): 0, ('X', 'M'): -1, ('Y', 'E'): -2, ('W', 'R'): -3, ('I', 'R'): -3, ('X', 'Z'): -1, ('H', 'E'): 0, ('V', 'M'): 1, ('N', 'R'): 0, ('I', 'D'): -3, ('F', 'D'): -3, ('W', 'C'): -2, ('N', 'A'): -2, ('W', 'Q'): -2, ('L', 'Q'): -2, ('S', 'N'): 1, ('Z', 'K'): 1, ('V', 'N'): -3, ('Q', 'N'): 0, ('M', 'K'): -1, ('V', 'H'): -3, ('G', 'E'): -2, ('S', 'L'): -2, ('P', 'R'): -2, ('D', 'A'): -2, ('S', 'C'): -1, ('E', 'D'): 2, ('Y', 'G'): -3, ('W', 'P'): -4, ('X', 'X'): -1, ('Z', 'L'): -3, ('Q', 'A'): -1, ('V', 'Y'): -1, ('W', 'A'): -3, ('G', 'D'): -1, ('X', 'P'): -2, ('K', 'D'): -1, ('T', 'N'): 0, ('Y', 'F'): 3, ('W', 'W'): 11, ('Z', 'M'): -1, ('L', 'D'): -4, ('M', 'R'): -1, ('Y', 'K'): -2, ('F', 'E'): -3, ('M', 'E'): -2, ('S', 'S'): 4, ('X', 'C'): -2, ('Y', 'L'): -1, ('H', 'R'): 0, ('P', 'P'): 7, ('K', 'C'): -3, ('S', 'A'): 1, ('P', 'I'): -3, ('Q', 'Q'): 5, ('L', 'I'): 2, ('P', 'F'): -4, ('B', 'A'): -2, ('Z', 'N'): 0, ('M', 'Q'): 0, ('V', 'I'): 3, ('Q', 'C'): -3, ('I', 'H'): -3, ('Z', 'D'): 1, ('Z', 'P'): -1, ('Y', 'W'): 2, ('T', 'G'): -2, ('B', 'P'): -2, ('P', 'A'): -1, ('C', 'D'): -3, ('Y', 'H'): 2, ('X', 'V'): -1, ('B', 'B'): 4, ('Z', 'F'): -3, ('M', 'L'): 2, ('F', 'G'): -3, ('S', 'M'): -1, ('M', 'G'): -3, ('Z', 'Q'): 3, ('S', 'Q'): 0, ('X', 'A'): 0, ('V', 'T'): 0, ('W', 'F'): 1, ('S', 'H'): -1, ('X', 'N'): -1, ('B', 'Q'): 0, ('K', 'A'): -1, ('I', 'Q'): -3, ('X', 'W'): -2, ('N', 'N'): 6, ('W', 'T'): -2, ('P', 'D'): -1, ('B', 'C'): -3, ('I', 'C'): -1, ('V', 'K'): -2, ('X', 'Y'): -1, ('K', 'R'): 2, ('Z', 'R'): 0, ('W', 'E'): -3, ('T', 'E'): -1, ('B', 'R'): -1, ('L', 'R'): -2, ('Q', 'R'): 1, ('X', 'F'): -1, ('T', 'S'): 1, ('B', 'D'): 4, ('Z', 'A'): -1, ('M', 'N'): -2, ('V', 'D'): -3, ('F', 'A'): -2, ('X', 'E'): -1, ('F', 'H'): -1, ('M', 'A'): -1, ('K', 'Q'): 1, ('Z', 'S'): 0, ('X', 'G'): -1, ('V', 'V'): 4, ('W', 'D'): -4, ('X', 'H'): -1, ('S', 'F'): -2, ('X', 'L'): -1, ('B', 'S'): 0, ('S', 'G'): 0, ('P', 'M'): -2, ('Y', 'M'): -1, ('H', 'D'): -1, ('B', 'E'): 1, ('Z', 'B'): 1, ('I', 'E'): -3, ('V', 'E'): -2, ('X', 'T'): 0, ('X', 'R'): -1, ('R', 'R'): 5, ('Z', 'T'): -1, ('Y', 'D'): -3, ('V', 'W'): -3, ('F', 'L'): 0, ('T', 'C'): -1, ('X', 'Q'): -1, ('B', 'T'): -1, ('K', 'N'): 0, ('T', 'H'): -2, ('Y', 'I'): -1, ('F', 'Q'): -3, ('T', 'I'): -1, ('T', 'Q'): -1, ('P', 'L'): -3, ('R', 'A'): -1, ('B', 'F'): -3, ('Z', 'C'): -3, ('M', 'H'): -2, ('V', 'F'): -1, ('F', 'C'): -2, ('L', 'L'): 4, ('M', 'C'): -1, ('C', 'R'): -3, ('D', 'D'): 6, ('E', 'R'): 0, ('V', 'P'): -2, ('S', 'D'): 0, ('E', 'E'): 5, ('W', 'G'): -2, ('P', 'C'): -3, ('F', 'R'): -3, ('B', 'G'): -1, ('C', 'C'): 9, ('I', 'G'): -4, ('V', 'G'): -3, ('W', 'K'): -3, ('G', 'N'): 0, ('I', 'N'): -3, ('Z', 'V'): -2, ('A', 'A'): 4, ('V', 'Q'): -2, ('F', 'K'): -3, ('T', 'A'): 0, ('B', 'V'): -3, ('K', 'L'): -2, ('L', 'N'): -3, ('Y', 'N'): -2, ('F', 'F'): 6, ('L', 'G'): -4, ('B', 'H'): 0, ('Z', 'E'): 4, ('Q', 'D'): 0, ('X', 'B'): -1, ('Z', 'W'): -3, ('S', 'K'): 0, ('X', 'K'): -1, ('V', 'R'): -3, ('K', 'E'): 1, ('I', 'A'): -1, ('P', 'H'): -2, ('B', 'W'): -4, ('K', 'K'): 5, ('H', 'C'): -3, ('E', 'N'): 0, ('Y', 'Q'): -1, ('H', 'H'): 8, ('B', 'I'): -3, ('C', 'A'): 0, ('I', 'I'): 4, ('V', 'A'): 0, ('W', 'I'): -3, ('T', 'F'): -2, ('V', 'S'): -2, ('T', 'T'): 5, ('F', 'M'): 0, ('L', 'E'): -3, ('M', 'M'): 5, ('Z', 'G'): -2, ('D', 'R'): -2, ('M', 'D'): -3, ('W', 'H'): -2, ('G', 'C'): -3, ('S', 'R'): -1, ('S', 'I'): -2, ('P', 'Q'): -1, ('Y', 'A'): -2, ('X', 'I'): -1, ('E', 'A'): -1, ('B', 'Y'): -3, ('K', 'I'): -3, ('H', 'A'): -2, ('P', 'G'): -2, ('F', 'N'): -3, ('H', 'N'): 1, ('B', 'K'): 0, ('V', 'C'): -1, ('T', 'L'): -1, ('P', 'K'): -1, ('W', 'S'): -3, ('T', 'D'): -1, ('T', 'M'): -1, ('P', 'N'): -2, ('K', 'H'): -1, ('T', 'R'): -1, ('Y', 'R'): -2, ('L', 'C'): -1, ('B', 'L'): -4, ('Z', 'Y'): -2, ('W', 'N'): -4, ('G', 'A'): 0, ('S', 'P'): -1, ('E', 'Q'): 2, ('C', 'N'): -3, ('H', 'Q'): 0, ('D', 'N'): 1, ('Y', 'C'): -2, ('L', 'H'): -3, ('E', 'C'): -4, ('Z', 'H'): 0, ('H', 'G'): -2, ('P', 'E'): -1, ('Y', 'S'): -2, ('G', 'R'): -2, ('B', 'M'): -3, ('Z', 'Z'): 4, ('W', 'M'): -1, ('Y', 'T'): -2, ('Y', 'P'): -3, ('Y', 'Y'): 7, ('T', 'K'): -1, ('Z', 'I'): -3, ('T', 'P'): -1, ('V', 'L'): 1, ('F', 'I'): 0, ('G', 'Q'): -2, ('L', 'A'): -1, ('M', 'I'): 1}

#Define constants for bases, codons, and amino acid translations.
bases = [l.upper() for l in 'tcag']
codons = [a+b+c for a in bases for b in bases for c in bases]
amino_acids = 'FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG'
codon_table = dict(zip(codons, amino_acids))

#Non-stop codon codons beginning with defined first letter.
first_letter_codons = {'T': ['TTT', 'TTC', 'TTA', 'TTG', 'TCT', 'TCC', 
                             'TCA', 'TCG', 'TAT', 'TAC', 'TGT', 'TGC', 'TGG'],
                       'G': ['GTT', 'GTC', 'GTA', 'GTG', 'GCT', 'GCC', 'GCA', 'GCG', 
                             'GAT', 'GAC', 'GAA', 'GAG', 'GGT', 'GGC', 'GGA', 'GGG'],
                       'A': ['ATT', 'ATC', 'ATA', 'ATG', 'ACT', 'ACC', 'ACA', 'ACG', 
                             'AAT', 'AAC', 'AAA', 'AAG', 'AGT', 'AGC', 'AGA', 'AGG'],
                       'C': ['CTT', 'CTC', 'CTA', 'CTG', 'CCT', 'CCC', 'CCA', 'CCG', 
                             'CAT', 'CAC', 'CAA', 'CAG', 'CGT', 'CGC', 'CGA', 'CGG']}

last_letter_codons = {'C': ['TTC', 'TCC', 'TAC', 'TGC', 'CTC', 'CCC', 'CAC', 'CGC', 
                            'ATC', 'ACC', 'AAC', 'AGC', 'GTC', 'GCC', 'GAC', 'GGC'],
                      'T': ['TTT', 'TCT', 'TAT', 'TGT', 'CTT', 'CCT', 'CAT', 'CGT', 
                            'ATT', 'ACT', 'AAT', 'AGT', 'GTT', 'GCT', 'GAT', 'GGT'],
                      'G': ['TTG', 'TCG', 'TGG', 'CTG', 'CCG', 'CAG', 'CGG', 'ATG', 
                            'ACG', 'AAG', 'AGG', 'GTG', 'GCG', 'GAG', 'GGG'],
                      'A': ['TTA', 'TCA', 'CTA', 'CCA', 'CAA', 'CGA', 'ATA', 'ACA', 
                            'AAA', 'AGA', 'GTA', 'GCA', 'GAA', 'GGA']}

def translate(seq):
    seq = seq.upper()
    seq_codons = filter(lambda s: len(s) == 3, [seq[x:x+3] for x in range(0, len(seq), 3)])
    #Separate sequence into codons of length 3 (above), return translations of these codons (below).
    return "".join([codon_table[codon] for codon in seq_codons])

def score_substitution(pair, matrix):
    if "*" in pair:
        return -1000 #if there's a stop codon, assign a large penalty
    if pair not in matrix: #BLOSUM stores only one half of matrix so we may need to reverse tuple.
        return matrix[(tuple(reversed(pair)))]
    else:
        return matrix[pair]<jupyter_output><empty_output><jupyter_text>Double-encoding, step-by-stepWe consider constructing a double-encoding sequence. Given that we expect the protein to begin with a start codon, we can stipulate that the first letter of the double-encoding solution will begin with the nucleotide "A".The sequence we are constructing can therefore be represented as:~~~~    A????????????? ... ~~~~where "?" represent bases that are unknown. We note that if we were to fix the fourth base in this sequence (to, for example, the nucleotide "C"), the optimal dinucleotides for the first amino acid in alpha and the first amino acid in beta could be set directly by scoring all dinucleotides with the BLOSUM matrix.Using the proposed fourth base "C", we have a sequence:~~~~    A??C?????????? ... ~~~~Given the base C, we can complete the first codon for both alpha and beta with one of 16 dinucleotides. We must now find the maximum out of the following options:~~~~    max(["A" + dinucleotide + "C" for dinucleotide in ["AA", "AC", "AG", "AT", "CA", "CC", ...]])~~~~Concretely scoring the possibilities:~~~~max(blosum_score{    (A aa C) -> alpha[0] = "K"; beta[0] = "N",        (A ga C) -> alpha[0] = "R"; beta[0] = "D",    (A ac C) -> alpha[0] = "N"; beta[0] = "T",        (A gc C) -> alpha[0] = "S"; beta[0] = "A",    (A ag C) -> alpha[0] = "K"; beta[0] = "S",        (A gg C) -> alpha[0] = "R"; beta[0] = "G",    (A at C) -> alpha[0] = "N"; beta[0] = "I",        (A gt C) -> alpha[0] = "S"; beta[0] = "V",    (A ca C) -> alpha[0] = "T"; beta[0] = "H",        (A ta C) -> alpha[0] = "I"; beta[0] = "Y",    (A cc C) -> alpha[0] = "T"; beta[0] = "P",        (A tc C) -> alpha[0] = "I"; beta[0] = "S",    (A cg C) -> alpha[0] = "T"; beta[0] = "R",        (A tg C) -> alpha[0] = "M"; beta[0] = "C",    (A ct C) -> alpha[0] = "T"; beta[0] = "L",        (A tt C) -> alpha[0] = "I"; beta[0] = "F",    })~~~~This work is performed by the function, `optimal_choice_p1()` which takes a fixed base ("A"), a proposed base ("C"), and the amino acids in alpha and beta that are being optimized. Optionally we can also flag whether we are at the beginning or end of the sequence to deal with special cases of start/stop codons.<jupyter_code>def optimal_choice_p1(fixed_base, proposed_base, alpha_aa, beta_aa, is_start = False, is_end = False):
    if not is_start and not is_end: #typical case
        alpha_scores = {}
        beta_scores = {}

        #Score all codons not leading to a stop codon, recording score in terms of the non-fixed dinucleotides.
        for codon in first_letter_codons[fixed_base]:
            alpha_scores[codon[1:]] = score_substitution((alpha_aa, codon_table[codon]), blosum62)
        for codon in last_letter_codons[proposed_base]:
            beta_scores[codon[:2]] = score_substitution((beta_aa, codon_table[codon]), blosum62)

        #get the set of dinucleotides that don't introduce a stop codon.
        no_stop_codons = set(alpha_scores.keys()).intersection(set(beta_scores.keys()))

        #return top-scoring dinucleotide as well as its score.
        dinuc_scores = {dinuc: alpha_scores[dinuc] + beta_scores[dinuc] for dinuc in no_stop_codons}
        #Return the maximum scoring dinculeotide.
        return sorted(dinuc_scores.items(), key = lambda (key, val): -val)[0]
    
    elif is_start: #we have no choice for the start codon, we just return the score of the ATG at the position.
        if fixed_base == "A":
            alpha_score = score_substitution(('M', 'M'), blosum62)
            beta_score = score_substitution((beta_aa, codon_table["TG" + proposed_base]), blosum62)

            return ('TG', alpha_score + beta_score) #whatever the score for TG, it's optimal (else no protein product).
        elif fixed_base != "A":  #we need A for a start codon so not having one is penalized.
            return ("TG", -10000.0)

    elif is_end:
        if fixed_base == "T":
            #We can get stop codons from TAG / TAA / TGA. We score each dinucleotide.
            scores = {"AG": score_substitution((beta_aa, codon_table["AG" + proposed_base]), blosum62),
                        "AA": score_substitution((beta_aa, codon_table["AA" + proposed_base]), blosum62),
                        "GA": score_substitution((beta_aa, codon_table["GA" + proposed_base]), blosum62)}
            return sorted(scores.items(), key = lambda (key, val): -val)[0]
        elif fixed_base != "T": #we need T for a stop codon, so not having one is penalized.
            return ("AA", -10000.0)<jupyter_output><empty_output><jupyter_text>Consider the first letter of infA, "M" and, without loss of generality, the eighth letter of ribF, "N".The optimal encoding for the proposed letter of "C" is...<jupyter_code>optimal_choice_p1("A", "C", "M", "N", is_start = True)<jupyter_output><empty_output><jupyter_text>The "2" here defines the sum of BLOSUM62 scoring of matching "M" and "M" (+1) and substituting "N" for "C" (-3). Given that this is the first codon, the correct dinucleotide will always be "TG", as we would not have a protein product otherwise.The letter "C" was proposed, but it may not be optimal. We consider the other scores:<jupyter_code>print("A =>", optimal_choice_p1("A", "A", "M", "N", is_start = True))
print("G =>", optimal_choice_p1("A", "G", "M", "N", is_start = True))
print("T =>", optimal_choice_p1("A", "T", "M", "N", is_start = True))<jupyter_output>('A =>', ('TG', -995))
('G =>', ('TG', 1))
('T =>', ('TG', 2))<jupyter_text>We note that "A" is not a feasible encoding, since "TGA" is a stop codon in the beta frame. However, the letter "T" appears to be a nucleotide that scores just as well as "C". The question, then, is whether the sequence:`ATGC???????...` scores better than `ATGT???????...`  Further optimizationThe above decision between C/T highlights that the optimal nucleotide choices for a given frame depend on downstream sequence features. In fact, given that the second amino acid in the infA sequence is alanine (encoded by the codons: "GCA", "GCC", "GCG", "GCT"), the "G" base in the fourth position may be preferable for downstream scoring even though it scores slightly lower in the first tetranucleotide.This observation could suggest a "brute force" optimization procedure, where for example, with a double-encoding of length 4 for proteins alpha and beta at positions, alpha_i and beta_j, we might consider a compound loop such as:<jupyter_code>def brute_force_p1(alpha, beta, alpha_i, beta_j):
    
    #alpha_i, beta_j define the position in the protein (we take alpha_i = 7, beta_j = 0 in the above example).
    base_1 = "A" #assume ATG to start, necessitating "A" as first base.
    top_scores = {}
    cur_score = 0.0
    cur_seq = start_base
    
    for base_4 in ["A", "C", "G", "T"]:
        
        #We determine the best di-nucleotide given the start base and fourth base and current position.
        best_dinuc, best_score = optimal_choice_p1(base_1, base_4, alpha[alpha_i], beta[beta_j], is_start = True)
        #We add the dinucleotide to our current sequence as well as the fourth base.
        cur_seq += best_dinuc + base_4
        #We add the score to our total which we hope to maximize.
        cur_score += best_score
        
        for base_7 in ["A", "C", "G", "T"]:
            
            #We move one position forward in both protein sequences.
            best_di, best_score = optimal_choice_p1(base_4, base_7, alpha[alpha_i + 1], beta[beta_j + 1])
            cur_seq += best_di + base_7
            cur_score += best_score
            
            for base_10 in ["A", "C", "G", "T"]:
                best_di, best_score = optimal_choice_p1(base_7, base_10, alpha[alpha_i + 2], beta[beta_j + 2])
                cur_seq += best_di + base_10
                cur_score += best_score
                
                #Now that we are at end of sequence we can record the result in a dictionary for future use.
                top_scores[(base_4, base_7, base_10)] = (cur_seq, cur_score)
                #Using this approach we would hope to find the minimum-scoring combination of bases.<jupyter_output><empty_output><jupyter_text>Unfortunately, this code requires searching an exponential number of possibilities, and becomes infeasible to run for proteins of relatively short length.Fortunately, our search can be substantially improved by observing an important independence: only the terminal base (the "proposed" base) at the end of each tetranucleotide impacts downstream decisions.When comparing:`ATGC???????...` and `ATGT???????...`The only base interacting with codons beyond the first tetranucleotide is the terminal "C" or "T", while the dinucleotide "TG" only optimizes the first tetranucleotide given fixed ("A") and proposed ("C/T") bases.Further, the scores are additive. If we were to compare`ATGC???????...` vs `GTGC???????...`It is clear that if "ATGC" has a better score than "GTGC", and the score of the downstream ("???????...") sequence depends only on the terminal base "C", then the global score of an optimal downstream sequence is only maximized if it is attached to "ATGC".At each step, we must therefore only keep track of the best sequence for each terminal base. This is done by extending earlier optimal subsequences, up to the end of the sequence, where optimal sequences across all possible terminal bases are considered.Code achieving this aim is shown below:<jupyter_code>def construct_p1(alpha_prot, beta_prot, alpha_position, beta_position, fixed_base = "A"):
    #cur_seq = ""
    #cur_score = 0.0
    best_seq_per_base = {"A": ("A", 0.0), "C": ("C", 0.0), "G": ("G", 0.0), "T": ("T", 0.0)}
    
    #We intend to fully encode all amino acids in the alpha_prot_seq within beta_prot.
    for alpha_i in range(len(alpha_prot)):
        #Get the amino acids at the considered position to evaluate costs of substitutions.
        alpha_aa = alpha_prot[alpha_i]
        beta_aa = beta_prot[beta_position + alpha_i]
        
        #Have an empty dictionary of best scoring sub-sequences according to their terminal letter.
        best_continuation = {"A": None, "C": None, "G": None, "T": None}
        
        #check if start/end for special treatment of substitutions.
        is_start = alpha_i == 0
        is_end = alpha_i == len(alpha_prot) - 1
        
        for fixed_base in "ACGT": #Consider extending earlier subsequences of different termini.
            for proposed_base in "ACGT": #See if extending earlier subsequences results in top-scoring terminal options.
                top_dinuc, top_score = optimal_choice_p1(fixed_base, proposed_base, alpha_aa, beta_aa, is_start, is_end)
                
                #Proposed_seq/score adds to previous seq/score for subsequences we extend.
                proposed_seq = best_seq_per_base[fixed_base][0] + top_dinuc + proposed_base
                proposed_score = best_seq_per_base[fixed_base][1] + top_score
                
                #If the proposal scores better than other subsequences with this terminal position up to this position
                #then record this option 
                if best_continuation[proposed_base] is None or proposed_score >= best_continuation[proposed_base][1]:
                    best_continuation[proposed_base] = (proposed_seq, proposed_score)
                    
        #assign the best sequence per terminal base for this position, to be further extended in next step.
        best_seq_per_base = {proposed_b: best_continuation[proposed_b] for proposed_b in "ACGT"}
    
    #At the end, find which of the four termini have highest score, and return.
    return max(best_seq_per_base.items(), key = lambda entry: entry[1])[1]<jupyter_output><empty_output><jupyter_text>Given that optimal_choice_p1() requires a constant number of operations, the above code clearly requires a constant number of operations for each amino acid in the alpha_prot, evaluating 4x4=16 possible combinations of start/end nucleotides and recording top subsequences as necessary.At the end, the optimal global sequence is returned.  Running an exampleThis algorithm runs very quickly for proteins of typical length (hundreds of amino acids). The results given example inputs of infA and ribF appear fairly compelling.<jupyter_code>def example():
    infA = "MAKEDNIEMQGTVLETLPNTMFRVELENGHVVTAHISGKMRKNYIRILTGDKVTVELTPYDLSKGRIVFRSR*"

    ribF = "MKLIRGIHNLSQAPQEGCVLTIGNFDGVHRGHRALLQGLQEEGRKRNLPVMVMLFEPQPLELFATDKAPA"
    ribF += "RLTRLREKLRYLAECGVDYVLCVRFDRRFAALTAQNFISDLLVKHLRVKFLAVGDDFRFGAGREGDFLLL"
    ribF += "QKAGMEYGFDITSTQTFCEGGVRISSTAVRQALADDNLALAESLLGHPFAISGRVVHGDELGRTIGFPTA"
    ribF += "NVPLRRQVSPVKGVYAVEVLGLGEKPLPGVANIGTRPTVAGIRQQLEVHLLDVAMDLYGRHIQVVLRKKI"
    ribF += "RNEQRFASLDELKAQIARDELTAREFFGLTKPA*"

    alpha_position = 0
    beta_position = 8 #set ahead of time for this example.
    
    p1_seq, p1_score = construct_p1(infA, ribF, alpha_position, beta_position)

    print(p1_seq) #the nucleotides that will encode two proteins.
    print(translate(p1_seq)) #the translation of the infA sequence.
    print(translate(p1_seq[1:])) #print just the double-encoding part of ribF
    print(ribF[:beta_position] + translate(p1_seq[1:]) + ribF[beta_position + len(infA):]) #ribF sequence.
    
example()<jupyter_output>ATGGCTAAGTCAGACTCCGCAGAAAGGCAAGGTACTGTCCTTAGGACACTTCCAGGGACTTCATTCCGGGCATCGCTCTCTAATGGAAGGGTTGCAACAGCAAGGGCGTCGGGAAAACTTGCCCGTAATTATATTCGTATTCTCACCGGAACCTCTGTCACTGTTCGCCTCCGACCGTACTCCCTCTCGTCTGGTAAGATTGCGTTCCGCTCTTCGTAAT
MAKSDSAERQGTVLRTLPGTSFRASLSNGRVATARASGKLARNYIRILTGTSVTVRLRPYSLSSGKIAFRSS*
WLSQTPQKGKVLSLGHFQGLHSGHRSLMEGLQQQGRRENLPVIIFVFSPEPLSLFASDRTPSRLVRLRSALRN
MKLIRGIHWLSQTPQKGKVLSLGHFQGLHSGHRSLMEGLQQQGRRENLPVIIFVFSPEPLSLFASDRTPSRLVRLRSALRNLAECGVDYVLCVRFDRRFAALTAQNFISDLLVKHLRVKFLAVGDDFRFGAGREGDFLLLQKAGMEYGFDITSTQTFCEGGVRISSTAVRQALADDNLALAESLLGHPFAISGRVVHGDELGRTIGFPTANVPLRRQVSPVKGVYAVEVLGLGEKPLPGVANIGTRPTVAGIRQQLEVHLLDVAMDLYGRHIQVVLRKKIRNEQRFASLDELKAQIARDELTAREFFGLTKPA*
{'fraction_non_alphanumeric': 0.20940284025756373, 'fraction_numerical': 0.019934727000088207, 'mean_word_length': 3.511539992041385, 'pattern_counts': {'":': 17, '<': 29, '<?xml version=': 0, '>': 50, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '490969', 'license': 'MIT', 'n_tokens_mistral': 8648, 'n_tokens_neox': 8098, 'n_words': 2890, 'path': 'guide.ipynb', 'repo_name': 'khyox/CAMEOS', 'size': '22674'}