File size: 9,453 Bytes
78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df 0f15b31 78cf0df |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
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()
|