Refactor: Remove AStarRouter, introduce AStarContext/AStarMetrics
This commit is contained in:
parent
62d357c147
commit
a77ae781a7
23 changed files with 226 additions and 276 deletions
|
|
@ -3,7 +3,7 @@ from inire.geometry.primitives import Port
|
|||
from inire.geometry.collision import CollisionEngine
|
||||
from inire.router.danger_map import DangerMap
|
||||
from inire.router.cost import CostEvaluator
|
||||
from inire.router.astar import AStarRouter
|
||||
from inire.router.astar import AStarContext, AStarMetrics
|
||||
from inire.router.pathfinder import PathFinder
|
||||
|
||||
def benchmark_scaling() -> None:
|
||||
|
|
@ -26,8 +26,9 @@ def benchmark_scaling() -> None:
|
|||
danger_map = DangerMap(bounds=routing_bounds)
|
||||
danger_map.precompute([])
|
||||
evaluator = CostEvaluator(engine, danger_map)
|
||||
router = AStarRouter(evaluator)
|
||||
pf = PathFinder(router, evaluator)
|
||||
context = AStarContext(evaluator)
|
||||
metrics = AStarMetrics()
|
||||
pf = PathFinder(context, metrics)
|
||||
|
||||
num_nets = 50
|
||||
netlist = {}
|
||||
|
|
@ -45,7 +46,7 @@ def benchmark_scaling() -> None:
|
|||
print(f"Time per net: {total_time/num_nets:.4f} s")
|
||||
|
||||
if total_time > 0:
|
||||
nodes_per_sec = router.total_nodes_expanded / total_time
|
||||
nodes_per_sec = metrics.total_nodes_expanded / total_time
|
||||
print(f"Node expansion rate: {nodes_per_sec:.2f} nodes/s")
|
||||
|
||||
# Success rate
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ 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.astar import AStarContext, route_astar
|
||||
from inire.router.cost import CostEvaluator
|
||||
from inire.router.danger_map import DangerMap
|
||||
from inire.router.pathfinder import RoutingResult
|
||||
|
|
@ -19,10 +19,10 @@ def basic_evaluator() -> CostEvaluator:
|
|||
|
||||
|
||||
def test_astar_straight(basic_evaluator: CostEvaluator) -> None:
|
||||
router = AStarRouter(basic_evaluator, snap_size=1.0)
|
||||
context = AStarContext(basic_evaluator, snap_size=1.0)
|
||||
start = Port(0, 0, 0)
|
||||
target = Port(50, 0, 0)
|
||||
path = router.route(start, target, net_width=2.0)
|
||||
path = route_astar(start, target, net_width=2.0, context=context)
|
||||
|
||||
assert path is not None
|
||||
result = RoutingResult(net_id="test", path=path, is_valid=True, collisions=0)
|
||||
|
|
@ -35,11 +35,11 @@ def test_astar_straight(basic_evaluator: CostEvaluator) -> None:
|
|||
|
||||
|
||||
def test_astar_bend(basic_evaluator: CostEvaluator) -> None:
|
||||
router = AStarRouter(basic_evaluator, snap_size=1.0, bend_radii=[10.0])
|
||||
context = AStarContext(basic_evaluator, snap_size=1.0, bend_radii=[10.0])
|
||||
start = Port(0, 0, 0)
|
||||
# 20um right, 20um up. Needs a 10um bend and a 10um bend.
|
||||
target = Port(20, 20, 0)
|
||||
path = router.route(start, target, net_width=2.0)
|
||||
path = route_astar(start, target, net_width=2.0, context=context)
|
||||
|
||||
assert path is not None
|
||||
result = RoutingResult(net_id="test", path=path, is_valid=True, collisions=0)
|
||||
|
|
@ -56,11 +56,10 @@ def test_astar_obstacle(basic_evaluator: CostEvaluator) -> None:
|
|||
basic_evaluator.collision_engine.add_static_obstacle(obstacle)
|
||||
basic_evaluator.danger_map.precompute([obstacle])
|
||||
|
||||
router = AStarRouter(basic_evaluator, snap_size=1.0, bend_radii=[10.0])
|
||||
router.node_limit = 1000000 # Give it more room for detour
|
||||
context = AStarContext(basic_evaluator, snap_size=1.0, bend_radii=[10.0], node_limit=1000000)
|
||||
start = Port(0, 0, 0)
|
||||
target = Port(60, 0, 0)
|
||||
path = router.route(start, target, net_width=2.0)
|
||||
path = route_astar(start, target, net_width=2.0, context=context)
|
||||
|
||||
assert path is not None
|
||||
result = RoutingResult(net_id="test", path=path, is_valid=True, collisions=0)
|
||||
|
|
@ -72,11 +71,11 @@ def test_astar_obstacle(basic_evaluator: CostEvaluator) -> None:
|
|||
|
||||
|
||||
def test_astar_snap_to_target_lookahead(basic_evaluator: CostEvaluator) -> None:
|
||||
router = AStarRouter(basic_evaluator, snap_size=1.0)
|
||||
context = AStarContext(basic_evaluator, snap_size=1.0)
|
||||
# Target is NOT on 1um grid
|
||||
start = Port(0, 0, 0)
|
||||
target = Port(10.1, 0, 0)
|
||||
path = router.route(start, target, net_width=2.0)
|
||||
path = route_astar(start, target, net_width=2.0, context=context)
|
||||
|
||||
assert path is not None
|
||||
result = RoutingResult(net_id="test", path=path, is_valid=True, collisions=0)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ 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.astar import AStarContext, route_astar
|
||||
from inire.router.cost import CostEvaluator
|
||||
from inire.router.danger_map import DangerMap
|
||||
from inire.router.pathfinder import PathFinder
|
||||
|
|
@ -19,12 +19,12 @@ def basic_evaluator() -> CostEvaluator:
|
|||
|
||||
|
||||
def test_astar_sbend(basic_evaluator: CostEvaluator) -> None:
|
||||
router = AStarRouter(basic_evaluator, snap_size=1.0, sbend_offsets=[2.0, 5.0])
|
||||
context = AStarContext(basic_evaluator, snap_size=1.0, sbend_offsets=[2.0, 5.0])
|
||||
# Start at (0,0), target at (50, 2) -> 2um lateral offset
|
||||
# This matches one of our discretized SBend offsets.
|
||||
start = Port(0, 0, 0)
|
||||
target = Port(50, 2, 0)
|
||||
path = router.route(start, target, net_width=2.0)
|
||||
path = route_astar(start, target, net_width=2.0, context=context)
|
||||
|
||||
assert path is not None
|
||||
# Check if any component in the path is an SBend
|
||||
|
|
@ -39,9 +39,9 @@ def test_astar_sbend(basic_evaluator: CostEvaluator) -> None:
|
|||
|
||||
|
||||
def test_pathfinder_negotiated_congestion_resolution(basic_evaluator: CostEvaluator) -> None:
|
||||
router = AStarRouter(basic_evaluator, snap_size=1.0, bend_radii=[5.0, 10.0])
|
||||
context = AStarContext(basic_evaluator, snap_size=1.0, bend_radii=[5.0, 10.0])
|
||||
# Increase base penalty to force detour immediately
|
||||
pf = PathFinder(router, basic_evaluator, max_iterations=10, base_congestion_penalty=1000.0)
|
||||
pf = PathFinder(context, max_iterations=10, base_congestion_penalty=1000.0)
|
||||
|
||||
netlist = {
|
||||
"net1": (Port(0, 0, 0), Port(50, 0, 0)),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import numpy
|
|||
from inire.geometry.primitives import Port
|
||||
from inire.geometry.collision import CollisionEngine
|
||||
from inire.router.cost import CostEvaluator
|
||||
from inire.router.astar import AStarRouter
|
||||
from inire.router.astar import AStarContext
|
||||
from inire.router.pathfinder import PathFinder
|
||||
from inire.router.danger_map import DangerMap
|
||||
|
||||
|
|
@ -24,12 +24,8 @@ def test_failed_net_visibility():
|
|||
evaluator = CostEvaluator(engine, dm)
|
||||
|
||||
# 2. Configure Router with low limit to FORCE failure
|
||||
# node_limit=5 is extremely low, likely allowing only a few moves.
|
||||
# node_limit=10 is extremely low, likely allowing only a few moves.
|
||||
# Start (0,0) -> Target (100,0) is 100um away.
|
||||
# If snap is 1.0, direct jump S100 might be tried.
|
||||
# If direct jump works, it might succeed in 1 expansion.
|
||||
# So we need to block the direct jump or make the limit VERY small (0?).
|
||||
# Or place a static obstacle that forces a search.
|
||||
|
||||
# Let's add a static obstacle that blocks the direct path.
|
||||
from shapely.geometry import box
|
||||
|
|
@ -38,11 +34,11 @@ def test_failed_net_visibility():
|
|||
|
||||
# With obstacle, direct jump fails. A* must search around.
|
||||
# Limit=10 should be enough to fail to find a path around.
|
||||
router = AStarRouter(evaluator, node_limit=10)
|
||||
context = AStarContext(evaluator, node_limit=10)
|
||||
|
||||
# 3. Configure PathFinder
|
||||
# max_iterations=1 because we only need to check the state after the first attempt.
|
||||
pf = PathFinder(router, evaluator, max_iterations=1, warm_start=None)
|
||||
pf = PathFinder(context, max_iterations=1, warm_start=None)
|
||||
|
||||
netlist = {
|
||||
"net1": (Port(0, 0, 0), Port(100, 0, 0))
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ 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.astar import AStarContext, route_astar
|
||||
from inire.router.cost import CostEvaluator
|
||||
from inire.router.danger_map import DangerMap
|
||||
from inire.router.pathfinder import RoutingResult
|
||||
|
|
@ -41,13 +41,12 @@ def test_fuzz_astar_no_crash(obstacles: list[Polygon], start: Port, target: Port
|
|||
danger_map.precompute(obstacles)
|
||||
|
||||
evaluator = CostEvaluator(engine, danger_map)
|
||||
router = AStarRouter(evaluator)
|
||||
router.node_limit = 5000 # Lower limit for fuzzing stability
|
||||
context = AStarContext(evaluator, node_limit=5000) # Lower limit for fuzzing stability
|
||||
|
||||
# Check if start/target are inside obstacles (safety zone check)
|
||||
# The router should handle this gracefully (either route or return None)
|
||||
try:
|
||||
path = router.route(start, target, net_width=2.0)
|
||||
path = route_astar(start, target, net_width=2.0, context=context)
|
||||
|
||||
# Analytic Correctness: if path is returned, verify it's collision-free
|
||||
if path:
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import pytest
|
|||
|
||||
from inire.geometry.collision import CollisionEngine
|
||||
from inire.geometry.primitives import Port
|
||||
from inire.router.astar import AStarRouter
|
||||
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
|
||||
|
|
@ -17,8 +17,8 @@ def basic_evaluator() -> CostEvaluator:
|
|||
|
||||
|
||||
def test_pathfinder_parallel(basic_evaluator: CostEvaluator) -> None:
|
||||
router = AStarRouter(basic_evaluator)
|
||||
pf = PathFinder(router, basic_evaluator)
|
||||
context = AStarContext(basic_evaluator)
|
||||
pf = PathFinder(context)
|
||||
|
||||
netlist = {
|
||||
"net1": (Port(0, 0, 0), Port(50, 0, 0)),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from inire.geometry.collision import CollisionEngine
|
||||
from inire.geometry.components import Bend90
|
||||
from inire.geometry.primitives import Port
|
||||
from inire.router.astar import AStarRouter
|
||||
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
|
||||
|
|
@ -29,8 +29,8 @@ def test_locked_paths() -> None:
|
|||
danger_map = DangerMap(bounds=(0, -50, 100, 50))
|
||||
danger_map.precompute([])
|
||||
evaluator = CostEvaluator(engine, danger_map)
|
||||
router = AStarRouter(evaluator, bend_radii=[5.0, 10.0])
|
||||
pf = PathFinder(router, evaluator)
|
||||
context = AStarContext(evaluator, bend_radii=[5.0, 10.0])
|
||||
pf = PathFinder(context)
|
||||
|
||||
# 1. Route Net A
|
||||
netlist_a = {"netA": (Port(0, 0, 0), Port(50, 0, 0))}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue