Skip to content

Commit 4fd5a5e

Browse files
committed
feat: optimize seed chaining algorithm for performance and readability; update CMake to use src/fm.cpp as main executable source
1 parent e6b533b commit 4fd5a5e

2 files changed

Lines changed: 67 additions & 15 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ set(SDSL_LIBRARY_DIR "/home/abhinavmishra/mambaforge/lib")
3131
# Create executable (assuming your source file is src/fm.cpp for the aligner)
3232
# If your main source file is still src/test.cpp, adjust accordingly.
3333
# Let's assume you want to build an executable named 'aligner' from 'src/fm.cpp'
34-
add_executable(aligner src/test.cpp) # Changed 'aligner' to 'aligner' and 'src/test.cpp' to 'src/fm.cpp'
34+
add_executable(aligner src/fm.cpp) # Changed 'aligner' to 'aligner' and 'src/test.cpp' to 'src/fm.cpp'
3535

3636
# Include directories
3737
target_include_directories(aligner PRIVATE

src/main_fmindex.cpp

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -706,22 +706,74 @@ std::vector<Seed> generate_raw_seeds(const std::string& query_seq, const FMIndex
706706
return current_seeds;
707707
}
708708

709-
ChainedSeed find_best_seed_chain(std::vector<Seed>& seeds_vec, int min_diag_gap_val = 0, int max_diag_gap_val = 50000, int max_offset_dev_val = 50) {
710-
if (seeds_vec.empty()) { return {}; }
709+
ChainedSeed find_best_seed_chain(
710+
std::vector<Seed> &seeds_vec,
711+
int min_diag_gap_val = 0,
712+
int max_diag_gap_val = 50000,
713+
int max_offset_dev_val = 50
714+
) {
715+
if (seeds_vec.empty()) return {};
716+
717+
// 1) sort by query_pos, then target_pos
711718
std::sort(seeds_vec.begin(), seeds_vec.end());
712-
int n_s_val = seeds_vec.size();
713-
std::vector<double> dp_scores(n_s_val); std::vector<int> prev_indices(n_s_val, -1); double max_chain_score = 0; int best_chain_end_idx = -1;
714-
for (int i_s = 0; i_s < n_s_val; ++i_s) { dp_scores[i_s] = seeds_vec[i_s].len;
715-
for (int j_s = 0; j_s < i_s; ++j_s) {
716-
if (seeds_vec[j_s].query_end() + min_diag_gap_val < seeds_vec[i_s].query_pos && seeds_vec[j_s].target_end() + min_diag_gap_val < seeds_vec[i_s].target_pos) {
717-
if (std::abs(((long long)seeds_vec[i_s].query_pos - seeds_vec[i_s].target_pos) - ((long long)seeds_vec[j_s].query_pos - seeds_vec[j_s].target_pos)) > max_offset_dev_val) continue;
718-
if ((seeds_vec[i_s].query_pos - seeds_vec[j_s].query_end() > max_diag_gap_val) || (seeds_vec[i_s].target_pos - seeds_vec[j_s].target_end() > max_diag_gap_val)) continue;
719-
if (dp_scores[j_s] + seeds_vec[i_s].len > dp_scores[i_s]) { dp_scores[i_s] = dp_scores[j_s] + seeds_vec[i_s].len; prev_indices[i_s] = j_s; }
719+
720+
int n = seeds_vec.size();
721+
std::vector<double> dp(n, 0.0);
722+
std::vector<int> prev(n, -1);
723+
724+
double best_score = 0.0;
725+
int best_idx = -1;
726+
727+
for (int i = 0; i < n; ++i) {
728+
// start chain with just this seed’s own score (len × match_score=1)
729+
double seed_score = static_cast<double>(seeds_vec[i].len);
730+
dp[i] = seed_score;
731+
732+
// try extending every earlier seed j → i
733+
for (int j = i - 1; j >= 0; --j) {
734+
// no‐overlap
735+
if (seeds_vec[j].query_end() + min_diag_gap_val >= seeds_vec[i].query_pos) continue;
736+
if (seeds_vec[j].target_end() + min_diag_gap_val >= seeds_vec[i].target_pos) continue;
737+
738+
// compute gaps
739+
int dq = seeds_vec[i].query_pos - seeds_vec[j].query_end() - 1;
740+
int dt = seeds_vec[i].target_pos - seeds_vec[j].target_end() - 1;
741+
if (dq < 0 || dt < 0) continue;
742+
if (dq > max_diag_gap_val || dt > max_diag_gap_val) continue;
743+
744+
// diagonal consistency
745+
int diag_j = seeds_vec[j].query_pos - seeds_vec[j].target_pos;
746+
int diag_i = seeds_vec[i].query_pos - seeds_vec[i].target_pos;
747+
if (std::abs(diag_i - diag_j) > max_offset_dev_val) continue;
748+
749+
// affine‐gap cost on each side
750+
double cost_q = dq > 0 ? (GAP_OPEN + (dq - 1) * GAP_EXTEND) : 0.0;
751+
double cost_t = dt > 0 ? (GAP_OPEN + (dt - 1) * GAP_EXTEND) : 0.0;
752+
double gap_cost = cost_q + cost_t;
753+
754+
// DP recurrence: extend j→i
755+
double cand = dp[j] + seed_score - gap_cost;
756+
if (cand > dp[i]) {
757+
dp[i] = cand;
758+
prev[i] = j;
720759
}
721-
} if (dp_scores[i_s] > max_chain_score) { max_chain_score = dp_scores[i_s]; best_chain_end_idx = i_s; }
722-
} ChainedSeed result_chain; result_chain.chain_score = 0;
723-
if (best_chain_end_idx != -1) { result_chain.chain_score = max_chain_score; int current_s_idx = best_chain_end_idx; while (current_s_idx != -1) { result_chain.seeds.push_back(seeds_vec[current_s_idx]); current_s_idx = prev_indices[current_s_idx]; } std::reverse(result_chain.seeds.begin(), result_chain.seeds.end()); }
724-
return result_chain;
760+
}
761+
762+
// track global best
763+
if (dp[i] > best_score) {
764+
best_score = dp[i];
765+
best_idx = i;
766+
}
767+
}
768+
769+
// reconstruct chain
770+
ChainedSeed chain;
771+
chain.chain_score = best_score;
772+
for (int cur = best_idx; cur != -1; cur = prev[cur]) {
773+
chain.seeds.push_back(seeds_vec[cur]);
774+
}
775+
std::reverse(chain.seeds.begin(), chain.seeds.end());
776+
return chain;
725777
}
726778

727779
// -------- Segment/Window Alignment Helpers & Structs (Full Code) --------

0 commit comments

Comments
 (0)