use haystackfm::alphabet::encode_byte;
use haystackfm::{BidirFmIndex, DnaSequence, FmIndexConfig};
fn encode(s: &str) -> Vec<u8> {
s.bytes().map(|b| encode_byte(b).unwrap()).collect()
}
fn brute_force_mems(query: &[u8], texts: &[Vec<u8>], min_len: usize) -> Vec<(usize, usize)> {
let mut out = std::collections::BTreeSet::new();
for t in texts {
for i in 0..query.len() {
for j in 0..t.len() {
if query[i] != t[j] {
continue;
}
if i > 0 && j > 0 && query[i - 1] == t[j - 1] {
continue; }
let mut l = 0;
while i + l < query.len() && j + l < t.len() && query[i + l] == t[j + l] {
l += 1;
}
if l >= min_len {
out.insert((i, i + l));
}
}
}
}
out.into_iter().collect()
}
fn main() {
let query = "ACGTACGTAC";
let ref_a = "ACGTACGTAC"; let ref_b = "ACGTACT"; let min_len = 2;
let seqs = vec![
DnaSequence::from_str_with_header(ref_a, "A").unwrap(),
DnaSequence::from_str_with_header(ref_b, "B").unwrap(),
];
let idx = BidirFmIndex::build_cpu(&seqs, &FmIndexConfig::default()).unwrap();
let q = encode(query);
let mems: Vec<(usize, usize)> = idx
.find_mems(&q, min_len, false)
.iter()
.map(|m| (m.query_start, m.query_end))
.collect();
let smems: Vec<(usize, usize)> = idx
.find_smems(&q, min_len, false)
.iter()
.map(|m| (m.query_start, m.query_end))
.collect();
let truth = brute_force_mems(&q, &[encode(ref_a), encode(ref_b)], min_len);
println!("true MEMs (brute force) = {truth:?}");
println!("find_mems = {mems:?}");
println!("find_smems = {smems:?}");
println!("find_mems == find_smems = {}", mems == smems);
println!(
"missed by find_mems = {:?}",
truth
.iter()
.filter(|x| !mems.contains(x))
.collect::<Vec<_>>()
);
assert_eq!(
mems, truth,
"find_mems must equal the brute-force truth set"
);
assert_ne!(
mems, smems,
"find_mems must be strictly richer than find_smems"
);
println!("\nOK: find_mems matches brute force and is strictly richer than find_smems.");
}