-
Notifications
You must be signed in to change notification settings - Fork 399
Graphs Pattern #68
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
Graphs Pattern #68
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
bb5f140
Graph pattern
95d2996
Graph pattern
0d13021
real graph -- v0
76a4abf
basic graph + forest -- v0
ec55466
Update patterns/graphs.md
simonsan 5a06ccb
Add graphs.md to SUMMARY
simonsan a4834ed
imprting modules
simonsan 5eeae39
Update patterns/graphs.md
simonsan c3b36ad
markdownlint
simonsan 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
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,112 @@ | ||
# Graphs | ||
|
||
## Description | ||
|
||
Implement idiomatic graph data structures (tree, forest, graph...) that are dynamically modifiable during runtime. | ||
|
||
## Example | ||
|
||
A simple graph structure: | ||
|
||
```rust | ||
struct Graph<T> { | ||
// The graph contains only a Vec of nodes. | ||
nodes: Vec<Node<T>>, | ||
} | ||
|
||
struct Node<T> { | ||
// Each node of the graph corresponds to an index. | ||
index: usize, | ||
// The node knows the index of its neighbors. | ||
adjacent: Vec<u32>, | ||
// The actual data associated to this node. | ||
pub data: T, | ||
} | ||
``` | ||
|
||
A more advanced example: a forest | ||
|
||
```rust | ||
// A node of the graph. | ||
pub struct Node<T> { | ||
// Each node can have at max one parent: multiple roots can exist. | ||
parent: Option<NodeId>, | ||
previous_sibling: Option<NodeId>, | ||
next_sibling: Option<NodeId>, | ||
first_child: Option<NodeId>, | ||
last_child: Option<NodeId>, | ||
|
||
// The actual data stored. | ||
pub data: T, | ||
} | ||
|
||
// indexes from the vector used for creating the graph. | ||
pub struct NodeId { | ||
index: usize, | ||
} | ||
|
||
// A memory management arena that ensures that every element of the arena has the same lifetime. | ||
pub struct Arena<T> { | ||
nodes: Vec<Node<T>>, | ||
} | ||
|
||
impl<T> Arena<T> { | ||
// Method to create a new node. | ||
pub fn new_node(&mut self, data: T) -> NodeId { | ||
// Get the next free index | ||
let next_index = self.nodes.len(); | ||
|
||
// Push the node into the arena | ||
self.nodes.push(Node { | ||
parent: None, | ||
first_child: None, | ||
last_child: None, | ||
previous_sibling: None, | ||
next_sibling: None, | ||
data: data, | ||
}); | ||
|
||
// Return the node identifier | ||
NodeId { index: next_index } | ||
} | ||
} | ||
``` | ||
|
||
## Motivation | ||
|
||
This pattern should be used when we need data structures that can be modified during runtime. | ||
|
||
## Advantages | ||
|
||
- Clear and easy to use. | ||
- Reduce the lifetime complexity within the structures. | ||
- Avoid runtime borrow checks. | ||
- Every element within the arena has the same lifetime. | ||
- Multi processing is possible given that parts of a vector can be shared across threads safely. | ||
|
||
## Discussion | ||
|
||
Region-based memory management is the common method used to deal with graph data structures in Rust. | ||
This avoids to use interior mutability with data structures as follows: | ||
|
||
```rust | ||
use std::rc::Rc; | ||
use std::cell::RefCell; | ||
|
||
struct Node<T> { | ||
previous: Rc<RefCell<Box<Node<T>>>>, | ||
next: Vec<Rc<RefCell<Box<T>>>>, | ||
data: T, | ||
// ... | ||
} | ||
``` | ||
|
||
which is hard to understand and will also lead into runtime borrow checks. | ||
|
||
## See also | ||
|
||
- [Region-based memory management](https://en.wikipedia.org/wiki/Region-based_memory_management) | ||
- [Module rustc_data_structures::graph](https://doc.rust-lang.org/1.1.0/rustc_data_structures/graph/) | ||
- [Code example: Arena based tree structure with multithreading support](https://github.com/saschagrunert/indextree) | ||
- [Code example: Graph data structure library](https://github.com/bluss/petgraph) | ||
- [Code example: How to implement complex data structure in Rust](https://github.com/danigm/rust-graph-example) |
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a node can have at most one parent, then the data structure is a tree, not a graph. Nodes in a graph can have more than one parent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks more like a forest, since this code allows for multiple roots 😉