packages feed

biohazard-2.0: cbits/myers_align.c

#include "myers_align.h"

#include <limits.h>
#include <stdlib.h>
#include <string.h>

// [*blech*, this looks and feels like FORTRAN.]
unsigned myers_diff(
        const char *seq_a, int len_a, enum myers_align_mode mode, 
        const char* seq_b, int len_b, int maxd,
        char *bt_a, char *bt_b ) 
{
	// int len_a = strlen( seq_a ), len_b = strlen( seq_b ) ;
	if( maxd > len_a + len_b ) maxd = len_a + len_b ;

	// in vee[d][k], d runs from 0 to maxd; k runs from -d to +d
	int **vee = calloc( maxd, sizeof(int*) ) ;

	int d, dd, k, x, y, r = UINT_MAX ;
	int *v_d_1 = 0, *v_d = 0 ; 															// "array slice" vee[.][d-1]
	for( d = 0 ; d != maxd ; ++d, v_d_1 = v_d )									// D-paths in order of increasing D
	{
		v_d = d + (vee[d] = malloc( (2 * d + 1) * sizeof( int ) )) ; 		// "array slice" vee[.][d]

		for( k = max(-d,-len_a) ; k <= min(d,len_b) ; ++k ) 					// diagonals
		{
			if( d == 0 )         x = 0 ;
			else if(d==1&&k==0)  x =                       v_d_1[ k ]+1 ;
			else if( k == -d   ) x =                                     v_d_1[ k+1 ] ;
			else if( k ==  d   ) x =       v_d_1[ k-1 ]+1 ;									// argh, need to check for d first, b/c -d+2 could be equal to d
			else if( k == -d+1 ) x = max(                  v_d_1[ k ]+1, v_d_1[ k+1 ] ) ;
			else if( k ==  d-1 ) x = max(  v_d_1[ k-1 ]+1, v_d_1[ k ]+1 ) ;
			else                 x = max3( v_d_1[ k-1 ]+1, v_d_1[ k ]+1, v_d_1[ k+1 ] ) ;

			y = x-k ;
			while( x < len_b && y < len_a && match( seq_b[x], seq_a[y] ) ) ++x, ++y ;
			v_d[ k ] = x ;

			if(
                    bt_a && bt_b &&
					(mode == myers_align_is_prefix || y == len_a) &&
					(mode == myers_align_has_prefix || x == len_b) )
			{
				char *out_a = bt_a + len_a + d +2 ;
				char *out_b = bt_b + len_b + d +2 ;
				*--out_a = 0 ;
				*--out_b = 0 ;
				for( dd = d ; dd != 0 ; )
				{
					if( k != -dd && k != dd && x == vee[ dd-1 ][ k + dd-1 ]+1 )
					{
						--dd ;
						--x ;
						--y ;
						*--out_b = seq_b[x] ;
						*--out_a = seq_a[y] ;
					}
					else if( k > -dd+1 && x == vee[ dd-1 ][ k-1 + dd-1 ]+1 )
					{
						--x ;
						--k ;
						--dd ;
						*--out_b = seq_b[x] ;
						*--out_a = '-' ;
					}
					else if( k < dd-1 && x == vee[ dd-1 ][ k+1 + dd-1 ] )
					{
						++k ;
						--y ;
						--dd ;
						*--out_b = '-' ;
						*--out_a = seq_a[y] ;
					}
					else // this better had been a match...
					{
						--x ;
						--y ;
						*--out_b = seq_b[x] ;
						*--out_a = seq_a[y] ;
					}
				}
				while( x > 0 )
				{
					--x ;
					*--out_b = seq_b[x] ;
					*--out_a = seq_a[x] ;
				}
				memmove( bt_a, out_a, bt_a + len_a + d + 2 - out_a ) ;
				memmove( bt_b, out_b, bt_b + len_b + d + 2 - out_b ) ;
				r = d ;
				goto cleanup ;
			}
		}
	}

cleanup:
	for( dd = maxd ; dd != 0 ; --dd )
		free( vee[dd-1] ) ;
	free( vee ) ;
	return r ;
}