POMDPPlanners.core.tree package
MCTS tree data structures.
Two implementations live here:
POMDPPlanners.core.tree.anytree_based— node-object tree (each node is a Python object subclassinganytree.NodeMixin). The original implementation, preserved for backward compatibility.POMDPPlanners.core.tree.arena— column-store SoA tree (Treeholds one list per node attribute, nodes are integer IDs). Faster on every measured tree-side operation.
The legacy classes (ActionNode, BeliefNode, BaseNode,
print_tree, get_optimal_action_*) are re-exported from this
package so existing from POMDPPlanners.core.tree import ActionNode
imports keep working.
- class POMDPPlanners.core.tree.ActionNode(action, parent=None, children=(), data=None)[source]
Bases:
BaseNode- Parameters:
data (Any)
- extend_child_cdf(weight)[source]
Append a newly-attached child’s weight to the cached CDF.
If no CDF is cached yet, this is a no-op — the next sample will rebuild the full CDF from current children.
- get_belief_node_child(observation, environment)[source]
- Return type:
- Parameters:
observation (Any)
environment (Environment)
- invalidate_child_cdf()[source]
Clear the cached child sampling CDF.
Called by
BeliefNodewhen a child’s weight mutates or it detaches, forcingsample_child_node()to rebuild from scratch.- Return type:
- property name
- property spec
- class POMDPPlanners.core.tree.BaseNode(parent=None, children=(), data=None)[source]
Bases:
NodeMixin- Parameters:
data (Any)
- class POMDPPlanners.core.tree.BeliefNode(belief, observation=None, weight=1.0, parent=None, children=(), data=None)[source]
Bases:
BaseNode- property name
- property spec
- update_belief(action, observation, pomdp, **kwargs)[source]
- Parameters:
action (Any)
observation (Any)
pomdp (Environment)
- POMDPPlanners.core.tree.get_optimal_action_cost_setting(belief_node)[source]
- Return type:
- Parameters:
belief_node (BeliefNode)
- POMDPPlanners.core.tree.get_optimal_action_reward_setting(belief_node)[source]
- Return type:
- Parameters:
belief_node (BeliefNode)
- POMDPPlanners.core.tree.print_tree(tree)[source]
- Parameters:
tree (BeliefNode | ActionNode)
Submodules
POMDPPlanners.core.tree.anytree_based module
Anytree-based implementation of the MCTS tree.
Each node is a Python object (subclass of anytree.NodeMixin) with
parent/children references. This is the original tree implementation,
preserved alongside the column-store arena implementation in
POMDPPlanners.core.tree.arena.
Use:
from POMDPPlanners.core.tree.anytree_based import (
ActionNode, BeliefNode, get_optimal_action_cost_setting,
)
- class POMDPPlanners.core.tree.anytree_based.ActionNode(action, parent=None, children=(), data=None)[source]
Bases:
BaseNode- Parameters:
data (Any)
- extend_child_cdf(weight)[source]
Append a newly-attached child’s weight to the cached CDF.
If no CDF is cached yet, this is a no-op — the next sample will rebuild the full CDF from current children.
- get_belief_node_child(observation, environment)[source]
- Return type:
- Parameters:
observation (Any)
environment (Environment)
- invalidate_child_cdf()[source]
Clear the cached child sampling CDF.
Called by
BeliefNodewhen a child’s weight mutates or it detaches, forcingsample_child_node()to rebuild from scratch.- Return type:
- property name
- property spec
- class POMDPPlanners.core.tree.anytree_based.BaseNode(parent=None, children=(), data=None)[source]
Bases:
NodeMixin- Parameters:
data (Any)
- class POMDPPlanners.core.tree.anytree_based.BeliefNode(belief, observation=None, weight=1.0, parent=None, children=(), data=None)[source]
Bases:
BaseNode- property name
- property spec
- update_belief(action, observation, pomdp, **kwargs)[source]
- Parameters:
action (Any)
observation (Any)
pomdp (Environment)
- POMDPPlanners.core.tree.anytree_based.get_optimal_action_cost_setting(belief_node)[source]
- Return type:
- Parameters:
belief_node (BeliefNode)
- POMDPPlanners.core.tree.anytree_based.get_optimal_action_reward_setting(belief_node)[source]
- Return type:
- Parameters:
belief_node (BeliefNode)
- POMDPPlanners.core.tree.anytree_based.print_tree(tree)[source]
- Parameters:
tree (BeliefNode | ActionNode)
POMDPPlanners.core.tree.arena module
Column-store implementation of the MCTS tree.
A single Tree instance holds one Python list per node attribute.
A node is identified by an integer ID — its index into every column. There
are no node objects; operations on the tree are methods of this class that
take (node_id, ...) and read or write the columns directly.
Use:
from POMDPPlanners.core.tree.arena import Tree, BELIEF, ACTION
tree = Tree()
root_id = tree.add_belief_node(some_belief)
action_id = tree.add_action_node("up", parent_id=root_id)
child_id = tree.add_belief_node(next_belief, observation="o", parent_id=action_id)
tree.visit_count[root_id] += 1
Schema is declared once in __init__. Adding a new per-node attribute
means adding a line to __init__ (the empty column) and one matching
line to _allocate (the default value at allocation). Direct attribute
access is used in _allocate rather than a generic setattr loop
because the per-allocation cost is on the hot path.
This layout uses contiguous typed vectors instead of a graph of Python objects, integer IDs instead of object references, and a single allocation point so per-node overhead is one append per column rather than a Python class instantiation plus GC bookkeeping.
In addition to the columns, the tree maintains two per-parent indexes:
children_cdf[parent]— cumulative distribution function over child weights, in the same order aschildren_ids[parent]. Maintained incrementally on everyadd_*_node. Enables O(log K) weighted sampling viasample_belief_child.obs_child_lookupandaction_child_lookup—(parent_id, key) → child_iddicts populated when the observation/action is hashable. Enable O(1) child lookup viaget_belief_child_indexedandget_action_child_indexed.
If the user mutates weight[id] after add_belief_node the CDF for
the parent becomes stale; call recompute_children_cdf(parent_id) to
rebuild. Indexed lookup is unavailable for unhashable
observations/actions (e.g. np.ndarray); use the linear-scan
get_belief_child / get_action_child for those.
- class POMDPPlanners.core.tree.arena.Tree[source]
Bases:
objectColumn-store search tree.
- add_action_node(action, parent_id, data=None, action_key=None)[source]
Allocate an action node under
parent_idand return its ID.Also: (a) extend the parent’s CDF by 1.0 (action nodes default to unit weight); (b) register
(parent_id, key) → node_idinaction_child_lookupwherekeyis the explicitaction_keyif provided (caller guarantees hashable), or the rawaction(silently dropped if unhashable).
- add_belief_node(belief, observation=None, weight=1.0, parent_id=None, data=None, obs_key=None)[source]
Allocate a belief node and return its ID.
If
parent_idis provided, also: (a) extend the parent’s CDF byweight; (b) register(parent_id, key) → node_idinobs_child_lookupwherekeyis the explicitobs_keyif provided (caller guarantees hashable), or the rawobservation(silently dropped if unhashable).
- best_action_by_cost(belief_id)[source]
Return the action of the lowest-q_value action child of
belief_id.Arena equivalent of
get_optimal_action_cost_setting()fromanytree_based.
- best_action_by_reward(belief_id)[source]
Return the action of the highest-q_value action child of
belief_id.Arena equivalent of
get_optimal_action_reward_setting()fromanytree_based.
- get_action_child(belief_id, action)[source]
Return the ID of the action child of
belief_idmatchingaction.Linear scan; compares numpy arrays by content, everything else by
==. Use whenactionmay not be hashable; otherwise preferget_action_child_indexed()for O(1) lookup.
- get_action_child_indexed(belief_id, action=None, action_key=None)[source]
O(1) lookup of an action child of
belief_idby hashable key.If
action_keyis provided the caller guarantees it is hashable; the lookup uses it directly. Otherwise, the rawactionis tried andNoneis returned for unhashable values.
- get_belief_child(action_id, observation, env)[source]
Return the ID of the belief child of
action_idmatchingobservation.Linear scan using
env.is_equal_observation. Use this when the observation may not be hashable (e.g.np.ndarray) or when equality is custom; otherwise preferget_belief_child_indexed()for O(1) lookup.- Return type:
- Parameters:
action_id (int)
observation (Any)
env (Environment)
- get_belief_child_indexed(action_id, observation=None, obs_key=None)[source]
O(1) lookup of a belief child of
action_idby hashable key.If
obs_keyis provided the caller guarantees it is hashable; the lookup uses it directly. Otherwise, the rawobservationis tried andNoneis returned for unhashable values.
- increment_visit_count(node_id)[source]
Increment
visit_count[node_id]by one. Works for either node kind.
- increment_weight(child_id, delta)[source]
Increment
weight[child_id]bydeltaand patch the parent’s CDF.Cheaper than
recompute_children_cdf()for the common case of a single weight bump (e.g. POMCPOW’s observation widening): walks the parent’s CDF only from this child’s position onward, addingdeltato each remaining entry. O(K - position) where K is the number of siblings.If
child_idis the root (no parent), only the weight is updated; there is no parent CDF to patch.
- recompute_children_cdf(parent_id)[source]
Rebuild the parent’s CDF from current
weightvalues.Use this when a caller has mutated
weight[id]for one or more children after they were added.
- reserve(capacity)[source]
Pre-allocate
capacityslots in every per-node column.After this call
len(tree)is unchanged, butcapacityslots are physically resident in each column so the firstcapacitysubsequent allocations write at a cursor instead of triggeringlist.append(and the periodic O(N) realloc bursts that come with it). Useful when the maximum tree size is known in advance (e.g.,2 * n_simulations * depthfor POMCPOW-style planners).Allocations beyond
capacityfall back toappendand grow the columns normally. Callingreserve()more than once is idempotent in the sense that columns are re-padded up tocapacityif more headroom is needed; existing entries are preserved.
- sample_belief_child(action_id)[source]
Sample one belief child of
action_idproportional to its weight.Uses the maintained CDF: O(log K) per sample via
bisect. If the caller has mutatedweight[id]after the children were added, callrecompute_children_cdf()first to refresh the CDF.
- set_immediate_cost(node_id, value)[source]
Set
immediate_costand mirror toimmediate_reward = -value.
- set_immediate_reward(node_id, value)[source]
Set
immediate_rewardand mirror toimmediate_cost = -value.