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()