use super::transaction::TransactionResult;
use crate::collections::graphs::GraphTransaction;
use crate::collections::{Direction, GraphNode};
use crate::{GraphIterator, NodeType};
use radiate_core::Valid;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::fmt::Debug;
use std::hash::Hash;
use std::ops::{Index, IndexMut};
#[derive(Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Graph<T> {
nodes: Vec<GraphNode<T>>,
}
impl<T> Graph<T> {
pub fn new(nodes: Vec<GraphNode<T>>) -> Self {
Graph { nodes }
}
pub fn take_nodes(&mut self) -> Vec<GraphNode<T>> {
std::mem::take(&mut self.nodes)
}
pub fn push(&mut self, node: impl Into<GraphNode<T>>) {
self.nodes.push(node.into());
}
pub fn insert(&mut self, node_type: NodeType, val: T) -> usize {
self.push((self.len(), node_type, val));
self.len() - 1
}
pub fn pop(&mut self) -> Option<GraphNode<T>> {
self.nodes.pop()
}
pub fn len(&self) -> usize {
self.nodes.len()
}
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut GraphNode<T>> {
self.nodes.get_mut(index)
}
pub fn get(&self, index: usize) -> Option<&GraphNode<T>> {
self.nodes.get(index)
}
pub fn iter(&self) -> impl Iterator<Item = &GraphNode<T>> {
self.nodes.iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut GraphNode<T>> {
self.nodes.iter_mut()
}
pub fn inputs(&self) -> impl Iterator<Item = &GraphNode<T>> {
self.get_nodes_of_type(NodeType::Input)
}
pub fn outputs(&self) -> impl Iterator<Item = &GraphNode<T>> {
self.get_nodes_of_type(NodeType::Output)
}
pub fn vertices(&self) -> impl Iterator<Item = &GraphNode<T>> {
self.get_nodes_of_type(NodeType::Vertex)
}
pub fn edges(&self) -> impl Iterator<Item = &GraphNode<T>> {
self.get_nodes_of_type(NodeType::Edge)
}
pub fn attach(&mut self, incoming: usize, outgoing: usize) -> &mut Self {
self.as_mut()[incoming].insert_outgoing(outgoing);
self.as_mut()[outgoing].insert_incoming(incoming);
self
}
pub fn detach(&mut self, incoming: usize, outgoing: usize) -> &mut Self {
self.as_mut()[incoming].remove_outgoing(&outgoing);
self.as_mut()[outgoing].remove_incoming(&incoming);
self
}
#[inline]
pub fn try_modify<F>(&mut self, mutation: F) -> TransactionResult<T>
where
F: FnOnce(GraphTransaction<T>) -> TransactionResult<T>,
T: Clone,
{
mutation(GraphTransaction::new(self))
}
#[inline]
pub fn set_cycles(&mut self, indecies: Vec<usize>) {
if indecies.is_empty() {
let all_indices = self
.as_ref()
.iter()
.map(|node| node.index())
.collect::<Vec<usize>>();
return self.set_cycles(all_indices);
}
for idx in indecies {
let cycles = self.get_cycles(idx);
if cycles.is_empty() {
if let Some(node) = self.get_mut(idx) {
node.set_direction(Direction::Forward);
}
} else {
for cycle in cycles {
if let Some(node) = self.get_mut(cycle) {
node.set_direction(Direction::Backward);
}
}
}
}
}
#[inline]
pub fn get_cycles(&self, from: usize) -> std::collections::HashSet<usize> {
let n = self.len();
let mut on_stack = vec![false; n];
let mut visited = vec![false; n];
let mut cycles = vec![false; n];
let mut stack = Vec::with_capacity(n.min(64));
fn dfs<T>(
g: &Graph<T>,
u: usize,
visited: &mut [bool],
on_stack: &mut [bool],
cycles: &mut [bool],
stack: &mut Vec<usize>,
) {
visited[u] = true;
on_stack[u] = true;
stack.push(u);
for &v in g.get(u).unwrap().outgoing() {
if !visited[v] {
dfs(g, v, visited, on_stack, cycles, stack);
} else if on_stack[v] {
let start = stack.iter().rposition(|&x| x == v).unwrap();
for &w in &stack[start..] {
cycles[w] = true;
}
}
}
stack.pop();
on_stack[u] = false;
}
dfs(
self,
from,
&mut visited,
&mut on_stack,
&mut cycles,
&mut stack,
);
let mut out = HashSet::with_capacity(stack.len());
for (i, &c) in cycles.iter().enumerate() {
if c {
out.insert(i);
}
}
out
}
}
impl<T> Valid for Graph<T> {
#[inline]
fn is_valid(&self) -> bool {
self.iter().all(|node| node.is_valid())
}
}
impl<T> AsRef<[GraphNode<T>]> for Graph<T> {
fn as_ref(&self) -> &[GraphNode<T>] {
&self.nodes
}
}
impl<T> AsMut<[GraphNode<T>]> for Graph<T> {
fn as_mut(&mut self) -> &mut [GraphNode<T>] {
&mut self.nodes
}
}
impl<T> Index<usize> for Graph<T> {
type Output = GraphNode<T>;
fn index(&self, index: usize) -> &Self::Output {
&self.nodes[index]
}
}
impl<T> IndexMut<usize> for Graph<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.nodes[index]
}
}
impl<T> IntoIterator for Graph<T> {
type Item = GraphNode<T>;
type IntoIter = std::vec::IntoIter<GraphNode<T>>;
fn into_iter(self) -> Self::IntoIter {
self.nodes.into_iter()
}
}
impl<T> FromIterator<GraphNode<T>> for Graph<T> {
fn from_iter<I: IntoIterator<Item = GraphNode<T>>>(iter: I) -> Self {
Graph {
nodes: iter.into_iter().collect(),
}
}
}
impl<T> Default for Graph<T> {
fn default() -> Self {
Graph { nodes: Vec::new() }
}
}
impl<T: Hash> Hash for Graph<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
for node in self.as_ref() {
node.hash(state);
}
}
}
impl<T: Debug> Debug for Graph<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Graph {{\n")?;
for node in self.as_ref() {
write!(f, " {:?},\n", node)?;
}
write!(f, "}}")
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{Arity, Node, Op};
#[test]
fn test_graph_is_valid() {
let mut graph_one = Graph::default();
graph_one.push((0, NodeType::Input, 123));
graph_one.push((1, NodeType::Output, 42));
graph_one.attach(0, 1);
let mut graph_two = Graph::default();
graph_two.push((0, NodeType::Input, 0));
graph_two.push((1, NodeType::Vertex, 1));
assert!(graph_one.is_valid());
assert!(!graph_two.is_valid());
}
#[test]
fn test_graph_attach() {
let mut graph = Graph::default();
graph.push((0, NodeType::Input, 0));
graph.push((1, NodeType::Output, 1));
graph.attach(0, 1);
assert_eq!(graph[0].outgoing(), &[1]);
assert_eq!(graph[1].incoming(), &[0]);
}
#[test]
fn test_graph_node_creations() {
let mut graph_one = Graph::from_iter(vec![
GraphNode::new(0, NodeType::Input, 0),
GraphNode::new(1, NodeType::Vertex, 1),
GraphNode::new(2, NodeType::Output, 1),
]);
graph_one.attach(0, 1).attach(1, 2);
assert_eq!(graph_one.len(), 3);
assert!(graph_one.is_valid());
assert_eq!(graph_one[0].arity(), Arity::Zero);
assert_eq!(graph_one[1].arity(), Arity::Any);
assert_eq!(graph_one[2].arity(), Arity::Any);
let mut graph_two = Graph::new(vec![
GraphNode::new(0, NodeType::Input, Op::var(0)),
GraphNode::new(1, NodeType::Input, Op::constant(5.0)),
GraphNode::with_arity(2, NodeType::Vertex, Op::add(), Arity::Exact(2)),
GraphNode::new(3, NodeType::Output, Op::linear()),
]);
graph_two.attach(0, 2).attach(1, 2).attach(2, 3);
assert_eq!(graph_two.len(), 4);
assert!(graph_two.is_valid());
assert_eq!(graph_two[0].arity(), Arity::Zero);
assert_eq!(graph_two[1].arity(), Arity::Zero);
assert_eq!(graph_two[2].arity(), Arity::Exact(2));
assert_eq!(graph_two[3].arity(), Arity::Any);
}
#[test]
fn test_simple_graph() {
let mut graph = Graph::<i32>::default();
let idx_one = graph.insert(NodeType::Input, 0);
let idx_two = graph.insert(NodeType::Vertex, 1);
let idx_three = graph.insert(NodeType::Output, 2);
graph.attach(idx_one, idx_two).attach(idx_two, idx_three);
assert_eq!(graph.len(), 3);
assert!(graph.is_valid());
assert!(graph[0].is_valid());
assert!(graph[1].is_valid());
assert!(graph[2].is_valid());
assert_eq!(graph[0].incoming().len(), 0);
assert_eq!(graph[0].outgoing().len(), 1);
assert_eq!(graph[1].incoming().len(), 1);
assert_eq!(graph[1].outgoing().len(), 1);
assert_eq!(graph[2].incoming().len(), 1);
assert_eq!(graph[2].outgoing().len(), 0);
}
#[test]
fn test_graph_with_cycles() {
let mut graph = Graph::<i32>::default();
graph.insert(NodeType::Input, 0);
graph.insert(NodeType::Vertex, 1);
graph.insert(NodeType::Vertex, 2);
graph.insert(NodeType::Output, 3);
graph.attach(0, 1).attach(1, 2).attach(2, 1).attach(2, 3);
assert_eq!(graph.len(), 4);
assert!(graph.is_valid());
assert!(graph[0].is_valid());
assert!(graph[1].is_valid());
assert!(graph[2].is_valid());
assert!(graph[3].is_valid());
assert_eq!(graph[0].incoming().len(), 0);
assert_eq!(graph[0].outgoing().len(), 1);
assert_eq!(graph[1].incoming().len(), 2);
assert_eq!(graph[1].outgoing().len(), 1);
assert_eq!(graph[2].incoming().len(), 1);
assert_eq!(graph[2].outgoing().len(), 2);
assert_eq!(graph[3].incoming().len(), 1);
assert_eq!(graph[3].outgoing().len(), 0);
}
#[test]
fn test_graph_with_cycles_and_recurrent_nodes() {
let mut graph = Graph::<i32>::default();
let idx_one = graph.insert(NodeType::Input, 0);
let idx_two = graph.insert(NodeType::Vertex, 1);
let idx_three = graph.insert(NodeType::Vertex, 2);
let idx_four = graph.insert(NodeType::Output, 3);
graph
.attach(idx_one, idx_two)
.attach(idx_two, idx_three)
.attach(idx_three, idx_two)
.attach(idx_three, idx_four)
.attach(idx_four, idx_two);
graph.set_cycles(vec![]);
assert_eq!(graph.len(), 4);
assert!(graph.is_valid());
assert!(graph[0].is_valid());
assert!(graph[1].is_valid());
assert!(graph[2].is_valid());
assert!(graph[3].is_valid());
assert_eq!(graph[0].incoming().len(), 0);
assert_eq!(graph[0].outgoing().len(), 1);
assert_eq!(graph[1].incoming().len(), 3);
assert_eq!(graph[1].outgoing().len(), 1);
assert_eq!(graph[2].incoming().len(), 1);
assert_eq!(graph[2].outgoing().len(), 2);
assert_eq!(graph[3].incoming().len(), 1);
assert_eq!(graph[3].outgoing().len(), 1);
assert_eq!(graph[0].direction(), Direction::Forward);
assert_eq!(graph[1].direction(), Direction::Backward);
assert_eq!(graph[2].direction(), Direction::Backward);
assert_eq!(graph[3].direction(), Direction::Backward);
}
#[test]
fn test_graph_set_cycles() {
let mut graph = Graph::<i32>::default();
let idx_one = graph.insert(NodeType::Input, 0);
let idx_two = graph.insert(NodeType::Vertex, 1);
let idx_three = graph.insert(NodeType::Vertex, 2);
let idx_four = graph.insert(NodeType::Output, 3);
graph
.attach(idx_one, idx_two)
.attach(idx_two, idx_three)
.attach(idx_three, idx_two)
.attach(idx_two, idx_four);
for node in graph.iter() {
assert!(node.is_valid());
assert_eq!(node.direction(), Direction::Forward);
}
graph.set_cycles(vec![]);
for node in graph.iter() {
assert!(node.is_valid());
if node.node_type() == NodeType::Vertex {
assert_eq!(node.direction(), Direction::Backward);
} else {
assert_eq!(node.direction(), Direction::Forward);
}
}
}
#[test]
fn test_graph_clone_and_partial_eq() {
let mut graph1 = Graph::default();
let input_idx = graph1.insert(NodeType::Input, 42);
let output_idx = graph1.insert(NodeType::Output, 24);
graph1.attach(input_idx, output_idx);
let graph2 = graph1.clone();
assert_eq!(graph1, graph2);
let mut graph3 = graph1.clone();
graph3[input_idx].set_direction(Direction::Backward);
assert_ne!(graph1, graph3);
let mut graph4 = graph1.clone();
if let Some(node) = graph4.get_mut(input_idx) {
*node.value_mut() = 100;
}
assert_ne!(graph1, graph4);
}
#[test]
fn test_graph_arity_validation() {
let mut graph = Graph::default();
let input_idx = graph.insert(NodeType::Input, 0);
graph.push((1, NodeType::Vertex, 1, Arity::Exact(2)));
let output_idx = graph.insert(NodeType::Output, 2);
graph.attach(input_idx, 1);
graph.attach(1, output_idx);
assert!(!graph.is_valid());
graph.attach(input_idx, 1);
assert!(!graph.is_valid());
let input3_idx = graph.insert(NodeType::Input, 3);
graph.attach(input3_idx, 1);
println!("{:?}", graph);
assert!(graph.is_valid());
}
#[test]
fn test_graph_indexing() {
let mut graph = Graph::default();
let input_idx = graph.insert(NodeType::Input, 42);
let output_idx = graph.insert(NodeType::Output, 24);
assert_eq!(graph[input_idx].value(), &42);
assert_eq!(graph[output_idx].value(), &24);
graph[input_idx].set_direction(Direction::Backward);
assert_eq!(graph[input_idx].direction(), Direction::Backward);
assert_eq!(graph.get(input_idx).unwrap().value(), &42);
assert_eq!(graph.get_mut(output_idx).unwrap().value(), &24);
assert!(graph.get(999).is_none());
assert!(graph.get_mut(999).is_none());
}
#[test]
fn test_graph_node_type_queries() {
let mut graph = Graph::default();
graph.insert(NodeType::Input, 0);
graph.insert(NodeType::Input, 1);
graph.insert(NodeType::Vertex, 2);
graph.insert(NodeType::Vertex, 3);
graph.insert(NodeType::Output, 4);
graph.insert(NodeType::Output, 5);
let inputs = graph.inputs().collect::<Vec<_>>();
assert_eq!(inputs.len(), 2);
assert!(
inputs
.iter()
.all(|node| node.node_type() == NodeType::Input)
);
let vertices = graph.vertices().collect::<Vec<_>>();
assert_eq!(vertices.len(), 2);
assert!(
vertices
.iter()
.all(|node| node.node_type() == NodeType::Vertex)
);
let outputs = graph.outputs().collect::<Vec<_>>();
assert_eq!(outputs.len(), 2);
assert!(
outputs
.iter()
.all(|node| node.node_type() == NodeType::Output)
);
}
#[test]
fn test_graph_iterators() {
let mut graph = Graph::default();
let input_idx = graph.insert(NodeType::Input, 0);
let vertex_idx = graph.insert(NodeType::Vertex, 1);
let output_idx = graph.insert(NodeType::Output, 2);
graph.attach(input_idx, vertex_idx);
graph.attach(vertex_idx, output_idx);
let nodes: Vec<_> = graph.iter().collect();
assert_eq!(nodes.len(), 3);
assert_eq!(nodes[0].value(), &0);
assert_eq!(nodes[1].value(), &1);
assert_eq!(nodes[2].value(), &2);
for node in graph.iter_mut() {
if node.node_type() == NodeType::Vertex {
node.set_direction(Direction::Backward);
}
}
assert_eq!(graph[vertex_idx].direction(), Direction::Backward);
let values: Vec<_> = graph.into_iter().map(|node| *node.value()).collect();
assert_eq!(values, vec![0, 1, 2]);
}
#[test]
fn test_graph_detach() {
let mut graph = Graph::default();
let input_idx = graph.insert(NodeType::Input, 0);
let output_idx = graph.insert(NodeType::Output, 1);
graph.attach(input_idx, output_idx);
assert!(graph[input_idx].outgoing().contains(&output_idx));
assert!(graph[output_idx].incoming().contains(&input_idx));
graph.detach(input_idx, output_idx);
assert!(!graph[input_idx].outgoing().contains(&output_idx));
assert!(!graph[output_idx].incoming().contains(&input_idx));
graph.detach(input_idx, output_idx); }
#[test]
#[cfg(feature = "serde")]
fn test_graph_eval_serde() {
use crate::Eval;
let mut graph = Graph::default();
graph.insert(NodeType::Input, 0);
graph.insert(NodeType::Vertex, 1);
graph.insert(NodeType::Output, 2);
graph.attach(0, 1);
graph.attach(1, 2);
let serialized = serde_json::to_string(&graph).unwrap();
let deserialized: Graph<i32> = serde_json::from_str(&serialized).unwrap();
assert_eq!(graph, deserialized);
let values = vec![
(NodeType::Input, vec![Op::var(0), Op::var(1)]),
(NodeType::Edge, vec![Op::weight()]),
(NodeType::Vertex, vec![Op::sub(), Op::mul(), Op::linear()]),
(NodeType::Output, vec![Op::linear()]),
];
let op_graph = Graph::directed(2, 2, values);
let eval_one = op_graph.eval(&vec![vec![0.5, 1.5]]);
let serialized_op = serde_json::to_string(&op_graph).unwrap();
let deserialized_op: Graph<Op<f32>> = serde_json::from_str(&serialized_op).unwrap();
let deserialized_eval = deserialized_op.eval(&vec![vec![0.5, 1.5]]);
assert_eq!(eval_one, deserialized_eval);
assert_eq!(op_graph, deserialized_op);
}
#[test]
#[cfg(feature = "serde")]
fn test_graph_pre_built_serde() {
use crate::Eval;
let mut graph = Graph::<Op<f32>>::default();
let idx_one = graph.insert(NodeType::Input, Op::var(0));
let idx_two = graph.insert(NodeType::Input, Op::constant(5_f32));
let idx_three = graph.insert(NodeType::Vertex, Op::add());
let idx_four = graph.insert(NodeType::Output, Op::linear());
graph
.attach(idx_one, idx_three)
.attach(idx_two, idx_three)
.attach(idx_three, idx_four);
let eval_to_six_one = graph.eval(&vec![vec![1_f32]]);
let eval_to_seven_one = graph.eval(&vec![vec![2_f32]]);
let eval_to_eight_one = graph.eval(&vec![vec![3_f32]]);
assert_eq!(eval_to_six_one, &[&[6_f32]]);
assert_eq!(eval_to_seven_one, &[&[7_f32]]);
assert_eq!(eval_to_eight_one, &[&[8_f32]]);
assert_eq!(graph.len(), 4);
let serialized = serde_json::to_string(&graph).unwrap();
let deserialized: Graph<Op<f32>> = serde_json::from_str(&serialized).unwrap();
assert_eq!(graph, deserialized);
let eval_to_six_two = deserialized.eval(&vec![vec![1_f32]]);
let eval_to_seven_two = deserialized.eval(&vec![vec![2_f32]]);
let eval_to_eight_two = deserialized.eval(&vec![vec![3_f32]]);
assert_eq!(eval_to_six_two, &[&[6_f32]]);
assert_eq!(eval_to_seven_two, &[&[7_f32]]);
assert_eq!(eval_to_eight_two, &[&[8_f32]]);
assert_eq!(deserialized.len(), 4);
}
}