#![allow(clippy::needless_range_loop)]
use std::marker::PhantomData;
use std::fmt::Debug;
use std::hash::{BuildHasherDefault, Hasher};
use serde::{Deserialize, Serialize};
use fnv::{FnvBuildHasher, FnvHashMap};
use num;
use num::{Bounded, FromPrimitive, Integer, ToPrimitive, Unsigned};
use rand_distr::uniform::SampleUniform;
use crate::nohasher::*;
use crate::base::{kmer::*, kmergenerator::KmerSeqIteratorT, kmergenerator::*};
use super::nbkmerguess::*;
use rayon::prelude::*;
use crate::sketcharg::{SeqSketcherParams, SketchAlgo};
use probminhash::{
densminhash::*, probminhasher::*, setsketcher::SetSketchParams, setsketcher::SetSketcher,
superminhasher::SuperMinHash,
};
#[cfg(feature = "sminhash2")]
use probminhash::superminhasher2::SuperMinHash2;
#[allow(clippy::ptr_arg)]
pub trait SeqSketcherT<Kmer>
where
Kmer: CompressedKmerT + KmerBuilder<Kmer>,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
{
type Sig: Serialize + Clone + Send + Sync;
fn get_kmer_size(&self) -> usize;
fn get_sketch_size(&self) -> usize;
fn get_algo(&self) -> SketchAlgo;
fn sketch_compressedkmer<F>(&self, vseq: &[&Sequence], fhash: F) -> Vec<Vec<Self::Sig>>
where
F: Fn(&Kmer) -> Kmer::Val + Send + Sync;
fn sketch_compressedkmer_seqs<F>(&self, vseq: &[&Sequence], fhash: F) -> Vec<Vec<Self::Sig>>
where
F: Fn(&Kmer) -> Kmer::Val + Send + Sync;
}
#[derive(Serialize, Deserialize, Copy, Clone)]
pub struct ProbHash3aSketch<Kmer> {
_kmer_marker: PhantomData<Kmer>,
params: SeqSketcherParams,
}
impl<Kmer> ProbHash3aSketch<Kmer> {
pub fn new(params: &SeqSketcherParams) -> Self {
ProbHash3aSketch {
_kmer_marker: PhantomData,
params: *params,
}
}
}
impl<Kmer> SeqSketcherT<Kmer> for ProbHash3aSketch<Kmer>
where
Kmer: CompressedKmerT + KmerBuilder<Kmer> + Send + Sync,
Kmer::Val: num::PrimInt + Send + Sync + Debug + Clone + Serialize,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
{
type Sig = Kmer::Val;
fn get_kmer_size(&self) -> usize {
self.params.get_kmer_size()
}
fn get_sketch_size(&self) -> usize {
self.params.get_sketch_size()
}
fn get_algo(&self) -> SketchAlgo {
SketchAlgo::PROB3A
}
fn sketch_compressedkmer<F>(&self, vseq: &[&Sequence], fhash: F) -> Vec<Vec<Self::Sig>>
where
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
{
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.get_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.get_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 (rank, sig): (Vec<usize>, Vec<Vec<Self::Sig>>) = sig_with_rank.into_iter().unzip();
assert_eq!(rank, (0usize..vseq.len()).collect::<Vec<usize>>());
sig
}
fn sketch_compressedkmer_seqs<F>(&self, vseq: &[&Sequence], fhash: F) -> Vec<Vec<Self::Sig>>
where
Kmer: CompressedKmerT + KmerBuilder<Kmer> + Send + Sync,
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
Kmer::Val: num::PrimInt + Send + Sync + Debug,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
{
log::debug!("entering sketch_compressedkmer_seqs for ProHash3aSketch");
let nb_kmer = get_nbkmer_guess_seqs(vseq);
let mut wb: FnvHashMap<Kmer::Val, u64> =
FnvHashMap::with_capacity_and_hasher(nb_kmer, FnvBuildHasher::default());
let mut nb_kmer_generated: u64 = 0;
for seq in vseq {
let mut kmergen = KmerSeqIterator::<Kmer>::new(self.get_kmer_size() as u8, seq);
kmergen.set_range(0, seq.size()).unwrap();
while let Some(kmer) = kmergen.next() {
nb_kmer_generated += 1;
let hashval = fhash(&kmer);
*wb.entry(hashval).or_insert(0) += 1;
if log::log_enabled!(log::Level::Debug) && nb_kmer_generated % 500_000_000 == 0 {
log::debug!("nb kmer generated : {:#}", nb_kmer_generated);
}
} }
let mut pminhashb: ProbMinHash3a<Kmer::Val, NoHashHasher> =
ProbMinHash3a::<Kmer::Val, NoHashHasher>::new(
self.get_sketch_size(),
<Kmer::Val>::default(),
);
pminhashb.hash_weigthed_hashmap(&wb);
let sigb = pminhashb.get_signature();
let v = vec![sigb.clone()];
v
} }
#[derive(Serialize, Deserialize, Copy, Clone)]
pub struct SuperHashSketch<Kmer, S: num::Float> {
_kmer_marker: PhantomData<Kmer>,
_sig_marker: PhantomData<S>,
params: SeqSketcherParams,
}
impl<Kmer, S: num::Float> SuperHashSketch<Kmer, S> {
pub fn new(params: &SeqSketcherParams) -> Self {
SuperHashSketch {
_kmer_marker: PhantomData,
_sig_marker: PhantomData,
params: *params,
}
}
}
impl<Kmer, S> SeqSketcherT<Kmer> for SuperHashSketch<Kmer, S>
where
Kmer: CompressedKmerT + KmerBuilder<Kmer> + Send + Sync,
Kmer::Val: num::PrimInt + Send + Sync + Debug,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
S: num::Float + SampleUniform + Send + Sync + Debug + Serialize,
{
type Sig = S;
fn get_kmer_size(&self) -> usize {
self.params.get_kmer_size()
}
fn get_sketch_size(&self) -> usize {
self.params.get_sketch_size()
}
fn get_algo(&self) -> SketchAlgo {
SketchAlgo::SUPER
}
fn sketch_compressedkmer<F>(&self, vseq: &[&Sequence], fhash: F) -> Vec<Vec<Self::Sig>>
where
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
{
log::debug!("entering sketch_superminhash_compressedkmer");
let comput_closure = |seqb: &Sequence, i: usize| -> (usize, Vec<Self::Sig>) {
log::debug!(" in sketch_compressedkmer, closure");
let mut nb_kmer_generated: u64 = 0;
let bh = BuildHasherDefault::<NoHashHasher>::default();
let mut sminhash: SuperMinHash<Self::Sig, Kmer::Val, NoHashHasher> =
SuperMinHash::new(self.get_sketch_size(), bh);
let mut kmergen = KmerSeqIterator::<Kmer>::new(self.get_kmer_size() as u8, seqb);
kmergen.set_range(0, seqb.size()).unwrap();
while let Some(kmer) = kmergen.next() {
nb_kmer_generated += 1;
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());
}
if log::log_enabled!(log::Level::Debug) && nb_kmer_generated % 500_000_000 == 0 {
log::debug!("nb kmer generated : {:#}", nb_kmer_generated);
}
} let sigb = sminhash.get_hsketch();
(i, sigb.clone())
};
let sig_with_rank: Vec<(usize, Vec<Self::Sig>)> = (0..vseq.len())
.into_par_iter()
.map(|i| comput_closure(vseq[i], i))
.collect();
let (rank, sig): (Vec<usize>, Vec<Vec<Self::Sig>>) = sig_with_rank.into_iter().unzip();
assert_eq!(rank, (0usize..vseq.len()).collect::<Vec<usize>>());
sig
}
fn sketch_compressedkmer_seqs<F>(&self, vseq: &[&Sequence], fhash: F) -> Vec<Vec<Self::Sig>>
where
Kmer: CompressedKmerT + KmerBuilder<Kmer> + Send + Sync,
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
Kmer::Val: num::PrimInt + Send + Sync + Debug,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
{
log::debug!("entering sketch_compressedkmer_seqs for SuperMinHashSketch");
let bh = BuildHasherDefault::<NoHashHasher>::default();
let mut setsketch: SuperMinHash<Self::Sig, Kmer::Val, NoHashHasher> =
SuperMinHash::new(self.get_sketch_size(), bh);
let mut nb_kmer_generated: u64 = 0;
for seq in vseq {
let mut kmergen = KmerSeqIterator::<Kmer>::new(self.get_kmer_size() as u8, seq);
kmergen.set_range(0, seq.size()).unwrap();
while let Some(kmer) = kmergen.next() {
nb_kmer_generated += 1;
let hashval = fhash(&kmer);
if setsketch.sketch(&hashval).is_err() {
log::error!("could not hash kmer : {:?}", kmer.get_uncompressed_kmer());
std::panic!("could not hash kmer : {:?}", kmer.get_uncompressed_kmer());
}
if log::log_enabled!(log::Level::Debug) && nb_kmer_generated % 500_000_000 == 0 {
log::debug!("nb kmer generated : {:#}", nb_kmer_generated);
}
} }
let sig = setsketch.get_hsketch();
let v = vec![sig.clone()];
v
}
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct OptDensHashSketch<Kmer, S: num::Float> {
_kmer_marker: PhantomData<Kmer>,
_sig_marker: PhantomData<S>,
params: SeqSketcherParams,
}
impl<Kmer, S: num::Float> OptDensHashSketch<Kmer, S> {
pub fn new(params: &SeqSketcherParams) -> Self {
OptDensHashSketch {
_kmer_marker: PhantomData,
_sig_marker: PhantomData,
params: *params,
}
}
}
impl<Kmer, S> SeqSketcherT<Kmer> for OptDensHashSketch<Kmer, S>
where
Kmer: CompressedKmerT + KmerBuilder<Kmer> + Send + Sync,
Kmer::Val: num::PrimInt + Send + Sync + Debug,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
S: num::Float + SampleUniform + Send + Sync + Debug + Serialize,
{
type Sig = S;
fn get_kmer_size(&self) -> usize {
self.params.get_kmer_size()
}
fn get_sketch_size(&self) -> usize {
self.params.get_sketch_size()
}
fn get_algo(&self) -> SketchAlgo {
SketchAlgo::OPTDENS
}
fn sketch_compressedkmer<F>(&self, vseq: &[&Sequence], fhash: F) -> Vec<Vec<Self::Sig>>
where
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
{
log::debug!("entering OptDensHashSketch::sketch_compressedkmer");
let comput_closure = |seqb: &Sequence, i: usize| -> (usize, Vec<Self::Sig>) {
log::debug!(" in sketch_compressedkmer, closure");
let mut nb_kmer_generated: u64 = 0;
let bh = BuildHasherDefault::<NoHashHasher>::default();
let mut sminhash: OptDensMinHash<Self::Sig, Kmer::Val, NoHashHasher> =
OptDensMinHash::new(self.get_sketch_size(), bh);
let mut kmergen = KmerSeqIterator::<Kmer>::new(self.get_kmer_size() as u8, seqb);
kmergen.set_range(0, seqb.size()).unwrap();
while let Some(kmer) = kmergen.next() {
nb_kmer_generated += 1;
let hashval = fhash(&kmer);
sminhash.sketch(&hashval);
if log::log_enabled!(log::Level::Debug) && nb_kmer_generated % 500_000_000 == 0 {
log::debug!("nb kmer generated : {:#}", nb_kmer_generated);
}
} sminhash.end_sketch();
let sigb = sminhash.get_hsketch();
(i, sigb.clone())
};
let sig_with_rank: Vec<(usize, Vec<Self::Sig>)> = (0..vseq.len())
.into_par_iter()
.map(|i| comput_closure(vseq[i], i))
.collect();
let (rank, sig): (Vec<usize>, Vec<Vec<Self::Sig>>) = sig_with_rank.into_iter().unzip();
assert_eq!(rank, (0usize..vseq.len()).collect::<Vec<usize>>());
sig
}
fn sketch_compressedkmer_seqs<F>(&self, vseq: &[&Sequence], fhash: F) -> Vec<Vec<Self::Sig>>
where
Kmer: CompressedKmerT + KmerBuilder<Kmer> + Send + Sync,
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
Kmer::Val: num::PrimInt + Send + Sync + Debug,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
{
log::debug!("entering OptDensHashSketch::sketch_compressedkmer_seqs");
let bh = BuildHasherDefault::<NoHashHasher>::default();
let mut setsketch: OptDensMinHash<Self::Sig, Kmer::Val, NoHashHasher> =
OptDensMinHash::new(self.get_sketch_size(), bh);
let mut nb_kmer_generated: u64 = 0;
for seq in vseq {
let mut kmergen = KmerSeqIterator::<Kmer>::new(self.get_kmer_size() as u8, seq);
kmergen.set_range(0, seq.size()).unwrap();
while let Some(kmer) = kmergen.next() {
nb_kmer_generated += 1;
let hashval = fhash(&kmer);
setsketch.sketch(&hashval);
if log::log_enabled!(log::Level::Debug) && nb_kmer_generated % 500_000_000 == 0 {
log::debug!("nb kmer generated : {:#}", nb_kmer_generated);
}
} }
setsketch.end_sketch();
let sig = setsketch.get_hsketch();
let v = vec![sig.clone()];
v
} }
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct RevOptDensHashSketch<Kmer, S: num::Float> {
_kmer_marker: PhantomData<Kmer>,
_sig_marker: PhantomData<S>,
params: SeqSketcherParams,
}
impl<Kmer, S: num::Float> RevOptDensHashSketch<Kmer, S> {
pub fn new(params: &SeqSketcherParams) -> Self {
RevOptDensHashSketch {
_kmer_marker: PhantomData,
_sig_marker: PhantomData,
params: *params,
}
}
}
impl<Kmer, S> SeqSketcherT<Kmer> for RevOptDensHashSketch<Kmer, S>
where
Kmer: CompressedKmerT + KmerBuilder<Kmer> + Send + Sync,
Kmer::Val: num::PrimInt + Send + Sync + Debug,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
S: num::Float + SampleUniform + Send + Sync + Debug + Serialize,
{
type Sig = S;
fn get_kmer_size(&self) -> usize {
self.params.get_kmer_size()
}
fn get_sketch_size(&self) -> usize {
self.params.get_sketch_size()
}
fn get_algo(&self) -> SketchAlgo {
SketchAlgo::REVOPTDENS
}
fn sketch_compressedkmer<F>(&self, vseq: &[&Sequence], fhash: F) -> Vec<Vec<Self::Sig>>
where
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
{
log::debug!("entering RevOptDensHashSketch::sketch_compressedkmer");
let comput_closure = |seqb: &Sequence, i: usize| -> (usize, Vec<Self::Sig>) {
log::debug!(" in sketch_compressedkmer, closure");
let mut nb_kmer_generated: u64 = 0;
let bh = BuildHasherDefault::<NoHashHasher>::default();
let mut sminhash: RevOptDensMinHash<Self::Sig, Kmer::Val, NoHashHasher> =
RevOptDensMinHash::new(self.get_sketch_size(), bh);
let mut kmergen = KmerSeqIterator::<Kmer>::new(self.get_kmer_size() as u8, seqb);
kmergen.set_range(0, seqb.size()).unwrap();
while let Some(kmer) = kmergen.next() {
nb_kmer_generated += 1;
let hashval = fhash(&kmer);
sminhash.sketch(&hashval);
if log::log_enabled!(log::Level::Debug) && nb_kmer_generated % 500_000_000 == 0 {
log::debug!("nb kmer generated : {:#}", nb_kmer_generated);
}
} sminhash.end_sketch();
let sigb = sminhash.get_hsketch();
(i, sigb.clone())
};
let sig_with_rank: Vec<(usize, Vec<Self::Sig>)> = (0..vseq.len())
.into_par_iter()
.map(|i| comput_closure(vseq[i], i))
.collect();
let (rank, sig): (Vec<usize>, Vec<Vec<Self::Sig>>) = sig_with_rank.into_iter().unzip();
assert_eq!(rank, (0usize..vseq.len()).collect::<Vec<usize>>());
sig
}
fn sketch_compressedkmer_seqs<F>(&self, vseq: &[&Sequence], fhash: F) -> Vec<Vec<Self::Sig>>
where
Kmer: CompressedKmerT + KmerBuilder<Kmer> + Send + Sync,
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
Kmer::Val: num::PrimInt + Send + Sync + Debug,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
{
log::debug!("entering RevOptDensHashSketch::sketch_compressedkmer_seqs");
let bh = BuildHasherDefault::<NoHashHasher>::default();
let mut setsketch: RevOptDensMinHash<Self::Sig, Kmer::Val, NoHashHasher> =
RevOptDensMinHash::new(self.get_sketch_size(), bh);
let mut nb_kmer_generated: u64 = 0;
for seq in vseq {
let mut kmergen = KmerSeqIterator::<Kmer>::new(self.get_kmer_size() as u8, seq);
kmergen.set_range(0, seq.size()).unwrap();
while let Some(kmer) = kmergen.next() {
nb_kmer_generated += 1;
let hashval = fhash(&kmer);
setsketch.sketch(&hashval);
if log::log_enabled!(log::Level::Debug) && nb_kmer_generated % 500_000_000 == 0 {
log::debug!("nb kmer generated : {:#}", nb_kmer_generated);
}
} }
setsketch.end_sketch();
let sig = setsketch.get_hsketch();
let v = vec![sig.clone()];
v
} }
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct HllSeqsThreading {
nb_iter_thread: usize,
thread_threshold: usize,
}
impl HllSeqsThreading {
pub fn new(nb_iter_thread: usize, thread_threshold: usize) -> Self {
HllSeqsThreading {
nb_iter_thread,
thread_threshold,
}
}
pub fn get_nb_iter_threads(&self) -> usize {
self.nb_iter_thread
}
pub fn get_thread_threshold(&self) -> usize {
self.thread_threshold
}
}
impl Default for HllSeqsThreading {
fn default() -> Self {
HllSeqsThreading {
nb_iter_thread: 4,
thread_threshold: 10_000_000,
}
}
}
#[derive(Serialize, Deserialize, Copy, Clone)]
pub struct HyperLogLogSketch<Kmer, S: num::Integer> {
params: SeqSketcherParams,
hll_params: SetSketchParams,
hll_threads: HllSeqsThreading,
_kmer_marker: PhantomData<Kmer>,
_sig_marker: PhantomData<S>,
}
impl<Kmer, S: Integer> HyperLogLogSketch<Kmer, S> {
pub fn new(
seq_params: &SeqSketcherParams,
hll_params: SetSketchParams,
hll_threads: HllSeqsThreading,
) -> Self {
HyperLogLogSketch {
params: *seq_params,
hll_params,
hll_threads,
_kmer_marker: PhantomData,
_sig_marker: PhantomData,
}
}
pub fn sketch_compressedkmer_seqs_block<F>(
&self,
vseq: &[&Sequence],
fhash: F,
) -> SetSketcher<S, Kmer::Val, NoHashHasher>
where
Kmer: CompressedKmerT + KmerBuilder<Kmer> + Send + Sync,
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
Kmer::Val: num::PrimInt + Send + Sync + Debug,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
S: Integer
+ Bounded
+ Copy
+ Clone
+ FromPrimitive
+ ToPrimitive
+ Send
+ Sync
+ Debug
+ Serialize,
{
log::trace!("entering sketch_compressedkmer_seqs_block for HyperLogLogSketch");
let bh = BuildHasherDefault::<NoHashHasher>::default();
let mut setsketch: SetSketcher<S, Kmer::Val, NoHashHasher> =
SetSketcher::new(self.hll_params, bh);
let mut nb_kmer_generated: u64 = 0;
for seq in vseq {
let mut kmergen = KmerSeqIterator::<Kmer>::new(self.get_kmer_size() as u8, seq);
kmergen.set_range(0, seq.size()).unwrap();
while let Some(kmer) = kmergen.next() {
nb_kmer_generated += 1;
let hashval = fhash(&kmer);
if setsketch.sketch(&hashval).is_err() {
log::error!("could not hash kmer : {:?}", kmer.get_uncompressed_kmer());
std::panic!("could not hash kmer : {:?}", kmer.get_uncompressed_kmer());
}
if log::log_enabled!(log::Level::Debug) && nb_kmer_generated % 500_000_000 == 0 {
log::debug!("nb kmer generated : {:#}", nb_kmer_generated);
}
} }
setsketch
}
}
impl<Kmer, S> SeqSketcherT<Kmer> for HyperLogLogSketch<Kmer, S>
where
Kmer: CompressedKmerT + KmerBuilder<Kmer> + Send + Sync,
Kmer::Val: num::PrimInt + Send + Sync + Debug,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
S: Integer
+ Bounded
+ Copy
+ Clone
+ FromPrimitive
+ ToPrimitive
+ Send
+ Sync
+ Debug
+ Serialize,
{
type Sig = S;
fn get_kmer_size(&self) -> usize {
self.params.get_kmer_size()
}
fn get_sketch_size(&self) -> usize {
self.params.get_sketch_size()
}
fn get_algo(&self) -> SketchAlgo {
SketchAlgo::HLL
}
fn sketch_compressedkmer<F>(&self, vseq: &[&Sequence], fhash: F) -> Vec<Vec<Self::Sig>>
where
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
{
log::debug!("entering sketch_compressedkmer for HyperLogLogSketch");
let comput_closure = |seqb: &Sequence, i: usize| -> (usize, Vec<Self::Sig>) {
log::debug!(" in sketch_compressedkmer, closure");
let mut nb_kmer_generated: u64 = 0;
let bh = BuildHasherDefault::<NoHashHasher>::default();
let mut setsketch: SetSketcher<Self::Sig, Kmer::Val, NoHashHasher> =
SetSketcher::new(self.hll_params, bh);
let mut kmergen = KmerSeqIterator::<Kmer>::new(self.get_kmer_size() as u8, seqb);
kmergen.set_range(0, seqb.size()).unwrap();
while let Some(kmer) = kmergen.next() {
nb_kmer_generated += 1;
let hashval = fhash(&kmer);
if setsketch.sketch(&hashval).is_err() {
log::error!("could not hash kmer : {:?}", kmer.get_uncompressed_kmer());
std::panic!("could not hash kmer : {:?}", kmer.get_uncompressed_kmer());
}
if log::log_enabled!(log::Level::Debug) && nb_kmer_generated % 500_000_000 == 0 {
log::debug!("nb kmer generated : {:#}", nb_kmer_generated);
}
} let sigb = setsketch.get_signature().clone();
drop(setsketch);
(i, sigb)
};
let sig_with_rank: Vec<(usize, Vec<Self::Sig>)> = (0..vseq.len())
.into_par_iter()
.map(|i| comput_closure(vseq[i], i))
.collect();
let (rank, sig): (Vec<usize>, Vec<Vec<Self::Sig>>) = sig_with_rank.into_iter().unzip();
assert_eq!(rank, (0usize..vseq.len()).collect::<Vec<usize>>());
sig
}
fn sketch_compressedkmer_seqs<F>(&self, vseq: &[&Sequence], fhash: F) -> Vec<Vec<Self::Sig>>
where
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
{
if log::log_enabled!(log::Level::Debug) {
log::debug!("entering sketch_compressedkmer_seqs for HyperLogLogSketch");
log::debug!("memory : {:?}", memory_stats::memory_stats().unwrap());
}
let thread_threshold = self.hll_threads.get_thread_threshold();
const BASE_LOG: usize = 3;
let total_size = vseq.iter().fold(0, |acc, s| acc + s.size());
if total_size <= BASE_LOG * thread_threshold {
log::debug!(
" calling directly sketch_compressedkmer_seqs_block, total size : {}",
total_size
);
let sketch = self.sketch_compressedkmer_seqs_block(vseq, fhash);
let v_sketch: Vec<Vec<S>> = vec![sketch.get_signature().clone()];
drop(sketch);
if log::log_enabled!(log::Level::Debug) {
log::debug!("exiting sketch_compressedkmer_seqs for HyperLogLogSketch");
log::debug!("memory : {:?}", memory_stats::memory_stats().unwrap());
}
return v_sketch;
}
let nb_sequences = vseq.len();
let nb_thread_max = self.hll_threads.get_nb_iter_threads();
let nb_blocks: usize =
nb_thread_max.min((total_size / thread_threshold).ilog(BASE_LOG) as usize);
let block_size = (nb_sequences as f64 / nb_blocks as f64).round() as usize;
log::debug!(
"nb_base : {}, nb_seq {}, block_size (nb_seq/thread): {}, nb_blocks : {}",
total_size,
nb_sequences,
block_size,
nb_blocks
);
let mut frontiers = Vec::<usize>::with_capacity(nb_blocks + 1);
for i in 0..nb_blocks {
if i == 0 {
frontiers.push(0);
} else {
frontiers.push(nb_sequences.min(i * block_size));
}
}
frontiers.push(nb_sequences);
let v_sketch: Vec<SetSketcher<S, Kmer::Val, NoHashHasher>> = (0..nb_blocks)
.into_par_iter()
.map(|i| {
self.sketch_compressedkmer_seqs_block(&vseq[frontiers[i]..frontiers[i + 1]], &fhash)
})
.collect();
let bh = BuildHasherDefault::<NoHashHasher>::default();
let mut setsketch: SetSketcher<S, Kmer::Val, NoHashHasher> =
SetSketcher::new(self.hll_params, bh);
for sketch in &v_sketch {
let res = setsketch.merge(sketch);
if res.is_err() {
log::error!("an error occurred in merging signatures");
std::panic!("an error occurred in merging signatures");
}
}
let sig = setsketch.get_signature().clone();
let v: Vec<Vec<Self::Sig>> = vec![sig];
drop(v_sketch);
drop(setsketch);
if log::log_enabled!(log::Level::Debug) {
log::debug!("exiting sketch_compressedkmer_seqs for HyperLogLogSketch");
log::debug!("memory : {:?}", memory_stats::memory_stats().unwrap());
}
v
} }
#[cfg(feature = "sminhash2")]
#[derive(Clone)]
pub struct SuperHash2Sketch<Kmer, S: Integer + Unsigned, H: Hasher + Default> {
_kmer_marker: PhantomData<Kmer>,
_sig_marker: PhantomData<S>,
build_hasher: BuildHasherDefault<H>,
params: SeqSketcherParams,
}
#[cfg(feature = "sminhash2")]
impl<Kmer, S: Integer + Unsigned, H: Hasher + Default> SuperHash2Sketch<Kmer, S, H> {
pub fn new(params: &SeqSketcherParams, build_hasher: BuildHasherDefault<H>) -> Self {
SuperHash2Sketch {
_kmer_marker: PhantomData,
_sig_marker: PhantomData,
build_hasher,
params: *params,
}
}
}
#[cfg(feature = "sminhash2")]
impl<Kmer, S, H> SeqSketcherT<Kmer> for SuperHash2Sketch<Kmer, S, H>
where
Kmer: CompressedKmerT + KmerBuilder<Kmer> + Send + Sync,
Kmer::Val: num::PrimInt + Send + Sync + Debug,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
H: Hasher + Default,
S: Integer
+ Unsigned
+ ToPrimitive
+ FromPrimitive
+ Bounded
+ Copy
+ Clone
+ Send
+ Sync
+ Serialize
+ std::fmt::Debug,
{
type Sig = S;
fn get_kmer_size(&self) -> usize {
self.params.get_kmer_size()
}
fn get_sketch_size(&self) -> usize {
self.params.get_sketch_size()
}
fn get_algo(&self) -> SketchAlgo {
SketchAlgo::SUPER2
}
fn sketch_compressedkmer<F>(&self, vseq: &[&Sequence], fhash: F) -> Vec<Vec<Self::Sig>>
where
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
{
log::debug!("entering sketch_compressedkmer for superminhash2");
let comput_closure = |seqb: &Sequence, i: usize| -> (usize, Vec<Self::Sig>) {
log::debug!(" in sketch_compressedkmer (superminhash), closure");
let mut nb_kmer_generated: u64 = 0;
let mut sminhash: SuperMinHash2<Self::Sig, Kmer::Val, H> =
SuperMinHash2::new(self.get_sketch_size(), self.build_hasher.clone());
let mut kmergen = KmerSeqIterator::<Kmer>::new(self.get_kmer_size() as u8, seqb);
kmergen.set_range(0, seqb.size()).unwrap();
while let Some(kmer) = kmergen.next() {
nb_kmer_generated += 1;
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());
}
if log::log_enabled!(log::Level::Debug) && nb_kmer_generated % 500_000_000 == 0 {
log::debug!("nb kmer generated : {:#}", nb_kmer_generated);
}
} let sigb = sminhash.get_hsketch();
(i, sigb.clone())
};
let sig_with_rank: Vec<(usize, Vec<Self::Sig>)> = (0..vseq.len())
.into_par_iter()
.map(|i| comput_closure(vseq[i], i))
.collect();
let (rank, sig): (Vec<usize>, Vec<Vec<Self::Sig>>) = sig_with_rank.into_iter().unzip();
assert_eq!(rank, (0usize..vseq.len()).collect::<Vec<usize>>());
sig
}
#[cfg(feature = "sminhash2")]
fn sketch_compressedkmer_seqs<F>(&self, vseq: &[&Sequence], fhash: F) -> Vec<Vec<Self::Sig>>
where
Kmer: CompressedKmerT + KmerBuilder<Kmer> + Send + Sync,
F: Fn(&Kmer) -> Kmer::Val + Send + Sync,
Kmer::Val: num::PrimInt + Send + Sync + Debug,
KmerGenerator<Kmer>: KmerGenerationPattern<Kmer>,
{
log::debug!("entering sketch_compressedkmer_seqs for SuperHash2Sketch");
let bh = BuildHasherDefault::<NoHashHasher>::default();
let mut setsketch: SuperMinHash2<Self::Sig, Kmer::Val, NoHashHasher> =
SuperMinHash2::new(self.get_sketch_size(), bh);
let mut nb_kmer_generated: u64 = 0;
for seq in vseq {
let mut kmergen = KmerSeqIterator::<Kmer>::new(self.get_kmer_size() as u8, seq);
kmergen.set_range(0, seq.size()).unwrap();
while let Some(kmer) = kmergen.next() {
nb_kmer_generated += 1;
let hashval = fhash(&kmer);
if setsketch.sketch(&hashval).is_err() {
log::error!("could not hash kmer : {:?}", kmer.get_uncompressed_kmer());
std::panic!("could not hash kmer : {:?}", kmer.get_uncompressed_kmer());
}
if log::log_enabled!(log::Level::Debug) && nb_kmer_generated % 500_000_000 == 0 {
log::debug!("nb kmer generated : {:#}", nb_kmer_generated);
}
} }
let sig = setsketch.get_hsketch();
let v = vec![sig.clone()];
v
} }
#[cfg(test)]
mod tests {
use super::*;
use crate::sketcharg::{DataType, SeqSketcherParams, SketchAlgo};
fn log_init_test() {
let mut builder = env_logger::Builder::from_default_env();
let _ = builder.is_test(true).try_init();
}
fn ascii_to_seq(asc: &str) -> Result<Sequence, ()> {
let alphabet = Alphabet2b::new();
let mut seq = Sequence::with_capacity(2, asc.len());
let mut bases = Vec::<u8>::with_capacity(asc.len());
for c in asc.chars() {
bases.push(c as u8);
}
log::info!("bases : {:?}", bases);
seq.encode_and_add(&bases, &alphabet);
log::info!("seq len {}", seq.size());
Ok(seq)
}
#[test]
fn test_seq_optdensminhash_trait() {
log_init_test();
log::debug!("test_seq_optdensminhash_trait");
let str1 = "ATCATGCCCCTTTAGAAAATTTCCGGATCATCGTACGGAGCATGCGTACAACGTCGATGC";
let str2 = "ATCATGCCCCTTTAGAAAATTTCCGGATCATCATGCCCCTTTAGAAAATTTCCGGATC";
let seq1 = ascii_to_seq(str1).unwrap();
let seq2 = ascii_to_seq(str2).unwrap();
log::debug!("seq1 : len : {}, {:?}", seq1.size(), seq1.decompress());
let vseq = vec![&seq1, &seq2];
let kmer_size = 5;
let sketch_size = 800;
let sketch_args =
SeqSketcherParams::new(kmer_size, sketch_size, SketchAlgo::OPTDENS, DataType::AA);
let nb_alphabet_bits = Alphabet2b::new().get_nb_bits();
let mask: u64 =
num::NumCast::from::<u64>((0b1 << (nb_alphabet_bits * kmer_size as u8)) - 1).unwrap();
log::debug!("mask = {:b}", mask);
let kmer_hash_fn = |kmer: &Kmer32bit| -> <Kmer32bit as CompressedKmerT>::Val {
let mask: <Kmer32bit as CompressedKmerT>::Val =
num::NumCast::from::<u64>((0b1 << (nb_alphabet_bits * kmer.get_nb_base())) - 1)
.unwrap();
kmer.get_compressed_value() & mask
};
log::info!("calling sketch_compressedkmeraa for OptDensHashSketch::<Kmer32bit, f64>");
let sketcher_f64 = OptDensHashSketch::<Kmer32bit, f64>::new(&sketch_args);
let signatures = sketcher_f64.sketch_compressedkmer(&vseq, kmer_hash_fn);
let sig1 = &signatures[0];
let sig2 = &signatures[1];
let inter: u64 = sig1
.iter()
.zip(sig2.iter())
.map(|(a, b)| if a == b { 1 } else { 0 })
.sum();
let dist = inter as f64 / sig1.len() as f64;
log::info!(
"OptDensHashSketch::<Kmer32bit, f64> inter : {:?} length {:?} jaccard distance {:?}",
inter,
sig1.len(),
dist
);
assert!((dist - 0.5).abs() < 1. / 10.);
let sketcher_f32 = OptDensHashSketch::<Kmer32bit, f32>::new(&sketch_args);
let signatures = sketcher_f32.sketch_compressedkmer(&vseq, kmer_hash_fn);
let sig1 = &signatures[0];
let sig2 = &signatures[1];
let inter: u64 = sig1
.iter()
.zip(sig2.iter())
.map(|(a, b)| if a == b { 1 } else { 0 })
.sum();
let dist = inter as f64 / sig1.len() as f64;
log::info!(
"OptDensHashSketch::<Kmer32bit, f32> inter : {:?} length {:?} jaccard distance {:?}",
inter,
sig1.len(),
dist
);
assert!((dist - 0.5).abs() < 1. / 10.);
}
#[test]
fn test_seq_revoptdensminhash_trait() {
log_init_test();
log::debug!("test_seq_revoptdensminhash_trait");
let str1 = "ATCATGCCCCTTTAGAAAATTTCCGGATCATCGTACGGAGCATGCGTACAACGTCGATGC";
let str2 = "ATCATGCCCCTTTAGAAAATTTCCGGATCATCATGCCCCTTTAGAAAATTTCCGGATC";
let seq1 = ascii_to_seq(str1).unwrap();
let seq2 = ascii_to_seq(str2).unwrap();
log::debug!("seq1 : len : {}, {:?}", seq1.size(), seq1.decompress());
let vseq = vec![&seq1, &seq2];
let kmer_size = 5;
let sketch_size = 8000;
let sketch_args =
SeqSketcherParams::new(kmer_size, sketch_size, SketchAlgo::OPTDENS, DataType::AA);
let nb_alphabet_bits = Alphabet2b::new().get_nb_bits();
let mask: u64 =
num::NumCast::from::<u64>((0b1 << (nb_alphabet_bits * kmer_size as u8)) - 1).unwrap();
log::debug!("mask = {:b}", mask);
let kmer_hash_fn = |kmer: &Kmer32bit| -> <Kmer32bit as CompressedKmerT>::Val {
let mask: <Kmer32bit as CompressedKmerT>::Val =
num::NumCast::from::<u64>((0b1 << (nb_alphabet_bits * kmer.get_nb_base())) - 1)
.unwrap();
kmer.get_compressed_value() & mask
};
log::info!("calling sketch_compressedkmeraa for RevOptDensHashSketch::<Kmer32bit, f64>");
let sketcher_f64 = RevOptDensHashSketch::<Kmer32bit, f64>::new(&sketch_args);
let signatures = sketcher_f64.sketch_compressedkmer(&vseq, kmer_hash_fn);
let sig1 = &signatures[0];
let sig2 = &signatures[1];
let inter: u64 = sig1
.iter()
.zip(sig2.iter())
.map(|(a, b)| if a == b { 1 } else { 0 })
.sum();
let dist = inter as f64 / sig1.len() as f64;
log::info!(
"RevOptDensHashSketch::<Kmer32bit, f64> inter : {:?} length {:?} jaccard distance {:?}",
inter,
sig1.len(),
dist
);
assert!((dist - 0.5).abs() < 1. / 10.);
let sketcher_f32 = RevOptDensHashSketch::<Kmer32bit, f32>::new(&sketch_args);
let signatures = sketcher_f32.sketch_compressedkmer(&vseq, kmer_hash_fn);
let sig1 = &signatures[0];
let sig2 = &signatures[1];
let inter: u64 = sig1
.iter()
.zip(sig2.iter())
.map(|(a, b)| if a == b { 1 } else { 0 })
.sum();
let dist = inter as f64 / sig1.len() as f64;
log::info!(
"RevOptDensHashSketch::<Kmer32bit, f32> inter : {:?} length {:?} jaccard distance {:?}",
inter,
sig1.len(),
dist
);
assert!((dist - 0.5).abs() < 1. / 10.);
} }