diff --git a/seq_smith/_seq_smith.pyi b/seq_smith/_seq_smith.pyi index 495b726..2e78a35 100644 --- a/seq_smith/_seq_smith.pyi +++ b/seq_smith/_seq_smith.pyi @@ -18,6 +18,13 @@ class Alignment: @final class AlignmentFragment: + def __init__( + self, + fragment_type: FragmentType, + sa_start: int, + sb_start: int, + length: int, + ) -> None: ... @property def fragment_type(self) -> FragmentType: ... @fragment_type.setter diff --git a/src/lib.rs b/src/lib.rs index 295a8f7..a1cc943 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -676,9 +676,10 @@ fn _local_global_align_core(params: AlignmentParams) -> PyResult { let mut max_col = 0; for row in 0..params.sb_len { - data.prev_score[row] = std::i32::MIN; + let score = params.gap_cost(row as i32 + 1); + data.prev_score[row] = score; data.hgap_pos[row] = -1; - data.hgap_score[row] = std::i32::MIN; + data.hgap_score[row] = score.saturating_add(params.gap_open); } for col in 0..params.sa_len { diff --git a/tests/test_seq_smith.py b/tests/test_seq_smith.py index 1e26e0d..b693855 100644 --- a/tests/test_seq_smith.py +++ b/tests/test_seq_smith.py @@ -3,6 +3,8 @@ from conftest import AlignmentData from seq_smith import ( + AlignmentFragment, + FragmentType, encode, format_alignment_ascii, generate_cigar, @@ -454,3 +456,23 @@ def test_generate_cigar_with_deletion(common_data: AlignmentData) -> None: alignment = global_align(seqa, seqb, common_data.score_matrix, common_data.gap_open, common_data.gap_extend) cigar = generate_cigar(alignment) assert cigar == "1M1D" # AC vs A-, so A matches, then C is a deletion in seqB (query) + + +def test_local_global_align_overhangs() -> None: + # Sequence B (Global) has overhanging tails + # sequence A: CCCC + # sequence B: AAACCCCAAA + # Expected: A aligns to central C's, B has leading/trailing gaps. + seqa = encode("CCCC", "ACGT") + seqb = encode("AAACCCCAAA", "ACGT") + sm = make_score_matrix("ACGT", match_score=2, mismatch_score=-2) + aln = local_global_align(seqa, seqb, sm, gap_open=-3, gap_extend=-1) + + expected_fragments = [ + AlignmentFragment(FragmentType.AGap, 0, 0, 3), + AlignmentFragment(FragmentType.Match, 0, 3, 4), + AlignmentFragment(FragmentType.AGap, 4, 7, 3), + ] + assert aln.fragments == expected_fragments + + assert aln.score == -2 diff --git a/uv.lock b/uv.lock index 1cc9c84..0828b28 100644 --- a/uv.lock +++ b/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "seq-smith" -version = "0.3.0" +version = "0.4.0" source = { editable = "." } dependencies = [ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },