void needleman_wunsch_align2(const char *a, const char *b, size_t len_a, size_t len_b, const scoring_t *scoring, nw_aligner_t *nw, alignment_t *result) { aligner_align(nw, a, b, len_a, len_b, scoring, 0); // work backwards re-tracing optimal alignment, then shift sequences into place // note: longest_alignment = strlen(seq_a) + strlen(seq_b) size_t longest_alignment = nw->score_width-1 + nw->score_height-1; alignment_ensure_capacity(result, longest_alignment); // Position of next alignment character in buffer (working backwards) size_t next_char = longest_alignment-1; size_t arr_size = nw->score_width * nw->score_height; // Get max score (and therefore current matrix) enum Matrix curr_matrix = MATCH; score_t curr_score = nw->match_scores[arr_size-1]; if(nw->gap_b_scores[arr_size-1] >= curr_score) { curr_matrix = GAP_B; curr_score = nw->gap_b_scores[arr_size-1]; } if(nw->gap_a_scores[arr_size-1] >= curr_score) { curr_matrix = GAP_A; curr_score = nw->gap_a_scores[arr_size-1]; } #ifdef DEBUG alignment_print_matrices(nw); #endif result->score = curr_score; char *alignment_a = result->result_a, *alignment_b = result->result_b; // coords in score matrices size_t score_x = nw->score_width-1, score_y = nw->score_height-1; size_t arr_index = arr_size - 1; for(; score_x > 0 && score_y > 0; next_char--) { #ifdef DEBUG printf("matrix: %s (%lu,%lu) score: %i\n", MATRIX_NAME(curr_matrix), score_x-1, score_y-1, curr_score); #endif switch(curr_matrix) { case MATCH: alignment_a[next_char] = nw->seq_a[score_x-1]; alignment_b[next_char] = nw->seq_b[score_y-1]; break; case GAP_A: alignment_a[next_char] = '-'; alignment_b[next_char] = nw->seq_b[score_y-1]; break; case GAP_B: alignment_a[next_char] = nw->seq_a[score_x-1]; alignment_b[next_char] = '-'; break; default: fprintf(stderr, "Program error: invalid matrix number\n"); fprintf(stderr, "Please submit a bug report to: [email protected]\n"); exit(EXIT_FAILURE); } if(score_x > 0 && score_y > 0) { alignment_reverse_move(&curr_matrix, &curr_score, &score_x, &score_y, &arr_index, nw); } } // Gap in A while(score_y > 0) { alignment_a[next_char] = '-'; alignment_b[next_char] = nw->seq_b[score_y-1]; next_char--; score_y--; } // Gap in B while(score_x > 0) { alignment_a[next_char] = nw->seq_a[score_x-1]; alignment_b[next_char] = '-'; next_char--; score_x--; } // Shift alignment strings back into 0th position in char arrays int first_char = next_char+1; int alignment_len = longest_alignment - first_char; // Use memmove memmove(alignment_a, alignment_a+first_char, alignment_len); memmove(alignment_b, alignment_b+first_char, alignment_len); alignment_a[alignment_len] = '\0'; alignment_b[alignment_len] = '\0'; result->length = alignment_len; }
// Return 1 if alignment was found, 0 otherwise static char _follow_hit(sw_aligner_t* sw, size_t arr_index, alignment_t* result) { const aligner_t *aligner = &(sw->aligner); const sw_history_t *hist = &(sw->history); // Follow path through matrix size_t score_x = (size_t)ARR_2D_X(arr_index, aligner->score_width); size_t score_y = (size_t)ARR_2D_Y(arr_index, aligner->score_width); // Local alignments always (start and) end with a match enum Matrix curr_matrix = MATCH; score_t curr_score = aligner->match_scores[arr_index]; // Store end arr_index and (x,y) coords for later size_t end_arr_index = arr_index; size_t end_score_x = score_x; size_t end_score_y = score_y; score_t end_score = curr_score; size_t length; for(length = 0; ; length++) { if(bitset32_get(hist->match_scores_mask.b, arr_index)) return 0; bitset32_set(hist->match_scores_mask.b, arr_index); if(curr_score == 0) break; //printf(" %i (%i, %i)\n", length, score_x, score_y); // Find out where to go next alignment_reverse_move(&curr_matrix, &curr_score, &score_x, &score_y, &arr_index, aligner); } // We got a result! // Allocate memory for the result result->length = length; alignment_ensure_capacity(result, length); // Jump back to the end of the alignment arr_index = end_arr_index; score_x = end_score_x; score_y = end_score_y; curr_matrix = MATCH; curr_score = end_score; // Now follow backwards again to create alignment! unsigned int i; for(i = length-1; curr_score > 0; i--) { switch(curr_matrix) { case MATCH: result->result_a[i] = aligner->seq_a[score_x-1]; result->result_b[i] = aligner->seq_b[score_y-1]; break; case GAP_A: result->result_a[i] = '-'; result->result_b[i] = aligner->seq_b[score_y-1]; break; case GAP_B: result->result_a[i] = aligner->seq_a[score_x-1]; result->result_b[i] = '-'; break; default: fprintf(stderr, "Program error: invalid matrix in _follow_hit()\n"); fprintf(stderr, "Please submit a bug report to: [email protected]\n"); exit(EXIT_FAILURE); } alignment_reverse_move(&curr_matrix, &curr_score, &score_x, &score_y, &arr_index, aligner); } result->result_a[length] = '\0'; result->result_b[length] = '\0'; result->score = end_score; result->pos_a = score_x; result->pos_b = score_y; result->len_a = end_score_x - score_x; result->len_b = end_score_y - score_y; return 1; }