import gradio as gr import numpy as np from PIL import Image import heapq def dijkstra_pathfinding(obstacles, speeds, source, target): """Simple Dijkstra pathfinding to demonstrate the algorithm""" H, W = obstacles.shape sx, sy = source tx, ty = target # Distance map dist = np.full((H, W), np.inf) dist[sy, sx] = 0.0 # Parent tracking for path reconstruction parent = {} # Priority queue: (distance, x, y) pq = [(0.0, sx, sy)] visited = set() # 4-connected neighbors neighbors = [(-1, 0), (1, 0), (0, -1), (0, 1)] while pq: d, x, y = heapq.heappop(pq) if (x, y) in visited: continue visited.add((x, y)) if (x, y) == (tx, ty): break for dx, dy in neighbors: nx, ny = x + dx, y + dy if 0 <= nx < W and 0 <= ny < H: if obstacles[ny, nx] > 0.5: # Blocked continue # Cost = 1 / speed (slower = higher cost) step_speed = max(speeds[ny, nx], 0.1) cost = 1.0 / step_speed new_dist = d + cost if new_dist < dist[ny, nx]: dist[ny, nx] = new_dist parent[(nx, ny)] = (x, y) heapq.heappush(pq, (new_dist, nx, ny)) # Reconstruct path if (tx, ty) not in parent and (tx, ty) != (sx, sy): return [] # No path found path = [] current = (tx, ty) while current != (sx, sy): path.append(current) if current not in parent: break current = parent[current] path.append((sx, sy)) path.reverse() return path def generate_pathfinding_demo(grid_size, obstacle_density, source_x, source_y, target_x, target_y): """Generate pathfinding visualization with actual path calculation""" # Generate obstacles np.random.seed(42) # Fixed seed for consistency obstacles = np.random.random((grid_size, grid_size)) < (obstacle_density / 100) obstacles = obstacles.astype(np.float32) # Ensure endpoints are free obstacles[source_y, source_x] = 0.0 obstacles[target_y, target_x] = 0.0 # Create speed field (uniform for simplicity) speeds = np.ones((grid_size, grid_size), dtype=np.float32) speeds[obstacles > 0.5] = 0.0 # Blocked cells have zero speed # Calculate path using Dijkstra path = dijkstra_pathfinding(obstacles, speeds, (source_x, source_y), (target_x, target_y)) # Create visualization vis = np.zeros((grid_size, grid_size, 3), dtype=np.uint8) # Base colors vis[obstacles > 0.5] = [40, 40, 40] # Obstacles: dark gray vis[obstacles < 0.5] = [200, 200, 200] # Free space: light gray # Draw path in bright green (before marking endpoints) if path: for px, py in path: if 0 <= px < grid_size and 0 <= py < grid_size: vis[py, px] = [0, 255, 0] # Bright green path # Mark source in red (larger, overwrites path) vis[max(0, source_y-2):min(grid_size, source_y+3), max(0, source_x-2):min(grid_size, source_x+3)] = [255, 0, 0] # Red source # Mark target in blue (larger, overwrites path) vis[max(0, target_y-2):min(grid_size, target_y+3), max(0, target_x-2):min(grid_size, target_x+3)] = [0, 100, 255] # Blue target # Calculate statistics blocked = int(np.sum(obstacles > 0.5)) free = grid_size * grid_size - blocked straight_dist = np.hypot(target_x - source_x, target_y - source_y) path_length = len(path) path_ratio = path_length / max(straight_dist, 1.0) if path else 0.0 stats = f""" ### Results - **Grid Size**: {grid_size}×{grid_size} ({grid_size*grid_size:,} cells) - **Obstacles**: {blocked:,} ({100*blocked/(grid_size*grid_size):.1f}%) - **Free Cells**: {free:,} ({100*free/(grid_size*grid_size):.1f}%) - **Straight Distance**: {straight_dist:.1f} cells - **Path Found**: {"✅ Yes" if path else "❌ No path exists"} - **Path Length**: {path_length} cells - **Path Ratio**: {path_ratio:.2f}x (efficiency) ### GPU Solver Performance The full Optical Neuromorphic GPU solver achieves: - **30-300× speedup** vs this CPU Dijkstra - **Sub-1% accuracy** (0.64% mean error) - **Near-optimal paths** (1.025× optimal length) - **Real-time** (2-4ms per query on 512×512 grids) **Colors**: 🔴 Red=Start, 🔵 Blue=Goal, 🟢 Green=Path, ⬛ Black=Obstacles This demo uses basic CPU Dijkstra. The full GPU implementation is 30-300× faster! """ img = Image.fromarray(vis) return img, stats # Gradio interface with gr.Blocks(title="Optical Neuromorphic Eikonal Solver Demo", theme=gr.themes.Soft()) as demo: gr.Markdown(""" # 🚀 Optical Neuromorphic Eikonal Solver **GPU-accelerated pathfinding with 30-300× speedup!** This demo shows pathfinding with basic CPU Dijkstra for comparison. The full GPU solver is 30-300× faster using neuromorphic computing principles. 🔗 **Full implementation**: [GitHub](https://github.com/Agnuxo1/optical-neuromorphic-eikonal-solver) """) with gr.Row(): with gr.Column(): gr.Markdown("### ⚙️ Configuration") grid_size = gr.Slider(64, 512, step=64, value=256, label="Grid Size") obstacle_density = gr.Slider(0, 50, step=5, value=20, label="Obstacle Density (%)") gr.Markdown("### 📍 Source (Red)") with gr.Row(): source_x = gr.Slider(0, 255, step=1, value=10, label="Source X") source_y = gr.Slider(0, 255, step=1, value=10, label="Source Y") gr.Markdown("### 🎯 Target (Blue)") with gr.Row(): target_x = gr.Slider(0, 255, step=1, value=245, label="Target X") target_y = gr.Slider(0, 255, step=1, value=245, label="Target Y") solve_btn = gr.Button("🎯 Find Path", variant="primary", size="lg") with gr.Column(): gr.Markdown("### 🗺️ Pathfinding Visualization") output_img = gr.Image(label="Grid with Optimal Path", height=400) stats_text = gr.Markdown("Click 'Find Path' to calculate optimal route") def update_sliders(size): return [gr.update(maximum=size-1)] * 4 grid_size.change(fn=update_sliders, inputs=[grid_size], outputs=[source_x, source_y, target_x, target_y]) solve_btn.click( fn=generate_pathfinding_demo, inputs=[grid_size, obstacle_density, source_x, source_y, target_x, target_y], outputs=[output_img, stats_text] ) gr.Markdown(""" --- ## 📚 Resources & Links - **Paper (HTML)**: [Full Academic Paper](https://github.com/Agnuxo1/optical-neuromorphic-eikonal-solver/blob/main/optical_neuromorphic_paper.html) - **Source Code**: [GitHub Repository](https://github.com/Agnuxo1/optical-neuromorphic-eikonal-solver) - **Datasets**: [HuggingFace](https://huggingface.co/datasets/Agnuxo/optical-neuromorphic-eikonal-benchmarks) - **OpenML**: [Datasets #47114-47118](https://www.openml.org/search?type=data&sort=date&status=active) - **W&B Metrics**: [Weights & Biases](https://wandb.ai/lareliquia-angulo-agnuxo/optical-neuromorphic-eikonal-solver) ## 🏆 Benchmark Results | Grid Size | GPU Time | CPU Time | Speedup | Accuracy | Path Quality | |-----------|----------|----------|---------|----------|--------------| | 128×128 | 2.3 ms | 73.9 ms | **32×** | 0.52% error | 1.004× optimal | | 256×256 | 3.1 ms | 275.5 ms | **89×** | 0.55% error | 1.015× optimal | | 512×512 | 4.1 ms | 948.9 ms | **231×** | 0.69% error | 1.042× optimal | | **Average** | **3.3 ms** | **505 ms** | **135×** | **0.64% error** | **1.025× optimal** | ## 🧠 How It Works The GPU solver uses **neuromorphic computing** principles: - Each grid cell maintains 4 directional memory states (N, E, S, W) - Information propagates like waves through the medium - All cells update in parallel on GPU (massively parallel) - System converges to optimal solution in ~2n iterations - No priority queues → Full parallelization ## 👤 Author **Francisco Angulo de Lafuente** - [GitHub](https://github.com/Agnuxo1) - [ResearchGate](https://www.researchgate.net/profile/Francisco-Angulo-Lafuente-3) - [Kaggle](https://www.kaggle.com/franciscoangulo) - [HuggingFace](https://huggingface.co/Agnuxo) - [Wikipedia](https://es.wikipedia.org/wiki/Francisco_Angulo_de_Lafuente) ## 📜 Citation If you use this work, please cite: ```bibtex @software{angulo2025optical, author = {Angulo de Lafuente, Francisco}, title = {Optical Neuromorphic Eikonal Solver}, year = {2025}, url = {https://github.com/Agnuxo1/optical-neuromorphic-eikonal-solver} } ``` """) demo.launch()