Generic hierarchical tree backed by NumPy arrays with typed node payloads
Project description
Array Tree
A generic hierarchical tree data structure backed by NumPy structured arrays, with typed node payloads.
ArrayTree stores tree topology (parent, child, and sibling pointers) in a compact NumPy structured array for cache-friendly memory layout and efficient bulk operations. Payloads are stored separately in a typed list, so the tree works with any Python object — strings, dicts, dataclasses, or the included DataNode container for data + metadata.
Designed for CAE (Computer-Aided Engineering) workflows where trees represent assembly structures, material hierarchies, and analysis results with thousands of nodes carrying large numerical arrays.
Key features
- Generic —
ArrayTree[T]accepts any payload type - NumPy-backed topology — structured array with uint32 IDs, ~29 bytes per node
- Soft deletion — O(1) delete, explicit
repack()for compaction - Lazy loading —
LazyDataNodeloads array data on demand, releases to free memory - Frozen mode — prevent mutations after construction
- Zero hard dependencies beyond NumPy
Installation
pip install vcti-array-tree>=1.4.0
In pyproject.toml dependencies
dependencies = [
"vcti-array-tree>=1.4.0",
]
Quick Start
from vcti.arraytree import ArrayTree, DataNode
# Create a tree with any payload type
tree: ArrayTree[str] = ArrayTree()
# Add nodes (root is always id=0)
models = tree.add_node(0, data="models")
results = tree.add_node(0, data="results")
stress = tree.add_node(results, data="stress")
# Navigate
children = tree.get_children_ids(0) # [1, 2]
parent = tree.get_parent_id(stress) # 2 (results)
all_nodes = tree.iter_nodes(0) # [1, 2, 3] depth-first
# Access and update payloads
tree.get_node(stress) # "stress"
tree.set_node(stress, "von_mises_stress") # update payload
# Ancestry and depth
tree.get_ancestor_ids(stress) # [2, 0] (results, root)
tree.get_depth(stress) # 2
# Soft-delete and repack
tree.delete_node(models)
mapping = tree.repack() # compacts, remaps IDs
# Freeze for read-only access
tree.freeze()
With DataNode payloads
import numpy as np
from vcti.arraytree import ArrayTree, DataNode
tree: ArrayTree[DataNode] = ArrayTree()
tree.add_node(0, DataNode(
data=np.array([1.0, 2.0, 3.0]),
attributes={'units': 'mm', 'name': 'displacement'},
))
tree.add_node(0, DataNode(
attributes={'type': 'group', 'solver': 'NASTRAN'},
))
Error handling
from vcti.arraytree import ArrayTree
tree: ArrayTree[str] = ArrayTree()
node = tree.add_node(0, "data")
# KeyError — node doesn't exist
try:
tree.get_node(999)
except KeyError:
pass
# ValueError — node is deleted
tree.delete_node(node)
try:
tree.get_node(node)
except ValueError:
pass
# RuntimeError — tree is frozen
tree.freeze()
try:
tree.add_node(0, "blocked")
except RuntimeError:
pass
Core API
ArrayTree[T]
| Method | Description |
|---|---|
add_node(parent_id, data) |
Add child node, returns new ID |
set_node(node_id, data) |
Update payload for existing node |
delete_node(node_id, recursive) |
Soft-delete (marks inactive) |
get_node(node_id) |
Get payload (O(1)) |
get_parent_id(node_id) |
Get parent ID |
get_children_ids(node_id) |
List child IDs |
get_ancestor_ids(node_id) |
List ancestor IDs (parent to root) |
get_depth(node_id) |
Depth of node (root = 0) |
iter_nodes(root_id, recursive) |
Depth-first traversal |
get_all_node_ids(active_only) |
All node IDs |
repack(new_capacity) |
Remove deleted nodes, compact arrays |
freeze(payloads=False) |
Freeze structure; optionally freeze payloads too |
is_payloads_frozen() |
True if payloads are also frozen |
count_nodes(active_only) |
Count nodes |
get_capacity() |
Current pre-allocated capacity |
len(tree) |
Number of active nodes |
node_id in tree |
Check if node is active |
for nid in tree |
Iterate active node IDs |
get_path(node_id) |
Path from root to node |
tree.topology |
Read-only numpy view of tree structure |
tree.payloads |
Read-only tuple of payloads |
DataNode
Simple container for tree node payloads:
| Attribute | Type | Description |
|---|---|---|
data |
Any (ndarray, MaskedArray, etc.) or None | Data payload |
attributes |
dict[str, Any] | Metadata dictionary |
LazyDataNode
DataNode subclass with on-demand loading for large arrays:
from vcti.arraytree import ArrayTree, LazyDataNode
tree: ArrayTree[LazyDataNode] = ArrayTree()
node = LazyDataNode(
loader=lambda: load_stress_data(path, offset),
attributes={'units': 'MPa', 'name': 'stress'},
)
nid = tree.add_node(0, node)
# Attributes always available
tree.get_node(nid).attributes # {'units': 'MPa', 'name': 'stress'}
# Array loaded on demand
tree.get_node(nid).is_loaded # False
tree.get_node(nid).load() # calls loader, caches result
tree.get_node(nid).is_loaded # True
tree.get_node(nid).release() # frees array, can reload later
| Method/Property | Description |
|---|---|
load() |
Load array via callback (idempotent) |
release() |
Free array data, attributes stay resident |
is_loaded |
True if array is in memory |
Configuration
The ID dtype and sentinel value are configurable per tree:
import numpy as np
from vcti.arraytree import ArrayTree
tree = ArrayTree(id_dtype=np.uint64) # 64-bit node IDs
tree.id_dtype # dtype('uint64')
tree.invalid_id # 18446744073709551615
tree.tree_dtype # structured dtype for topology
The make_tree_dtype(id_dtype) helper builds the structured dtype for
external consumers (e.g., file loaders building topology arrays).
Exceptions
| Exception | Raised when |
|---|---|
KeyError |
Node ID doesn't exist |
ValueError |
Node is deleted, or invalid operation (e.g., delete root) |
RuntimeError |
Tree structure is frozen, or payloads are frozen |
Dependencies
- numpy (>=1.24)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vcti_array_tree-1.4.0.tar.gz.
File metadata
- Download URL: vcti_array_tree-1.4.0.tar.gz
- Upload date:
- Size: 22.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0e0e91de0b10dc0b25f57331a2719a717d7661c246bc72aa770b2753f445e1d7
|
|
| MD5 |
b2950cf3f019be9d1bbc25aca4315dda
|
|
| BLAKE2b-256 |
28b7b079437841e07551eab623fdc8937097eb381d790bf2fe59397397ee14de
|
Provenance
The following attestation bundles were made for vcti_array_tree-1.4.0.tar.gz:
Publisher:
publish.yml on vcollab/vcti-python-array-tree
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
vcti_array_tree-1.4.0.tar.gz -
Subject digest:
0e0e91de0b10dc0b25f57331a2719a717d7661c246bc72aa770b2753f445e1d7 - Sigstore transparency entry: 1244346160
- Sigstore integration time:
-
Permalink:
vcollab/vcti-python-array-tree@1fcc1cf00baef0c98c1bf9449560a98da4c8b711 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/vcollab
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1fcc1cf00baef0c98c1bf9449560a98da4c8b711 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file vcti_array_tree-1.4.0-py3-none-any.whl.
File metadata
- Download URL: vcti_array_tree-1.4.0-py3-none-any.whl
- Upload date:
- Size: 14.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e133e4d0a8cf6a2d014e65e866b3664d8862d63231c9fa65ba8a3f658f25f3be
|
|
| MD5 |
8803777b8409faa6be2def46b86b2780
|
|
| BLAKE2b-256 |
c4a662a636c725798b36bdd7712da471eb51cf4202c2c03679183cb998801423
|
Provenance
The following attestation bundles were made for vcti_array_tree-1.4.0-py3-none-any.whl:
Publisher:
publish.yml on vcollab/vcti-python-array-tree
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
vcti_array_tree-1.4.0-py3-none-any.whl -
Subject digest:
e133e4d0a8cf6a2d014e65e866b3664d8862d63231c9fa65ba8a3f658f25f3be - Sigstore transparency entry: 1244346178
- Sigstore integration time:
-
Permalink:
vcollab/vcti-python-array-tree@1fcc1cf00baef0c98c1bf9449560a98da4c8b711 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/vcollab
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1fcc1cf00baef0c98c1bf9449560a98da4c8b711 -
Trigger Event:
workflow_dispatch
-
Statement type: