pythonalgorithmfunctionsequence-alignment

Smith-Waterman Implement in python


I want to write the first part of the Smith-Waterman algorithm in python with basic functions.

I found this example, but it doesn't give me what I'm looking for.

def zeros(X: int, Y: int):
    #        ^       ^  incorrect type annotations. should be str
    lenX = len(X) + 1
    lenY = len(Y) + 1
    matrix = []
    for i in range(lenX):
        matrix.append([0] * lenY)
    # A more "pythonic" way of expressing the above would be:
    # matrix = [[0] * len(Y) + 1 for _ in range(len(x) + 1)]
    
    def score(X, Y):
        #     ^  ^ shadowing variables from outer scope. this is not a bug per se but it's considered bad practice
        if X[n] == Y[m]: return 4
        #    ^       ^  variables not defined in scope
        if X[n] == '-' or Y[m] == '-': return -4
        #    ^              ^  variables not defined in scope
        else: return -2

    def SmithWaterman(X, Y, score): # this function is never called
        #                   ^ unnecessary function passed as parameter. function is defined in scope
        for n in range(1, len(X) + 1):
            for m in range(1, len(Y) + 1):
                align = matrix[n-1, m-1] + (score(X[n-1], Y[m-1]))
                #                 ^ invalid list lookup. should be: matrix[n-1][m-1]
                indelX = matrix[n-1, m] + (score(X[n-1], Y[m]))
                #                                          ^ out of bounds error when m == len(Y)
                indelY = matrix[n, m-1] + (score(X[n], Y[m-1]))
                #                                  ^ out of bounds error when n == len(X)
        matrix[n, m] = max(align, indelX, indelY, 0)
        # this should be nested in the inner for-loop. m, n, indelX, and indelY are not defined in scope here
    print(matrix)

zeros("ACGT", "ACGT")

On a book I found this algorithm, but I couldn't implement it correctly.

input: sequences s and t, with |s| =n, |t| = m, score function, penality InDel

match +1, mismatch -2, InDel -1

M = matrix of size n+1 * m+1
M[i,j] = 0
i=j=0

enter image description here

Any help please Thanks


Solution

  • The problems with the code you presented are well described in the comments in that piece of code.

    Assuming that you want a linear gap-penalty of 2 points, and you are looking for the first phase algorithm only (so excluding the trace-back process), the code can be fixed as follows:

    def score(x, y):
        return 4 if x == y else (
            -4 if '-' in (x, y) else -2
        )
    
    def zeros(a, b):
        penalty = 2  # linear penalty (see Wikipedia)
        nextrow = [0] * (len(b) + 1)
        matrix = [nextrow]
        for valA in a:
            row, nextrow = nextrow, [0]
            for m, valB in enumerate(b):
                nextrow.append(max(
                    row[m] + score(valA, valB),
                    row[m+1] - penalty,
                    nextrow[m] - penalty,
                    0
                ))
            matrix.append(nextrow)
        return matrix
    
    # Example run:
    result = zeros("ACGT", "AC-GT")
    print(result)