1use std::{
2 fmt,
3 iter::*,
4 ops::*,
5};
6
7use bon::{bon};
8use itertools::Itertools;
9use num_traits as nums;
10use rand::{
11 prelude::*,
12 seq::SliceRandom,
13};
14
15
16pub trait Weight:
17 nums::NumAssign
18 + nums::NumCast
19 + Copy
20 + PartialOrd
21 + Sum
22 + fmt::Display
23{}
24
25impl<Type> Weight for Type where Type:
26 nums::NumAssign
27 + nums::NumCast
28 + Copy
29 + PartialOrd
30 + Sum
31 + fmt::Display
32{}
33
34
35#[derive(Debug, Clone, Eq, PartialEq, Hash)]
42pub struct WeightedItem<V, W: Weight>
43{
44 pub weight: W,
45 pub value: V,
46}
47
48impl<V, W: Weight> WeightedItem<V,W>
49{
50 pub fn unit(value: V) -> WeightedItem<V,W>
52 {
53 Self {
54 weight: W::one(),
55 value: value
56 }
57 }
58
59 pub fn new(weight: W, value: V) -> WeightedItem<V,W>
61 {
62 Self { weight, value }
63 }
64
65 pub fn from((weight, value): (W, V)) -> WeightedItem<V,W>
67 {
68 Self { weight, value }
69 }
70}
71
72#[macro_export]
82macro_rules! wit {
83 ( $weight: expr, $value: expr ) => {
84 WeightedItem::new($weight, $value)
85 };
86}
87
88impl<V: fmt::Display, W: Weight> fmt::Display for WeightedItem<V,W>
89{
90 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
91 {
92 write!(f, "{{ {}, {} }}", self.weight, self.value)
93 }
94}
95
96impl<V: Eq, W: Weight + Ord> Ord for WeightedItem<V,W>
97{
98 fn cmp(&self, other: &Self) -> std::cmp::Ordering
99 {
100 self.weight.cmp(&other.weight)
101 }
102}
103
104impl<V: Eq, W: Weight> PartialOrd for WeightedItem<V,W>
105{
106 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering>
107 {
108 self.weight.partial_cmp(&other.weight)
109 }
110}
111
112
113#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
154pub struct WeightedList<V, W: Weight>
155{
156 data: Vec<WeightedItem<V,W>>,
157}
158
159impl<V, W: Weight> WeightedList<V,W>
161{
162 pub fn new() -> Self
164 {
165 Self {
166 data: Vec::new()
167 }
168 }
169
170 pub fn with_capacity(capacity: usize) -> Self
172 {
173 Self {
174 data: Vec::with_capacity(capacity)
175 }
176 }
177
178 pub fn init<I>(items: I) -> Self
180 where I: IntoIterator<Item = (W, V)>
181 {
182 Self {
183 data: items.into_iter().map(
184 |(weight, value)|
185 WeightedItem::new(weight, value)
186 ).collect::<Vec<WeightedItem<V,W>>>()
187 }
188 }
189}
190
191#[macro_export]
204macro_rules! wlist {
205 ( $( $item: expr ),* $(,)? ) => {
206 WeightedList::init([
207 $( $item, )*
208 ])
209 };
210}
211
212impl<V, W: Weight> WeightedList<V,W>
214{
215 pub fn weights(&self) -> impl Iterator<Item = W>
217 {
218 self.data.iter().map(|item| item.weight)
219 }
220
221 pub fn values(&self) -> impl Iterator<Item = &V>
223 {
224 self.data.iter().map(|item| &item.value)
225 }
226
227 pub fn items(&self) -> &Vec<WeightedItem<V,W>>
229 {
230 &self.data
231 }
232
233 pub fn raw(&self) -> impl Iterator<Item = (W,&V)>
249 {
250 self.data.iter().map(|item| (item.weight, &item.value))
251 }
252}
253
254impl<V, W: Weight> WeightedList<V,W>
256{
257 pub fn len(&self) -> W
263 {
264 self.data.iter().map(|item| item.weight).sum()
265 }
266
267 pub fn capacity(&self) -> usize
268 {
269 self.data.capacity()
270 }
271
272 pub fn total_values(&self) -> usize
276 {
277 self.data.len()
278 }
279
280 pub fn is_empty(&self) -> bool
284 {
285 self.data.is_empty()
286 }
287
288 pub fn is_zero(&self) -> bool
290 {
291 !self.is_empty()
292 && self.data.iter().all(|item| item.weight == W::zero())
293 }
294
295 pub fn has_negative_weights(&self) -> bool
297 {
298 !self.is_empty()
299 && self.data.iter().any(|item| item.weight < W::zero())
300 }
301}
302
303impl<V, W: Weight> FromIterator<WeightedItem<V,W>> for WeightedList<V,W>
305{
306 fn from_iter<I>(items: I) -> Self
307 where I: IntoIterator<Item = WeightedItem<V,W>>
308 {
309 let mut data = vec![];
315
316 for item in items {
317 data.push(item);
318 }
319
320 Self { data }
321 }
322}
323
324impl<V, W: Weight> From<Vec<WeightedItem<V,W>>> for WeightedList<V,W>
325{
326 fn from(vec: Vec<WeightedItem<V,W>>) -> Self {
327 Self { data: vec }
328 }
329}
330
331impl<V, W: Weight> Into<Vec<WeightedItem<V,W>>> for WeightedList<V,W>
332{
333 fn into(self) -> Vec<WeightedItem<V,W>> {
334 self.data
335 }
336}
337
338impl<V, W: Weight> AsRef<Vec<WeightedItem<V,W>>> for WeightedList<V,W>
339{
340 fn as_ref(&self) -> &Vec<WeightedItem<V,W>> {
341 &self.data
342 }
343}
344
345impl<V, W: Weight> Deref for WeightedList<V,W>
346{
347 type Target = [WeightedItem<V,W>];
348
349 fn deref(&self) -> &Self::Target {
350 self.data.deref()
351 }
352}
353
354impl<V, W: Weight> DerefMut for WeightedList<V,W>
355{
356 fn deref_mut(&mut self) -> &mut Self::Target {
357 self.data.deref_mut()
358 }
359}
360
361impl<V: fmt::Display, W: Weight + fmt::Display> fmt::Display for WeightedList<V,W>
363{
364 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365 write!(f,
366 "WeightedList[{}]",
367 self.data.iter().map(|item| item.to_string()).join(", ")
368 )
369 }
370}
371
372impl<V, W: Weight> Extend<WeightedItem<V,W>> for WeightedList<V,W>
373{
374 fn extend<T>(&mut self, iter: T)
375 where T: IntoIterator<Item = WeightedItem<V,W>>
376 {
377 for item in iter {
378 self.push_item(item);
379 }
380 }
381}
382
383impl<V, W: Weight> WeightedList<V,W>
385{
386 fn _unweight_index_nopanic_(&self, weighted_index: W) -> usize
388 {
389 let mut t = W::zero();
390 let mut i = 0;
391
392 for item in &self.data {
393 t += item.weight;
394
395 if t > weighted_index {
396 return i;
397 }
398
399 i += 1;
400 }
401
402 i
403 }
404
405 fn _unweight_index_(&self, weighted_index: W) -> usize
407 {
408 let mut t = W::zero();
409 let mut i = 0;
410
411 for item in &self.data {
412 t += item.weight;
413
414 if t > weighted_index {
415 return i;
416 }
417
418 i += 1;
419 }
420
421 panic!(
422 "index out of bounds: the len is {} but the index is {}",
423 self.len(), weighted_index
424 );
425 }
426}
427
428impl<V, W: Weight> Index<W> for WeightedList<V,W>
430{
431 type Output = WeightedItem<V,W>;
432
433 fn index(&self, weighted_index: W) -> &Self::Output
434 {
435 let mut t = W::zero();
436
437 for item in &self.data {
438 t += item.weight;
439
440 if t > weighted_index {
441 return item;
442 }
443 };
444
445 panic!("index out of bounds: the len is {} but the index is {weighted_index}", self.len());
446 }
447}
448
449impl<V, W: Weight> IndexMut<W> for WeightedList<V,W>
450{
451 fn index_mut(&mut self, weighted_index: W) -> &mut WeightedItem<V,W>
452 {
453 let idx = self._unweight_index_(weighted_index);
454 &mut self.data[idx]
455 }
456}
457
458impl<V, W: Weight> WeightedList<V,W> {
460 pub fn iter(&self) -> impl Iterator<Item = &WeightedItem<V,W>> {
461 self.data.iter()
462 }
463
464 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut WeightedItem<V,W>> {
465 self.data.iter_mut()
466 }
467}
468
469impl<V, W: Weight> IntoIterator for WeightedList<V,W>
470{
471 type Item = WeightedItem<V,W>;
472 type IntoIter = <Vec<Self::Item> as IntoIterator>::IntoIter;
473
474 fn into_iter(self) -> Self::IntoIter {
482 self.data.into_iter()
483 }
484}
485
486impl<'l, V, W: Weight> IntoIterator for &'l WeightedList<V,W>
487{
488 type Item = &'l WeightedItem<V,W>;
489 type IntoIter = std::slice::Iter<'l, WeightedItem<V,W>>;
490
491 fn into_iter(self) -> Self::IntoIter {
492 self.data.iter()
493 }
494}
495
496impl<'l, V, W: Weight> IntoIterator for &'l mut WeightedList<V,W>
497{
498 type Item = &'l mut WeightedItem<V,W>;
499 type IntoIter = std::slice::IterMut<'l, WeightedItem<V,W>>;
500
501 fn into_iter(self) -> Self::IntoIter {
502 self.data.iter_mut()
503 }
504}
505
506impl<V, W: Weight> WeightedList<V,W>
508{
509 pub fn reserve(&mut self, additional: usize) -> &mut Self
510 {
511 self.data.reserve(additional);
512 self
513 }
514
515 pub fn push_item(&mut self, item: WeightedItem<V,W>) -> &mut Self
516 {
517 self.data.push(item);
518 self
519 }
520
521 pub fn push_new_item(&mut self, weight: W, value: V) -> &mut Self
522 {
523 self.push_item(WeightedItem { weight, value })
524 }
525
526 pub fn push_value(&mut self, value: V) -> &mut Self
527 {
528 self.push_item(WeightedItem::unit(value))
529 }
530
531 pub fn insert_item(&mut self,
533 weighted_index: W,
534 item: WeightedItem<V,W>
535 ) -> &mut Self
536 {
537 self.data.insert(self._unweight_index_nopanic_(weighted_index), item);
538 self
539 }
540
541 pub fn insert_new_item(&mut self,
543 weighted_index: W,
544 (weight, value): (W, V)
545 ) -> &mut Self
546 {
547 self.insert_item(weighted_index, WeightedItem::new(weight, value))
548 }
549
550 pub fn insert_value(&mut self,
552 weighted_index: W,
553 value: V,
554 ) -> &mut Self
555 {
556 self.insert_item(weighted_index, WeightedItem::unit(value))
557 }
558
559 pub fn append(&mut self, other: &mut WeightedList<V,W>) -> &mut Self
560 {
561 self.data.append(&mut other.data);
562 self
563 }
564
565 pub fn reverse(&mut self) -> &mut Self
566 {
567 self.data.reverse();
568 self
569 }
570
571 pub fn swap(&mut self, left: W, right: W) -> &mut Self
572 {
573 let l = self._unweight_index_(left);
574 let r = self._unweight_index_(right);
575 self.data.swap(l, r);
576 self
577 }
578
579 pub fn pop(&mut self) -> Option<WeightedItem<V,W>>
580 {
581 self.data.pop()
582 }
583
584 pub fn pop_if(&mut self,
585 predicate: impl FnOnce(&mut WeightedItem<V,W>) -> bool
586 ) -> Option<WeightedItem<V,W>>
587 {
588 self.data.pop_if(predicate)
589 }
590
591 pub fn remove(&mut self, weighted_index: W) -> WeightedItem<V,W>
593 {
594 self.data.remove(self._unweight_index_(weighted_index))
595 }
596
597 pub fn truncate(&mut self, len: W) -> &mut Self
599 {
600 let mut t = W::zero();
601
602 for each in &mut self.data {
603 t += each.weight;
604
605 if t > len {
606 each.weight = t - len;
607 }
608 }
609
610 self
611 }
612
613 pub fn retain<F>(&mut self, predicate: F) -> &mut Self
614 where F: FnMut(&WeightedItem<V,W>) -> bool
615 {
616 self.data.retain(predicate);
617 self
618 }
619
620 pub fn retain_mut<F>(&mut self, predicate: F) -> &mut Self
621 where F: FnMut(&mut WeightedItem<V,W>) -> bool
622 {
623 self.data.retain_mut(predicate);
624 self
625 }
626
627 pub fn clear(&mut self) -> &mut Self
629 {
630 self.data.clear();
631 self
632 }
633}
634
635impl<V: Clone, W: Weight> WeightedList<V,W>
636{
637 pub fn sorted(&self) -> Self
638 where V: Eq, W: Ord
639 {
640 let mut out = self.clone();
641 out.sort();
642 out
643 }
644
645 pub fn reversed(&self) -> Self
646 {
647 let mut out = self.clone();
648 out.reverse();
649 out
650 }
651}
652
653impl<V, W: Weight> WeightedList<V,W>
655{
656 pub fn prune(&mut self) -> &mut Self
658 {
659 self.data.retain(|item| item.weight > W::zero());
660 self
661 }
662
663 pub fn zero_all_weights(&mut self) -> &mut Self
665 {
666 for item in &mut self.data {
667 item.weight = W::zero();
668 }
669
670 self
671 }
672
673 pub fn set_all_weights(&mut self, weight: W) -> &mut Self
675 {
676 for item in &mut self.data {
677 item.weight = weight;
678 }
679
680 self
681 }
682
683 pub fn normalised(&mut self) -> Result<WeightedList<V, f64>, &str>
684 where V: Clone
685 {
686 let total;
687
688 if let Some(t) = nums::cast::<W, f64>(self.len()) {
689 total = t;
690 } else {
691 return Err("Error casting total weights to `f64`");
692 };
693
694 let items =
695 self.data
696 .iter()
697 .map(|item| {
698 let weight = nums::cast::<W, f64>(item.weight)?;
699 Some(WeightedItem {
700 weight: weight / total,
701 value: item.value.clone()
702 })
703 })
704 .collect::<Option<Vec<WeightedItem<V, f64>>>>()
705 ;
706
707 match items {
708 Some(data) => Ok(WeightedList { data }),
709 None => Err("Error casting weights to `f64`")
710 }
711 }
712}
713
714impl<V: PartialEq, W: Weight> WeightedList<V,W>
715{
716 pub fn merge_item(&mut self, item: WeightedItem<V,W>) -> &mut Self
738 {
739 if let Some(existing) = self.data.iter_mut().find(|each| each.value == item.value) {
740 existing.weight += item.weight;
741 }
742 else {
743 self.data.push(item);
744 }
745
746 self
747 }
748
749 pub fn merge_new_item(&mut self, weight: W, value: V) -> &mut Self
753 {
754 self.merge_item(WeightedItem { weight, value })
755 }
756
757 pub fn merge_value(&mut self, value: V) -> &mut Self
761 {
762 self.merge_item(WeightedItem::unit(value))
763 }
764
765 pub fn merge_with(&mut self, other: WeightedList<V,W>) -> &mut Self
766 {
767 for item in other {
768 self.merge_item(item);
769 }
770
771 self
772 }
773
774 pub fn merge_duplicates(&mut self) -> &mut Self
775 {
776 let orig = std::mem::replace(self, WeightedList::new());
777 self.merge_with(orig);
778 self
779 }
780}
781
782impl<V: Clone, W: Weight> WeightedList<V,W>
783{
784 pub fn take_one(&mut self, weighted_index: W) -> WeightedItem<V,W>
785 {
786 self.take_by(weighted_index, W::one())
787 }
788
789 pub fn take_by(&mut self, weighted_index: W, decrement: W) -> WeightedItem<V,W>
791 {
792 let idx = self._unweight_index_(weighted_index);
793 let target = &mut self.data[idx];
794 target.weight -= decrement;
795
796 if target.weight <= W::zero() {
797 self.data.remove(idx)
798 }
799 else {
800 target.clone()
801 }
802 }
803
804 pub fn take_entire(&mut self, weighted_index: W) -> WeightedItem<V,W>
805 {
806 self.remove(weighted_index)
807 }
808}
809
810impl<V, W: Weight> WeightedList<V,W>
812{
813 fn _get_random_weighted_index_<RNG>(&self, rng: &mut RNG) -> Option<W>
814 where RNG: Rng + ?Sized
815 {
816 let len: f64 = nums::cast::<W, f64>(self.len())?;
817 let scalar: f64 = rng.random();
818
819 let idx = (len * scalar).floor();
820 let out = nums::cast::<f64, W>(idx)?;
821
822 Some(out)
823 }
824
825 pub fn select_random_value<RNG>(&self, rng: &mut RNG) -> Option<&V>
826 where RNG: Rng + ?Sized
827 {
828 let out = &self.select_random_item(rng)?.value;
829 Some(out)
830 }
831
832 pub fn select_random_item<RNG>(&self, rng: &mut RNG) -> Option<&WeightedItem<V,W>>
836 where RNG: Rng + ?Sized
837 {
838 if self.data.is_empty() { return None }
839
840 let idx = self._get_random_weighted_index_(rng)?;
841 let out = &self[idx];
842
843 Some(out)
844 }
845}
846
847impl<V: Clone, W: Weight> WeightedList<V,W>
848{
849 pub fn take_one_random<RNG>(&mut self, rng: &mut RNG) -> Option<WeightedItem<V,W>>
850 where RNG: Rng + ?Sized
851 {
852 self.take_by_random(rng, W::one())
853 }
854
855 pub fn take_by_random<RNG>(&mut self, rng: &mut RNG, decrement: W) -> Option<WeightedItem<V,W>>
856 where RNG: Rng + ?Sized
857 {
858 if self.data.is_empty() { return None }
859
860 let idx = self._get_random_weighted_index_(rng)?;
861 let out = self.take_by(idx, decrement);
862
863 Some(out)
864 }
865
866 pub fn take_entire_random<RNG>(&mut self, rng: &mut RNG) -> Option<WeightedItem<V,W>>
867 where RNG: Rng + ?Sized
868 {
869 if self.data.is_empty() { return None }
870
871 let idx = self._get_random_weighted_index_(rng)?;
872 let out = self.take_entire(idx);
873
874 Some(out)
875 }
876}
877
878#[bon]
879impl<V: Clone + Eq, W: Weight> WeightedList<V,W>
880{
881 #[builder]
939 pub fn select_random_values<RNG>(&self,
940 count: u32,
941 rng: &mut RNG,
942 replace: Option<bool>,
943 decrement: Option<W>,
944 unique: Option<bool>,
945 ) -> Vec<V>
946 where RNG: Rng + ?Sized
947 {
948 let unique = unique.unwrap_or(false);
949 let replace = replace.unwrap_or(true);
950 let decrement = decrement.unwrap_or(W::one());
951
952 let mut pool = self.clone();
953 let mut i = 0;
954 let mut out = Vec::with_capacity(count as usize);
955
956 loop
957 {
958 i += 1;
959 if i > count { break }
960
961 if let Some(item) = {
962 if unique { pool.take_entire_random(rng) }
963 else if replace { pool.take_by_random(rng, W::zero()) }
964 else { pool.take_by_random(rng, decrement) }
965 } {
966 out.push(item.value.clone());
967 }
968 else {
969 continue
970 }
971 }
972
973 out
974 }
975}
976
977impl<V: Clone, W: Weight + Clone> WeightedList<V,W>
978{
979 pub fn shuffle_items<RNG>(&mut self, rng: &mut RNG) -> &mut Self
980 where RNG: Rng + ?Sized
981 {
982 self.data.shuffle(rng);
983 self
984 }
985
986 pub fn shuffled_items<RNG>(&self, rng: &mut RNG) -> Self
987 where RNG: Rng + ?Sized
988 {
989 let mut out = self.clone();
990 out.shuffle_items(rng);
991
992 out
993 }
994
995 pub fn shuffle_weights<RNG>(&mut self, rng: &mut RNG) -> &mut Self
996 where RNG: Rng + ?Sized
997 {
998 let mut weights: Vec<W> = self.weights().collect();
999 weights.shuffle(rng);
1000
1001 for item in &mut self.data {
1002 item.weight = weights.pop().unwrap();
1004 }
1005
1006 self
1007 }
1008
1009 pub fn shuffled_weights<RNG>(&self, rng: &mut RNG) -> Self
1010 where RNG: Rng + ?Sized
1011 {
1012 let mut out = self.clone();
1013 out.shuffle_weights(rng);
1014
1015 out
1016 }
1017}
1018
1019
1020#[cfg(test)]
1024mod tests
1025{
1026 use super::*;
1027
1028 fn wl() -> WeightedList<String, i32>
1029 {
1030 wlist![
1031 (2, String::from("sup")),
1032 (3, String::from("nova")),
1033 (5, String::from("shard")),
1034 ]
1035 }
1036
1037 #[test]
1038 fn _unweight_index_()
1039 {
1040 let list = wl();
1041 assert_eq!( list._unweight_index_(0), 0 );
1042 assert_eq!( list._unweight_index_(1), 0 );
1043 assert_eq!( list._unweight_index_(2), 1 );
1044 assert_eq!( list._unweight_index_(3), 1 );
1045 assert_eq!( list._unweight_index_(4), 1 );
1046 assert_eq!( list._unweight_index_(5), 2 );
1047 assert_eq!( list._unweight_index_(6), 2 );
1048 assert_eq!( list._unweight_index_(7), 2 );
1049 assert_eq!( list._unweight_index_(8), 2 );
1050 assert_eq!( list._unweight_index_(9), 2 );
1051 }
1052
1053 #[test]
1054 #[should_panic]
1055 fn _unweight_index_panic_()
1056 {
1057 let list = wl();
1058 list._unweight_index_(10);
1059 }
1060
1061 #[test]
1062 fn _unweight_index_nopanic_()
1063 {
1064 let list = wl();
1065 assert_eq!( list._unweight_index_nopanic_(10), 3 );
1066 assert_eq!( list._unweight_index_nopanic_(11), 3 );
1067 assert_eq!( list._unweight_index_nopanic_(12), 3 );
1068 }
1069}