rework structure of everything
This commit is contained in:
parent
dcc4d6436c
commit
941d3e01df
64 changed files with 3819 additions and 3559 deletions
|
|
@ -1,54 +1,29 @@
|
|||
from inire.geometry.collision import CollisionEngine
|
||||
from inire.geometry.primitives import Port
|
||||
from inire.router.astar import AStarContext, AStarMetrics
|
||||
from inire.router.cost import CostEvaluator
|
||||
from inire.router.danger_map import DangerMap
|
||||
from inire.router.pathfinder import PathFinder
|
||||
from inire import NetSpec, Port, RoutingOptions, RoutingProblem, SearchOptions, route
|
||||
from inire.utils.visualization import plot_routing_results
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("Running Example 01: Simple Route...")
|
||||
|
||||
# 1. Setup Environment
|
||||
# We define a 100um x 100um routing area
|
||||
bounds = (0, 0, 100, 100)
|
||||
|
||||
# Clearance of 2.0um between waveguides
|
||||
engine = CollisionEngine(clearance=2.0)
|
||||
|
||||
# Precompute DangerMap for heuristic speedup
|
||||
danger_map = DangerMap(bounds=bounds)
|
||||
danger_map.precompute([]) # No obstacles yet
|
||||
|
||||
# 2. Configure Router
|
||||
evaluator = CostEvaluator(engine, danger_map)
|
||||
context = AStarContext(evaluator, bend_radii=[10.0])
|
||||
metrics = AStarMetrics()
|
||||
pf = PathFinder(context, metrics)
|
||||
|
||||
# 3. Define Netlist
|
||||
# Start at (10, 50) pointing East (0 deg)
|
||||
# Target at (90, 50) pointing East (0 deg)
|
||||
netlist = {
|
||||
"net1": (Port(10, 50, 0), Port(90, 50, 0)),
|
||||
}
|
||||
net_widths = {"net1": 2.0}
|
||||
problem = RoutingProblem(
|
||||
bounds=bounds,
|
||||
nets=(NetSpec("net1", *netlist["net1"], width=2.0),),
|
||||
)
|
||||
options = RoutingOptions(search=SearchOptions(bend_radii=(10.0,)))
|
||||
|
||||
# 4. Route
|
||||
results = pf.route_all(netlist, net_widths)
|
||||
|
||||
# 5. Check Results
|
||||
res = results["net1"]
|
||||
if res.is_valid:
|
||||
run = route(problem, options=options)
|
||||
result = run.results_by_net["net1"]
|
||||
if result.is_valid:
|
||||
print("Success! Route found.")
|
||||
print(f"Path collisions: {res.collisions}")
|
||||
print(f"Path collisions: {result.collisions}")
|
||||
else:
|
||||
print("Failed to find route.")
|
||||
|
||||
# 6. Visualize
|
||||
# plot_routing_results takes a dict of RoutingResult objects
|
||||
fig, ax = plot_routing_results(results, [], bounds)
|
||||
fig, _ax = plot_routing_results(run.results_by_net, [], bounds, netlist=netlist)
|
||||
fig.savefig("examples/01_simple_route.png")
|
||||
print("Saved plot to examples/01_simple_route.png")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,49 +1,41 @@
|
|||
from inire.geometry.collision import CollisionEngine
|
||||
from inire.geometry.primitives import Port
|
||||
from inire.router.astar import AStarContext, AStarMetrics
|
||||
from inire.router.cost import CostEvaluator
|
||||
from inire.router.danger_map import DangerMap
|
||||
from inire.router.pathfinder import PathFinder
|
||||
from inire import CongestionOptions, NetSpec, ObjectiveWeights, Port, RoutingOptions, RoutingProblem, SearchOptions, route
|
||||
from inire.utils.visualization import plot_routing_results
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("Running Example 02: Congestion Resolution (Triple Crossing)...")
|
||||
|
||||
# 1. Setup Environment
|
||||
bounds = (0, 0, 100, 100)
|
||||
engine = CollisionEngine(clearance=2.0)
|
||||
danger_map = DangerMap(bounds=bounds)
|
||||
danger_map.precompute([])
|
||||
|
||||
# Configure a router with high congestion penalties
|
||||
evaluator = CostEvaluator(engine, danger_map, greedy_h_weight=1.5, bend_penalty=250.0, sbend_penalty=500.0)
|
||||
context = AStarContext(evaluator, bend_radii=[10.0], sbend_radii=[10.0])
|
||||
metrics = AStarMetrics()
|
||||
pf = PathFinder(context, metrics, base_congestion_penalty=1000.0)
|
||||
|
||||
# 2. Define Netlist
|
||||
# Three nets that must cross each other in a small area
|
||||
netlist = {
|
||||
"horizontal": (Port(10, 50, 0), Port(90, 50, 0)),
|
||||
"vertical_up": (Port(45, 10, 90), Port(45, 90, 90)),
|
||||
"vertical_down": (Port(55, 90, 270), Port(55, 10, 270)),
|
||||
}
|
||||
net_widths = {nid: 2.0 for nid in netlist}
|
||||
problem = RoutingProblem(
|
||||
bounds=bounds,
|
||||
nets=tuple(NetSpec(net_id, start, target, width=2.0) for net_id, (start, target) in netlist.items()),
|
||||
)
|
||||
options = RoutingOptions(
|
||||
search=SearchOptions(
|
||||
bend_radii=(10.0,),
|
||||
sbend_radii=(10.0,),
|
||||
greedy_h_weight=1.5,
|
||||
),
|
||||
objective=ObjectiveWeights(
|
||||
bend_penalty=250.0,
|
||||
sbend_penalty=500.0,
|
||||
),
|
||||
congestion=CongestionOptions(base_penalty=1000.0),
|
||||
)
|
||||
|
||||
# 3. Route
|
||||
# PathFinder uses Negotiated Congestion to resolve overlaps iteratively
|
||||
results = pf.route_all(netlist, net_widths)
|
||||
|
||||
# 4. Check Results
|
||||
all_valid = all(res.is_valid for res in results.values())
|
||||
run = route(problem, options=options)
|
||||
all_valid = all(result.is_valid for result in run.results_by_net.values())
|
||||
if all_valid:
|
||||
print("Success! Congestion resolved for all nets.")
|
||||
else:
|
||||
print("Failed to resolve congestion for some nets.")
|
||||
|
||||
# 5. Visualize
|
||||
fig, ax = plot_routing_results(results, [], bounds, netlist=netlist)
|
||||
fig, _ax = plot_routing_results(run.results_by_net, [], bounds, netlist=netlist)
|
||||
fig.savefig("examples/02_congestion_resolution.png")
|
||||
print("Saved plot to examples/02_congestion_resolution.png")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,42 +1,37 @@
|
|||
from inire.geometry.collision import CollisionEngine
|
||||
from inire.geometry.primitives import Port
|
||||
from inire.router.astar import AStarContext, AStarMetrics
|
||||
from inire.router.cost import CostEvaluator
|
||||
from inire.router.danger_map import DangerMap
|
||||
from inire.router.pathfinder import PathFinder
|
||||
from inire import NetSpec, ObjectiveWeights, Port, RoutingOptions, RoutingProblem, SearchOptions, route
|
||||
from inire.utils.visualization import plot_routing_results
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("Running Example 03: Locked Paths...")
|
||||
print("Running Example 03: Locked Routes...")
|
||||
|
||||
# 1. Setup Environment
|
||||
bounds = (0, -50, 100, 50)
|
||||
engine = CollisionEngine(clearance=2.0)
|
||||
danger_map = DangerMap(bounds=bounds)
|
||||
danger_map.precompute([])
|
||||
|
||||
evaluator = CostEvaluator(engine, danger_map, bend_penalty=250.0, sbend_penalty=500.0)
|
||||
context = AStarContext(evaluator, bend_radii=[10.0])
|
||||
metrics = AStarMetrics()
|
||||
pf = PathFinder(context, metrics)
|
||||
|
||||
# 2. Route Net A and 'Lock' it
|
||||
# Net A is a straight path blocking the direct route for Net B
|
||||
options = RoutingOptions(
|
||||
search=SearchOptions(bend_radii=(10.0,)),
|
||||
objective=ObjectiveWeights(
|
||||
bend_penalty=250.0,
|
||||
sbend_penalty=500.0,
|
||||
),
|
||||
)
|
||||
print("Routing initial net...")
|
||||
netlist_a = {"netA": (Port(10, 0, 0), Port(90, 0, 0))}
|
||||
results_a = pf.route_all(netlist_a, {"netA": 2.0})
|
||||
|
||||
# Locking prevents Net A from being removed or rerouted during NC iterations
|
||||
engine.lock_net("netA")
|
||||
print("Initial net locked as static obstacle.")
|
||||
results_a = route(
|
||||
RoutingProblem(
|
||||
bounds=bounds,
|
||||
nets=(NetSpec("netA", Port(10, 0, 0), Port(90, 0, 0), width=2.0),),
|
||||
),
|
||||
options=options,
|
||||
).results_by_net
|
||||
|
||||
# 3. Route Net B (forced to detour)
|
||||
print("Routing detour net around locked path...")
|
||||
netlist_b = {"netB": (Port(50, -20, 90), Port(50, 20, 90))}
|
||||
results_b = pf.route_all(netlist_b, {"netB": 2.0})
|
||||
results_b = route(
|
||||
RoutingProblem(
|
||||
bounds=bounds,
|
||||
nets=(NetSpec("netB", Port(50, -20, 90), Port(50, 20, 90), width=2.0),),
|
||||
locked_routes={"netA": results_a["netA"].as_locked_route()},
|
||||
),
|
||||
options=options,
|
||||
).results_by_net
|
||||
|
||||
# 4. Visualize
|
||||
results = {**results_a, **results_b}
|
||||
fig, ax = plot_routing_results(results, [], bounds)
|
||||
fig.savefig("examples/03_locked_paths.png")
|
||||
|
|
|
|||
|
|
@ -1,60 +1,38 @@
|
|||
from inire.geometry.collision import CollisionEngine
|
||||
from inire.geometry.primitives import Port
|
||||
from inire.router.astar import AStarContext, AStarMetrics
|
||||
from inire.router.cost import CostEvaluator
|
||||
from inire.router.danger_map import DangerMap
|
||||
from inire.router.pathfinder import PathFinder
|
||||
from inire import NetSpec, ObjectiveWeights, Port, RoutingOptions, RoutingProblem, SearchOptions, route
|
||||
from inire.utils.visualization import plot_routing_results
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("Running Example 04: S-Bends and Multiple Radii...")
|
||||
|
||||
# 1. Setup Environment
|
||||
bounds = (0, 0, 100, 100)
|
||||
engine = CollisionEngine(clearance=2.0)
|
||||
danger_map = DangerMap(bounds=bounds)
|
||||
danger_map.precompute([])
|
||||
|
||||
# 2. Configure Router
|
||||
evaluator = CostEvaluator(
|
||||
engine,
|
||||
danger_map,
|
||||
unit_length_cost=1.0,
|
||||
bend_penalty=10.0,
|
||||
sbend_penalty=20.0,
|
||||
)
|
||||
|
||||
context = AStarContext(
|
||||
evaluator,
|
||||
node_limit=50000,
|
||||
bend_radii=[10.0, 30.0],
|
||||
sbend_offsets=[5.0], # Use a simpler offset
|
||||
bend_penalty=10.0,
|
||||
sbend_penalty=20.0,
|
||||
)
|
||||
|
||||
metrics = AStarMetrics()
|
||||
pf = PathFinder(context, metrics)
|
||||
|
||||
# 3. Define Netlist
|
||||
# start (10, 50), target (60, 55) -> 5um offset
|
||||
netlist = {
|
||||
"sbend_only": (Port(10, 50, 0), Port(60, 55, 0)),
|
||||
"multi_radii": (Port(10, 10, 0), Port(90, 90, 0)),
|
||||
}
|
||||
net_widths = {"sbend_only": 2.0, "multi_radii": 2.0}
|
||||
problem = RoutingProblem(
|
||||
bounds=bounds,
|
||||
nets=tuple(NetSpec(net_id, start, target, width=2.0) for net_id, (start, target) in netlist.items()),
|
||||
)
|
||||
options = RoutingOptions(
|
||||
search=SearchOptions(
|
||||
node_limit=50000,
|
||||
bend_radii=(10.0, 30.0),
|
||||
sbend_offsets=(5.0,),
|
||||
),
|
||||
objective=ObjectiveWeights(
|
||||
unit_length_cost=1.0,
|
||||
bend_penalty=10.0,
|
||||
sbend_penalty=20.0,
|
||||
),
|
||||
)
|
||||
|
||||
# 4. Route
|
||||
results = pf.route_all(netlist, net_widths)
|
||||
run = route(problem, options=options)
|
||||
for net_id, result in run.results_by_net.items():
|
||||
status = "Success" if result.is_valid else "Failed"
|
||||
print(f"{net_id}: {status}, collisions={result.collisions}")
|
||||
|
||||
# 5. Check Results
|
||||
for nid, res in results.items():
|
||||
status = "Success" if res.is_valid else "Failed"
|
||||
print(f"{nid}: {status}, collisions={res.collisions}")
|
||||
|
||||
# 6. Visualize
|
||||
fig, ax = plot_routing_results(results, [], bounds, netlist=netlist)
|
||||
fig, _ax = plot_routing_results(run.results_by_net, [], bounds, netlist=netlist)
|
||||
fig.savefig("examples/04_sbends_and_radii.png")
|
||||
print("Saved plot to examples/04_sbends_and_radii.png")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,46 +1,32 @@
|
|||
from inire.geometry.collision import CollisionEngine
|
||||
from inire.geometry.primitives import Port
|
||||
from inire.router.astar import AStarContext, AStarMetrics
|
||||
from inire.router.cost import CostEvaluator
|
||||
from inire.router.danger_map import DangerMap
|
||||
from inire.router.pathfinder import PathFinder
|
||||
from inire import NetSpec, ObjectiveWeights, Port, RoutingOptions, RoutingProblem, SearchOptions, route
|
||||
from inire.utils.visualization import plot_routing_results
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("Running Example 05: Orientation Stress Test...")
|
||||
|
||||
# 1. Setup Environment
|
||||
bounds = (0, 0, 200, 200)
|
||||
engine = CollisionEngine(clearance=2.0)
|
||||
danger_map = DangerMap(bounds=bounds)
|
||||
danger_map.precompute([])
|
||||
|
||||
evaluator = CostEvaluator(engine, danger_map, bend_penalty=50.0)
|
||||
context = AStarContext(evaluator, bend_radii=[20.0])
|
||||
metrics = AStarMetrics()
|
||||
pf = PathFinder(context, metrics)
|
||||
|
||||
# 2. Define Netlist
|
||||
# Challenging orientation combinations
|
||||
netlist = {
|
||||
"u_turn": (Port(50, 50, 0), Port(50, 70, 180)),
|
||||
"loop": (Port(100, 100, 90), Port(100, 80, 270)),
|
||||
"zig_zag": (Port(20, 150, 0), Port(180, 150, 0)),
|
||||
}
|
||||
net_widths = {nid: 2.0 for nid in netlist}
|
||||
problem = RoutingProblem(
|
||||
bounds=bounds,
|
||||
nets=tuple(NetSpec(net_id, start, target, width=2.0) for net_id, (start, target) in netlist.items()),
|
||||
)
|
||||
options = RoutingOptions(
|
||||
search=SearchOptions(bend_radii=(20.0,)),
|
||||
objective=ObjectiveWeights(bend_penalty=50.0),
|
||||
)
|
||||
|
||||
# 3. Route
|
||||
print("Routing complex orientation nets...")
|
||||
results = pf.route_all(netlist, net_widths)
|
||||
run = route(problem, options=options)
|
||||
for net_id, result in run.results_by_net.items():
|
||||
status = "Success" if result.is_valid else "Failed"
|
||||
print(f" {net_id}: {status}")
|
||||
|
||||
# 4. Check Results
|
||||
for nid, res in results.items():
|
||||
status = "Success" if res.is_valid else "Failed"
|
||||
print(f" {nid}: {status}")
|
||||
|
||||
# 5. Visualize
|
||||
fig, ax = plot_routing_results(results, [], bounds, netlist=netlist)
|
||||
fig, _ax = plot_routing_results(run.results_by_net, [], bounds, netlist=netlist)
|
||||
fig.savefig("examples/05_orientation_stress.png")
|
||||
print("Saved plot to examples/05_orientation_stress.png")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
from shapely.geometry import Polygon
|
||||
|
||||
from inire.geometry.collision import CollisionEngine
|
||||
from inire import CongestionOptions, NetSpec, ObjectiveWeights, RoutingOptions, RoutingProblem, RoutingResult, SearchOptions, route
|
||||
from inire.geometry.primitives import Port
|
||||
from inire.router.astar import AStarContext
|
||||
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
|
||||
|
||||
|
||||
|
|
@ -15,34 +11,30 @@ def _route_scenario(
|
|||
bend_collision_type: str,
|
||||
netlist: dict[str, tuple[Port, Port]],
|
||||
widths: dict[str, float],
|
||||
*,
|
||||
bend_clip_margin: float = 10.0,
|
||||
) -> dict[str, object]:
|
||||
engine = CollisionEngine(clearance=2.0)
|
||||
for obstacle in obstacles:
|
||||
engine.add_static_obstacle(obstacle)
|
||||
|
||||
danger_map = DangerMap(bounds=bounds)
|
||||
danger_map.precompute(obstacles)
|
||||
evaluator = CostEvaluator(engine, danger_map, bend_penalty=50.0, sbend_penalty=150.0)
|
||||
context = AStarContext(
|
||||
evaluator,
|
||||
bend_radii=[10.0],
|
||||
bend_collision_type=bend_collision_type,
|
||||
bend_clip_margin=bend_clip_margin,
|
||||
) -> dict[str, RoutingResult]:
|
||||
problem = RoutingProblem(
|
||||
bounds=bounds,
|
||||
nets=tuple(NetSpec(net_id, start, target, width=widths[net_id]) for net_id, (start, target) in netlist.items()),
|
||||
static_obstacles=tuple(obstacles),
|
||||
)
|
||||
return PathFinder(context, use_tiered_strategy=False).route_all(netlist, widths)
|
||||
options = RoutingOptions(
|
||||
search=SearchOptions(
|
||||
bend_radii=(10.0,),
|
||||
bend_collision_type=bend_collision_type,
|
||||
),
|
||||
objective=ObjectiveWeights(
|
||||
bend_penalty=50.0,
|
||||
sbend_penalty=150.0,
|
||||
),
|
||||
congestion=CongestionOptions(use_tiered_strategy=False),
|
||||
)
|
||||
return route(problem, options=options).results_by_net
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("Running Example 06: Bend Collision Models...")
|
||||
|
||||
# 1. Setup Environment
|
||||
# Give room for 10um bends near the edges
|
||||
bounds = (-20, -20, 170, 170)
|
||||
|
||||
# Create three scenarios with identical obstacles
|
||||
# We'll space them out vertically
|
||||
obs_arc = Polygon([(40, 110), (60, 110), (60, 130), (40, 130)])
|
||||
obs_bbox = Polygon([(40, 60), (60, 60), (60, 80), (40, 80)])
|
||||
obs_clipped = Polygon([(40, 10), (60, 10), (60, 30), (40, 30)])
|
||||
|
|
@ -52,29 +44,17 @@ def main() -> None:
|
|||
netlist_bbox = {"bbox_model": (Port(10, 70, 0), Port(90, 90, 90))}
|
||||
netlist_clipped = {"clipped_model": (Port(10, 20, 0), Port(90, 40, 90))}
|
||||
|
||||
# 2. Route each scenario
|
||||
print("Routing Scenario 1 (Arc)...")
|
||||
res_arc = _route_scenario(bounds, obstacles, "arc", netlist_arc, {"arc_model": 2.0})
|
||||
|
||||
print("Routing Scenario 2 (BBox)...")
|
||||
res_bbox = _route_scenario(bounds, obstacles, "bbox", netlist_bbox, {"bbox_model": 2.0})
|
||||
|
||||
print("Routing Scenario 3 (Clipped BBox)...")
|
||||
res_clipped = _route_scenario(
|
||||
bounds,
|
||||
obstacles,
|
||||
"clipped_bbox",
|
||||
netlist_clipped,
|
||||
{"clipped_model": 2.0},
|
||||
bend_clip_margin=1.0,
|
||||
)
|
||||
res_clipped = _route_scenario(bounds, obstacles, "clipped_bbox", netlist_clipped, {"clipped_model": 2.0})
|
||||
|
||||
# 3. Combine results for visualization
|
||||
all_results = {**res_arc, **res_bbox, **res_clipped}
|
||||
all_netlists = {**netlist_arc, **netlist_bbox, **netlist_clipped}
|
||||
|
||||
# 4. Visualize
|
||||
fig, ax = plot_routing_results(all_results, obstacles, bounds, netlist=all_netlists)
|
||||
fig, _ax = plot_routing_results(all_results, obstacles, bounds, netlist=all_netlists)
|
||||
fig.savefig("examples/06_bend_collision_models.png")
|
||||
print("Saved plot to examples/06_bend_collision_models.png")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,108 +1,111 @@
|
|||
import numpy as np
|
||||
import time
|
||||
from inire.geometry.collision import CollisionEngine
|
||||
from inire.geometry.primitives import Port
|
||||
from inire.router.astar import AStarContext, AStarMetrics
|
||||
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, plot_danger_map, plot_expanded_nodes, plot_expansion_density
|
||||
|
||||
from shapely.geometry import box
|
||||
|
||||
from inire import (
|
||||
CongestionOptions,
|
||||
DiagnosticsOptions,
|
||||
NetSpec,
|
||||
ObjectiveWeights,
|
||||
Port,
|
||||
RoutingOptions,
|
||||
RoutingProblem,
|
||||
RoutingResult,
|
||||
SearchOptions,
|
||||
route,
|
||||
)
|
||||
from inire.utils.visualization import plot_expanded_nodes, plot_routing_results
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("Running Example 07: Fan-Out (10 Nets, 50um Radius)...")
|
||||
|
||||
# 1. Setup Environment
|
||||
bounds = (0, 0, 1000, 1000)
|
||||
engine = CollisionEngine(clearance=6.0)
|
||||
|
||||
# Bottleneck at x=500, 200um gap
|
||||
obstacles = [
|
||||
box(450, 0, 550, 400),
|
||||
box(450, 600, 550, 1000),
|
||||
]
|
||||
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, unit_length_cost=0.1, bend_penalty=100.0, sbend_penalty=400.0, congestion_penalty=100.0)
|
||||
|
||||
context = AStarContext(evaluator, node_limit=2000000, bend_radii=[50.0], sbend_radii=[50.0])
|
||||
metrics = AStarMetrics()
|
||||
pf = PathFinder(context, metrics, max_iterations=15, base_congestion_penalty=100.0, congestion_multiplier=1.4)
|
||||
|
||||
# 2. Define Netlist
|
||||
netlist = {}
|
||||
num_nets = 10
|
||||
start_x = 50
|
||||
start_y_base = 500 - (num_nets * 10.0) / 2.0
|
||||
|
||||
end_x = 950
|
||||
end_y_base = 100
|
||||
end_y_pitch = 800.0 / (num_nets - 1)
|
||||
|
||||
for i in range(num_nets):
|
||||
sy = int(round(start_y_base + i * 10.0))
|
||||
ey = int(round(end_y_base + i * end_y_pitch))
|
||||
netlist[f"net_{i:02d}"] = (Port(start_x, sy, 0), Port(end_x, ey, 0))
|
||||
netlist: dict[str, tuple[Port, Port]] = {}
|
||||
for index in range(num_nets):
|
||||
start_y = int(round(start_y_base + index * 10.0))
|
||||
end_y = int(round(end_y_base + index * end_y_pitch))
|
||||
netlist[f"net_{index:02d}"] = (Port(start_x, start_y, 0), Port(end_x, end_y, 0))
|
||||
|
||||
net_widths = {nid: 2.0 for nid in netlist}
|
||||
problem = RoutingProblem(
|
||||
bounds=bounds,
|
||||
nets=tuple(NetSpec(net_id, start, target, width=2.0) for net_id, (start, target) in netlist.items()),
|
||||
static_obstacles=tuple(obstacles),
|
||||
clearance=6.0,
|
||||
)
|
||||
options = RoutingOptions(
|
||||
search=SearchOptions(
|
||||
node_limit=2_000_000,
|
||||
bend_radii=(50.0,),
|
||||
sbend_radii=(50.0,),
|
||||
greedy_h_weight=1.5,
|
||||
),
|
||||
objective=ObjectiveWeights(
|
||||
unit_length_cost=0.1,
|
||||
bend_penalty=100.0,
|
||||
sbend_penalty=400.0,
|
||||
),
|
||||
congestion=CongestionOptions(
|
||||
max_iterations=15,
|
||||
base_penalty=100.0,
|
||||
multiplier=1.4,
|
||||
shuffle_nets=True,
|
||||
seed=42,
|
||||
),
|
||||
diagnostics=DiagnosticsOptions(capture_expanded=True),
|
||||
)
|
||||
|
||||
iteration_stats: list[dict[str, int]] = []
|
||||
|
||||
def iteration_callback(iteration: int, current_results: dict[str, RoutingResult]) -> None:
|
||||
successes = sum(1 for result in current_results.values() if result.is_valid)
|
||||
total_collisions = sum(result.collisions for result in current_results.values())
|
||||
print(f" Iteration {iteration} finished. Successes: {successes}/{len(netlist)}, Collisions: {total_collisions}")
|
||||
iteration_stats.append(
|
||||
{
|
||||
"Iteration": iteration,
|
||||
"Success": successes,
|
||||
"Congestion": total_collisions,
|
||||
}
|
||||
)
|
||||
|
||||
# 3. Route
|
||||
print(f"Routing {len(netlist)} nets through 200um bottleneck...")
|
||||
start_time = time.perf_counter()
|
||||
run = route(problem, options=options, iteration_callback=iteration_callback)
|
||||
end_time = time.perf_counter()
|
||||
|
||||
iteration_stats = []
|
||||
|
||||
def iteration_callback(idx, current_results):
|
||||
successes = sum(1 for r in current_results.values() if r.is_valid)
|
||||
total_collisions = sum(r.collisions for r in current_results.values())
|
||||
total_nodes = metrics.nodes_expanded
|
||||
|
||||
print(f" Iteration {idx} finished. Successes: {successes}/{len(netlist)}, Collisions: {total_collisions}")
|
||||
|
||||
# Adaptive Greediness: Decay from 1.5 to 1.1 over 10 iterations
|
||||
new_greedy = max(1.1, 1.5 - ((idx + 1) / 10.0) * 0.4)
|
||||
evaluator.greedy_h_weight = new_greedy
|
||||
print(f" Adaptive Greedy Weight for Next Iteration: {new_greedy:.3f}")
|
||||
|
||||
iteration_stats.append({
|
||||
'Iteration': idx,
|
||||
'Success': successes,
|
||||
'Congestion': total_collisions,
|
||||
'Nodes': total_nodes
|
||||
})
|
||||
metrics.reset_per_route()
|
||||
|
||||
t0 = time.perf_counter()
|
||||
results = pf.route_all(netlist, net_widths, store_expanded=True, iteration_callback=iteration_callback, shuffle_nets=True, seed=42)
|
||||
t1 = time.perf_counter()
|
||||
|
||||
print(f"Routing took {t1-t0:.4f}s")
|
||||
|
||||
# 4. Check Results
|
||||
print(f"Routing took {end_time - start_time:.4f}s")
|
||||
print("\n--- Iteration Summary ---")
|
||||
print(f"{'Iter':<5} | {'Success':<8} | {'Congest':<8} | {'Nodes':<10}")
|
||||
print("-" * 40)
|
||||
for s in iteration_stats:
|
||||
print(f"{s['Iteration']:<5} | {s['Success']:<8} | {s['Congestion']:<8} | {s['Nodes']:<10}")
|
||||
print(f"{'Iter':<5} | {'Success':<8} | {'Congest':<8}")
|
||||
print("-" * 30)
|
||||
for stats in iteration_stats:
|
||||
print(f"{stats['Iteration']:<5} | {stats['Success']:<8} | {stats['Congestion']:<8}")
|
||||
|
||||
success_count = sum(1 for res in results.values() if res.is_valid)
|
||||
success_count = sum(1 for result in run.results_by_net.values() if result.is_valid)
|
||||
print(f"\nFinal: Routed {success_count}/{len(netlist)} nets successfully.")
|
||||
|
||||
for nid, res in results.items():
|
||||
if not res.is_valid:
|
||||
print(f" FAILED: {nid}, collisions={res.collisions}")
|
||||
for net_id, result in run.results_by_net.items():
|
||||
if not result.is_valid:
|
||||
print(f" FAILED: {net_id}, collisions={result.collisions}")
|
||||
else:
|
||||
print(f" {nid}: SUCCESS")
|
||||
|
||||
# 5. Visualize
|
||||
fig, ax = plot_routing_results(results, obstacles, bounds, netlist=netlist)
|
||||
plot_danger_map(danger_map, ax=ax)
|
||||
print(f" {net_id}: SUCCESS")
|
||||
|
||||
fig, ax = plot_routing_results(run.results_by_net, list(obstacles), bounds, netlist=netlist)
|
||||
plot_expanded_nodes(list(run.expanded_nodes), ax=ax)
|
||||
fig.savefig("examples/07_large_scale_routing.png")
|
||||
print("Saved plot to examples/07_large_scale_routing.png")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -1,59 +1,61 @@
|
|||
from shapely.geometry import Polygon
|
||||
|
||||
from inire.geometry.collision import CollisionEngine
|
||||
from inire import CongestionOptions, NetSpec, ObjectiveWeights, RoutingOptions, RoutingProblem, RoutingResult, SearchOptions, route
|
||||
from inire.geometry.primitives import Port
|
||||
from inire.router.astar import AStarContext, AStarMetrics
|
||||
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 _route_with_context(
|
||||
context: AStarContext,
|
||||
metrics: AStarMetrics,
|
||||
netlist: dict[str, tuple[Port, Port]],
|
||||
net_widths: dict[str, float],
|
||||
) -> dict[str, object]:
|
||||
return PathFinder(context, metrics, use_tiered_strategy=False).route_all(netlist, net_widths)
|
||||
def _run_request(
|
||||
bounds: tuple[float, float, float, float],
|
||||
bend_collision_type: object,
|
||||
net_id: str,
|
||||
start: Port,
|
||||
target: Port,
|
||||
) -> dict[str, RoutingResult]:
|
||||
problem = RoutingProblem(
|
||||
bounds=bounds,
|
||||
nets=(NetSpec(net_id, start, target, width=2.0),),
|
||||
)
|
||||
options = RoutingOptions(
|
||||
search=SearchOptions(
|
||||
bend_radii=(10.0,),
|
||||
bend_collision_type=bend_collision_type,
|
||||
sbend_radii=(),
|
||||
),
|
||||
objective=ObjectiveWeights(
|
||||
bend_penalty=50.0,
|
||||
sbend_penalty=150.0,
|
||||
),
|
||||
congestion=CongestionOptions(use_tiered_strategy=False),
|
||||
)
|
||||
return route(problem, options=options).results_by_net
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("Running Example 08: Custom Bend Geometry...")
|
||||
|
||||
# 1. Setup Environment
|
||||
bounds = (0, 0, 150, 150)
|
||||
start = Port(20, 20, 0)
|
||||
target = Port(100, 100, 90)
|
||||
|
||||
# 2. Define Netlist
|
||||
netlist = {
|
||||
"custom_bend": (Port(20, 20, 0), Port(100, 100, 90)),
|
||||
}
|
||||
net_widths = {"custom_bend": 2.0}
|
||||
|
||||
def build_context(bend_collision_type: object = "arc") -> tuple[AStarContext, AStarMetrics]:
|
||||
engine = CollisionEngine(clearance=2.0)
|
||||
danger_map = DangerMap(bounds=bounds)
|
||||
danger_map.precompute([])
|
||||
evaluator = CostEvaluator(engine, danger_map, bend_penalty=50.0, sbend_penalty=150.0)
|
||||
return AStarContext(evaluator, bend_radii=[10.0], bend_collision_type=bend_collision_type, sbend_radii=[]), AStarMetrics()
|
||||
|
||||
# 3. Route with standard arc first
|
||||
print("Routing with standard arc...")
|
||||
context_std, metrics_std = build_context()
|
||||
results_std = _route_with_context(context_std, metrics_std, netlist, net_widths)
|
||||
results_std = _run_request(bounds, "arc", "custom_bend", start, target)
|
||||
|
||||
# 4. Define a custom Manhattan 90-degree bend proxy in bend-local coordinates.
|
||||
# The polygon origin is the bend center. It is mirrored for CW bends and
|
||||
# rotated with the bend orientation before being translated into place.
|
||||
custom_poly = Polygon([(0, -11), (11, -11), (11, 0), (9, 0), (9, -9), (0, -9)])
|
||||
|
||||
print("Routing with custom bend geometry...")
|
||||
context_custom, metrics_custom = build_context(custom_poly)
|
||||
results_custom = _route_with_context(context_custom, metrics_custom, {"custom_model": netlist["custom_bend"]}, {"custom_model": 2.0})
|
||||
results_custom = _run_request(bounds, custom_poly, "custom_model", start, target)
|
||||
|
||||
# 5. Visualize
|
||||
all_results = {**results_std, **results_custom}
|
||||
fig, ax = plot_routing_results(all_results, [], bounds, netlist=netlist)
|
||||
fig, _ax = plot_routing_results(
|
||||
all_results,
|
||||
[],
|
||||
bounds,
|
||||
netlist={
|
||||
"custom_bend": (start, target),
|
||||
"custom_model": (start, target),
|
||||
},
|
||||
)
|
||||
fig.savefig("examples/08_custom_bend_geometry.png")
|
||||
print("Saved plot to examples/08_custom_bend_geometry.png")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,58 +1,46 @@
|
|||
from inire.geometry.collision import CollisionEngine
|
||||
from inire.geometry.primitives import Port
|
||||
from inire.router.astar import AStarContext, AStarMetrics
|
||||
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
|
||||
|
||||
from inire import CongestionOptions, NetSpec, ObjectiveWeights, Port, RoutingOptions, RoutingProblem, SearchOptions, route
|
||||
from inire.utils.visualization import plot_routing_results
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("Running Example 09: Best-Effort Under Tight Search Budget...")
|
||||
|
||||
# 1. Setup Environment
|
||||
bounds = (0, 0, 100, 100)
|
||||
engine = CollisionEngine(clearance=2.0)
|
||||
|
||||
# A small obstacle cluster keeps the partial route visually interesting.
|
||||
obstacles = [
|
||||
box(35, 35, 45, 65),
|
||||
box(55, 35, 65, 65),
|
||||
]
|
||||
for obs in obstacles:
|
||||
engine.add_static_obstacle(obs)
|
||||
problem = RoutingProblem(
|
||||
bounds=bounds,
|
||||
nets=(NetSpec("budget_limited_net", Port(10, 50, 0), Port(85, 60, 180), width=2.0),),
|
||||
static_obstacles=tuple(obstacles),
|
||||
)
|
||||
options = RoutingOptions(
|
||||
search=SearchOptions(
|
||||
node_limit=3,
|
||||
bend_radii=(10.0,),
|
||||
),
|
||||
objective=ObjectiveWeights(
|
||||
bend_penalty=50.0,
|
||||
sbend_penalty=150.0,
|
||||
),
|
||||
congestion=CongestionOptions(warm_start=None),
|
||||
)
|
||||
|
||||
danger_map = DangerMap(bounds=bounds)
|
||||
danger_map.precompute(obstacles)
|
||||
|
||||
evaluator = CostEvaluator(engine, danger_map, bend_penalty=50.0, sbend_penalty=150.0)
|
||||
# Keep the search budget intentionally tiny so the router returns a partial path.
|
||||
context = AStarContext(evaluator, node_limit=3, bend_radii=[10.0])
|
||||
metrics = AStarMetrics()
|
||||
|
||||
pf = PathFinder(context, metrics, warm_start=None)
|
||||
|
||||
# 2. Define Netlist: reaching the target requires additional turns the search budget cannot afford.
|
||||
netlist = {
|
||||
"budget_limited_net": (Port(10, 50, 0), Port(85, 60, 180)),
|
||||
}
|
||||
net_widths = {"budget_limited_net": 2.0}
|
||||
|
||||
# 3. Route
|
||||
print("Routing with a deliberately tiny node budget (should return a partial path)...")
|
||||
results = pf.route_all(netlist, net_widths)
|
||||
|
||||
# 4. Check Results
|
||||
res = results["budget_limited_net"]
|
||||
if not res.reached_target:
|
||||
print(f"Target not reached as expected. Partial path length: {len(res.path)} segments.")
|
||||
run = route(problem, options=options)
|
||||
result = run.results_by_net["budget_limited_net"]
|
||||
if not result.reached_target:
|
||||
print(f"Target not reached as expected. Partial path length: {len(result.path)} segments.")
|
||||
else:
|
||||
print("The route unexpectedly reached the target. Increase difficulty or reduce the node budget further.")
|
||||
|
||||
# 5. Visualize
|
||||
fig, ax = plot_routing_results(results, obstacles, bounds, netlist=netlist)
|
||||
fig, _ax = plot_routing_results(run.results_by_net, list(obstacles), bounds, netlist={"budget_limited_net": (Port(10, 50, 0), Port(85, 60, 180))})
|
||||
fig.savefig("examples/09_unroutable_best_effort.png")
|
||||
print("Saved plot to examples/09_unroutable_best_effort.png")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue