From 977792d6915cb6f67502606c36f39171323528b4 Mon Sep 17 00:00:00 2001
From: Valtteri Vallius <36015558+kaphula@users.noreply.github.com>
Date: Mon, 15 Jan 2024 12:25:37 +0200
Subject: [PATCH] Separate graphing data from main BT struct (#32)
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: https://github.com/Sollimann/bonsai/issues/29
---
bonsai/Cargo.toml | 2 +-
bonsai/src/bt.rs | 27 ++++----
bonsai/src/state.rs | 2 +-
bonsai/src/visualizer.rs | 131 ++++++++++++++++++---------------------
4 files changed, 75 insertions(+), 87 deletions(-)
diff --git a/bonsai/Cargo.toml b/bonsai/Cargo.toml
index 461a129..0083206 100644
--- a/bonsai/Cargo.toml
+++ b/bonsai/Cargo.toml
@@ -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"
diff --git a/bonsai/src/bt.rs b/bonsai/src/bt.rs
index 78694b5..bdd57df 100644
--- a/bonsai/src/bt.rs
+++ b/bonsai/src/bt.rs
@@ -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};
@@ -33,10 +33,6 @@ pub struct BT {
initial_behavior: Behavior,
/// blackboard
bb: BlackBoard,
- /// Tree formulated as PetGraph
- pub(crate) graph: Graph, u32, petgraph::Directed>,
- /// root node
- root_id: NodeIndex,
}
impl BT {
@@ -44,16 +40,10 @@ impl BT {
let backup_behavior = behavior.clone();
let bt = State::new(behavior);
- // generate graph
- let mut graph = Graph::, 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,
}
}
@@ -109,10 +99,19 @@ impl BT {
/// 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, 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::, 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
diff --git a/bonsai/src/state.rs b/bonsai/src/state.rs
index eea3e07..6dd1842 100644
--- a/bonsai/src/state.rs
+++ b/bonsai/src/state.rs
@@ -99,7 +99,7 @@ impl State {
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(),
);
diff --git a/bonsai/src/visualizer.rs b/bonsai/src/visualizer.rs
index 9a4c57e..177d0d3 100644
--- a/bonsai/src/visualizer.rs
+++ b/bonsai/src/visualizer.rs
@@ -22,103 +22,107 @@ pub(crate) enum NodeType {
}
impl BT {
- pub(crate) fn dfs_recursive(&mut self, behavior: Behavior, parent_node: NodeIndex) {
+ pub(crate) fn dfs_recursive(
+ graph: &mut Graph, u32, petgraph::Directed>,
+ behavior: Behavior,
+ 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)
}
}
}
@@ -177,8 +181,7 @@ mod tests {
let h: HashMap = 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]));
@@ -196,8 +199,7 @@ mod tests {
let h: HashMap = 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]));
@@ -216,8 +218,7 @@ mod tests {
let h: HashMap = 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]));
@@ -231,8 +232,7 @@ mod tests {
let h: HashMap = 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]));
@@ -246,8 +246,7 @@ mod tests {
let h: HashMap = 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]));
@@ -268,8 +267,7 @@ mod tests {
let h: HashMap = 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]));
@@ -283,8 +281,7 @@ mod tests {
let h: HashMap = 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]));
@@ -303,8 +300,7 @@ mod tests {
let h: HashMap = 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]));
@@ -318,8 +314,7 @@ mod tests {
let h: HashMap = 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]));
@@ -338,8 +333,7 @@ mod tests {
let h: HashMap = 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]));
@@ -360,8 +354,7 @@ mod tests {
let h: HashMap = 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);
@@ -382,8 +375,7 @@ mod tests {
let h: HashMap = 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]));
@@ -402,8 +394,7 @@ mod tests {
let h: HashMap = 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);
@@ -421,8 +412,7 @@ mod tests {
let h: HashMap = 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]));
@@ -441,8 +431,7 @@ mod tests {
let h: HashMap = 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]));