Skip to main content

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

  • GenericArrayTree[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 loadingLazyDataNode loads 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.2.0

In pyproject.toml dependencies

dependencies = [
    "vcti-array-tree>=1.2.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() Make tree immutable
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

Constants

Name Description
TREE_DTYPE NumPy structured dtype for the tree topology array
INVALID_ID Sentinel value (uint32.max) for null node references

Exceptions

Exception Raised when
KeyError Node ID doesn't exist
ValueError Node is deleted, or invalid operation (e.g., delete root)
RuntimeError Tree is frozen and a mutation is attempted

Dependencies

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vcti_array_tree-1.2.0.tar.gz (21.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vcti_array_tree-1.2.0-py3-none-any.whl (13.5 kB view details)

Uploaded Python 3

File details

Details for the file vcti_array_tree-1.2.0.tar.gz.

File metadata

  • Download URL: vcti_array_tree-1.2.0.tar.gz
  • Upload date:
  • Size: 21.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for vcti_array_tree-1.2.0.tar.gz
Algorithm Hash digest
SHA256 4e37c87ea117ecdba4b828648d1db56cd22f98edee3363df81acbcdc26bcd6ed
MD5 f2fa9bb0f178387602f0bb3610e2632f
BLAKE2b-256 95722184d4e91a6c1a7ac9e09f5d435d85307598bc60efc520e67f6965919dcb

See more details on using hashes here.

Provenance

The following attestation bundles were made for vcti_array_tree-1.2.0.tar.gz:

Publisher: publish.yml on vcollab/vcti-python-array-tree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file vcti_array_tree-1.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for vcti_array_tree-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7d6f890b22d59cb3ff0a238ec846c048863b6d1df17e132e373515006076a3e8
MD5 2870d17280f308d0513d9f246d8af017
BLAKE2b-256 9e8a2949362ddca371971a84b9ca1fe655fb4b1c9e795fa1ea9accec0e314208

See more details on using hashes here.

Provenance

The following attestation bundles were made for vcti_array_tree-1.2.0-py3-none-any.whl:

Publisher: publish.yml on vcollab/vcti-python-array-tree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page