def tokenize_mutation_seq(seq, placeholder_token='_'):
  """Converts a variable-length mutation sequence to a fixed-length sequence.

  For an N-residue reference sequence, the encoding is shape (N+1, M, A), where
  A is the alphabet size (e.g., A=20 for the canonical peptide alphabet) and M
  is the number of distinct mutation types at each position; here, M=2
  (1x sub + 1x ins at each reference sequence position).

  Args:
    seq: (str) A mutation sequence to tokenize; e.g., "__A_" or "aTEST".
    placeholder_token: (str) Sentinel value used to encode non-mutated positions
      in the mutation sequence.
  Returns:
    A length-N+1 sequence of ("<substitution_token>", "<insertion token>")
    2-tuples.
  """
  tokens = []
  i = 0
  # Consume the prefix insertion mutation if there is one.
  # A prefix insertion is denoted by a leading lower case letter on the seq.
  if seq[i].islower():
    tokens.append((placeholder_token, seq[i].upper()))
    i += 1
  else:
    tokens.append((placeholder_token, placeholder_token))

  while i < len(seq):
    if i < len(seq) - 1 and seq[i + 1].islower():
      tokens.append((seq[i], seq[i+1].upper()))
      i += 2
    else:
      tokens.append((seq[i], placeholder_token))
      i += 1
  return tokens