Use local sequence alignment, such as the Smith-Waterman algorithm, to compare the globin fragment with the matching region of each full-length target. A global sequence alignment would penalize long target flanks absent from the fragment. For a linear gap penalty the dynamic programming recurrence includes a restart option:Initialize boundary entries to zero, start traceback at the largest entry anywhere, and stop at zero. If the entire query is known to be valid and must be retained, fitting sequence alignment is a suitable refinement: align the whole fragment while leaving target flanks unpenalized.
First check the sequence alphabet: the prompt calls the targets “genes”. If the FASTA format file contains DNA rather than protein, translate the relevant coding sequences into amino acids before a protein-to-protein sequence alignment. If coding frames are unknown, search translated frames. A file in FASTA format specifies storage syntax, not whether the contents are nucleotides or residues.
Use the supplied BLOSUM62 entry for every diagonal move in the Smith-Waterman algorithm, while retaining the stipulated linear gap penalty of . If and are the current amino acids, the dynamic programming recurrence isThe zero option permits a new local start. The following original implementation also records the traceback coordinates needed in part (c); its tie ordering is left, up, diagonal, and an equal overall maximum replaces the previous best cell, as in the supplied convention:
def local_alignment(query,reference,alphabet,scores,gap=-1):
lookup={aa:i for i,aa in enumerate(alphabet)}
table=np.asarray(scores,dtype=int)
height,width=len(query)+1,len(reference)+1
H=np.zeros((height,width),dtype=int)
back=np.zeros((height,width),dtype=np.int8)
best=(0,0,0)
for i,a in enumerate(query,1):
for j,b in enumerate(reference,1):
# Order implements the printed LEFT, UP, DIAGONAL tie priority.
candidates=(0,H[i,j-1]+gap,H[i-1,j]+gap,
H[i-1,j-1]+int(table[lookup[a],lookup[b]]))
value=max(candidates);H[i,j]=value
back[i,j]=0 if value==0 else candidates.index(value)
if value>=best[0]:best=(value,i,j)
score,i,j=best;query_end,ref_end=i,j
aq=[];ar=[]
while H[i,j]>0:
step=back[i,j]
if step==1:aq.append('-');ar.append(reference[j-1]);j-=1
elif step==2:aq.append(query[i-1]);ar.append('-');i-=1
elif step==3:aq.append(query[i-1]);ar.append(reference[j-1]);i-=1;j-=1
qa=''.join(reversed(aq));ra=''.join(reversed(ar));length=len(qa)
identities=sum(a==b and a!='-' for a,b in zip(qa,ra))
similarities=sum(a!='-' and b!='-' and table[lookup[a],lookup[b]]>0 for a,b in zip(qa,ra))
gaps=sum(a=='-' or b=='-' for a,b in zip(qa,ra))
return dict(query=qa,reference=ra,score=int(score),query_start=i+1,query_end=query_end,
reference_start=j+1,reference_end=ref_end,query_length=len(query),reference_length=len(reference),
alignment_length=length,identities=int(identities),similarities=int(similarities),gaps=int(gaps),
identity_percent=100*identities/length if length else 0.,
similarity_percent=100*similarities/length if length else 0.,gap_percent=100*gaps/length if length else 0.)
queries = {"baboon": baboon, "squirrel_monkey": squirrel_monkey,
"dingo": dingo, "goldfish": goldfish}
alignments = {
name: local_alignment(seq, reference_epo_receptor_human, amino_acids, bmat)
for name, seq in queries.items()
}
for name, result in alignments.items():
print(name, "score", result["score"])
print(result["query"])
print(result["reference"])The resulting local sequence alignments, with the query above the reference, are:
baboon; score 314
SLLTPSDLDPLILTLSLILVLIVVLLTVLALLSHRRALKQKIWPGIPSPESEFEGLFTTHKG-FQL
SLLTPSDLDPLILTLSLILVVILVLLTVLALLSHRRALKQKIWPGIPSPESEFEGLFTTHKGNFQLsquirrel monkey; score 278
VCFWEEAASAGMGPDNYSFSYQL-DNEPWKR-CRLHQTPTARGVVRFWCSLPRADTSS
VCFWEEAASAGVGPGNYSFSYQLED-EPWK-LCRLHQAPTARGAVRFWCSLPTADTSSdingo; score 301
MNHLW--THLWPG-VGSLCLLLAGAAWASLPKP-L-DPKFESKAALLAARAPEELLCFTERLEDLVCFWEE
MDHL-GAS-LWP-QVGSLCLLLAGAAWAP-P-PNLPDPKFESKAALLAARGPEELLCFTERLEDLVCFWEEgoldfish; score 190
L--LVLSIGLILC--L-LSLTVI-L-SHQKFLLK-KLWPDIPTPEHKFPGLFTVYKGDFKE-WMSH-NNGSM
LDPLILTLSLILVVILVL-LTVLALLSHRR-ALKQKIWPGIPSPESEFEGLFTTHKGNF-QLWL-YQNDGCLThe several short gaps are a consequence of the specified inexpensive linear gap penalty; substituting a different default or an affine gap penalty would solve a different scoring problem.
Smith-Waterman algorithm Created 2026-10-20 Updated 2026-11-05
The Smith-Waterman algorithm finds an optimal local sequence alignment for a specified additive scoring scheme. For a linear gap penalty , a dynamic programming score satisfiesZero permits an alignment to restart; tracing back from the largest entry to zero recovers a highest-scoring segment pair. Every optimal ending must have one of the listed final steps, which proves the recurrence by induction over the table. Optimality concerns this score, not guaranteed biological ancestry. [ref]
Identification of common molecular subsequences by Temple F. Smith and Michael S. Waterman. Smith and Waterman, 1981, Identification of common molecular subsequences
Temple F. Smith 2026-11-05
Temple F. Smith coauthored the algorithm for finding maximally similar segments within longer molecular sequences, now known as the Smith-Waterman algorithm. Its dynamic programming table permits a fresh start at score zero; a high-scoring segment can therefore begin and end inside either input rather than being forced to span both entire sequences.[ref]
Identification of common molecular subsequences by Temple F. Smith and Michael S. Waterman. Algorithm, equation 1 and traceback description, printed pp. 195–196
The zero option is a mechanistic part of the optimization: it discards a sufficiently unfavorable preceding alignment. Alignment traceback begins at a largest table entry and ends at zero. This supports finding a conserved region embedded within otherwise different sequences; the resulting similarity still requires biological interpretation rather than automatically proving a particular evolutionary history.