use crate::lattice::Lattice;
#[derive(Clone, Debug)]
pub struct Activity {
pub values: Vec<f64>,
}
impl Activity {
#[must_use]
pub fn new(sites: usize) -> Self {
Self {
values: vec![0.0; sites],
}
}
#[must_use]
pub fn is_quiet(&self) -> bool {
self.values.iter().all(|&v| v <= 0.0)
}
pub fn decay(&mut self) {
for value in &mut self.values {
if *value > 0.0 {
*value -= 1.0;
}
}
}
pub fn refresh(&mut self, site: usize, max_activity: f64) {
self.values[site] = max_activity;
}
#[must_use]
pub fn neighbourhood_mean(&self, lattice: &Lattice, site: usize, label: u32) -> f64 {
let (x, y, z) = lattice.coords(site);
let mut log_sum = self.values[site].max(0.0).ln();
let mut count = 1.0f64;
for &(dx, dy, dz) in &lattice.offsets {
let n = lattice.index(x + dx, y + dy, z + dz);
if n == site || lattice.labels[n] != label {
continue;
}
let value = self.values[n];
if value <= 0.0 {
return 0.0;
}
log_sum += value.ln();
count += 1.0;
}
if !log_sum.is_finite() {
return 0.0;
}
(log_sum / count).exp()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn two_cell_lattice() -> Lattice {
let mut lattice = Lattice::medium(8, 8, 1, 2);
for x in 0..4 {
for y in 0..8 {
let index = lattice.index(x, y, 0);
lattice.labels[index] = 1;
}
}
lattice
}
#[test]
fn decay_takes_one_step_and_stops_at_nothing() {
let mut activity = Activity::new(4);
activity.refresh(0, 2.0);
activity.decay();
assert_eq!(activity.values[0], 1.0);
activity.decay();
activity.decay();
assert_eq!(activity.values[0], 0.0);
}
#[test]
fn a_forgotten_neighbour_takes_the_mean_to_nothing() {
let lattice = two_cell_lattice();
let mut activity = Activity::new(lattice.len());
let site = lattice.index(1, 4, 0);
activity.refresh(site, 10.0);
assert_eq!(activity.neighbourhood_mean(&lattice, site, 1), 0.0);
}
#[test]
fn a_uniformly_remembered_cell_reads_its_own_value() {
let lattice = two_cell_lattice();
let mut activity = Activity::new(lattice.len());
for (site, &label) in lattice.labels.iter().enumerate() {
if label == 1 {
activity.refresh(site, 7.0);
}
}
let site = lattice.index(1, 4, 0);
assert!((activity.neighbourhood_mean(&lattice, site, 1) - 7.0).abs() < 1e-9);
}
#[test]
fn the_mean_sits_between_the_values_it_reads() {
let lattice = two_cell_lattice();
let mut activity = Activity::new(lattice.len());
for (site, &label) in lattice.labels.iter().enumerate() {
if label == 1 {
activity.refresh(site, 4.0);
}
}
let site = lattice.index(1, 4, 0);
activity.refresh(site, 16.0);
let mean = activity.neighbourhood_mean(&lattice, site, 1);
assert!(mean > 4.0 && mean < 16.0, "{mean}");
}
#[test]
fn a_quiet_lattice_says_so() {
let mut activity = Activity::new(4);
assert!(activity.is_quiet());
activity.refresh(2, 1.0);
assert!(!activity.is_quiet());
}
}