A high-performance, Rust-powered Python library for graph data structures and algorithms. Built with PyO3, IronWeaver
provides fast, memory-efficient graph operations with seamless Python integration.
- High Performance: Rust-powered backend for blazing-fast graph operations
- Rich Graph API: Intuitive Python interface for creating and manipulating graphs
- Advanced Algorithms: BFS, shortest path, graph expansion, and filtering
- NetworkX Integration: Seamless conversion to NetworkX for visualization
- Serialization: JSON and binary save/load capabilities
- Event-Driven: Callback system for node and edge modifications
- Memory Efficient: Optimized Rust implementation for large graphs
FIXME: this will not work yet, it needs to be cloned from github, rust compiled and installed
pip install IronWeaver
from ironweaver import Vertex, Node, Edge
import networkx as nx
import matplotlib.pyplot as plt
# Create a new graph
graph = Vertex()
# Add nodes with attributes
node1 = graph.add_node('node1', {'value': 1, 'type': 'start'})
node2 = graph.add_node('node2', {'value': 2, 'type': 'process'})
node3 = graph.add_node('node3', {'value': 3, 'type': 'end'})
# Add edges with weights
edge1 = graph.add_edge('node1', 'node2', {'weight': 1.0})
edge2 = graph.add_edge('node2', 'node3', {'weight': 2.0})
edge3 = graph.add_edge('node1', 'node3', {'weight': 3.0})
print(f"Graph: {graph}")
print(f"Node count: {graph.node_count()}")
# Convert to NetworkX for visualization
nx_graph = graph.to_networkx()
# Visualize with matplotlib
plt.figure(figsize=(10, 8))
pos = nx.spring_layout(nx_graph)
nx.draw(nx_graph,
pos=pos,
with_labels=True,
node_color='lightblue',
node_size=1000,
font_size=12,
font_weight='bold',
edge_color='gray',
arrows=True)
plt.title("Graph Visualization")
plt.show()
# Find shortest path between nodes using BFS
path = graph.shortest_path_bfs('node1', 'node3')
print(f"Shortest path: {path}")
# Visualize the path
path_nx = path.to_networkx()
nx.draw(path_nx, with_labels=True, node_color='orange')
plt.title("Shortest Path from node1 to node3")
plt.show()
# Create a subgraph and expand it by exploring neighbors
filtered_graph = graph.filter(['node2']) # Start with just node2
expanded = filtered_graph.expand(graph, depth=1) # Expand 1 level
print(f"Original nodes: {graph.keys()}")
print(f"Filtered nodes: {filtered_graph.keys()}")
print(f"Expanded nodes: {expanded.keys()}")
# Set up callbacks for graph modifications
def on_node_added(vertex, node):
print(f"Node added: {node.id}")
# Track visited nodes in metadata
if "visited_nodes" not in vertex.meta:
vertex.meta["visited_nodes"] = []
vertex.meta["visited_nodes"].append(node.id)
return True # Continue processing
def on_edge_added(vertex, edge):
print(f"Edge added: {edge.from_node.id} -> {edge.to_node.id}")
edge.meta["timestamp"] = "2025-05-25"
return True
# Register callbacks
graph.on_node_add_callbacks.append(on_node_added)
graph.on_edge_add_callbacks.append(on_edge_added)
# Add nodes and edges - callbacks will be triggered
new_node = graph.add_node('node4', {'value': 4})
new_edge = graph.add_edge('node3', 'node4', {'weight': 1.5})
print(f"Graph metadata: {graph.meta}")
# Save graph to JSON
graph.save_to_json("my_graph.json")
# Save to binary format (more efficient for large graphs)
graph.save_to_binary("my_graph.bin")
# Or use half precision floats to reduce file size
graph.save_to_binary_f16("my_graph_f16.bin")
# Load from file
loaded_graph = Vertex.load_from_json("my_graph.json")
print(f"Loaded graph: {loaded_graph}")
print(f"Metadata: {loaded_graph.get_metadata()}")
The main graph container that holds nodes and provides graph-level operations.
# Create empty graph
graph = Vertex()
# Node operations
node = graph.add_node(id: str, attr: dict = None) -> Node
node = graph.get_node(id: str) -> Node
exists = graph.has_node(id: str) -> bool
count = graph.node_count() -> int
# Edge operations
edge = graph.add_edge(from_id: str, to_id: str, attr: dict = None) -> Edge
# Algorithms
path = graph.shortest_path_bfs(start: str, end: str, max_depth: int = None) -> Vertex
expanded = graph.expand(source: Vertex, depth: int = 1) -> Vertex
filtered = graph.filter(node_ids: List[str]) -> Vertex
# Conversion and analysis
nx_graph = graph.to_networkx() -> networkx.DiGraph
metadata = graph.get_metadata() -> dict
# Persistence
graph.save_to_json(file_path: str)
graph.save_to_binary(file_path: str)
graph.save_to_binary_f16(file_path: str)
loaded = Vertex.load_from_json(file_path: str) -> Vertex
loaded = Vertex.load_from_binary(file_path: str) -> Vertex
Represents individual vertices in the graph with attributes and edges.
# Access node properties
id = node.id # Node identifier
attrs = node.attr # Node attributes dict
edges = node.edges # List of outgoing edges
# Traversal from node
reachable = node.traverse(depth: int = None) -> Vertex
bfs_result = node.bfs(depth: int = None) -> Vertex
found = node.bfs_search(target_id: str, depth: int = None) -> Node
Represents connections between nodes with optional attributes.
# Access edge properties
from_node = edge.from_node # Source node
to_node = edge.to_node # Target node
attrs = edge.attr # Edge attributes dict
IronWeaver
is built with performance in mind:
- Rust Backend: Core algorithms implemented in Rust for maximum speed
- Memory Efficient: Optimized data structures for large graphs
- Minimal Overhead: PyO3 bindings provide near-native performance
- Scalable: Tested with graphs containing thousands of nodes and edges
The library includes comprehensive performance testing for various graph operations:
- BFS traversal performance
- Shortest path algorithms
- Graph expansion operations
- Memory usage optimization
- Cyclic graph handling
See the performance_results/
directory for detailed benchmarks.
Contributions are welcome! Please see our contributing guidelines for more information.
# Clone the repository
git clone <repository-url>
cd ironweaver
# Build the Rust extension
maturin develop
# Run tests
pytest
TODO: Add license information here.
- Built with PyO3 for Rust-Python bindings
- Compatible with NetworkX for visualization
- Inspired by the need for high-performance graph operations in Python
Note: This library is designed for applications requiring high-performance graph operations. For simple use cases, NetworkX might be more appropriate. For complex, large-scale graph analysis, IronWeaver
might provide significant performance advantages.
Initially it was developed for the Gustabor project.