1use std::ops::Index;
29
30#[derive(Debug, Clone)]
35pub struct Ring<T> {
36 nodes: Vec<T>,
37}
38
39impl<T> Ring<T> {
40 pub fn new(nodes: Vec<T>) -> Self {
46 assert!(!nodes.is_empty(), "Ring cannot be empty");
47 Self { nodes }
48 }
49
50 pub fn with_capacity(capacity: usize) -> Self {
52 Self {
53 nodes: Vec::with_capacity(capacity),
54 }
55 }
56
57 #[inline]
59 pub fn len(&self) -> usize {
60 self.nodes.len()
61 }
62
63 #[inline]
65 pub fn is_empty(&self) -> bool {
66 self.nodes.is_empty()
67 }
68
69 #[inline]
71 pub fn get(&self, idx: usize) -> &T {
72 &self.nodes[idx % self.len()]
73 }
74
75 #[inline]
77 pub fn get_mut(&mut self, idx: usize) -> &mut T {
78 let len = self.len();
79 &mut self.nodes[idx % len]
80 }
81
82 #[inline]
84 pub fn next(&self, idx: usize) -> usize {
85 (idx + 1) % self.len()
86 }
87
88 #[inline]
90 pub fn prev(&self, idx: usize) -> usize {
91 if idx == 0 {
92 self.len() - 1
93 } else {
94 idx - 1
95 }
96 }
97
98 #[inline]
110 pub fn ring_distance(&self, a: usize, b: usize) -> usize {
111 let n = self.len();
112 let a = a % n;
113 let b = b % n;
114 let forward = (b + n - a) % n;
115 let backward = (a + n - b) % n;
116 forward.min(backward)
117 }
118
119 pub fn neighbors(&self, idx: usize, radius: usize) -> impl Iterator<Item = &T> {
129 let n = self.len();
130 let idx = idx % n;
131
132 (1..=radius).flat_map(move |d| {
133 let prev_idx = (idx + n - d) % n;
134 let next_idx = (idx + d) % n;
135
136 if prev_idx == next_idx {
138 vec![&self.nodes[prev_idx]].into_iter()
139 } else {
140 vec![&self.nodes[prev_idx], &self.nodes[next_idx]].into_iter()
141 }
142 })
143 }
144
145 pub fn neighbor_indices(&self, idx: usize, radius: usize) -> Vec<usize> {
149 let n = self.len();
150 let idx = idx % n;
151
152 let mut indices = Vec::with_capacity(radius * 2);
153
154 for d in 1..=radius {
155 let prev_idx = (idx + n - d) % n;
156 let next_idx = (idx + d) % n;
157
158 if prev_idx == next_idx {
159 indices.push(prev_idx);
160 } else {
161 indices.push(prev_idx);
162 indices.push(next_idx);
163 }
164 }
165
166 indices
167 }
168
169 pub fn iter(&self) -> impl Iterator<Item = &T> {
171 self.nodes.iter()
172 }
173
174 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
176 self.nodes.iter_mut()
177 }
178
179 pub fn iter_from(&self, start: usize) -> impl Iterator<Item = &T> {
181 let n = self.len();
182 let start = start % n;
183 (0..n).map(move |i| &self.nodes[(start + i) % n])
184 }
185
186 pub fn push(&mut self, node: T) {
188 self.nodes.push(node);
189 }
190
191 #[inline]
193 pub fn as_slice(&self) -> &[T] {
194 &self.nodes
195 }
196
197 #[inline]
199 pub fn as_mut_slice(&mut self) -> &mut [T] {
200 &mut self.nodes
201 }
202
203 pub fn into_inner(self) -> Vec<T> {
205 self.nodes
206 }
207}
208
209impl<T> Index<usize> for Ring<T> {
210 type Output = T;
211
212 #[inline]
213 fn index(&self, idx: usize) -> &Self::Output {
214 self.get(idx)
215 }
216}
217
218impl<T> FromIterator<T> for Ring<T> {
219 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
220 Self::new(iter.into_iter().collect())
221 }
222}
223
224#[derive(Debug, Clone)]
226pub struct RingNode<T> {
227 pub value: T,
229 pub weight: f32,
231 pub forward_weight: f32,
233 pub backward_weight: f32,
235}
236
237impl<T> RingNode<T> {
238 pub fn new(value: T) -> Self {
240 Self {
241 value,
242 weight: 1.0,
243 forward_weight: 1.0,
244 backward_weight: 1.0,
245 }
246 }
247
248 pub fn with_weight(value: T, weight: f32) -> Self {
250 Self {
251 value,
252 weight,
253 forward_weight: 1.0,
254 backward_weight: 1.0,
255 }
256 }
257}
258
259pub type EpisodeRing<E> = Ring<RingNode<E>>;
261
262pub fn build_weighted_ring<T>(episodes: Vec<T>, weights: &[f32]) -> Ring<RingNode<T>> {
269 assert_eq!(episodes.len(), weights.len(), "Episode and weight counts must match");
270
271 let nodes: Vec<RingNode<T>> = episodes
272 .into_iter()
273 .zip(weights.iter())
274 .map(|(e, &w)| RingNode::with_weight(e, w))
275 .collect();
276
277 Ring::new(nodes)
278}
279
280#[derive(Debug, Clone)]
314pub struct DualRing<T> {
315 nodes: Vec<DualRingNode<T>>,
317 influence_order: Vec<usize>,
319}
320
321#[derive(Debug, Clone)]
323pub struct DualRingNode<T> {
324 pub value: T,
326 pub temporal_idx: usize,
328 pub influence: f32,
330 pub attention_received: f32,
332 pub attention_given: f32,
334}
335
336impl<T> DualRingNode<T> {
337 pub fn new(temporal_idx: usize, value: T, influence: f32) -> Self {
339 Self {
340 value,
341 temporal_idx,
342 influence,
343 attention_received: 0.0,
344 attention_given: 0.0,
345 }
346 }
347
348 pub fn with_attention(
350 temporal_idx: usize,
351 value: T,
352 influence: f32,
353 attention_received: f32,
354 attention_given: f32,
355 ) -> Self {
356 Self {
357 value,
358 temporal_idx,
359 influence,
360 attention_received,
361 attention_given,
362 }
363 }
364}
365
366impl<T> DualRing<T> {
367 pub fn new(nodes: Vec<DualRingNode<T>>) -> Self {
371 assert!(!nodes.is_empty(), "DualRing cannot be empty");
372
373 let mut influence_order: Vec<usize> = (0..nodes.len()).collect();
375 influence_order.sort_by(|&a, &b| {
376 nodes[b].influence.partial_cmp(&nodes[a].influence)
377 .unwrap_or(std::cmp::Ordering::Equal)
378 });
379
380 Self { nodes, influence_order }
381 }
382
383 #[inline]
385 pub fn len(&self) -> usize {
386 self.nodes.len()
387 }
388
389 #[inline]
391 pub fn is_empty(&self) -> bool {
392 self.nodes.is_empty()
393 }
394
395 #[inline]
399 pub fn get_temporal(&self, idx: usize) -> &DualRingNode<T> {
400 &self.nodes[idx % self.len()]
401 }
402
403 #[inline]
405 pub fn temporal_next(&self, idx: usize) -> usize {
406 (idx + 1) % self.len()
407 }
408
409 #[inline]
411 pub fn temporal_prev(&self, idx: usize) -> usize {
412 if idx == 0 { self.len() - 1 } else { idx - 1 }
413 }
414
415 #[inline]
417 pub fn temporal_distance(&self, a: usize, b: usize) -> usize {
418 let n = self.len();
419 let a = a % n;
420 let b = b % n;
421 let forward = (b + n - a) % n;
422 let backward = (a + n - b) % n;
423 forward.min(backward)
424 }
425
426 pub fn iter_temporal(&self) -> impl Iterator<Item = &DualRingNode<T>> {
428 self.nodes.iter()
429 }
430
431 pub fn iter_temporal_from(&self, start: usize) -> impl Iterator<Item = &DualRingNode<T>> {
433 let n = self.len();
434 let start = start % n;
435 (0..n).map(move |i| &self.nodes[(start + i) % n])
436 }
437
438 pub fn temporal_neighbors(&self, idx: usize, radius: usize) -> impl Iterator<Item = &DualRingNode<T>> {
440 let n = self.len();
441 let idx = idx % n;
442
443 (1..=radius).flat_map(move |d| {
444 let prev_idx = (idx + n - d) % n;
445 let next_idx = (idx + d) % n;
446
447 if prev_idx == next_idx {
448 vec![&self.nodes[prev_idx]].into_iter()
449 } else {
450 vec![&self.nodes[prev_idx], &self.nodes[next_idx]].into_iter()
451 }
452 })
453 }
454
455 #[inline]
459 pub fn get_by_influence_rank(&self, rank: usize) -> &DualRingNode<T> {
460 let idx = self.influence_order[rank % self.len()];
461 &self.nodes[idx]
462 }
463
464 pub fn influence_rank_of(&self, temporal_idx: usize) -> usize {
466 self.influence_order.iter()
467 .position(|&idx| idx == temporal_idx)
468 .unwrap_or(self.len())
469 }
470
471 pub fn iter_by_influence(&self) -> impl Iterator<Item = &DualRingNode<T>> {
473 self.influence_order.iter().map(move |&idx| &self.nodes[idx])
474 }
475
476 pub fn top_influential(&self, k: usize) -> impl Iterator<Item = &DualRingNode<T>> {
478 self.influence_order.iter()
479 .take(k)
480 .map(move |&idx| &self.nodes[idx])
481 }
482
483 pub fn influence_distance(&self, a_temporal: usize, b_temporal: usize) -> usize {
485 let a_rank = self.influence_rank_of(a_temporal);
486 let b_rank = self.influence_rank_of(b_temporal);
487
488 let n = self.len();
489 let forward = (b_rank + n - a_rank) % n;
490 let backward = (a_rank + n - b_rank) % n;
491 forward.min(backward)
492 }
493
494 pub fn influence_neighbors(&self, temporal_idx: usize, radius: usize) -> impl Iterator<Item = &DualRingNode<T>> {
496 let rank = self.influence_rank_of(temporal_idx);
497 let n = self.len();
498
499 (1..=radius).flat_map(move |d| {
500 let prev_rank = if rank >= d { rank - d } else { n - (d - rank) };
501 let next_rank = (rank + d) % n;
502
503 let prev_idx = self.influence_order[prev_rank];
504 let next_idx = self.influence_order[next_rank];
505
506 if prev_idx == next_idx {
507 vec![&self.nodes[prev_idx]].into_iter()
508 } else {
509 vec![&self.nodes[prev_idx], &self.nodes[next_idx]].into_iter()
510 }
511 })
512 }
513
514 pub fn influence_temporal_spread(&self) -> f32 {
521 if self.len() < 2 {
522 return 0.0;
523 }
524
525 let mut total_distance = 0.0;
526 let count = self.len().min(5); for i in 0..count {
529 for j in (i + 1)..count {
530 let idx_i = self.influence_order[i];
531 let idx_j = self.influence_order[j];
532 total_distance += self.temporal_distance(idx_i, idx_j) as f32;
533 }
534 }
535
536 let pairs = (count * (count - 1)) / 2;
537 if pairs > 0 {
538 total_distance / pairs as f32
539 } else {
540 0.0
541 }
542 }
543
544 pub fn forward_attention_flow(&self) -> f32 {
548 self.nodes.iter()
549 .map(|n| n.attention_given)
550 .sum()
551 }
552
553 pub fn inverse_attention_flow(&self) -> f32 {
557 self.nodes.iter()
558 .map(|n| n.attention_received)
559 .sum()
560 }
561
562 pub fn update_influence(&mut self, temporal_idx: usize, new_influence: f32) {
564 let idx = temporal_idx % self.len();
565 self.nodes[idx].influence = new_influence;
566
567 self.influence_order.sort_by(|&a, &b| {
569 self.nodes[b].influence.partial_cmp(&self.nodes[a].influence)
570 .unwrap_or(std::cmp::Ordering::Equal)
571 });
572 }
573
574 pub fn as_slice(&self) -> &[DualRingNode<T>] {
576 &self.nodes
577 }
578}
579
580pub fn build_dual_ring<T>(
582 episodes: Vec<T>,
583 influences: &[f32],
584) -> DualRing<T> {
585 assert_eq!(episodes.len(), influences.len(), "Episode and influence counts must match");
586
587 let nodes: Vec<DualRingNode<T>> = episodes
588 .into_iter()
589 .enumerate()
590 .zip(influences.iter())
591 .map(|((idx, value), &influence)| DualRingNode::new(idx, value, influence))
592 .collect();
593
594 DualRing::new(nodes)
595}
596
597pub fn build_dual_ring_with_attention<T>(
599 episodes: Vec<T>,
600 influences: &[f32],
601 attention_received: &[f32],
602 attention_given: &[f32],
603) -> DualRing<T> {
604 assert_eq!(episodes.len(), influences.len());
605 assert_eq!(episodes.len(), attention_received.len());
606 assert_eq!(episodes.len(), attention_given.len());
607
608 let nodes: Vec<DualRingNode<T>> = episodes
609 .into_iter()
610 .enumerate()
611 .zip(influences.iter())
612 .zip(attention_received.iter())
613 .zip(attention_given.iter())
614 .map(|((((idx, value), &inf), &recv), &given)| {
615 DualRingNode::with_attention(idx, value, inf, recv, given)
616 })
617 .collect();
618
619 DualRing::new(nodes)
620}
621
622#[cfg(test)]
623mod tests {
624 use super::*;
625
626 #[test]
627 fn test_new_ring() {
628 let ring = Ring::new(vec![1, 2, 3, 4, 5]);
629 assert_eq!(ring.len(), 5);
630 assert!(!ring.is_empty());
631 }
632
633 #[test]
634 #[should_panic(expected = "Ring cannot be empty")]
635 fn test_empty_ring_panics() {
636 let _ring: Ring<i32> = Ring::new(vec![]);
637 }
638
639 #[test]
640 fn test_get_wrapping() {
641 let ring = Ring::new(vec![0, 1, 2, 3, 4]);
642
643 assert_eq!(*ring.get(0), 0);
644 assert_eq!(*ring.get(4), 4);
645 assert_eq!(*ring.get(5), 0); assert_eq!(*ring.get(7), 2); }
648
649 #[test]
650 fn test_next_prev() {
651 let ring = Ring::new(vec![0, 1, 2, 3, 4]);
652
653 assert_eq!(ring.next(0), 1);
654 assert_eq!(ring.next(4), 0); assert_eq!(ring.prev(0), 4); assert_eq!(ring.prev(3), 2);
657 }
658
659 #[test]
660 fn test_ring_distance() {
661 let ring = Ring::new(vec![0, 1, 2, 3, 4]);
662
663 assert_eq!(ring.ring_distance(0, 0), 0);
665
666 assert_eq!(ring.ring_distance(0, 1), 1);
668 assert_eq!(ring.ring_distance(0, 4), 1); assert_eq!(ring.ring_distance(0, 2), 2);
672 assert_eq!(ring.ring_distance(0, 3), 2); assert_eq!(ring.ring_distance(1, 4), 2);
676 }
677
678 #[test]
679 fn test_neighbors() {
680 let ring = Ring::new(vec![0, 1, 2, 3, 4]);
681
682 let neighbors: Vec<_> = ring.neighbors(0, 1).copied().collect();
684 assert_eq!(neighbors.len(), 2);
685 assert!(neighbors.contains(&4));
686 assert!(neighbors.contains(&1));
687
688 let neighbors: Vec<_> = ring.neighbors(0, 2).copied().collect();
690 assert_eq!(neighbors.len(), 4);
691 assert!(neighbors.contains(&3));
692 assert!(neighbors.contains(&4));
693 assert!(neighbors.contains(&1));
694 assert!(neighbors.contains(&2));
695 }
696
697 #[test]
698 fn test_neighbor_indices() {
699 let ring = Ring::new(vec![0, 1, 2, 3, 4]);
700
701 let indices = ring.neighbor_indices(0, 1);
702 assert_eq!(indices.len(), 2);
703 assert!(indices.contains(&4));
704 assert!(indices.contains(&1));
705 }
706
707 #[test]
708 fn test_iter_from() {
709 let ring = Ring::new(vec![0, 1, 2, 3, 4]);
710
711 let from_2: Vec<_> = ring.iter_from(2).copied().collect();
712 assert_eq!(from_2, vec![2, 3, 4, 0, 1]);
713
714 let from_0: Vec<_> = ring.iter_from(0).copied().collect();
715 assert_eq!(from_0, vec![0, 1, 2, 3, 4]);
716 }
717
718 #[test]
719 fn test_index_operator() {
720 let ring = Ring::new(vec![10, 20, 30]);
721
722 assert_eq!(ring[0], 10);
723 assert_eq!(ring[2], 30);
724 assert_eq!(ring[3], 10); }
726
727 #[test]
728 fn test_from_iterator() {
729 let ring: Ring<i32> = (0..5).collect();
730 assert_eq!(ring.len(), 5);
731 assert_eq!(*ring.get(0), 0);
732 assert_eq!(*ring.get(4), 4);
733 }
734
735 #[test]
736 fn test_ring_node() {
737 let node = RingNode::new(42);
738 assert_eq!(node.value, 42);
739 assert!((node.weight - 1.0).abs() < 1e-6);
740
741 let weighted = RingNode::with_weight("hello", 0.5);
742 assert_eq!(weighted.value, "hello");
743 assert!((weighted.weight - 0.5).abs() < 1e-6);
744 }
745
746 #[test]
747 fn test_build_weighted_ring() {
748 let episodes = vec!["a", "b", "c"];
749 let weights = vec![0.1, 0.5, 0.9];
750
751 let ring = build_weighted_ring(episodes, &weights);
752
753 assert_eq!(ring.len(), 3);
754 assert_eq!(ring.get(0).value, "a");
755 assert!((ring.get(0).weight - 0.1).abs() < 1e-6);
756 assert!((ring.get(2).weight - 0.9).abs() < 1e-6);
757 }
758
759 #[test]
762 fn test_dual_ring_creation() {
763 let nodes = vec![
764 DualRingNode::new(0, "a", 0.3),
765 DualRingNode::new(1, "b", 0.9),
766 DualRingNode::new(2, "c", 0.5),
767 DualRingNode::new(3, "d", 0.1),
768 ];
769
770 let dual = DualRing::new(nodes);
771 assert_eq!(dual.len(), 4);
772 }
773
774 #[test]
775 fn test_dual_ring_temporal_order() {
776 let nodes = vec![
777 DualRingNode::new(0, "first", 0.3),
778 DualRingNode::new(1, "second", 0.9),
779 DualRingNode::new(2, "third", 0.5),
780 ];
781
782 let dual = DualRing::new(nodes);
783
784 let temporal: Vec<_> = dual.iter_temporal().map(|n| n.value).collect();
786 assert_eq!(temporal, vec!["first", "second", "third"]);
787 }
788
789 #[test]
790 fn test_dual_ring_influence_order() {
791 let nodes = vec![
792 DualRingNode::new(0, "low", 0.1),
793 DualRingNode::new(1, "high", 0.9),
794 DualRingNode::new(2, "medium", 0.5),
795 ];
796
797 let dual = DualRing::new(nodes);
798
799 let influence: Vec<_> = dual.iter_by_influence().map(|n| n.value).collect();
801 assert_eq!(influence, vec!["high", "medium", "low"]);
802 }
803
804 #[test]
805 fn test_dual_ring_top_influential() {
806 let nodes = vec![
807 DualRingNode::new(0, "a", 0.2),
808 DualRingNode::new(1, "b", 0.8),
809 DualRingNode::new(2, "c", 0.5),
810 DualRingNode::new(3, "d", 0.9),
811 DualRingNode::new(4, "e", 0.1),
812 ];
813
814 let dual = DualRing::new(nodes);
815
816 let top2: Vec<_> = dual.top_influential(2).map(|n| n.value).collect();
817 assert_eq!(top2, vec!["d", "b"]); }
819
820 #[test]
821 fn test_dual_ring_influence_rank() {
822 let nodes = vec![
823 DualRingNode::new(0, "a", 0.1),
824 DualRingNode::new(1, "b", 0.9),
825 DualRingNode::new(2, "c", 0.5),
826 ];
827
828 let dual = DualRing::new(nodes);
829
830 assert_eq!(dual.influence_rank_of(1), 0);
832 assert_eq!(dual.influence_rank_of(2), 1);
834 assert_eq!(dual.influence_rank_of(0), 2);
836 }
837
838 #[test]
839 fn test_dual_ring_temporal_distance() {
840 let nodes: Vec<DualRingNode<i32>> = (0..5)
841 .map(|i| DualRingNode::new(i, i as i32, 0.5))
842 .collect();
843
844 let dual = DualRing::new(nodes);
845
846 assert_eq!(dual.temporal_distance(0, 1), 1);
847 assert_eq!(dual.temporal_distance(0, 4), 1); assert_eq!(dual.temporal_distance(0, 2), 2);
849 }
850
851 #[test]
852 fn test_dual_ring_influence_distance() {
853 let nodes = vec![
854 DualRingNode::new(0, "a", 0.1), DualRingNode::new(1, "b", 0.9), DualRingNode::new(2, "c", 0.5), ];
858
859 let dual = DualRing::new(nodes);
860
861 assert_eq!(dual.influence_distance(1, 2), 1);
863 assert_eq!(dual.influence_distance(1, 0), 1); }
866
867 #[test]
868 fn test_dual_ring_temporal_neighbors() {
869 let nodes: Vec<DualRingNode<i32>> = (0..5)
870 .map(|i| DualRingNode::new(i, i as i32, 0.5))
871 .collect();
872
873 let dual = DualRing::new(nodes);
874
875 let neighbors: Vec<_> = dual.temporal_neighbors(0, 1).map(|n| n.value).collect();
877 assert_eq!(neighbors.len(), 2);
878 assert!(neighbors.contains(&4));
879 assert!(neighbors.contains(&1));
880 }
881
882 #[test]
883 fn test_dual_ring_update_influence() {
884 let nodes = vec![
885 DualRingNode::new(0, "a", 0.1),
886 DualRingNode::new(1, "b", 0.9),
887 DualRingNode::new(2, "c", 0.5),
888 ];
889
890 let mut dual = DualRing::new(nodes);
891
892 assert_eq!(dual.get_by_influence_rank(0).value, "b");
894
895 dual.update_influence(0, 0.99);
897
898 assert_eq!(dual.get_by_influence_rank(0).value, "a");
900 }
901
902 #[test]
903 fn test_dual_ring_influence_temporal_spread() {
904 let clustered = vec![
907 DualRingNode::new(0, "a", 0.95), DualRingNode::new(1, "b", 0.90), DualRingNode::new(2, "c", 0.85), DualRingNode::new(3, "d", 0.80), DualRingNode::new(4, "e", 0.75), DualRingNode::new(5, "f", 0.10), DualRingNode::new(6, "g", 0.10), ];
915 let dual_clustered = DualRing::new(clustered);
916 let spread = vec![
920 DualRingNode::new(0, "a", 0.95), DualRingNode::new(1, "b", 0.10), DualRingNode::new(2, "c", 0.90), DualRingNode::new(3, "d", 0.10), DualRingNode::new(4, "e", 0.85), DualRingNode::new(5, "f", 0.10), DualRingNode::new(6, "g", 0.80), ];
928 let dual_spread = DualRing::new(spread);
929 assert!(
933 dual_spread.influence_temporal_spread() >= dual_clustered.influence_temporal_spread(),
934 "spread={}, clustered={}",
935 dual_spread.influence_temporal_spread(),
936 dual_clustered.influence_temporal_spread()
937 );
938 }
939
940 #[test]
941 fn test_build_dual_ring() {
942 let episodes = vec!["a", "b", "c"];
943 let influences = vec![0.3, 0.9, 0.5];
944
945 let dual = build_dual_ring(episodes, &influences);
946
947 assert_eq!(dual.len(), 3);
948 assert_eq!(dual.get_temporal(0).value, "a");
949 assert!((dual.get_temporal(1).influence - 0.9).abs() < 1e-6);
950 }
951
952 #[test]
953 fn test_build_dual_ring_with_attention() {
954 let episodes = vec!["a", "b"];
955 let influences = vec![0.5, 0.8];
956 let received = vec![0.3, 0.7];
957 let given = vec![0.4, 0.6];
958
959 let dual = build_dual_ring_with_attention(episodes, &influences, &received, &given);
960
961 assert_eq!(dual.len(), 2);
962 assert!((dual.get_temporal(0).attention_received - 0.3).abs() < 1e-6);
963 assert!((dual.get_temporal(1).attention_given - 0.6).abs() < 1e-6);
964 }
965}