-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
First approach for bevy_graph
#7130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
186 commits
Select commit
Hold shift + click to select a range
1a3cbba
Add AdjacencyMapGraph for `bevy_graph`
DasLixou b091e36
Make the CI happy :D and add Default trait
DasLixou bb0f39c
Directed and Undirected Edges
DasLixou 3b035c0
Moving files and modules
DasLixou 9c5f2ea
Whoops was faster than cargo check
DasLixou 6a8d902
Make NodeIdx and EdgeIdx new keys
DasLixou c5157b8
Add basic SimpleListGraph
DasLixou 27c9fe0
Set directed with const generic bool
DasLixou 3eabc13
Let Map also use SecondaryMap instead of HashMap
DasLixou d6e0f9c
Replace SlotMap with HopSlotMap
DasLixou 817556c
Extract basic Graph functions into `Graph` trait
DasLixou 49582c7
`DirectedGraph` and `UndirectedGraph` traits
DasLixou 8ffee13
More Edge util functions
DasLixou e239c99
Removing edges with `edge_between`
DasLixou 9031134
Make CI happy :D
DasLixou ac4cdce
remove returns the Edge Data
DasLixou 40c27c5
Naming
DasLixou 3a4d94d
API Design changes
DasLixou 602bd2b
Add basic benchmark for `SimpleMapGraph`
DasLixou a75bf1a
Another day of making the CI happy
DasLixou defb878
Making Graphs clonable
DasLixou b0cee31
naive implementation of `edges_of`
DasLixou f427cd8
Make `edges_of` also return destination of edge
DasLixou c79ba21
make clippy happy
DasLixou 3edc070
Better Error Handling with `GraphError`
DasLixou 69b9f59
Simple BFS
DasLixou 803efc0
Better BFS Api
DasLixou 499db70
Mutable Iteration for BFS
DasLixou 8b0031b
allow(clippy::len_without_is_empty)
DasLixou 6e8725c
ok clippy ill just write it
DasLixou daa4646
Auto trait function for algos
DasLixou b815eb3
Store connected Nodes for Edge
DasLixou bbbef82
Restructuring crate
DasLixou e19e320
Use the new data from edge to simplify edge-remove
DasLixou 73b59b0
Fix benchmarks
DasLixou e3e791d
CI...
DasLixou 4fad13e
Restructed traits
DasLixou 3db9d7e
Another try of api
DasLixou 70f1700
impl_graph macro is now a Sigma 🗿
DasLixou 5c51e84
Update Bench
DasLixou be83c21
Now i understand what $crate does :D
DasLixou 46fcd86
Add support to remove nodes
DasLixou a7442e7
Move Tests for Graph in one file
DasLixou 5aa9c14
graph_tests macro :o
DasLixou 0710a1d
Cleanup
DasLixou cf661e1
Refactor `new_edge` with safety ⚠️
DasLixou 7e1571d
outscore in unsafe functions 🥶
DasLixou 033c200
Make clippy happy 😆
DasLixou 18a4232
benchmarks fast fix
DasLixou e3be206
make indices const :D
DasLixou 450ff00
Preparation for Multi Graphs :O
DasLixou c2c0ddc
`edge_between` now returns GraphResult
DasLixou 7753257
Fix tests
DasLixou d25ec0a
Clippy.
DasLixou 06d5709
Fix benchmarks
DasLixou 83467a2
Add iterative DepthFirstSearch algo
DasLixou 86cbf7e
Implement unsafe `get_node` for graphs
DasLixou 78f510c
Add `next_unchecked` functions for BFS and DFS
DasLixou d59e6ba
Clippy 📎
DasLixou 9788bae
Simple Graph `new_edge` should not have same node
DasLixou 5c0fe70
`edge(s)_between` chaos for multi graph
DasLixou ca9d139
[DIRTY] refactor `impl_graph!` macro and traits
DasLixou 2410df4
Use new `impl_graph` for cleaner `edge_between`
DasLixou 7908c1f
benchi benchi
DasLixou d011cd9
Add benchmarks for `bfs` and `dfs` algo
DasLixou f94dd22
Move `new` into Graph trait
DasLixou 5518c6b
Impl `new_edge` for `MultiMapGraph`
DasLixou 088cfe1
add `remove_edge` for `MultiMapGraph`
DasLixou 159e70f
Add unsafe `remove_edge_unchecked`
DasLixou bb1333c
Cleanup duplicates
DasLixou dcc8df7
Add `remove_node` for `MultiMapGraph`
DasLixou a007ee5
Add `edges_of` for `MultiMapGraph`
DasLixou 2dac00b
Make `SimpleGraph`'s `edge_between` an Option
DasLixou 7ab4f66
Implement last methods for `MultiMapGraph` :D
DasLixou b8dea3a
Add tests for MultiGraphs
DasLixou c957fc5
Fix benches
DasLixou dc00827
Add skeleton for `MultiListGraph`
DasLixou 09eee1e
Finish `MultiListGraph`
DasLixou dcfcfeb
Ci is happy = I am happy
DasLixou 8d750db
Documenting Graph and SimpleGraph traits
DasLixou f4e703a
Merge branches 'graph' and 'graph' of github.com:DasLixou/bevy into g…
DasLixou 1523a38
More documentation
DasLixou 3aec991
backticks...
DasLixou c63597a
Apparently don't know my own API - well thats cool
DasLixou 3867311
Update description in Cargo.toml
DasLixou 51faf5f
Link algorythms
DasLixou c4150ca
algos with `with_capacity`
DasLixou a13b35b
docs
DasLixou e0c24ae
docs
DasLixou 2552932
docs
DasLixou 6389a6a
docs
DasLixou c387337
the wording i saw infront of me
DasLixou 8cf48b3
docs
DasLixou 0ced1be
docs
DasLixou 5304cc2
docs
DasLixou b082151
`GraphError` docs
DasLixou 849e9e9
`Edge<E>` docs
DasLixou 5df0f04
missing_docs warn
DasLixou 6c9e168
thiserror and document Idx types
DasLixou 37bcd3f
Merge branch 'graph' of github.com:DasLixou/bevy into graph
DasLixou 91e4c79
big doc and result change
DasLixou d23424c
renaming `algo_*` methods for graph
DasLixou 624d871
working on algos
DasLixou 8fb962c
docs for Graph traits
DasLixou f864a31
benchies
DasLixou 03b95db
remove algo functions from `Graph` trait
DasLixou 1249298
remove `impl_graph` macro
DasLixou dd78ecc
clippy
DasLixou 3d6fac5
more cleanup
DasLixou 2c75cdf
add some more counting functions
DasLixou f57620b
changes
DasLixou 8531841
`add_node`
DasLixou 498c0f6
Remove all old code and implement `new_edge`
DasLixou d170306
`remove_edge`
DasLixou 3a6f22a
changes to `add_edge` signature
DasLixou 4a548f7
`clear_edges` and `clear`
DasLixou 840f53a
getting nodes and edges
DasLixou 0781f40
Add `AdjacencyStorage`
DasLixou ea34164
`nodes` iterator 🤧
DasLixou aa47441
`EdgeRef` and `EdgeMut`
DasLixou 1245f90
`edges` and `edges_mut`
DasLixou 34a48b1
Resolve all errors
DasLixou c58dec5
Make VecMap faster with binary search
DasLixou 2f3ea70
Some more graph creation funcs
DasLixou 658da34
Add `reserve`ing for graphs
DasLixou 974d0ab
Change file structure
DasLixou c9b2d6c
Make `Edges` iter 🥳🫠
DasLixou 584f89c
Move iters to own folder
DasLixou 68d6b86
make ci happy
DasLixou 71c8881
ci
DasLixou 6b20640
doc backtick
DasLixou d790808
Renaimg iter
DasLixou eabfb85
Add `EdgesRef` iter
DasLixou ab9cdcd
Use the new `EdgesRef` iter
DasLixou 8ffa7a8
Add `EdgesMut` iter
DasLixou 2ff2a2f
Use new `EdgesMut` iter
DasLixou 52db276
[DIRTY] brokey iter code :c
DasLixou f66274b
Add `in_degree` and `out_degree`
DasLixou 99dfc53
Changes
DasLixou ed5e7ce
Fix `EdgesByIdxMut`
DasLixou 1500cc8
Cleanup
DasLixou c7f410b
backticks
DasLixou f3230a3
Add `reverse_edge`
DasLixou 1c6511e
Add `reverse` function
DasLixou 7776f94
Fix `with_capacity` adjacencies
DasLixou fb4ac2c
[WIP] Source and Sink iters
DasLixou 96c2aa5
Rework on `Source` iter
DasLixou dbb082d
Finally `SourcesMut`
DasLixou 069f6b3
Add `Sinks` 😀
DasLixou 507d991
Add `in_neighbors(_mut)` and `out_neighbors(_mut)`
DasLixou 5947d27
implement `degree` for directed graphs
DasLixou 3c3a37d
Store `EdgeIdx` in `Edge<E>`
DasLixou 1192e3d
Add umimplemented `edges_of`
DasLixou 38424ac
implement `remove_node`
DasLixou caed68e
Revert saving `EdgeIdx` in `Edge<E>`
DasLixou 0dfbe39
yeah forgot about algos lol
DasLixou d393fde
docs
DasLixou 7349546
Add `GraphIterator` trait for BFS and DFS
DasLixou bad5971
Make `BFS/DFS` return `NodeIdx` and wrap them
DasLixou 639e8ec
Add `new_mut` to algos
DasLixou 222b73b
Add `from_graph` also for other `ByIdx(Mut)` iters
DasLixou ee88d17
Work on customizing algos
DasLixou 14a98e8
Add `custom_ref` and `custom_mut` for algos
DasLixou 4bc80f2
Add `ancestors(_mut)` and `descendants(_mut)`
DasLixou 05f639a
Add `edges_of(_mut)` for simple graphs
DasLixou cd2c693
Hopefully working `edges_of(_mut)` for multi graph
DasLixou d204e1e
Finish `degree`
DasLixou c9a0581
CI
DasLixou f37b72a
Make WrappedIterator simpler
DasLixou aff9c04
Lemme just implement that 💀
DasLixou 9befe86
Start of simple integration tests
DasLixou 0551822
Rename `has_node` to `contains_node`
DasLixou 0a3a257
Add `find_node` and `find_edge`
DasLixou 4a22a17
Test the new funcs
DasLixou 638d503
tests: unordered eq
DasLixou e79151b
Now finally ever iter is nonborrowed index
DasLixou 2a55cbd
Undirected Simple List works aswell 🤗
DasLixou 4bbd4c0
Add tests for `directed` simple graphs and ...
DasLixou d3f356e
`remove_[node/edge]` tests and list fix
DasLixou 1ca6cb3
Big fixes
DasLixou 2f23d10
Fix everything
DasLixou dc294ed
Add tests for `multi_list`
DasLixou 573ed2e
the final clippy touches
DasLixou baa23a0
Update BFS/DFS Safety comments
DasLixou 4e9e959
fix: `contains_edge_between` panics no more
DasLixou 21d5fb0
Merge branch 'main' into graph
DasLixou File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[package] | ||
name = "bevy_graph" | ||
version = "0.9.0" | ||
edition = "2021" | ||
description = "Graph data structures, as used by the Bevy game engine" | ||
homepage = "https://bevyengine.org" | ||
repository = "https://github.com/bevyengine/bevy" | ||
license = "MIT OR Apache-2.0" | ||
keywords = ["bevy"] | ||
|
||
[dependencies] | ||
hashbrown = "0.13.1" | ||
slotmap = "1.0.6" | ||
thiserror = "1.0.38" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
use std::{collections::VecDeque, marker::PhantomData}; | ||
|
||
use hashbrown::HashSet; | ||
|
||
use crate::{ | ||
graphs::{edge::EdgeRef, keys::NodeIdx, Graph}, | ||
iters, | ||
}; | ||
|
||
/// Implementation of the [`BFS` algorithm](https://www.geeksforgeeks.org/breadth-first-search-or-bfs-for-a-graph/) | ||
/// | ||
/// when `d` is the distance between a node and the startnode, | ||
/// it will evaluate every node with `d=1`, then continue with `d=2` and so on. | ||
pub struct BreadthFirstSearch<'g, N, E: 'g, G: Graph<N, E>, I: Iterator<Item = EdgeRef<'g, E>>> { | ||
graph: &'g G, | ||
queue: VecDeque<NodeIdx>, | ||
visited: HashSet<NodeIdx>, | ||
visitor: fn(&'g G, NodeIdx) -> I, | ||
phantom: PhantomData<(N, E)>, | ||
} | ||
|
||
impl<'g, N, E: 'g, G: Graph<N, E>, I: Iterator<Item = EdgeRef<'g, E>>> | ||
BreadthFirstSearch<'g, N, E, G, I> | ||
{ | ||
/// Creates a new `BreadthFirstSearch` with a start node and a custom visitor | ||
pub fn custom(graph: &'g G, start: NodeIdx, visitor: fn(&'g G, NodeIdx) -> I) -> Self { | ||
let node_count = graph.node_count(); | ||
let mut queue = VecDeque::with_capacity(node_count); | ||
let mut visited = HashSet::with_capacity(node_count); | ||
|
||
visited.insert(start); | ||
queue.push_back(start); | ||
|
||
Self { | ||
graph, | ||
queue, | ||
visited, | ||
visitor, | ||
phantom: PhantomData, | ||
} | ||
} | ||
|
||
/// Creates a new `BreadthFirstSearch` with a start node and a custom visitor wrapped inside an `NodesByIdx` iterator | ||
#[inline] | ||
pub fn custom_ref( | ||
graph: &'g G, | ||
start: NodeIdx, | ||
visitor: fn(&'g G, NodeIdx) -> I, | ||
) -> iters::NodesByIdx<'g, N, NodeIdx, Self> { | ||
let inner = Self::custom(graph, start, visitor); | ||
iters::NodesByIdx::from_graph(inner, graph) | ||
} | ||
|
||
/// Creates a new `BreadthFirstSearch` with a start node and a custom visitor wrapped inside an `NodesByIdxMut` iterator | ||
#[inline] | ||
pub fn custom_mut( | ||
graph: &'g mut G, | ||
start: NodeIdx, | ||
visitor: fn(&'g G, NodeIdx) -> I, | ||
) -> iters::NodesByIdxMut<'g, N, NodeIdx, Self> { | ||
unsafe { | ||
// SAFETY: `BreadthFirstSearch` assueres that every node gets visited only once | ||
let ptr: *mut G = &mut *graph; | ||
let inner = Self::custom(&*ptr, start, visitor); | ||
|
||
iters::NodesByIdxMut::from_graph(inner, graph) | ||
} | ||
} | ||
} | ||
|
||
impl<'g, N, E: 'g, G: Graph<N, E>> BreadthFirstSearch<'g, N, E, G, G::OutgoingEdgesOf<'g>> { | ||
/// Creates a new `BreadthFirstSearch` with a start node and the default visitor of `outgoing` | ||
#[inline] | ||
pub fn new(graph: &'g G, start: NodeIdx) -> Self { | ||
Self::custom(graph, start, |graph, index| graph.outgoing_edges_of(index)) | ||
} | ||
|
||
/// Creates a new `BreadthFirstSearch` with a start node and the default visitor of `outgoing` wrapped inside an `NodesByIdx` iterator | ||
#[inline] | ||
pub fn new_ref(graph: &'g G, start: NodeIdx) -> iters::NodesByIdx<'g, N, NodeIdx, Self> { | ||
let inner = Self::new(graph, start); | ||
iters::NodesByIdx::from_graph(inner, graph) | ||
} | ||
|
||
/// Creates a new `BreadthFirstSearch` with a start node and the default visitor of `outgoing` wrapped inside an `NodesByIdxMut` iterator | ||
#[inline] | ||
pub fn new_mut(graph: &'g mut G, start: NodeIdx) -> iters::NodesByIdxMut<'g, N, NodeIdx, Self> { | ||
unsafe { | ||
// SAFETY: `BreadthFirstSearch` assueres that every node gets visited only once | ||
let ptr: *mut G = &mut *graph; | ||
let inner = Self::new(&*ptr, start); | ||
|
||
iters::NodesByIdxMut::from_graph(inner, graph) | ||
} | ||
} | ||
} | ||
|
||
impl<'g, N, E: 'g, G: Graph<N, E>, I: Iterator<Item = EdgeRef<'g, E>>> Iterator | ||
for BreadthFirstSearch<'g, N, E, G, I> | ||
{ | ||
type Item = NodeIdx; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
if let Some(node) = self.queue.pop_front() { | ||
for EdgeRef(_, dst, _) in (self.visitor)(self.graph, node) { | ||
if !self.visited.contains(&dst) { | ||
self.visited.insert(dst); | ||
self.queue.push_back(dst); | ||
} | ||
} | ||
Some(node) | ||
} else { | ||
None | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use crate::{ | ||
algos::bfs::BreadthFirstSearch, | ||
graphs::{map::SimpleMapGraph, Graph}, | ||
}; | ||
|
||
#[test] | ||
fn basic_imperative_bfs() { | ||
let mut graph = SimpleMapGraph::<i32, (), true>::new(); | ||
|
||
let zero = graph.add_node(0); | ||
let one = graph.add_node(1); | ||
let two = graph.add_node(2); | ||
let three = graph.add_node(3); | ||
|
||
graph.add_edge(zero, one, ()); | ||
graph.add_edge(zero, two, ()); | ||
graph.add_edge(one, two, ()); | ||
graph.add_edge(two, zero, ()); | ||
graph.add_edge(two, three, ()); | ||
|
||
let elements = vec![0, 2, 1, 3]; | ||
|
||
let mut counted_elements = Vec::with_capacity(4); | ||
|
||
let bfs = BreadthFirstSearch::new_ref(&graph, zero); | ||
for node in bfs { | ||
counted_elements.push(*node); | ||
} | ||
|
||
assert_eq!(elements, counted_elements); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
use std::marker::PhantomData; | ||
|
||
use hashbrown::HashSet; | ||
|
||
use crate::{ | ||
graphs::{edge::EdgeRef, keys::NodeIdx, Graph}, | ||
iters, | ||
}; | ||
|
||
/// Implementation of the [`DFS` algorithm](https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/) | ||
/// | ||
/// it will evaluate every node from the start as deep as it can and then continue at the next sibling node from the top. | ||
pub struct DepthFirstSearch<'g, N, E: 'g, G: Graph<N, E>, I: Iterator<Item = EdgeRef<'g, E>>> { | ||
graph: &'g G, | ||
stack: Vec<NodeIdx>, | ||
visited: HashSet<NodeIdx>, | ||
visitor: fn(&'g G, NodeIdx) -> I, | ||
phantom: PhantomData<(N, E)>, | ||
} | ||
|
||
impl<'g, N, E: 'g, G: Graph<N, E>, I: Iterator<Item = EdgeRef<'g, E>>> | ||
DepthFirstSearch<'g, N, E, G, I> | ||
{ | ||
/// Creates a new `DepthFirstSearch` with a start node and a custom visitor | ||
pub fn custom(graph: &'g G, start: NodeIdx, visitor: fn(&'g G, NodeIdx) -> I) -> Self { | ||
let node_count = graph.node_count(); | ||
let mut stack = Vec::with_capacity(node_count); | ||
let mut visited = HashSet::with_capacity(node_count); | ||
|
||
visited.insert(start); | ||
stack.push(start); | ||
|
||
Self { | ||
graph, | ||
stack, | ||
visited, | ||
visitor, | ||
phantom: PhantomData, | ||
} | ||
} | ||
|
||
/// Creates a new `DepthFirstSearch` with a start node and a custom visitor wrapped inside an `NodesByIdx` iterator | ||
#[inline] | ||
pub fn custom_ref( | ||
graph: &'g G, | ||
start: NodeIdx, | ||
visitor: fn(&'g G, NodeIdx) -> I, | ||
) -> iters::NodesByIdx<'g, N, NodeIdx, Self> { | ||
let inner = Self::custom(graph, start, visitor); | ||
iters::NodesByIdx::from_graph(inner, graph) | ||
} | ||
|
||
/// Creates a new `DepthFirstSearch` with a start node and a custom visitor wrapped inside an `NodesByIdxMut` iterator | ||
#[inline] | ||
pub fn custom_mut( | ||
graph: &'g mut G, | ||
start: NodeIdx, | ||
visitor: fn(&'g G, NodeIdx) -> I, | ||
) -> iters::NodesByIdxMut<'g, N, NodeIdx, Self> { | ||
unsafe { | ||
// SAFETY: `DepthFirstSearch` assueres that every node gets visited only once | ||
let ptr: *mut G = &mut *graph; | ||
let inner = Self::custom(&*ptr, start, visitor); | ||
|
||
iters::NodesByIdxMut::from_graph(inner, graph) | ||
} | ||
} | ||
} | ||
|
||
impl<'g, N, E: 'g, G: Graph<N, E>> DepthFirstSearch<'g, N, E, G, G::OutgoingEdgesOf<'g>> { | ||
/// Creates a new `DepthFirstSearch` with a start node and the default visitor of `outgoing` | ||
#[inline] | ||
pub fn new(graph: &'g G, start: NodeIdx) -> Self { | ||
Self::custom(graph, start, |graph, index| graph.outgoing_edges_of(index)) | ||
} | ||
|
||
/// Creates a new `DepthFirstSearch` with a start node and the default visitor of `outgoing` wrapped inside an `NodesByIdx` iterator | ||
pub fn new_ref(graph: &'g G, start: NodeIdx) -> iters::NodesByIdx<'g, N, NodeIdx, Self> { | ||
let inner = Self::new(graph, start); | ||
iters::NodesByIdx::from_graph(inner, graph) | ||
} | ||
|
||
/// Creates a new `DepthFirstSearch` with a start node and the default visitor of `outgoing` wrapped inside an `NodesByIdxMut` iterator | ||
pub fn new_mut(graph: &'g mut G, start: NodeIdx) -> iters::NodesByIdxMut<'g, N, NodeIdx, Self> { | ||
unsafe { | ||
// SAFETY: `DepthFirstSearch` assueres that every node gets visited only once | ||
let ptr: *mut G = &mut *graph; | ||
let inner = Self::new(&*ptr, start); | ||
|
||
iters::NodesByIdxMut::from_graph(inner, graph) | ||
} | ||
} | ||
} | ||
|
||
impl<'g, N, E: 'g, G: Graph<N, E>, I: Iterator<Item = EdgeRef<'g, E>>> Iterator | ||
for DepthFirstSearch<'g, N, E, G, I> | ||
{ | ||
type Item = NodeIdx; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
if let Some(node) = self.stack.pop() { | ||
for EdgeRef(_, dst, _) in (self.visitor)(self.graph, node) { | ||
if !self.visited.contains(&dst) { | ||
self.visited.insert(dst); | ||
self.stack.push(dst); | ||
} | ||
} | ||
Some(node) | ||
} else { | ||
None | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use crate::{ | ||
algos::dfs::DepthFirstSearch, | ||
graphs::{map::SimpleMapGraph, Graph}, | ||
}; | ||
|
||
#[test] | ||
fn basic_imperative_dfs() { | ||
let mut graph = SimpleMapGraph::<i32, (), true>::new(); | ||
|
||
let zero = graph.add_node(0); | ||
let one = graph.add_node(1); | ||
let two = graph.add_node(2); | ||
let three = graph.add_node(3); | ||
|
||
graph.add_edge(zero, one, ()); | ||
graph.add_edge(zero, two, ()); | ||
graph.add_edge(one, two, ()); | ||
graph.add_edge(two, zero, ()); | ||
graph.add_edge(two, three, ()); | ||
|
||
let elements = vec![0, 1, 2, 3]; | ||
|
||
let mut counted_elements = Vec::with_capacity(4); | ||
|
||
let dfs = DepthFirstSearch::new_ref(&graph, zero); | ||
for node in dfs { | ||
counted_elements.push(*node); | ||
} | ||
|
||
assert_eq!(elements, counted_elements); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/// Implementation of the [`BFS` algorythm](https://www.geeksforgeeks.org/breadth-first-search-or-bfs-for-a-graph/) | ||
pub mod bfs; | ||
/// Implementation of the [`DFS` algorythm](https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/) | ||
pub mod dfs; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
use thiserror::Error; | ||
|
||
use crate::graphs::keys::NodeIdx; | ||
|
||
/// An error that can occur when traversing or manipulating a graph data structure | ||
#[derive(Debug, Error)] | ||
pub enum GraphError { | ||
/// the given `NodeIdx` is not preset in the graph | ||
#[error("the given `{0:?}` isn't preset in the graph")] | ||
NodeNotFound(NodeIdx), | ||
/// there is already an edge between those nodes (not allowed in `SimpleGraph`) | ||
#[error("there is already an edge between those nodes (not allowed in `SimpleGraph`)")] | ||
Loop, | ||
/// the `src` and `dst` nodes are equal, the edge would be a loop (not allowed in `SimpleGraph`) | ||
#[error("the `src` and `dst` nodes are equal, the edge would be a loop (not allowed in `SimpleGraph`)")] | ||
ContainsEdgeBetween, | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.