pylinkage.hypergraph package
Submodules
pylinkage.hypergraph.core module
Core graph elements for the hypergraph representation.
This module provides the fundamental data structures for representing planar linkages as hypergraphs: Node, Edge, and Hyperedge.
These are pure topological elements - they define structure and connectivity only. Dimensional data (positions, distances, angles) is stored separately in the Dimensions class (see pylinkage.dimensions).
- class pylinkage.hypergraph.core.Edge(id: str, source: str, target: str)
Bases:
objectA binary connection between two nodes (topology only).
Edges represent rigid links connecting exactly two joints. For N-way rigid bodies (N > 2), use Hyperedge instead.
Distance constraints are stored separately in a Dimensions object.
- Variables:
id (str) – Unique identifier for this edge.
source (str) – ID of the source node.
target (str) – ID of the target node.
Example
>>> edge = Edge("AB", source="A", target="B")
- connects(node_id: str) bool
Check if this edge connects to the given node.
- id: str
- other_node(node_id: str) str
Get the node on the other end of this edge.
- Parameters:
node_id – One endpoint of this edge.
- Returns:
The ID of the other endpoint.
- Raises:
ValueError – If node_id is not an endpoint of this edge.
- source: str
- target: str
- class pylinkage.hypergraph.core.Hyperedge(id: str, nodes: tuple[str, ...]=<factory>, name: str | None = None)
Bases:
objectAn N-way rigid body connection (topology only).
A hyperedge connects N nodes (joints) that belong to the same rigid link. This is a topological grouping - distance constraints are stored separately in a Dimensions object.
This is more expressive than multiple edges with a shared body_id because it explicitly groups all related nodes together.
- Variables:
id (str) – Unique identifier for this hyperedge.
nodes (tuple[str, ...]) – Tuple of node IDs connected by this rigid body.
name (str | None) – Human-readable name for the rigid body.
Example
>>> # Triangle rigid body connecting A, B, C >>> he = Hyperedge( ... id="triangle", ... nodes=("A", "B", "C"), ... name="Triangle Link" ... )
- classmethod from_edges(edges: list[Edge], hyperedge_id: str, name: str | None = None) Hyperedge
Create a hyperedge from a collection of edges.
Assumes all edges belong to the same rigid body.
- Parameters:
edges – List of edges to combine.
hyperedge_id – ID for the new hyperedge.
name – Optional name for the hyperedge.
- Returns:
A new Hyperedge combining all the edges.
- Raises:
ValueError – If edges list is empty.
Example
>>> edges = [ ... Edge("e1", "A", "B"), ... Edge("e2", "B", "C"), ... ] >>> he = Hyperedge.from_edges(edges, "combined") >>> "A" in he.nodes True
- id: str
- name: str | None = None
- nodes: tuple[str, ...]
- to_edges(prefix: str = '') list[Edge]
Convert hyperedge to regular binary edges.
Creates one Edge for each pair of adjacent nodes in this hyperedge. For a hyperedge with N nodes, creates N-1 edges forming a chain.
- Parameters:
prefix – Optional prefix for generated edge IDs.
- Returns:
List of Edge objects representing pairwise connections.
Example
>>> he = Hyperedge("tri", ("A", "B", "C")) >>> edges = he.to_edges() >>> len(edges) 2
- class pylinkage.hypergraph.core.Node(id: str, role: NodeRole = NodeRole.DRIVEN, joint_type: JointType = JointType.REVOLUTE, name: str | None = None)
Bases:
objectA joint in the linkage hypergraph (topology only).
Represents the topological aspect of a joint - its identity, role, and type. Geometric data (position, angles) is stored separately in a Dimensions object.
- Variables:
id (str) – Unique identifier for this node.
role (pylinkage._types.NodeRole) – The role in the mechanism (GROUND, DRIVER, or DRIVEN).
joint_type (pylinkage._types.JointType) – The kinematic joint type (REVOLUTE or PRISMATIC).
name (str | None) – Human-readable name for display.
Example
>>> node = Node("A", role=NodeRole.GROUND) >>> node.joint_type <JointType.REVOLUTE: 1>
- id: str
- name: str | None = None
- role: NodeRole = 2
pylinkage.hypergraph.graph module
Hypergraph-based representation of planar linkages (topology only).
This module provides the HypergraphLinkage class, which represents linkages as hypergraphs where nodes are joints and connections can be either binary edges or N-way hyperedges (rigid bodies).
This is a pure topological representation - dimensional data (positions, distances, angles) is stored separately in a Dimensions object.
- class pylinkage.hypergraph.graph.HypergraphLinkage(nodes: dict[str, ~pylinkage.hypergraph.core.Node]=<factory>, edges: dict[str, ~pylinkage.hypergraph.core.Edge]=<factory>, hyperedges: dict[str, ~pylinkage.hypergraph.core.Hyperedge]=<factory>, name: str = '', _adjacency: dict[str, list[str]]=<factory>, _hyperedge_membership: dict[str, list[str]]=<factory>)
Bases:
objectPure topological hypergraph representation of a planar linkage.
A linkage is represented as a hypergraph where: - Nodes are joints (revolute R or prismatic P) with roles - Edges are binary link connections - Hyperedges are N-way rigid body groupings
This is a topology-only representation. Dimensional data (positions, distances, angles) is stored separately in a Dimensions object.
This representation enables: - First-class rigid body representation via hyperedges - Hierarchical composition - Conversion to other representations (Assur, Mechanism) - Pure structural analysis without geometric constraints
- Variables:
nodes (dict[str, pylinkage.hypergraph.core.Node]) – Dictionary mapping node IDs to Node objects.
edges (dict[str, pylinkage.hypergraph.core.Edge]) – Dictionary mapping edge IDs to Edge objects.
hyperedges (dict[str, pylinkage.hypergraph.core.Hyperedge]) – Dictionary mapping hyperedge IDs to Hyperedge objects.
name (str) – Human-readable name for the linkage.
Example
>>> graph = HypergraphLinkage(name="Four-bar") >>> graph.add_node(Node("A", role=NodeRole.GROUND)) >>> graph.add_node(Node("B", role=NodeRole.DRIVER)) >>> graph.add_edge(Edge("AB", source="A", target="B"))
- add_edge(edge: Edge) None
Add an edge to the graph.
- Parameters:
edge – The Edge to add.
- Raises:
ValueError – If an edge with the same ID already exists, or if source/target nodes don’t exist.
- add_hyperedge(hyperedge: Hyperedge) None
Add a hyperedge to the graph.
- Parameters:
hyperedge – The Hyperedge to add.
- Raises:
ValueError – If a hyperedge with the same ID already exists, or if any referenced nodes don’t exist.
- add_node(node: Node) None
Add a node to the graph.
- Parameters:
node – The Node to add.
- Raises:
ValueError – If a node with the same ID already exists.
- all_neighbors(node_id: str) list[str]
Get all nodes connected to the given node via edges or hyperedges.
- Parameters:
node_id – The node to find neighbors of.
- Returns:
List of all connected node IDs (deduplicated).
- copy() HypergraphLinkage
Create a deep copy of the graph.
- Returns:
A new HypergraphLinkage with copied nodes, edges, and hyperedges.
- degree(node_id: str) int
Get the edge degree (number of edge connections) of a node.
- Parameters:
node_id – The node ID.
- Returns:
Number of edges connected to the node.
- get_edge_between(node1: str, node2: str) Edge | None
Get the edge connecting two nodes, if any.
- Parameters:
node1 – First node ID.
node2 – Second node ID.
- Returns:
The Edge connecting the nodes, or None if not connected.
- get_edges_for_node(node_id: str) list[Edge]
Get all edges connected to a node.
- Parameters:
node_id – The node ID.
- Returns:
List of Edge objects connected to the node.
- get_hyperedges_for_node(node_id: str) list[Hyperedge]
Get all hyperedges containing a node.
- Parameters:
node_id – The node ID.
- Returns:
List of Hyperedge objects containing the node.
- hyperdegree(node_id: str) int
Get the hyperedge degree (number of hyperedge memberships) of a node.
- Parameters:
node_id – The node ID.
- Returns:
Number of hyperedges containing the node.
- hyperedge_neighbors(node_id: str) list[str]
Get all nodes sharing a hyperedge with the given node.
- Parameters:
node_id – The node to find hyperedge neighbors of.
- Returns:
List of node IDs sharing hyperedges with the given node.
- name: str = ''
- neighbors(node_id: str) list[str]
Get all nodes connected to the given node via edges.
- Parameters:
node_id – The node to find neighbors of.
- Returns:
List of node IDs connected via edges.
- remove_edge(edge_id: str) Edge
Remove an edge from the graph.
- Parameters:
edge_id – ID of the edge to remove.
- Returns:
The removed Edge.
- Raises:
KeyError – If edge not found.
- remove_hyperedge(hyperedge_id: str) Hyperedge
Remove a hyperedge from the graph.
- Parameters:
hyperedge_id – ID of the hyperedge to remove.
- Returns:
The removed Hyperedge.
- Raises:
KeyError – If hyperedge not found.
- remove_node(node_id: str) Node
Remove a node and all its connections from the graph.
- Parameters:
node_id – ID of the node to remove.
- Returns:
The removed Node.
- Raises:
KeyError – If node not found.
- to_simple_graph() HypergraphLinkage
Convert to a simple graph by expanding hyperedges to edges.
Creates a new HypergraphLinkage with no hyperedges. Every hyperedge becomes the clique of its nodes — one edge per pair — since a rigid body holds each pair of its joints at a fixed distance. Pairs already joined by an edge are left as they are.
- Returns:
A new HypergraphLinkage with only nodes and edges.
pylinkage.hypergraph.hierarchy module
Hierarchical linkage composition (topology only).
This module provides classes for assembling linkages from component instances and flattening them to a single HypergraphLinkage for analysis or simulation.
- class pylinkage.hypergraph.hierarchy.ComponentInstance(id: str, topology: HypergraphLinkage, ports: dict[str, str]=<factory>, name: str = '')
Bases:
objectAn instance of a topology with connection ports.
Represents a concrete instantiation of a HypergraphLinkage with defined ports for connecting to other instances.
- Variables:
id (str) – Unique identifier for this instance within the hierarchy.
topology (pylinkage.hypergraph.graph.HypergraphLinkage) – The HypergraphLinkage defining this component’s structure.
ports (dict[str, str]) – Mapping from port IDs to internal node IDs.
name (str) – Human-readable name for this instance.
Example
>>> topology = HypergraphLinkage(name="leg") >>> # ... add nodes and edges ... >>> instance = ComponentInstance( ... id="left_leg", ... topology=topology, ... ports={"input": "A", "output": "B"}, ... name="Left Leg" ... )
- get_port_qualified_node(port_id: str) str
Get the qualified node ID for a port.
- Parameters:
port_id – The port ID.
- Returns:
The globally qualified node ID for the port’s internal node.
- Raises:
KeyError – If port not found.
- get_qualified_node_id(internal_node: str) str
Get the globally qualified node ID for an internal node.
- Parameters:
internal_node – The internal node ID within the component.
- Returns:
A globally unique node ID like “instance_id.internal_node”.
- id: str
- name: str = ''
- ports: dict[str, str]
- topology: HypergraphLinkage
- class pylinkage.hypergraph.hierarchy.Connection(from_instance: str, from_port: str, to_instance: str, to_port: str)
Bases:
objectConnection between two component ports.
Defines how two component instances are connected via their ports. During flattening, connected ports are merged into a single node.
- Variables:
from_instance (str) – Instance ID of the source component.
from_port (str) – Port ID on the source component.
to_instance (str) – Instance ID of the target component.
to_port (str) – Port ID on the target component.
Example
>>> conn = Connection( ... from_instance="leg1", ... from_port="output", ... to_instance="leg2", ... to_port="input" ... )
- from_instance: str
- from_port: str
- to_instance: str
- to_port: str
- class pylinkage.hypergraph.hierarchy.HierarchicalLinkage(instances: dict[str, ~pylinkage.hypergraph.hierarchy.ComponentInstance]=<factory>, connections: list[Connection] = <factory>, name: str = '')
Bases:
objectTop-level container for hierarchical linkage definition.
A hierarchical linkage contains component instances and defines connections between them. It can be flattened to a HypergraphLinkage for simulation or further processing.
- Variables:
instances (dict[str, pylinkage.hypergraph.hierarchy.ComponentInstance]) – Dictionary of component instances by ID.
connections (list[pylinkage.hypergraph.hierarchy.Connection]) – List of connections between component ports.
name (str) – Human-readable name for the linkage.
Example
>>> # Create instances >>> leg1 = ComponentInstance("leg1", leg_topology, {"input": "A", "output": "B"}) >>> leg2 = ComponentInstance("leg2", leg_topology, {"input": "A", "output": "B"}) >>> >>> # Create hierarchical linkage >>> linkage = HierarchicalLinkage( ... instances={"leg1": leg1, "leg2": leg2}, ... connections=[ ... Connection("leg1", "output", "leg2", "input"), ... ], ... name="Two-Leg Walker" ... ) >>> >>> # Flatten for simulation >>> flat_graph = linkage.flatten()
- add_connection(connection: Connection) None
Add a connection between ports.
- Parameters:
connection – The Connection to add.
- Raises:
ValueError – If the connection references invalid instances or ports.
- add_instance(instance: ComponentInstance) None
Add a component instance.
- Parameters:
instance – The ComponentInstance to add.
- Raises:
ValueError – If an instance with the same ID already exists.
- connections: list[Connection]
- flatten() HypergraphLinkage
Flatten the hierarchy to a single HypergraphLinkage.
This is the key method that converts the hierarchical representation to a flat hypergraph that can be converted to other representations or used for analysis.
The flattening process: 1. Creates qualified nodes from all component instances 2. Creates qualified edges from all component instances 3. Creates qualified hyperedges from all component instances 4. Merges connected ports into single nodes
- Returns:
A HypergraphLinkage with all components expanded and connected.
- get_all_port_nodes() dict[str, str]
Get all exposed port nodes with their qualified IDs.
- Returns:
Dictionary mapping “instance_id.port_id” to qualified node ID.
- instances: dict[str, ComponentInstance]
- name: str = ''
pylinkage.hypergraph.mechanism_conversion module
Direct conversion between HypergraphLinkage and Mechanism.
This module provides direct conversion between the hypergraph representation and the mechanism model, bypassing the legacy Linkage class.
This is the preferred conversion path for new code: - HypergraphLinkage is the pure topological representation - Dimensions holds the geometric data (positions, distances, angles) - Mechanism is the concrete simulation model with Links + Joints
For backward compatibility with legacy Linkage, use conversion.py instead.
- pylinkage.hypergraph.mechanism_conversion.from_mechanism(mechanism: Mechanism) tuple[HypergraphLinkage, Dimensions]
Convert a Mechanism to a HypergraphLinkage and Dimensions.
This converts an existing Mechanism to the hypergraph representation for analysis, visualization, or manipulation.
- Parameters:
mechanism – The Mechanism to convert.
- Returns:
A tuple of (HypergraphLinkage, Dimensions).
Example
>>> mechanism = Mechanism(joints=[...], links=[...]) >>> hg, dims = from_mechanism(mechanism) >>> # Analyze or modify the hypergraph
- pylinkage.hypergraph.mechanism_conversion.to_mechanism(hypergraph: HypergraphLinkage, dimensions: Dimensions) Mechanism
Convert a HypergraphLinkage and Dimensions to a Mechanism.
This converts the hypergraph topology plus dimensional data to the mechanism model. This is the preferred conversion path for new code.
- Parameters:
hypergraph – The HypergraphLinkage defining the topology.
dimensions – The Dimensions providing positions, distances, angles.
- Returns:
A Mechanism instance ready for simulation.
- Raises:
ValueError – If the hypergraph is underconstrained or has disconnected components that cannot be solved.
Example
>>> hg = HypergraphLinkage(name="Four-bar") >>> hg.add_node(Node("A", role=NodeRole.GROUND)) >>> hg.add_edge(Edge("AB", "A", "B")) >>> dims = Dimensions( ... node_positions={"A": (0, 0), "B": (1, 0)}, ... edge_distances={"AB": 1.0}, ... ) >>> mechanism = to_mechanism(hg, dims)
pylinkage.hypergraph.serialization module
Serialization for hypergraph structures (topology only).
This module provides functions to convert hypergraph objects to and from dictionaries and JSON files. This enables persistence and interoperability.
Note: This module only handles topological data. For dimensional data, use the serialization functions in pylinkage.dimensions.
- pylinkage.hypergraph.serialization.component_instance_from_dict(data: dict[str, Any]) ComponentInstance
Create a ComponentInstance from a dictionary.
- Parameters:
data – Dictionary representation.
- Returns:
A ComponentInstance.
- pylinkage.hypergraph.serialization.component_instance_to_dict(instance: ComponentInstance) dict[str, Any]
Convert a ComponentInstance to a dictionary.
- Parameters:
instance – The ComponentInstance to convert.
- Returns:
Dictionary representation.
- pylinkage.hypergraph.serialization.connection_from_dict(data: dict[str, Any]) Connection
Create a Connection from a dictionary.
- pylinkage.hypergraph.serialization.connection_to_dict(connection: Connection) dict[str, Any]
Convert a Connection to a dictionary.
- pylinkage.hypergraph.serialization.edge_from_dict(data: dict[str, Any]) Edge
Create an Edge from a dictionary.
- Parameters:
data – Dictionary representation.
- Returns:
An Edge instance.
- pylinkage.hypergraph.serialization.edge_to_dict(edge: Edge) dict[str, Any]
Convert an Edge to a dictionary (topology only).
- Parameters:
edge – The Edge to convert.
- Returns:
Dictionary representation of the edge.
- pylinkage.hypergraph.serialization.graph_from_dict(data: dict[str, Any]) HypergraphLinkage
Create a HypergraphLinkage from a dictionary.
- Parameters:
data – Dictionary representation.
- Returns:
A HypergraphLinkage instance.
- pylinkage.hypergraph.serialization.graph_from_json(path: str | Path) HypergraphLinkage
Load a HypergraphLinkage from a JSON file.
- Parameters:
path – Path to the input file.
- Returns:
A HypergraphLinkage instance.
- pylinkage.hypergraph.serialization.graph_to_dict(graph: HypergraphLinkage) dict[str, Any]
Convert a HypergraphLinkage to a dictionary.
- Parameters:
graph – The HypergraphLinkage to convert.
- Returns:
Dictionary representation of the graph.
- pylinkage.hypergraph.serialization.graph_to_json(graph: HypergraphLinkage, path: str | Path) None
Save a HypergraphLinkage to a JSON file.
- Parameters:
graph – The HypergraphLinkage to save.
path – Path to the output file.
- pylinkage.hypergraph.serialization.hierarchical_from_dict(data: dict[str, Any]) HierarchicalLinkage
Create a HierarchicalLinkage from a dictionary.
- Parameters:
data – Dictionary representation.
- Returns:
A HierarchicalLinkage instance.
- pylinkage.hypergraph.serialization.hierarchical_from_json(path: str | Path) HierarchicalLinkage
Load a HierarchicalLinkage from a JSON file.
- Parameters:
path – Path to the input file.
- Returns:
A HierarchicalLinkage instance.
- pylinkage.hypergraph.serialization.hierarchical_to_dict(linkage: HierarchicalLinkage) dict[str, Any]
Convert a HierarchicalLinkage to a dictionary.
- Parameters:
linkage – The HierarchicalLinkage to convert.
- Returns:
Dictionary representation.
- pylinkage.hypergraph.serialization.hierarchical_to_json(linkage: HierarchicalLinkage, path: str | Path) None
Save a HierarchicalLinkage to a JSON file.
- Parameters:
linkage – The HierarchicalLinkage to save.
path – Path to the output file.
- pylinkage.hypergraph.serialization.hyperedge_from_dict(data: dict[str, Any]) Hyperedge
Create a Hyperedge from a dictionary.
- Parameters:
data – Dictionary representation.
- Returns:
A Hyperedge instance.
- pylinkage.hypergraph.serialization.hyperedge_to_dict(hyperedge: Hyperedge) dict[str, Any]
Convert a Hyperedge to a dictionary (topology only).
- Parameters:
hyperedge – The Hyperedge to convert.
- Returns:
Dictionary representation of the hyperedge.
pylinkage.hypergraph.sim_conversion module
Conversion between simulation.Linkage and HypergraphLinkage.
simulation.Linkage (a.k.a. “SimLinkage”) is the joint-free
component/actuator/dyad API produced by pylinkage.synthesis and
pylinkage.optimization.co_optimize. This module converts one of
those objects into the topological HypergraphLinkage plus a
companion Dimensions record so downstream tooling
(leggedsnake.Walker, exporters) can consume synthesis output
directly.
Only the component types that the upstream synthesis / catalog co-optimization actually emit are handled:
Ground→NodeRole.GROUNDCrank/ArcCrank→NodeRole.DRIVERwith aDriverAngleLinearActuator→NodeRole.DRIVER(modelled as a prismatic-joint node; the prismatic axis lives on the output node)RRRDyad→ two edges (one per distance constraint)FixedDyad→ a hyperedge over the rigid triangle plus two edges carrying the two leg distances as numeric fallbacksRRPDyad→ one edge for the revolute leg; the prismatic track is encoded as a hyperedge over the three line/anchor nodesPPDyad→ a hyperedge over the four line anchors (no numeric distances — it is fully determined by the four line anchors)
Anything else raises NotImplementedError so callers know to
extend the bridge when pylinkage grows new component types.
- pylinkage.hypergraph.sim_conversion.from_sim_linkage(sim_linkage: SimLinkage) tuple[HypergraphLinkage, Dimensions]
Convert a
pylinkage.simulation.Linkageto a hypergraph.- Parameters:
sim_linkage – A
simulation.Linkagebuilt from the modern component/actuator/dyad API.- Returns:
A tuple
(hypergraph, dimensions)suitable for feeding intopylinkage.hypergraph.to_mechanism()or into any hypergraph-native consumer.- Raises:
TypeError – If
sim_linkagedoes not look like asimulation.Linkage(no.components).NotImplementedError – If a component type is encountered that this bridge does not yet handle.
Module contents
Hypergraph-based representation of planar linkages (topology only).
This module provides a hierarchical hypergraph abstraction for defining and manipulating planar linkages. It serves as an abstract mathematical foundation that can be converted to other representations (Assur graphs, Mechanism) for different purposes.
This is a pure topological representation - dimensional data (positions, distances, angles) is stored separately in a Dimensions object.
Key concepts: - HypergraphLinkage: Abstract graph supporting both edges and hyperedges - ComponentInstance: Instance of a topology with connection ports - HierarchicalLinkage: Composition of component instances
Example usage:
from pylinkage.hypergraph import (
HypergraphLinkage, Node, Edge, NodeRole,
to_mechanism
)
from pylinkage.dimensions import Dimensions, DriverAngle
# Create topology
hg = HypergraphLinkage(name="Four-bar")
hg.add_node(Node("A", role=NodeRole.GROUND))
hg.add_node(Node("B", role=NodeRole.DRIVER))
hg.add_node(Node("C", role=NodeRole.DRIVEN))
hg.add_node(Node("D", role=NodeRole.GROUND))
hg.add_edge(Edge("AB", "A", "B"))
hg.add_edge(Edge("BC", "B", "C"))
hg.add_edge(Edge("CD", "C", "D"))
# Create dimensions
dims = Dimensions(
node_positions={"A": (0, 0), "B": (1, 0), "C": (2, 1), "D": (3, 0)},
driver_angles={"B": DriverAngle(0.1)},
edge_distances={"AB": 1.0, "BC": 2.0, "CD": 2.0},
)
# Convert to mechanism for simulation
mechanism = to_mechanism(hg, dims)
- class pylinkage.hypergraph.ComponentInstance(id: str, topology: HypergraphLinkage, ports: dict[str, str]=<factory>, name: str = '')
Bases:
objectAn instance of a topology with connection ports.
Represents a concrete instantiation of a HypergraphLinkage with defined ports for connecting to other instances.
- Variables:
id (str) – Unique identifier for this instance within the hierarchy.
topology (pylinkage.hypergraph.graph.HypergraphLinkage) – The HypergraphLinkage defining this component’s structure.
ports (dict[str, str]) – Mapping from port IDs to internal node IDs.
name (str) – Human-readable name for this instance.
Example
>>> topology = HypergraphLinkage(name="leg") >>> # ... add nodes and edges ... >>> instance = ComponentInstance( ... id="left_leg", ... topology=topology, ... ports={"input": "A", "output": "B"}, ... name="Left Leg" ... )
- get_port_qualified_node(port_id: str) str
Get the qualified node ID for a port.
- Parameters:
port_id – The port ID.
- Returns:
The globally qualified node ID for the port’s internal node.
- Raises:
KeyError – If port not found.
- get_qualified_node_id(internal_node: str) str
Get the globally qualified node ID for an internal node.
- Parameters:
internal_node – The internal node ID within the component.
- Returns:
A globally unique node ID like “instance_id.internal_node”.
- id: str
- name: str = ''
- ports: dict[str, str]
- topology: HypergraphLinkage
- class pylinkage.hypergraph.Connection(from_instance: str, from_port: str, to_instance: str, to_port: str)
Bases:
objectConnection between two component ports.
Defines how two component instances are connected via their ports. During flattening, connected ports are merged into a single node.
- Variables:
from_instance (str) – Instance ID of the source component.
from_port (str) – Port ID on the source component.
to_instance (str) – Instance ID of the target component.
to_port (str) – Port ID on the target component.
Example
>>> conn = Connection( ... from_instance="leg1", ... from_port="output", ... to_instance="leg2", ... to_port="input" ... )
- from_instance: str
- from_port: str
- to_instance: str
- to_port: str
- class pylinkage.hypergraph.Edge(id: str, source: str, target: str)
Bases:
objectA binary connection between two nodes (topology only).
Edges represent rigid links connecting exactly two joints. For N-way rigid bodies (N > 2), use Hyperedge instead.
Distance constraints are stored separately in a Dimensions object.
- Variables:
id (str) – Unique identifier for this edge.
source (str) – ID of the source node.
target (str) – ID of the target node.
Example
>>> edge = Edge("AB", source="A", target="B")
- connects(node_id: str) bool
Check if this edge connects to the given node.
- id: str
- other_node(node_id: str) str
Get the node on the other end of this edge.
- Parameters:
node_id – One endpoint of this edge.
- Returns:
The ID of the other endpoint.
- Raises:
ValueError – If node_id is not an endpoint of this edge.
- source: str
- target: str
- pylinkage.hypergraph.EdgeId
alias of
str
- class pylinkage.hypergraph.HierarchicalLinkage(instances: dict[str, ~pylinkage.hypergraph.hierarchy.ComponentInstance]=<factory>, connections: list[Connection] = <factory>, name: str = '')
Bases:
objectTop-level container for hierarchical linkage definition.
A hierarchical linkage contains component instances and defines connections between them. It can be flattened to a HypergraphLinkage for simulation or further processing.
- Variables:
instances (dict[str, pylinkage.hypergraph.hierarchy.ComponentInstance]) – Dictionary of component instances by ID.
connections (list[pylinkage.hypergraph.hierarchy.Connection]) – List of connections between component ports.
name (str) – Human-readable name for the linkage.
Example
>>> # Create instances >>> leg1 = ComponentInstance("leg1", leg_topology, {"input": "A", "output": "B"}) >>> leg2 = ComponentInstance("leg2", leg_topology, {"input": "A", "output": "B"}) >>> >>> # Create hierarchical linkage >>> linkage = HierarchicalLinkage( ... instances={"leg1": leg1, "leg2": leg2}, ... connections=[ ... Connection("leg1", "output", "leg2", "input"), ... ], ... name="Two-Leg Walker" ... ) >>> >>> # Flatten for simulation >>> flat_graph = linkage.flatten()
- add_connection(connection: Connection) None
Add a connection between ports.
- Parameters:
connection – The Connection to add.
- Raises:
ValueError – If the connection references invalid instances or ports.
- add_instance(instance: ComponentInstance) None
Add a component instance.
- Parameters:
instance – The ComponentInstance to add.
- Raises:
ValueError – If an instance with the same ID already exists.
- connections: list[Connection]
- flatten() HypergraphLinkage
Flatten the hierarchy to a single HypergraphLinkage.
This is the key method that converts the hierarchical representation to a flat hypergraph that can be converted to other representations or used for analysis.
The flattening process: 1. Creates qualified nodes from all component instances 2. Creates qualified edges from all component instances 3. Creates qualified hyperedges from all component instances 4. Merges connected ports into single nodes
- Returns:
A HypergraphLinkage with all components expanded and connected.
- get_all_port_nodes() dict[str, str]
Get all exposed port nodes with their qualified IDs.
- Returns:
Dictionary mapping “instance_id.port_id” to qualified node ID.
- instances: dict[str, ComponentInstance]
- name: str = ''
- class pylinkage.hypergraph.Hyperedge(id: str, nodes: tuple[str, ...]=<factory>, name: str | None = None)
Bases:
objectAn N-way rigid body connection (topology only).
A hyperedge connects N nodes (joints) that belong to the same rigid link. This is a topological grouping - distance constraints are stored separately in a Dimensions object.
This is more expressive than multiple edges with a shared body_id because it explicitly groups all related nodes together.
- Variables:
id (str) – Unique identifier for this hyperedge.
nodes (tuple[str, ...]) – Tuple of node IDs connected by this rigid body.
name (str | None) – Human-readable name for the rigid body.
Example
>>> # Triangle rigid body connecting A, B, C >>> he = Hyperedge( ... id="triangle", ... nodes=("A", "B", "C"), ... name="Triangle Link" ... )
- classmethod from_edges(edges: list[Edge], hyperedge_id: str, name: str | None = None) Hyperedge
Create a hyperedge from a collection of edges.
Assumes all edges belong to the same rigid body.
- Parameters:
edges – List of edges to combine.
hyperedge_id – ID for the new hyperedge.
name – Optional name for the hyperedge.
- Returns:
A new Hyperedge combining all the edges.
- Raises:
ValueError – If edges list is empty.
Example
>>> edges = [ ... Edge("e1", "A", "B"), ... Edge("e2", "B", "C"), ... ] >>> he = Hyperedge.from_edges(edges, "combined") >>> "A" in he.nodes True
- id: str
- name: str | None = None
- nodes: tuple[str, ...]
- to_edges(prefix: str = '') list[Edge]
Convert hyperedge to regular binary edges.
Creates one Edge for each pair of adjacent nodes in this hyperedge. For a hyperedge with N nodes, creates N-1 edges forming a chain.
- Parameters:
prefix – Optional prefix for generated edge IDs.
- Returns:
List of Edge objects representing pairwise connections.
Example
>>> he = Hyperedge("tri", ("A", "B", "C")) >>> edges = he.to_edges() >>> len(edges) 2
- pylinkage.hypergraph.HyperedgeId
alias of
str
- class pylinkage.hypergraph.HypergraphLinkage(nodes: dict[str, ~pylinkage.hypergraph.core.Node]=<factory>, edges: dict[str, ~pylinkage.hypergraph.core.Edge]=<factory>, hyperedges: dict[str, ~pylinkage.hypergraph.core.Hyperedge]=<factory>, name: str = '', _adjacency: dict[str, list[str]]=<factory>, _hyperedge_membership: dict[str, list[str]]=<factory>)
Bases:
objectPure topological hypergraph representation of a planar linkage.
A linkage is represented as a hypergraph where: - Nodes are joints (revolute R or prismatic P) with roles - Edges are binary link connections - Hyperedges are N-way rigid body groupings
This is a topology-only representation. Dimensional data (positions, distances, angles) is stored separately in a Dimensions object.
This representation enables: - First-class rigid body representation via hyperedges - Hierarchical composition - Conversion to other representations (Assur, Mechanism) - Pure structural analysis without geometric constraints
- Variables:
nodes (dict[str, pylinkage.hypergraph.core.Node]) – Dictionary mapping node IDs to Node objects.
edges (dict[str, pylinkage.hypergraph.core.Edge]) – Dictionary mapping edge IDs to Edge objects.
hyperedges (dict[str, pylinkage.hypergraph.core.Hyperedge]) – Dictionary mapping hyperedge IDs to Hyperedge objects.
name (str) – Human-readable name for the linkage.
Example
>>> graph = HypergraphLinkage(name="Four-bar") >>> graph.add_node(Node("A", role=NodeRole.GROUND)) >>> graph.add_node(Node("B", role=NodeRole.DRIVER)) >>> graph.add_edge(Edge("AB", source="A", target="B"))
- add_edge(edge: Edge) None
Add an edge to the graph.
- Parameters:
edge – The Edge to add.
- Raises:
ValueError – If an edge with the same ID already exists, or if source/target nodes don’t exist.
- add_hyperedge(hyperedge: Hyperedge) None
Add a hyperedge to the graph.
- Parameters:
hyperedge – The Hyperedge to add.
- Raises:
ValueError – If a hyperedge with the same ID already exists, or if any referenced nodes don’t exist.
- add_node(node: Node) None
Add a node to the graph.
- Parameters:
node – The Node to add.
- Raises:
ValueError – If a node with the same ID already exists.
- all_neighbors(node_id: str) list[str]
Get all nodes connected to the given node via edges or hyperedges.
- Parameters:
node_id – The node to find neighbors of.
- Returns:
List of all connected node IDs (deduplicated).
- copy() HypergraphLinkage
Create a deep copy of the graph.
- Returns:
A new HypergraphLinkage with copied nodes, edges, and hyperedges.
- degree(node_id: str) int
Get the edge degree (number of edge connections) of a node.
- Parameters:
node_id – The node ID.
- Returns:
Number of edges connected to the node.
- driven_nodes() list[Node]
Get all driven nodes.
- driver_nodes() list[Node]
Get all driver/input nodes.
- edges: dict[str, Edge]
- get_edge_between(node1: str, node2: str) Edge | None
Get the edge connecting two nodes, if any.
- Parameters:
node1 – First node ID.
node2 – Second node ID.
- Returns:
The Edge connecting the nodes, or None if not connected.
- get_edges_for_node(node_id: str) list[Edge]
Get all edges connected to a node.
- Parameters:
node_id – The node ID.
- Returns:
List of Edge objects connected to the node.
- get_hyperedges_for_node(node_id: str) list[Hyperedge]
Get all hyperedges containing a node.
- Parameters:
node_id – The node ID.
- Returns:
List of Hyperedge objects containing the node.
- ground_nodes() list[Node]
Get all ground/frame nodes.
- hyperdegree(node_id: str) int
Get the hyperedge degree (number of hyperedge memberships) of a node.
- Parameters:
node_id – The node ID.
- Returns:
Number of hyperedges containing the node.
- hyperedge_neighbors(node_id: str) list[str]
Get all nodes sharing a hyperedge with the given node.
- Parameters:
node_id – The node to find hyperedge neighbors of.
- Returns:
List of node IDs sharing hyperedges with the given node.
- hyperedges: dict[str, Hyperedge]
- name: str = ''
- neighbors(node_id: str) list[str]
Get all nodes connected to the given node via edges.
- Parameters:
node_id – The node to find neighbors of.
- Returns:
List of node IDs connected via edges.
- nodes: dict[str, Node]
- remove_edge(edge_id: str) Edge
Remove an edge from the graph.
- Parameters:
edge_id – ID of the edge to remove.
- Returns:
The removed Edge.
- Raises:
KeyError – If edge not found.
- remove_hyperedge(hyperedge_id: str) Hyperedge
Remove a hyperedge from the graph.
- Parameters:
hyperedge_id – ID of the hyperedge to remove.
- Returns:
The removed Hyperedge.
- Raises:
KeyError – If hyperedge not found.
- remove_node(node_id: str) Node
Remove a node and all its connections from the graph.
- Parameters:
node_id – ID of the node to remove.
- Returns:
The removed Node.
- Raises:
KeyError – If node not found.
- to_simple_graph() HypergraphLinkage
Convert to a simple graph by expanding hyperedges to edges.
Creates a new HypergraphLinkage with no hyperedges. Every hyperedge becomes the clique of its nodes — one edge per pair — since a rigid body holds each pair of its joints at a fixed distance. Pairs already joined by an edge are left as they are.
- Returns:
A new HypergraphLinkage with only nodes and edges.
- class pylinkage.hypergraph.JointType(value)
Bases:
IntEnumKinematic joint type.
This enum classifies joints by their allowed degrees of freedom. Values are explicit integers for serialization stability.
- Variables:
REVOLUTE – Pin joint allowing rotation (R). 1 DOF rotation.
PRISMATIC – Slider joint allowing translation (P). 1 DOF translation.
GROUND – Fixed revolute joint on frame. Special case for mechanism module.
TRACKER – Observer joint (T). 0 DOF, just tracks a position.
- GROUND = 3
- PRISMATIC = 2
- REVOLUTE = 1
- TRACKER = 4
- class pylinkage.hypergraph.Node(id: str, role: NodeRole = NodeRole.DRIVEN, joint_type: JointType = JointType.REVOLUTE, name: str | None = None)
Bases:
objectA joint in the linkage hypergraph (topology only).
Represents the topological aspect of a joint - its identity, role, and type. Geometric data (position, angles) is stored separately in a Dimensions object.
- Variables:
id (str) – Unique identifier for this node.
role (pylinkage._types.NodeRole) – The role in the mechanism (GROUND, DRIVER, or DRIVEN).
joint_type (pylinkage._types.JointType) – The kinematic joint type (REVOLUTE or PRISMATIC).
name (str | None) – Human-readable name for display.
Example
>>> node = Node("A", role=NodeRole.GROUND) >>> node.joint_type <JointType.REVOLUTE: 1>
- id: str
- joint_type: JointType = 1
- name: str | None = None
- role: NodeRole = 2
- pylinkage.hypergraph.NodeId
alias of
str
- class pylinkage.hypergraph.NodeRole(value)
Bases:
IntEnumRole of a node/joint in the mechanism.
Classifies joints by their kinematic role in the linkage structure.
- Variables:
GROUND – Fixed frame point that does not move.
DRIVER – Input/motor joint that provides motion (actuated).
DRIVEN – Position computed from constraints (passive, part of Assur groups).
- DRIVEN = 2
- DRIVER = 1
- GROUND = 0
- pylinkage.hypergraph.PortId
alias of
str
- pylinkage.hypergraph.from_mechanism(mechanism: Mechanism) tuple[HypergraphLinkage, Dimensions]
Convert a Mechanism to a HypergraphLinkage and Dimensions.
This converts an existing Mechanism to the hypergraph representation for analysis, visualization, or manipulation.
- Parameters:
mechanism – The Mechanism to convert.
- Returns:
A tuple of (HypergraphLinkage, Dimensions).
Example
>>> mechanism = Mechanism(joints=[...], links=[...]) >>> hg, dims = from_mechanism(mechanism) >>> # Analyze or modify the hypergraph
- pylinkage.hypergraph.from_sim_linkage(sim_linkage: SimLinkage) tuple[HypergraphLinkage, Dimensions]
Convert a
pylinkage.simulation.Linkageto a hypergraph.- Parameters:
sim_linkage – A
simulation.Linkagebuilt from the modern component/actuator/dyad API.- Returns:
A tuple
(hypergraph, dimensions)suitable for feeding intopylinkage.hypergraph.to_mechanism()or into any hypergraph-native consumer.- Raises:
TypeError – If
sim_linkagedoes not look like asimulation.Linkage(no.components).NotImplementedError – If a component type is encountered that this bridge does not yet handle.
- pylinkage.hypergraph.graph_from_dict(data: dict[str, Any]) HypergraphLinkage
Create a HypergraphLinkage from a dictionary.
- Parameters:
data – Dictionary representation.
- Returns:
A HypergraphLinkage instance.
- pylinkage.hypergraph.graph_from_json(path: str | Path) HypergraphLinkage
Load a HypergraphLinkage from a JSON file.
- Parameters:
path – Path to the input file.
- Returns:
A HypergraphLinkage instance.
- pylinkage.hypergraph.graph_to_dict(graph: HypergraphLinkage) dict[str, Any]
Convert a HypergraphLinkage to a dictionary.
- Parameters:
graph – The HypergraphLinkage to convert.
- Returns:
Dictionary representation of the graph.
- pylinkage.hypergraph.graph_to_json(graph: HypergraphLinkage, path: str | Path) None
Save a HypergraphLinkage to a JSON file.
- Parameters:
graph – The HypergraphLinkage to save.
path – Path to the output file.
- pylinkage.hypergraph.hierarchical_from_dict(data: dict[str, Any]) HierarchicalLinkage
Create a HierarchicalLinkage from a dictionary.
- Parameters:
data – Dictionary representation.
- Returns:
A HierarchicalLinkage instance.
- pylinkage.hypergraph.hierarchical_from_json(path: str | Path) HierarchicalLinkage
Load a HierarchicalLinkage from a JSON file.
- Parameters:
path – Path to the input file.
- Returns:
A HierarchicalLinkage instance.
- pylinkage.hypergraph.hierarchical_to_dict(linkage: HierarchicalLinkage) dict[str, Any]
Convert a HierarchicalLinkage to a dictionary.
- Parameters:
linkage – The HierarchicalLinkage to convert.
- Returns:
Dictionary representation.
- pylinkage.hypergraph.hierarchical_to_json(linkage: HierarchicalLinkage, path: str | Path) None
Save a HierarchicalLinkage to a JSON file.
- Parameters:
linkage – The HierarchicalLinkage to save.
path – Path to the output file.
- pylinkage.hypergraph.to_mechanism(hypergraph: HypergraphLinkage, dimensions: Dimensions) Mechanism
Convert a HypergraphLinkage and Dimensions to a Mechanism.
This converts the hypergraph topology plus dimensional data to the mechanism model. This is the preferred conversion path for new code.
- Parameters:
hypergraph – The HypergraphLinkage defining the topology.
dimensions – The Dimensions providing positions, distances, angles.
- Returns:
A Mechanism instance ready for simulation.
- Raises:
ValueError – If the hypergraph is underconstrained or has disconnected components that cannot be solved.
Example
>>> hg = HypergraphLinkage(name="Four-bar") >>> hg.add_node(Node("A", role=NodeRole.GROUND)) >>> hg.add_edge(Edge("AB", "A", "B")) >>> dims = Dimensions( ... node_positions={"A": (0, 0), "B": (1, 0)}, ... edge_distances={"AB": 1.0}, ... ) >>> mechanism = to_mechanism(hg, dims)