refactor: migrate pipeline stages and improve graph processing
Refactored neighbor resolution to explicitly track unvisited indices for degree-1 nodes, updated display formatting, and added timing and debug logging to the degree computation routine. Migrated pipeline stages from eager vector returns to explicit flat implementations, enabling backpressure-aware streaming, configurable batch processing, incremental yielding, and progress tracking via a delta channel.
This commit is contained in:
@@ -6,6 +6,7 @@ use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
||||
use std::fmt;
|
||||
use std::sync::atomic::{AtomicU8, Ordering};
|
||||
use xxhash_rust::xxh3::Xxh3Builder;
|
||||
use std::time::Instant;
|
||||
use tracing::{debug, info};
|
||||
|
||||
// ── Types ─────────────────────────────────────────────────────────────────────
|
||||
@@ -96,25 +97,6 @@ impl Node {
|
||||
(self.0 >> 5) & 0b11
|
||||
}
|
||||
|
||||
/// Number of left neighbours.
|
||||
pub fn n_left_neighbours(self) -> u8 {
|
||||
if self.can_extend_left() {
|
||||
1
|
||||
} else {
|
||||
let v = (self.0 >> 5) & 0b11;
|
||||
v + (v != 0) as u8
|
||||
}
|
||||
}
|
||||
|
||||
/// Number of right neighbours.
|
||||
pub fn n_right_neighbours(self) -> u8 {
|
||||
if self.can_extend_right() {
|
||||
1
|
||||
} else {
|
||||
let v = (self.0 >> 3) & 0b11;
|
||||
v + (v != 0) as u8
|
||||
}
|
||||
}
|
||||
|
||||
/// Marks the node as visited.
|
||||
#[inline]
|
||||
@@ -162,13 +144,17 @@ impl fmt::Display for Node {
|
||||
const NUC: [char; 4] = ['A', 'C', 'G', 'T'];
|
||||
let r = if self.can_extend_right() {
|
||||
format!("→{}", NUC[self.right_nuc() as usize])
|
||||
} else if (self.0 >> 3) & 0b11 == 0 {
|
||||
"→0".to_string()
|
||||
} else {
|
||||
format!("→{}", self.n_right_neighbours())
|
||||
"→≥2".to_string()
|
||||
};
|
||||
let l = if self.can_extend_left() {
|
||||
format!("←{}", NUC[self.left_nuc() as usize])
|
||||
} else if (self.0 >> 5) & 0b11 == 0 {
|
||||
"←0".to_string()
|
||||
} else {
|
||||
format!("←{}", self.n_left_neighbours())
|
||||
"←≥2".to_string()
|
||||
};
|
||||
let v = if self.is_visited() { "V" } else { "." };
|
||||
write!(f, "Node({r} {l} {v})")
|
||||
@@ -272,6 +258,7 @@ impl GraphDeBruijn {
|
||||
pub fn compute_degrees_and_mark_starts(&self) {
|
||||
// Pass 1: count right/left neighbors for each node
|
||||
|
||||
let t1 = Instant::now();
|
||||
self.for_each_node(|kmer, atomic| {
|
||||
let mut old = Node(atomic.load(Ordering::Relaxed));
|
||||
if old.is_visited() {
|
||||
@@ -286,9 +273,11 @@ impl GraphDeBruijn {
|
||||
node.set_left(lc, ln);
|
||||
atomic.store(node.0, Ordering::Relaxed);
|
||||
});
|
||||
debug!("[compute_degrees] pass 1 (degrees): {:?} — {} nodes", t1.elapsed(), self.nodes.len());
|
||||
|
||||
// Pass 2: mark start nodes
|
||||
|
||||
let t2 = Instant::now();
|
||||
self.for_each_node(|kmer, atomic| {
|
||||
let mut node = Node(atomic.load(Ordering::Relaxed));
|
||||
if node.is_visited() {
|
||||
@@ -299,6 +288,7 @@ impl GraphDeBruijn {
|
||||
atomic.store(node.0, Ordering::Relaxed);
|
||||
}
|
||||
});
|
||||
debug!("[compute_degrees] pass 2 (starts): {:?} — {} nodes", t2.elapsed(), self.nodes.len());
|
||||
}
|
||||
|
||||
pub fn is_visited(&self, kmer: &CanonicalKmer) -> Option<bool> {
|
||||
@@ -527,23 +517,18 @@ fn count_neighbors(
|
||||
nodes: &FastHashMap<CanonicalKmer, AtomicU8>,
|
||||
) -> (u8, Option<u8>) {
|
||||
let mut count = 0u8;
|
||||
let mut first = None;
|
||||
let mut nuc = 0u8;
|
||||
for (i, neighbour) in neighbors.iter().enumerate() {
|
||||
if let Some(a) = nodes.get(neighbour) {
|
||||
if Node(a.load(Ordering::Relaxed)).is_visited() {
|
||||
continue;
|
||||
}
|
||||
nuc = i as u8;
|
||||
count += 1;
|
||||
if first.is_none() {
|
||||
first = Some(i as u8);
|
||||
}
|
||||
if count >= 2 { return (2, None); }
|
||||
}
|
||||
}
|
||||
if count == 1 {
|
||||
(1, first)
|
||||
} else {
|
||||
(count, None)
|
||||
}
|
||||
if count == 1 { (1, Some(nuc)) } else { (0, None) }
|
||||
}
|
||||
|
||||
// ── tests ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user