examples work
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 116 KiB |
|
|
@ -18,8 +18,9 @@ def main() -> None:
|
|||
danger_map.precompute([])
|
||||
|
||||
evaluator = CostEvaluator(engine, danger_map, greedy_h_weight=1.1)
|
||||
# router = AStarRouter(evaluator, node_limit=100000)
|
||||
router = AStarRouter(evaluator, node_limit=100000, bend_collision_type="clipped_bbox", bend_clip_margin=1.0)
|
||||
router = AStarRouter(evaluator, node_limit=100000)
|
||||
router.config.bend_collision_type = "clipped_bbox"
|
||||
router.config.bend_clip_margin = 1.0
|
||||
pf = PathFinder(router, evaluator)
|
||||
|
||||
# 2. Define Netlist with various orientation challenges
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 88 KiB |
|
|
@ -46,13 +46,13 @@ def main() -> None:
|
|||
|
||||
# 2. Route each scenario
|
||||
print("Routing Scenario 1 (Arc)...")
|
||||
res_arc = PathFinder(router_arc, evaluator).route_all(netlist_arc, {"arc_model": 2.0})
|
||||
res_arc = PathFinder(router_arc, evaluator, use_tiered_strategy=False).route_all(netlist_arc, {"arc_model": 2.0})
|
||||
|
||||
print("Routing Scenario 2 (BBox)...")
|
||||
res_bbox = PathFinder(router_bbox, evaluator).route_all(netlist_bbox, {"bbox_model": 2.0})
|
||||
res_bbox = PathFinder(router_bbox, evaluator, use_tiered_strategy=False).route_all(netlist_bbox, {"bbox_model": 2.0})
|
||||
|
||||
print("Routing Scenario 3 (Clipped BBox)...")
|
||||
res_clipped = PathFinder(router_clipped, evaluator).route_all(netlist_clipped, {"clipped_model": 2.0})
|
||||
res_clipped = PathFinder(router_clipped, evaluator, use_tiered_strategy=False).route_all(netlist_clipped, {"clipped_model": 2.0})
|
||||
|
||||
# 3. Combine results for visualization
|
||||
all_results = {**res_arc, **res_bbox, **res_clipped}
|
||||
|
|
|
|||
BIN
examples/07_large_scale_routing.png
Normal file
|
After Width: | Height: | Size: 77 KiB |
70
examples/07_large_scale_routing.py
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import numpy as np
|
||||
from inire.geometry.collision import CollisionEngine
|
||||
from inire.geometry.primitives import Port
|
||||
from inire.router.astar import AStarRouter
|
||||
from inire.router.cost import CostEvaluator
|
||||
from inire.router.danger_map import DangerMap
|
||||
from inire.router.pathfinder import PathFinder
|
||||
from inire.utils.visualization import plot_routing_results
|
||||
from shapely.geometry import box
|
||||
|
||||
def main() -> None:
|
||||
print("Running Example 07: Fan-Out (5 Nets)...")
|
||||
|
||||
# 1. Setup Environment
|
||||
# Small area for fast and reliable demonstration
|
||||
bounds = (0, 0, 100, 100)
|
||||
engine = CollisionEngine(clearance=2.0)
|
||||
|
||||
# Wide bottleneck at x=50, 60um gap (from y=20 to y=80)
|
||||
obstacles = [
|
||||
box(50, 0, 55, 20),
|
||||
box(50, 80, 55, 100),
|
||||
]
|
||||
for obs in obstacles:
|
||||
engine.add_static_obstacle(obs)
|
||||
|
||||
danger_map = DangerMap(bounds=bounds)
|
||||
danger_map.precompute(obstacles)
|
||||
|
||||
evaluator = CostEvaluator(engine, danger_map, greedy_h_weight=1.5)
|
||||
|
||||
# Increase node_limit for more complex search
|
||||
router = AStarRouter(evaluator, node_limit=50000)
|
||||
pf = PathFinder(router, evaluator, max_iterations=2)
|
||||
|
||||
# 2. Define Netlist: Fan-Out Configuration
|
||||
netlist = {}
|
||||
num_nets = 10
|
||||
start_x = 10
|
||||
# Bundle centered at y=50, 4um pitch
|
||||
start_y_base = 50 - (num_nets * 4.0) / 2.0
|
||||
|
||||
end_x = 90
|
||||
end_y_base = 10
|
||||
end_y_pitch = 80.0 / (num_nets - 1)
|
||||
|
||||
for i in range(num_nets):
|
||||
sy = start_y_base + i * 4.0
|
||||
ey = end_y_base + i * end_y_pitch
|
||||
|
||||
net_id = f"net_{i:02d}"
|
||||
netlist[net_id] = (Port(start_x, sy, 0), Port(end_x, ey, 0))
|
||||
|
||||
net_widths = {nid: 2.0 for nid in netlist}
|
||||
|
||||
# 3. Route
|
||||
print(f"Routing {len(netlist)} nets through 60um bottleneck...")
|
||||
results = pf.route_all(netlist, net_widths)
|
||||
|
||||
# 4. Check Results
|
||||
success_count = sum(1 for res in results.values() if res.is_valid)
|
||||
print(f"Routed {success_count}/{len(netlist)} nets successfully.")
|
||||
|
||||
# 5. Visualize
|
||||
fig, ax = plot_routing_results(results, obstacles, bounds, netlist=netlist)
|
||||
fig.savefig("examples/07_large_scale_routing.png")
|
||||
print("Saved plot to examples/07_large_scale_routing.png")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
examples/08_custom_bend_geometry.png
Normal file
|
After Width: | Height: | Size: 122 KiB |
66
examples/08_custom_bend_geometry.py
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
from shapely.geometry import Polygon
|
||||
from inire.geometry.collision import CollisionEngine
|
||||
from inire.geometry.primitives import Port
|
||||
from inire.router.astar import AStarRouter
|
||||
from inire.router.cost import CostEvaluator
|
||||
from inire.router.danger_map import DangerMap
|
||||
from inire.router.pathfinder import PathFinder
|
||||
from inire.utils.visualization import plot_routing_results
|
||||
|
||||
def main() -> None:
|
||||
print("Running Example 08: Custom Bend Geometry Models...")
|
||||
|
||||
bounds = (0, 0, 150, 150)
|
||||
engine = CollisionEngine(clearance=2.0)
|
||||
|
||||
# Static obstacle to force specific bend paths
|
||||
obstacle = Polygon([(60, 40), (90, 40), (90, 110), (60, 110)])
|
||||
engine.add_static_obstacle(obstacle)
|
||||
|
||||
danger_map = DangerMap(bounds=bounds)
|
||||
danger_map.precompute([obstacle])
|
||||
evaluator = CostEvaluator(engine, danger_map)
|
||||
|
||||
# We will route three nets, each with a DIFFERENT collision model
|
||||
# To do this cleanly with the current architecture, we'll use one router
|
||||
# but change its config per route call (or use tiered escalation in PathFinder).
|
||||
# Since AStarRouter.route now accepts bend_collision_type, we can do it directly.
|
||||
|
||||
router = AStarRouter(evaluator)
|
||||
pf = PathFinder(router, evaluator)
|
||||
|
||||
netlist = {
|
||||
"model_arc": (Port(10, 130, 0), Port(130, 100, -90)),
|
||||
"model_bbox": (Port(10, 80, 0), Port(130, 50, -90)),
|
||||
"model_clipped": (Port(10, 30, 0), Port(130, 10, -90)),
|
||||
}
|
||||
net_widths = {nid: 2.0 for nid in netlist}
|
||||
|
||||
# Manual routing to specify different models per net
|
||||
results = {}
|
||||
|
||||
print("Routing with 'arc' model...")
|
||||
results["model_arc"] = pf.router.route(netlist["model_arc"][0], netlist["model_arc"][1], 2.0,
|
||||
net_id="model_arc", bend_collision_type="arc")
|
||||
|
||||
print("Routing with 'bbox' model...")
|
||||
results["model_bbox"] = pf.router.route(netlist["model_bbox"][0], netlist["model_bbox"][1], 2.0,
|
||||
net_id="model_bbox", bend_collision_type="bbox")
|
||||
|
||||
print("Routing with 'clipped_bbox' model...")
|
||||
results["model_clipped"] = pf.router.route(netlist["model_clipped"][0], netlist["model_clipped"][1], 2.0,
|
||||
net_id="model_clipped", bend_collision_type="clipped_bbox")
|
||||
|
||||
# Wrap in RoutingResult for visualization
|
||||
from inire.router.pathfinder import RoutingResult
|
||||
final_results = {
|
||||
nid: RoutingResult(nid, path if path else [], path is not None, 0)
|
||||
for nid, path in results.items()
|
||||
}
|
||||
|
||||
fig, ax = plot_routing_results(final_results, [obstacle], bounds, netlist=netlist)
|
||||
fig.savefig("examples/08_custom_bend_geometry.png")
|
||||
print("Saved plot to examples/08_custom_bend_geometry.png")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
examples/09_unroutable_best_effort.png
Normal file
|
After Width: | Height: | Size: 79 KiB |
46
examples/09_unroutable_best_effort.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
from inire.geometry.collision import CollisionEngine
|
||||
from inire.geometry.primitives import Port
|
||||
from inire.router.astar import AStarRouter
|
||||
from inire.router.cost import CostEvaluator
|
||||
from inire.router.danger_map import DangerMap
|
||||
from inire.router.pathfinder import PathFinder, RoutingResult
|
||||
from inire.utils.visualization import plot_routing_results
|
||||
from shapely.geometry import box
|
||||
|
||||
def main() -> None:
|
||||
print("Running Example 09: Unroutable Nets & Best Effort Display...")
|
||||
|
||||
bounds = (0, 0, 100, 100)
|
||||
engine = CollisionEngine(clearance=2.0)
|
||||
|
||||
# A large obstacle that completely blocks the target port
|
||||
blocking_obs = box(40, 0, 60, 100)
|
||||
engine.add_static_obstacle(blocking_obs)
|
||||
|
||||
danger_map = DangerMap(bounds=bounds)
|
||||
danger_map.precompute([blocking_obs])
|
||||
evaluator = CostEvaluator(engine, danger_map)
|
||||
|
||||
# Use a low node limit to fail quickly
|
||||
router = AStarRouter(evaluator, node_limit=5000)
|
||||
|
||||
netlist = {
|
||||
"blocked_net": (Port(10, 50, 0), Port(90, 50, 180))
|
||||
}
|
||||
|
||||
print("Routing blocked net (expecting failure)...")
|
||||
# Manually call route with return_partial=True
|
||||
path = router.route(netlist["blocked_net"][0], netlist["blocked_net"][1], 2.0,
|
||||
net_id="blocked_net", return_partial=True)
|
||||
|
||||
# Wrap in RoutingResult. Even if path is returned, is_valid=False
|
||||
results = {
|
||||
"blocked_net": RoutingResult("blocked_net", path if path else [], False, 1)
|
||||
}
|
||||
|
||||
fig, ax = plot_routing_results(results, [blocking_obs], bounds, netlist=netlist)
|
||||
fig.savefig("examples/09_unroutable_best_effort.png")
|
||||
print("Saved plot to examples/09_unroutable_best_effort.png")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
38
examples/README.md
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# Inire Routing Examples
|
||||
|
||||
This directory contains examples demonstrating the features and architectural capabilities of the `inire` router.
|
||||
|
||||
## Architectural Visualization
|
||||
In all plots generated by `inire`, we distinguish between the search-time geometry and the final "actual" geometry:
|
||||
* **Dashed Lines & Translucent Fill**: The **Collision Proxy** used during the A* search (e.g., `clipped_bbox` or `bbox`). This represents the conservative envelope the router used to guarantee clearance.
|
||||
* **Solid Lines**: The **Actual Geometry** (high-fidelity arcs). This is the exact shape that will be used for PDK generation and fabrication.
|
||||
|
||||
---
|
||||
|
||||
## 1. Fan-Out (Negotiated Congestion)
|
||||
Demonstrates the Negotiated Congestion algorithm handling multiple intersecting nets. The router iteratively increases penalties for overlaps until a collision-free solution is found. This example shows a bundle of nets fanning out through a narrow bottleneck.
|
||||
|
||||

|
||||
|
||||
## 2. Custom Bend Geometry Models
|
||||
`inire` supports multiple collision models for bends, allowing a trade-off between search speed and geometric accuracy:
|
||||
* **Arc**: High-fidelity geometry (Highest accuracy).
|
||||
* **BBox**: Simple axis-aligned bounding box (Fastest search).
|
||||
* **Clipped BBox**: A balanced model that clips the corners of the AABB to better fit the arc (Optimal performance).
|
||||
|
||||

|
||||
|
||||
## 3. Unroutable Nets & Best-Effort Display
|
||||
When a net is physically blocked or exceeds the node limit, the router returns the "best-effort" partial path—the path that reached the point closest to the target according to the heuristic. This is critical for debugging design constraints.
|
||||
|
||||

|
||||
|
||||
## 4. Orientation Stress Test
|
||||
Demonstrates the router's ability to handle complex orientation requirements, including U-turns, 90-degree flips, and loops.
|
||||
|
||||

|
||||
|
||||
## 5. Tiered Fidelity & Lazy Dilation
|
||||
Our architecture leverages two key optimizations for high-performance routing:
|
||||
1. **Tiered Fidelity**: Initial routing passes use fast `clipped_bbox` proxies. If collisions are found, the system automatically escalates to high-fidelity `arc` geometry for the affected regions.
|
||||
2. **Lazy Dilation**: Geometric buffering (dilation) is deferred until a collision check is strictly necessary, avoiding thousands of redundant `buffer()` and `translate()` calls.
|
||||