1#![allow(deprecated)]
2use{
3 crate::histogram::*,
4 num_traits::{
5 ops::{
6 checked::*,
7 wrapping::*
8 },
9 cast::*,
10 identities::*,
11 Bounded
12 },
13 std::{
14 borrow::*,
15 ops::*,
16 num::*
17 }
18};
19
20#[cfg(feature = "serde_support")]
21use serde::{Serialize, Deserialize};
22
23
24#[derive(Debug, Clone)]
30#[deprecated(since="0.2.0", note="Use GenericHist of BinningWithWidth instead")]
31#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
32pub struct HistogramInt<T>
33{
34 pub(crate) bin_borders: Vec<T>,
35 pub(crate) hist: Vec<usize>,
36}
37
38impl<T> HistogramInt<T>{
39 pub fn borders(&self) -> &Vec<T>
41 {
42 &self.bin_borders
43 }
44
45 pub fn bin_iter(& self) -> impl Iterator<Item = &[T;2]>
67 {
68 BorderWindow::new(self.bin_borders.as_slice())
69 }
70
71 pub fn bin_hits_iter(&self) -> impl Iterator<Item = (&[T;2], usize)>
111 {
112 self.bin_iter()
113 .zip(
114 self.hist
115 .iter()
116 .copied()
117 )
118 }
119
120}
121
122
123impl<T> HistogramInt<T>
124where T: Sub<T, Output=T> + Add<T, Output=T> + Ord + One + Copy + NumCast
125{
126 #[inline]
127 pub fn increment<V: Borrow<T>>(&mut self, val: V) -> Result<usize, HistErrors> {
134 self.count_val(val)
135 }
136
137 #[inline]
138 pub fn increment_quiet<V: Borrow<T>>(&mut self, val: V)
142 {
143 let _ = self.increment(val);
144 }
145}
146
147
148impl<T> HistogramInt<T>
149where T: Copy{
150 fn get_right(&self) -> T
151 {
152 self.bin_borders[self.bin_borders.len() - 1]
153 }
154}
155
156
157impl<T> HistogramInt<T>
158where T: PartialOrd + ToPrimitive + FromPrimitive + CheckedAdd + One + HasUnsignedVersion + Bounded
159 + Sub<T, Output=T> + Mul<T, Output=T> + Zero + Copy,
160 std::ops::RangeInclusive<T>: Iterator<Item=T>,
161 T::Unsigned: Bounded + HasUnsignedVersion<LeBytes=T::LeBytes, Unsigned=T::Unsigned>
162 + WrappingAdd + ToPrimitive + Sub<Output=T::Unsigned>
163 + std::ops::Rem<Output=T::Unsigned> + FromPrimitive + Zero
164 + std::cmp::Eq + std::ops::Div<Output=T::Unsigned>
165 + Ord + std::ops::Mul<Output=T::Unsigned> + WrappingSub + Copy,
166 std::ops::RangeInclusive<T::Unsigned>: Iterator<Item=T::Unsigned>
167{
168 pub fn new(left: T, right: T, bins: usize) -> Result<Self, HistErrors> {
176 if left >= right {
177 return Err(HistErrors::IntervalWidthZero);
178 } else if bins == 0 {
179 return Err(HistErrors::NoBins);
180 }
181 let left_u = to_u(left);
182 let right_u = to_u(right);
183 let border_difference = right_u - left_u;
184 let b = match T::Unsigned::from_usize(bins)
185 {
186 Some(val) => val,
187 None => return Err(HistErrors::IntervalWidthZero),
188 };
189 if border_difference % b != T::Unsigned::zero() {
190 return Err(HistErrors::ModuloError);
191 }
192
193 let bin_size = border_difference / b;
194
195 if bin_size <= T::Unsigned::zero() {
196 return Err(HistErrors::IntervalWidthZero);
197 }
198
199 let hist = vec![0; bins];
200 let bin_borders: Vec<_> = (T::Unsigned::zero()..=b)
201 .map(|val| {
202 from_u(
203 left_u + to_u(val) * bin_size
204 )
205 })
206 .collect();
207 Ok(
208 Self{
209 bin_borders,
210 hist
211 }
212 )
213 }
214 pub fn new_inclusive(left: T, right: T, bins: usize) -> Result<Self, HistErrors>
221 {
222 let right = match right.checked_add(&T::one()){
223 None => return Err(HistErrors::Overflow),
224 Some(val) => val,
225 };
226 Self::new(left, right, bins)
227 }
228}
229
230impl<T> Histogram for HistogramInt<T>
231{
232 #[inline]
233 fn bin_count(&self) -> usize {
234 self.hist.len()
235 }
236
237 #[inline]
238 fn hist(&self) -> &Vec<usize> {
239 &self.hist
240 }
241
242 #[inline]
243 fn increment_index_by(&mut self, index: usize, count: usize) -> Result<(), HistErrors> {
244 match self.hist.get_mut(index) {
245 None => Err(HistErrors::OutsideHist),
246 Some(val) => {
247 *val += count;
248 Ok(())
249 },
250 }
251 }
252
253 #[inline]
254 fn reset(&mut self) {
255 self.hist
257 .iter_mut()
258 .for_each(|h| *h = 0);
259 }
260}
261
262impl<T> HistogramVal<T> for HistogramInt<T>
263where T: Ord + Sub<T, Output=T> + Add<T, Output=T> + One + NumCast + Copy
264{
265 fn count_val<V: Borrow<T>>(&mut self, val: V) -> Result<usize, HistErrors>
266 {
267 let id = self.get_bin_index(val)?;
268 self.increment_index(id)
269 .map(|_| id)
270 }
271
272 fn distance<V: Borrow<T>>(&self, val: V) -> f64 {
273 let val = val.borrow();
274 if self.not_inside(val) {
275 let dist = if *val < self.first_border() {
276 self.first_border() - *val
277 } else {
278 *val - self.get_right() + T::one()
279 };
280 dist.to_f64().unwrap()
281 } else {
282 0.0
283 }
284 }
285
286 #[inline]
287 fn first_border(&self) -> T {
288 self.bin_borders[0]
289 }
290
291 fn last_border(&self) -> T {
292 self.bin_borders[self.bin_borders.len() - 1]
293 }
294
295 #[inline(always)]
296 fn last_border_is_inclusive(&self) -> bool {
297 false
298 }
299
300 #[inline]
301 fn is_inside<V: Borrow<T>>(&self, val: V) -> bool {
302 let val = *val.borrow();
303 val >= self.first_border()
304 && val < self.get_right()
305 }
306
307 #[inline]
308 fn not_inside<V: Borrow<T>>(&self, val: V) -> bool {
309 let val = *val.borrow();
310 val < self.first_border()
311 || val >= self.get_right()
312 }
313
314 fn get_bin_index<V: Borrow<T>>(&self, val: V) -> Result<usize, HistErrors>
316 {
317 let val = val.borrow();
318 if self.not_inside(val)
319 {
320 return Err(HistErrors::OutsideHist);
321 }
322
323 self.bin_borders
324 .binary_search(val.borrow())
325 .or_else(|index_m1| Ok(index_m1 - 1))
326 }
327
328 fn bin_enum_iter(&'_ self) -> Box<dyn Iterator<Item=Bin<T>> + '_> {
333 let iter = self.bin_iter()
334 .map(|[left, right]| Bin::InclusiveExclusive(*left, *right));
335 Box::new(iter)
336 }
337}
338
339impl<T> HistogramIntervalDistance<T> for HistogramInt<T>
340where T: Ord + Sub<T, Output=T> + Add<T, Output=T> + One + NumCast + Copy
341{
342 fn interval_distance_overlap<V: Borrow<T>>(&self, val: V, overlap: NonZeroUsize) -> usize {
343 let val = val.borrow();
344 if self.not_inside(val) {
345 let num_bins_overlap = 1usize.max(self.bin_count() / overlap.get());
346 let dist =
347 if *val < self.first_border() {
348 self.first_border() - *val
349 } else {
350 *val - self.get_right()
351 };
352 1 + dist.to_usize().unwrap() / num_bins_overlap
353 } else {
354 0
355 }
356 }
357}
358
359impl<T> HistogramPartition for HistogramInt<T>
360where T: Clone + std::fmt::Debug
361{
362 fn overlapping_partition(&self, n: NonZeroUsize, overlap: usize) -> Result<Vec<Self>, HistErrors>
363 {
364 let mut result = Vec::with_capacity(n.get());
365 let size = self.bin_count() - 1;
366 let denominator = n.get() + overlap;
367
368 for c in 0..n.get() {
369 let left_index = c.checked_mul(size)
370 .ok_or(HistErrors::Overflow)?
371 / denominator;
372
373 let zaehler = c + overlap + 1;
374 let right_index = 1 + zaehler.checked_mul(size)
375 .ok_or(HistErrors::Overflow)?
376 / denominator;
377
378 if left_index >= right_index {
379 return Err(HistErrors::IntervalWidthZero);
380 }
381
382 let borders = self
383 .borders()[left_index..=right_index]
384 .to_vec();
385 let hist = vec![0; borders.len() - 1];
386
387 let res = Self{
388 bin_borders: borders,
389 hist
390 };
391
392 result.push(res);
393 }
394 Ok(result)
395 }
396}
397
398impl<T> IntervalOrder for HistogramInt<T>
399where T: Ord
400{
401 fn left_compare(&self, other: &Self) -> std::cmp::Ordering {
402 let self_left = &self.bin_borders[0];
403 let other_left = &other.bin_borders[0];
404 let order = self_left.cmp(other_left);
405 if order.is_eq() {
406 let self_right = self.bin_borders.last().unwrap();
407 let other_right = other.bin_borders.last().unwrap();
408 return self_right.cmp(other_right);
409 }
410 order
411 }
412}
413
414
415#[deprecated(since="0.2.0", note="Use GenericHist of BinningUSIZE instead")]
421pub type HistUsize = HistogramInt<usize>;
422#[deprecated(since="0.2.0", note="Use GenericHist of BinningU128 instead")]
428pub type HistU128 = HistogramInt<u128>;
429#[deprecated(since="0.2.0", note="Use GenericHist of BinningU64 instead")]
435pub type HistU64 = HistogramInt<u64>;
436#[deprecated(since="0.2.0", note="Use GenericHist of BinningU32 instead")]
442pub type HistU32 = HistogramInt<u32>;
443#[deprecated(since="0.2.0", note="Use GenericHist of BinningU16 instead")]
449pub type HistU16 = HistogramInt<u16>;
450#[deprecated(since="0.2.0", note="Use GenericHist of BinningU8 instead")]
456pub type HistU8 = HistogramInt<u8>;
457
458#[deprecated(since="0.2.0", note="Use GenericHist of BinningISIZE instead")]
464pub type HistIsize = HistogramInt<isize>;
465#[deprecated(since="0.2.0", note="Use GenericHist of BinningI128 instead")]
471pub type HistI128 = HistogramInt<i128>;
472#[deprecated(since="0.2.0", note="Use GenericHist of BinningI64 instead")]
478pub type HistI64 = HistogramInt<i64>;
479#[deprecated(since="0.2.0", note="Use GenericHist of BinningI32 instead")]
485pub type HistI32 = HistogramInt<i32>;
486#[deprecated(since="0.2.0", note="Use GenericHist of BinningI16 instead")]
492pub type HistI16 = HistogramInt<i16>;
493#[deprecated(since="0.2.0", note="Use GenericHist of BinningI8 instead")]
499pub type HistI8 = HistogramInt<i8>;
500
501#[cfg(test)]
502mod tests{
503 use super::*;
504 use rand::{SeedableRng, distributions::*};
505 use rand_pcg::Pcg64Mcg;
506 use num_traits::Bounded;
507 fn hist_test_normal<T>(left: T, right: T)
508 where T: num_traits::Bounded + PartialOrd + CheckedSub
509 + CheckedAdd + Zero + Ord + HasUnsignedVersion
510 + One + NumCast + Copy + FromPrimitive + Bounded,
511 std::ops::RangeInclusive<T>: Iterator<Item=T>,
512 T::Unsigned: Bounded + HasUnsignedVersion<LeBytes=T::LeBytes, Unsigned=T::Unsigned>
513 + WrappingAdd + ToPrimitive + Sub<Output=T::Unsigned>
514 + std::ops::Rem<Output=T::Unsigned> + FromPrimitive + Zero
515 + std::cmp::Eq + std::ops::Div<Output=T::Unsigned>
516 + Ord + std::ops::Mul<Output=T::Unsigned> + WrappingSub + Copy,
517 std::ops::RangeInclusive<T::Unsigned>: Iterator<Item=T::Unsigned>,
518 HistogramInt::<T>: std::fmt::Debug,
519 {
520 let bin_count = (to_u(right) - to_u(left)).to_usize().unwrap() + 1;
521 let hist_wrapped = HistogramInt::<T>::new_inclusive(left, right, bin_count);
522
523 let mut hist = hist_wrapped.unwrap();
524 assert!(hist.not_inside(T::max_value()));
525 assert!(hist.not_inside(T::min_value()));
526 for (id, i) in (left..=right).enumerate() {
527 assert!(hist.is_inside(i));
528 assert_eq!(hist.is_inside(i), !hist.not_inside(i));
529 assert!(hist.get_bin_index(i).unwrap() == id);
530 assert_eq!(hist.distance(i), 0.0);
531 assert_eq!(hist.interval_distance_overlap(i, unsafe{NonZeroUsize::new_unchecked(2)}), 0);
532 hist.count_val(i).unwrap();
533 }
534 let lm1 = left - T::one();
535 let rp1 = right + T::one();
536 assert!(hist.not_inside(lm1));
537 assert!(hist.not_inside(rp1));
538 assert_eq!(hist.is_inside(lm1), !hist.not_inside(lm1));
539 assert_eq!(hist.is_inside(rp1), !hist.not_inside(rp1));
540 assert_eq!(hist.distance(lm1), 1.0);
541 assert_eq!(hist.distance(rp1), 1.0);
542 let one = unsafe{NonZeroUsize::new_unchecked(1)};
543 assert_eq!(hist.interval_distance_overlap(rp1, one), 1);
544 assert_eq!(hist.interval_distance_overlap(lm1, one), 1);
545 let borders: Vec<_> = hist.bin_enum_iter()
546 .map(
547 |bin|
548 {
549 match bin {
550 Bin::InclusiveExclusive(left, right) => (left, right),
551 _ => unreachable!()
552 }
553 }
554 ).collect();
555 assert_eq!(borders.len(), hist.bin_count());
556 assert_eq!(
557 HistogramInt::<T>::new_inclusive(left, T::max_value(), bin_count).expect_err("err"),
558 HistErrors::Overflow
559 );
560 }
561
562
563 #[test]
564 fn hist_normal()
565 {
566 hist_test_normal(20usize, 31usize);
567 hist_test_normal(-23isize, 31isize);
568 hist_test_normal(-23i16, 31);
569 hist_test_normal(1u8, 3u8);
570 hist_test_normal(123u128, 300u128);
571 hist_test_normal(-123i128, 300i128);
572
573 hist_test_normal(i8::MIN + 1, i8::MAX - 1);
574 }
575
576 #[test]
577 fn hist_index(){
578 let hist = HistogramInt::<isize>::new(0, 20, 2).unwrap();
579 assert_eq!(hist.borders(), &[0_isize, 10, 20]);
580 for i in 0..=9
581 {
582 assert_eq!(hist.get_bin_index(i).unwrap(), 0);
583 }
584 for i in 10..20 {
585 assert_eq!(hist.get_bin_index(i).unwrap(), 1);
586 }
587 assert!(hist.get_bin_index(20).is_err());
588 }
589
590 #[allow(deprecated)]
593 #[test]
594 fn overlapping_partition_test()
595 {
596
597 let mut rng = Pcg64Mcg::seed_from_u64(2314668);
598 let uni = Uniform::new_inclusive(-100, 100);
599 let uni_n = Uniform::new_inclusive(1, 16);
600
601 for overlap in 0..=5 {
602 for _ in 0..100 {
603 let n: usize = uni_n.sample(&mut rng);
604 let (left, right) = loop {
605 let mut num_1 = uni.sample(&mut rng);
606 let mut num_2 = uni.sample(&mut rng);
607
608 if num_1 != num_2 {
609 if num_2 < num_1 {
610 std::mem::swap(&mut num_1, &mut num_2);
611 }
612 if (num_2 as isize - num_1 as isize) < (overlap as isize + 1) {
613 continue;
614 }
615 break (num_1, num_2)
616 }
617 };
618
619 let hist_fast = HistI8Fast::new_inclusive(left, right).unwrap();
620 let hist_i = HistI8::new_inclusive(left, right, hist_fast.bin_count()).unwrap();
621 let n_non_zero = NonZeroUsize::new(n).unwrap();
622
623 let overlapping_f = hist_fast.overlapping_partition(n_non_zero, overlap);
624 let overlapping_i = hist_i.overlapping_partition(n_non_zero, overlap);
625
626 if overlapping_i.is_err() {
627 assert_eq!(overlapping_f.unwrap_err(), overlapping_i.unwrap_err());
628 continue;
629 }
630
631 let overlapping_i = overlapping_i.unwrap();
632 let overlapping_f = overlapping_f.unwrap();
633
634 let len = overlapping_i.len();
635
636 for (index,(a, b)) in overlapping_f
637 .into_iter()
638 .zip(overlapping_i)
639 .enumerate()
640 {
641 let bins_a: Vec<_> = a
642 .bin_enum_iter()
643 .map(
644 |bin|
645 {
646 match bin{
647 Bin::SingleValued(val) => val,
648 _ => unreachable!()
649 }
650 }
651 ).collect();
652
653 assert_eq!(bins_a.len(), a.hist().len());
654
655 let bins_b: Vec<_> = b
656 .bin_enum_iter()
657 .map(
658 |bin|
659 {
660 match bin{
661 Bin::InclusiveExclusive(left, right) => (left, right),
662 _ => unreachable!()
663 }
664 }
665 ).collect();
666
667 assert_eq!(bins_b.len(), b.hist().len());
668
669 if bins_a.len() != bins_b.len()
670 {
671 println!("Fast: {} SLOW {}", a.bin_count(), b.bin_count());
672 dbg!(left, right, overlap);
673 dbg!(hist_i.bin_count(), hist_fast.bin_count());
674 dbg!(&bins_b, &bins_a);
675 eprintln!("index: {} of {}", index, len);
676 }
677
678 assert_eq!(bins_a.len(), bins_b.len());
679 assert_eq!(a.bin_count(), b.bin_count());
680
681 for (b_a, b_b) in bins_a.into_iter().zip(bins_b)
682 {
683 assert_eq!((b_a, b_a + 1), b_b);
684 }
685 }
686 }
687 }
688
689 }
690
691 #[allow(deprecated)]
693 #[test]
694 fn overlapping_partition_test2()
695 {
696 let mut rng = Pcg64Mcg::seed_from_u64(231468);
697 let uni = Uniform::new_inclusive(-100, 100);
698 let uni_n = Uniform::new_inclusive(2, 6);
699 for overlap in 0..=5 {
700 for _ in 0..100 {
701 let n: usize = uni_n.sample(&mut rng);
702 let (left, right) = loop {
703 let mut num_1 = uni.sample(&mut rng);
704 let mut num_2 = uni.sample(&mut rng);
705
706 if num_1 != num_2 {
707 if num_2 < num_1 {
708 std::mem::swap(&mut num_1, &mut num_2);
709 }
710 if (num_2 as isize - num_1 as isize) < (overlap as isize + 1) {
711 continue;
712 }
713 break (num_1, num_2)
714 }
715 };
716 let hist_fast = HistI8Fast::new_inclusive(left, right).unwrap();
717 let hist_i = HistI8::new_inclusive(left, right, hist_fast.bin_count()).unwrap();
718 let overlapping_i = hist_i.overlapping_partition(NonZeroUsize::new(n).unwrap(), overlap)
719 .unwrap();
720
721 assert_eq!(
722 overlapping_i.last().unwrap().borders().last(),
723 hist_i.borders().last()
724 );
725
726 assert_eq!(
727 overlapping_i.first().unwrap().borders().first(),
728 hist_i.borders().first()
729 );
730 }
731 }
732 }
733
734 #[allow(deprecated)]
737 #[test]
738 fn overlapping_partition_test3()
739 {
740 let mut rng = Pcg64Mcg::seed_from_u64(23148);
741 let uni = Uniform::new_inclusive(-300, 300);
742 let uni_n = Uniform::new_inclusive(2, 4);
743 for binsize in 2..=7 {
744 for overlap in 0..=5 {
745 for _ in 0..100 {
746 let n: usize = uni_n.sample(&mut rng);
747 let (left, right) = loop {
748 let mut num_1 = uni.sample(&mut rng);
749 let mut num_2 = uni.sample(&mut rng);
750
751 if num_1 != num_2 {
752 if num_2 < num_1 {
753 std::mem::swap(&mut num_1, &mut num_2);
754 }
755 if (num_2 as isize - num_1 as isize) < (overlap as isize + 1) {
756 continue;
757 }
758 let hist_fast = HistI16Fast::new_inclusive(num_1, num_2).unwrap();
759 if hist_fast.bin_count() % binsize != 0 {
760 continue;
761 }
762 break (num_1, num_2)
763 }
764 };
765 let hist_fast = HistI16Fast::new_inclusive(left, right).unwrap();
766 let hist_i = HistI16::new_inclusive(left, right, hist_fast.bin_count() / binsize).unwrap();
767 let overlapping_i = hist_i.overlapping_partition(NonZeroUsize::new(n).unwrap(), overlap)
768 .unwrap();
769
770 assert_eq!(
771 overlapping_i.last().unwrap().borders().last(),
772 hist_i.borders().last()
773 );
774
775 assert_eq!(
776 overlapping_i.first().unwrap().borders().first(),
777 hist_i.borders().first()
778 );
779 }
780 }
781 }
782
783 }
784
785 #[allow(deprecated)]
786 #[test]
787 fn bin_iter_test()
788 {
789 let hist = HistI16::new(0, 4, 4).unwrap();
790
791 let mut bin_iter = hist.bin_iter();
792
793 assert_eq!(bin_iter.next(), Some(&[0_i16, 1_i16]));
794 assert_eq!(bin_iter.next(), Some(&[1_i16, 2_i16]));
795 assert_eq!(bin_iter.next(), Some(&[2_i16, 3_i16]));
796 assert_eq!(bin_iter.next(), Some(&[3_i16, 4_i16]));
797 assert_eq!(bin_iter.next(), None);
798
799 let hist = HistU8::new(0,8, 4).unwrap();
800
801 let mut bin_iter = hist.bin_iter();
802
803 assert_eq!(bin_iter.next(), Some(&[0_u8, 2_u8]));
804 assert_eq!(bin_iter.next(), Some(&[2_u8, 4_u8]));
805 assert_eq!(bin_iter.next(), Some(&[4_u8, 6_u8]));
806 assert_eq!(bin_iter.next(), Some(&[6_u8, 8_u8]));
807 assert_eq!(bin_iter.next(), None);
808 }
809}