Behavior Tree → SMV Translation¶
BehaVerify’s core contribution is a translation from BTs to SMV models that exposes exactly the right transitions to nuXmv. This page formalises the fast-forwarding encoding from Serbinowska & Johnson (SEFM 2022) and describes its variable-staging scheme.
Encoding at a glance¶
Naive encoding. Every internal BT step — entering the root, ticking each child, bubbling statuses up, updating the blackboard — is its own SMV transition.¶
Fast-forwarding encoding. One SMV transition collapses an entire root-to-leaf traversal plus all blackboard updates into a single atomic step.¶
Let \(T\) be a BT with node set \(V\) and blackboard variables \(B = \{b_1, \ldots, b_k\}\). Write \(\Sigma = \mathrm{dom}(B)\) for the set of blackboard valuations.
Naive encoding¶
The naive encoding tracks a program counter \(\mathrm{pc} \in V \cup \{\bot\}\) that names the node currently being visited. A single SMV transition corresponds to one atomic step of the BT interpreter: entering a composite, ticking a child, bubbling up a status. Because a full tick of a tree with \(n\) nodes requires \(\Theta(n)\) such steps, the induced SMV model grows linearly in the tree size at every “real” tick of the BT.
Fast-forwarding encoding¶
The fast-forwarding encoding removes the program counter. Every SMV transition encodes a whole tick: given a blackboard valuation \(\sigma\), the transition \(R(\sigma, \sigma')\) holds iff \(\sigma'\) is the blackboard that results from running one tick of the BT on \(\sigma\). Formally, if \(\mathrm{tick}_T : \Sigma \to \Sigma\) is the BT’s one-tick blackboard map, then
Serbinowska & Johnson showed that this encoding is semantically equivalent to the naive one for every INVAR/CTL/LTL formula whose atoms refer only to blackboard variables and post-tick node statuses — the very formulas that BehaVerify’s DSL accepts.
Variable staging¶
A single tick may read and write the same blackboard slot multiple
times (e.g., a sequence whose children all update pos_x). The
straightforward compilation into SMV would use intermediate variables
for each such read, exploding the state space. BehaVerify instead
stages each blackboard variable:
where \(b_i^{(0)}\) is the tick-start value, \(b_i^{(n_i)}\) is the tick-end value, and the intermediate stages \(b_i^{(j)}\) record writes in the order they occur inside the tick. The SMV transition relation then closes the loop across ticks with
An intermediate stage \(b_i^{(j)}\) is dead if no subsequent
stage reads it; BehaVerify’s post-generation pass
(behaverify.dsl_to_nuxmv) removes dead stages, so the final
model carries only live stages.
Node trimming¶
A sub-tree whose guard condition (the tick_prerequisite plus any
ancestor-imposed boolean) is unsatisfiable in every reachable state
cannot fire. The trimming pass in
behaverify.dsl_to_nuxmv identifies such sub-trees (via a
conservative BDD-based reachability argument) and removes them from
the emitted SMV. The --do_not_trim flag disables this pass.
Trimming is sound but incomplete: it never removes a node that could fire, and it may leave in place a node that never fires in practice.
Non-determinism¶
Unknown initial values or environmental noise are encoded as set-valued SMV assignments:
init(x) := {1, 2, 3};
nuXmv treats these as non-deterministic. Every property is then implicitly universally quantified over the choices:
This gives worst-case guarantees, adequate for safety properties but not for quantitative reasoning.
Putting it together¶
The full BehaVerify $to$ SMV pipeline is:
Parse. TextX consumes a
.treeand builds an AST.Validate.
behaverify.check_grammarrejects type/scope/reference errors.Build IR.
behaverify.node_creatorconverts the AST to the internal node tree.Meta-compile expressions.
behaverify.meta_functionslowers prefix-notation expressions to per-backend expression trees, resolvingconstant_indexandloopconstructs.Generate SMV.
behaverify.dsl_to_nuxmvwalks the IR, emits the staging variables, the fast-forwarding transition relation, thespecificationsblock, and (optionally) runs the trimming pass.
The resulting .smv file is self-contained: it can be fed to nuXmv
without the original .tree.
Encoding size¶
Serbinowska & Johnson (SEFM 2022) report empirical sizes:
Naive encoding: state space \(\Theta(|V| \cdot 2^{|B|})\).
Fast-forwarding: state space \(\Theta(2^{|B|})\).
The authors verified a binary BT with 2,055 nodes under fast-forwarding; naive timed out well below 200. The practical takeaway: use fast-forwarding (the default) unless you are actively debugging the compiled transition and want per-step granularity.
References¶
Serbinowska, Johnson. BehaVerify: Verifying Temporal Logic Specifications for Behavior Trees. SEFM 2022, LNCS 13550, pp. 307–323. https://doi.org/10.1007/978-3-031-17108-6_19