<commit_before>#!/usr/bin/env python
'''
Simple Smith-Waterman aligner
'''

import sys
import StringIO


class ScoringMatrix(object):
    def __init__(self, filename=None, text=None):
        assert filename or text

        if filename:
            fs = open(filename)
        else:
            fs = StringIO.StringIO(text)

        self.scores = []
        self.bases = None

        for line in fs:
            if not self.bases:
                self.bases = line.split()
                self.base_count = len(self.bases)
            else:
                cols = line.split()
                self.scores.extend([int(x) for x in cols[1:]])
        fs.close()

    def score(self, one, two):
        one_idx = 0
        two_idx = 0
        for i, b in enumerate(self.bases):
            if b == one:
                one_idx = i
            if b == two:
                two_idx = i

        return self.scores[(one_idx * self.base_count) + two_idx]


class NucleotideScoringMatrix(object):
    def __init__(self, match=1, mismatch=-1):
        self.match = match
        self.mismatch = mismatch

    def score(self, one, two):
        if one == two:
            return self.match
        return self.mismatch


class Matrix(object):
    def __init__(self, rows, cols, init=None):
        self.rows = rows
        self.cols = cols
        self.values = [init, ] * rows * cols

    def get(self, row, col):
        return self.values[(row * self.cols) + col]

    def set(self, row, col, val):
        self.values[(row * self.cols) + col] = val


class LocalAlignment(object):
    def __init__(self, scoring_matrix, gap_penalty=-1):
        self.scoring_matrix = scoring_matrix
        self.gap_penalty = gap_penalty

    def align(self, ref, query):
        ref = ref.upper()
        query = query.upper()

        matrix = Matrix(len(query) + 1, len(ref) + 1, (0, ' '))

        max_val = 0
        max_row = 0
        max_col = 0

        # calculate matrix
        for row in xrange(1, matrix.rows):
            for col in xrange(1, matrix.cols):
                mm = matrix.get(row - 1, col - 1)[0] + self.scoring_matrix.score(query[row - 1], ref[col - 1])
                delete = matrix.get(row - 1, col)[0] + self.gap_penalty
                insert = matrix.get(row, col - 1)[0] + self.gap_penalty
                m = max(0, mm, delete, insert)

                if m == mm:
                    val = (m, 'm')
                elif m == delete:
                    val = (m, 'd')
                elif m == insert:
                    val = (m, 'i')
                else:
                    val = (0, 'x')

                if val[0] >= max_val:
                    max_val = val[0]
                    max_row = row
                    max_col = col

                matrix.set(row, col, val)

        # backtrack
        row = max_row
        col = max_col
        val = max_val
        op = 'm'

        aln = []

        while val > 0:
            aln.append(op)

            op = matrix.get(row, col)[1]

            if op == 'm':
                row -= 1
                col -= 1
            elif op == 'd':
                row -= 1
            elif op == 'i':
                col -= 1
            else:
                break

            val, op = matrix.get(row, col)
        aln.reverse()

        return Alignment(query, ref, row, col, self._reduce_cigar(aln), max_val)

    def _reduce_cigar(self, cigar):
        count = 1
        last = None
        ret = []
        for op in cigar:
            if last and op == last:
                count += 1
            elif last:
                ret.append((count, last.upper()))
                count = 1
            last = op

        ret.append((count,last.upper()))
        return ret

    def dump_matrix(self, ref, query, matrix, show_row=-1, show_col=-1):
        sys.stdout.write('   -   ')
        sys.stdout.write('   '.join(ref))
        sys.stdout.write('\n')
        for row in xrange(matrix.rows):
            if row == 0:
                sys.stdout.write('-')
            else:<commit_msg>edge case where there is no alignment...<commit_after>#!/usr/bin/env python
'''
Simple Smith-Waterman aligner
'''

import sys
import StringIO


class ScoringMatrix(object):
    def __init__(self, filename=None, text=None):
        assert filename or text

        if filename:
            fs = open(filename)
        else:
            fs = StringIO.StringIO(text)

        self.scores = []
        self.bases = None

        for line in fs:
            if not self.bases:
                self.bases = line.split()
                self.base_count = len(self.bases)
            else:
                cols = line.split()
                self.scores.extend([int(x) for x in cols[1:]])
        fs.close()

    def score(self, one, two):
        one_idx = 0
        two_idx = 0
        for i, b in enumerate(self.bases):
            if b == one:
                one_idx = i
            if b == two:
                two_idx = i

        return self.scores[(one_idx * self.base_count) + two_idx]


class NucleotideScoringMatrix(object):
    def __init__(self, match=1, mismatch=-1):
        self.match = match
        self.mismatch = mismatch

    def score(self, one, two):
        if one == two:
            return self.match
        return self.mismatch


class Matrix(object):
    def __init__(self, rows, cols, init=None):
        self.rows = rows
        self.cols = cols
        self.values = [init, ] * rows * cols

    def get(self, row, col):
        return self.values[(row * self.cols) + col]

    def set(self, row, col, val):
        self.values[(row * self.cols) + col] = val


class LocalAlignment(object):
    def __init__(self, scoring_matrix, gap_penalty=-1):
        self.scoring_matrix = scoring_matrix
        self.gap_penalty = gap_penalty

    def align(self, ref, query):
        ref = ref.upper()
        query = query.upper()

        matrix = Matrix(len(query) + 1, len(ref) + 1, (0, ' '))

        max_val = 0
        max_row = 0
        max_col = 0

        # calculate matrix
        for row in xrange(1, matrix.rows):
            for col in xrange(1, matrix.cols):
                mm = matrix.get(row - 1, col - 1)[0] + self.scoring_matrix.score(query[row - 1], ref[col - 1])
                delete = matrix.get(row - 1, col)[0] + self.gap_penalty
                insert = matrix.get(row, col - 1)[0] + self.gap_penalty
                m = max(0, mm, delete, insert)

                if m == mm:
                    val = (m, 'm')
                elif m == delete:
                    val = (m, 'd')
                elif m == insert:
                    val = (m, 'i')
                else:
                    val = (0, 'x')

                if val[0] >= max_val:
                    max_val = val[0]
                    max_row = row
                    max_col = col

                matrix.set(row, col, val)

        # backtrack
        row = max_row
        col = max_col
        val = max_val
        op = 'm'

        aln = []

        while val > 0:
            aln.append(op)

            op = matrix.get(row, col)[1]

            if op == 'm':
                row -= 1
                col -= 1
            elif op == 'd':
                row -= 1
            elif op == 'i':
                col -= 1
            else:
                break

            val, op = matrix.get(row, col)
        aln.reverse()

        return Alignment(query, ref, row, col, self._reduce_cigar(aln), max_val)

    def _reduce_cigar(self, cigar):
        count = 1
        last = None
        ret = []
        for op in cigar:
            if last and op == last:
                count += 1
            elif last:
                ret.append((count, last.upper()))
                count = 1
            last = op

        if last:
            ret.append((count,last.upper()))
        return ret

    def dump_matrix(self, ref, query, matrix, show_row=-1, show_col=-1):
        sys.stdout.write('   -   ')
        sys.stdout.write('   '.join(ref))
        sys.stdout.write('\n')
        for row in xrange(matrix.rows):
            if row == 0:
                sys.stdout.write('-')
            else:
{'fraction_non_alphanumeric': 0.1175030599755202, 'fraction_numerical': 0.009547123623011015, 'mean_word_length': 1.3068887634105026, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, '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}}
{'dir': 'git-commits-cleaned', 'id': '7111457', 'n_tokens_mistral': 2617, 'n_tokens_neox': 2406, 'n_words': 661}