diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d54fa2f..14b4770 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,24 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Build - run: cargo build --verbose + run: cargo build --verbose --examples + - name: Run tests run: cargo test --verbose + + - name: Set up environment + run: | + sudo apt update + sudo apt install -y libev-dev valgrind + + - name: Run Tests with Valgrind + run: | + touch results + valgrind --leak-check=full --track-origins=yes -q ./target/debug/examples/dijkstra-shortest-path >> results + valgrind --leak-check=full --track-origins=yes -q ./target/debug/examples/serialization-example >> results + valgrind --leak-check=full --track-origins=yes -q ./target/debug/examples/edmonds-karp-maximum-flow >> results + valgrind --leak-check=full --track-origins=yes -q ./target/debug/examples/prim-minimum-spanning-tree >> results + valgrind --leak-check=full --track-origins=yes -q ./target/debug/examples/kojarasu-strongly-connected-components >> results + [ -s ./results ] && (cat ./results && exit -1) || echo "No leaks detected" \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index b6e9129..2b22f39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -189,7 +189,7 @@ checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "gdsl" -version = "0.1.0" +version = "0.1.1" dependencies = [ "ahash", "criterion", diff --git a/Cargo.toml b/Cargo.toml index b234d44..bdfd507 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,21 @@ [package] name = "gdsl" -version = "0.1.0" +version = "0.1.1" edition = "2021" readme = "README.md" license = "MIT/Apache-2.0" -authors = [ "juliuskoskela" ] +authors = ["Julius Koskela "] -description = "Graph Data Structure Library" +description = """ +GDSL is a graph data-structure library including graph containers, +connected node strutures and efficient algorithms on those structures. +Nodes are independent of a graph container and can be used as connected +smart pointers. +""" repository = "https://github.com/juliuskoskela/gdsl" keywords = ["data-structure", "graph", "algorithms", "containers", "graph-theory"] -categories = ["Data structures"] +categories = ["data-structure", "algorithms", "mathematics", "science"] [dependencies] min-max-heap = "1.3.0" diff --git a/README.md b/README.md index c7013b3..903881a 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ assert!(*n1 == 42); assert!(n2.key() == &'B'); // Get the next edge from the outbound iterator. -let (u, v, e) = n1.iter_out().next().unwrap(); +let Edge(u, v, e) = n1.iter_out().next().unwrap(); assert!(u.key() == &'A'); assert!(v == n2); @@ -70,12 +70,19 @@ inbound edges in case of a directed graph or adjacent edges in the case of an un graph. ```rust -for (u, v, e) in &node { + +// Edge is a tuple struct so can be decomposed using tuple syntax.. +for Edge(u, v, e) in &node { println!("{} -> {} : {}", u.key(), v.key(), e); } +// ..or used more conventionally as one type. +for edge in &node { + println!("{} -> {} : {}", edge.source().key(), edge.target().key(), edge.value()); +} + // Transposed iteration i.e. iterating the inbound edges of a node in digrap. -for (u, v, e) in node.iter_in() { +for Edge(v, u, e) in node.iter_in() { println!("{} <- {} : {}", u.key(), v.key(), e); } ``` @@ -240,14 +247,14 @@ g['A'].set(0); // by calling the `pfs()` method on the node. // // If we find a shorter distance to a node we are traversing, we need to -// update the distance of the node. We do this by using the `map()` method -// on the PFS search object. The `map()` method takes a closure as argument +// update the distance of the node. We do this by using the `for_each()` method +// on the PFS search object. The `for_each()` method takes a closure as argument // and calls it for each edge that is traversed. This way we can manipulate // the distance of the node. based on the edge that is traversed. // // The search-object evaluates lazily. This means that the search is only // executed when calling either `search()` or `search_path()`. -g['A'].pfs().map(&|u, v, e| { +g['A'].pfs().for_each(&mut |Edge(u, v, e)| { // Since we are using a `Cell` to store the distance we use `get()` to // read the distance values. diff --git a/examples/dijkstra.rs b/examples/dijkstra-shortest-path.rs similarity index 92% rename from examples/dijkstra.rs rename to examples/dijkstra-shortest-path.rs index 59f9973..5672d63 100644 --- a/examples/dijkstra.rs +++ b/examples/dijkstra-shortest-path.rs @@ -6,6 +6,7 @@ // https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm use gdsl::*; +use gdsl::digraph::*; use std::cell::Cell; fn main() { @@ -45,15 +46,14 @@ fn main() { // by calling the `pfs()` method on the node. // // If we find a shorter distance to a node we are traversing, we need to - // update the distance of the node. We do this by using the `map()` method - // on the PFS search object. The `map()` method takes a closure as argument + // update the distance of the node. We do this by using the `for_each()` method + // on the PFS search object. The `for_each()` method takes a closure as argument // and calls it for each edge that is traversed. This way we can manipulate // the distance of the node. based on the edge that is traversed. // // The search-object evaluates lazily. This means that the search is only // executed when calling either `search()` or `search_path()`. - g['A'].pfs().map(&|u, v, e| { - + g['A'].pfs().for_each(&mut |Edge(u, v, e)| { // Since we are using a `Cell` to store the distance we use `get()` to // read the distance values. let (u_dist, v_dist) = (u.get(), v.get()); diff --git a/examples/print_graph.rs b/examples/dot-printing-example.rs similarity index 100% rename from examples/print_graph.rs rename to examples/dot-printing-example.rs diff --git a/examples/edmonds-karp.rs b/examples/edmonds-karp-maximum-flow.rs similarity index 70% rename from examples/edmonds-karp.rs rename to examples/edmonds-karp-maximum-flow.rs index 082f2df..31eaadb 100644 --- a/examples/edmonds-karp.rs +++ b/examples/edmonds-karp-maximum-flow.rs @@ -70,20 +70,20 @@ fn max_flow(g: &G) -> u64 { .dfs() .target(&5) // 2. We exclude saturated edges from the search. - .filter(&|_, _, e| e.cur() < e.max()) + .filter(&mut |Edge(_, _, e)| e.cur() < e.max()) .search_path() { let mut aug_flow = std::u64::MAX; // 3. We find the minimum augmenting flow along the path. - for (_, _, flow) in path.iter_edges() { + for Edge(_, _, flow) in path.iter_edges() { if flow.max() - flow.cur() < aug_flow { aug_flow = flow.max() - flow.cur(); } } // 4. We update the flow along the path. - for (_, _, flow) in path.iter_edges() { + for Edge(_, _, flow) in path.iter_edges() { flow.update(aug_flow); } @@ -118,49 +118,4 @@ fn main() { // For this Graph we expect the maximum flow from 0 -> 5 to be 23 assert!(max_flow(&g) == 23); - - // print_flow_graph(&g); -} - -// fn attr(field: &str, value: &str) -> (String, String) { -// (field.to_string(), value.to_string()) -// } - -// pub const THEME: [&str; 5] = [ -// "#ffffff", // 0. background -// "#ffe5a9", // 1. medium -// "#423f3b", // 2. dark -// "#ff6666", // 3. accent -// "#525266", // 4. theme -// ]; - -// fn print_flow_graph(g: &G) { -// let dot_str = g.to_dot_with_attr( -// &|| { -// Some(vec![ -// attr("bgcolor", THEME[0]), -// attr("fontcolor", THEME[4]), -// attr("label", "Flow Graph"), -// ]) -// }, -// &|node| { -// Some(vec![ -// attr("fillcolor", THEME[1]), -// attr("fontcolor", THEME[4]), -// attr("label", &format!("{}", node.key())), -// ]) -// }, -// &|_, _, edge| { -// let Flow (max, cur) = edge.0.get(); -// let flow_str = format!("{}/{}", cur, max); -// let color = if cur == 0 { THEME[4] } else { THEME[3] }; -// Some(vec![ -// attr("fontcolor", THEME[4]), -// attr("label", &flow_str), -// attr("color", &color), -// ]) -// } -// ); - -// println!("{}", dot_str); -// } \ No newline at end of file +} \ No newline at end of file diff --git a/examples/kojarasu.rs b/examples/kojarasu-strongly-connected-components.rs similarity index 93% rename from examples/kojarasu.rs rename to examples/kojarasu-strongly-connected-components.rs index 01e4b76..cba2f07 100644 --- a/examples/kojarasu.rs +++ b/examples/kojarasu-strongly-connected-components.rs @@ -23,7 +23,7 @@ fn ordering(graph: &G) -> G { if !visited.contains(next.key()) { let partition = next .postorder() - .filter(&|_, v, _| !visited.contains(v.key())) + .filter(&mut |Edge(_, v, _)| !visited.contains(v.key())) .search_nodes(); for node in &partition { visited.insert(node.key().clone()); @@ -44,7 +44,7 @@ fn kojarasu(graph: &G) -> Vec { let cycle = node .dfs() .transpose() - .filter(&|_, v, _| !invariant.contains(v.key())) + .filter(&mut |Edge(_, v, _)| !invariant.contains(v.key())) .search_cycle(); match cycle { Some(cycle) => { @@ -94,7 +94,7 @@ fn ex1() { ]; let mut g = g.to_vec(); - g.sort(); + g.sort_by(|a, b| a.key().cmp(&b.key())); let mut components = kojarasu(&g); for (i, component) in components.iter_mut().enumerate() { @@ -135,7 +135,7 @@ fn ex2() { ]; let mut g = g.to_vec(); - g.sort(); + g.sort_by(|a, b| a.key().cmp(&b.key())); let mut components = kojarasu(&g); for (i, component) in components.iter_mut().enumerate() { @@ -174,7 +174,7 @@ fn ex3() { ]; let mut g = g.to_vec(); - g.sort(); + g.sort_by(|a, b| a.key().cmp(&b.key())); let mut components = kojarasu(&g); for (i, component) in components.iter_mut().enumerate() { @@ -213,7 +213,7 @@ fn ex4() { ]; let mut g = g.to_vec(); - g.sort(); + g.sort_by(|a, b| a.key().cmp(&b.key())); let mut components = kojarasu(&g); for (i, component) in components.iter_mut().enumerate() { diff --git a/examples/prim-minimum-spanning-tree.rs b/examples/prim-minimum-spanning-tree.rs new file mode 100644 index 0000000..c0be344 --- /dev/null +++ b/examples/prim-minimum-spanning-tree.rs @@ -0,0 +1,115 @@ +// Prim's algorithm +// +// Prim's algorithm (also known as Jarník's algorithm) is a greedy algorithm +// that finds a minimum spanning tree for a weighted undirected graph. This +// means it finds a subset of the edges that forms a tree that includes every +// vertex, where the total weight of all the edges in the tree is minimized. +// The algorithm operates by building this tree one vertex at a time, +// from an arbitrary starting vertex, at each step adding the cheapest possible +// connection from the tree to another vertex. +// +// https://en.wikipedia.org/wiki/Prim%27s_algorithm + +use gdsl::ungraph::*; +use gdsl::*; +use std::collections::{BinaryHeap, HashSet}; +use std::cmp::Reverse; + +type N = Node; +type E = Edge; + +// Standard library's BinaryHeap is a max-heap, so we need to reverse the +// ordering of the edge weights to get a min-heap using the Reverse wrapper. +type Heap = BinaryHeap>; + +fn prim_minimum_spanning_tree(s: &N) -> Vec { + + // We collect the resulting MST edges in to a vector. + let mut mst: Vec = vec![]; + + // We use a HashSet to keep track of the nodes that are in the MST. + let mut in_mst: HashSet = HashSet::new(); + + // We use a BinaryHeap to keep track of all edges sorted by weight. + let mut heap = Heap::new(); + + in_mst.insert(*s.key()); + + // Collect all edges reachable from `s` to a Min Heap. + s.bfs().for_each(&mut |edge| { + heap.push(Reverse(edge.clone())); + }).search(); + + // When we pop from the min heap, we know that the edge is the cheapest + // edge to add to the MST, but we need to make sure that the edge + // connecting to a node that is not already in the MST, otherwise we + // we store the edge and continue to the next iteration. When we find + // an edge that connects to a node that is not in the MST, we add the + // stored edges back to the heap. + let mut tmp: Vec = vec![]; + + // While the heap is not empty, search for the next edge + // that connects a node in the tree to a node not in the tree. + while let Some(Reverse(edge)) = heap.pop() { + let Edge(u, v, _) = edge.clone(); + + // If the edge's source node `u` is in the MST... + if in_mst.contains(u.key()) { + + // ...and the edge's destination node `v` is not in the MST, + // then we add the edge to the MST and add all edges + // in `tmp` back to the heap. + if in_mst.contains(v.key()) == false { + in_mst.insert(*v.key()); + mst.push(edge.clone()); + for tmp_edge in &tmp { + heap.push(Reverse(tmp_edge.clone())); + } + } + } else { + + // The edge is the cheapest edge to add to the MST, but + // it's source node `u` nor it's destination node `v` are + // in the MST, so we store the edge and continue to the next + // iteration. + if in_mst.contains(v.key()) == false { + tmp.push(edge); + } + } + + // If neither condition is met, then the edge's destination node + // `v` is already in the MST, so we continue to the next iteration. + } + mst +} + +fn main() { + // Example g1 from Wikipedia + let g1 = ungraph![ + (usize) => [u64] + (0) => [ (1, 1), (3, 4), (4, 3)] + (1) => [ (3, 4), (4, 2)] + (2) => [ (4, 4), (5, 5)] + (3) => [ (4, 4)] + (4) => [ (5, 7)] + (5) => [] + ]; + let forest = prim_minimum_spanning_tree(&g1[0]); + let sum = forest.iter().fold(0, |acc, e| acc + e.2); + assert!(sum == 16); + + // Example g2 from Figure 7.1 in https://jeffe.cs.illinois.edu/teaching/algorithms/book/07-mst.pdf + let g2 = ungraph![ + (usize) => [u64] + (0) => [ (1, 8), (2, 5)] + (1) => [ (2, 10), (3, 2), (4, 18)] + (2) => [ (3, 3), (5, 16)] + (3) => [ (4, 12), (5, 30)] + (4) => [ (6, 4)] + (5) => [ (6, 26)] + (6) => [] + ]; + let forest = prim_minimum_spanning_tree(&g2[0]); + let sum = forest.iter().fold(0, |acc, e| acc + e.2); + assert!(sum == 42); +} diff --git a/examples/serde.rs b/examples/serialization-example.rs similarity index 95% rename from examples/serde.rs rename to examples/serialization-example.rs index 5d532e4..66ce052 100644 --- a/examples/serde.rs +++ b/examples/serialization-example.rs @@ -34,7 +34,7 @@ fn main() { for (a, b) in graph_cbor_vec.iter().zip(graph_json_vec.iter()) { assert!(a == b); - for ((u, v, e), (uu, vv, ee)) in a.iter_out().zip(b.iter_out()) { + for (Edge(u, v, e), Edge(uu, vv, ee)) in a.iter_out().zip(b.iter_out()) { assert!(u == uu); assert!(v == vv); assert!(e == ee); diff --git a/src/digraph/graph_serde.rs b/src/digraph/graph_serde.rs index d73c965..f6b4956 100644 --- a/src/digraph/graph_serde.rs +++ b/src/digraph/graph_serde.rs @@ -17,11 +17,10 @@ where for (_, n) in g.iter() { nodes.push((n.key().clone(), n.value().clone())); - for (u, v, e) in n.iter_out() { + for Edge(u, v, e) in n { edges.push((u.key().clone(), v.key().clone(), e)); } } - (nodes, edges) } diff --git a/src/digraph/mod.rs b/src/digraph/mod.rs index 622acf6..ef93484 100644 --- a/src/digraph/mod.rs +++ b/src/digraph/mod.rs @@ -5,8 +5,8 @@ //! //! - `Graph` is a container type for a directed graph. //! - `Node` is a node type for a directed graph. -//! - An edge is denoted by a tuple `(u, v, e)` where `u` and `v` are the -//! source and target node and `e` is the edge parameter. +//! - An edge is denoted by a tuple struct `Edge(u, v, e)` where`u` and `v` are +//! the source and target node and `e` is the edge parameter. //! //! # Example //! @@ -320,7 +320,7 @@ where /// g.insert(Node::new("B", 0)); /// g.insert(Node::new("C", 0)); /// - /// for (key, _)in g.iter() { + /// for (key, _) in g.iter() { /// println!("{}", key); /// } /// ``` @@ -383,7 +383,7 @@ where let cycle = node .dfs() .transpose() - .filter(&|_, v, _| !invariant.contains(v.key())) + .filter(&mut |Edge(_, v, _)| !invariant.contains(v.key())) .search_cycle(); match cycle { Some(cycle) => { @@ -412,7 +412,7 @@ where if !visited.contains(next.key()) { let partition = next .postorder() - .filter(&|_, v, _| !visited.contains(v.key())) + .filter(&mut |Edge(_, v, _)| !visited.contains(v.key())) .search_nodes(); for node in &partition { visited.insert(node.key().clone()); @@ -428,7 +428,7 @@ where s.push_str("digraph {\n"); for (u_key, node) in self.iter() { s.push_str(&format!(" {}", u_key.clone())); - for (_, v, _) in node { + for Edge(_, v, _) in node { s.push_str(&format!("\n {} -> {}", u_key, v.key())); } s.push_str("\n"); @@ -466,9 +466,9 @@ where s.push_str("\n"); } for (_, node) in self.iter() { - for (u, v, edge) in node { + for Edge(u, v, e) in node { s.push_str(&format!("\t{} -> {}", u.key(), v.key())); - if let Some(eattrs) = eattr(&u, &v, &edge) { + if let Some(eattrs) = eattr(&u, &v, &e) { s.push_str(&format!(" {}", Self::fmt_attr(eattrs))); } s.push_str("\n"); diff --git a/src/digraph/node/adjacent.rs b/src/digraph/node/adjacent.rs index 127fcad..c49ff22 100644 --- a/src/digraph/node/adjacent.rs +++ b/src/digraph/node/adjacent.rs @@ -1,13 +1,40 @@ use super::*; +#[derive(Clone)] +pub struct WeakNode +where + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, +{ + inner: Weak<(K, N, RefCell>)>, +} + +impl WeakNode +where + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, +{ + pub fn upgrade(&self) -> Option> { + self.inner.upgrade().map(|inner| Node { inner }) + } + + pub fn downgrade(node: &Node) -> Self { + WeakNode { + inner: Rc::downgrade(&node.inner) + } + } +} + pub struct Adjacent where K: Clone + Hash + PartialEq + Eq + Display, N: Clone, E: Clone, { - outbound: Vec<(Node, E)>, - inbound: Vec<(Node, E)>, + outbound: Vec<(WeakNode, E)>, + inbound: Vec<(WeakNode, E)>, } impl Adjacent @@ -23,33 +50,33 @@ where }) } - pub fn get_outbound(&self, idx: usize) -> Option<(Node, E)> { + pub fn get_outbound(&self, idx: usize) -> Option<(&WeakNode, &E)> { match self.outbound.get(idx) { - Some(edge) => Some((edge.0.clone(), edge.1.clone())), + Some(edge) => Some((&edge.0, &edge.1)), None => None, } } - pub fn get_inbound(&self, idx: usize) -> Option<(Node, E)> { + pub fn get_inbound(&self, idx: usize) -> Option<(&WeakNode, &E)> { match self.inbound.get(idx) { - Some(edge) => Some((edge.0.clone(), edge.1.clone())), + Some(edge) => Some((&edge.0, &edge.1)), None => None, } } - pub fn find_outbound(&self, node: &K) -> Option<(Node, E)> { + pub fn find_outbound(&self, node: &K) -> Option<(&WeakNode, &E)> { for edge in self.outbound.iter() { - if edge.0.key() == node { - return Some((edge.0.clone(), edge.1.clone())); + if edge.0.upgrade().unwrap().key() == node { + return Some((&edge.0, &edge.1)); } } None } - pub fn find_inbound(&self, node: &K) -> Option<(Node, E)> { + pub fn find_inbound(&self, node: &K) -> Option<(&WeakNode, &E)> { for edge in self.inbound.iter() { - if edge.0.key() == node { - return Some((edge.0.clone(), edge.1.clone())); + if edge.0.upgrade().unwrap().key() == node { + return Some((&edge.0, &edge.1)); } } None @@ -64,33 +91,29 @@ where } pub fn push_inbound(&mut self, edge: (Node, E)) { - self.inbound.push(edge); + self.inbound.push((WeakNode::downgrade(&edge.0), edge.1)); } pub fn push_outbound(&mut self, edge: (Node, E)) { - self.outbound.push(edge); + self.outbound.push((WeakNode::downgrade(&edge.0), edge.1)); } pub fn remove_inbound(&mut self, source: &K) -> Result { - let idx = self.inbound.iter().position(|edge| edge.0.key() == source); - match idx { - Some(idx) => { - let edge = self.inbound.remove(idx); - Ok(edge.1.clone()) - } - None => Err(()), - } + for (idx, edge) in self.inbound.iter().enumerate() { + if edge.0.upgrade().unwrap().key() == source { + return Ok(self.inbound.remove(idx).1); + } + } + Err(()) } pub fn remove_outbound(&mut self, target: &K) -> Result { - let idx = self.outbound.iter().position(|edge| edge.0.key() == target); - match idx { - Some(idx) => { - let edge = self.outbound.remove(idx); - Ok(edge.1.clone()) - } - None => Err(()), - } + for (idx, edge) in self.outbound.iter().enumerate() { + if edge.0.upgrade().unwrap().key() == target { + return Ok(self.outbound.remove(idx).1); + } + } + Err(()) } pub fn clear_inbound(&mut self) { diff --git a/src/sync_digraph/node/bfs.rs b/src/digraph/node/algo/bfs.rs similarity index 75% rename from src/sync_digraph/node/bfs.rs rename to src/digraph/node/algo/bfs.rs index d04eaa5..0d69604 100644 --- a/src/sync_digraph/node/bfs.rs +++ b/src/digraph/node/algo/bfs.rs @@ -9,7 +9,7 @@ where E: Clone, { root: Node, - target: Option<&'a K>, + target: Option, method: Method<'a, K, N, E>, transpose: Transposition, } @@ -29,8 +29,8 @@ where } } - pub fn target(mut self, target: &'a K) -> Self { - self.target = Some(target); + pub fn target(mut self, target: &K) -> Self { + self.target = Some(target.clone()); self } @@ -39,8 +39,8 @@ where self } - pub fn map(mut self, f: Map<'a, K, N, E>) -> Self { - self.method = Method::Map(f); + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); self } @@ -49,11 +49,6 @@ where self } - pub fn filter_map(mut self, f: FilterMap<'a, K, N, E>) -> Self { - self.method = Method::FilterMap(f); - self - } - pub fn search(&'a mut self) -> Option> { let mut queue = VecDeque::new(); let mut visited = HashSet::default(); @@ -77,7 +72,7 @@ where let mut visited = HashSet::default(); let target_found; - self.target = Some(self.root.key()); + self.target = Some(self.root.key().clone()); queue.push_back(self.root.clone()); match self.transpose { @@ -118,19 +113,22 @@ where } fn loop_outbound( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut VecDeque>, ) -> bool { while let Some(node) = queue.pop_front() { - for (u, v, e) in node.iter_out() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.1.clone(); if !visited.contains(v.key()) { visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } queue.push_back(v.clone()); } @@ -141,19 +139,23 @@ where } fn loop_inbound( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut VecDeque>, ) -> bool { while let Some(node) = queue.pop_front() { - for (v, u, e) in node.iter_in() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.1.clone(); if !visited.contains(v.key()) { visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } queue.push_back(v.clone()); } @@ -164,17 +166,20 @@ where } fn loop_outbound_find( - &self, + &mut self, visited: &mut HashSet, queue: &mut VecDeque>, ) -> Option> { while let Some(node) = queue.pop_front() { - for (u, v, e) in node.iter_out() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let Edge(_, v, _) = edge; if !visited.contains(v.key()) { visited.insert(v.key().clone()); - if self.target.is_some() && self.target.unwrap() == v.key() { - return Some(v); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } } queue.push_back(v.clone()); } @@ -185,17 +190,21 @@ where } fn loop_inbound_find( - &self, + &mut self, visited: &mut HashSet, queue: &mut VecDeque>, ) -> Option> { while let Some(node) = queue.pop_front() { - for (v, u, e) in node.iter_in() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let Edge(_, v, _) = edge; if !visited.contains(v.key()) { visited.insert(v.key().clone()); - if self.target.is_some() && self.target.unwrap() == v.key() { - return Some(v); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } } queue.push_back(v.clone()); } diff --git a/src/digraph/node/dfs.rs b/src/digraph/node/algo/dfs.rs similarity index 75% rename from src/digraph/node/dfs.rs rename to src/digraph/node/algo/dfs.rs index 37a733c..c4d16ff 100644 --- a/src/digraph/node/dfs.rs +++ b/src/digraph/node/algo/dfs.rs @@ -9,7 +9,7 @@ where E: Clone, { root: Node, - target: Option<&'a K>, + target: Option, method: Method<'a, K, N, E>, transpose: Transposition, } @@ -29,8 +29,8 @@ where } } - pub fn target(mut self, target: &'a K) -> Self { - self.target = Some(target); + pub fn target(mut self, target: &K) -> Self { + self.target = Some(target.clone()); self } @@ -39,8 +39,8 @@ where self } - pub fn map(mut self, f: Map<'a, K, N, E>) -> Self { - self.method = Method::Map(f); + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); self } @@ -49,11 +49,6 @@ where self } - pub fn filter_map(mut self, f: FilterMap<'a, K, N, E>) -> Self { - self.method = Method::FilterMap(f); - self - } - pub fn search(&'a mut self) -> Option> { let mut queue = vec![]; let mut visited = HashSet::default(); @@ -77,7 +72,7 @@ where let mut visited = HashSet::default(); let target_found; - self.target = Some(self.root.key()); + self.target = Some(self.root.key().clone()); queue.push(self.root.clone()); match self.transpose { @@ -117,20 +112,23 @@ where None } - fn recurse_outbound(&self, + fn recurse_outbound(&mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (u, v, e) in node.iter_out() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.target().clone(); if visited.contains(v.key()) == false { - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; - } visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } queue.push(v.clone()); if self.recurse_outbound(result, visited, queue) { return true; @@ -142,20 +140,24 @@ where false } - fn recurse_inbound(&self, + fn recurse_inbound(&mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (v, u, e) in node.iter_in() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.target().clone(); if visited.contains(v.key()) == false { - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; - } visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } queue.push(v.clone()); if self.recurse_inbound(result, visited, queue) { return true; @@ -167,18 +169,21 @@ where false } - fn recurse_outbound_find(&self, + fn recurse_outbound_find(&mut self, visited: &mut HashSet, queue: &mut Vec>, ) -> Option> { if let Some(node) = queue.pop() { - for (u, v, e) in node.iter_out() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.target(); if visited.contains(v.key()) == false { - if self.target.is_some() && self.target.unwrap() == v.key() { - return Some(v); - } visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } + } queue.push(v.clone()); match self.recurse_outbound_find(visited, queue) { Some(t) => return Some(t), @@ -191,18 +196,22 @@ where None } - fn recurse_inbound_find(&self, + fn recurse_inbound_find(&mut self, visited: &mut HashSet, queue: &mut Vec>, ) -> Option> { if let Some(node) = queue.pop() { - for (v, u, e) in node.iter_in() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.target(); if visited.contains(v.key()) == false { - if self.target.is_some() && self.target.unwrap() == v.key() { - return Some(v); - } visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } + } queue.push(v.clone()); match self.recurse_inbound_find(visited, queue) { Some(t) => return Some(t), diff --git a/src/digraph/node/algo/method.rs b/src/digraph/node/algo/method.rs new file mode 100644 index 0000000..e552875 --- /dev/null +++ b/src/digraph/node/algo/method.rs @@ -0,0 +1,30 @@ +use super::*; + +pub type Filter<'a, K, N, E> = &'a mut dyn FnMut(&Edge) -> bool; +pub type ForEach<'a, K, N, E> = &'a mut dyn FnMut(&Edge); + +pub enum Method<'a, K, N, E> +where + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, +{ + NullMethod, + Filter(Filter<'a, K, N, E>), + ForEach(ForEach<'a, K, N, E>), +} + +impl<'a, K, N, E> Method<'a, K, N, E> +where + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, +{ + pub fn exec(&mut self, e: &Edge) -> bool { + match self { + Method::NullMethod => true, + Method::ForEach(f) => {f(e); true}, + Method::Filter(f) => f(e), + } + } +} \ No newline at end of file diff --git a/src/digraph/node/algo/mod.rs b/src/digraph/node/algo/mod.rs new file mode 100644 index 0000000..ad8023c --- /dev/null +++ b/src/digraph/node/algo/mod.rs @@ -0,0 +1,9 @@ +use super::*; + +pub mod bfs; +pub mod dfs; +pub mod pfs; +pub mod order; + +mod path; +mod method; \ No newline at end of file diff --git a/src/digraph/node/order.rs b/src/digraph/node/algo/order.rs similarity index 77% rename from src/digraph/node/order.rs rename to src/digraph/node/algo/order.rs index 3f15165..5bb5a67 100644 --- a/src/digraph/node/order.rs +++ b/src/digraph/node/algo/order.rs @@ -2,6 +2,11 @@ use std::{fmt::Display, hash::Hash}; use super::{*, method::*}; use ahash::AHashSet as HashSet; +pub enum Ordering { + Pre, + Post, +} + pub struct Order<'a, K, N, E> where K: Clone + Hash + Display + PartialEq + Eq, @@ -44,8 +49,8 @@ where self } - pub fn map(mut self, f: Map<'a, K, N, E>) -> Self { - self.method = Method::Map(f); + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); self } @@ -54,11 +59,6 @@ where self } - pub fn filter_map(mut self, f: FilterMap<'a, K, N, E>) -> Self { - self.method = Method::FilterMap(f); - self - } - pub fn search_nodes(&mut self) -> Vec> { let mut nodes = vec![]; let mut edges = vec![]; @@ -74,12 +74,12 @@ where Ordering::Pre => { self.preorder_forward(&mut edges, &mut visited, &mut queue); nodes.push(self.root.clone()); - let mut coll = edges.iter().map(|(_, v, _)| v.clone()).collect(); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); nodes.append(&mut coll); }, Ordering::Post => { self.postorder_forward(&mut edges, &mut visited, &mut queue); - let mut coll = edges.iter().map(|(_, v, _)| v.clone()).collect(); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); nodes.append(&mut coll); nodes.push(self.root.clone()); }, @@ -90,12 +90,12 @@ where Ordering::Pre => { self.preorder_backward(&mut edges, &mut visited, &mut queue); nodes.push(self.root.clone()); - let mut coll = edges.iter().map(|(_, v, _)| v.clone()).collect(); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); nodes.append(&mut coll); }, Ordering::Post => { self.postorder_backward(&mut edges, &mut visited, &mut queue); - let mut coll = edges.iter().map(|(_, v, _)| v.clone()).collect(); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); nodes.append(&mut coll); nodes.push(self.root.clone()); }, @@ -139,18 +139,19 @@ where } fn preorder_forward( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (u, v, e) in node.iter_out() { - if visited.contains(v.key()) == false { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + let v = edge.1.clone(); + if self.method.exec(&edge) { + if visited.contains(v.key()) == false { visited.insert(v.key().clone()); queue.push(v.clone()); - result.push((u, v.clone(), e)); + result.push(edge); self.preorder_forward( result, visited, @@ -163,18 +164,20 @@ where } fn preorder_backward( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (v, u, e) in node.iter_in() { - if visited.contains(v.key()) == false { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_in() { + let edge = edge.reverse(); + let v = edge.1.clone(); + if self.method.exec(&edge) { + if visited.contains(v.key()) == false { visited.insert(v.key().clone()); queue.push(v.clone()); - result.push((u, v.clone(), e)); + result.push(edge); self.preorder_forward( result, visited, @@ -187,22 +190,23 @@ where } fn postorder_forward( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (u, v, e) in node.iter_out() { - if visited.contains(v.key()) == false { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + let v = edge.1.clone(); + if self.method.exec(&edge) { + if visited.contains(v.key()) == false { visited.insert(v.key().clone()); queue.push(v.clone()); self.postorder_forward( result, visited, queue); - result.push((u, v.clone(), e)); + result.push(edge); } } } @@ -211,22 +215,24 @@ where } fn postorder_backward( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (v, u, e) in node.iter_in() { - if visited.contains(v.key()) == false { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_in() { + let edge = edge.reverse(); + let v = edge.1.clone(); + if self.method.exec(&edge) { + if visited.contains(v.key()) == false { visited.insert(v.key().clone()); queue.push(v.clone()); self.postorder_forward( result, visited, queue); - result.push((u, v.clone(), e)); + result.push(edge); } } } diff --git a/src/sync_digraph/node/path.rs b/src/digraph/node/algo/path.rs similarity index 93% rename from src/sync_digraph/node/path.rs rename to src/digraph/node/algo/path.rs index b93c32c..6499b8d 100644 --- a/src/sync_digraph/node/path.rs +++ b/src/digraph/node/algo/path.rs @@ -16,10 +16,11 @@ where let w = edge_tree.last().unwrap(); path.push(w.clone()); let mut i = 0; - for (u, v, e) in edge_tree.iter().rev() { - let (s, _, _) = &path[i]; + for edge in edge_tree.iter().rev() { + let Edge(_, v, _) = edge; + let Edge(s, _, _) = &path[i]; if s == v { - path.push((u.clone(), v.clone(), e.clone())); + path.push(edge.clone()); i += 1; } } @@ -121,13 +122,13 @@ where N: Clone, E: Clone, { - type Item = (Node, Node, E); + type Item = Edge; fn next(&mut self) -> Option { match self.path.edges.get(self.position) { Some(edge) => { self.position += 1; - Some((edge.0.clone(), edge.1.clone(), edge.2.clone())) + Some(Edge(edge.0.clone(), edge.1.clone(), edge.2.clone())) } None => None, } diff --git a/src/digraph/node/pfs.rs b/src/digraph/node/algo/pfs.rs similarity index 67% rename from src/digraph/node/pfs.rs rename to src/digraph/node/algo/pfs.rs index 1b9a6f8..42f71bf 100644 --- a/src/digraph/node/pfs.rs +++ b/src/digraph/node/algo/pfs.rs @@ -20,7 +20,7 @@ where E: Clone, { root: Node, - target: Option<&'a K>, + target: Option, method: Method<'a, K, N, E>, transpose: Transposition, priority: Priority, @@ -52,8 +52,8 @@ where self } - pub fn target(mut self, target: &'a K) -> Self { - self.target = Some(target); + pub fn target(mut self, target: &K) -> Self { + self.target = Some(target.clone()); self } @@ -62,8 +62,8 @@ where self } - pub fn map(mut self, f: Map<'a, K, N, E>) -> Self { - self.method = Method::Map(f); + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); self } @@ -72,27 +72,24 @@ where self } - - pub fn filter_map(mut self, f: FilterMap<'a, K, N, E>) -> Self { - self.method = Method::FilterMap(f); - self - } - - fn forward_min( - &self, + fn loop_outbound_min( + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut BinaryHeap>>, ) -> bool { while let Some(node) = queue.pop() { let node = node.0; - for (u, v, e) in node.iter_out() { - if !visited.contains(v.key()) { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } queue.push(Reverse(v.clone())); } @@ -102,21 +99,25 @@ where false } - fn backward_min( - &self, + fn loop_inbound_min( + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut BinaryHeap>>, ) -> bool { while let Some(node) = queue.pop() { let node = node.0; - for (v, u, e) in node.iter_in() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.1.clone(); if !visited.contains(v.key()) { visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } queue.push(Reverse(v.clone())); } @@ -126,20 +127,23 @@ where false } - fn forward_max( - &self, + fn loop_outbound_max( + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut BinaryHeap>, ) -> bool { while let Some(node) = queue.pop() { - for (u, v, e) in node.iter_out() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.1.clone(); if !visited.contains(v.key()) { visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } queue.push(v.clone()); } @@ -149,20 +153,24 @@ where false } - fn backward_max( - &self, + fn loop_inbound_max( + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut BinaryHeap>, ) -> bool { while let Some(node) = queue.pop() { - for (v, u, e) in node.iter_in() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.1.clone(); if !visited.contains(v.key()) { visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } queue.push(v.clone()); } @@ -185,7 +193,7 @@ where let mut visited = HashSet::default(); let target_found; - self.target = Some(self.root.key()); + self.target = Some(self.root.key().clone()); match self.transpose { Transposition::Outbound => { @@ -193,12 +201,12 @@ where Priority::Min => { let mut queue = BinaryHeap::new(); queue.push(Reverse(self.root.clone())); - target_found = self.forward_min(&mut edges, &mut visited, &mut queue); + target_found = self.loop_outbound_min(&mut edges, &mut visited, &mut queue); } Priority::Max => { let mut queue = BinaryHeap::new(); queue.push(self.root.clone()); - target_found = self.forward_max(&mut edges, &mut visited, &mut queue); + target_found = self.loop_outbound_max(&mut edges, &mut visited, &mut queue); } } } @@ -207,12 +215,12 @@ where Priority::Min => { let mut queue = BinaryHeap::new(); queue.push(Reverse(self.root.clone())); - target_found = self.backward_min(&mut edges, &mut visited, &mut queue); + target_found = self.loop_inbound_min(&mut edges, &mut visited, &mut queue); } Priority::Max => { let mut queue = BinaryHeap::new(); queue.push(self.root.clone()); - target_found = self.backward_max(&mut edges, &mut visited, &mut queue); + target_found = self.loop_inbound_max(&mut edges, &mut visited, &mut queue); } } } @@ -236,12 +244,12 @@ where Priority::Min => { let mut queue = BinaryHeap::new(); queue.push(Reverse(self.root.clone())); - target_found = self.forward_min(&mut edges, &mut visited, &mut queue); + target_found = self.loop_outbound_min(&mut edges, &mut visited, &mut queue); } Priority::Max => { let mut queue = BinaryHeap::new(); queue.push(self.root.clone()); - target_found = self.forward_max(&mut edges, &mut visited, &mut queue); + target_found = self.loop_outbound_max(&mut edges, &mut visited, &mut queue); } } } @@ -250,12 +258,12 @@ where Priority::Min => { let mut queue = BinaryHeap::new(); queue.push(Reverse(self.root.clone())); - target_found = self.backward_min(&mut edges, &mut visited, &mut queue); + target_found = self.loop_inbound_min(&mut edges, &mut visited, &mut queue); } Priority::Max => { let mut queue = BinaryHeap::new(); queue.push(self.root.clone()); - target_found = self.backward_max(&mut edges, &mut visited, &mut queue); + target_found = self.loop_inbound_max(&mut edges, &mut visited, &mut queue); } } } diff --git a/src/digraph/node/method.rs b/src/digraph/node/method.rs deleted file mode 100644 index 76ecaa2..0000000 --- a/src/digraph/node/method.rs +++ /dev/null @@ -1,44 +0,0 @@ -use super::*; - -pub type FilterMap<'a, K, N, E> = &'a dyn Fn(&Node, &Node, &E) -> bool; -pub type Filter<'a, K, N, E> = &'a dyn Fn(&Node, &Node, &E) -> bool; -pub type Map<'a, K, N, E> = &'a dyn Fn(&Node, &Node, &E); - -#[derive(Clone)] -pub enum Method<'a, K, N, E> -where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, -{ - NullMethod, - FilterMap(FilterMap<'a, K, N, E>), - Filter(Filter<'a, K, N, E>), - Map(Map<'a, K, N, E>), -} - -impl<'a, K, N, E> Method<'a, K, N, E> -where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, -{ - pub fn exec(&self, u: &Node, v: &Node, e: &E) -> bool { - match self { - Method::NullMethod => true, - Method::Map(f) => {f(u, v, e); true}, - Method::Filter(f) => f(u, v, e), - Method::FilterMap(f) => f(u, v, e), - } - } -} - -pub enum Ordering { - Pre, - Post, -} - -pub enum Transposition { - Outbound, - Inbound, -} \ No newline at end of file diff --git a/src/digraph/node/mod.rs b/src/digraph/node/mod.rs index 26e4826..e2a212c 100644 --- a/src/digraph/node/mod.rs +++ b/src/digraph/node/mod.rs @@ -31,20 +31,55 @@ //! //! This node uses `Rc` for reference counting, thus it is not thread-safe. -mod bfs; -mod dfs; -mod method; -mod order; -mod path; -mod pfs; mod adjacent; +mod algo; -use std::{cell::RefCell, fmt::Display, hash::Hash, ops::Deref, rc::Rc}; -use self::{bfs::*, dfs::*, order::*, pfs::*, adjacent::*}; +use self::{adjacent::*, algo::{bfs::*, dfs::*, order::*, pfs::*}}; +use std::{cell::RefCell, fmt::Display, hash::Hash, ops::Deref, rc::{Rc, Weak}}; -/// An edge between nodes is a tuple `(u, v, e)` where `u` is the +enum Transposition { + Outbound, + Inbound, +} + +/// An edge between nodes is a tuple struct `Edge(u, v, e)` where `u` is the /// source node, `v` is the target node, and `e` is the edge's value. -pub type Edge = (Node, Node, E); +#[derive(Clone, PartialEq)] +pub struct Edge( + pub Node, + pub Node, + pub E, +) where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone; + +impl Edge +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone, +{ + /// Returns the source node of the edge. + pub fn source(&self) -> &Node { + &self.0 + } + + /// Returns the target node of the edge. + pub fn target(&self) -> &Node { + &self.1 + } + + /// Returns the edge's value. + pub fn value(&self) -> &E { + &self.2 + } + + /// Reverse the edge's direction. + pub fn reverse(&self) -> Edge { + Edge(self.1.clone(), self.0.clone(), self.2.clone()) + } +} /// A `Node` is a key value pair smart-pointer, which includes inbound /// and outbound connections to other nodes. Nodes can be created individually @@ -66,7 +101,7 @@ pub type Edge = (Node, Node, E); /// b.connect(&c, 0.09); /// c.connect(&b, 12.9); /// -/// let (u, v, e) = a.iter_out().next().unwrap(); +/// let Edge(u, v, e) = a.iter_out().next().unwrap(); /// /// assert!(u == a); /// assert!(v == b); @@ -139,46 +174,46 @@ where &self.inner.1 } - /// Returns the out-degree of the node. The out degree is the number of - /// outbound edges. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let a = Node::new(0x1, "A"); - /// let b = Node::new(0x2, "B"); - /// let c = Node::new(0x4, "C"); - /// - /// a.connect(&b, 0.42); - /// a.connect(&c, 1.7); - /// - /// assert!(a.out_degree() == 2); - /// ``` - pub fn out_degree(&self) -> usize { - self.inner.2.borrow().len_outbound() - } - - /// Returns the in-degree of the node. The out degree is the number of - /// inbound edges. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let a = Node::new(0x1, "A"); - /// let b = Node::new(0x2, "B"); - /// let c = Node::new(0x4, "C"); - /// - /// b.connect(&a, 0.42); - /// c.connect(&a, 1.7); - /// - /// assert!(a.in_degree() == 2); - pub fn in_degree(&self) -> usize { - self.inner.2.borrow().len_inbound() - } + /// Returns the out-degree of the node. The out degree is the number of + /// outbound edges. + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let a = Node::new(0x1, "A"); + /// let b = Node::new(0x2, "B"); + /// let c = Node::new(0x4, "C"); + /// + /// a.connect(&b, 0.42); + /// a.connect(&c, 1.7); + /// + /// assert!(a.out_degree() == 2); + /// ``` + pub fn out_degree(&self) -> usize { + self.inner.2.borrow().len_outbound() + } + + /// Returns the in-degree of the node. The out degree is the number of + /// inbound edges. + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let a = Node::new(0x1, "A"); + /// let b = Node::new(0x2, "B"); + /// let c = Node::new(0x4, "C"); + /// + /// b.connect(&a, 0.42); + /// c.connect(&a, 1.7); + /// + /// assert!(a.in_degree() == 2); + pub fn in_degree(&self) -> usize { + self.inner.2.borrow().len_inbound() + } /// Connects this node to another node. The connection is created in both /// directions. The connection is created with the given edge value and @@ -198,10 +233,13 @@ where /// assert!(n1.is_connected(n2.key())); /// ``` pub fn connect(&self, other: &Self, value: E) { - self.inner.2 + self.inner + .2 .borrow_mut() .push_outbound((other.clone(), value.clone())); - other.inner.2 + other + .inner + .2 .borrow_mut() .push_inbound((self.clone(), value)); } @@ -241,7 +279,7 @@ where /// Disconnect two nodes from each other. The connection is removed in both /// directions. Returns Ok(EdgeValue) if the connection was removed, - /// Err(()) if the connection doesn't exist. + /// Err(()) if the connection doesn't exist. /// /// # Example /// @@ -263,13 +301,9 @@ where /// ``` pub fn disconnect(&self, other: &K) -> Result { match self.find_outbound(other) { - Some(other) => match self.inner.2 - .borrow_mut() - .remove_outbound(other.key()) { + Some(other) => match self.inner.2.borrow_mut().remove_outbound(other.key()) { Ok(edge) => { - other.inner.2 - .borrow_mut() - .remove_inbound(self.key())?; + other.inner.2.borrow_mut().remove_inbound(self.key())?; Ok(edge) } Err(_) => Err(()), @@ -306,17 +340,11 @@ where /// assert!(n1.is_orphan()); /// ``` pub fn isolate(&self) { - for (_, v, _) in self.iter_out() { - v.inner.2 - .borrow_mut() - .remove_inbound(self.key()) - .unwrap(); + for Edge(_, v, _) in self.iter_out() { + v.inner.2.borrow_mut().remove_inbound(self.key()).unwrap(); } - for (v, _, _) in self.iter_in() { - v.inner.2 - .borrow_mut() - .remove_outbound(self.key()) - .unwrap(); + for Edge(v, _, _) in self.iter_in() { + v.inner.2.borrow_mut().remove_outbound(self.key()).unwrap(); } self.inner.2.borrow_mut().clear_outbound(); self.inner.2.borrow_mut().clear_inbound(); @@ -324,166 +352,168 @@ where /// Returns true if the node is a root node. Root nodes are nodes that have /// no incoming connections. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// - /// n1.connect(&n2, ()); - /// - /// assert!(n1.is_root()); - /// assert!(!n2.is_root()); - /// ``` + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// + /// n1.connect(&n2, ()); + /// + /// assert!(n1.is_root()); + /// assert!(!n2.is_root()); + /// ``` pub fn is_root(&self) -> bool { self.inner.2.borrow().len_inbound() == 0 } /// Returns true if the node is a leaf node. Leaf nodes are nodes that have /// no outgoing connections. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// - /// n1.connect(&n2, ()); - /// - /// assert!(!n1.is_leaf()); - /// assert!(n2.is_leaf()); - /// ``` + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// + /// n1.connect(&n2, ()); + /// + /// assert!(!n1.is_leaf()); + /// assert!(n2.is_leaf()); + /// ``` pub fn is_leaf(&self) -> bool { self.inner.2.borrow().len_outbound() == 0 } /// Returns true if the node is an oprhan. Orphan nodes are nodes that have /// no connections. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// - /// n1.connect(&n2, ()); - /// - /// assert!(!n1.is_orphan()); - /// - /// n1.disconnect(n2.key()).unwrap(); - /// - /// assert!(n1.is_orphan()); - /// ``` + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// + /// n1.connect(&n2, ()); + /// + /// assert!(!n1.is_orphan()); + /// + /// n1.disconnect(n2.key()).unwrap(); + /// + /// assert!(n1.is_orphan()); + /// ``` pub fn is_orphan(&self) -> bool { self.is_root() && self.is_leaf() } /// Returns true if the node is connected to another node with a given key. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// - /// n1.connect(&n2, ()); - /// - /// assert!(n1.is_connected(n2.key())); - /// ``` + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// + /// n1.connect(&n2, ()); + /// + /// assert!(n1.is_connected(n2.key())); + /// ``` pub fn is_connected(&self, other: &K) -> bool { self.find_outbound(other).is_some() } /// Get a pointer to an adjacent node with a given key. Returns None if no /// node with the given key is found from the node's adjacency list. - /// Outbound edges are searches, this is the default direction. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// - /// n1.connect(&n2, ()); - /// n1.connect(&n3, ()); - /// - /// assert!(n1.find_outbound(n2.key()).is_some()); - /// assert!(n1.find_outbound(n3.key()).is_some()); - /// assert!(n1.find_outbound(&4).is_none()); - /// ``` + /// Outbound edges are searches, this is the default direction. + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// + /// n1.connect(&n2, ()); + /// n1.connect(&n3, ()); + /// + /// assert!(n1.find_outbound(n2.key()).is_some()); + /// assert!(n1.find_outbound(n3.key()).is_some()); + /// assert!(n1.find_outbound(&4).is_none()); + /// ``` pub fn find_outbound(&self, other: &K) -> Option> { - let edge = self.inner.2.borrow().find_outbound(other); + let edge = self.inner.2.borrow(); + let edge = edge.find_outbound(other); if let Some(edge) = edge { - Some(edge.0.clone()) + Some(edge.0.upgrade().unwrap().clone()) } else { None } } - /// Get a pointer to an adjacent node with a given key. Returns None if no - /// node with the given key is found from the node's adjacency list. - /// Inbound edges are searched ie. the transposed graph. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// - /// n1.connect(&n2, ()); - /// n1.connect(&n3, ()); - /// - /// assert!(n2.find_inbound(n1.key()).is_some()); - /// assert!(n3.find_inbound(n1.key()).is_some()); - /// assert!(n1.find_inbound(&4).is_none()); - /// ``` + /// Get a pointer to an adjacent node with a given key. Returns None if no + /// node with the given key is found from the node's adjacency list. + /// Inbound edges are searched ie. the transposed graph. + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// + /// n1.connect(&n2, ()); + /// n1.connect(&n3, ()); + /// + /// assert!(n2.find_inbound(n1.key()).is_some()); + /// assert!(n3.find_inbound(n1.key()).is_some()); + /// assert!(n1.find_inbound(&4).is_none()); + /// ``` pub fn find_inbound(&self, other: &K) -> Option> { - let edge = self.inner.2.borrow().find_inbound(other); + let edge = self.inner.2.borrow(); + let edge = edge.find_inbound(other); if let Some(edge) = edge { - Some(edge.0.clone()) + Some(edge.0.upgrade().unwrap().clone()) } else { None } } - /// Returns an iterator-like object that can be used to map, filter and + /// Returns an iterator-like object that can be used to map, filter and /// collect reachable nodes or edges in different orderings such as /// postorder or preorder. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// - /// n1.connect(&n2, ()); - /// n2.connect(&n3, ()); - /// n3.connect(&n1, ()); - /// - /// let order = n1.preorder().search_nodes(); - /// - /// assert!(order[0] == n1); - /// assert!(order[1] == n2); - /// assert!(order[2] == n3); - /// ``` + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// + /// n1.connect(&n2, ()); + /// n2.connect(&n3, ()); + /// n3.connect(&n1, ()); + /// + /// let order = n1.preorder().search_nodes(); + /// + /// assert!(order[0] == n1); + /// assert!(order[1] == n2); + /// assert!(order[2] == n3); + /// ``` pub fn preorder(&self) -> Order { Order::preorder(self) } @@ -491,91 +521,91 @@ where /// Returns an iterator-like object that can be used to map, filter and /// collect reachable nodes or edges in different orderings such as /// postorder or preorder. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// - /// n1.connect(&n2, ()); - /// n2.connect(&n3, ()); - /// n3.connect(&n1, ()); - /// - /// let order = n1.postorder().search_nodes(); - /// - /// assert!(order[2] == n1); - /// assert!(order[1] == n2); - /// assert!(order[0] == n3); - /// ``` + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// + /// n1.connect(&n2, ()); + /// n2.connect(&n3, ()); + /// n3.connect(&n1, ()); + /// + /// let order = n1.postorder().search_nodes(); + /// + /// assert!(order[2] == n1); + /// assert!(order[1] == n2); + /// assert!(order[0] == n3); + /// ``` pub fn postorder(&self) -> Order { Order::postroder(self) } /// Returns an iterator-like object that can be used to map, filter, /// search and collect nodes or edges resulting from a depth-first search. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// - /// n1.connect(&n2, ()); - /// n2.connect(&n3, ()); - /// n3.connect(&n1, ()); - /// - /// let path = n1 - /// .dfs() - /// .target(&3) - /// .search_path() - /// .unwrap(); - /// - /// let mut iter = path.iter_nodes(); - /// - /// assert!(iter.next().unwrap() == n1); - /// assert!(iter.next().unwrap() == n2); - /// assert!(iter.next().unwrap() == n3); - /// ``` + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// + /// n1.connect(&n2, ()); + /// n2.connect(&n3, ()); + /// n3.connect(&n1, ()); + /// + /// let path = n1 + /// .dfs() + /// .target(&3) + /// .search_path() + /// .unwrap(); + /// + /// let mut iter = path.iter_nodes(); + /// + /// assert!(iter.next().unwrap() == n1); + /// assert!(iter.next().unwrap() == n2); + /// assert!(iter.next().unwrap() == n3); + /// ``` pub fn dfs(&self) -> DFS { DFS::new(self) } /// Returns an iterator-like object that can be used to map, filter, /// search and collect nodes or edges resulting from a breadth-first - /// search. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// - /// n1.connect(&n2, ()); - /// n2.connect(&n3, ()); - /// n3.connect(&n1, ()); - /// - /// let path = n1 - /// .bfs() - /// .target(&3) - /// .search_path() - /// .unwrap(); - /// - /// let mut iter = path.iter_nodes(); - /// - /// assert!(iter.next().unwrap() == n1); - /// assert!(iter.next().unwrap() == n2); - /// assert!(iter.next().unwrap() == n3); - /// ``` + /// search. + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// + /// n1.connect(&n2, ()); + /// n2.connect(&n3, ()); + /// n3.connect(&n1, ()); + /// + /// let path = n1 + /// .bfs() + /// .target(&3) + /// .search_path() + /// .unwrap(); + /// + /// let mut iter = path.iter_nodes(); + /// + /// assert!(iter.next().unwrap() == n1); + /// assert!(iter.next().unwrap() == n2); + /// assert!(iter.next().unwrap() == n3); + /// ``` pub fn bfs(&self) -> BFS { BFS::new(self) } @@ -583,31 +613,31 @@ where /// Returns an iterator-like object that can be used to map, filter, /// search and collect nodes or edges resulting from a /// priority-first search. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new('A', 0); - /// let n2 = Node::new('B', 42); - /// let n3 = Node::new('C', 7); - /// let n4 = Node::new('D', 23); - /// - /// n1.connect(&n2, ()); - /// n1.connect(&n3, ()); - /// n2.connect(&n4, ()); - /// n3.connect(&n4, ()); - /// - /// let path = n1 - /// .pfs() - /// .target(&'D') - /// .search_path() - /// .unwrap(); - /// - /// assert!(path[0] == (n1, n3.clone(), ())); - /// assert!(path[1] == (n3, n4, ())); - ///``` + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new('A', 0); + /// let n2 = Node::new('B', 42); + /// let n3 = Node::new('C', 7); + /// let n4 = Node::new('D', 23); + /// + /// n1.connect(&n2, ()); + /// n1.connect(&n3, ()); + /// n2.connect(&n4, ()); + /// n3.connect(&n4, ()); + /// + /// let path = n1 + /// .pfs() + /// .target(&'D') + /// .search_path() + /// .unwrap(); + /// + /// assert!(path[0] == Edge(n1, n3.clone(), ())); + /// assert!(path[1] == Edge(n3, n4, ())); + ///``` pub fn pfs(&self) -> PFS where N: Ord, @@ -615,24 +645,24 @@ where PFS::new(self) } - /// Returns an iterator over the node's outbound edges. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// - /// n1.connect(&n2, ()); - /// n1.connect(&n3, ()); - /// - /// let mut iter = n1.iter_out(); - /// assert!(iter.next().unwrap() == (n1.clone(), n2.clone(), ())); - /// assert!(iter.next().unwrap() == (n1, n3, ())); - /// ``` + /// Returns an iterator over the node's outbound edges. + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// + /// n1.connect(&n2, ()); + /// n1.connect(&n3, ()); + /// + /// let mut iter = n1.iter_out(); + /// assert!(iter.next().unwrap() == Edge(n1.clone(), n2.clone(), ())); + /// assert!(iter.next().unwrap() == Edge(n1, n3, ())); + /// ``` pub fn iter_out(&self) -> IterOut { IterOut { node: self, @@ -640,25 +670,25 @@ where } } - /// Returns an iterator over the node's inbound edges. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// - /// n1.connect(&n2, ()); - /// n1.connect(&n3, ()); - /// - /// let mut iter = n2.iter_in(); - /// - /// assert!(iter.next().unwrap() == (n1.clone(), n2.clone(), ())); - /// assert!(iter.next().is_none()); - /// ``` + /// Returns an iterator over the node's inbound edges. + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// + /// n1.connect(&n2, ()); + /// n1.connect(&n3, ()); + /// + /// let mut iter = n2.iter_in(); + /// + /// assert!(iter.next().unwrap() == Edge(n1.clone(), n2.clone(), ())); + /// assert!(iter.next().is_none()); + /// ``` pub fn iter_in(&self) -> IterIn { IterIn { node: self, @@ -666,13 +696,13 @@ where } } - /// Return's the node's size in bytes. + /// Return's the node's size in bytes. pub fn sizeof(&self) -> usize { - std::mem::size_of::>() - + std::mem::size_of::() - + std::mem::size_of::() - + self.inner.2.borrow().sizeof() - + std::mem::size_of::() + std::mem::size_of::>() + + std::mem::size_of::() + + std::mem::size_of::() + + self.inner.2.borrow().sizeof() + + std::mem::size_of::() } } @@ -704,7 +734,8 @@ where K: Clone + Hash + Display + PartialEq + Eq, N: Clone, E: Clone, -{} +{ +} impl PartialOrd for Node where @@ -728,7 +759,6 @@ where } } -/// An iterator over the node's outbound edges. pub struct IterOut<'a, K, N, E> where K: Clone + Hash + Display + PartialEq + Eq, @@ -745,23 +775,29 @@ where N: Clone, E: Clone, { - type Item = (Node, Node, E); + type Item = Edge; fn next(&mut self) -> Option { match self.node.inner.2.borrow().get_outbound(self.position) { Some(current) => { - self.position += 1; - Some((self.node.clone(), current.0, current.1)) - } - None => None, + match current.0.upgrade() { + Some(node) => { + self.position += 1; + Some(Edge(self.node.clone(), node, current.1.clone())) + }, + None => { + panic!("Target node in the adjacency list of `node = {}` has been dropped.", self.node.key()); + } + } + } + None => None, } } } -/// An iterator over the node's inbound edges. pub struct IterIn<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, + K: Clone + Hash + Display + PartialEq + Eq + Display, N: Clone, E: Clone, { @@ -771,19 +807,26 @@ where impl<'a, K, N, E> Iterator for IterIn<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, + K: Clone + Hash + Display + PartialEq + Eq + Display, N: Clone, E: Clone, { - type Item = (Node, Node, E); + type Item = Edge; fn next(&mut self) -> Option { match self.node.inner.2.borrow().get_inbound(self.position) { Some(current) => { - self.position += 1; - Some((current.0, self.node.clone(), current.1)) - } - None => None, + match current.0.upgrade() { + Some(node) => { + self.position += 1; + Some(Edge(node, self.node.clone(), current.1.clone())) + }, + None => { + panic!("Target node in the adjacency list of `node = {}` has been dropped.", self.node.key()); + } + } + } + None => None, } } } @@ -794,7 +837,7 @@ where N: Clone, E: Clone, { - type Item = (Node, Node, E); + type Item = Edge; type IntoIter = IterOut<'a, K, N, E>; fn into_iter(self) -> Self::IntoIter { diff --git a/src/lib.rs b/src/lib.rs index c01b91e..018acbd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,6 +36,7 @@ //! //! ``` //! use gdsl::*; +//! use gdsl::digraph::*; //! use std::cell::Cell; //! //! // We create a directed graph using the `digraph![]` macro. In the macro @@ -80,7 +81,7 @@ //! // //! // The search-object evaluates lazily. This means that the search is only //! // executed when calling either `search()` or `search_path()`. -//! g['A'].pfs().map(&|u, v, e| { +//! g['A'].pfs().for_each(&mut |Edge(u, v, e)| { //! //! // Since we are using a `Cell` to store the distance we use `get()` to //! // read the distance values. @@ -91,7 +92,8 @@ //! // edge `e`. If this is the case we update the distance stored in the //! // node `v`. //! if v_dist > u_dist + e { v.set(u_dist + e); } -//! }).search(); +//! }).search(); // pfs() is lazy, we need to call search() to execute the +//! // traversal. //! //! // We expect that the distance to the node `E` is 21. //! assert!(g['E'].take() == 21); diff --git a/src/sync_digraph/graph_macros.rs b/src/sync_digraph/graph_macros.rs index 4159859..7428432 100644 --- a/src/sync_digraph/graph_macros.rs +++ b/src/sync_digraph/graph_macros.rs @@ -52,7 +52,7 @@ macro_rules! sync_digraph { () => { { - use gdsl::sync_digraph::Graph; + use gdsl::sync_digraph::*; Graph::::new() } diff --git a/src/sync_digraph/graph_serde.rs b/src/sync_digraph/graph_serde.rs index d73c965..f6b4956 100644 --- a/src/sync_digraph/graph_serde.rs +++ b/src/sync_digraph/graph_serde.rs @@ -17,11 +17,10 @@ where for (_, n) in g.iter() { nodes.push((n.key().clone(), n.value().clone())); - for (u, v, e) in n.iter_out() { + for Edge(u, v, e) in n { edges.push((u.key().clone(), v.key().clone(), e)); } } - (nodes, edges) } diff --git a/src/sync_digraph/mod.rs b/src/sync_digraph/mod.rs index 10d7d0c..b4c0781 100644 --- a/src/sync_digraph/mod.rs +++ b/src/sync_digraph/mod.rs @@ -1,13 +1,12 @@ -//! # Sync Directed Graph +//! # Directed Graph //! -//! This module containes the implementation of a sync directed graph and its -//! node-type and algorithms. Sync means that the nodes and edges are wrapped in -//! a `Arc` and `RwLock` to allow for concurrent access. +//! This module containes the implementation of a directed graph and its +//! node-type and algorithms. //! //! - `Graph` is a container type for a directed graph. //! - `Node` is a node type for a directed graph. -//! - An edge is denoted by a tuple `(u, v, e)` where `u` and `v` are the -//! source and target node and `e` is the edge parameter. +//! - An edge is denoted by a tuple struct `Edge(u, v, e)` where`u` and `v` are +//! the source and target node and `e` is the edge parameter. //! //! # Example //! @@ -45,7 +44,7 @@ mod graph_macros; mod graph_serde; mod node; -pub use crate::sync_digraph::node::*; +pub use self::node::*; use ahash::{AHashMap as HashMap, AHashSet as HashSet}; use std::{fmt::Display, hash::Hash}; @@ -321,7 +320,7 @@ where /// g.insert(Node::new("B", 0)); /// g.insert(Node::new("C", 0)); /// - /// for (key, _)in g.iter() { + /// for (key, _) in g.iter() { /// println!("{}", key); /// } /// ``` @@ -384,7 +383,7 @@ where let cycle = node .dfs() .transpose() - .filter(&|_, v, _| !invariant.contains(v.key())) + .filter(&mut |Edge(_, v, _)| !invariant.contains(v.key())) .search_cycle(); match cycle { Some(cycle) => { @@ -413,7 +412,7 @@ where if !visited.contains(next.key()) { let partition = next .postorder() - .filter(&|_, v, _| !visited.contains(v.key())) + .filter(&mut |Edge(_, v, _)| !visited.contains(v.key())) .search_nodes(); for node in &partition { visited.insert(node.key().clone()); @@ -429,7 +428,7 @@ where s.push_str("digraph {\n"); for (u_key, node) in self.iter() { s.push_str(&format!(" {}", u_key.clone())); - for (_, v, _) in node { + for Edge(_, v, _) in node { s.push_str(&format!("\n {} -> {}", u_key, v.key())); } s.push_str("\n"); @@ -467,9 +466,9 @@ where s.push_str("\n"); } for (_, node) in self.iter() { - for (u, v, edge) in node { + for Edge(u, v, e) in node { s.push_str(&format!("\t{} -> {}", u.key(), v.key())); - if let Some(eattrs) = eattr(&u, &v, &edge) { + if let Some(eattrs) = eattr(&u, &v, &e) { s.push_str(&format!(" {}", Self::fmt_attr(eattrs))); } s.push_str("\n"); diff --git a/src/sync_digraph/node/adjacent.rs b/src/sync_digraph/node/adjacent.rs index ef23e48..42d6577 100644 --- a/src/sync_digraph/node/adjacent.rs +++ b/src/sync_digraph/node/adjacent.rs @@ -1,13 +1,40 @@ use super::*; +#[derive(Clone)] +pub struct WeakNode +where + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, +{ + inner: Weak<(K, N, RwLock>)>, +} + +impl WeakNode +where + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, +{ + pub fn upgrade(&self) -> Option> { + self.inner.upgrade().map(|inner| Node { inner }) + } + + pub fn downgrade(node: &Node) -> Self { + WeakNode { + inner: Arc::downgrade(&node.inner) + } + } +} + pub struct Adjacent where K: Clone + Hash + PartialEq + Eq + Display, N: Clone, E: Clone, { - outbound: Vec<(Node, E)>, - inbound: Vec<(Node, E)>, + outbound: Vec<(WeakNode, E)>, + inbound: Vec<(WeakNode, E)>, } impl Adjacent @@ -23,33 +50,33 @@ where }) } - pub fn get_outbound(&self, idx: usize) -> Option<(Node, E)> { + pub fn get_outbound(&self, idx: usize) -> Option<(&WeakNode, &E)> { match self.outbound.get(idx) { - Some(edge) => Some((edge.0.clone(), edge.1.clone())), + Some(edge) => Some((&edge.0, &edge.1)), None => None, } } - pub fn get_inbound(&self, idx: usize) -> Option<(Node, E)> { + pub fn get_inbound(&self, idx: usize) -> Option<(&WeakNode, &E)> { match self.inbound.get(idx) { - Some(edge) => Some((edge.0.clone(), edge.1.clone())), + Some(edge) => Some((&edge.0, &edge.1)), None => None, } } - pub fn find_outbound(&self, node: &K) -> Option<(Node, E)> { + pub fn find_outbound(&self, node: &K) -> Option<(&WeakNode, &E)> { for edge in self.outbound.iter() { - if edge.0.key() == node { - return Some((edge.0.clone(), edge.1.clone())); + if edge.0.upgrade().unwrap().key() == node { + return Some((&edge.0, &edge.1)); } } None } - pub fn find_inbound(&self, node: &K) -> Option<(Node, E)> { + pub fn find_inbound(&self, node: &K) -> Option<(&WeakNode, &E)> { for edge in self.inbound.iter() { - if edge.0.key() == node { - return Some((edge.0.clone(), edge.1.clone())); + if edge.0.upgrade().unwrap().key() == node { + return Some((&edge.0, &edge.1)); } } None @@ -64,33 +91,29 @@ where } pub fn push_inbound(&mut self, edge: (Node, E)) { - self.inbound.push(edge); + self.inbound.push((WeakNode::downgrade(&edge.0), edge.1)); } pub fn push_outbound(&mut self, edge: (Node, E)) { - self.outbound.push(edge); + self.outbound.push((WeakNode::downgrade(&edge.0), edge.1)); } pub fn remove_inbound(&mut self, source: &K) -> Result { - let idx = self.inbound.iter().position(|edge| edge.0.key() == source); - match idx { - Some(idx) => { - let edge = self.inbound.remove(idx); - Ok(edge.1.clone()) - } - None => Err(()), - } + for (idx, edge) in self.inbound.iter().enumerate() { + if edge.0.upgrade().unwrap().key() == source { + return Ok(self.inbound.remove(idx).1); + } + } + Err(()) } pub fn remove_outbound(&mut self, target: &K) -> Result { - let idx = self.outbound.iter().position(|edge| edge.0.key() == target); - match idx { - Some(idx) => { - let edge = self.outbound.remove(idx); - Ok(edge.1.clone()) - } - None => Err(()), - } + for (idx, edge) in self.outbound.iter().enumerate() { + if edge.0.upgrade().unwrap().key() == target { + return Ok(self.outbound.remove(idx).1); + } + } + Err(()) } pub fn clear_inbound(&mut self) { diff --git a/src/digraph/node/bfs.rs b/src/sync_digraph/node/algo/bfs.rs similarity index 75% rename from src/digraph/node/bfs.rs rename to src/sync_digraph/node/algo/bfs.rs index d04eaa5..0d69604 100644 --- a/src/digraph/node/bfs.rs +++ b/src/sync_digraph/node/algo/bfs.rs @@ -9,7 +9,7 @@ where E: Clone, { root: Node, - target: Option<&'a K>, + target: Option, method: Method<'a, K, N, E>, transpose: Transposition, } @@ -29,8 +29,8 @@ where } } - pub fn target(mut self, target: &'a K) -> Self { - self.target = Some(target); + pub fn target(mut self, target: &K) -> Self { + self.target = Some(target.clone()); self } @@ -39,8 +39,8 @@ where self } - pub fn map(mut self, f: Map<'a, K, N, E>) -> Self { - self.method = Method::Map(f); + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); self } @@ -49,11 +49,6 @@ where self } - pub fn filter_map(mut self, f: FilterMap<'a, K, N, E>) -> Self { - self.method = Method::FilterMap(f); - self - } - pub fn search(&'a mut self) -> Option> { let mut queue = VecDeque::new(); let mut visited = HashSet::default(); @@ -77,7 +72,7 @@ where let mut visited = HashSet::default(); let target_found; - self.target = Some(self.root.key()); + self.target = Some(self.root.key().clone()); queue.push_back(self.root.clone()); match self.transpose { @@ -118,19 +113,22 @@ where } fn loop_outbound( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut VecDeque>, ) -> bool { while let Some(node) = queue.pop_front() { - for (u, v, e) in node.iter_out() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.1.clone(); if !visited.contains(v.key()) { visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } queue.push_back(v.clone()); } @@ -141,19 +139,23 @@ where } fn loop_inbound( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut VecDeque>, ) -> bool { while let Some(node) = queue.pop_front() { - for (v, u, e) in node.iter_in() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.1.clone(); if !visited.contains(v.key()) { visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } queue.push_back(v.clone()); } @@ -164,17 +166,20 @@ where } fn loop_outbound_find( - &self, + &mut self, visited: &mut HashSet, queue: &mut VecDeque>, ) -> Option> { while let Some(node) = queue.pop_front() { - for (u, v, e) in node.iter_out() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let Edge(_, v, _) = edge; if !visited.contains(v.key()) { visited.insert(v.key().clone()); - if self.target.is_some() && self.target.unwrap() == v.key() { - return Some(v); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } } queue.push_back(v.clone()); } @@ -185,17 +190,21 @@ where } fn loop_inbound_find( - &self, + &mut self, visited: &mut HashSet, queue: &mut VecDeque>, ) -> Option> { while let Some(node) = queue.pop_front() { - for (v, u, e) in node.iter_in() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let Edge(_, v, _) = edge; if !visited.contains(v.key()) { visited.insert(v.key().clone()); - if self.target.is_some() && self.target.unwrap() == v.key() { - return Some(v); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } } queue.push_back(v.clone()); } diff --git a/src/sync_digraph/node/dfs.rs b/src/sync_digraph/node/algo/dfs.rs similarity index 75% rename from src/sync_digraph/node/dfs.rs rename to src/sync_digraph/node/algo/dfs.rs index 37a733c..c4d16ff 100644 --- a/src/sync_digraph/node/dfs.rs +++ b/src/sync_digraph/node/algo/dfs.rs @@ -9,7 +9,7 @@ where E: Clone, { root: Node, - target: Option<&'a K>, + target: Option, method: Method<'a, K, N, E>, transpose: Transposition, } @@ -29,8 +29,8 @@ where } } - pub fn target(mut self, target: &'a K) -> Self { - self.target = Some(target); + pub fn target(mut self, target: &K) -> Self { + self.target = Some(target.clone()); self } @@ -39,8 +39,8 @@ where self } - pub fn map(mut self, f: Map<'a, K, N, E>) -> Self { - self.method = Method::Map(f); + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); self } @@ -49,11 +49,6 @@ where self } - pub fn filter_map(mut self, f: FilterMap<'a, K, N, E>) -> Self { - self.method = Method::FilterMap(f); - self - } - pub fn search(&'a mut self) -> Option> { let mut queue = vec![]; let mut visited = HashSet::default(); @@ -77,7 +72,7 @@ where let mut visited = HashSet::default(); let target_found; - self.target = Some(self.root.key()); + self.target = Some(self.root.key().clone()); queue.push(self.root.clone()); match self.transpose { @@ -117,20 +112,23 @@ where None } - fn recurse_outbound(&self, + fn recurse_outbound(&mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (u, v, e) in node.iter_out() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.target().clone(); if visited.contains(v.key()) == false { - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; - } visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } queue.push(v.clone()); if self.recurse_outbound(result, visited, queue) { return true; @@ -142,20 +140,24 @@ where false } - fn recurse_inbound(&self, + fn recurse_inbound(&mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (v, u, e) in node.iter_in() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.target().clone(); if visited.contains(v.key()) == false { - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; - } visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } queue.push(v.clone()); if self.recurse_inbound(result, visited, queue) { return true; @@ -167,18 +169,21 @@ where false } - fn recurse_outbound_find(&self, + fn recurse_outbound_find(&mut self, visited: &mut HashSet, queue: &mut Vec>, ) -> Option> { if let Some(node) = queue.pop() { - for (u, v, e) in node.iter_out() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.target(); if visited.contains(v.key()) == false { - if self.target.is_some() && self.target.unwrap() == v.key() { - return Some(v); - } visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } + } queue.push(v.clone()); match self.recurse_outbound_find(visited, queue) { Some(t) => return Some(t), @@ -191,18 +196,22 @@ where None } - fn recurse_inbound_find(&self, + fn recurse_inbound_find(&mut self, visited: &mut HashSet, queue: &mut Vec>, ) -> Option> { if let Some(node) = queue.pop() { - for (v, u, e) in node.iter_in() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.target(); if visited.contains(v.key()) == false { - if self.target.is_some() && self.target.unwrap() == v.key() { - return Some(v); - } visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } + } queue.push(v.clone()); match self.recurse_inbound_find(visited, queue) { Some(t) => return Some(t), diff --git a/src/sync_digraph/node/algo/method.rs b/src/sync_digraph/node/algo/method.rs new file mode 100644 index 0000000..e552875 --- /dev/null +++ b/src/sync_digraph/node/algo/method.rs @@ -0,0 +1,30 @@ +use super::*; + +pub type Filter<'a, K, N, E> = &'a mut dyn FnMut(&Edge) -> bool; +pub type ForEach<'a, K, N, E> = &'a mut dyn FnMut(&Edge); + +pub enum Method<'a, K, N, E> +where + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, +{ + NullMethod, + Filter(Filter<'a, K, N, E>), + ForEach(ForEach<'a, K, N, E>), +} + +impl<'a, K, N, E> Method<'a, K, N, E> +where + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, +{ + pub fn exec(&mut self, e: &Edge) -> bool { + match self { + Method::NullMethod => true, + Method::ForEach(f) => {f(e); true}, + Method::Filter(f) => f(e), + } + } +} \ No newline at end of file diff --git a/src/sync_digraph/node/algo/mod.rs b/src/sync_digraph/node/algo/mod.rs new file mode 100644 index 0000000..ad8023c --- /dev/null +++ b/src/sync_digraph/node/algo/mod.rs @@ -0,0 +1,9 @@ +use super::*; + +pub mod bfs; +pub mod dfs; +pub mod pfs; +pub mod order; + +mod path; +mod method; \ No newline at end of file diff --git a/src/sync_digraph/node/order.rs b/src/sync_digraph/node/algo/order.rs similarity index 77% rename from src/sync_digraph/node/order.rs rename to src/sync_digraph/node/algo/order.rs index 3f15165..5bb5a67 100644 --- a/src/sync_digraph/node/order.rs +++ b/src/sync_digraph/node/algo/order.rs @@ -2,6 +2,11 @@ use std::{fmt::Display, hash::Hash}; use super::{*, method::*}; use ahash::AHashSet as HashSet; +pub enum Ordering { + Pre, + Post, +} + pub struct Order<'a, K, N, E> where K: Clone + Hash + Display + PartialEq + Eq, @@ -44,8 +49,8 @@ where self } - pub fn map(mut self, f: Map<'a, K, N, E>) -> Self { - self.method = Method::Map(f); + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); self } @@ -54,11 +59,6 @@ where self } - pub fn filter_map(mut self, f: FilterMap<'a, K, N, E>) -> Self { - self.method = Method::FilterMap(f); - self - } - pub fn search_nodes(&mut self) -> Vec> { let mut nodes = vec![]; let mut edges = vec![]; @@ -74,12 +74,12 @@ where Ordering::Pre => { self.preorder_forward(&mut edges, &mut visited, &mut queue); nodes.push(self.root.clone()); - let mut coll = edges.iter().map(|(_, v, _)| v.clone()).collect(); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); nodes.append(&mut coll); }, Ordering::Post => { self.postorder_forward(&mut edges, &mut visited, &mut queue); - let mut coll = edges.iter().map(|(_, v, _)| v.clone()).collect(); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); nodes.append(&mut coll); nodes.push(self.root.clone()); }, @@ -90,12 +90,12 @@ where Ordering::Pre => { self.preorder_backward(&mut edges, &mut visited, &mut queue); nodes.push(self.root.clone()); - let mut coll = edges.iter().map(|(_, v, _)| v.clone()).collect(); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); nodes.append(&mut coll); }, Ordering::Post => { self.postorder_backward(&mut edges, &mut visited, &mut queue); - let mut coll = edges.iter().map(|(_, v, _)| v.clone()).collect(); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); nodes.append(&mut coll); nodes.push(self.root.clone()); }, @@ -139,18 +139,19 @@ where } fn preorder_forward( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (u, v, e) in node.iter_out() { - if visited.contains(v.key()) == false { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + let v = edge.1.clone(); + if self.method.exec(&edge) { + if visited.contains(v.key()) == false { visited.insert(v.key().clone()); queue.push(v.clone()); - result.push((u, v.clone(), e)); + result.push(edge); self.preorder_forward( result, visited, @@ -163,18 +164,20 @@ where } fn preorder_backward( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (v, u, e) in node.iter_in() { - if visited.contains(v.key()) == false { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_in() { + let edge = edge.reverse(); + let v = edge.1.clone(); + if self.method.exec(&edge) { + if visited.contains(v.key()) == false { visited.insert(v.key().clone()); queue.push(v.clone()); - result.push((u, v.clone(), e)); + result.push(edge); self.preorder_forward( result, visited, @@ -187,22 +190,23 @@ where } fn postorder_forward( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (u, v, e) in node.iter_out() { - if visited.contains(v.key()) == false { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + let v = edge.1.clone(); + if self.method.exec(&edge) { + if visited.contains(v.key()) == false { visited.insert(v.key().clone()); queue.push(v.clone()); self.postorder_forward( result, visited, queue); - result.push((u, v.clone(), e)); + result.push(edge); } } } @@ -211,22 +215,24 @@ where } fn postorder_backward( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (v, u, e) in node.iter_in() { - if visited.contains(v.key()) == false { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_in() { + let edge = edge.reverse(); + let v = edge.1.clone(); + if self.method.exec(&edge) { + if visited.contains(v.key()) == false { visited.insert(v.key().clone()); queue.push(v.clone()); self.postorder_forward( result, visited, queue); - result.push((u, v.clone(), e)); + result.push(edge); } } } diff --git a/src/digraph/node/path.rs b/src/sync_digraph/node/algo/path.rs similarity index 93% rename from src/digraph/node/path.rs rename to src/sync_digraph/node/algo/path.rs index b93c32c..6499b8d 100644 --- a/src/digraph/node/path.rs +++ b/src/sync_digraph/node/algo/path.rs @@ -16,10 +16,11 @@ where let w = edge_tree.last().unwrap(); path.push(w.clone()); let mut i = 0; - for (u, v, e) in edge_tree.iter().rev() { - let (s, _, _) = &path[i]; + for edge in edge_tree.iter().rev() { + let Edge(_, v, _) = edge; + let Edge(s, _, _) = &path[i]; if s == v { - path.push((u.clone(), v.clone(), e.clone())); + path.push(edge.clone()); i += 1; } } @@ -121,13 +122,13 @@ where N: Clone, E: Clone, { - type Item = (Node, Node, E); + type Item = Edge; fn next(&mut self) -> Option { match self.path.edges.get(self.position) { Some(edge) => { self.position += 1; - Some((edge.0.clone(), edge.1.clone(), edge.2.clone())) + Some(Edge(edge.0.clone(), edge.1.clone(), edge.2.clone())) } None => None, } diff --git a/src/sync_digraph/node/pfs.rs b/src/sync_digraph/node/algo/pfs.rs similarity index 67% rename from src/sync_digraph/node/pfs.rs rename to src/sync_digraph/node/algo/pfs.rs index 1b9a6f8..42f71bf 100644 --- a/src/sync_digraph/node/pfs.rs +++ b/src/sync_digraph/node/algo/pfs.rs @@ -20,7 +20,7 @@ where E: Clone, { root: Node, - target: Option<&'a K>, + target: Option, method: Method<'a, K, N, E>, transpose: Transposition, priority: Priority, @@ -52,8 +52,8 @@ where self } - pub fn target(mut self, target: &'a K) -> Self { - self.target = Some(target); + pub fn target(mut self, target: &K) -> Self { + self.target = Some(target.clone()); self } @@ -62,8 +62,8 @@ where self } - pub fn map(mut self, f: Map<'a, K, N, E>) -> Self { - self.method = Method::Map(f); + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); self } @@ -72,27 +72,24 @@ where self } - - pub fn filter_map(mut self, f: FilterMap<'a, K, N, E>) -> Self { - self.method = Method::FilterMap(f); - self - } - - fn forward_min( - &self, + fn loop_outbound_min( + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut BinaryHeap>>, ) -> bool { while let Some(node) = queue.pop() { let node = node.0; - for (u, v, e) in node.iter_out() { - if !visited.contains(v.key()) { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } queue.push(Reverse(v.clone())); } @@ -102,21 +99,25 @@ where false } - fn backward_min( - &self, + fn loop_inbound_min( + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut BinaryHeap>>, ) -> bool { while let Some(node) = queue.pop() { let node = node.0; - for (v, u, e) in node.iter_in() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.1.clone(); if !visited.contains(v.key()) { visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } queue.push(Reverse(v.clone())); } @@ -126,20 +127,23 @@ where false } - fn forward_max( - &self, + fn loop_outbound_max( + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut BinaryHeap>, ) -> bool { while let Some(node) = queue.pop() { - for (u, v, e) in node.iter_out() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.1.clone(); if !visited.contains(v.key()) { visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } queue.push(v.clone()); } @@ -149,20 +153,24 @@ where false } - fn backward_max( - &self, + fn loop_inbound_max( + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut BinaryHeap>, ) -> bool { while let Some(node) = queue.pop() { - for (v, u, e) in node.iter_in() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.1.clone(); if !visited.contains(v.key()) { visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } queue.push(v.clone()); } @@ -185,7 +193,7 @@ where let mut visited = HashSet::default(); let target_found; - self.target = Some(self.root.key()); + self.target = Some(self.root.key().clone()); match self.transpose { Transposition::Outbound => { @@ -193,12 +201,12 @@ where Priority::Min => { let mut queue = BinaryHeap::new(); queue.push(Reverse(self.root.clone())); - target_found = self.forward_min(&mut edges, &mut visited, &mut queue); + target_found = self.loop_outbound_min(&mut edges, &mut visited, &mut queue); } Priority::Max => { let mut queue = BinaryHeap::new(); queue.push(self.root.clone()); - target_found = self.forward_max(&mut edges, &mut visited, &mut queue); + target_found = self.loop_outbound_max(&mut edges, &mut visited, &mut queue); } } } @@ -207,12 +215,12 @@ where Priority::Min => { let mut queue = BinaryHeap::new(); queue.push(Reverse(self.root.clone())); - target_found = self.backward_min(&mut edges, &mut visited, &mut queue); + target_found = self.loop_inbound_min(&mut edges, &mut visited, &mut queue); } Priority::Max => { let mut queue = BinaryHeap::new(); queue.push(self.root.clone()); - target_found = self.backward_max(&mut edges, &mut visited, &mut queue); + target_found = self.loop_inbound_max(&mut edges, &mut visited, &mut queue); } } } @@ -236,12 +244,12 @@ where Priority::Min => { let mut queue = BinaryHeap::new(); queue.push(Reverse(self.root.clone())); - target_found = self.forward_min(&mut edges, &mut visited, &mut queue); + target_found = self.loop_outbound_min(&mut edges, &mut visited, &mut queue); } Priority::Max => { let mut queue = BinaryHeap::new(); queue.push(self.root.clone()); - target_found = self.forward_max(&mut edges, &mut visited, &mut queue); + target_found = self.loop_outbound_max(&mut edges, &mut visited, &mut queue); } } } @@ -250,12 +258,12 @@ where Priority::Min => { let mut queue = BinaryHeap::new(); queue.push(Reverse(self.root.clone())); - target_found = self.backward_min(&mut edges, &mut visited, &mut queue); + target_found = self.loop_inbound_min(&mut edges, &mut visited, &mut queue); } Priority::Max => { let mut queue = BinaryHeap::new(); queue.push(self.root.clone()); - target_found = self.backward_max(&mut edges, &mut visited, &mut queue); + target_found = self.loop_inbound_max(&mut edges, &mut visited, &mut queue); } } } diff --git a/src/sync_digraph/node/method.rs b/src/sync_digraph/node/method.rs deleted file mode 100644 index 76ecaa2..0000000 --- a/src/sync_digraph/node/method.rs +++ /dev/null @@ -1,44 +0,0 @@ -use super::*; - -pub type FilterMap<'a, K, N, E> = &'a dyn Fn(&Node, &Node, &E) -> bool; -pub type Filter<'a, K, N, E> = &'a dyn Fn(&Node, &Node, &E) -> bool; -pub type Map<'a, K, N, E> = &'a dyn Fn(&Node, &Node, &E); - -#[derive(Clone)] -pub enum Method<'a, K, N, E> -where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, -{ - NullMethod, - FilterMap(FilterMap<'a, K, N, E>), - Filter(Filter<'a, K, N, E>), - Map(Map<'a, K, N, E>), -} - -impl<'a, K, N, E> Method<'a, K, N, E> -where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, -{ - pub fn exec(&self, u: &Node, v: &Node, e: &E) -> bool { - match self { - Method::NullMethod => true, - Method::Map(f) => {f(u, v, e); true}, - Method::Filter(f) => f(u, v, e), - Method::FilterMap(f) => f(u, v, e), - } - } -} - -pub enum Ordering { - Pre, - Post, -} - -pub enum Transposition { - Outbound, - Inbound, -} \ No newline at end of file diff --git a/src/sync_digraph/node/mod.rs b/src/sync_digraph/node/mod.rs index 749ecac..d10224f 100644 --- a/src/sync_digraph/node/mod.rs +++ b/src/sync_digraph/node/mod.rs @@ -1,4 +1,4 @@ -//! # Node + Send + Sync +//! # Node //! //! `Node` is a key value pair smart-pointer, which includes inbound and //! outbound connections to other nodes. Nodes can be created @@ -30,24 +30,56 @@ //! that a node can be cloned and shared among multiple owners. //! //! This node uses `Arc` for reference counting, thus it is thread-safe. -//! This doesn't mean that all the methods on the node are atomic. -//! The node can be shared among multiple threads, and manipulating -//! its connections is thread-safe. - -mod bfs; -mod dfs; -mod method; -mod order; -mod path; -mod pfs; + mod adjacent; +mod algo; + +use self::{adjacent::*, algo::{bfs::*, dfs::*, order::*, pfs::*}}; +use std::{fmt::Display, hash::Hash, ops::Deref, sync::{Arc, Weak, RwLock}}; -use std::{sync::{RwLock, Arc}, fmt::Display, hash::Hash, ops::Deref}; -use self::{bfs::*, dfs::*, order::*, pfs::*, adjacent::*}; +enum Transposition { + Outbound, + Inbound, +} -/// An edge between nodes is a tuple `(u, v, e)` where `u` is the +/// An edge between nodes is a tuple struct `Edge(u, v, e)` where `u` is the /// source node, `v` is the target node, and `e` is the edge's value. -pub type Edge = (Node, Node, E); +#[derive(Clone, PartialEq)] +pub struct Edge( + pub Node, + pub Node, + pub E, +) where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone; + +impl Edge +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone, +{ + /// Returns the source node of the edge. + pub fn source(&self) -> &Node { + &self.0 + } + + /// Returns the target node of the edge. + pub fn target(&self) -> &Node { + &self.1 + } + + /// Returns the edge's value. + pub fn value(&self) -> &E { + &self.2 + } + + /// Reverse the edge's direction. + pub fn reverse(&self) -> Edge { + Edge(self.1.clone(), self.0.clone(), self.2.clone()) + } +} /// A `Node` is a key value pair smart-pointer, which includes inbound /// and outbound connections to other nodes. Nodes can be created individually @@ -69,7 +101,7 @@ pub type Edge = (Node, Node, E); /// b.connect(&c, 0.09); /// c.connect(&b, 12.9); /// -/// let (u, v, e) = a.iter_out().next().unwrap(); +/// let Edge(u, v, e) = a.iter_out().next().unwrap(); /// /// assert!(u == a); /// assert!(v == b); @@ -142,49 +174,46 @@ where &self.inner.1 } - /// Returns the out-degree of the node. The out degree is the number of - /// outbound edges. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let a = Node::new(0x1, "A"); - /// let b = Node::new(0x2, "B"); - /// let c = Node::new(0x4, "C"); - /// - /// a.connect(&b, 0.42); - /// a.connect(&c, 1.7); - /// - /// assert!(a.out_degree() == 2); - /// ``` - pub fn out_degree(&self) -> usize { - self.inner.2.read().unwrap().len_outbound() - } - - /// Returns the in-degree of the node. The out degree is the number of - /// inbound edges. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let a = Node::new(0x1, "A"); - /// let b = Node::new(0x2, "B"); - /// let c = Node::new(0x4, "C"); - /// - /// b.connect(&a, 0.42); - /// c.connect(&a, 1.7); - /// - /// assert!(a.in_degree() == 2); - pub fn in_degree(&self) -> usize { - self.inner.2 - .read() - .unwrap() - .len_inbound() - } + /// Returns the out-degree of the node. The out degree is the number of + /// outbound edges. + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let a = Node::new(0x1, "A"); + /// let b = Node::new(0x2, "B"); + /// let c = Node::new(0x4, "C"); + /// + /// a.connect(&b, 0.42); + /// a.connect(&c, 1.7); + /// + /// assert!(a.out_degree() == 2); + /// ``` + pub fn out_degree(&self) -> usize { + self.inner.2.read().unwrap().len_outbound() + } + + /// Returns the in-degree of the node. The out degree is the number of + /// inbound edges. + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let a = Node::new(0x1, "A"); + /// let b = Node::new(0x2, "B"); + /// let c = Node::new(0x4, "C"); + /// + /// b.connect(&a, 0.42); + /// c.connect(&a, 1.7); + /// + /// assert!(a.in_degree() == 2); + pub fn in_degree(&self) -> usize { + self.inner.2.read().unwrap().len_inbound() + } /// Connects this node to another node. The connection is created in both /// directions. The connection is created with the given edge value and @@ -204,11 +233,14 @@ where /// assert!(n1.is_connected(n2.key())); /// ``` pub fn connect(&self, other: &Self, value: E) { - self.inner.2 + self.inner + .2 .write() .unwrap() .push_outbound((other.clone(), value.clone())); - other.inner.2 + other + .inner + .2 .write() .unwrap() .push_inbound((self.clone(), value)); @@ -249,7 +281,7 @@ where /// Disconnect two nodes from each other. The connection is removed in both /// directions. Returns Ok(EdgeValue) if the connection was removed, - /// Err(()) if the connection doesn't exist. + /// Err(()) if the connection doesn't exist. /// /// # Example /// @@ -272,12 +304,12 @@ where pub fn disconnect(&self, other: &K) -> Result { match self.find_outbound(other) { Some(other) => match self.inner.2 - .write().unwrap() + .write() + .unwrap() .remove_outbound(other.key()) { Ok(edge) => { - other.inner.2 - .write().unwrap() - .remove_inbound(self.key())?; + other.inner.2.write() + .unwrap().remove_inbound(self.key())?; Ok(edge) } Err(_) => Err(()), @@ -314,186 +346,184 @@ where /// assert!(n1.is_orphan()); /// ``` pub fn isolate(&self) { - for (_, v, _) in self.iter_out() { - v.inner.2 - .write() - .unwrap() - .remove_inbound(self.key()) - .unwrap(); + for Edge(_, v, _) in self.iter_out() { + v.inner.2.write() + .unwrap().remove_inbound(self.key()).unwrap(); } - for (v, _, _) in self.iter_in() { - v.inner.2 - .write() - .unwrap() - .remove_outbound(self.key()) - .unwrap(); + for Edge(v, _, _) in self.iter_in() { + v.inner.2.write() + .unwrap().remove_outbound(self.key()).unwrap(); } - self.inner.2.write().unwrap().clear_outbound(); - self.inner.2.write().unwrap().clear_inbound(); + self.inner.2.write() + .unwrap().clear_outbound(); + self.inner.2.write() + .unwrap().clear_inbound(); } /// Returns true if the node is a root node. Root nodes are nodes that have /// no incoming connections. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// - /// n1.connect(&n2, ()); - /// - /// assert!(n1.is_root()); - /// assert!(!n2.is_root()); - /// ``` + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// + /// n1.connect(&n2, ()); + /// + /// assert!(n1.is_root()); + /// assert!(!n2.is_root()); + /// ``` pub fn is_root(&self) -> bool { self.inner.2.read().unwrap().len_inbound() == 0 } /// Returns true if the node is a leaf node. Leaf nodes are nodes that have /// no outgoing connections. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// - /// n1.connect(&n2, ()); - /// - /// assert!(!n1.is_leaf()); - /// assert!(n2.is_leaf()); - /// ``` + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// + /// n1.connect(&n2, ()); + /// + /// assert!(!n1.is_leaf()); + /// assert!(n2.is_leaf()); + /// ``` pub fn is_leaf(&self) -> bool { self.inner.2.read().unwrap().len_outbound() == 0 } /// Returns true if the node is an oprhan. Orphan nodes are nodes that have /// no connections. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// - /// n1.connect(&n2, ()); - /// - /// assert!(!n1.is_orphan()); - /// - /// n1.disconnect(n2.key()).unwrap(); - /// - /// assert!(n1.is_orphan()); - /// ``` + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// + /// n1.connect(&n2, ()); + /// + /// assert!(!n1.is_orphan()); + /// + /// n1.disconnect(n2.key()).unwrap(); + /// + /// assert!(n1.is_orphan()); + /// ``` pub fn is_orphan(&self) -> bool { self.is_root() && self.is_leaf() } /// Returns true if the node is connected to another node with a given key. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// - /// n1.connect(&n2, ()); - /// - /// assert!(n1.is_connected(n2.key())); - /// ``` + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// + /// n1.connect(&n2, ()); + /// + /// assert!(n1.is_connected(n2.key())); + /// ``` pub fn is_connected(&self, other: &K) -> bool { self.find_outbound(other).is_some() } /// Get a pointer to an adjacent node with a given key. Returns None if no /// node with the given key is found from the node's adjacency list. - /// Outbound edges are searches, this is the default direction. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// - /// n1.connect(&n2, ()); - /// n1.connect(&n3, ()); - /// - /// assert!(n1.find_outbound(n2.key()).is_some()); - /// assert!(n1.find_outbound(n3.key()).is_some()); - /// assert!(n1.find_outbound(&4).is_none()); - /// ``` + /// Outbound edges are searches, this is the default direction. + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// + /// n1.connect(&n2, ()); + /// n1.connect(&n3, ()); + /// + /// assert!(n1.find_outbound(n2.key()).is_some()); + /// assert!(n1.find_outbound(n3.key()).is_some()); + /// assert!(n1.find_outbound(&4).is_none()); + /// ``` pub fn find_outbound(&self, other: &K) -> Option> { - let edge = self.inner.2.read().unwrap().find_outbound(other); + let edge = self.inner.2.read().unwrap(); + let edge = edge.find_outbound(other); if let Some(edge) = edge { - Some(edge.0.clone()) + Some(edge.0.upgrade().unwrap().clone()) } else { None } } - /// Get a pointer to an adjacent node with a given key. Returns None if no - /// node with the given key is found from the node's adjacency list. - /// Inbound edges are searched ie. the transposed graph. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// - /// n1.connect(&n2, ()); - /// n1.connect(&n3, ()); - /// - /// assert!(n2.find_inbound(n1.key()).is_some()); - /// assert!(n3.find_inbound(n1.key()).is_some()); - /// assert!(n1.find_inbound(&4).is_none()); - /// ``` + /// Get a pointer to an adjacent node with a given key. Returns None if no + /// node with the given key is found from the node's adjacency list. + /// Inbound edges are searched ie. the transposed graph. + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// + /// n1.connect(&n2, ()); + /// n1.connect(&n3, ()); + /// + /// assert!(n2.find_inbound(n1.key()).is_some()); + /// assert!(n3.find_inbound(n1.key()).is_some()); + /// assert!(n1.find_inbound(&4).is_none()); + /// ``` pub fn find_inbound(&self, other: &K) -> Option> { - let edge = self.inner.2.read().unwrap().find_inbound(other); + let edge = self.inner.2.read().unwrap(); + let edge = edge.find_inbound(other); if let Some(edge) = edge { - Some(edge.0.clone()) + Some(edge.0.upgrade().unwrap().clone()) } else { None } } - /// Returns an iterator-like object that can be used to map, filter and + /// Returns an iterator-like object that can be used to map, filter and /// collect reachable nodes or edges in different orderings such as /// postorder or preorder. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// - /// n1.connect(&n2, ()); - /// n2.connect(&n3, ()); - /// n3.connect(&n1, ()); - /// - /// let order = n1.preorder().search_nodes(); - /// - /// assert!(order[0] == n1); - /// assert!(order[1] == n2); - /// assert!(order[2] == n3); - /// ``` + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// + /// n1.connect(&n2, ()); + /// n2.connect(&n3, ()); + /// n3.connect(&n1, ()); + /// + /// let order = n1.preorder().search_nodes(); + /// + /// assert!(order[0] == n1); + /// assert!(order[1] == n2); + /// assert!(order[2] == n3); + /// ``` pub fn preorder(&self) -> Order { Order::preorder(self) } @@ -501,91 +531,91 @@ where /// Returns an iterator-like object that can be used to map, filter and /// collect reachable nodes or edges in different orderings such as /// postorder or preorder. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// - /// n1.connect(&n2, ()); - /// n2.connect(&n3, ()); - /// n3.connect(&n1, ()); - /// - /// let order = n1.postorder().search_nodes(); - /// - /// assert!(order[2] == n1); - /// assert!(order[1] == n2); - /// assert!(order[0] == n3); - /// ``` + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// + /// n1.connect(&n2, ()); + /// n2.connect(&n3, ()); + /// n3.connect(&n1, ()); + /// + /// let order = n1.postorder().search_nodes(); + /// + /// assert!(order[2] == n1); + /// assert!(order[1] == n2); + /// assert!(order[0] == n3); + /// ``` pub fn postorder(&self) -> Order { Order::postroder(self) } /// Returns an iterator-like object that can be used to map, filter, /// search and collect nodes or edges resulting from a depth-first search. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// - /// n1.connect(&n2, ()); - /// n2.connect(&n3, ()); - /// n3.connect(&n1, ()); - /// - /// let path = n1 - /// .dfs() - /// .target(&3) - /// .search_path() - /// .unwrap(); - /// - /// let mut iter = path.iter_nodes(); - /// - /// assert!(iter.next().unwrap() == n1); - /// assert!(iter.next().unwrap() == n2); - /// assert!(iter.next().unwrap() == n3); - /// ``` + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// + /// n1.connect(&n2, ()); + /// n2.connect(&n3, ()); + /// n3.connect(&n1, ()); + /// + /// let path = n1 + /// .dfs() + /// .target(&3) + /// .search_path() + /// .unwrap(); + /// + /// let mut iter = path.iter_nodes(); + /// + /// assert!(iter.next().unwrap() == n1); + /// assert!(iter.next().unwrap() == n2); + /// assert!(iter.next().unwrap() == n3); + /// ``` pub fn dfs(&self) -> DFS { DFS::new(self) } /// Returns an iterator-like object that can be used to map, filter, /// search and collect nodes or edges resulting from a breadth-first - /// search. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// - /// n1.connect(&n2, ()); - /// n2.connect(&n3, ()); - /// n3.connect(&n1, ()); - /// - /// let path = n1 - /// .bfs() - /// .target(&3) - /// .search_path() - /// .unwrap(); - /// - /// let mut iter = path.iter_nodes(); - /// - /// assert!(iter.next().unwrap() == n1); - /// assert!(iter.next().unwrap() == n2); - /// assert!(iter.next().unwrap() == n3); - /// ``` + /// search. + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// + /// n1.connect(&n2, ()); + /// n2.connect(&n3, ()); + /// n3.connect(&n1, ()); + /// + /// let path = n1 + /// .bfs() + /// .target(&3) + /// .search_path() + /// .unwrap(); + /// + /// let mut iter = path.iter_nodes(); + /// + /// assert!(iter.next().unwrap() == n1); + /// assert!(iter.next().unwrap() == n2); + /// assert!(iter.next().unwrap() == n3); + /// ``` pub fn bfs(&self) -> BFS { BFS::new(self) } @@ -593,31 +623,31 @@ where /// Returns an iterator-like object that can be used to map, filter, /// search and collect nodes or edges resulting from a /// priority-first search. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new('A', 0); - /// let n2 = Node::new('B', 42); - /// let n3 = Node::new('C', 7); - /// let n4 = Node::new('D', 23); - /// - /// n1.connect(&n2, ()); - /// n1.connect(&n3, ()); - /// n2.connect(&n4, ()); - /// n3.connect(&n4, ()); - /// - /// let path = n1 - /// .pfs() - /// .target(&'D') - /// .search_path() - /// .unwrap(); - /// - /// assert!(path[0] == (n1, n3.clone(), ())); - /// assert!(path[1] == (n3, n4, ())); - ///``` + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new('A', 0); + /// let n2 = Node::new('B', 42); + /// let n3 = Node::new('C', 7); + /// let n4 = Node::new('D', 23); + /// + /// n1.connect(&n2, ()); + /// n1.connect(&n3, ()); + /// n2.connect(&n4, ()); + /// n3.connect(&n4, ()); + /// + /// let path = n1 + /// .pfs() + /// .target(&'D') + /// .search_path() + /// .unwrap(); + /// + /// assert!(path[0] == Edge(n1, n3.clone(), ())); + /// assert!(path[1] == Edge(n3, n4, ())); + ///``` pub fn pfs(&self) -> PFS where N: Ord, @@ -625,24 +655,24 @@ where PFS::new(self) } - /// Returns an iterator over the node's outbound edges. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// - /// n1.connect(&n2, ()); - /// n1.connect(&n3, ()); - /// - /// let mut iter = n1.iter_out(); - /// assert!(iter.next().unwrap() == (n1.clone(), n2.clone(), ())); - /// assert!(iter.next().unwrap() == (n1, n3, ())); - /// ``` + /// Returns an iterator over the node's outbound edges. + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// + /// n1.connect(&n2, ()); + /// n1.connect(&n3, ()); + /// + /// let mut iter = n1.iter_out(); + /// assert!(iter.next().unwrap() == Edge(n1.clone(), n2.clone(), ())); + /// assert!(iter.next().unwrap() == Edge(n1, n3, ())); + /// ``` pub fn iter_out(&self) -> IterOut { IterOut { node: self, @@ -650,25 +680,25 @@ where } } - /// Returns an iterator over the node's inbound edges. - /// - /// # Example - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// - /// n1.connect(&n2, ()); - /// n1.connect(&n3, ()); - /// - /// let mut iter = n2.iter_in(); - /// - /// assert!(iter.next().unwrap() == (n1.clone(), n2.clone(), ())); - /// assert!(iter.next().is_none()); - /// ``` + /// Returns an iterator over the node's inbound edges. + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// + /// n1.connect(&n2, ()); + /// n1.connect(&n3, ()); + /// + /// let mut iter = n2.iter_in(); + /// + /// assert!(iter.next().unwrap() == Edge(n1.clone(), n2.clone(), ())); + /// assert!(iter.next().is_none()); + /// ``` pub fn iter_in(&self) -> IterIn { IterIn { node: self, @@ -676,13 +706,13 @@ where } } - /// Return's the node's size in bytes. + /// Return's the node's size in bytes. pub fn sizeof(&self) -> usize { - std::mem::size_of::>() - + std::mem::size_of::() - + std::mem::size_of::() - + self.inner.2.read().unwrap().sizeof() - + std::mem::size_of::() + std::mem::size_of::>() + + std::mem::size_of::() + + std::mem::size_of::() + + self.inner.2.read().unwrap().sizeof() + + std::mem::size_of::() } } @@ -714,7 +744,8 @@ where K: Clone + Hash + Display + PartialEq + Eq, N: Clone, E: Clone, -{} +{ +} impl PartialOrd for Node where @@ -738,7 +769,6 @@ where } } -/// An iterator over the node's outbound edges. pub struct IterOut<'a, K, N, E> where K: Clone + Hash + Display + PartialEq + Eq, @@ -755,23 +785,22 @@ where N: Clone, E: Clone, { - type Item = (Node, Node, E); + type Item = Edge; fn next(&mut self) -> Option { match self.node.inner.2.read().unwrap().get_outbound(self.position) { Some(current) => { self.position += 1; - Some((self.node.clone(), current.0, current.1)) + Some(Edge(self.node.clone(), current.0.upgrade().unwrap().clone(), current.1.clone())) } None => None, } } } -/// An iterator over the node's inbound edges. pub struct IterIn<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, + K: Clone + Hash + Display + PartialEq + Eq + Display, N: Clone, E: Clone, { @@ -781,17 +810,17 @@ where impl<'a, K, N, E> Iterator for IterIn<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, + K: Clone + Hash + Display + PartialEq + Eq + Display, N: Clone, E: Clone, { - type Item = (Node, Node, E); + type Item = Edge; fn next(&mut self) -> Option { match self.node.inner.2.read().unwrap().get_inbound(self.position) { Some(current) => { self.position += 1; - Some((current.0, self.node.clone(), current.1)) + Some(Edge(current.0.upgrade().unwrap().clone(), self.node.clone(), current.1.clone())) } None => None, } @@ -804,7 +833,7 @@ where N: Clone, E: Clone, { - type Item = (Node, Node, E); + type Item = Edge; type IntoIter = IterOut<'a, K, N, E>; fn into_iter(self) -> Self::IntoIter { diff --git a/src/sync_ungraph/graph_macros.rs b/src/sync_ungraph/graph_macros.rs index f78aa46..45d73ae 100644 --- a/src/sync_ungraph/graph_macros.rs +++ b/src/sync_ungraph/graph_macros.rs @@ -7,7 +7,7 @@ macro_rules! sync_ungraph_node { // graph::Node ( $key:expr ) => { { - use gdsl::sync_ungraph::*; + use gdsl::ungraph::*; Node::new($key, ()) } @@ -16,7 +16,7 @@ macro_rules! sync_ungraph_node { // graph::Node ( $key:expr, $param:expr ) => { { - use gdsl::sync_ungraph::*; + use gdsl::ungraph::*; Node::new($key, $param) } @@ -30,7 +30,7 @@ macro_rules! sync_ungraph_connect { ( $s:expr => $t:expr ) => { { - use gdsl::sync_ungraph::*; + use gdsl::ungraph::*; Node::connect($s, $t, ()) } @@ -38,7 +38,7 @@ macro_rules! sync_ungraph_connect { ( $s:expr => $t:expr, $params:expr ) => { { - use gdsl::sync_ungraph::*; + use gdsl::ungraph::*; Node::connect($s, $t, $params) } @@ -52,7 +52,7 @@ macro_rules! sync_ungraph { () => { { - use gdsl::sync_ungraph::*; + use gdsl::ungraph::Graph; Graph::::new() } @@ -62,7 +62,7 @@ macro_rules! sync_ungraph { ( ($K:ty) $(($NODE:expr) => $( [ $( $EDGE:expr),*] )? )* ) => { { - use gdsl::sync_ungraph::*; + use gdsl::ungraph::*; use gdsl::*; let mut edges = Vec::<($K, $K)>::new(); @@ -97,7 +97,7 @@ macro_rules! sync_ungraph { ( ($K:ty, $N:ty) $(($NODE:expr, $NPARAM:expr) => $( [$( $EDGE:expr) ,*] )? )* ) => { { - use gdsl::sync_ungraph::*; + use gdsl::ungraph::*; use gdsl::*; let mut edges = Vec::<($K, $K)>::new(); @@ -132,7 +132,7 @@ macro_rules! sync_ungraph { ( ($K:ty) => [$E:ty] $(($NODE:expr) => $( [$( ( $EDGE:expr, $EPARAM:expr) ),*] )? )* ) => { { - use gdsl::sync_ungraph::*; + use gdsl::ungraph::*; use gdsl::*; let mut edges = Vec::<($K, $K, $E)>::new(); @@ -167,7 +167,7 @@ macro_rules! sync_ungraph { ( ($K:ty, $N:ty) => [$E:ty] $(($NODE:expr, $NPARAM:expr) => $( [$( ( $EDGE:expr, $EPARAM:expr) ),*] )? )* ) => { { - use gdsl::sync_ungraph::*; + use gdsl::ungraph::*; use gdsl::*; let mut edges = Vec::<($K, $K, $E)>::new(); diff --git a/src/sync_ungraph/graph_serde.rs b/src/sync_ungraph/graph_serde.rs index 56a7a7a..cd1c0fe 100644 --- a/src/sync_ungraph/graph_serde.rs +++ b/src/sync_ungraph/graph_serde.rs @@ -1,8 +1,9 @@ -use serde::Deserialize; -use serde::ser::{Serialize, Serializer, SerializeTuple}; -use serde::de::{self, Visitor}; -use crate::sync_ungraph::node::*; -use crate::sync_ungraph::*; +use serde::{ + Deserialize, + ser::{Serialize, Serializer, SerializeTuple}, + de::{self, Visitor}, +}; +use super::*; fn graph_serde_decompose<'de, K, N, E>(g: &Graph) -> (Vec<(K, N)>, Vec<(K, K, E)>) where @@ -16,7 +17,7 @@ where for (_, n) in g.iter() { nodes.push((n.key().clone(), n.value().clone())); - for (u, v, e) in n.iter() { + for Edge(u, v, e) in n.iter() { edges.push((u.key().clone(), v.key().clone(), e)); } } diff --git a/src/sync_ungraph/mod.rs b/src/sync_ungraph/mod.rs index 2a07a2a..62c01df 100644 --- a/src/sync_ungraph/mod.rs +++ b/src/sync_ungraph/mod.rs @@ -1,13 +1,9 @@ //! Undirected Graph -//==== Submodules ============================================================= - mod node; mod graph_macros; mod graph_serde; -//==== Includes =============================================================== - use std::{ fmt::Display, hash::Hash, @@ -15,7 +11,7 @@ use std::{ use ahash::HashMap as HashMap; -pub use crate::sync_ungraph::node::*; +pub use self::node::*; pub struct Graph where @@ -232,7 +228,7 @@ where s.push_str("digraph {\n"); for (u_key, node) in self.iter() { s.push_str(&format!(" {}", u_key.clone())); - for (_, v, _) in node { + for Edge(_, v, _) in node { s.push_str(&format!("\n {} -> {}", u_key, v.key())); } s.push_str("\n"); diff --git a/src/sync_ungraph/node/adjacent.rs b/src/sync_ungraph/node/adjacent.rs new file mode 100644 index 0000000..a00ea30 --- /dev/null +++ b/src/sync_ungraph/node/adjacent.rs @@ -0,0 +1,143 @@ +use super::*; + +#[derive(Clone)] +pub struct WeakNode +where + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, +{ + inner: Weak<(K, N, RwLock>)>, +} + +impl WeakNode +where + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, +{ + pub fn upgrade(&self) -> Option> { + self.inner.upgrade().map(|inner| Node { inner }) + } + + pub fn downgrade(node: &Node) -> Self { + WeakNode { + inner: Arc::downgrade(&node.inner) + } + } +} + +pub struct Adjacent +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone, +{ + outbound: Vec<(WeakNode, E)>, + inbound: Vec<(WeakNode, E)>, +} + +impl Adjacent +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone, +{ + pub fn new() -> RwLock { + RwLock::new(Self { + outbound: Vec::new(), + inbound: Vec::new(), + }) + } + + pub fn get_adjacent(&self, idx: usize) -> Option<(&WeakNode, &E)> { + match self.outbound.get(idx) { + Some(edge) => Some((&edge.0, &edge.1)), + None => match self.inbound.get(idx - self.outbound.len()) { + Some(edge) => Some((&edge.0, &edge.1)), + None => None, + }, + } + } + + pub fn find_outbound(&self, node: &K) -> Option<(&WeakNode, &E)> { + for edge in self.outbound.iter() { + if edge.0.upgrade().unwrap().key() == node { + return Some((&edge.0, &edge.1)); + } + } + None + } + + pub fn find_inbound(&self, node: &K) -> Option<(&WeakNode, &E)> { + for edge in self.inbound.iter() { + if edge.0.upgrade().unwrap().key() == node { + return Some((&edge.0, &edge.1)); + } + } + None + } + + pub fn find_adjacent(&self, node: &K) -> Option<(&WeakNode, &E)> { + match self.find_outbound(node) { + Some(edge) => Some(edge), + None => self.find_inbound(node), + } + } + + pub fn len_outbound(&self) -> usize { + self.outbound.len() + } + + pub fn len_inbound(&self) -> usize { + self.inbound.len() + } + + pub fn push_inbound(&mut self, edge: (Node, E)) { + self.inbound.push((WeakNode::downgrade(&edge.0), edge.1)); + } + + pub fn push_outbound(&mut self, edge: (Node, E)) { + self.outbound.push((WeakNode::downgrade(&edge.0), edge.1)); + } + + pub fn remove_inbound(&mut self, source: &K) -> Result { + for (idx, edge) in self.inbound.iter().enumerate() { + if edge.0.upgrade().unwrap().key() == source { + return Ok(self.inbound.remove(idx).1); + } + } + Err(()) + } + + pub fn remove_outbound(&mut self, target: &K) -> Result { + for (idx, edge) in self.outbound.iter().enumerate() { + if edge.0.upgrade().unwrap().key() == target { + return Ok(self.outbound.remove(idx).1); + } + } + Err(()) + } + + pub fn remove_undirected(&mut self, node: &K) -> Result { + match self.remove_inbound(node) { + Ok(edge) => Ok(edge), + Err(_) => self.remove_outbound(node), + } + } + + pub fn clear_inbound(&mut self) { + self.inbound.clear(); + } + + pub fn clear_outbound(&mut self) { + self.outbound.clear(); + } + + pub fn sizeof(&self) -> usize { + self.inbound.len() + self.outbound.len() + * (std::mem::size_of::>() + + std::mem::size_of::()) + + std::mem::size_of::() + } +} \ No newline at end of file diff --git a/src/ungraph/node/bfs.rs b/src/sync_ungraph/node/algo/bfs.rs similarity index 70% rename from src/ungraph/node/bfs.rs rename to src/sync_ungraph/node/algo/bfs.rs index 9d7671e..7518557 100644 --- a/src/ungraph/node/bfs.rs +++ b/src/sync_ungraph/node/algo/bfs.rs @@ -1,15 +1,6 @@ -//==== Includes =============================================================== - -use std::{ - fmt::Display, - hash::Hash, - collections::VecDeque -}; - -use ahash::HashSet as HashSet; - -use crate::ungraph::node::*; -use self::{method::*, path::*}; +use std::{fmt::Display, hash::Hash, collections::VecDeque}; +use super::{*, method::*, path::*}; +use ahash::AHashSet as HashSet; pub struct BFS<'a, K, N, E> where @@ -18,7 +9,7 @@ where E: Clone, { root: Node, - target: Option<&'a K>, + target: Option, method: Method<'a, K, N, E>, } @@ -37,12 +28,12 @@ where } pub fn target(mut self, target: &'a K) -> Self { - self.target = Some(target); + self.target = Some(target.clone()); self } - pub fn map(mut self, f: Map<'a, K, N, E>) -> Self { - self.method = Method::Map(f); + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); self } @@ -51,25 +42,23 @@ where self } - pub fn filter_map(mut self, f: FilterMap<'a, K, N, E>) -> Self { - self.method = Method::FilterMap(f); - self - } - fn loop_adjacent( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut VecDeque>, ) -> bool { while let Some(node) = queue.pop_front() { - for (u, v, e) in node.iter() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.target().clone(); if !visited.contains(v.key()) { visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } queue.push_back(v.clone()); } @@ -80,17 +69,20 @@ where } fn loop_adjacent_find( - &self, + &mut self, visited: &mut HashSet, queue: &mut VecDeque>, ) -> Option> { while let Some(node) = queue.pop_front() { - for (u, v, e) in node.iter() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.target(); if !visited.contains(v.key()) { visited.insert(v.key().clone()); - if self.target.is_some() && self.target.unwrap() == v.key() { - return Some(v); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } } queue.push_back(v.clone()); } @@ -115,7 +107,7 @@ where let mut queue = VecDeque::new(); let mut visited = HashSet::default(); - self.target = Some(self.root.key()); + self.target = Some(self.root.key().clone()); queue.push_back(self.root.clone()); if self.loop_adjacent(&mut edges, &mut visited, &mut queue) { diff --git a/src/ungraph/node/dfs.rs b/src/sync_ungraph/node/algo/dfs.rs similarity index 67% rename from src/ungraph/node/dfs.rs rename to src/sync_ungraph/node/algo/dfs.rs index b32dd27..523112f 100644 --- a/src/ungraph/node/dfs.rs +++ b/src/sync_ungraph/node/algo/dfs.rs @@ -1,17 +1,6 @@ -//==== Includes =============================================================== - -use std::{ - fmt::Display, - hash::Hash, - // collections::HashSet -}; - -use ahash::HashSet as HashSet; -use crate::ungraph::node::*; - -use self::{method::*, path::*}; - -//==== DFS ==================================================================== +use std::{fmt::Display, hash::Hash}; +use super::{*, method::*, path::*}; +use ahash::AHashSet as HashSet; pub struct DFS<'a, K, N, E> where @@ -20,7 +9,7 @@ where E: Clone, { root: Node, - target: Option<&'a K>, + target: Option, method: Method<'a, K, N, E>, } @@ -38,13 +27,13 @@ where } } - pub fn target(mut self, target: &'a K) -> Self { - self.target = Some(target); + pub fn target(mut self, target: &K) -> Self { + self.target = Some(target.clone()); self } - pub fn map(mut self, f: Map<'a, K, N, E>) -> Self { - self.method = Method::Map(f); + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); self } @@ -53,25 +42,23 @@ where self } - pub fn filter_map(mut self, f: FilterMap<'a, K, N, E>) -> Self { - self.method = Method::FilterMap(f); - self - } - - fn recurse_adjacent(&self, + fn recurse_adjacent(&mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (u, v, e) in node.iter() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.target().clone(); if visited.contains(v.key()) == false { - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; - } visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } queue.push(v.clone()); if self.recurse_adjacent(result, visited, queue) { return true; @@ -83,18 +70,21 @@ where false } - fn recurse_adjacent_find(&self, + fn recurse_adjacent_find(&mut self, visited: &mut HashSet, queue: &mut Vec>, ) -> Option> { if let Some(node) = queue.pop() { - for (u, v, e) in node.iter() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.target(); if visited.contains(v.key()) == false { - if self.target.is_some() && self.target.unwrap() == v.key() { - return Some(v); - } visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } + } queue.push(v.clone()); match self.recurse_adjacent_find(visited, queue) { Some(t) => return Some(t), @@ -122,7 +112,7 @@ where let mut queue = vec![]; let mut visited = HashSet::default(); - self.target = Some(self.root.key()); + self.target = Some(self.root.key().clone()); queue.push(self.root.clone()); if self.recurse_adjacent(&mut edges, &mut visited, &mut queue) { diff --git a/src/sync_ungraph/node/algo/method.rs b/src/sync_ungraph/node/algo/method.rs new file mode 100644 index 0000000..c973f3b --- /dev/null +++ b/src/sync_ungraph/node/algo/method.rs @@ -0,0 +1,30 @@ +use super::*; + +pub type Filter<'a, K, N, E> = &'a mut dyn FnMut(&Edge) -> bool; +pub type ForEach<'a, K, N, E> = &'a mut dyn FnMut(&Edge); + +pub enum Method<'a, K, N, E> +where + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, +{ + NullMethod, + Filter(Filter<'a, K, N, E>), + ForEach(ForEach<'a, K, N, E>), +} + +impl<'a, K, N, E> Method<'a, K, N, E> +where + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, +{ + pub fn exec(&mut self, e: &Edge) -> bool { + match self { + Method::NullMethod => true, + Method::Filter(f) => f(e), + Method::ForEach(f) => {f(e); true}, + } + } +} \ No newline at end of file diff --git a/src/sync_ungraph/node/algo/mod.rs b/src/sync_ungraph/node/algo/mod.rs new file mode 100644 index 0000000..ad8023c --- /dev/null +++ b/src/sync_ungraph/node/algo/mod.rs @@ -0,0 +1,9 @@ +use super::*; + +pub mod bfs; +pub mod dfs; +pub mod pfs; +pub mod order; + +mod path; +mod method; \ No newline at end of file diff --git a/src/sync_ungraph/node/order.rs b/src/sync_ungraph/node/algo/order.rs similarity index 80% rename from src/sync_ungraph/node/order.rs rename to src/sync_ungraph/node/algo/order.rs index 276da54..eaa1b64 100644 --- a/src/sync_ungraph/node/order.rs +++ b/src/sync_ungraph/node/algo/order.rs @@ -12,6 +12,11 @@ use super::method::*; //==== Ordering =============================================================== +pub enum Ordering { + Pre, + Post, +} + pub struct Order<'a, K, N, E> where K: Clone + Hash + Display + PartialEq + Eq, @@ -48,8 +53,8 @@ where self } - pub fn map(mut self, f: Map<'a, K, N, E>) -> Self { - self.method = Method::Map(f); + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); self } @@ -58,12 +63,6 @@ where self } - - pub fn filter_map(mut self, f: FilterMap<'a, K, N, E>) -> Self { - self.method = Method::FilterMap(f); - self - } - pub fn search_nodes(&mut self) -> Vec> { let mut nodes = vec![]; let mut edges = vec![]; @@ -77,12 +76,12 @@ where Ordering::Pre => { self.recurse_preorder(&mut edges, &mut visited, &mut queue); nodes.push(self.root.clone()); - let mut coll = edges.iter().map(|(_, v, _)| v.clone()).collect(); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); nodes.append(&mut coll); }, Ordering::Post => { self.recurse_postorder(&mut edges, &mut visited, &mut queue); - let mut coll = edges.iter().map(|(_, v, _)| v.clone()).collect(); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); nodes.append(&mut coll); nodes.push(self.root.clone()); }, @@ -110,18 +109,20 @@ where } fn recurse_preorder( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (u, v, e) in node.iter() { - if visited.contains(v.key()) == false { - if self.method.exec(&u, &v, &e) { + for edge in node.iter() { + let edge = edge.reverse(); + let v = edge.1.clone(); + if self.method.exec(&edge) { + if visited.contains(v.key()) == false { visited.insert(v.key().clone()); queue.push(v.clone()); - result.push((u, v.clone(), e)); + result.push(edge); self.recurse_preorder( result, visited, @@ -134,22 +135,23 @@ where } fn recurse_postorder( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (u, v, e) in node.iter() { - if visited.contains(v.key()) == false { - if self.method.exec(&u, &v, &e) { + for edge in node.iter() { + let v = edge.1.clone(); + if self.method.exec(&edge) { + if visited.contains(v.key()) == false { visited.insert(v.key().clone()); queue.push(v.clone()); self.recurse_postorder( result, visited, queue); - result.push((u, v.clone(), e)); + result.push(edge); } } } diff --git a/src/ungraph/node/path.rs b/src/sync_ungraph/node/algo/path.rs similarity index 85% rename from src/ungraph/node/path.rs rename to src/sync_ungraph/node/algo/path.rs index 0128451..6499b8d 100644 --- a/src/ungraph/node/path.rs +++ b/src/sync_ungraph/node/algo/path.rs @@ -1,9 +1,5 @@ -use std::{ - fmt::Display, - hash::Hash, ops::Index, -}; - -use crate::ungraph::node::*; +use std::{fmt::Display, hash::Hash, ops::Index}; +use super::*; pub fn backtrack_edge_tree(edge_tree: Vec>) -> Vec> where @@ -20,10 +16,11 @@ where let w = edge_tree.last().unwrap(); path.push(w.clone()); let mut i = 0; - for (u, v, e) in edge_tree.iter().rev() { - let (s, _, _) = &path[i]; + for edge in edge_tree.iter().rev() { + let Edge(_, v, _) = edge; + let Edge(s, _, _) = &path[i]; if s == v { - path.push((u.clone(), v.clone(), e.clone())); + path.push(edge.clone()); i += 1; } } @@ -46,6 +43,13 @@ where N: Clone, E: Clone, { + pub fn len(&self) -> usize { + // Conceptually a path always contains at least one node, + // the root node. The path containes edges, so the length + // of the path is the number of edges plus one. + self.edges.len() + 1 + } + pub fn from_edge_tree(edge_tree: Vec>) -> Path { Path { edges: backtrack_edge_tree(edge_tree) } } @@ -118,13 +122,13 @@ where N: Clone, E: Clone, { - type Item = (Node, Node, E); + type Item = Edge; fn next(&mut self) -> Option { match self.path.edges.get(self.position) { Some(edge) => { self.position += 1; - Some((edge.0.clone(), edge.1.clone(), edge.2.clone())) + Some(Edge(edge.0.clone(), edge.1.clone(), edge.2.clone())) } None => None, } @@ -167,4 +171,4 @@ where None => None, } } -} +} \ No newline at end of file diff --git a/src/ungraph/node/pfs.rs b/src/sync_ungraph/node/algo/pfs.rs similarity index 56% rename from src/ungraph/node/pfs.rs rename to src/sync_ungraph/node/algo/pfs.rs index a6617e2..eadf25e 100644 --- a/src/ungraph/node/pfs.rs +++ b/src/sync_ungraph/node/algo/pfs.rs @@ -1,16 +1,11 @@ -//==== Includes =============================================================== - use std::{ fmt::Display, hash::Hash, + collections::BinaryHeap, + cmp::Reverse }; - -use ahash::HashSet as HashSet; -use min_max_heap::MinMaxHeap; - -use crate::ungraph::node::*; -use crate::ungraph::node::path::*; -use self::method::*; +use super::{*, method::*, path::*}; +use ahash::AHashSet as HashSet; enum Priority { Min, @@ -24,7 +19,7 @@ where E: Clone, { root: Node, - target: Option<&'a K>, + target: Option, method: Method<'a, K, N, E>, priority: Priority, } @@ -55,12 +50,12 @@ where } pub fn target(mut self, target: &'a K) -> Self { - self.target = Some(target); + self.target = Some(target.clone()); self } - pub fn map(mut self, f: Map<'a, K, N, E>) -> Self { - self.method = Method::Map(f); + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); self } @@ -69,28 +64,25 @@ where self } - - pub fn filter_map(mut self, f: FilterMap<'a, K, N, E>) -> Self { - self.method = Method::FilterMap(f); - self - } - - fn recurse_min( - &self, + fn loop_min( + &mut self, result: &mut Vec>, visited: &mut HashSet, - queue: &mut MinMaxHeap>, + queue: &mut BinaryHeap>>, ) -> bool { - while let Some(node) = queue.pop_min() { - for (u, v, e) in node.iter() { - if self.method.exec(&u, &v, &e) { + while let Some(Reverse(node)) = queue.pop() { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.1.clone(); if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } - queue.push(v.clone()); + visited.insert(v.key().clone()); + result.push(edge); + queue.push(Reverse(v)); } } } @@ -98,22 +90,25 @@ where false } - fn recurse_max( - &self, + fn loop_max( + &mut self, result: &mut Vec>, visited: &mut HashSet, - queue: &mut MinMaxHeap>, + queue: &mut BinaryHeap>, ) -> bool { - while let Some(node) = queue.pop_max() { - for (u, v, e) in node.iter() { - if self.method.exec(&u, &v, &e) { + while let Some(node) = queue.pop() { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.1.clone(); if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } - queue.push(v.clone()); + visited.insert(v.key().clone()); + result.push(edge); + queue.push(v); } } } @@ -131,19 +126,21 @@ where pub fn search_cycle(&'a mut self) -> Option> { let mut edges = vec![]; - let mut queue = MinMaxHeap::new(); let mut visited = HashSet::default(); let target_found; - self.target = Some(self.root.key()); - queue.push(self.root.clone()); + self.target = Some(self.root.key().clone()); match self.priority { Priority::Min => { - target_found = self.recurse_min(&mut edges, &mut visited, &mut queue); + let mut queue = BinaryHeap::new(); + queue.push(Reverse(self.root.clone())); + target_found = self.loop_min(&mut edges, &mut visited, &mut queue); } Priority::Max => { - target_found = self.recurse_max(&mut edges, &mut visited, &mut queue); + let mut queue = BinaryHeap::new(); + queue.push(self.root.clone()); + target_found = self.loop_max(&mut edges, &mut visited, &mut queue); } } if target_found { @@ -154,19 +151,21 @@ where pub fn search_path(&mut self) -> Option> { let mut edges = vec![]; - let mut queue = MinMaxHeap::new(); let mut visited = HashSet::default(); let target_found; - queue.push(self.root.clone()); visited.insert(self.root.key().clone()); match self.priority { Priority::Min => { - target_found = self.recurse_min(&mut edges, &mut visited, &mut queue); + let mut queue = BinaryHeap::new(); + queue.push(Reverse(self.root.clone())); + target_found = self.loop_min(&mut edges, &mut visited, &mut queue); } Priority::Max => { - target_found = self.recurse_max(&mut edges, &mut visited, &mut queue); + let mut queue = BinaryHeap::new(); + queue.push(self.root.clone()); + target_found = self.loop_max(&mut edges, &mut visited, &mut queue); } } if target_found { diff --git a/src/sync_ungraph/node/method.rs b/src/sync_ungraph/node/method.rs deleted file mode 100644 index 34aba3b..0000000 --- a/src/sync_ungraph/node/method.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::sync_ungraph::node::*; - -pub type FilterMap<'a, K, N, E> = &'a dyn Fn(&Node, &Node, &E) -> bool; -pub type Filter<'a, K, N, E> = &'a dyn Fn(&Node, &Node, &E) -> bool; -pub type Map<'a, K, N, E> = &'a dyn Fn(&Node, &Node, &E); - -#[derive(Clone)] -pub enum Method<'a, K, N, E> -where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, -{ - NullMethod, - FilterMap(FilterMap<'a, K, N, E>), - Filter(Filter<'a, K, N, E>), - Map(Map<'a, K, N, E>), -} - -impl<'a, K, N, E> Method<'a, K, N, E> -where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, -{ - pub fn exec(&self, u: &Node, v: &Node, e: &E) -> bool { - match self { - Method::NullMethod => true, - Method::Map(f) => {f(u, v, e); true}, - Method::Filter(f) => f(u, v, e), - Method::FilterMap(f) => f(u, v, e), - } - } -} - -pub enum Ordering { - Pre, - Post, -} diff --git a/src/sync_ungraph/node/mod.rs b/src/sync_ungraph/node/mod.rs index dd6b451..7ba1e94 100644 --- a/src/sync_ungraph/node/mod.rs +++ b/src/sync_ungraph/node/mod.rs @@ -31,34 +31,104 @@ //! //! This node uses `Arc` for reference counting, thus it is thread-safe. -mod method; -mod order; -mod bfs; -mod dfs; -mod pfs; -mod path; +mod algo; +mod adjacent; use std::{ fmt::Display, hash::Hash, - sync::{RwLock, Arc, Weak}, ops::Deref, + sync::{Arc, Weak, RwLock}, }; use self::{ - pfs::*, - dfs::*, - bfs::*, - order::*, + algo::{ + pfs::*, + dfs::*, + bfs::*, + order::*, + }, + adjacent::*, }; -// pub use self::path::Path; +/// An edge between nodes is a tuple struct `Edge(u, v, e)` where `u` is the +/// source node, `v` is the target node, and `e` is the edge's value. +#[derive(Clone)] +pub struct Edge( + pub Node, + pub Node, + pub E, +) where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone; -//==== PUBLIC ================================================================= + impl Edge +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone, +{ + /// Returns the source node of the edge. + pub fn source(&self) -> &Node { + &self.0 + } -/// An edge between nodes is a tuple `(u, v, e)` where `u` is the -/// source node, `v` is the target node, and `e` is the edge's value. -pub type Edge = (Node, Node, E); + /// Returns the target node of the edge. + pub fn target(&self) -> &Node { + &self.1 + } + + /// Returns the edge's value. + pub fn value(&self) -> &E { + &self.2 + } + + /// Reverse the edge's direction. + pub fn reverse(&self) -> Edge { + Edge(self.1.clone(), self.0.clone(), self.2.clone()) + } +} + +impl PartialEq for Edge +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + Ord +{ + fn eq(&self, other: &Edge) -> bool { + self.2 == other.2 + } +} + +impl Eq for Edge +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + Ord +{} + +impl PartialOrd for Edge +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + Ord +{ + fn partial_cmp(&self, other: &Edge) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Edge +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + Ord +{ + fn cmp(&self, other: &Edge) -> std::cmp::Ordering { + self.2.cmp(&other.2) + } +} /// A `Node` is a key value pair smart-pointer, which includes inbound and /// outbound connections to other nodes. Nodes can be created individually and they @@ -80,7 +150,7 @@ pub type Edge = (Node, Node, E); /// b.connect(&c, 0.09); /// c.connect(&b, 12.9); /// -/// let (u, v, e) = a.iter().next().unwrap(); +/// let Edge(u, v, e) = a.iter().next().unwrap(); /// /// assert!(u == a); /// assert!(v == b); @@ -89,11 +159,11 @@ pub type Edge = (Node, Node, E); #[derive(Clone)] pub struct Node where - K: Clone + Hash + PartialEq + Eq + Display, + K: Clone + Hash + PartialEq + Eq + Display, N: Clone, E: Clone, { - inner: Arc>, + inner: Arc<(K, N, RwLock>)>, } impl Node @@ -118,13 +188,9 @@ where /// assert!(*n1.value() == 'A'); /// ``` pub fn new(key: K, value: N) -> Self { - Node { - inner: Arc::new(NodeInner { - key, - value, - edges: Adjacent::new(), - }), - } + Node { + inner: Arc::new((key, value, Adjacent::new())), + } } /// Returns a reference to the node's key. @@ -139,7 +205,7 @@ where /// assert!(*n1.key() == 1); /// ``` pub fn key(&self) -> &K { - &self.inner.key + &self.inner.0 } /// Returns a reference to the node's value. @@ -154,7 +220,29 @@ where /// assert!(*n1.value() == 'A'); /// ``` pub fn value(&self) -> &N { - &self.inner.value + &self.inner.1 + } + + /// Returns the degree of the node. The degree is the number of + /// adjacent edges. + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let a = Node::new(0x1, "A"); + /// let b = Node::new(0x2, "B"); + /// let c = Node::new(0x4, "C"); + /// + /// a.connect(&b, 0.42); + /// a.connect(&c, 1.7); + /// + /// assert!(a.out_degree() == 2); + /// ``` + pub fn degree(&self) -> usize { + self.inner.2.read().unwrap().len_outbound() + + self.inner.2.read().unwrap().len_inbound() } /// Connects this node to another node. The connection is created in both @@ -174,12 +262,19 @@ where /// /// assert!(n1.is_connected(n2.key())); /// ``` - pub fn connect(&self, other: &Node, value: E) { - let edge = EdgeInner::new(other, value.clone()); - let rev_edge = EdgeInner::new(&self, value); - self.inner.edges.push_outbound(edge); - other.inner.edges.push_inbound(rev_edge); - } + pub fn connect(&self, other: &Self, value: E) { + self.inner + .2 + .write() + .unwrap() + .push_outbound((other.clone(), value.clone())); + other + .inner + .2 + .write() + .unwrap() + .push_inbound((self.clone(), value)); + } /// Connects this node to another node. The connection is created in both /// directions. The connection is created with the given edge value and @@ -237,18 +332,8 @@ where /// assert!(!n1.is_connected(n2.key())); /// ``` pub fn disconnect(&self, other: &K) -> Result { - match self.find_adjacent(other) { - Some(other) => { - match self.inner.edges.remove_outbound(other.key()) { - Ok(edge) => { - other.inner.edges.remove_inbound(self.key())?; - Ok(edge) - }, - Err(_) => Err(()), - } - }, - None => Err(()), - } + self.inner.2.write() + .unwrap().remove_undirected(other) } /// Removes all inbound and outbound connections to and from the node. @@ -279,19 +364,23 @@ where /// assert!(n1.is_orphan()); /// ``` pub fn isolate(&self) { - for (_, v, _) in self.iter() { - if v.inner.edges.remove_inbound(self.key()).is_err() { - v.inner.edges.remove_outbound(self.key()).unwrap(); + for Edge(_, v, _) in self.iter() { + if v.inner.2.write() + .unwrap().remove_inbound(self.key()).is_err() { + v.inner.2.write() + .unwrap().remove_outbound(self.key()).unwrap(); } } - self.inner.edges.clear_outbound(); - self.inner.edges.clear_inbound(); + self.inner.2.write() + .unwrap().clear_outbound(); + self.inner.2.write() + .unwrap().clear_inbound(); } /// Returns true if the node is an oprhan. Orphan nodes are nodes that have /// no connections. pub fn is_orphan(&self) -> bool { - self.inner.edges.len_outbound() == 0 && self.inner.edges.len_inbound() == 0 + self.inner.2.read().unwrap().len_outbound() == 0 && self.inner.2.read().unwrap().len_inbound() == 0 } /// Returns true if the node is connected to another node with a given key. @@ -302,16 +391,9 @@ where /// Get a pointer to an adjacent node with a given key. Returns None if no /// node with the given key is found from the node's adjacency list. pub fn find_adjacent(&self, other: &K) -> Option> { - let edge = self.inner.edges.find_outbound(other); - if let Some(edge) = edge { - Some(edge.target().clone()) - } else { - let edge = self.inner.edges.find_inbound(other); - if let Some(edge) = edge { - Some(edge.target().clone()) - } else { - None - } + match self.inner.2.read().unwrap().find_adjacent(other) { + Some((n, _)) => Some(n.upgrade().unwrap()), + None => None, } } @@ -350,12 +432,12 @@ where } pub fn sizeof(&self) -> usize { - let len_in = self.inner.edges.len_inbound(); - let len_out = self.inner.edges.len_outbound(); - let size_edges = (len_in + len_out) * std::mem::size_of::>(); - let size_node_inner = std::mem::size_of::>(); - size_edges + size_node_inner + 8 - } + std::mem::size_of::>() + + std::mem::size_of::() + + std::mem::size_of::() + + self.inner.2.read().unwrap().sizeof() + + std::mem::size_of::() + } } //==== TRAIT IMPLEMENTATIONS ================================================== @@ -428,32 +510,16 @@ where N: Clone, E: Clone, { - type Item = (Node, Node, E); + type Item = Edge; fn next(&mut self) -> Option { - let adjacent = &self.node.inner.edges; - match adjacent.get_outbound(self.position) { - Some(current) => { + let adjacent = &self.node.inner.2.read().unwrap(); + match adjacent.get_adjacent(self.position) { + Some((n, e)) => { self.position += 1; - Some(( - self.node.clone(), - current.target().clone(), - current.value.clone() - )) + Some(Edge(self.node.clone(), n.upgrade().unwrap(), e.clone())) } - None => { - match adjacent.get_inbound(self.position - adjacent.len_outbound()) { - Some(current) => { - self.position += 1; - Some(( - self.node.clone(), - current.target().clone(), - current.value.clone() - )) - } - None => None - } - }, + None => None, } } } @@ -464,205 +530,10 @@ where N: Clone, E: Clone, { - type Item = (Node, Node, E); + type Item = Edge; type IntoIter = NodeIterator<'a, K, N, E>; fn into_iter(self) -> Self::IntoIter { NodeIterator { node: self, position: 0 } } -} - -//==== PRIVATE ================================================================ - -struct NodeInner -where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, -{ - key: K, - value: N, - edges: Adjacent, -} - -#[derive(Clone)] -struct WeakNode -where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, -{ - inner: Weak>, -} - -impl WeakNode -where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, -{ - fn upgrade(&self) -> Option> { - self.inner.upgrade().map(|inner| Node { inner }) - } - - fn downgrade(node: &Node) -> Self { - WeakNode { - inner: Arc::downgrade(&node.inner) - } - } -} - -#[derive(Clone)] -struct EdgeInner -where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, -{ - target: WeakNode, - value: E, -} - -impl EdgeInner -where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, -{ - fn new(target: &Node, value: E) -> Self { - Self { - value, - target: WeakNode::downgrade(target), - } - } - - fn target(&self) -> Node { - self.target.upgrade().unwrap() - } - - fn value(&self) -> &E { - &self.value - } -} - -impl Deref for EdgeInner -where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, -{ - type Target = E; - - fn deref(&self) -> &Self::Target { - self.value() - } -} - -#[derive(Clone)] -struct Adjacent -where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, -{ - edges: Arc>>, -} - -#[derive(Clone)] -struct AdjacentInner -where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, -{ - outbound: Vec>, - inbound: Vec>, -} - -impl Adjacent -where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, -{ - fn new() -> Self { - Self { - edges: Arc::new(RwLock::new(AdjacentInner { - outbound: Vec::new(), - inbound: Vec::new(), - })), - } - } - - fn get_outbound(&self, idx: usize) -> Option> { - let edges = self.edges.read().unwrap(); - edges.outbound.get(idx).cloned() - } - - fn get_inbound(&self, idx: usize) -> Option> { - let edges = self.edges.read().unwrap(); - edges.inbound.get(idx).cloned() - } - - fn find_outbound(&self, node: &K) -> Option> { - let edges = self.edges.read().unwrap(); - edges.outbound.iter().find(|edge| edge.target().key() == node).cloned() - } - - fn find_inbound(&self, node: &K) -> Option> { - let edges = self.edges.read().unwrap(); - edges.inbound.iter().find(|edge| edge.target().key() == node).cloned() - } - - fn len_outbound(&self) -> usize { - let edges = self.edges.read().unwrap(); - edges.outbound.len() - } - - fn len_inbound(&self) -> usize { - let edges = self.edges.read().unwrap(); - edges.inbound.len() - } - - fn push_inbound(&self, edge: EdgeInner) { - self.edges.write().unwrap().inbound.push(edge); - } - - fn push_outbound(&self, edge: EdgeInner) { - self.edges.write().unwrap().outbound.push(edge); - } - - fn remove_inbound(&self, source: &K) -> Result { - let mut edges = self.edges.write().unwrap(); - let idx = edges.inbound.iter().position(|edge| edge.target().key() == source); - match idx { - Some(idx) => { - let edge = edges.inbound.remove(idx); - Ok(edge.value().clone()) - }, - None => Err(()), - } - } - - fn remove_outbound(&self, target: &K) -> Result { - let mut edges = self.edges.write().unwrap(); - let idx = edges.outbound.iter().position(|edge| edge.target().key() == target); - match idx { - Some(idx) => { - let edge = edges.outbound.remove(idx); - Ok(edge.value().clone()) - }, - None => Err(()), - } - } - - fn clear_inbound(&self) { - self.edges.write().unwrap().inbound.clear(); - } - - fn clear_outbound(&self) { - self.edges.write().unwrap().outbound.clear(); - } -} - -//==== EOF ==================================================================== \ No newline at end of file +} \ No newline at end of file diff --git a/src/ungraph/graph_serde.rs b/src/ungraph/graph_serde.rs index f60f1a0..cd1c0fe 100644 --- a/src/ungraph/graph_serde.rs +++ b/src/ungraph/graph_serde.rs @@ -1,8 +1,9 @@ -use serde::Deserialize; -use serde::ser::{Serialize, Serializer, SerializeTuple}; -use serde::de::{self, Visitor}; -use crate::ungraph::node::*; -use crate::ungraph::*; +use serde::{ + Deserialize, + ser::{Serialize, Serializer, SerializeTuple}, + de::{self, Visitor}, +}; +use super::*; fn graph_serde_decompose<'de, K, N, E>(g: &Graph) -> (Vec<(K, N)>, Vec<(K, K, E)>) where @@ -16,7 +17,7 @@ where for (_, n) in g.iter() { nodes.push((n.key().clone(), n.value().clone())); - for (u, v, e) in n.iter() { + for Edge(u, v, e) in n.iter() { edges.push((u.key().clone(), v.key().clone(), e)); } } diff --git a/src/ungraph/mod.rs b/src/ungraph/mod.rs index 263b3d8..7751d09 100644 --- a/src/ungraph/mod.rs +++ b/src/ungraph/mod.rs @@ -11,7 +11,7 @@ use std::{ use ahash::HashMap as HashMap; -pub use crate::ungraph::node::*; +pub use self::node::*; pub struct Graph where @@ -228,7 +228,7 @@ where s.push_str("digraph {\n"); for (u_key, node) in self.iter() { s.push_str(&format!(" {}", u_key.clone())); - for (_, v, _) in node { + for Edge(_, v, _) in node { s.push_str(&format!("\n {} -> {}", u_key, v.key())); } s.push_str("\n"); diff --git a/src/ungraph/node/adjacent.rs b/src/ungraph/node/adjacent.rs new file mode 100644 index 0000000..8090030 --- /dev/null +++ b/src/ungraph/node/adjacent.rs @@ -0,0 +1,143 @@ +use super::*; + +#[derive(Clone)] +pub struct WeakNode +where + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, +{ + inner: Weak<(K, N, RefCell>)>, +} + +impl WeakNode +where + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, +{ + pub fn upgrade(&self) -> Option> { + self.inner.upgrade().map(|inner| Node { inner }) + } + + pub fn downgrade(node: &Node) -> Self { + WeakNode { + inner: Rc::downgrade(&node.inner) + } + } +} + +pub struct Adjacent +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone, +{ + outbound: Vec<(WeakNode, E)>, + inbound: Vec<(WeakNode, E)>, +} + +impl Adjacent +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone, +{ + pub fn new() -> RefCell { + RefCell::new(Self { + outbound: Vec::new(), + inbound: Vec::new(), + }) + } + + pub fn get_adjacent(&self, idx: usize) -> Option<(&WeakNode, &E)> { + match self.outbound.get(idx) { + Some(edge) => Some((&edge.0, &edge.1)), + None => match self.inbound.get(idx - self.outbound.len()) { + Some(edge) => Some((&edge.0, &edge.1)), + None => None, + }, + } + } + + pub fn find_outbound(&self, node: &K) -> Option<(&WeakNode, &E)> { + for edge in self.outbound.iter() { + if edge.0.upgrade().unwrap().key() == node { + return Some((&edge.0, &edge.1)); + } + } + None + } + + pub fn find_inbound(&self, node: &K) -> Option<(&WeakNode, &E)> { + for edge in self.inbound.iter() { + if edge.0.upgrade().unwrap().key() == node { + return Some((&edge.0, &edge.1)); + } + } + None + } + + pub fn find_adjacent(&self, node: &K) -> Option<(&WeakNode, &E)> { + match self.find_outbound(node) { + Some(edge) => Some(edge), + None => self.find_inbound(node), + } + } + + pub fn len_outbound(&self) -> usize { + self.outbound.len() + } + + pub fn len_inbound(&self) -> usize { + self.inbound.len() + } + + pub fn push_inbound(&mut self, edge: (Node, E)) { + self.inbound.push((WeakNode::downgrade(&edge.0), edge.1)); + } + + pub fn push_outbound(&mut self, edge: (Node, E)) { + self.outbound.push((WeakNode::downgrade(&edge.0), edge.1)); + } + + pub fn remove_inbound(&mut self, source: &K) -> Result { + for (idx, edge) in self.inbound.iter().enumerate() { + if edge.0.upgrade().unwrap().key() == source { + return Ok(self.inbound.remove(idx).1); + } + } + Err(()) + } + + pub fn remove_outbound(&mut self, target: &K) -> Result { + for (idx, edge) in self.outbound.iter().enumerate() { + if edge.0.upgrade().unwrap().key() == target { + return Ok(self.outbound.remove(idx).1); + } + } + Err(()) + } + + pub fn remove_undirected(&mut self, node: &K) -> Result { + match self.remove_inbound(node) { + Ok(edge) => Ok(edge), + Err(_) => self.remove_outbound(node), + } + } + + pub fn clear_inbound(&mut self) { + self.inbound.clear(); + } + + pub fn clear_outbound(&mut self) { + self.outbound.clear(); + } + + pub fn sizeof(&self) -> usize { + self.inbound.len() + self.outbound.len() + * (std::mem::size_of::>() + + std::mem::size_of::()) + + std::mem::size_of::() + } +} \ No newline at end of file diff --git a/src/sync_ungraph/node/bfs.rs b/src/ungraph/node/algo/bfs.rs similarity index 70% rename from src/sync_ungraph/node/bfs.rs rename to src/ungraph/node/algo/bfs.rs index fc72c05..7518557 100644 --- a/src/sync_ungraph/node/bfs.rs +++ b/src/ungraph/node/algo/bfs.rs @@ -1,15 +1,6 @@ -//==== Includes =============================================================== - -use std::{ - fmt::Display, - hash::Hash, - collections::VecDeque -}; - -use ahash::HashSet as HashSet; - -use crate::sync_ungraph::node::*; -use self::{method::*, path::*}; +use std::{fmt::Display, hash::Hash, collections::VecDeque}; +use super::{*, method::*, path::*}; +use ahash::AHashSet as HashSet; pub struct BFS<'a, K, N, E> where @@ -18,7 +9,7 @@ where E: Clone, { root: Node, - target: Option<&'a K>, + target: Option, method: Method<'a, K, N, E>, } @@ -37,12 +28,12 @@ where } pub fn target(mut self, target: &'a K) -> Self { - self.target = Some(target); + self.target = Some(target.clone()); self } - pub fn map(mut self, f: Map<'a, K, N, E>) -> Self { - self.method = Method::Map(f); + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); self } @@ -51,25 +42,23 @@ where self } - pub fn filter_map(mut self, f: FilterMap<'a, K, N, E>) -> Self { - self.method = Method::FilterMap(f); - self - } - fn loop_adjacent( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut VecDeque>, ) -> bool { while let Some(node) = queue.pop_front() { - for (u, v, e) in node.iter() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.target().clone(); if !visited.contains(v.key()) { visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } queue.push_back(v.clone()); } @@ -80,17 +69,20 @@ where } fn loop_adjacent_find( - &self, + &mut self, visited: &mut HashSet, queue: &mut VecDeque>, ) -> Option> { while let Some(node) = queue.pop_front() { - for (u, v, e) in node.iter() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.target(); if !visited.contains(v.key()) { visited.insert(v.key().clone()); - if self.target.is_some() && self.target.unwrap() == v.key() { - return Some(v); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } } queue.push_back(v.clone()); } @@ -115,7 +107,7 @@ where let mut queue = VecDeque::new(); let mut visited = HashSet::default(); - self.target = Some(self.root.key()); + self.target = Some(self.root.key().clone()); queue.push_back(self.root.clone()); if self.loop_adjacent(&mut edges, &mut visited, &mut queue) { diff --git a/src/sync_ungraph/node/dfs.rs b/src/ungraph/node/algo/dfs.rs similarity index 67% rename from src/sync_ungraph/node/dfs.rs rename to src/ungraph/node/algo/dfs.rs index f9404c0..523112f 100644 --- a/src/sync_ungraph/node/dfs.rs +++ b/src/ungraph/node/algo/dfs.rs @@ -1,17 +1,6 @@ -//==== Includes =============================================================== - -use std::{ - fmt::Display, - hash::Hash, - // collections::HashSet -}; - -use ahash::HashSet as HashSet; -use crate::sync_ungraph::node::*; - -use self::{method::*, path::*}; - -//==== DFS ==================================================================== +use std::{fmt::Display, hash::Hash}; +use super::{*, method::*, path::*}; +use ahash::AHashSet as HashSet; pub struct DFS<'a, K, N, E> where @@ -20,7 +9,7 @@ where E: Clone, { root: Node, - target: Option<&'a K>, + target: Option, method: Method<'a, K, N, E>, } @@ -38,13 +27,13 @@ where } } - pub fn target(mut self, target: &'a K) -> Self { - self.target = Some(target); + pub fn target(mut self, target: &K) -> Self { + self.target = Some(target.clone()); self } - pub fn map(mut self, f: Map<'a, K, N, E>) -> Self { - self.method = Method::Map(f); + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); self } @@ -53,25 +42,23 @@ where self } - pub fn filter_map(mut self, f: FilterMap<'a, K, N, E>) -> Self { - self.method = Method::FilterMap(f); - self - } - - fn recurse_adjacent(&self, + fn recurse_adjacent(&mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (u, v, e) in node.iter() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.target().clone(); if visited.contains(v.key()) == false { - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; - } visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } queue.push(v.clone()); if self.recurse_adjacent(result, visited, queue) { return true; @@ -83,18 +70,21 @@ where false } - fn recurse_adjacent_find(&self, + fn recurse_adjacent_find(&mut self, visited: &mut HashSet, queue: &mut Vec>, ) -> Option> { if let Some(node) = queue.pop() { - for (u, v, e) in node.iter() { - if self.method.exec(&u, &v, &e) { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.target(); if visited.contains(v.key()) == false { - if self.target.is_some() && self.target.unwrap() == v.key() { - return Some(v); - } visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } + } queue.push(v.clone()); match self.recurse_adjacent_find(visited, queue) { Some(t) => return Some(t), @@ -122,7 +112,7 @@ where let mut queue = vec![]; let mut visited = HashSet::default(); - self.target = Some(self.root.key()); + self.target = Some(self.root.key().clone()); queue.push(self.root.clone()); if self.recurse_adjacent(&mut edges, &mut visited, &mut queue) { diff --git a/src/ungraph/node/algo/method.rs b/src/ungraph/node/algo/method.rs new file mode 100644 index 0000000..c973f3b --- /dev/null +++ b/src/ungraph/node/algo/method.rs @@ -0,0 +1,30 @@ +use super::*; + +pub type Filter<'a, K, N, E> = &'a mut dyn FnMut(&Edge) -> bool; +pub type ForEach<'a, K, N, E> = &'a mut dyn FnMut(&Edge); + +pub enum Method<'a, K, N, E> +where + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, +{ + NullMethod, + Filter(Filter<'a, K, N, E>), + ForEach(ForEach<'a, K, N, E>), +} + +impl<'a, K, N, E> Method<'a, K, N, E> +where + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, +{ + pub fn exec(&mut self, e: &Edge) -> bool { + match self { + Method::NullMethod => true, + Method::Filter(f) => f(e), + Method::ForEach(f) => {f(e); true}, + } + } +} \ No newline at end of file diff --git a/src/ungraph/node/algo/mod.rs b/src/ungraph/node/algo/mod.rs new file mode 100644 index 0000000..ad8023c --- /dev/null +++ b/src/ungraph/node/algo/mod.rs @@ -0,0 +1,9 @@ +use super::*; + +pub mod bfs; +pub mod dfs; +pub mod pfs; +pub mod order; + +mod path; +mod method; \ No newline at end of file diff --git a/src/ungraph/node/order.rs b/src/ungraph/node/algo/order.rs similarity index 80% rename from src/ungraph/node/order.rs rename to src/ungraph/node/algo/order.rs index 276da54..eaa1b64 100644 --- a/src/ungraph/node/order.rs +++ b/src/ungraph/node/algo/order.rs @@ -12,6 +12,11 @@ use super::method::*; //==== Ordering =============================================================== +pub enum Ordering { + Pre, + Post, +} + pub struct Order<'a, K, N, E> where K: Clone + Hash + Display + PartialEq + Eq, @@ -48,8 +53,8 @@ where self } - pub fn map(mut self, f: Map<'a, K, N, E>) -> Self { - self.method = Method::Map(f); + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); self } @@ -58,12 +63,6 @@ where self } - - pub fn filter_map(mut self, f: FilterMap<'a, K, N, E>) -> Self { - self.method = Method::FilterMap(f); - self - } - pub fn search_nodes(&mut self) -> Vec> { let mut nodes = vec![]; let mut edges = vec![]; @@ -77,12 +76,12 @@ where Ordering::Pre => { self.recurse_preorder(&mut edges, &mut visited, &mut queue); nodes.push(self.root.clone()); - let mut coll = edges.iter().map(|(_, v, _)| v.clone()).collect(); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); nodes.append(&mut coll); }, Ordering::Post => { self.recurse_postorder(&mut edges, &mut visited, &mut queue); - let mut coll = edges.iter().map(|(_, v, _)| v.clone()).collect(); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); nodes.append(&mut coll); nodes.push(self.root.clone()); }, @@ -110,18 +109,20 @@ where } fn recurse_preorder( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (u, v, e) in node.iter() { - if visited.contains(v.key()) == false { - if self.method.exec(&u, &v, &e) { + for edge in node.iter() { + let edge = edge.reverse(); + let v = edge.1.clone(); + if self.method.exec(&edge) { + if visited.contains(v.key()) == false { visited.insert(v.key().clone()); queue.push(v.clone()); - result.push((u, v.clone(), e)); + result.push(edge); self.recurse_preorder( result, visited, @@ -134,22 +135,23 @@ where } fn recurse_postorder( - &self, + &mut self, result: &mut Vec>, visited: &mut HashSet, queue: &mut Vec>, ) -> bool { if let Some(node) = queue.pop() { - for (u, v, e) in node.iter() { - if visited.contains(v.key()) == false { - if self.method.exec(&u, &v, &e) { + for edge in node.iter() { + let v = edge.1.clone(); + if self.method.exec(&edge) { + if visited.contains(v.key()) == false { visited.insert(v.key().clone()); queue.push(v.clone()); self.recurse_postorder( result, visited, queue); - result.push((u, v.clone(), e)); + result.push(edge); } } } diff --git a/src/sync_ungraph/node/path.rs b/src/ungraph/node/algo/path.rs similarity index 85% rename from src/sync_ungraph/node/path.rs rename to src/ungraph/node/algo/path.rs index 7c6bb81..6499b8d 100644 --- a/src/sync_ungraph/node/path.rs +++ b/src/ungraph/node/algo/path.rs @@ -1,9 +1,5 @@ -use std::{ - fmt::Display, - hash::Hash, ops::Index, -}; - -use crate::sync_ungraph::node::*; +use std::{fmt::Display, hash::Hash, ops::Index}; +use super::*; pub fn backtrack_edge_tree(edge_tree: Vec>) -> Vec> where @@ -20,10 +16,11 @@ where let w = edge_tree.last().unwrap(); path.push(w.clone()); let mut i = 0; - for (u, v, e) in edge_tree.iter().rev() { - let (s, _, _) = &path[i]; + for edge in edge_tree.iter().rev() { + let Edge(_, v, _) = edge; + let Edge(s, _, _) = &path[i]; if s == v { - path.push((u.clone(), v.clone(), e.clone())); + path.push(edge.clone()); i += 1; } } @@ -46,6 +43,13 @@ where N: Clone, E: Clone, { + pub fn len(&self) -> usize { + // Conceptually a path always contains at least one node, + // the root node. The path containes edges, so the length + // of the path is the number of edges plus one. + self.edges.len() + 1 + } + pub fn from_edge_tree(edge_tree: Vec>) -> Path { Path { edges: backtrack_edge_tree(edge_tree) } } @@ -118,13 +122,13 @@ where N: Clone, E: Clone, { - type Item = (Node, Node, E); + type Item = Edge; fn next(&mut self) -> Option { match self.path.edges.get(self.position) { Some(edge) => { self.position += 1; - Some((edge.0.clone(), edge.1.clone(), edge.2.clone())) + Some(Edge(edge.0.clone(), edge.1.clone(), edge.2.clone())) } None => None, } @@ -167,4 +171,4 @@ where None => None, } } -} +} \ No newline at end of file diff --git a/src/sync_ungraph/node/pfs.rs b/src/ungraph/node/algo/pfs.rs similarity index 56% rename from src/sync_ungraph/node/pfs.rs rename to src/ungraph/node/algo/pfs.rs index 4ca87fc..eadf25e 100644 --- a/src/sync_ungraph/node/pfs.rs +++ b/src/ungraph/node/algo/pfs.rs @@ -1,16 +1,11 @@ -//==== Includes =============================================================== - use std::{ fmt::Display, hash::Hash, + collections::BinaryHeap, + cmp::Reverse }; - -use ahash::HashSet as HashSet; -use min_max_heap::MinMaxHeap; - -use crate::sync_ungraph::node::*; -use crate::sync_ungraph::node::path::*; -use self::method::*; +use super::{*, method::*, path::*}; +use ahash::AHashSet as HashSet; enum Priority { Min, @@ -24,7 +19,7 @@ where E: Clone, { root: Node, - target: Option<&'a K>, + target: Option, method: Method<'a, K, N, E>, priority: Priority, } @@ -55,12 +50,12 @@ where } pub fn target(mut self, target: &'a K) -> Self { - self.target = Some(target); + self.target = Some(target.clone()); self } - pub fn map(mut self, f: Map<'a, K, N, E>) -> Self { - self.method = Method::Map(f); + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); self } @@ -69,28 +64,25 @@ where self } - - pub fn filter_map(mut self, f: FilterMap<'a, K, N, E>) -> Self { - self.method = Method::FilterMap(f); - self - } - - fn recurse_min( - &self, + fn loop_min( + &mut self, result: &mut Vec>, visited: &mut HashSet, - queue: &mut MinMaxHeap>, + queue: &mut BinaryHeap>>, ) -> bool { - while let Some(node) = queue.pop_min() { - for (u, v, e) in node.iter() { - if self.method.exec(&u, &v, &e) { + while let Some(Reverse(node)) = queue.pop() { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.1.clone(); if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } - queue.push(v.clone()); + visited.insert(v.key().clone()); + result.push(edge); + queue.push(Reverse(v)); } } } @@ -98,22 +90,25 @@ where false } - fn recurse_max( - &self, + fn loop_max( + &mut self, result: &mut Vec>, visited: &mut HashSet, - queue: &mut MinMaxHeap>, + queue: &mut BinaryHeap>, ) -> bool { - while let Some(node) = queue.pop_max() { - for (u, v, e) in node.iter() { - if self.method.exec(&u, &v, &e) { + while let Some(node) = queue.pop() { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.1.clone(); if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push((u, v.clone(), e)); - if self.target.is_some() && self.target.unwrap() == v.key() { - return true; + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } } - queue.push(v.clone()); + visited.insert(v.key().clone()); + result.push(edge); + queue.push(v); } } } @@ -131,19 +126,21 @@ where pub fn search_cycle(&'a mut self) -> Option> { let mut edges = vec![]; - let mut queue = MinMaxHeap::new(); let mut visited = HashSet::default(); let target_found; - self.target = Some(self.root.key()); - queue.push(self.root.clone()); + self.target = Some(self.root.key().clone()); match self.priority { Priority::Min => { - target_found = self.recurse_min(&mut edges, &mut visited, &mut queue); + let mut queue = BinaryHeap::new(); + queue.push(Reverse(self.root.clone())); + target_found = self.loop_min(&mut edges, &mut visited, &mut queue); } Priority::Max => { - target_found = self.recurse_max(&mut edges, &mut visited, &mut queue); + let mut queue = BinaryHeap::new(); + queue.push(self.root.clone()); + target_found = self.loop_max(&mut edges, &mut visited, &mut queue); } } if target_found { @@ -154,19 +151,21 @@ where pub fn search_path(&mut self) -> Option> { let mut edges = vec![]; - let mut queue = MinMaxHeap::new(); let mut visited = HashSet::default(); let target_found; - queue.push(self.root.clone()); visited.insert(self.root.key().clone()); match self.priority { Priority::Min => { - target_found = self.recurse_min(&mut edges, &mut visited, &mut queue); + let mut queue = BinaryHeap::new(); + queue.push(Reverse(self.root.clone())); + target_found = self.loop_min(&mut edges, &mut visited, &mut queue); } Priority::Max => { - target_found = self.recurse_max(&mut edges, &mut visited, &mut queue); + let mut queue = BinaryHeap::new(); + queue.push(self.root.clone()); + target_found = self.loop_max(&mut edges, &mut visited, &mut queue); } } if target_found { diff --git a/src/ungraph/node/method.rs b/src/ungraph/node/method.rs deleted file mode 100644 index e21b339..0000000 --- a/src/ungraph/node/method.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::ungraph::node::*; - -pub type FilterMap<'a, K, N, E> = &'a dyn Fn(&Node, &Node, &E) -> bool; -pub type Filter<'a, K, N, E> = &'a dyn Fn(&Node, &Node, &E) -> bool; -pub type Map<'a, K, N, E> = &'a dyn Fn(&Node, &Node, &E); - -#[derive(Clone)] -pub enum Method<'a, K, N, E> -where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, -{ - NullMethod, - FilterMap(FilterMap<'a, K, N, E>), - Filter(Filter<'a, K, N, E>), - Map(Map<'a, K, N, E>), -} - -impl<'a, K, N, E> Method<'a, K, N, E> -where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, -{ - pub fn exec(&self, u: &Node, v: &Node, e: &E) -> bool { - match self { - Method::NullMethod => true, - Method::Map(f) => {f(u, v, e); true}, - Method::Filter(f) => f(u, v, e), - Method::FilterMap(f) => f(u, v, e), - } - } -} - -pub enum Ordering { - Pre, - Post, -} diff --git a/src/ungraph/node/mod.rs b/src/ungraph/node/mod.rs index 6ca325f..8cac122 100644 --- a/src/ungraph/node/mod.rs +++ b/src/ungraph/node/mod.rs @@ -31,12 +31,8 @@ //! //! This node uses `Rc` for reference counting, thus it is not thread-safe. -mod method; -mod order; -mod bfs; -mod dfs; -mod pfs; -mod path; +mod algo; +mod adjacent; use std::{ fmt::Display, @@ -47,19 +43,93 @@ use std::{ }; use self::{ - pfs::*, - dfs::*, - bfs::*, - order::*, + algo::{ + pfs::*, + dfs::*, + bfs::*, + order::*, + }, + adjacent::*, }; -// pub use self::path::Path; +/// An edge between nodes is a tuple struct `Edge(u, v, e)` where `u` is the +/// source node, `v` is the target node, and `e` is the edge's value. +#[derive(Clone)] +pub struct Edge( + pub Node, + pub Node, + pub E, +) where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone; -//==== PUBLIC ================================================================= + impl Edge +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone, +{ + /// Returns the source node of the edge. + pub fn source(&self) -> &Node { + &self.0 + } -/// An edge between nodes is a tuple `(u, v, e)` where `u` is the -/// source node, `v` is the target node, and `e` is the edge's value. -pub type Edge = (Node, Node, E); + /// Returns the target node of the edge. + pub fn target(&self) -> &Node { + &self.1 + } + + /// Returns the edge's value. + pub fn value(&self) -> &E { + &self.2 + } + + /// Reverse the edge's direction. + pub fn reverse(&self) -> Edge { + Edge(self.1.clone(), self.0.clone(), self.2.clone()) + } +} + +impl PartialEq for Edge +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + Ord +{ + fn eq(&self, other: &Edge) -> bool { + self.2 == other.2 + } +} + +impl Eq for Edge +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + Ord +{} + +impl PartialOrd for Edge +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + Ord +{ + fn partial_cmp(&self, other: &Edge) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Edge +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + Ord +{ + fn cmp(&self, other: &Edge) -> std::cmp::Ordering { + self.2.cmp(&other.2) + } +} /// A `Node` is a key value pair smart-pointer, which includes inbound and /// outbound connections to other nodes. Nodes can be created individually and they @@ -81,7 +151,7 @@ pub type Edge = (Node, Node, E); /// b.connect(&c, 0.09); /// c.connect(&b, 12.9); /// -/// let (u, v, e) = a.iter().next().unwrap(); +/// let Edge(u, v, e) = a.iter().next().unwrap(); /// /// assert!(u == a); /// assert!(v == b); @@ -90,11 +160,11 @@ pub type Edge = (Node, Node, E); #[derive(Clone)] pub struct Node where - K: Clone + Hash + PartialEq + Eq + Display, + K: Clone + Hash + PartialEq + Eq + Display, N: Clone, E: Clone, { - inner: Rc>, + inner: Rc<(K, N, RefCell>)>, } impl Node @@ -119,13 +189,9 @@ where /// assert!(*n1.value() == 'A'); /// ``` pub fn new(key: K, value: N) -> Self { - Node { - inner: Rc::new(NodeInner { - key, - value, - edges: Adjacent::new(), - }), - } + Node { + inner: Rc::new((key, value, Adjacent::new())), + } } /// Returns a reference to the node's key. @@ -140,7 +206,7 @@ where /// assert!(*n1.key() == 1); /// ``` pub fn key(&self) -> &K { - &self.inner.key + &self.inner.0 } /// Returns a reference to the node's value. @@ -155,7 +221,29 @@ where /// assert!(*n1.value() == 'A'); /// ``` pub fn value(&self) -> &N { - &self.inner.value + &self.inner.1 + } + + /// Returns the degree of the node. The degree is the number of + /// adjacent edges. + /// + /// # Example + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let a = Node::new(0x1, "A"); + /// let b = Node::new(0x2, "B"); + /// let c = Node::new(0x4, "C"); + /// + /// a.connect(&b, 0.42); + /// a.connect(&c, 1.7); + /// + /// assert!(a.out_degree() == 2); + /// ``` + pub fn degree(&self) -> usize { + self.inner.2.borrow().len_outbound() + + self.inner.2.borrow().len_inbound() } /// Connects this node to another node. The connection is created in both @@ -175,12 +263,17 @@ where /// /// assert!(n1.is_connected(n2.key())); /// ``` - pub fn connect(&self, other: &Node, value: E) { - let edge = EdgeInner::new(other, value.clone()); - let rev_edge = EdgeInner::new(&self, value); - self.inner.edges.push_outbound(edge); - other.inner.edges.push_inbound(rev_edge); - } + pub fn connect(&self, other: &Self, value: E) { + self.inner + .2 + .borrow_mut() + .push_outbound((other.clone(), value.clone())); + other + .inner + .2 + .borrow_mut() + .push_inbound((self.clone(), value)); + } /// Connects this node to another node. The connection is created in both /// directions. The connection is created with the given edge value and @@ -238,18 +331,7 @@ where /// assert!(!n1.is_connected(n2.key())); /// ``` pub fn disconnect(&self, other: &K) -> Result { - match self.find_adjacent(other) { - Some(other) => { - match self.inner.edges.remove_outbound(other.key()) { - Ok(edge) => { - other.inner.edges.remove_inbound(self.key())?; - Ok(edge) - }, - Err(_) => Err(()), - } - }, - None => Err(()), - } + self.inner.2.borrow_mut().remove_undirected(other) } /// Removes all inbound and outbound connections to and from the node. @@ -280,19 +362,19 @@ where /// assert!(n1.is_orphan()); /// ``` pub fn isolate(&self) { - for (_, v, _) in self.iter() { - if v.inner.edges.remove_inbound(self.key()).is_err() { - v.inner.edges.remove_outbound(self.key()).unwrap(); + for Edge(_, v, _) in self.iter() { + if v.inner.2.borrow_mut().remove_inbound(self.key()).is_err() { + v.inner.2.borrow_mut().remove_outbound(self.key()).unwrap(); } } - self.inner.edges.clear_outbound(); - self.inner.edges.clear_inbound(); + self.inner.2.borrow_mut().clear_outbound(); + self.inner.2.borrow_mut().clear_inbound(); } /// Returns true if the node is an oprhan. Orphan nodes are nodes that have /// no connections. pub fn is_orphan(&self) -> bool { - self.inner.edges.len_outbound() == 0 && self.inner.edges.len_inbound() == 0 + self.inner.2.borrow().len_outbound() == 0 && self.inner.2.borrow().len_inbound() == 0 } /// Returns true if the node is connected to another node with a given key. @@ -303,16 +385,9 @@ where /// Get a pointer to an adjacent node with a given key. Returns None if no /// node with the given key is found from the node's adjacency list. pub fn find_adjacent(&self, other: &K) -> Option> { - let edge = self.inner.edges.find_outbound(other); - if let Some(edge) = edge { - Some(edge.target().clone()) - } else { - let edge = self.inner.edges.find_inbound(other); - if let Some(edge) = edge { - Some(edge.target().clone()) - } else { - None - } + match self.inner.2.borrow().find_adjacent(other) { + Some((n, _)) => Some(n.upgrade().unwrap()), + None => None, } } @@ -351,12 +426,12 @@ where } pub fn sizeof(&self) -> usize { - let len_in = self.inner.edges.len_inbound(); - let len_out = self.inner.edges.len_outbound(); - let size_edges = (len_in + len_out) * std::mem::size_of::>(); - let size_node_inner = std::mem::size_of::>(); - size_edges + size_node_inner + 8 - } + std::mem::size_of::>() + + std::mem::size_of::() + + std::mem::size_of::() + + self.inner.2.borrow().sizeof() + + std::mem::size_of::() + } } //==== TRAIT IMPLEMENTATIONS ================================================== @@ -429,32 +504,16 @@ where N: Clone, E: Clone, { - type Item = (Node, Node, E); + type Item = Edge; fn next(&mut self) -> Option { - let adjacent = &self.node.inner.edges; - match adjacent.get_outbound(self.position) { - Some(current) => { + let adjacent = &self.node.inner.2.borrow(); + match adjacent.get_adjacent(self.position) { + Some((n, e)) => { self.position += 1; - Some(( - self.node.clone(), - current.target().clone(), - current.value.clone() - )) + Some(Edge(self.node.clone(), n.upgrade().unwrap(), e.clone())) } - None => { - match adjacent.get_inbound(self.position - adjacent.len_outbound()) { - Some(current) => { - self.position += 1; - Some(( - self.node.clone(), - current.target().clone(), - current.value.clone() - )) - } - None => None - } - }, + None => None, } } } @@ -465,205 +524,10 @@ where N: Clone, E: Clone, { - type Item = (Node, Node, E); + type Item = Edge; type IntoIter = NodeIterator<'a, K, N, E>; fn into_iter(self) -> Self::IntoIter { NodeIterator { node: self, position: 0 } } -} - -//==== PRIVATE ================================================================ - -struct NodeInner -where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, -{ - key: K, - value: N, - edges: Adjacent, -} - -#[derive(Clone)] -struct WeakNode -where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, -{ - inner: Weak>, -} - -impl WeakNode -where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, -{ - fn upgrade(&self) -> Option> { - self.inner.upgrade().map(|inner| Node { inner }) - } - - fn downgrade(node: &Node) -> Self { - WeakNode { - inner: Rc::downgrade(&node.inner) - } - } -} - -#[derive(Clone)] -struct EdgeInner -where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, -{ - target: WeakNode, - value: E, -} - -impl EdgeInner -where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, -{ - fn new(target: &Node, value: E) -> Self { - Self { - value, - target: WeakNode::downgrade(target), - } - } - - fn target(&self) -> Node { - self.target.upgrade().unwrap() - } - - fn value(&self) -> &E { - &self.value - } -} - -impl Deref for EdgeInner -where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, -{ - type Target = E; - - fn deref(&self) -> &Self::Target { - self.value() - } -} - -#[derive(Clone)] -struct Adjacent -where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, -{ - edges: RefCell>, -} - -#[derive(Clone)] -struct AdjacentInner -where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, -{ - outbound: Vec>, - inbound: Vec>, -} - -impl Adjacent -where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, -{ - fn new() -> Self { - Self { - edges: RefCell::new(AdjacentInner { - outbound: Vec::new(), - inbound: Vec::new(), - }), - } - } - - fn get_outbound(&self, idx: usize) -> Option> { - let edges = self.edges.borrow(); - edges.outbound.get(idx).cloned() - } - - fn get_inbound(&self, idx: usize) -> Option> { - let edges = self.edges.borrow(); - edges.inbound.get(idx).cloned() - } - - fn find_outbound(&self, node: &K) -> Option> { - let edges = self.edges.borrow(); - edges.outbound.iter().find(|edge| edge.target().key() == node).cloned() - } - - fn find_inbound(&self, node: &K) -> Option> { - let edges = self.edges.borrow(); - edges.inbound.iter().find(|edge| edge.target().key() == node).cloned() - } - - fn len_outbound(&self) -> usize { - let edges = self.edges.borrow(); - edges.outbound.len() - } - - fn len_inbound(&self) -> usize { - let edges = self.edges.borrow(); - edges.inbound.len() - } - - fn push_inbound(&self, edge: EdgeInner) { - self.edges.borrow_mut().inbound.push(edge); - } - - fn push_outbound(&self, edge: EdgeInner) { - self.edges.borrow_mut().outbound.push(edge); - } - - fn remove_inbound(&self, source: &K) -> Result { - let mut edges = self.edges.borrow_mut(); - let idx = edges.inbound.iter().position(|edge| edge.target().key() == source); - match idx { - Some(idx) => { - let edge = edges.inbound.remove(idx); - Ok(edge.value().clone()) - }, - None => Err(()), - } - } - - fn remove_outbound(&self, target: &K) -> Result { - let mut edges = self.edges.borrow_mut(); - let idx = edges.outbound.iter().position(|edge| edge.target().key() == target); - match idx { - Some(idx) => { - let edge = edges.outbound.remove(idx); - Ok(edge.value().clone()) - }, - None => Err(()), - } - } - - fn clear_inbound(&self) { - self.edges.borrow_mut().inbound.clear(); - } - - fn clear_outbound(&self) { - self.edges.borrow_mut().outbound.clear(); - } -} - -//==== EOF ==================================================================== \ No newline at end of file +} \ No newline at end of file diff --git a/tests/digraph_tests.rs b/tests/digraph_tests.rs index 6dc3fd4..faabe6e 100644 --- a/tests/digraph_tests.rs +++ b/tests/digraph_tests.rs @@ -28,7 +28,7 @@ fn ut_digraph_manual_bfs() visited.insert(g[0].key().clone()); while let Some(node) = queue.pop_front() { - for (_, v, _) in &node { + for Edge(_, v, _) in &node { if !visited.contains(v.key()) { if v == g[4] { return; @@ -80,7 +80,7 @@ fn ut_digraph() b.connect(&c, 0.09); c.connect(&b, 12.9); - let (u, v, e) = a.iter_out().next().unwrap(); + let Edge(u, v, e) = a.iter_out().next().unwrap(); assert!(u == a); assert!(v == b); @@ -364,7 +364,7 @@ fn ut_digraph_deref_node() { assert!(*n1 == 42); assert!(n2.key() == &'B'); - let (u, v, e) = n1.iter_out().next().unwrap(); + let Edge(u, v, e) = n1.iter_out().next().unwrap(); assert!(u.key() == &'A'); assert!(v == n2); @@ -397,7 +397,7 @@ fn ut_serde_json() { for (a, b) in graph_vec.iter().zip(de_vec.iter()) { assert!(a == b); - for ((u, v, e), (u2, v2, e2)) in a.iter_out().zip(b.iter_out()) { + for (Edge(u, v, e), Edge(u2, v2, e2)) in a.iter_out().zip(b.iter_out()) { assert!(u == u2); assert!(v == v2); assert!(e == e2); @@ -431,7 +431,7 @@ fn ut_serde_cbor() { for (a, b) in graph_vec.iter().zip(de_vec.iter()) { assert!(a == b); - for ((u, v, e), (u2, v2, e2)) in a.iter_out().zip(b.iter_out()) { + for (Edge(u, v, e), Edge(u2, v2, e2)) in a.iter_out().zip(b.iter_out()) { assert!(u == u2); assert!(v == v2); assert!(e == e2); @@ -470,7 +470,7 @@ fn ut_serde_cbor_big() { for (a, b) in graph_vec.iter().zip(de_vec.iter()) { assert!(a == b); - for ((u, v, e), (u2, v2, e2)) in a.iter_out().zip(b.iter_out()) { + for (Edge(u, v, e), Edge(u2, v2, e2)) in a.iter_out().zip(b.iter_out()) { assert!(u == u2); assert!(v == v2); assert!(e == e2); diff --git a/tests/ungraph_tests.rs b/tests/ungraph_tests.rs index 0530816..2363bca 100644 --- a/tests/ungraph_tests.rs +++ b/tests/ungraph_tests.rs @@ -28,7 +28,7 @@ fn ut_ungraph_manual_bfs() visited.insert(g[0].key().clone()); while let Some(node) = queue.pop_front() { - for (_, v, _) in &node { + for Edge(_, v, _) in &node { if !visited.contains(v.key()) { if v == g[4] { return; @@ -80,7 +80,7 @@ fn ut_ungraph() b.connect(&c, 0.09); c.connect(&b, 12.9); - let (u, v, e) = a.iter().next().unwrap(); + let Edge(u, v, e) = a.iter().next().unwrap(); assert!(u == a); assert!(v == b); @@ -328,7 +328,6 @@ fn ut_ungraph_bfs_cycle_2() { assert!(cycle.last().unwrap() == &g[0]); } - #[test] fn ut_ungraph_sizes() { use gdsl::ungraph::*; @@ -356,6 +355,6 @@ fn ut_ungraph_sizes() { n1.connect(&n1t2, ()); n1.connect(&n1t3, ()); - assert!(n1.sizeof() == 120); - assert!(n1t1.sizeof() == 88); + assert!(n1.sizeof() == 96); + assert!(n1t1.sizeof() == 73); } \ No newline at end of file