Skip to main content

ArticulateArena

PyPI Python License: MIT arXiv

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 E and 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 alpha must match the length unit.
  • E is not normalized. Only compare values produced under the same norm and the same alpha or 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, and docs/RELEASING.md for 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)

Source distribution for articulatearena 0.1.0
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)

Table of built distributions (wheels) for articulatearena 0.1.0
File Interpreter ABI Platform Actions
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.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page