1use crate::lattice::Lattice;
15
16#[derive(Clone, Debug)]
18pub struct Activity {
19 pub values: Vec<f64>,
21}
22
23impl Activity {
24 #[must_use]
26 pub fn new(sites: usize) -> Self {
27 Self {
28 values: vec![0.0; sites],
29 }
30 }
31
32 #[must_use]
34 pub fn is_quiet(&self) -> bool {
35 self.values.iter().all(|&v| v <= 0.0)
36 }
37
38 pub fn decay(&mut self) {
40 for value in &mut self.values {
41 if *value > 0.0 {
42 *value -= 1.0;
43 }
44 }
45 }
46
47 pub fn refresh(&mut self, site: usize, max_activity: f64) {
49 self.values[site] = max_activity;
50 }
51
52 #[must_use]
58 pub fn neighbourhood_mean(&self, lattice: &Lattice, site: usize, label: u32) -> f64 {
59 let (x, y, z) = lattice.coords(site);
60 let mut log_sum = self.values[site].max(0.0).ln();
61 let mut count = 1.0f64;
62 for &(dx, dy, dz) in &lattice.offsets {
63 let n = lattice.index(x + dx, y + dy, z + dz);
64 if n == site || lattice.labels[n] != label {
65 continue;
66 }
67 let value = self.values[n];
68 if value <= 0.0 {
69 return 0.0;
70 }
71 log_sum += value.ln();
72 count += 1.0;
73 }
74 if !log_sum.is_finite() {
75 return 0.0;
76 }
77 (log_sum / count).exp()
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 fn two_cell_lattice() -> Lattice {
86 let mut lattice = Lattice::medium(8, 8, 1, 2);
87 for x in 0..4 {
88 for y in 0..8 {
89 let index = lattice.index(x, y, 0);
90 lattice.labels[index] = 1;
91 }
92 }
93 lattice
94 }
95
96 #[test]
97 fn decay_takes_one_step_and_stops_at_nothing() {
98 let mut activity = Activity::new(4);
99 activity.refresh(0, 2.0);
100 activity.decay();
101 assert_eq!(activity.values[0], 1.0);
102 activity.decay();
103 activity.decay();
104 assert_eq!(activity.values[0], 0.0);
105 }
106
107 #[test]
108 fn a_forgotten_neighbour_takes_the_mean_to_nothing() {
109 let lattice = two_cell_lattice();
110 let mut activity = Activity::new(lattice.len());
111 let site = lattice.index(1, 4, 0);
112 activity.refresh(site, 10.0);
113 assert_eq!(activity.neighbourhood_mean(&lattice, site, 1), 0.0);
114 }
115
116 #[test]
117 fn a_uniformly_remembered_cell_reads_its_own_value() {
118 let lattice = two_cell_lattice();
119 let mut activity = Activity::new(lattice.len());
120 for (site, &label) in lattice.labels.iter().enumerate() {
121 if label == 1 {
122 activity.refresh(site, 7.0);
123 }
124 }
125 let site = lattice.index(1, 4, 0);
126 assert!((activity.neighbourhood_mean(&lattice, site, 1) - 7.0).abs() < 1e-9);
127 }
128
129 #[test]
130 fn the_mean_sits_between_the_values_it_reads() {
131 let lattice = two_cell_lattice();
132 let mut activity = Activity::new(lattice.len());
133 for (site, &label) in lattice.labels.iter().enumerate() {
134 if label == 1 {
135 activity.refresh(site, 4.0);
136 }
137 }
138 let site = lattice.index(1, 4, 0);
139 activity.refresh(site, 16.0);
140 let mean = activity.neighbourhood_mean(&lattice, site, 1);
141 assert!(mean > 4.0 && mean < 16.0, "{mean}");
142 }
143
144 #[test]
145 fn a_quiet_lattice_says_so() {
146 let mut activity = Activity::new(4);
147 assert!(activity.is_quiet());
148 activity.refresh(2, 1.0);
149 assert!(!activity.is_quiet());
150 }
151}