Skip to content

Commit

Permalink
Separate graphing data from main BT struct (#32)
Browse files Browse the repository at this point in the history
All data needed to draw graphs is now created on the fly every time when
`get_graphviz()` gets called. This should make behavior trees consume
less memory and construct faster.

Issue: #29
  • Loading branch information
kaphula authored Jan 15, 2024
1 parent 637be3d commit 977792d
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 87 deletions.
2 changes: 1 addition & 1 deletion bonsai/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ name = "bonsai-bt"
readme = "../README.md"
repository = "https://github.com/sollimann/bonsai.git"
rust-version = "1.60.0"
version = "0.6.1"
version = "0.6.2"

[lib]
name = "bonsai_bt"
Expand Down
27 changes: 13 additions & 14 deletions bonsai/src/bt.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fmt::Debug;

use petgraph::dot::{Config, Dot};
use petgraph::{stable_graph::NodeIndex, Graph};
use petgraph::Graph;

use crate::visualizer::NodeType;
use crate::{ActionArgs, Behavior, State, Status, UpdateEvent};
Expand Down Expand Up @@ -33,27 +33,17 @@ pub struct BT<A, K> {
initial_behavior: Behavior<A>,
/// blackboard
bb: BlackBoard<K>,
/// Tree formulated as PetGraph
pub(crate) graph: Graph<NodeType<A>, u32, petgraph::Directed>,
/// root node
root_id: NodeIndex,
}

impl<A: Clone + Debug, K: Debug> BT<A, K> {
pub fn new(behavior: Behavior<A>, blackboard: K) -> Self {
let backup_behavior = behavior.clone();
let bt = State::new(behavior);

// generate graph
let mut graph = Graph::<NodeType<A>, u32, petgraph::Directed>::new();
let root_id = graph.add_node(NodeType::Root);

Self {
state: bt,
initial_behavior: backup_behavior,
bb: BlackBoard(blackboard),
graph,
root_id,
}
}

Expand Down Expand Up @@ -109,10 +99,19 @@ impl<A: Clone + Debug, K: Debug> BT<A, K> {
/// println!("{}", g);
/// ```
pub fn get_graphviz(&mut self) -> String {
self.get_graphviz_with_graph_instance().0
}

pub(crate) fn get_graphviz_with_graph_instance(&mut self) -> (String, Graph<NodeType<A>, u32>) {
let behavior = self.initial_behavior.to_owned();
self.dfs_recursive(behavior, self.root_id);
let digraph = Dot::with_config(&self.graph, &[Config::EdgeNoLabel]);
format!("{:?}", digraph)

let mut graph = Graph::<NodeType<A>, u32, petgraph::Directed>::new();
let root_id = graph.add_node(NodeType::Root);

Self::dfs_recursive(&mut graph, behavior, root_id);

let digraph = Dot::with_config(&graph, &[Config::EdgeNoLabel]);
(format!("{:?}", digraph), graph)
}

/// Retrieve a mutable reference to the blackboard for
Expand Down
2 changes: 1 addition & 1 deletion bonsai/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ impl<A: Clone> State<A> {
Behavior::After(after_all) => State::AfterState(0, after_all.into_iter().map(State::new).collect()),
Behavior::RepeatSequence(ev, rep) => {
let state = State::new(
rep.get(0)
rep.first()
.expect("RepeatSequence's sequence of behaviors to run cannot be empty!")
.clone(),
);
Expand Down
131 changes: 60 additions & 71 deletions bonsai/src/visualizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,103 +22,107 @@ pub(crate) enum NodeType<A> {
}

impl<A: Clone + Debug, K: Debug> BT<A, K> {
pub(crate) fn dfs_recursive(&mut self, behavior: Behavior<A>, parent_node: NodeIndex) {
pub(crate) fn dfs_recursive(
graph: &mut Graph<NodeType<A>, u32, petgraph::Directed>,
behavior: Behavior<A>,
parent_node: NodeIndex,
) {
match behavior {
Behavior::Action(action) => {
let node_id = self.graph.add_node(NodeType::Action(action));
self.graph.add_edge(parent_node, node_id, 1);
let node_id = graph.add_node(NodeType::Action(action));
graph.add_edge(parent_node, node_id, 1);
}
Behavior::Invert(ev) => {
let node_id = self.graph.add_node(NodeType::Invert);
self.graph.add_edge(parent_node, node_id, 1);
self.dfs_recursive(*ev, node_id)
let node_id = graph.add_node(NodeType::Invert);
graph.add_edge(parent_node, node_id, 1);
Self::dfs_recursive(graph, *ev, node_id)
}
Behavior::AlwaysSucceed(ev) => {
let node_id = self.graph.add_node(NodeType::AlwaysSucceed);
self.graph.add_edge(parent_node, node_id, 1);
self.dfs_recursive(*ev, node_id)
let node_id = graph.add_node(NodeType::AlwaysSucceed);
graph.add_edge(parent_node, node_id, 1);
Self::dfs_recursive(graph, *ev, node_id)
}
Behavior::Wait(dt) => {
let node_id = self.graph.add_node(NodeType::Wait(dt));
self.graph.add_edge(parent_node, node_id, 1);
let node_id = graph.add_node(NodeType::Wait(dt));
graph.add_edge(parent_node, node_id, 1);
}
Behavior::WaitForever => {
let node_id = self.graph.add_node(NodeType::WaitForever);
self.graph.add_edge(parent_node, node_id, 1);
let node_id = graph.add_node(NodeType::WaitForever);
graph.add_edge(parent_node, node_id, 1);
}
Behavior::If(condition, success, failure) => {
let node_id = self.graph.add_node(NodeType::If);
self.graph.add_edge(parent_node, node_id, 1);
let node_id = graph.add_node(NodeType::If);
graph.add_edge(parent_node, node_id, 1);

// left (if condition)
let left = *condition;
self.dfs_recursive(left, node_id);
Self::dfs_recursive(graph, left, node_id);

// middle (execute if condition is True)
let middle = *success;
self.dfs_recursive(middle, node_id);
Self::dfs_recursive(graph, middle, node_id);

// right (execute if condition is False)
let right = *failure;
self.dfs_recursive(right, node_id);
Self::dfs_recursive(graph, right, node_id);
}
Behavior::Select(sel) => {
let node_id = self.graph.add_node(NodeType::Select);
self.graph.add_edge(parent_node, node_id, 1);
let node_id = graph.add_node(NodeType::Select);
graph.add_edge(parent_node, node_id, 1);
for b in sel {
self.dfs_recursive(b, node_id)
Self::dfs_recursive(graph, b, node_id)
}
}
Behavior::Sequence(seq) => {
let node_id = self.graph.add_node(NodeType::Sequence);
self.graph.add_edge(parent_node, node_id, 1);
let node_id = graph.add_node(NodeType::Sequence);
graph.add_edge(parent_node, node_id, 1);
for b in seq {
self.dfs_recursive(b, node_id)
Self::dfs_recursive(graph, b, node_id)
}
}
Behavior::While(ev, seq) => {
let node_id = self.graph.add_node(NodeType::While);
self.graph.add_edge(parent_node, node_id, 1);
let node_id = graph.add_node(NodeType::While);
graph.add_edge(parent_node, node_id, 1);

// left
let left = *ev;
self.dfs_recursive(left, node_id);
Self::dfs_recursive(graph, left, node_id);

// right
let right = Sequence(seq);
self.dfs_recursive(right, node_id)
Self::dfs_recursive(graph, right, node_id)
}
Behavior::RepeatSequence(ev, seq) => {
let node_id = self.graph.add_node(NodeType::RepeatSequence);
self.graph.add_edge(parent_node, node_id, 1);
let node_id = graph.add_node(NodeType::RepeatSequence);
graph.add_edge(parent_node, node_id, 1);

// left
let left = *ev;
self.dfs_recursive(left, node_id);
Self::dfs_recursive(graph, left, node_id);

// right
let right = Sequence(seq);
self.dfs_recursive(right, node_id)
Self::dfs_recursive(graph, right, node_id)
}
Behavior::WhenAll(all) => {
let node_id = self.graph.add_node(NodeType::WhenAll);
self.graph.add_edge(parent_node, node_id, 1);
let node_id = graph.add_node(NodeType::WhenAll);
graph.add_edge(parent_node, node_id, 1);
for b in all {
self.dfs_recursive(b, node_id)
Self::dfs_recursive(graph, b, node_id)
}
}
Behavior::WhenAny(any) => {
let node_id = self.graph.add_node(NodeType::WhenAny);
self.graph.add_edge(parent_node, node_id, 1);
let node_id = graph.add_node(NodeType::WhenAny);
graph.add_edge(parent_node, node_id, 1);
for b in any {
self.dfs_recursive(b, node_id)
Self::dfs_recursive(graph, b, node_id)
}
}
Behavior::After(after_all) => {
let node_id = self.graph.add_node(NodeType::After);
self.graph.add_edge(parent_node, node_id, 1);
let node_id = graph.add_node(NodeType::After);
graph.add_edge(parent_node, node_id, 1);
for b in after_all {
self.dfs_recursive(b, node_id)
Self::dfs_recursive(graph, b, node_id)
}
}
}
Expand Down Expand Up @@ -177,8 +181,7 @@ mod tests {

let h: HashMap<String, i32> = HashMap::new();
let mut bt = BT::new(behavior, h);
bt.get_graphviz();
let g = bt.graph.clone();
let (_, g) = bt.get_graphviz_with_graph_instance();

println!("{:?}", Dot::with_config(&g, &[Config::EdgeNoLabel]));

Expand All @@ -196,8 +199,7 @@ mod tests {

let h: HashMap<String, i32> = HashMap::new();
let mut bt = BT::new(behavior, h);
bt.get_graphviz();
let g = bt.graph.clone();
let (_, g) = bt.get_graphviz_with_graph_instance();

println!("{:?}", Dot::with_config(&g, &[Config::EdgeNoLabel]));

Expand All @@ -216,8 +218,7 @@ mod tests {

let h: HashMap<String, i32> = HashMap::new();
let mut bt = BT::new(behavior, h);
bt.get_graphviz();
let g = bt.graph.clone();
let (_, g) = bt.get_graphviz_with_graph_instance();

println!("{:?}", Dot::with_config(&g, &[Config::EdgeNoLabel]));

Expand All @@ -231,8 +232,7 @@ mod tests {

let h: HashMap<String, i32> = HashMap::new();
let mut bt = BT::new(behavior, h);
bt.get_graphviz();
let g = bt.graph.clone();
let (_, g) = bt.get_graphviz_with_graph_instance();

println!("{:?}", Dot::with_config(&g, &[Config::EdgeNoLabel]));

Expand All @@ -246,8 +246,7 @@ mod tests {

let h: HashMap<String, i32> = HashMap::new();
let mut bt = BT::new(behavior, h);
bt.get_graphviz();
let g = bt.graph.clone();
let (_, g) = bt.get_graphviz_with_graph_instance();

println!("{:?}", Dot::with_config(&g, &[Config::EdgeNoLabel]));

Expand All @@ -268,8 +267,7 @@ mod tests {

let h: HashMap<String, i32> = HashMap::new();
let mut bt = BT::new(behavior, h);
bt.get_graphviz();
let g = bt.graph.clone();
let (_, g) = bt.get_graphviz_with_graph_instance();

println!("{:?}", Dot::with_config(&g, &[Config::EdgeNoLabel]));

Expand All @@ -283,8 +281,7 @@ mod tests {

let h: HashMap<String, i32> = HashMap::new();
let mut bt = BT::new(behavior, h);
bt.get_graphviz();
let g = bt.graph.clone();
let (_, g) = bt.get_graphviz_with_graph_instance();

println!("{:?}", Dot::with_config(&g, &[Config::EdgeNoLabel]));

Expand All @@ -303,8 +300,7 @@ mod tests {

let h: HashMap<String, i32> = HashMap::new();
let mut bt = BT::new(behavior, h);
bt.get_graphviz();
let g = bt.graph.clone();
let (_, g) = bt.get_graphviz_with_graph_instance();

println!("{:?}", Dot::with_config(&g, &[Config::EdgeNoLabel]));

Expand All @@ -318,8 +314,7 @@ mod tests {

let h: HashMap<String, i32> = HashMap::new();
let mut bt = BT::new(behavior, h);
bt.get_graphviz();
let g = bt.graph.clone();
let (_, g) = bt.get_graphviz_with_graph_instance();

println!("{:?}", Dot::with_config(&g, &[Config::EdgeNoLabel]));

Expand All @@ -338,8 +333,7 @@ mod tests {

let h: HashMap<String, i32> = HashMap::new();
let mut bt = BT::new(behavior, h);
bt.get_graphviz();
let g = bt.graph.clone();
let (_, g) = bt.get_graphviz_with_graph_instance();

println!("{:?}", Dot::with_config(&g, &[Config::EdgeNoLabel]));

Expand All @@ -360,8 +354,7 @@ mod tests {

let h: HashMap<String, i32> = HashMap::new();
let mut bt = BT::new(behavior, h);
bt.get_graphviz();
let g = bt.graph.clone();
let (_, g) = bt.get_graphviz_with_graph_instance();

println!("{:?}", Dot::with_config(&g, &[Config::EdgeNoLabel]));
assert_eq!(g.edge_count(), 16);
Expand All @@ -382,8 +375,7 @@ mod tests {

let h: HashMap<String, i32> = HashMap::new();
let mut bt = BT::new(behavior, h);
bt.get_graphviz();
let g = bt.graph.clone();
let (_, g) = bt.get_graphviz_with_graph_instance();

println!("{:?}", Dot::with_config(&g, &[Config::EdgeNoLabel]));

Expand All @@ -402,8 +394,7 @@ mod tests {

let h: HashMap<String, i32> = HashMap::new();
let mut bt = BT::new(behavior, h);
bt.get_graphviz();
let g = bt.graph.clone();
let (_, g) = bt.get_graphviz_with_graph_instance();

println!("{:?}", Dot::with_config(&g, &[Config::EdgeNoLabel]));
assert_eq!(g.edge_count(), 7);
Expand All @@ -421,8 +412,7 @@ mod tests {

let h: HashMap<String, i32> = HashMap::new();
let mut bt = BT::new(behavior, h);
bt.get_graphviz();
let g = bt.graph.clone();
let (_, g) = bt.get_graphviz_with_graph_instance();

println!("{:?}", Dot::with_config(&g, &[Config::EdgeNoLabel]));

Expand All @@ -441,8 +431,7 @@ mod tests {

let h: HashMap<String, i32> = HashMap::new();
let mut bt = BT::new(behavior, h);
bt.get_graphviz();
let g = bt.graph.clone();
let (_, g) = bt.get_graphviz_with_graph_instance();

println!("{:?}", Dot::with_config(&g, &[Config::EdgeNoLabel]));

Expand Down

0 comments on commit 977792d

Please sign in to comment.