Skip to content

Commit 2ed38d4

Browse files
committed
Re-use syncmers of the forward sequence for the revcomp sequence
1 parent 18f6d5e commit 2ed38d4

3 files changed

Lines changed: 53 additions & 33 deletions

File tree

src/index.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -545,16 +545,17 @@ impl<'a> StrobemerIndex<'a> {
545545
if seq.len() < self.parameters.randstrobe.w_max {
546546
return;
547547
}
548-
let mut syncmer_iter = SyncmerIterator::new(
548+
let syncmer_iter = SyncmerIterator::new(
549549
seq,
550550
self.parameters.syncmer.k,
551551
self.parameters.syncmer.s,
552552
self.parameters.syncmer.t,
553553
);
554+
554555
let randstrobe_iter =
555-
RandstrobeIterator::new(&mut syncmer_iter, &self.parameters.randstrobe);
556+
RandstrobeIterator::new(syncmer_iter, self.parameters.randstrobe.clone());
556557

557-
let mut n= 0;
558+
let mut n = 0;
558559
for (i, randstrobe) in randstrobe_iter.enumerate() {
559560
n += 1;
560561
let offset = randstrobe.strobe2_pos - randstrobe.strobe1_pos;

src/mapper.rs

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -84,34 +84,53 @@ pub struct QueryRandstrobe {
8484
/// Generate randstrobes for a query sequence and its reverse complement.
8585
/// TODO move to strobes.rs?
8686
pub fn randstrobes_query(seq: &[u8], parameters: &IndexParameters) -> [Vec<QueryRandstrobe>; 2] {
87-
let mut randstrobes= [Vec::<QueryRandstrobe>::new(), Vec::<QueryRandstrobe>::new()];
87+
let mut randstrobes = [vec![], vec![]];
8888
if seq.len() < parameters.randstrobe.w_max {
8989
return randstrobes;
9090
}
9191

92-
// TODO
93-
// For the reverse complement, we could re-use the syncmers of the forward
92+
// Generate syncmers for the forward sequence
93+
let mut syncmer_iter = SyncmerIterator::new(seq, parameters.syncmer.k, parameters.syncmer.s, parameters.syncmer.t);
94+
let mut syncmers: Vec<_> = syncmer_iter.collect();
95+
96+
// Generate randstrobes for the forward sequence
97+
let randstrobe_iter = RandstrobeIterator::new(syncmers.iter().cloned(), parameters.randstrobe.clone());
98+
99+
for randstrobe in randstrobe_iter {
100+
randstrobes[0].push(
101+
QueryRandstrobe {
102+
hash: randstrobe.hash,
103+
hash_revcomp: randstrobe.hash_revcomp,
104+
start: randstrobe.strobe1_pos,
105+
end: randstrobe.strobe2_pos + parameters.syncmer.k,
106+
}
107+
);
108+
}
109+
110+
// For the reverse complement, we can re-use the syncmers of the forward
94111
// sequence because canonical syncmers are invariant under reverse
95112
// complementing. Only the coordinates need to be adjusted.
96-
97-
let seq_rc = reverse_complement(seq);
98-
for (s, is_revcomp) in [(seq, false), (&seq_rc, true)] {
99-
// Generate randstrobes for the forward sequence
100-
let mut syncmer_iter = SyncmerIterator::new(s, parameters.syncmer.k, parameters.syncmer.s, parameters.syncmer.t);
101-
let randstrobe_iter = RandstrobeIterator::new(&mut syncmer_iter, &parameters.randstrobe);
102-
103-
for randstrobe in randstrobe_iter {
104-
randstrobes[is_revcomp as usize].push(
105-
QueryRandstrobe {
106-
hash: randstrobe.hash,
107-
hash_revcomp: randstrobe.hash_revcomp,
108-
start: randstrobe.strobe1_pos,
109-
end: randstrobe.strobe2_pos + parameters.syncmer.k,
110-
}
111-
);
112-
}
113+
syncmers.reverse();
114+
for i in 0..syncmers.len() {
115+
syncmers[i].position = seq.len() - syncmers[i].position - parameters.syncmer.k;
113116
}
114117

118+
// Randstrobes cannot be re-used for the reverse complement:
119+
// If in the forward direction, syncmer[i] and syncmer[j] were paired up, it
120+
// is not necessarily the case that syncmer[j] is going to be paired with
121+
// syncmer[i] in the reverse direction because i is fixed in the forward
122+
// direction and j is fixed in the reverse direction.
123+
let rc_randstrobe_iter = RandstrobeIterator::new(syncmers.into_iter(), parameters.randstrobe.clone());
124+
for randstrobe in rc_randstrobe_iter {
125+
randstrobes[1].push(
126+
QueryRandstrobe {
127+
hash: randstrobe.hash,
128+
hash_revcomp: randstrobe.hash_revcomp,
129+
start: randstrobe.strobe1_pos,
130+
end: randstrobe.strobe2_pos + parameters.syncmer.k,
131+
}
132+
);
133+
}
115134
randstrobes
116135
}
117136

src/strobes.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ impl Randstrobe {
5757
}
5858
}
5959

60-
pub struct RandstrobeIterator<'a> {
61-
parameters: &'a RandstrobeParameters,
60+
pub struct RandstrobeIterator<I: Iterator<Item = Syncmer>> {
61+
parameters: RandstrobeParameters,
6262
syncmers: VecDeque<Syncmer>,
63-
syncmer_iterator: &'a mut SyncmerIterator<'a>,
63+
syncmer_iterator: I,
6464
}
6565

66-
impl<'a> RandstrobeIterator<'a> {
67-
pub fn new(syncmer_iterator: &'a mut SyncmerIterator<'a>, parameters: &'a RandstrobeParameters) -> RandstrobeIterator<'a> {
66+
impl<I: Iterator<Item = Syncmer>> RandstrobeIterator<I> {
67+
pub fn new(syncmer_iterator: I, parameters: RandstrobeParameters) -> RandstrobeIterator<I> {
6868
RandstrobeIterator {
6969
parameters,
7070
syncmers: VecDeque::<Syncmer>::new(),
@@ -73,7 +73,7 @@ impl<'a> RandstrobeIterator<'a> {
7373
}
7474
}
7575

76-
impl Iterator for RandstrobeIterator<'_> {
76+
impl<SI: Iterator<Item = Syncmer>> Iterator for RandstrobeIterator<SI> {
7777
type Item = Randstrobe;
7878
fn next(&mut self) -> Option<Self::Item> {
7979
while self.syncmers.len() <= self.parameters.w_max {
@@ -128,8 +128,8 @@ mod test {
128128
fn test_randstrobe_iterator() {
129129
let refseq = read_phix().sequence;
130130
let parameters = IndexParameters::default_from_read_length(300);
131-
let mut syncmer_iter = SyncmerIterator::new(&refseq, parameters.syncmer.k, parameters.syncmer.s, parameters.syncmer.t);
132-
let randstrobe_iter = RandstrobeIterator::new(&mut syncmer_iter, &parameters.randstrobe);
131+
let syncmer_iter = SyncmerIterator::new(&refseq, parameters.syncmer.k, parameters.syncmer.s, parameters.syncmer.t);
132+
let randstrobe_iter = RandstrobeIterator::new(syncmer_iter, parameters.randstrobe.clone());
133133

134134
for randstrobe in randstrobe_iter {
135135
assert!(randstrobe.hash > 0);
@@ -148,8 +148,8 @@ mod test {
148148
let syncmer_iter = SyncmerIterator::new(&refseq, parameters.syncmer.k, parameters.syncmer.s, parameters.syncmer.t);
149149
let syncmer_count = syncmer_iter.count();
150150

151-
let mut syncmer_iter = SyncmerIterator::new(&refseq, parameters.syncmer.k, parameters.syncmer.s, parameters.syncmer.t);
152-
let randstrobe_iter = RandstrobeIterator::new(&mut syncmer_iter, &parameters.randstrobe);
151+
let syncmer_iter = SyncmerIterator::new(&refseq, parameters.syncmer.k, parameters.syncmer.s, parameters.syncmer.t);
152+
let randstrobe_iter = RandstrobeIterator::new(syncmer_iter, parameters.randstrobe.clone());
153153
let randstrobe_count = randstrobe_iter.count();
154154

155155
assert_eq!(randstrobe_count, syncmer_count);

0 commit comments

Comments
 (0)