1use bimap::BiMap;
2use clap::ValueEnum;
3use serde::{de::DeserializeOwned, Deserialize, Serialize};
4use statrs::distribution::{ContinuousCDF, Normal, StudentsT};
5use summarydata_derive::SummaryData;
6use crate::{BaseQuality, EdgeMap, EdgeMult, Exts, Kmer, KmerDataItem, Tags};
7use std::{cmp::min_by, collections::HashMap, error::Error, fmt::{Debug, Display}, mem};
8
9#[cfg(not(feature = "sample128"))]
11pub type Marker = u64;
12
13#[cfg(feature = "sample128")]
15pub type Marker = u128;
16
17#[cfg(not(feature = "id4b"))]
19pub type ID = u16;
20
21#[cfg(feature = "id4b")]
23pub type ID = u32;
24
25pub type Tag = u8;
27
28#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Serialize, Deserialize, Hash)]
29pub struct IDTag {
31 id: ID,
32 tag: Tag
33}
34
35impl IDTag {
36 pub fn new(id: ID, tag: Tag) -> IDTag {
37 IDTag { id, tag }
38 }
39
40 pub fn tag(&self) -> Tag {
41 self.tag
42 }
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
46pub struct Translator {
48 ids: Option<BiMap<String, ID>>,
49 tags: Option<BiMap<String,Tag>>,
50}
51
52impl Translator {
53 pub fn new(ids: BiMap<String, ID>, tags: BiMap<String,Tag>) -> Translator {
55 Translator { ids: Some(ids), tags: Some(tags) }
56 }
57
58 pub fn empty() -> Translator {
60 Translator { ids: None, tags: None }
61 }
62
63 pub fn new_tag_translator(hashed_tags: BiMap<String, Tag>) -> Translator {
65 Translator { ids: None, tags: Some(hashed_tags) }
66 }
67
68 pub fn new_id_translator(hashed_ids: BiMap<String, ID>) -> Translator {
70 Translator { ids: Some(hashed_ids), tags: None }
71 }
72
73 pub fn tag_translator(&self) -> &Option<BiMap<String, Tag>> {
75 &self.tags
76 }
77
78 pub fn id_translator(&self) -> &Option<BiMap<String, ID>> {
80 &self.ids
81 }
82
83 pub fn mut_id_translator(&mut self) -> &mut Option<BiMap<String, ID>> {
85 &mut self.ids
86 }
87
88 pub fn dissolve(self) -> (Option<BiMap<String, ID>>, Option<BiMap<String,Tag>>) {
90 (self.ids, self.tags)
91 }
92}
93
94fn id_format(ids: &[ID], translator: &Translator, id_group_translator: Option<&HashMap<ID, ID>>) -> String {
95 if let Some(id_gr_tr) = id_group_translator {
96 let mut t_ids = ids
98 .iter()
99 .map(|id| id_gr_tr.get(id).unwrap_or_else(|| panic!("ID does not exist - ids {:?}", ids)))
100 .collect::<Vec<_>>();
101 t_ids.sort();
102 t_ids.dedup();
103 format!("{:?}", t_ids)
104 } else if let Some(id_translator) = translator.id_translator() {
105 let t_ids = ids
107 .iter()
108 .map(|id| id_translator.get_by_right(id).unwrap_or_else(|| panic!("ID does not exist - ids {:?}", ids)))
109 .collect::<Vec<_>>();
110 format!("{:?}", t_ids)
111 } else {
112 format!("{:?}", ids)
114 }
115}
116
117#[derive(Debug, PartialEq)]
118struct NotEnoughSamplesError {}
119
120impl Error for NotEnoughSamplesError {}
121
122impl Display for NotEnoughSamplesError {
123 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124 write!(f, "not enough samples were supplied to perform a statistical test")
125 }
126}
127
128#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
195pub struct SummaryConfig {
196 min_kmer_obs: usize,
197 significant: Option<u32>,
198 group_frac: GroupFrac,
199 frac_cutoff: f32,
200 sample_info: SampleInfo,
201 max_p: Option<f32>,
202 stat_test: StatTest,
203 stat_test_changed: bool,
204 min_quality: BaseQuality,
205 min_quality_for_edge: BaseQuality
206}
207
208impl SummaryConfig {
209 pub fn new(sample_info: SampleInfo) -> Self {
215 SummaryConfig::empty().with_sample_info(sample_info)
216 }
217
218 pub fn empty() -> Self {
221 SummaryConfig {
222 min_kmer_obs: 1,
223 significant: None,
224 group_frac: GroupFrac::None,
225 frac_cutoff: 0.,
226 sample_info: SampleInfo::empty(),
227 max_p: None,
228 stat_test: StatTest::WelchsTTest,
229 stat_test_changed: false,
230 min_quality: BaseQuality::NoCall,
231 min_quality_for_edge: BaseQuality::NoCall,
232 }
233 }
234
235 pub fn with_min_kmer_obs(&self, min_kmer_obs: usize) -> Self {
238 let mut config = self.clone();
239 config.min_kmer_obs = min_kmer_obs;
240 config
241 }
242
243 pub fn set_min_kmer_obs(&mut self, min_kmer_obs: usize) {
246 self.min_kmer_obs = min_kmer_obs;
247 }
248
249 pub fn with_significant(&self, significant_digits: Option<u32>) -> Self {
252 let mut config = self.clone();
253 config.significant = significant_digits;
254 config
255 }
256
257 pub fn set_significant(&mut self, significant_digits: Option<u32>) {
260 self.significant = significant_digits;
261 }
262
263 pub fn with_group_frac(&self, group_frac: GroupFrac, frac_cutoff: f32) -> Self {
267 let mut config = self.clone();
268 config.group_frac = group_frac;
269 config.frac_cutoff = frac_cutoff;
270 config
271 }
272
273 pub fn set_group_frac(&mut self, group_frac: GroupFrac, frac_cutoff: f32) {
277 self.group_frac = group_frac;
278 self.frac_cutoff = frac_cutoff;
279 }
280
281 fn with_sample_info(self, sample_info: SampleInfo) -> Self {
283 let mut config = self.clone();
284 config.sample_info = sample_info;
285 config
286 }
287
288 pub fn with_max_p(&self, max_p: Option<f32>) -> Self {
291 let mut config = self.clone();
292 config.max_p = max_p;
293 config
294 }
295
296 pub fn set_max_p(&mut self, max_p: Option<f32>) {
298 self.max_p = max_p;
299 }
300
301 pub fn with_stat_test(&self, stat_test: StatTest) -> Self {
304 let mut config = self.clone();
305 config.stat_test = stat_test;
306 config
307 }
308
309 pub fn set_stat_test(&mut self, stat_test: StatTest) {
312 if stat_test != self.stat_test { self.stat_test_changed = true }
313 self.stat_test = stat_test;
314 }
315
316 pub fn with_min_quality(&self, min_quality: BaseQuality) -> Self {
318 let mut config = self.clone();
319 config.min_quality = min_quality;
320 config
321 }
322
323 pub fn set_min_quality(&mut self, min_quality: BaseQuality) {
326 self.min_quality = min_quality;
327 }
328
329 pub fn with_min_quality_for_edge(&self, min_quality_for_edge: BaseQuality) -> Self {
333 let mut config = self.clone();
334 config.min_quality_for_edge = min_quality_for_edge;
335 config
336 }
337
338 pub fn set_min_quality_for_edge(&mut self, min_quality_for_edge: BaseQuality) {
341 self.min_quality_for_edge = min_quality_for_edge;
342 }
343
344 pub fn get_markers(&self) -> (Marker, Marker) {
346 self.sample_info.get_markers()
347 }
348
349 pub fn sample_info(&self) -> &SampleInfo {
351 &self.sample_info
352 }
353}
354
355#[derive(Copy, Clone, PartialEq, PartialOrd, ValueEnum, Debug, Serialize, Deserialize)]
358#[serde(rename_all = "kebab-case")]
359pub enum GroupFrac {
360 None,
361 One,
362 Both,
363}
364
365impl std::fmt::Display for GroupFrac {
366 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
367 match &self {
368 GroupFrac::None => write!(f, "none"),
369 GroupFrac::One => write!(f, "one"),
370 GroupFrac::Both => write!(f, "both")
371 }
372 }
373}
374
375#[derive(Copy, Clone, PartialEq, PartialOrd, ValueEnum, Debug, Serialize, Deserialize)]
377#[serde(rename_all = "kebab-case")]
378pub enum StatTest {
379 StudentsTTest,
380 WelchsTTest,
381 UTest,
382}
383
384impl std::fmt::Display for StatTest {
385 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
386 match self {
387 Self::StudentsTTest => write!(f, "students-t-test"),
388 Self::WelchsTTest => write!(f, "welchs-t-test"),
389 Self::UTest => write!(f, "u-test"),
390
391 }
392 }
393
394}
395
396#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord)]
417pub struct SampleInfo {
418 marker0: Marker,
419 marker1: Marker,
420 count0: u8,
421 count1: u8,
422 sample_kmers: Vec<u64>,
423}
424
425impl SampleInfo {
426 pub fn new(marker0: Marker, marker1: Marker, sample_kmers: Vec<u64>) -> Self {
434 let count0 = marker0.count_ones() as u8;
435 let count1 = marker1.count_ones() as u8;
436 assert_eq!(count0+count1, sample_kmers.len() as u8);
437
438 SampleInfo { marker0, marker1, count0, count1, sample_kmers }
439 }
440
441 pub fn empty() -> Self {
443 SampleInfo { marker0: 0, marker1: 0, count0: 0, count1: 0, sample_kmers: Vec::new() }
444 }
445
446 pub fn get_markers(&self) -> (Marker, Marker) {
448 (self.marker0, self.marker1)
449 }
450}
451
452fn tag_counter(tag_vec: &[Tag]) -> Vec<u32> {
454 let mut tag_counter = 1;
455 let mut tag_counts: Vec<u32> = Vec::new();
456
457 for i in 1..tag_vec.len() {
459 if tag_vec[i] == tag_vec[i-1] {
460 tag_counter += 1;
461 } else {
462 tag_counts.push(tag_counter);
463 tag_counter = 1;
464 }
465 }
466 tag_counts.push(tag_counter);
467 tag_counts.shrink_to_fit();
468
469 tag_counts
470}
471
472#[derive(Debug)]
473struct TagSummary {
474 all_exts: Exts,
475 tag_vec: Vec<Tag>,
476 tag_counts: Vec<u32>,
477 sum: u32,
478 edge_mults: EdgeMult,
479 highest_quality: Option<BaseQuality>,
480}
481
482fn summarize_tags<K: Kmer, F: Iterator<Item = KmerDataItem<K, Tag>>>(items: F) -> TagSummary {
484 let mut all_exts = Exts::empty();
485 let mut tag_vec: Vec<Tag> = Vec::with_capacity(items.size_hint().0);
486 let mut edge_mults = EdgeMult::new();
487 let mut highest_quality = None;
488
489 let mut nobs = 0;
490 for item in items {
491 tag_vec.push(item.data);
492 all_exts = all_exts.add(item.exts);
493 edge_mults.add_exts(item.exts);
494 nobs += 1;
495
496 if let Some(q) = item.quality {
497 if let Some(hq) = highest_quality {
498 if q > hq { highest_quality = Some(q) }
499 } else {
500 highest_quality = Some(q)
501 }
502 }
503 }
504
505 assert_eq!(all_exts, edge_mults.exts());
506
507 tag_vec.sort();
508
509 let tag_counts = tag_counter(&tag_vec);
510
511 tag_vec.dedup();
512
513 TagSummary { all_exts, tag_vec, tag_counts, sum: nobs, edge_mults, highest_quality }
514}
515
516fn summarize_tags_edge_q<K: Kmer, F: Iterator<Item = KmerDataItem<K, Tag>>>(items: F, config: &SummaryConfig)
517-> TagSummary
518{
519 let items_filtered = items.filter(|item|
521 match item.quality {
522 None => true,
523 Some(q) => q >= config.min_quality_for_edge
524 }
525 );
526
527 summarize_tags(items_filtered)
528}
529
530#[derive(Debug)]
531struct IDTagSummary {
532 all_exts: Exts,
533 tag_vec: Vec<Tag>,
534 tag_counts: Vec<u32>,
535 sum: u32,
536 id_vec: Vec<ID>,
537 edge_mults: EdgeMult,
538 highest_quality: Option<BaseQuality>,
539}
540
541fn summarize_tags_ids<K: Kmer, F: Iterator<Item = KmerDataItem<K, IDTag>>>(items: F) -> IDTagSummary {
543 let mut all_exts = Exts::empty();
544 let mut tag_vec = Vec::with_capacity(items.size_hint().0);
545 let mut id_vec = Vec::new();
546 let mut edge_mults = EdgeMult::new();
547 let mut highest_quality = None;
548
549 let mut nobs = 0;
550 for item in items {
551 tag_vec.push(item.data.tag);
552 id_vec.push(item.data.id);
553 all_exts = all_exts.add(item.exts);
554 edge_mults.add_exts(item.exts);
555 nobs += 1;
556
557 if let Some(q) = item.quality {
558 if let Some(hq) = highest_quality {
559 if q > hq { highest_quality = Some(q) }
560 } else {
561 highest_quality = Some(q)
562 }
563 }
564 }
565
566 tag_vec.sort();
567 id_vec.sort();
568
569 let tag_counts = tag_counter(&tag_vec);
570
571 tag_vec.dedup();
572 id_vec.dedup();
573 id_vec.shrink_to_fit();
574
575 IDTagSummary {all_exts, tag_vec, tag_counts, sum: nobs, id_vec, edge_mults, highest_quality}
576}
577
578fn summarize_tags_ids_edge_q<K: Kmer, F: Iterator<Item = KmerDataItem<K, IDTag>>>(items: F, config: &SummaryConfig)
579-> IDTagSummary
580{
581 let items_filtered = items.filter(|item|
583 match item.quality {
584 None => true,
585 Some(q) => q >= config.min_quality_for_edge
586 }
587 );
588
589 summarize_tags_ids(items_filtered)
590}
591
592pub fn round_digits(number: u32, digits: u32) -> u32 {
595 let length = (number as f32).log10() as u32 + 1;
596 if digits > length { return number }
597 let empty = length - digits;
598 ((number as f32/ 10i32.pow(empty) as f32).round() * 10i32.pow(empty) as f32) as u32
599}
600
601fn valid_counts(tags: Tags, nobs: Option<u32>, config: &SummaryConfig) -> bool {
603 let nobs_valid = match nobs {
604 Some(n) => n as usize >= config.min_kmer_obs,
605 None => true
606 };
607
608 match config.group_frac {
609 GroupFrac::None => nobs_valid,
610 GroupFrac::Both => {
611 let dist0= tags.bit_and_dist(config.sample_info.marker0);
613 let dist1= tags.bit_and_dist(config.sample_info.marker1);
614
615 assert_eq!(dist0 + dist1, tags.to_tag_vec().len());
616
617 nobs_valid
621 && (dist0 as f32 / config.sample_info.count0 as f32 >= config.frac_cutoff)
622 && (dist1 as f32 / config.sample_info.count1 as f32 >= config.frac_cutoff)
623 },
624 GroupFrac::One => {
625 let dist0= tags.bit_and_dist(config.sample_info.marker0);
627 let dist1= tags.bit_and_dist(config.sample_info.marker1);
628
629
630 assert_eq!(dist0 + dist1, tags.to_tag_vec().len());
631
632 nobs_valid
636 && ((dist0 as f32 / config.sample_info.count0 as f32 >= config.frac_cutoff)
637 | (dist1 as f32 / config.sample_info.count1 as f32 >= config.frac_cutoff))
638 }
639 }
640}
641
642enum PInfo<'a> {
643 PValue { p: f32 },
644 Calculate { tag_vec: &'a [Tag], tag_counts: &'a Vec<u32> }
645}
646
647fn valid_p(p_info: PInfo, config: &SummaryConfig) -> bool {
648 match config.max_p {
649 Some(max_p) => {
650 match p_info {
651 PInfo::PValue { p } => p <= max_p,
652 PInfo::Calculate { tag_vec, tag_counts } => {
653 match p_value(tag_vec, tag_counts, config) {
654 Ok(p) => p <= max_p,
655 Err(_) => true
656 }
657 }
658 }
659 },
660 None => true
661 }
662}
663
664fn p_value(tag_vec: &[Tag], tag_counts: &[u32], config: &SummaryConfig) -> Result<f32, NotEnoughSamplesError> {
665 match config.stat_test {
666 StatTest::StudentsTTest => students_t_test(tag_vec, tag_counts, &config.sample_info),
667 StatTest::WelchsTTest => welchs_t_test(tag_vec, tag_counts, &config.sample_info),
668 StatTest::UTest => u_test(tag_vec, tag_counts, &config.sample_info),
669 }
670}
671
672fn students_t_test(tag_vec: &[Tag], tag_counts: &[u32], sample_info: &SampleInfo) -> Result<f32, NotEnoughSamplesError> {
674 let n0 = sample_info.count0 as f64;
675 let n1 = sample_info.count1 as f64;
676
677 if (n0 < 2.) | (n1 < 2.) { return Err(NotEnoughSamplesError {})}
678
679 let mut counts_g0 = Vec::new();
680 let mut counts_g1 = Vec::new();
681
682 let (m0, m1) = sample_info.get_markers();
683
684 for (label, count) in tag_vec.iter().zip(tag_counts) {
685 let bin_rep = (2 as Marker).pow(*label as u32);
686 let norm = *count as f64 / sample_info.sample_kmers[*label as usize] as f64;
687 if (m0 & bin_rep) > 0 { counts_g0.push(norm); }
688 if (m1 & bin_rep) > 0 { counts_g1.push(norm); }
689 }
690
691 let mean0 = counts_g0.iter().sum::<f64>() / n0;
692 let mean1 = counts_g1.iter().sum::<f64>() / n1;
693
694 let df = n0 + n1 - 2.;
695
696 let var0 = (counts_g0.iter().map(|count| (*count - mean0).powi(2)).sum::<f64>() + (n0 - counts_g0.len() as f64) * mean0.powi(2)) / (n0 - 1.);
697 let var1 = (counts_g1.iter().map(|count| (*count - mean1).powi(2)).sum::<f64>() + (n1 - counts_g1.len() as f64) * mean1.powi(2)) / (n1 - 1.);
698
699 let s = ((1./n0 + 1./n1) * ((n0 - 1.) * var0 + (n1 - 1.) * var1) / df).sqrt();
700
701 let t = (mean0 - mean1) / s;
702
703 let t_dist = StudentsT::new(0.0, 1.0, df).expect("error creating student dist: check if you have enough samples (at least 3)");
704
705 let p_value = 2. * (1. - t_dist.cdf(t.abs())) as f32;
706
707 Ok(p_value)
708}
709
710fn welchs_t_test(tag_vec: &[Tag], tag_counts: &[u32], sample_info: &SampleInfo) -> Result<f32, NotEnoughSamplesError> {
712 let n0 = sample_info.count0 as f64;
713 let n1 = sample_info.count1 as f64;
714
715 if (n0 < 2.) | (n1 < 2.) { return Err(NotEnoughSamplesError {})}
716
717 let mut counts_g0 = Vec::new();
718 let mut counts_g1 = Vec::new();
719
720 let (m0, m1) = sample_info.get_markers();
721
722 for (label, count) in tag_vec.iter().zip(tag_counts) {
723 let bin_rep = (2 as Marker).pow(*label as u32);
724 let norm = *count as f64 / sample_info.sample_kmers[*label as usize] as f64;
725 if (m0 & bin_rep) > 0 { counts_g0.push(norm); }
726 if (m1 & bin_rep) > 0 { counts_g1.push(norm); }
727 }
728
729 let mean0 = counts_g0.iter().sum::<f64>() / n0;
730 let mean1 = counts_g1.iter().sum::<f64>() / n1;
731
732 let s0 = (counts_g0.iter().map(|count| (*count - mean0).powi(2)).sum::<f64>() + (n0 - counts_g0.len() as f64) * mean0.powi(2)) / (n0 - 1.);
733 let s1 = (counts_g1.iter().map(|count| (*count - mean1).powi(2)).sum::<f64>() + (n1 - counts_g1.len() as f64) * mean1.powi(2)) / (n1 - 1.);
734
735 let s0 = s0.sqrt();
736 let s1 = s1.sqrt();
737
738 let t = (mean0 - mean1) / (s0.powi(2)/n0 + s1.powi(2)/n1).sqrt();
739
740 let df0 = n0 - 1.;
741 let df1 = n1 - 1.;
742
743 let df = ((s0.powi(2) / n0 + s1.powi(2) / n1).powi(2) /
744 (s0.powi(4) / (n0.powi(2) * df0)
745 + s1.powi(4) / (n1.powi(2) * df1))).floor();
746
747 let t_dist = StudentsT::new(0.0, 1.0, df).expect("error creating student dist: check if you have enough samples");
748
749 let p_value = 2. * (1. - t_dist.cdf(t.abs())) as f32;
750
751 Ok(p_value)
752}
753
754fn u_test(tag_vec: &[Tag], tag_counts: &[u32], sample_info: &SampleInfo) -> Result<f32, NotEnoughSamplesError> {
756
757 let n0 = sample_info.count0 as f64;
758 let n1 = sample_info.count1 as f64;
759
760 if (n0 < 2.) | (n1 < 2.) { return Err(NotEnoughSamplesError {})}
761
762
763 let mut counts_g0 = Vec::new();
764 let mut counts_g1 = Vec::new();
765
766 let (m0, m1) = sample_info.get_markers();
767
768 for (label, count) in tag_vec.iter().zip(tag_counts) {
769 let bin_rep = (2 as Marker).pow(*label as u32);
770 let norm = *count as f64 / sample_info.sample_kmers[*label as usize] as f64;
771 if (m0 & bin_rep) > 0 { counts_g0.push(norm); }
772 if (m1 & bin_rep) > 0 { counts_g1.push(norm); }
773 }
774
775 let n = n0 + n1;
776 let m = (n0 * n1) / 2.;
777
778 let mut all_counts = vec![(0u8, 0f64); n0 as usize - counts_g0.len()];
781 all_counts.append(&mut vec![(1, 0f64); n1 as usize - counts_g1.len()]);
782
783 all_counts.append(&mut counts_g0.iter().map(|elt| (0, *elt)).collect());
784 all_counts.append(&mut counts_g1.iter().map(|elt| (1, *elt)).collect());
785
786 all_counts.sort_by(|(_, x), (_, y)| x.total_cmp(y));
787
788 let chunked = all_counts
789 .chunk_by(|(_, x), (_, y)| x == y);
790
791 let mut ranks = Vec::new();
792 let mut tie_factor = 0.;
793
794 for chunk in chunked {
795 let rank = (chunk.len() + 1) as f64 / 2. + ranks.len() as f64;
796 ranks.append(&mut chunk.iter().map(|(g, _)| (*g, rank)).collect());
797 if !chunk.is_empty() {
798 tie_factor += (chunk.len().pow(3) - chunk.len()) as f64;
799 }
800 }
801
802 let mut rank_sum0 = 0.;
803 let mut rank_sum1 = 0.;
804 ranks.iter().for_each(|(group, rank)| match group {
805 0 => rank_sum0 += rank,
806 1 => rank_sum1 += rank,
807 _ => panic!("should not happen"),
808 });
809
810 let u0 = rank_sum0 - n0 * (n0 + 1.) / 2.;
811 let u1 = rank_sum1 - n1 * (n1 + 1.) / 2.;
812
813 let u = min_by(u0, u1, |a, b| a.total_cmp(b));
814
815 let s = ((n0 * n1 * (n + 1.) / 12.) - (n0 * n1 * tie_factor / (12. * n * (n - 1.)))).sqrt();
816 let z = (u - m) / s;
820
821 let dist = Normal::standard();
822 let p_value = 2. * (1. - dist.cdf(z.abs())) as f32;
823
824 Ok(p_value)
825}
826
827fn log2_fold_change(tags: Tags, counts: &[u32], sample_info: &SampleInfo) -> f32 {
829 let mut norm_count_g0 = 0.;
830 let mut norm_count_g1 = 0.;
831
832 let (m0, m1) = sample_info.get_markers();
833
834 for (label, count) in tags.to_tag_vec().iter().zip(counts) {
835 let bin_rep = (2 as Marker).pow(*label as u32);
836 let norm = *count as f64 / sample_info.sample_kmers[*label as usize] as f64;
838 if (m0 & bin_rep) > 0 { norm_count_g0 += norm; }
839 if (m1 & bin_rep) > 0 { norm_count_g1 += norm; }
840 }
841
842 norm_count_g0 /= sample_info.count0 as f64;
844 norm_count_g1 /= sample_info.count1 as f64;
845
846 (norm_count_g0 / norm_count_g1).log2() as f32
847}
848pub trait SummaryData<DI>: Clone + Debug + Send + Sync + PartialEq + Serialize + DeserializeOwned {
850 fn print(&self, translator: &Translator, config: &SummaryConfig, id_group_translator: Option<&HashMap<ID, ID>>) -> String;
852 fn print_ol(&self, translator: &Translator, config: &SummaryConfig, id_group_translator: Option<&HashMap<ID, ID>>) -> String;
854 fn print_json(&self, translator: &Translator, config: &SummaryConfig, id_group_translator: Option<&HashMap<ID, ID>>) -> String;
856 fn tags(&self) -> Option<Tags> { None }
858 fn mem(&self) -> usize;
860 fn sum(&self) -> Option<u32> { None }
862 fn ids(&self) -> Option<&[ID]> { None }
864 fn p_value(&self, _config: &SummaryConfig) -> Option<f32> { None }
866 fn fold_change(&self, _config: &SummaryConfig) -> Option<f32> { None }
868 fn sample_count(&self) -> Option<usize> { None }
870 fn edge_mults(&self) -> Option<&EdgeMult> { None }
872 fn quality(&self) -> Option<BaseQuality> { None }
874 fn fix_edge_data(&mut self, _exts: Exts) { }
876 fn set_edge_mults(&mut self, _edge_mults: Option<EdgeMult>) { }
878 fn mapped_ids(&self) -> Option<&[ID]> { None }
880 fn set_mapped_ids(&mut self, _mapped_ids: Box<[ID]>) { }
882 fn mapped_edge_ids(&self) -> Option<&EdgeMap> { None }
884 fn set_mapped_edge_ids(&mut self, _mapped_edge_ids: Option<EdgeMap>) { }
886 fn join_test(&self, other: &Self) -> bool { self == other }
888 fn valid(&self, _config: &SummaryConfig) -> bool { true }
890 fn summarize<K: Kmer, F: Iterator<Item = KmerDataItem<K, DI>>>(items: F, config: &SummaryConfig) -> (bool, Exts, Self);
892 fn summarizer() -> Summarizers;
894}
895impl SummaryData<Tag> for u32 {
899 fn print(&self, _: &Translator, _: &SummaryConfig, _: Option<&HashMap<ID, ID>>) -> String {
900 format!("sum: {}", self)
901 }
902
903 fn print_ol(&self, _: &Translator, _: &SummaryConfig, _: Option<&HashMap<ID, ID>>) -> String {
904 format!("sum: {}", self)
905 }
906
907 fn print_json(&self, _: &Translator, _: &SummaryConfig, _: Option<&HashMap<ID, ID>>) -> String {
908 format!("\"sum\": {}", self)
909 }
910
911 fn mem(&self) -> usize {
912 mem::size_of::<Self>()
913 }
914
915 fn sum(&self) -> Option<u32> {
916 Some(*self)
917 }
918
919 fn valid(&self, config: &SummaryConfig) -> bool {
920 *self >= config.min_kmer_obs as u32
921 }
922
923 fn summarize<K: Kmer, F: Iterator<Item = KmerDataItem<K, Tag>>>(items: F, config: &SummaryConfig) -> (bool, Exts, Self) {
924 let summary = summarize_tags_edge_q(items, config);
925
926 let valid_p = valid_p(PInfo::Calculate { tag_vec: &summary.tag_vec, tag_counts: &summary.tag_counts}, config);
927 let valid_q = if let Some(q) = summary.highest_quality { q >= config.min_quality } else {true };
928
929 let tags = Tags::from_tag_vec(&summary.tag_vec);
930
931 let valid = valid_counts(tags, Some(summary.sum), config) && valid_p && valid_q;
932
933 let sum = match config.significant {
934 Some(digits) => round_digits(summary.sum, digits),
935 None => summary.sum
936 };
937
938 (valid, summary.all_exts, sum)
939 }
940
941 fn summarizer() -> Summarizers {
942 Summarizers::Sum
943 }
944}
945
946#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
950pub struct TagVecData {
952 tag_vec: Vec<Tag>,
953}
954
955#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
958pub struct IDData {
960 ids: Box<[ID]>,
961}
962
963#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
966pub struct IDSumData {
968 ids: Box<[ID]>,
969 sum: u32,
970}
971
972#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
974pub struct TagsData {
975 tags: Tags,
976}
977
978#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
980pub struct TagsSumData {
982 tags: Tags,
983 sum: u32,
984}
985
986#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
991pub struct TagsCountsSumData {
992 tags: Tags,
993 sum: u32,
994 counts: Box<[u32]>,
995}
996
997#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
1002pub struct TagsCountsData {
1003 tags: Tags,
1004 counts: Box<[u32]>
1005}
1006
1007impl TagsCountsData {
1008 #[inline]
1009 pub fn sum(&self) -> u32 {
1010 self.counts.iter().sum::<u32>()
1011 }
1012}
1013
1014#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
1019pub struct TagsCountsPData {
1020 tags: Tags,
1021 counts: Box<[u32]>,
1022 p_value: f32
1023}
1024
1025impl TagsCountsPData {
1026 #[inline]
1027 pub fn sum(&self) -> u32 {
1028 self.counts.iter().sum::<u32>()
1029 }
1030}
1031
1032#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
1037pub struct TagsCountsEMData {
1038 tags: Tags,
1039 counts: Box<[u32]>,
1040 edge_mults: EdgeMult,
1041}
1042
1043impl TagsCountsEMData {
1044 #[inline]
1045 pub fn sum(&self) -> u32 {
1046 self.counts.iter().sum::<u32>()
1047 }
1048}
1049
1050#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
1055pub struct TagsCountsPEMData {
1056 tags: Tags,
1057 counts: Box<[u32]>,
1058 p_value: f32,
1059 edge_mults: EdgeMult,
1060}
1061
1062impl TagsCountsPEMData {
1063 #[inline]
1064 pub fn sum(&self) -> u32 {
1065 self.counts.iter().sum::<u32>()
1066 }
1067}
1068
1069#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
1074pub struct TagsCountsPEMQualityData {
1075 tags: Tags,
1076 counts: Box<[u32]>,
1077 p_value: f32,
1078 quality: BaseQuality,
1079 edge_mults: EdgeMult,
1080}
1081
1082impl TagsCountsPEMQualityData {
1083 #[inline]
1084 pub fn sum(&self) -> u32 {
1085 self.counts.iter().sum::<u32>()
1086 }
1087}
1088
1089#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
1094pub struct IDTagsCountsData {
1095 ids: Box<[ID]>,
1096 tags: Tags,
1097 counts: Box<[u32]>
1098}
1099
1100impl IDTagsCountsData {
1101 #[inline]
1102 pub fn sum(&self) -> u32 {
1103 self.counts.iter().sum::<u32>()
1104 }
1105}
1106
1107#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
1112pub struct IDTagsCountsPEMData {
1113 tags: Tags,
1114 counts: Box<[u32]>,
1115 ids: Box<[ID]>,
1116 p_value: f32,
1117 edge_mults: EdgeMult,
1118}
1119
1120impl IDTagsCountsPEMData {
1121 #[inline]
1122 pub fn sum(&self) -> u32 {
1123 self.counts.iter().sum::<u32>()
1124 }
1125}
1126
1127#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
1131pub struct IDEMData {
1132 ids: Box<[ID]>,
1133 edge_mults: EdgeMult,
1134}
1135
1136#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
1140pub struct IDMapEMData {
1141 ids: Box<[ID]>,
1142 map_ids: Box<[ID]>,
1143 edge_mults: EdgeMult,
1144}
1145
1146#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
1150pub struct IDMapEMQualityData {
1151 ids: Box<[ID]>,
1152 map_ids: Box<[ID]>,
1153 quality: BaseQuality,
1154 edge_mults: EdgeMult,
1155
1156}
1157
1158#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
1162pub struct SumMapEMQualityData {
1163 sum: u32,
1164 map_ids: Box<[ID]>,
1165 quality: BaseQuality,
1166 edge_mults: EdgeMult,
1167}
1168
1169#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
1173pub struct MapEMEmapQualityData {
1174 map_ids: Box<[ID]>,
1175 edge_mults: EdgeMult,
1176 edge_maps: EdgeMap,
1177 quality: BaseQuality,
1178}
1179
1180#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
1184pub struct GroupCountData {
1185 group1: u32,
1186 group2: u32,
1187}
1188
1189impl GroupCountData {
1190 #[inline(always)]
1191 fn sum(&self) -> u32 {
1192 self.group1 + self.group2
1193 }
1194}
1195
1196#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SummaryData)]
1201pub struct RelCountData {
1202 percent: u32,
1203 sum: u32
1204}
1205
1206#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
1207pub enum Summarizers {
1208 Sum,
1209 TagVecData,
1210 IDData,
1211 IDSumData,
1212 TagsData,
1213 TagsSumData,
1214 TagsCountsData,
1215 TagsCountsSumData,
1216 TagsCountsPData,
1217 TagsCountsEMData,
1218 TagsCountsPEMData,
1219 TagsCountsPEMQualityData,
1220 IDTagsCountsData,
1221 IDTagsCountsPEMData,
1222 IDEMData,
1223 IDMapEMData,
1224 IDMapEMQualityData,
1225 SumMapEMQualityData,
1226 MapEMEmapQualityData,
1227 GroupCountData,
1228 RelCountData
1229}
1230
1231#[cfg(test)]
1232mod test {
1233
1234
1235 use bimap::BiMap;
1236 use crate::{Tags, clean_graph::CleanGraph, compression::{ CheckCompress, ScmapCompress, compress_graph, compress_kmers_with_hash}, dna_string::DnaString, filter::filter_kmers, graph::{BaseGraph, Node}, kmer::{Kmer8, Kmer16}, reads::{Reads, ReadsPaired}, summarizer::{self, ID, IDData, IDTag, NotEnoughSamplesError, SampleInfo, SummaryData, TagsData, Translator, id_format, p_value, students_t_test, u_test, valid_p, welchs_t_test}};
1237 use crate::Exts;
1238
1239 use super::{log2_fold_change, round_digits, SummaryConfig, TagsCountsSumData};
1240
1241 #[test]
1242 fn test_p_value() -> Result<(), NotEnoughSamplesError> {
1243
1244 let sample_kmers = vec![1; 12];
1250 let sample_info = SampleInfo::new(31, 4064, sample_kmers);
1251
1252 let summary_config_w = SummaryConfig::new(sample_info.clone()).with_stat_test(summarizer::StatTest::WelchsTTest);
1253 let summary_config_t = SummaryConfig::new(sample_info.clone()).with_stat_test(summarizer::StatTest::StudentsTTest);
1254 let summary_config_u = SummaryConfig::new(sample_info.clone()).with_stat_test(summarizer::StatTest::UTest);
1255
1256 let tag_vec = [0, 1, 2, 3, 4, 8];
1257 let tag_counts = vec![1; 6];
1258
1259 let p = welchs_t_test(&tag_vec, &tag_counts, &sample_info)?;
1260 assert_eq!((p * 1000.).round(), 1.);
1261 let p = students_t_test(&tag_vec, &tag_counts, &sample_info)?;
1262 assert_eq!((p * 10000.).round(), 5.);
1263 let p = u_test(&tag_vec, &tag_counts, &sample_info)?;
1264 assert_eq!((p * 1000.).round(), 5.);
1265
1266 let p: f32 = p_value(&tag_vec, &tag_counts, &summary_config_w)?;
1267 assert_eq!((p * 1000.).round(), 1.);
1268 let p = p_value(&tag_vec, &tag_counts, &summary_config_t)?;
1269 assert_eq!((p * 10000.).round(), 5.);
1270 let p = p_value(&tag_vec, &tag_counts, &summary_config_u)?;
1271 assert_eq!((p * 1000.).round(), 5.);
1272
1273
1274 let sample_kmers = vec![12, 3345, 3478, 87, 1, 2, 666, 98111, 23982938, 555, 122, 7238];
1276
1277 let sample_info = SampleInfo::new(31, 4064, sample_kmers);
1278 let summary_config_w = SummaryConfig::new(sample_info.clone()).with_stat_test(summarizer::StatTest::WelchsTTest);
1279 let summary_config_t = SummaryConfig::new(sample_info.clone()).with_stat_test(summarizer::StatTest::StudentsTTest);
1280 let summary_config_u = SummaryConfig::new(sample_info.clone()).with_stat_test(summarizer::StatTest::UTest);
1281
1282 let tag_vec = [0, 1, 7, 8, 9, 10];
1283 let tag_counts = vec![1; 6];
1284
1285 let p = welchs_t_test(&tag_vec, &tag_counts, &sample_info)?;
1286 assert_eq!((p * 10000.).round(), 4113.);
1287 let p = students_t_test(&tag_vec, &tag_counts, &sample_info)?;
1288 assert_eq!((p * 10000.).round(), 2955.);
1289 let p = u_test(&tag_vec, &tag_counts, &sample_info)?;
1290 assert_eq!((p * 1000.).round(), 862.);
1291
1292 let p: f32 = p_value(&tag_vec, &tag_counts, &summary_config_w)?;
1293 assert_eq!((p * 10000.).round(), 4113.);
1294 let p: f32 = p_value(&tag_vec, &tag_counts, &summary_config_t)?;
1295 assert_eq!((p * 10000.).round(), 2955.);
1296 let p: f32 = p_value(&tag_vec, &tag_counts, &summary_config_u)?;
1297 assert_eq!((p * 1000.).round(), 862.);
1298
1299
1300 let sample_kmers = vec![3, 3, 3];
1308 let sample_info = SampleInfo::new(0b100, 0b11, sample_kmers);
1309 let summary_config_w = SummaryConfig::new(sample_info.clone()).with_stat_test(summarizer::StatTest::WelchsTTest);
1310 let summary_config_t = SummaryConfig::new(sample_info.clone()).with_stat_test(summarizer::StatTest::StudentsTTest);
1311 let summary_config_u = SummaryConfig::new(sample_info.clone()).with_stat_test(summarizer::StatTest::UTest);
1312
1313 let tag_vec = [0, 1, 2];
1314 let tag_counts = vec![2, 3, 1];
1315
1316 if welchs_t_test(&tag_vec, &tag_counts, &sample_info).is_ok() { panic!("should throw err") }
1317 if students_t_test(&tag_vec, &tag_counts, &sample_info).is_ok() { panic!("should throw err") }
1318 if u_test(&tag_vec, &tag_counts, &sample_info).is_ok() { panic!("should throw err") }
1319
1320 if p_value(&tag_vec, &tag_counts, &summary_config_w).is_ok() { panic!("should throw err") }
1321 if p_value(&tag_vec, &tag_counts, &summary_config_t).is_ok() { panic!("should throw err") }
1322 if p_value(&tag_vec, &tag_counts, &summary_config_u).is_ok() { panic!("should throw err") }
1323
1324 Ok(())
1325 }
1326
1327 #[test]
1328 fn test_valid_p() {
1329 let sample_kmers = vec![1; 12];
1330 let sample_info = SampleInfo::new(31, 4064, sample_kmers);
1331 let summary_config_m = SummaryConfig::new(sample_info.clone()).with_max_p(None);
1332 let summary_config_p = SummaryConfig::new(sample_info.clone()).with_max_p(Some(0.05));
1333
1334 let tag_vec = [0, 1, 2, 3, 4, 8]; let tag_counts = vec![1; 6];
1336 let vp = valid_p(summarizer::PInfo::Calculate { tag_vec: &tag_vec, tag_counts: &tag_counts }, &summary_config_m);
1337 assert!(vp);
1338 let vp = valid_p(summarizer::PInfo::Calculate { tag_vec: &tag_vec, tag_counts: &tag_counts }, &summary_config_p);
1339 assert!(vp);
1340
1341
1342 let tag_vec = [0, 7, 8, 9, 10]; let tag_counts = vec![1; 5];
1344
1345 let vp = valid_p(summarizer::PInfo::Calculate { tag_vec: &tag_vec, tag_counts: &tag_counts }, &summary_config_m);
1346 assert!(vp);
1347 let vp = valid_p(summarizer::PInfo::Calculate { tag_vec: &tag_vec, tag_counts: &tag_counts }, &summary_config_p);
1348 assert!(!vp);
1349 }
1350
1351 #[test]
1352 #[cfg(not(feature = "sample128"))]
1353 fn test_data_valid() {
1354 use crate::{kmer::Kmer16, test::build_test_graph};
1355
1356 let mut graph: BaseGraph<Kmer8, TagsCountsSumData> = BaseGraph::new(false);
1357
1358 let tags = Tags::from_tag_vec(&vec![0, 2, 6]);
1359 let counts: Box<[u32]> = [1, 3, 5].into();
1360 let sum = counts.iter().sum::<u32>();
1361 graph.add(&DnaString::from_acgt_bytes("AAAAAAAA".as_bytes()), Exts::empty(), TagsCountsSumData { tags, counts, sum });
1362
1363 let tags = Tags::from_tag_vec(&vec![0]);
1364 let counts: Box<[u32]> = [1].into();
1365 let sum = counts.iter().sum::<u32>();
1366 graph.add(&DnaString::from_acgt_bytes("CCCCCCCC".as_bytes()), Exts::empty(), TagsCountsSumData { tags, counts, sum });
1367
1368
1369 let graph = graph.finish();
1370
1371 graph.print();
1372
1373 let sample_kmers = vec![123, 234, 12334, 34, 1232, 123, 123, 34];
1374 let sample_info = SampleInfo::new(0b00100101, 0b11011010, sample_kmers);
1375 let config = SummaryConfig::new(sample_info).with_stat_test(summarizer::StatTest::StudentsTTest);
1376
1377 let censor_nodes = CleanGraph::new(|node: &Node<'_, Kmer8, TagsCountsSumData>| !node.data().valid(&config))
1378 .find_bad_nodes(&graph);
1379 println!("censor nodes: {:?}", censor_nodes);
1380 let filter_graph = compress_graph(false, &ScmapCompress::new(), graph, Some(censor_nodes));
1381
1382 filter_graph.print();
1383
1384 let (_, _, ser_graph) = build_test_graph::<Kmer16, TagsCountsSumData, _>();
1387 let (graph, _translator, mut config) = ser_graph.dissolve();
1388
1389 config.set_min_kmer_obs(3);
1390
1391 let node3 = graph.get_node(3);
1392 assert!(!node3.data().valid(&config));
1393
1394 let bad_nodes = graph.find_bad_nodes(|node| node.data().valid(&config));
1395 let bad_node_correct = vec![3, 15, 20, 21, 23, 35, 36, 37, 40, 41, 46, 58, 61, 66, 67, 76, 77, 80, 89, 98, 99];
1396 assert_eq!(bad_nodes, bad_node_correct);
1397 let _filtered_graph = compress_graph(false, &ScmapCompress::new(), graph, Some(bad_nodes));
1398
1399 }
1400
1401 #[test]
1402 fn test_fold_change() {
1403 let marker0 = 0b0000000001111;
1404 let marker1 = 0b1111111110000;
1405 let sample_kmers = vec![2834, 2343, 12, 1234, 345345, 122, 234, 23455, 231, 2, 3564, 12344, 34555];
1406 let sample_info = SampleInfo::new(marker0, marker1, sample_kmers);
1407 let labels = vec![0, 1, 2, 3, 7, 8];
1410 let tags = Tags::from_tag_vec(&labels);
1411 let counts = vec![1, 6, 9, 3, 6, 10];
1412 let fold_change = log2_fold_change(tags, &counts, &sample_info);
1413 assert_eq!(fold_change, 5.286_453_2);
1414
1415 let labels = vec![0, 6, 7, 8, 10, 11];
1416 let tags = Tags::from_tag_vec(&labels);
1417 let counts = vec![12, 3, 7, 1, 22, 6];
1418 let fold_change = log2_fold_change(tags, &counts, &sample_info);
1419 assert_eq!(fold_change, -1.339_324_5);
1420
1421 let labels = vec![0, 1];
1423 let tags = Tags::from_tag_vec(&labels);
1424 let counts = vec![12, 3];
1425 let fold_change = log2_fold_change(tags, &counts, &sample_info);
1426 assert_eq!(fold_change, f32::INFINITY);
1427
1428 let labels = vec![7, 8];
1430 let tags = Tags::from_tag_vec(&labels);
1431 let counts = vec![12, 3];
1432 let fold_change = log2_fold_change(tags, &counts, &sample_info);
1433 assert_eq!(fold_change, f32::NEG_INFINITY);
1434 }
1435
1436 #[test]
1437 fn test_round_digits() {
1438 assert_eq!(round_digits(18293092, 4), 18290000);
1439 assert_eq!(round_digits(333, 4), 333);
1440 assert_eq!(round_digits(129552, 2), 130000);
1441 assert_eq!(round_digits(1829399, 6), 1829400);
1442 assert_eq!(round_digits(1829399, 0), 0);
1443 }
1444
1445
1446 #[test]
1447 fn test_id_format() {
1448 let id_translator = [("A", 0), ("B", 1), ("C", 2), ("D", 3), ("E", 4), ("F", 5), ("G", 6)].into_iter().map(|(a, b)| (a.to_string(), b as ID)).collect();
1449 let id_gr_tr = [(0 as ID, 0 as ID), (1, 0), (2, 0), (3, 0), (4, 1), (5, 1), (6, 1)].into_iter().collect();
1450
1451 let translator = Translator::new_id_translator(id_translator);
1452 let e_tr = Translator::new_tag_translator(BiMap::new());
1453
1454 assert_eq!("[\"A\", \"B\", \"C\"]", id_format(&[0, 1, 2], &translator, None));
1455 assert_eq!("[0, 1]", id_format(&[0, 1, 5], &translator, Some(&id_gr_tr)));
1456 assert_eq!("[0, 1, 2]", id_format(&[0, 1, 2], &e_tr, None));
1457 }
1458
1459 #[test]
1460 fn test_summary_config() {
1461 let sample_info = SampleInfo::new(0b11, 0b1100, vec![12, 12, 12, 12]);
1462 let config1 = SummaryConfig::new(sample_info.clone())
1463 .with_group_frac(summarizer::GroupFrac::One, 0.3)
1464 .with_max_p(Some(0.3))
1465 .with_min_kmer_obs(2)
1466 .with_min_quality(crate::BaseQuality::Marginal)
1467 .with_min_quality_for_edge(crate::BaseQuality::Medium)
1468 .with_significant(Some(4))
1469 .with_stat_test(summarizer::StatTest::StudentsTTest);
1470
1471 let config2 = SummaryConfig {
1472 min_kmer_obs: 2,
1473 significant: Some(4),
1474 group_frac: summarizer::GroupFrac::One,
1475 frac_cutoff: 0.3,
1476 sample_info,
1477 max_p: Some(0.3),
1478 stat_test: summarizer::StatTest::StudentsTTest,
1479 stat_test_changed: false,
1480 min_quality: crate::BaseQuality::Marginal,
1481 min_quality_for_edge: crate::BaseQuality::Medium
1482 };
1483
1484 assert_eq!(config1, config2)
1485 }
1486
1487 #[test]
1488 fn test_summarize_edge_q() {
1489 let read1 = "AGCTAGCGATGCTAGCTAGCATCGTAGCTAGCAAGCTGATCAAGTCGATGCTGACTGATGCTAGCTGACTGATCGATGCTAGCTGATC";
1490 let qual1 = "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC";
1491 let read2 = "GAAATCGTAGCTGAAAAATCGTAGCTGATCGTAGCTGATCTATTCTAGCTGATCAAGTCGATCGGAGGGGTTTCGGAGTTTCGGGATTCGTAT";
1492 let qual2 = "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC-CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC";
1493
1494 let mut reads = Reads::new_with_quality(crate::reads::Strandedness::Forward);
1508 reads.add_read(DnaString::from_acgt_bytes(read1.as_bytes()), None, 0, Some(qual1.as_bytes()));
1509 reads.add_read(DnaString::from_acgt_bytes(read2.as_bytes()), None, 1, Some(qual2.as_bytes()));
1510
1511 let reads_paired = ReadsPaired::Unpaired { reads };
1512
1513 let sample_info = SampleInfo::new(0b10, 0b01, vec![73, 78]);
1514 let summary_config = SummaryConfig::new(sample_info)
1515 .with_min_quality_for_edge(crate::BaseQuality::Medium);
1516
1517 let (kmers, _) = filter_kmers::<TagsData, Kmer16, _>(&reads_paired, &summary_config, false, 1., false);
1518
1519 let comp_spec = CheckCompress::new(|a: TagsData, _b| a, |a, b| a.join_test(b));
1520 let mut graph = compress_kmers_with_hash(true, &comp_spec, kmers, false, false).finish();
1521 graph.fix_exts(None);
1522
1523 for node_id in 0..graph.len() {
1524 let node = graph.get_node(node_id);
1525 println!{"seq: {:?}, node: {:?}", node.sequence(), node}
1526 }
1527
1528 let expected_components = [vec![0], vec![1], vec![2]];
1529
1530 for (i, component) in graph.iter_components().enumerate() {
1531 println!("{:?}", component);
1532 assert_eq!(component, expected_components[i]);
1533 }
1534
1535 let mut reads = Reads::new_with_quality(crate::reads::Strandedness::Forward);
1538 reads.add_read(DnaString::from_acgt_bytes(read1.as_bytes()), None, IDTag::new(0, 0), Some(qual1.as_bytes()));
1539 reads.add_read(DnaString::from_acgt_bytes(read2.as_bytes()), None, IDTag::new(1, 1), Some(qual2.as_bytes()));
1540
1541 let reads_paired = ReadsPaired::Unpaired { reads };
1542
1543 let (kmers, _) = filter_kmers::<IDData, Kmer16, _>(&reads_paired, &summary_config, false, 1., false);
1544
1545 let comp_spec = CheckCompress::new(|a: IDData, _b| a, |a, b| a.join_test(b));
1546 let mut graph = compress_kmers_with_hash(true, &comp_spec, kmers, false, false).finish();
1547 graph.fix_exts(None);
1548
1549 for node_id in 0..graph.len() {
1550 let node = graph.get_node(node_id);
1551 println!{"seq: {:?}, node: {:?}", node.sequence(), node}
1552 }
1553
1554 let expected_components = [vec![0], vec![1], vec![2]];
1555
1556 for (i, component) in graph.iter_components().enumerate() {
1557 println!("{:?}", component);
1558 assert_eq!(component, expected_components[i]);
1559 }
1560
1561 }
1562}