use super::*;
use std::collections::VecDeque;
use std::sync::{Arc, RwLock};
pub struct Node<I: Input, S: Storage<Item = I>> {
pub weights: Vec<f64>,
pub error: f64,
pub total_hits: usize,
pub last_hits: VecDeque<usize>,
pub coordinate: Coordinate,
pub topology: Topology<I, S>,
pub storage: S,
pub creation_time: usize,
hit_memory_size: usize,
}
pub struct Topology<I: Input, S: Storage<Item = I>> {
pub dimension: usize,
pub right: Option<NodeLink<I, S>>,
pub left: Option<NodeLink<I, S>>,
pub up: Option<NodeLink<I, S>>,
pub down: Option<NodeLink<I, S>>,
}
pub type NodeLink<I, S> = Arc<RwLock<Node<I, S>>>;
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct Coordinate(pub i32, pub i32);
impl<I: Input, S: Storage<Item = I>> Node<I, S> {
pub fn new(coordinate: Coordinate, weights: &[f64], time: usize, hit_memory_size: usize, storage: S) -> Self {
Self {
weights: weights.to_vec(),
error: 0.0,
total_hits: 0,
last_hits: VecDeque::with_capacity(hit_memory_size + 1),
coordinate,
topology: Topology::empty(weights.len()),
storage,
creation_time: time,
hit_memory_size,
}
}
pub fn adjust(&mut self, target: &[f64], learning_rate: f64) {
debug_assert!(self.weights.len() == target.len());
for (idx, value) in target.iter().enumerate() {
self.weights[idx] += learning_rate * (*value - self.weights[idx]);
}
}
pub fn distance(&self, weights: &[f64]) -> f64 {
self.storage.distance(self.weights.as_slice(), weights)
}
pub fn new_hit(&mut self, time: usize) {
self.total_hits += 1;
if self.last_hits.get(0).map_or(true, |last_time| *last_time != time) {
self.last_hits.push_front(time);
self.last_hits.truncate(self.hit_memory_size);
}
}
pub fn is_old(&self, time: usize) -> bool {
(time as i32 - self.hit_memory_size as i32) > self.creation_time as i32
}
}
impl<I: Input, S: Storage<Item = I>> Clone for Topology<I, S> {
fn clone(&self) -> Self {
Self {
dimension: self.dimension,
right: self.right.clone(),
left: self.left.clone(),
up: self.up.clone(),
down: self.down.clone(),
}
}
}
impl<I: Input, S: Storage<Item = I>> Topology<I, S> {
pub fn empty(dimension: usize) -> Self {
Self { dimension, right: None, left: None, up: None, down: None }
}
pub fn neighbours(&self) -> impl Iterator<Item = &NodeLink<I, S>> {
TopologyIterator { topology: self, state: 0 }
}
pub fn is_boundary(&self) -> bool {
self.right.is_none() || self.left.is_none() || self.up.is_none() || self.down.is_none()
}
}
struct TopologyIterator<'a, I: Input, S: Storage<Item = I>> {
topology: &'a Topology<I, S>,
state: usize,
}
impl<'a, I: Input, S: Storage<Item = I>> TopologyIterator<'a, I, S> {
fn transition(&mut self, state: usize, node: Option<&'a NodeLink<I, S>>) -> Result<(), Option<&'a NodeLink<I, S>>> {
if self.state == state {
self.state = state + 1;
if node.is_some() {
return Err(node);
}
}
Ok(())
}
fn iterate(&mut self) -> Result<(), Option<&'a NodeLink<I, S>>> {
self.transition(0, self.topology.left.as_ref())?;
self.transition(1, self.topology.right.as_ref())?;
self.transition(2, self.topology.down.as_ref())?;
self.transition(3, self.topology.up.as_ref())?;
Ok(())
}
}
impl<'a, I: Input, S: Storage<Item = I>> Iterator for TopologyIterator<'a, I, S> {
type Item = &'a NodeLink<I, S>;
fn next(&mut self) -> Option<Self::Item> {
if let Err(node) = self.iterate() {
node
} else {
None
}
}
}