vibe_graph_layout_gpu/lib.rs
1//! GPU-accelerated force-directed graph layout using WebGPU.
2//!
3//! This crate provides a high-performance Barnes-Hut force-directed layout
4//! algorithm that runs on the GPU via wgpu, supporting both native (Vulkan/Metal/DX12)
5//! and web (WebGPU) platforms.
6//!
7//! ## Architecture
8//!
9//! ```text
10//! ┌─────────────────────────────────────────────────────────────┐
11//! │ CPU Side │
12//! │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
13//! │ │ Graph Data │───▶│ Quadtree │───▶│ GPU Buffers │ │
14//! │ │ (positions) │ │ (Barnes-Hut)│ │ (upload) │ │
15//! │ └─────────────┘ └─────────────┘ └─────────────┘ │
16//! └─────────────────────────────────────────────────────────────┘
17//! │
18//! ▼
19//! ┌─────────────────────────────────────────────────────────────┐
20//! │ GPU Side │
21//! │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
22//! │ │ Repulsive │───▶│ Attractive │───▶│ Integrate │ │
23//! │ │ Forces │ │ Forces │ │ Positions │ │
24//! │ │ (BH approx) │ │ (edges) │ │ │ │
25//! │ └─────────────┘ └─────────────┘ └─────────────┘ │
26//! └─────────────────────────────────────────────────────────────┘
27//! │
28//! ▼
29//! ┌─────────────────────────────────────────────────────────────┐
30//! │ Read Back │
31//! │ Updated positions copied back to CPU for rendering │
32//! └─────────────────────────────────────────────────────────────┘
33//! ```
34//!
35//! ## Performance
36//!
37//! - Traditional Fruchterman-Reingold: O(n²) per iteration
38//! - Barnes-Hut approximation: O(n log n) per iteration
39//! - GPU parallelization: ~100x speedup for large graphs
40//!
41//! For a 10,000 node graph:
42//! - CPU O(n²): ~100M operations → ~10 FPS
43//! - GPU Barnes-Hut: ~100K operations, parallelized → 60+ FPS
44
45mod error;
46mod gpu;
47mod layout;
48mod quadtree;
49mod shaders;
50
51pub use error::LayoutError;
52pub use layout::{GpuLayout, LayoutConfig, LayoutState};
53pub use quadtree::QuadTree;
54
55/// Result type for layout operations.
56pub type Result<T> = std::result::Result<T, LayoutError>;
57
58/// A 2D position.
59#[derive(Debug, Clone, Copy, Default, bytemuck::Pod, bytemuck::Zeroable)]
60#[repr(C)]
61pub struct Position {
62 pub x: f32,
63 pub y: f32,
64}
65
66impl Position {
67 pub fn new(x: f32, y: f32) -> Self {
68 Self { x, y }
69 }
70}
71
72/// A 2D velocity.
73#[derive(Debug, Clone, Copy, Default, bytemuck::Pod, bytemuck::Zeroable)]
74#[repr(C)]
75pub struct Velocity {
76 pub x: f32,
77 pub y: f32,
78}
79
80/// An edge between two nodes.
81#[derive(Debug, Clone, Copy, Default, bytemuck::Pod, bytemuck::Zeroable)]
82#[repr(C)]
83pub struct Edge {
84 pub source: u32,
85 pub target: u32,
86}
87
88impl Edge {
89 pub fn new(source: u32, target: u32) -> Self {
90 Self { source, target }
91 }
92}
93
94/// Barnes-Hut quadtree node for GPU upload.
95/// This is a flattened representation suitable for GPU processing.
96#[derive(Debug, Clone, Copy, Default, bytemuck::Pod, bytemuck::Zeroable)]
97#[repr(C)]
98pub struct QuadTreeNode {
99 /// Center of mass X
100 pub center_x: f32,
101 /// Center of mass Y
102 pub center_y: f32,
103 /// Total mass (number of nodes in this cell)
104 pub mass: f32,
105 /// Cell width (for Barnes-Hut theta criterion)
106 pub width: f32,
107 /// Index of first child (-1 if leaf or empty)
108 pub child_nw: i32,
109 pub child_ne: i32,
110 pub child_sw: i32,
111 pub child_se: i32,
112}
113
114/// Layout parameters for the force-directed algorithm.
115#[derive(Debug, Clone, Copy)]
116#[repr(C)]
117pub struct LayoutParams {
118 /// Number of nodes
119 pub node_count: u32,
120 /// Number of edges
121 pub edge_count: u32,
122 /// Number of quadtree nodes
123 pub tree_size: u32,
124 /// Time step
125 pub dt: f32,
126 /// Damping factor (0-1, higher = more damping)
127 pub damping: f32,
128 /// Repulsion strength
129 pub repulsion: f32,
130 /// Attraction strength
131 pub attraction: f32,
132 /// Barnes-Hut theta (0.5-1.0, higher = faster but less accurate)
133 pub theta: f32,
134 /// Center gravity strength
135 pub gravity: f32,
136 /// Ideal edge length
137 pub ideal_length: f32,
138}
139
140impl Default for LayoutParams {
141 fn default() -> Self {
142 Self {
143 node_count: 0,
144 edge_count: 0,
145 tree_size: 0,
146 dt: 0.016, // ~60 FPS
147 damping: 0.9,
148 repulsion: 1000.0,
149 attraction: 0.01,
150 theta: 0.8, // Good balance of speed/accuracy
151 gravity: 0.1,
152 ideal_length: 50.0,
153 }
154 }
155}
156
157// Ensure LayoutParams is Pod-compatible by implementing manually
158unsafe impl bytemuck::Pod for LayoutParams {}
159unsafe impl bytemuck::Zeroable for LayoutParams {}