ArticulateArena
A quotient metric on articulated kinematics via Lie-algebra endpoint twists.
articulatearena is the reference implementation of the metric E from the
paper ArticulateArena: A Metric for Articulated Kinematics. It gives a single
principled distance between a predicted articulated object and its ground
truth, in place of the hand-combined type / axis / origin / limit scores used by
earlier evaluation protocols.
A one-degree-of-freedom joint J = (ξ, [l⁻, l⁺]) with unit screw twist ξ ∈ se(3) and limits l⁻, l⁺ is represented by its unordered pair of endpoint twists {l⁻ξ, l⁺ξ}. The joint metric is the quotient distance of se(3) × se(3) under the swap of the two endpoints:
E(J1, J2) = min{ ‖z1⁻ − z2⁻‖² + ‖z1⁺ − z2⁺‖², ‖z1⁻ − z2⁺‖² + ‖z1⁺ − z2⁻‖² }^(1/2)
where ‖·‖ is an se(3) norm that the caller injects. Because it is a quotient of a flat space by a finite group of isometries, E is a genuine metric (symmetric, with the triangle inequality), it is invariant to the sign of the axis and to which limit is called "lower", and it is zero exactly when the two joints produce the same motion.
The package provides:
- the joint metric
Eand a smooth, swap-invariant training surrogate; - three injected se(3) norms: the dimensionless split norm (E_α), the kinetic-energy norm of the moving link (E_B, in meters), and a general Riemannian norm;
- the radial compactification ϕ that extends E continuously to unbounded (continuous) joints (E_ϕ);
- two object-level lifts: an optimal-assignment skeleton distance with a topology penalty, and a motion-aware tree edit distance (E_tree) with a certified assignment relaxation;
- loaders for YAML configs and URDF files (axes resolved to the world frame by forward kinematics), a JSON / Markdown report writer, and a command-line tool;
- the component scores of the earlier evaluation template, kept for baseline comparisons.
Links: project page · documentation · paper · source
Installation
pip install articulatearena
Python 3.10 or newer. The core depends only on numpy, scipy and pyyaml.
Two optional extras exist:
pip install "articulatearena[mesh]" # trimesh, for mesh-derived link inertia (kinetic-energy norm)
pip install "articulatearena[dev]" # pytest, build, twine
From a source checkout:
git clone https://github.com/YumengHe/ArticulateMetrics.git
cd ArticulateMetrics
pip install -e ".[dev]"
pytest
Quickstart
Build the endpoint pairs of two joints, pick an se(3) norm, and evaluate
joint_metric. The distance is 0 exactly when the two joints induce the same
motion.
import numpy as np
from articulatearena import joint_metric, make_endpoint_pair, make_split_norm
xi = np.array([0.0, 0.0, 1.0, 0.0, 0.0, 0.0]) # unit screw twist (omega; nu)
gt = make_endpoint_pair(xi, 0.0, 1.0) # joint limits [a, b]
pred = make_endpoint_pair(xi, 0.0, 1.2)
norm = make_split_norm(alpha=1.0) # the norm is injected, never hardcoded
E = joint_metric(gt.u.data, gt.v.data, pred.u.data, pred.v.data, norm)
print(E) # 0.2 (only the upper endpoint moved by 0.2 along the axis)
Reversing the axis and negating the limits describes the same motion, and E sees that without any special casing:
flipped = make_endpoint_pair(-xi, -1.0, 0.0)
print(joint_metric(gt.u.data, gt.v.data, flipped.u.data, flipped.v.data, norm)) # 0.0
To score real URDF joints, load them through the reader layer instead of constructing twists by hand. The loader resolves each joint's axis into the world frame with forward kinematics at the zero configuration:
from articulatearena import load_joint, joint_to_endpoint_pair
joint = load_joint("sample_data/45168/mobility.urdf", "joint_0")
pair = joint_to_endpoint_pair(joint) # unordered {a*xi, b*xi}
Continuous (unbounded) joints have no finite endpoint pair. Compare them, or mix them with bounded joints, through the compactified metric E_ϕ:
import math
from articulatearena import compactified_joint_metric, continuous_joint_repr, radial_compactify
kappa = math.pi # benchmark setting
# two bounded joints: E after mapping all four endpoints into the unit ball
E_phi = compactified_joint_metric(gt.u.data, gt.v.data, pred.u.data, pred.v.data, norm, kappa)
# a bounded joint against a continuous joint about the same axis
gt_ball = [radial_compactify(z, kappa, norm) for z in (gt.u.data, gt.v.data)]
u2, v2 = continuous_joint_repr(xi, norm) # antipodal boundary pair, already in the closed ball
E_phi = joint_metric(*gt_ball, u2, v2, norm)
Whole kinematic trees are compared with the assignment relaxation of the tree
edit distance, assignment_tree_distance, or the exact exact_tree_distance
when a certificate is wanted. See the
documentation for the
full API and a tutorial on the underlying concepts.
Command line
The articulatearena command loads a config, runs the pure metric functions
and writes a JSON report:
articulatearena # built-in demo joints, report under ./out
articulatearena configs/default.yaml # the URDF case named in the config (run from the repo root)
articulatearena my_config.yaml --data joints.json --output out
--data points at a JSON file with top-level prediction and ground_truth
lists, each joint being {"xi_hat": [6 numbers], "a": lower, "b": upper}.
The config groups the knobs that the paper treats as caller-supplied
(inner_product.form and split_norm_alpha, compactification.kappa,
skeleton.lambda_topology, the aggregation form and its smoothing ε) plus an
optional evaluation case (prediction / ground_truth, each a URDF path and a
joint name). The packaged default lives at
src/articulatearena/configs/default.yaml.
Anything left null has to be provided before use. split_norm_alpha is a
characteristic inverse length. Set it to match your length units before
comparing across methods.
In a source checkout the same entry point runs without installing:
python scripts/run.py configs/default.yaml
Package layout
articulatearena/
types.py, config.py, validation.py # typed data models, flat Config, input checks
new_equation/ # the paper's formulas
representation.py # screw twist, endpoint pair {a*xi, b*xi}, revolute wrap
E.py # joint_metric E and the smooth training_loss
inner_product.py # split / kinetic-energy / Riemannian norms
continuous.py # radial compactification, continuous joints, E_phi
tree.py # motion-aware tree edit distance and its relaxation
skeleton.py # assignment skeleton distance with topology penalty
material_motion.py # finite-displacement material discrepancy (calibration)
general_equation/ # background math: se(3) exp map, Hungarian assignment,
# Zhang-Shasha tree edit, L2 configuration difference
previous_metrics/ # baseline component scores of the earlier template
read/ # config, URDF, evaluation-case and mesh-inertia loaders
write/ # JSON / Markdown report generation
cli.py # the `articulatearena` command
configs/default.yaml # packaged default configuration
All metric functions are pure: norms, weights and tolerances are passed in by the caller and never hardcoded, and nothing in the metric layer reads or writes files.
Scope and conventions
- One-DOF joints only: revolute, prismatic, continuous and helical. Multi-DOF joints are out of scope.
- Twists are
(6,)float64 arrays with the angular part first. Revolute and helical joints use a unit angular part, prismatic joints a unit linear part. - Coordinate frames and units are the caller's responsibility. All inputs
must share one reference frame, and
alphamust match the length unit. Eis not normalized. Only compare values produced under the same norm and the samealphaor inertia.
Repository contents beyond the package
The GitHub repository also holds material that is not part of the wheel:
examples/: end-to-end runs on real PartNet-Mobility objects.scripts/: the benchmark driver for the baseline component scores and a generator of controlled error cases.render/: URDF and joint-motion renderers used for the figures (see its README).ablation/: the parameter ablations of the paper.docs/IMPLEMENTATION.md: formula coverage and test strategy, anddocs/RELEASING.mdfor the release procedure.
Tests
pytest
Every formula has a dedicated test class with hand-computed values, metric
properties (identity, symmetry, triangle inequality, swap invariance) and edge
cases. examples/run_real_cases.py adds real-data invariants: zero
self-distance, zero assignment cost against an identical copy, and monotone
growth of E under axis perturbation.
Citation
@article{he2026articulatearena,
title = {ArticulateArena: A Metric for Articulated Kinematics},
author = {He, Yumeng and She, Yongfei and Chen, Huanyu and Yuan, Chun and Li, Peihao
and Masterjohn, Joseph and Yang, Yin and Jiang, Ying and Jiang, Chenfanfu},
journal = {arXiv preprint arXiv:2609.33931},
year = {2026}
}
License
MIT. See LICENSE.
Metadata
Release files for articulatearena 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| articulatearena-0.1.0.tar.gz | 73.3 kB | Without provenance | Details for articulatearena-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| articulatearena-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for articulatearena-0.1.0-py3-none-any.whl |
Total release size: 128.6 kB
Release files / articulatearena-0.1.0.tar.gz
| Download URL | articulatearena-0.1.0.tar.gz |
|---|---|
| Size | 73.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5f15d9b1192f3615109adaf931f70bb0655504b5ef11edf803e4a0f50e2bb4ba
|
|
BLAKE2b-256 checksum How to use checksums |
f9d69d9c477d0bd211db526435c1c265d3a90dcd1725e47e9e80eadd204feb78
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.20
|
Release files / articulatearena-0.1.0-py3-none-any.whl
| Download URL | articulatearena-0.1.0-py3-none-any.whl |
|---|---|
| Size | 55.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c66319522683a1fea8674dbebc7b9ab0d46420f2582eadfb54b61b02275169c9
|
|
BLAKE2b-256 checksum How to use checksums |
e121464dbaf559f1d10ece0a6a474c22bc4b699b610558b939fd3f7cb480a14d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.20
|
Security for articulatearena 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.