#![allow(clippy::should_implement_trait)]
#![allow(clippy::needless_range_loop)]
#![allow(clippy::unnecessary_unwrap)]
use log::*;
use std::io;
use std::io::{BufReader, BufWriter, ErrorKind, Read, Write};
use std::fmt::Debug;
use std::fs;
use std::fs::OpenOptions;
use std::path::{Path, PathBuf};
use std::hash::{BuildHasherDefault, Hash, Hasher};
use serde::{Deserialize, Serialize};
use serde_json::to_writer;
use fnv::{FnvBuildHasher, FnvHashMap};
use indexmap::IndexMap;
use num;
use rand_distr::uniform::SampleUniform;
use crate::nohasher::*;
use super::nbkmerguess::*;
use crate::base::{kmer::*, kmergenerator::KmerSeqIteratorT, kmergenerator::*};
use rayon::prelude::*;
use probminhash::{probminhasher::*, superminhasher::SuperMinHash};
use probminhash::jaccard::compute_probminhash_jaccard;
pub fn compute_probminhash3a_jaccard<D, H, Hidx>(
idxa: &IndexMap<D, f64, Hidx>,
idxb: &IndexMap<D, f64, Hidx>,
sketch_size: usize,
return_object: bool,
) -> (f64, Option<Vec<D>>)
where
D: Copy + Eq + Hash + Debug + Default,
H: Hasher + Default,
Hidx: std::hash::BuildHasher,
{
let mut pminhasha = ProbMinHash3a::<D, H>::new(sketch_size, D::default());
pminhasha.hash_weigthed_idxmap(idxa);
let mut pminhashb = ProbMinHash3a::<D, H>::new(sketch_size, D::default());
pminhashb.hash_weigthed_idxmap(idxb);
let siga = pminhasha.get_signature();
let sigb = pminhashb.get_signature();
let jac: f64;
if !return_object {
jac = compute_probminhash_jaccard(siga, sigb);
(jac, None)
} else {
probminhash_get_jaccard_objects(siga, sigb)
}
}
pub fn probminhash_get_jaccard_objects<D: Eq + Copy>(
siga: &[D],
sigb: &[D],
) -> (f64, Option<Vec<D>>) {
let sig_size = siga.len();
assert_eq!(sig_size, sigb.len());
let mut common_objects = Vec::<D>::new();
let mut inter = 0;
for i in 0..siga.len() {
if siga[i] == sigb[i] {
inter += 1;
common_objects.push(siga[i]);
}
}
let jp = inter as f64 / siga.len() as f64;
if jp > 0. {
(jp, Some(common_objects))
} else {
(0., None)
}
}
#[derive(Serialize, Deserialize, Copy, Clone)]
pub struct SeqSketcher {
kmer_size: usize,
sketch_size: usize,
}
impl SeqSketcher {
pub fn new(kmer_size: usize, sketch_size: usize) -> Self {
SeqSketcher {
kmer_size,
sketch_size,
}
}
pub fn get_kmer_size(&self) -> usize {
self.kmer_size
}
pub fn get_sketch_size(&self) -> usize {
self.sketch_size
}
pub fn dump_json(&self, filename: &String) -> Result<(), String> {
let filepath = PathBuf::from(filename.clone());
log::info!("dumping sketching parameters in json file : {}", filename);
let fileres = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&filepath);
if fileres.is_err() {
log::error!(
"SeqSketcher dump : dump could not open file {:?}",
filepath.as_os_str()
);
println!(
"SeqSketcher dump: could not open file {:?}",
filepath.as_os_str()
);
return Err("SeqSketcher dump failed".to_string());
}
let mut writer = BufWriter::new(fileres.unwrap());
to_writer(&mut writer, &self).unwrap();
Ok(())
}
pub fn reload_json(dirpath: &Path) -> Result<SeqSketcher, String> {
log::info!("in reload_json");
let filepath = dirpath.join("sketchparams_dump.json");
let fileres = OpenOptions::new().read(true).open(&filepath);
if fileres.is_err() {
log::error!(
"Sketcher reload_json : reload could not open file {:?}",
filepath.as_os_str()
);
println!(
"Sketcher reload_json: could not open file {:?}",
filepath.as_os_str()
);
return Err("Sketcher reload_json could not open file".to_string());
}
let loadfile = fileres.unwrap();
let reader = BufReader::new(loadfile);
let sketch_params: SeqSketcher = serde_json::from_reader(reader).unwrap();
log::info!(
"SeqSketcher reload, kmer_size : {}, sketch_size : {}",
sketch_params.get_kmer_size(),
sketch_params.get_sketch_size()
);
Ok(sketch_params)
}
pub fn sketch_probminhash3a<Kmer: CompressedKmerT + KmerBuilder<Kmer>, F>(
&self,
vseq: &[&Sequence],
fhash: F,
) -> Vec<Vec<Kmer::Val>>
where
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
Kmer::Val: num::PrimInt + Send + Sync + Debug,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
{
log::debug!("entering sketch_probminhash3a_compressedkmer");
let comput_closure = |seqb: &Sequence, i: usize| -> (usize, Vec<Kmer::Val>) {
let nb_kmer = get_nbkmer_guess(seqb);
let mut wb: FnvHashMap<Kmer::Val, u64> =
FnvHashMap::with_capacity_and_hasher(nb_kmer, FnvBuildHasher::default());
let mut kmergen = KmerSeqIterator::<Kmer>::new(self.kmer_size as u8, seqb);
kmergen.set_range(0, seqb.size()).unwrap();
while let Some(kmer) = kmergen.next() {
let hashval = fhash(&kmer);
*wb.entry(hashval).or_insert(0) += 1;
} let mut pminhashb = ProbMinHash3a::<Kmer::Val, NoHashHasher>::new(
self.sketch_size,
<Kmer::Val>::default(),
);
pminhashb.hash_weigthed_hashmap(&wb);
let sigb = pminhashb.get_signature();
(i, sigb.clone())
};
let sig_with_rank: Vec<(usize, Vec<Kmer::Val>)> = (0..vseq.len())
.into_par_iter()
.map(|i| comput_closure(vseq[i], i))
.collect();
let mut jaccard_vec = Vec::<Vec<Kmer::Val>>::with_capacity(vseq.len());
for _ in 0..vseq.len() {
jaccard_vec.push(Vec::new());
}
for i in 0..sig_with_rank.len() {
let slot = sig_with_rank[i].0;
jaccard_vec[slot].clone_from(&sig_with_rank[i].1);
}
jaccard_vec
}
pub fn sketch_probminhash3<Kmer: CompressedKmerT + KmerBuilder<Kmer>, F>(
&self,
vseq: &[&Sequence],
fhash: F,
) -> Vec<Vec<Kmer::Val>>
where
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
Kmer::Val: num::PrimInt + Send + Sync + Debug,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
{
let comput_closure = |seqb: &Sequence, i: usize| -> (usize, Vec<Kmer::Val>) {
let nb_kmer = get_nbkmer_guess(seqb);
let mut wb: FnvHashMap<Kmer::Val, u64> =
FnvHashMap::with_capacity_and_hasher(nb_kmer, FnvBuildHasher::default());
let mut kmergen = KmerSeqIterator::<Kmer>::new(self.kmer_size as u8, seqb);
kmergen.set_range(0, seqb.size()).unwrap();
while let Some(kmer) = kmergen.next() {
let hashval = fhash(&kmer);
*wb.entry(hashval).or_insert(0) += 1;
} let mut pminhashb = ProbMinHash3::<Kmer::Val, NoHashHasher>::new(
self.sketch_size,
<Kmer::Val>::default(),
);
pminhashb.hash_weigthed_hashmap(&wb);
let sigb = pminhashb.get_signature();
(i, sigb.clone())
};
let sig_with_rank: Vec<(usize, Vec<Kmer::Val>)> = (0..vseq.len())
.into_par_iter()
.map(|i| comput_closure(vseq[i], i))
.collect();
let mut jaccard_vec = Vec::<Vec<Kmer::Val>>::with_capacity(vseq.len());
for _ in 0..vseq.len() {
jaccard_vec.push(Vec::new());
}
for i in 0..sig_with_rank.len() {
let slot = sig_with_rank[i].0;
jaccard_vec[slot].clone_from(&sig_with_rank[i].1);
}
jaccard_vec
}
pub fn sketch_superminhash<Kmer: CompressedKmerT + KmerBuilder<Kmer>, S, F>(
&self,
vseq: &[&Sequence],
fhash: F,
) -> Vec<Vec<S>>
where
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
Kmer::Val: num::PrimInt + Send + Sync + Debug,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
S: num::Float + SampleUniform + Debug + Send + Sync,
{
log::debug!("entering sketch_superminhash_compressedkmer");
let comput_closure = |seqb: &Sequence, i: usize| -> (usize, Vec<S>) {
log::debug!(" in sketch_superminhash_compressedkmer, closure");
let bh = BuildHasherDefault::<fnv::FnvHasher>::default();
let mut sminhash: SuperMinHash<S, Kmer::Val, fnv::FnvHasher> =
SuperMinHash::<S, Kmer::Val, fnv::FnvHasher>::new(self.sketch_size, bh);
let mut kmergen = KmerSeqIterator::<Kmer>::new(self.kmer_size as u8, seqb);
kmergen.set_range(0, seqb.size()).unwrap();
while let Some(kmer) = kmergen.next() {
let hashval = fhash(&kmer);
if sminhash.sketch(&hashval).is_err() {
log::error!("could not hash kmer : {:?}", kmer.get_uncompressed_kmer());
std::panic!("could not hash kmer : {:?}", kmer.get_uncompressed_kmer());
}
} let sigb = sminhash.get_hsketch();
(i, sigb.clone())
};
let sig_with_rank: Vec<(usize, Vec<S>)> = (0..vseq.len())
.into_par_iter()
.map(|i| comput_closure(vseq[i], i))
.collect();
let mut jaccard_vec = Vec::<Vec<S>>::with_capacity(vseq.len());
for _ in 0..vseq.len() {
jaccard_vec.push(Vec::new());
}
for i in 0..sig_with_rank.len() {
let slot = sig_with_rank[i].0;
jaccard_vec[slot].clone_from(&sig_with_rank[i].1);
}
jaccard_vec
}
pub fn create_signature_dump(&self, dumpfname: &String) -> io::BufWriter<fs::File> {
let dumpfile_res = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(dumpfname);
let dumpfile = if dumpfile_res.is_ok() {
dumpfile_res.unwrap()
} else {
println!("cannot open {}", dumpfname);
std::process::exit(1);
};
let sig_size: u32 = 4;
let sketch_size_u32 = self.sketch_size as u32;
let kmer_size_u32 = self.kmer_size as u32;
let mut sigbuf: io::BufWriter<fs::File> =
io::BufWriter::with_capacity(1_000_000_000, dumpfile);
sigbuf.write_all(&MAGIC_SIG_DUMP.to_le_bytes()).unwrap();
sigbuf.write_all(&sig_size.to_le_bytes()).unwrap();
sigbuf.write_all(&sketch_size_u32.to_le_bytes()).unwrap();
sigbuf.write_all(&kmer_size_u32.to_le_bytes()).unwrap();
sigbuf
} }
pub fn jaccard_index_probminhash3a<Kmer: CompressedKmerT + KmerBuilder<Kmer>, F>(
seqa: &Sequence,
vseqb: &[Sequence],
sketch_size: usize,
kmer_size: u8,
fhash: F,
) -> Vec<f64>
where
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
Kmer::Val: num::PrimInt + Send + Sync + Debug,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
{
debug!("seqsketcher : entering compute_jaccard_index_probminhash3a");
let mut jaccard_vec = vec![0_f64; vseqb.len()];
let mut pminhasha = ProbMinHash3a::<<Kmer as CompressedKmerT>::Val, NoHashHasher>::new(
sketch_size,
Kmer::Val::default(),
);
let nb_kmer = get_nbkmer_guess(seqa);
let mut wa: FnvHashMap<Kmer::Val, u64> =
FnvHashMap::with_capacity_and_hasher(nb_kmer, FnvBuildHasher::default());
let mut kmergen = KmerSeqIterator::<Kmer>::new(kmer_size, seqa);
kmergen.set_range(0, seqa.size()).unwrap();
while let Some(kmer) = kmergen.next() {
let hashval = fhash(&kmer);
trace!(
" kmer in seqa {:?}, hvalval {:?} ",
kmer.get_uncompressed_kmer(),
hashval
);
*wa.entry(hashval).or_insert(0) += 1;
} pminhasha.hash_weigthed_hashmap(&wa);
let siga = pminhasha.get_signature();
trace!("siga = {:?}", siga);
let comput_closure = |seqb: &Sequence, i: usize| -> (usize, f64) {
let nb_kmer = get_nbkmer_guess(seqb);
let mut wb: FnvHashMap<Kmer::Val, u64> =
FnvHashMap::with_capacity_and_hasher(nb_kmer, FnvBuildHasher::default());
let mut kmergen = KmerSeqIterator::<Kmer>::new(kmer_size, seqb);
kmergen.set_range(0, seqb.size()).unwrap();
while let Some(kmer) = kmergen.next() {
let hashval = fhash(&kmer);
*wb.entry(hashval).or_insert(0) += 1;
} let mut pminhashb =
ProbMinHash3a::<Kmer::Val, NoHashHasher>::new(sketch_size, Kmer::Val::default());
pminhashb.hash_weigthed_hashmap(&wb);
let sigb = pminhashb.get_signature();
let jac = compute_probminhash_jaccard(siga, sigb);
(i, jac)
};
let jac_with_rank: Vec<(usize, f64)> = (0..vseqb.len())
.into_par_iter()
.map(|i| comput_closure(&vseqb[i], i))
.collect();
for i in 0..jac_with_rank.len() {
let slot = jac_with_rank[i].0;
jaccard_vec[slot] = jac_with_rank[i].1;
}
jaccard_vec
}
pub fn jaccard_index_probminhash3_kmer32bit<F>(
seqa: &Sequence,
vseqb: &[Sequence],
sketch_size: usize,
kmer_size: u8,
fhash: F,
) -> Vec<f64>
where
F: Fn(&Kmer32bit) -> u32 + Send + Sync,
{
debug!("seqsketcher : entering compute_jaccard_index_probminhash3a_kmer32bit");
let mut jaccard_vec = vec![0_f64; vseqb.len()];
let mut pminhasha = ProbMinHash3::<usize, NoHashHasher>::new(sketch_size, 0);
let nb_kmer = get_nbkmer_guess(seqa);
let mut wa: FnvHashMap<usize, f64> =
FnvHashMap::with_capacity_and_hasher(nb_kmer, FnvBuildHasher::default());
let mut kmergen = KmerSeqIterator::<Kmer32bit>::new(kmer_size, seqa);
kmergen.set_range(0, seqa.size()).unwrap();
while let Some(kmer) = kmergen.next() {
let hashval = fhash(&kmer);
trace!(
" kmer in seqa {:?}, hvalval {:?} ",
kmer.get_uncompressed_kmer(),
hashval
);
*wa.entry(hashval as usize).or_insert(0.) += 1.;
} pminhasha.hash_weigthed_hashmap(&wa);
let siga = pminhasha.get_signature();
trace!("siga = {:?}", siga);
let comput_closure = |seqb: &Sequence, i: usize| -> (usize, f64) {
let nb_kmer = get_nbkmer_guess(seqb);
let mut wb: FnvHashMap<usize, f64> =
FnvHashMap::with_capacity_and_hasher(nb_kmer, FnvBuildHasher::default());
let mut kmergen = KmerSeqIterator::<Kmer32bit>::new(kmer_size, seqb);
kmergen.set_range(0, seqb.size()).unwrap();
while let Some(kmer) = kmergen.next() {
let hashval = fhash(&kmer);
*wb.entry(hashval as usize).or_insert(0.) += 1.;
} let mut pminhashb = ProbMinHash3::<usize, NoHashHasher>::new(sketch_size, 0);
pminhashb.hash_weigthed_hashmap(&wb);
let sigb = pminhashb.get_signature();
let jac = compute_probminhash_jaccard(siga, sigb);
(i, jac)
};
let jac_with_rank: Vec<(usize, f64)> = (0..vseqb.len())
.into_par_iter()
.map(|i| comput_closure(&vseqb[i], i))
.collect();
for i in 0..jac_with_rank.len() {
let slot = jac_with_rank[i].0;
jaccard_vec[slot] = jac_with_rank[i].1;
}
jaccard_vec
}
const MAGIC_SIG_DUMP: u32 = 0xceabeadd;
pub fn dump_signatures_block_u32(signatures: &[Vec<u32>], out: &mut dyn Write) -> io::Result<()> {
for sig in signatures {
for j in 0..sig.len() {
out.write_all(&sig[j].to_le_bytes()).unwrap();
}
} Ok(())
}
pub struct SigSketchFileReader {
_fname: String,
sig_size: u8,
sketch_size: usize,
kmer_size: u8,
signature_buf: io::BufReader<fs::File>,
}
impl SigSketchFileReader {
pub fn new(fname: &String) -> Result<SigSketchFileReader, String> {
let dumpfile_res = OpenOptions::new().read(true).open(fname);
let dumpfile = if dumpfile_res.is_ok() {
dumpfile_res.unwrap()
} else {
println!("cannot open {}", fname);
return Err(String::from(
"SigSketchFileReader : could not open dumpfile",
));
};
let mut signature_buf: io::BufReader<fs::File> =
io::BufReader::with_capacity(1_000_000_000, dumpfile);
let mut buf_u32 = [0u8; 4];
let mut io_res;
io_res = signature_buf.read_exact(&mut buf_u32);
if io_res.is_err() {
println!("SigSketchFileReader could no read magic");
return Err(String::from("SigSketchFileReader could no read magic"));
}
let magic = u32::from_le_bytes(buf_u32);
if magic != MAGIC_SIG_DUMP {
println!("file {} is not a dump of signature", fname);
return Err(String::from("file is not a dump of signature"));
}
io_res = signature_buf.read_exact(&mut buf_u32);
if io_res.is_err() {
println!("SigSketchFileReader could no read sketch_size");
return Err(String::from(
"SigSketchFileReader could no read sketch_size",
));
}
let sig_size = u32::from_le_bytes(buf_u32);
if sig_size != 4 {
println!("SigSketchFileReader could no read sketch_size");
return Err(String::from(
"SigSketchFileReader , sig_size != 4 not yet implemented",
));
}
io_res = signature_buf.read_exact(&mut buf_u32);
if io_res.is_err() {
println!("SigSketchFileReader could no read sketch_size");
return Err(String::from(
"SigSketchFileReader could no read sketch_size",
));
}
let sketch_size = u32::from_le_bytes(buf_u32);
trace!("read sketch size {}", sketch_size);
io_res = signature_buf.read_exact(&mut buf_u32);
if io_res.is_err() {
println!("SigSketchFileReader could no read kmer_size");
return Err(String::from("SigSketchFileReader could no read kmer_size"));
}
let kmer_size = u32::from_le_bytes(buf_u32);
trace!("read kmer_size {}", kmer_size);
Ok(SigSketchFileReader {
_fname: fname.clone(),
sig_size: sig_size as u8,
sketch_size: sketch_size as usize,
kmer_size: kmer_size as u8,
signature_buf,
})
}
pub fn get_kmer_size(&self) -> u8 {
self.kmer_size
}
pub fn get_signature_length(&self) -> usize {
self.sketch_size
}
pub fn get_signature_size(&self) -> usize {
self.sig_size as usize
}
pub fn next(&mut self) -> Option<Vec<u32>> {
let nb_bytes = self.sketch_size * std::mem::size_of::<u32>();
let mut buf: Vec<u8> = (0..nb_bytes).map(|_| 0u8).collect();
let io_res = self.signature_buf.read_exact(buf.as_mut_slice());
if io_res.is_err() {
match io_res.err().unwrap().kind() {
ErrorKind::UnexpectedEof => None,
_ => {
println!("an unexpected error occurred reading signature buffer");
std::process::exit(1);
}
}
} else {
let sig = Vec::<u32>::with_capacity(self.sketch_size);
Some(sig)
}
} }
#[cfg(test)]
mod tests {
use super::*;
#[inline]
fn compute_superminhash_jaccard(
hsketch: &Vec<f64>,
other_sketch: &Vec<f64>,
) -> anyhow::Result<f64> {
probminhash::superminhasher::get_jaccard_index_estimate(hsketch, other_sketch)
}
fn log_init_test() {
let mut builder = env_logger::Builder::from_default_env();
let _ = builder.is_test(true).try_init();
}
#[test]
fn test_pminhasha_kmer_smallb() {
log_init_test();
log::info!("test_probminhasha_kmer_smallb");
let kmer_size = 5;
let sketch_size = 4000;
let seqstr = String::from(
"TCAAAGGGAAACATTCAAAATCAGTATGCGCCCGTTCAGTTACGTATTGCTCTCGCTAATGAGATGGGCTGGGTACAGAG",
);
let seqabytes = seqstr.as_bytes();
let seqa = Sequence::new(seqstr.as_bytes(), 2);
let mut vecseqb = Vec::<Sequence>::new();
let seqb1 = Sequence::new(&seqabytes[0..40], 2); vecseqb.push(seqb1);
let seqarevcomp = seqa.get_reverse_complement();
vecseqb.push(seqarevcomp.clone());
let reverse_str = String::from_utf8(seqarevcomp.decompress()).unwrap();
println!("\n reverse string : {}", reverse_str);
let jac_theo_0 = (40 - kmer_size) as f64 / (80 - kmer_size) as f64;
log::info!("jac_theo_0 : {:.3e}", jac_theo_0);
let kmer_revcomp_hash_fn = |kmer: &Kmer32bit| -> u32 {
let canonical = kmer.reverse_complement().min(*kmer);
probminhash::invhash::int32_hash(canonical.0)
};
let kmer_identity = |kmer: &Kmer32bit| -> u32 { kmer.0 };
let vecsig = jaccard_index_probminhash3a(
&seqa,
&vecseqb,
sketch_size,
kmer_size,
kmer_revcomp_hash_fn,
);
log::info!("vecsig with revcomp hash {:?}", vecsig);
assert!(vecsig[0] >= 0.75 * jac_theo_0);
assert!(vecsig[1] >= 1.);
println!("calling with identity hash");
let vecsig =
jaccard_index_probminhash3a(&seqa, &vecseqb, sketch_size, kmer_size, kmer_identity);
debug!("vecsig with identity {:?}", vecsig);
assert!(vecsig[0] >= 0.75 * jac_theo_0);
if vecsig[1] > 0. {
println!("got intersection with reverse complement seq");
let mut wa: FnvHashMap<u32, f64> =
FnvHashMap::with_capacity_and_hasher(seqa.size(), FnvBuildHasher::default());
let mut pminhasha = ProbMinHash3a::<u32, NoHashHasher>::new(sketch_size, 0);
let mut kmergen = KmerSeqIterator::<Kmer32bit>::new(kmer_size, &seqa);
kmergen.set_range(0, seqa.size()).unwrap();
loop {
match kmergen.next() {
Some(kmer) => {
let hashval = kmer_identity(&kmer);
debug!(
" kmer in seqa {:?}, hvalval {:?} ",
String::from_utf8(kmer.get_uncompressed_kmer()).unwrap(),
hashval
);
*wa.entry(hashval).or_insert(0.) += 1.;
}
None => break,
}
} pminhasha.hash_weigthed_hashmap(&wa);
let mut wb: FnvHashMap<u32, f64> =
FnvHashMap::with_capacity_and_hasher(seqarevcomp.size(), FnvBuildHasher::default());
let mut pminhashb = ProbMinHash3a::<u32, NoHashHasher>::new(sketch_size, 0);
let mut kmergen = KmerSeqIterator::<Kmer32bit>::new(kmer_size, &seqarevcomp);
kmergen.set_range(0, seqarevcomp.size()).unwrap();
loop {
match kmergen.next() {
Some(kmer) => {
let hashval = kmer_identity(&kmer);
trace!(
" kmer in seqrevcomp {:?}, hvalval {:?} ",
kmer.get_uncompressed_kmer(),
hashval
);
*wb.entry(hashval).or_insert(0.) += 1.;
}
None => break,
}
} pminhashb.hash_weigthed_hashmap(&wb);
let (jac, common) = probminhash_get_jaccard_objects(
pminhasha.get_signature(),
pminhashb.get_signature(),
);
debug!("jac for common objects = {}", jac);
if jac > 0. {
debug!("common kemrs {:?}", common.unwrap());
}
} assert!(vecsig[1] <= 0.1);
}
#[test]
fn test_pminhasha_k16b32bit_serial() {
log_init_test();
let kmer_size = 16;
let seqstr = String::from(
"TCAAAGGGAAACATTCAAAATCAGTATGCGCCCGTTCAGTTACGTATTGCTCTCGCTAATGAGATGGGCTGGGTACAGAG",
);
let seqabytes = seqstr.as_bytes();
let seqa = Sequence::new(seqstr.as_bytes(), 2);
let mut vecseqb = Vec::<Sequence>::new();
let seqb1 = Sequence::new(&seqabytes[0..40], 2); vecseqb.push(seqb1);
let seqarevcomp = seqa.get_reverse_complement();
vecseqb.push(seqarevcomp.clone());
let reverse_str = String::from_utf8(seqarevcomp.decompress()).unwrap();
debug!("\n reverse string : {}", reverse_str);
let jac_theo_0 = (40 - kmer_size) as f64 / (80 - kmer_size) as f64;
let kmer_revcomp_hash_fn = |kmer: &Kmer16b32bit| -> u32 {
let canonical = kmer.reverse_complement().min(*kmer);
probminhash::invhash::int32_hash(canonical.0)
};
let kmer_identity = |kmer: &Kmer16b32bit| -> u32 { kmer.0 };
let vec_0 = jaccard_index_probminhash3a(
&seqa,
&vec![vecseqb[0].clone()],
50,
16,
kmer_revcomp_hash_fn,
);
let vec_1 = jaccard_index_probminhash3a(
&seqa,
&vec![vecseqb[1].clone()],
50,
16,
kmer_revcomp_hash_fn,
);
let mut vecsig = Vec::<f64>::with_capacity(2);
vecsig.push(vec_0[0]);
vecsig.push(vec_1[0]);
info!("vecsig with revcomp hash {:?}", vecsig);
assert!(vecsig[0] >= 0.75 * jac_theo_0);
assert!(vecsig[1] >= 1.);
info!("calling with identity hash");
let vecsig = jaccard_index_probminhash3a(&seqa, &vecseqb, 50, 16, kmer_identity);
info!("vecsig with identity {:?}", vecsig);
assert!(vecsig[0] >= 0.75 * jac_theo_0);
assert!(vecsig[1] <= 0.1);
}
#[test]
fn test_pminhash_kmer64bit_serial() {
log_init_test();
let kmer_size = 16;
let seqstr = String::from(
"TCAAAGGGAAACATTCAAAATCAGTATGCGCCCGTTCAGTTACGTATTGCTCTCGCTAATGAGATGGGCTGGGTACAGAG",
);
let seqabytes = seqstr.as_bytes();
let seqa = Sequence::new(seqstr.as_bytes(), 2);
let mut vecseqb = Vec::<Sequence>::new();
let seqb1 = Sequence::new(&seqabytes[0..40], 2); vecseqb.push(seqb1);
let seqarevcomp = seqa.get_reverse_complement();
vecseqb.push(seqarevcomp);
let kmer_revcomp_hash_fn = |kmer: &Kmer64bit| -> u64 {
let canonical = kmer.reverse_complement().min(*kmer);
probminhash::invhash::int64_hash(canonical.0)
};
let vec_jac = jaccard_index_probminhash3a(&seqa, &vecseqb, 50, 16, kmer_revcomp_hash_fn);
let jac_theo_0 = (40 - kmer_size) as f64 / (80 - kmer_size) as f64;
info!(
"vecsig with revcomp hash {:?} jaccard theo : {:.3e}",
vec_jac, jac_theo_0
);
assert!(vec_jac[0] >= 0.75 * jac_theo_0);
assert!(vec_jac[1] >= 1.);
}
#[test]
fn test_superminhash_kmer_16b32bit_serial() {
log_init_test();
let kmer_size = 16;
let sketch_size = 100;
let mut vecseq = Vec::<&Sequence>::new();
let seqstr = String::from(
"TCAAAGGGAAACATTCAAAATCAGTATGCGCCCGTTCAGTTACGTATTGCTCTCGCTAATGAGATGGGCTGGGTACAGAG",
);
let seqabytes = seqstr.as_bytes();
let seqa = Sequence::new(seqstr.as_bytes(), 2);
vecseq.push(&seqa);
let seqb1 = Sequence::new(&seqabytes[0..40], 2); vecseq.push(&seqb1);
let seqarevcomp = seqa.get_reverse_complement();
vecseq.push(&seqarevcomp);
let reverse_str = String::from_utf8(seqarevcomp.decompress()).unwrap();
log::debug!("\n reverse string : {}", reverse_str);
let jac_theo_0 = (40 - kmer_size) as f64 / (80 - kmer_size) as f64;
let kmer_revcomp_hash_fn = |kmer: &Kmer16b32bit| -> u32 {
let canonical = kmer.reverse_complement().min(*kmer);
probminhash::invhash::int32_hash(canonical.0)
};
let kmer_identity = |kmer: &Kmer16b32bit| -> u32 { kmer.0 };
let sketcher = SeqSketcher::new(kmer_size, sketch_size);
let sig_vec = sketcher.sketch_superminhash(&vecseq, kmer_revcomp_hash_fn);
let d_01 = compute_superminhash_jaccard(&sig_vec[0], &sig_vec[1]).unwrap();
let d_02 = compute_superminhash_jaccard(&sig_vec[0], &sig_vec[2]).unwrap();
debug!("seqa with revcomp hash {:?}", sig_vec[0]);
debug!("seqb with revcomp hash {:?}", sig_vec[1]);
debug!("seq rev comp with revcomp hash {:?}", sig_vec[2]);
info!("ditances with revcomp hash {:.3e} {:.3e}", d_01, d_02);
info!("expectiong {:.3e} {:.3e}", jac_theo_0, 1.);
assert!(d_01 >= 0.75 * jac_theo_0);
assert!(d_02 >= 1.);
println!("calling with identity hash");
let sig_vec = sketcher.sketch_superminhash(&vecseq, kmer_identity);
let d_01 = compute_superminhash_jaccard(&sig_vec[0], &sig_vec[1]).unwrap();
let d_02 = compute_superminhash_jaccard(&sig_vec[0], &sig_vec[2]).unwrap();
debug!("vecsig with identity {:?}", sig_vec);
info!("ditances with revcomp hash {:.3e} {:.3e}", d_01, d_02);
info!("expecting {:.3e}, {:.3e}", jac_theo_0, 0.);
assert!(d_01 >= 0.75 * jac_theo_0);
assert!(d_02 <= 0.1);
}
#[test]
fn test_reload_sketch_file() {
log_init_test();
let fname = String::from("/home.1/jpboth/Rust/kmerutils/Runs/umpsigk8s200");
let sketch_reader_res = SigSketchFileReader::new(&fname);
if sketch_reader_res.is_err() {
return;
}
let sketch_reader_res_ref = sketch_reader_res.as_ref();
if let Some(msg) = sketch_reader_res_ref.err() {
println!(
"test_reload_sketch_file, error with file : {} {} ",
fname, msg
);
return;
}
let mut sketch_reader_ref = sketch_reader_res.ok().unwrap();
println!("kmer size : {}", sketch_reader_ref.get_kmer_size());
println!("sig length : {}", sketch_reader_ref.get_signature_length());
println!("sig size : {}", sketch_reader_ref.get_signature_size());
let mut nbread = 0;
while let Some(_sig) = sketch_reader_ref.next() {
nbread += 1;
if nbread % 100000 == 0 {
println!("loaded nb sig : {}", nbread);
}
}
println!("loaded nb sig : {}", nbread);
} }