forceatlas2 0.8.0

fast force-directed generic n-dimension graph layout
Documentation
use crate::util::*;

use num_traits::Zero;
use rayon::prelude::*;

/// Graph vertex without position nor speed
#[derive(Clone, Debug)]
pub struct AbstractNode<T> {
	/// Radius
	pub size: T,
	/// Mass
	pub mass: T,
}

impl<T: Coord> Default for AbstractNode<T> {
	fn default() -> Self {
		AbstractNode {
			size: T::one(),
			mass: T::one(),
		}
	}
}

/// Graph vertex positioned in the layout
#[derive(Clone, Debug)]
pub struct Node<T, const N: usize> {
	/// Position
	pub pos: VecN<T, N>,
	/// Current speed
	pub speed: VecN<T, N>,
	/// Speed at previous iteration
	pub old_speed: VecN<T, N>,
	/// Radius
	pub size: T,
	/// Mass
	pub mass: T,
}

impl<T: Coord, const N: usize> Node<T, N> {
	/// Strip spatial data off the node
	pub fn to_abstract(&self) -> AbstractNode<T> {
		AbstractNode {
			size: self.size,
			mass: self.mass,
		}
	}
}

impl<T: Coord, const N: usize> Default for Node<T, N> {
	fn default() -> Self {
		Node {
			pos: Zero::zero(),
			speed: Zero::zero(),
			old_speed: Zero::zero(),
			size: T::one(),
			mass: T::one(),
		}
	}
}

/// Collection of nodes for the layout
pub trait Nodes<T, const N: usize, Id> {
	/// Create an iterator through the nodes
	fn iter_nodes<'a>(&'a self) -> impl Iterator<Item = &'a Node<T, N>>
	where
		T: 'a;
	/// Create a mutable iterator through the nodes
	fn iter_nodes_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut Node<T, N>>
	where
		T: 'a;
	/// Create a mutable parallel iterator through the nodes
	fn par_iter_nodes_mut<'a>(&'a mut self) -> impl ParallelIterator<Item = &'a mut Node<T, N>>
	where
		T: 'a + Send,
		Id: Sync;
	/// Get mutable references to 2 distinct nodes
	fn get_2_mut(&mut self, i1: Id, i2: Id) -> (&mut Node<T, N>, &mut Node<T, N>);
	/// Get the number of nodes
	fn len(&self) -> usize;
	/// Is length zero?
	fn is_empty(&self) -> bool {
		self.len() == 0
	}
}

/// Collection of nodes for the layout, stored in a Vec
///
/// Nodes are indexed by their position in the Vec.
/// Beware that removing a node would shift all subsequent nodes' indices, thus would imply updating the edges.
pub type NodeVec<T, const N: usize> = Vec<Node<T, N>>;

impl<T: Clone, const N: usize> Nodes<T, N, usize> for NodeVec<T, N> {
	fn iter_nodes<'a>(&'a self) -> impl Iterator<Item = &'a Node<T, N>>
	where
		T: 'a,
	{
		self.iter()
	}
	fn iter_nodes_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut Node<T, N>>
	where
		T: 'a,
	{
		self.iter_mut()
	}
	fn par_iter_nodes_mut<'a>(&'a mut self) -> impl ParallelIterator<Item = &'a mut Node<T, N>>
	where
		T: 'a + Send,
	{
		self.par_iter_mut()
	}
	fn get_2_mut(&mut self, i1: usize, i2: usize) -> (&mut Node<T, N>, &mut Node<T, N>) {
		let (i1, i2) = if i1 < i2 { (i1, i2) } else { (i2, i1) };
		let (s1, s2) = self.split_at_mut(i2);
		(&mut s1[i1], &mut s2[0])
	}
	fn len(&self) -> usize {
		self.len()
	}
}

/// Collection of nodes for the layout, stored in a HashMap
pub type NodeHashMap<T, const N: usize, Id> = std::collections::HashMap<Id, Node<T, N>>;

impl<T: Clone, const N: usize, Id: Eq + std::hash::Hash> Nodes<T, N, Id> for NodeHashMap<T, N, Id> {
	fn iter_nodes<'a>(&'a self) -> impl Iterator<Item = &'a Node<T, N>>
	where
		T: 'a,
	{
		self.values()
	}
	fn iter_nodes_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut Node<T, N>>
	where
		T: 'a,
	{
		self.values_mut()
	}
	fn par_iter_nodes_mut<'a>(&'a mut self) -> impl ParallelIterator<Item = &'a mut Node<T, N>>
	where
		T: 'a + Send,
		Id: Sync,
	{
		self.par_iter_mut().map(|(_id, node)| node)
	}
	fn get_2_mut(&mut self, i1: Id, i2: Id) -> (&mut Node<T, N>, &mut Node<T, N>) {
		let [n1, n2] = self.get_disjoint_mut([&i1, &i2]);
		(n1.unwrap(), n2.unwrap())
	}
	fn len(&self) -> usize {
		self.len()
	}
}

/// Collection of nodes that can be built node by node
pub trait BuildableNodes<T, const N: usize, Id> {
	/// Add a node the the collection
	fn add_node(&mut self, id: Id, node: Node<T, N>);
}

impl<T: Clone, const N: usize> BuildableNodes<T, N, usize> for NodeVec<T, N> {
	/// Panics if `id` is not the collection's length
	fn add_node(&mut self, id: usize, node: Node<T, N>) {
		assert_eq!(id, self.len(), "not contiguous node id");
		self.push(node);
	}
}

impl<T: Clone, const N: usize, Id: Eq + std::hash::Hash> BuildableNodes<T, N, Id>
	for NodeHashMap<T, N, Id>
{
	fn add_node(&mut self, id: Id, node: Node<T, N>) {
		if self.insert(id, node).is_some() {
			panic!("node id already exists");
		}
	}
}