Skip to content

fix(topology): count rigid bodies in compute_mobility, expand hyperedges as cliques - #55

Merged
HugoFara merged 1 commit into
mainfrom
fix/hyperedge-mobility
Sep 12, 2026
Merged

HugoFara merged 1 commit into
mainfrom
fix/hyperedge-mobility

Conversation

@HugoFara

Copy link
Copy Markdown
Owner

Resolves the hyperedge convention mismatch the 1.2.0 graph tutorial documented instead of fixing.

What was wrong

compute_mobility / compute_dof counted 1 + len(edges) + len(hyperedges) links and len(nodes) joints. That is only true of the topology catalog's hyperedge-only graphs. For any geometric graph — a coupler point, a Hyperedge labelling a triangle of edges, Linkage.to_hypergraph() output for a FixedDyad, every classical walker leggedsnake ships (Walker.dof wraps this) — the answer was nonsense:

graph before after
tutorial coupler four-bar (hyperedge + 3 inner edges) 8 1
same, hyperedge only −1 1
to_hypergraph() of a four-bar + FixedDyad 8 1
leggedsnake Jansen / Chebyshev / Klann / TrotBot / Strider 17 / 5 / 11 / 34 / 41 1 each
19 catalog entries 1 1 (links unchanged too)

Separately, to_simple_graph() expanded a hyperedge to a chain of N−1 edges while topology.isomorphism and assur.from_hypergraph expand to a clique — so to_mechanism() raised "could not determine solve order" for a ternary link written as a hyperedge alone, unless the caller repeated its edges by hand (which the tutorial told them to do).

The fix

  • Links are rigid bodies: the ground (all GROUND nodes), one body per edge and per hyperedge, merged whenever two share ≥ 2 nodes (two links pinned at two points are one link). A node in k bodies is k − 1 one-DOF joints: coupler points are not joints, multiple joints count. A PRISMATIC node is a slider block with a prismatic joint to its guide hyperedge. Three edges closing a triangle without a hyperedge still count as three bars — the DOF is identical, only num_links differs — documented.
  • to_simple_graph() expands to the clique, keeping (not duplicating) pairs already joined by an edge. Hyperedge.to_edges() is public and keeps its documented chain.
  • Two old tests pinned the wrong values and their own docstrings said so: a lone crank now reports DOF 1 (was −1), a triangle with one side on the ground DOF 0 (was 3). New tests cover the coupler variants, a multiple joint, a slider, the FixedDyad round trip, catalog invariance, and to_mechanism on a hyperedge-only ternary link in every node order.
  • Tutorial: counting rules described, the "analyze without the coupler point" caveat replaced by the coupler four-bar's actual mobility.

2608 passed, ruff and mypy clean, the graph tutorial page executes. leggedsnake against this branch: 627 pass, 1 fails — test_triangle_dof_is_three, which pinned the old wrong value (a triangle pinned at one ground node is 1 DOF); to be updated there after release.

Found on the way, not fixed here: RRPDyad → to_hypergraph() → to_mechanism() builds the slider as an RRR dyad — from_sim_linkage only tags LinearActuator nodes PRISMATIC and to_mechanism never sets a slide axis — so a slider-crank round trip raises UnbuildableError a few steps in. Issue to follow.

…ges as cliques

compute_mobility counted every edge and hyperedge as a link and every
node as a joint, which only holds for the catalog's hyperedge-only graphs;
a coupler four-bar reported 8 DOF, a Jansen leg 17. Links are now rigid
bodies (ground, edges, hyperedges, merged when they share two nodes),
joints are counted per node as bodies - 1, and a PRISMATIC node is a
slider block with a prismatic joint to its guide. Catalog counts are
unchanged.

to_simple_graph expanded a hyperedge to a chain of N - 1 edges, so
to_mechanism could not solve a ternary link written as a hyperedge alone;
it now expands to the clique, as isomorphism and assur already did.
@HugoFara
HugoFara merged commit b18664b into main Sep 12, 2026
10 checks passed
@HugoFara
HugoFara deleted the fix/hyperedge-mobility branch September 12, 2026 15:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant