babylon.engine.graph_protocol
Graph Protocol definition for backend-agnostic graph operations.
Slice 1.7: The Graph Bridge
The GraphProtocol is a typing.Protocol that defines the abstract interface for all graph operations. Systems interact with the simulation graph ONLY through this protocol. The concrete implementation (NetworkX, DuckDB) is hidden behind the adapter.
- Design Principles:
Backend-agnostic: Works with NetworkX now, DuckDB later
Set-oriented: Think in tables, not just objects (DuckDB-ready)
Minimal but complete: Just enough methods to cover all System needs
Lazy evaluation: Return iterators/generators, not materialized lists
- Protocol Methods (18 total):
Node CRUD: add_node, get_node, update_node, remove_node Edge CRUD: add_edge, get_edge, update_edge, remove_edge Traversal: get_neighborhood, execute_traversal, shortest_path Set Ops: query_nodes, query_edges, count_nodes, count_edges, aggregate Graph Attrs: get_graph_attr, set_graph_attr
Classes
|
Protocol for backend-agnostic graph operations. |
- class babylon.engine.graph_protocol.GraphProtocol(*args, **kwargs)[source]
Bases:
ProtocolProtocol for backend-agnostic graph operations.
Systems interact with the simulation graph ONLY through this protocol. The concrete implementation (NetworkX, DuckDB) is hidden behind adapters.
This protocol is runtime_checkable, enabling isinstance() checks for protocol compliance.
Example
>>> class MyAdapter: ... def add_node(self, node_id: str, node_type: str, **attrs: Any) -> None: ... pass ... # ... implement all 16 methods >>> adapter = MyAdapter() >>> isinstance(adapter, GraphProtocol) True
- add_node(node_id, node_type, **attributes)[source]
Add a node with type marker and arbitrary attributes.
- add_edge(source, target, edge_type, weight=1.0, **attributes)[source]
Add directed edge with type, weight, and attributes.
- get_neighborhood(node_id, radius=1, edge_types=None, direction='out')[source]
Get all nodes within radius hops of the source node.
- Parameters:
- Return type:
- Returns:
SubgraphView or equivalent containing nodes in neighborhood.
- Raises:
KeyError – If node does not exist.
- execute_traversal(query)[source]
Execute a generic traversal query.
This is the hook for complex operations like percolation analysis, pathfinding, and component detection.
- Parameters:
query (
TraversalQuery) – TraversalQuery specifying the traversal.- Return type:
- Returns:
TraversalResult with nodes, edges, paths, or aggregates.
- Raises:
ValueError – If query_type is not supported.
- shortest_path(source, target, edge_types=None, weight_attr=None)[source]
Find shortest path between two nodes.
- query_nodes(node_type=None, predicate=None, attributes=None)[source]
Query nodes with optional filtering.
Returns an iterator for DuckDB compatibility (lazy evaluation).
- Parameters:
- Return type:
- Returns:
Iterator of matching GraphNode models.
- query_edges(edge_type=None, predicate=None, min_weight=None, max_weight=None)[source]
Query edges with optional filtering.
Returns an iterator for DuckDB compatibility (lazy evaluation).
- Parameters:
- Return type:
- Returns:
Iterator of matching GraphEdge models.
- aggregate(target, group_by=None, agg_func='count', agg_attr=None)[source]
Aggregate over nodes or edges.
- Parameters:
target (
Literal['nodes','edges']) – Whether to aggregate nodes or edges.group_by (
str|None) – Attribute to group by (e.g., ‘type’).agg_func (
Literal['count','sum','avg','min','max']) – Aggregation function to apply.agg_attr (
str|None) – Attribute to aggregate (required for sum/avg/min/max).
- Return type:
- Returns:
Dict mapping group keys to aggregated values.
Example
>>> graph.aggregate("nodes", group_by="type") {"social_class": 4, "territory": 2}
- get_graph_attr(key, default=None)[source]
Retrieve a graph-level attribute.
Graph attributes store global metadata (e.g., economy state, base_year, tick_dynamics). Maps to a metadata table in DuckDB.
- __init__(*args, **kwargs)