forked from dendibakh/perf-ninja
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsolution.cpp
87 lines (76 loc) · 3.01 KB
/
solution.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include "solution.hpp"
#include <cassert>
#include <type_traits>
// The alignment algorithm which computes the alignment of the given sequence
// pairs.
result_t compute_alignment(std::vector<sequence_t> const &sequences1,
std::vector<sequence_t> const &sequences2) {
result_t result{};
for (size_t sequence_idx = 0; sequence_idx < sequences1.size();
++sequence_idx) {
using score_t = int16_t;
using column_t = std::array<score_t, sequence_size_v + 1>;
sequence_t const &sequence1 = sequences1[sequence_idx];
sequence_t const &sequence2 = sequences2[sequence_idx];
/*
* Initialise score values.
*/
score_t gap_open{-11};
score_t gap_extension{-1};
score_t match{6};
score_t mismatch{-4};
/*
* Setup the matrix.
* Note we can compute the entire matrix with just one column in memory,
* since we are only interested in the last value of the last column in the
* score matrix.
*/
column_t score_column{};
column_t horizontal_gap_column{};
score_t last_vertical_gap{};
/*
* Initialise the first column of the matrix.
*/
horizontal_gap_column[0] = gap_open;
last_vertical_gap = gap_open;
for (size_t i = 1; i < score_column.size(); ++i) {
score_column[i] = last_vertical_gap;
horizontal_gap_column[i] = last_vertical_gap + gap_open;
last_vertical_gap += gap_extension;
}
/*
* Compute the main recursion to fill the matrix.
*/
for (unsigned col = 1; col <= sequence2.size(); ++col) {
score_t last_diagonal_score =
score_column[0]; // Cache last diagonal score to compute this cell.
score_column[0] = horizontal_gap_column[0];
last_vertical_gap = horizontal_gap_column[0] + gap_open;
horizontal_gap_column[0] += gap_extension;
for (unsigned row = 1; row <= sequence1.size(); ++row) {
// Compute next score from diagonal direction with match/mismatch.
score_t best_cell_score =
last_diagonal_score +
(sequence1[row - 1] == sequence2[col - 1] ? match : mismatch);
// Determine best score from diagonal, vertical, or horizontal
// direction.
best_cell_score = max(best_cell_score, last_vertical_gap);
best_cell_score = max(best_cell_score, horizontal_gap_column[row]);
// Cache next diagonal value and store optimum in score_column.
last_diagonal_score = score_column[row];
score_column[row] = best_cell_score;
// Compute the next values for vertical and horizontal gap.
best_cell_score += gap_open;
last_vertical_gap += gap_extension;
horizontal_gap_column[row] += gap_extension;
// Store optimum between gap open and gap extension.
last_vertical_gap = max(last_vertical_gap, best_cell_score);
horizontal_gap_column[row] =
max(horizontal_gap_column[row], best_cell_score);
}
}
// Report the best score.
result[sequence_idx] = score_column.back();
}
return result;
}