diff --git a/examples/02_congestion_resolution.py b/examples/02_congestion_resolution.py index 520c631..0cb4b0e 100644 --- a/examples/02_congestion_resolution.py +++ b/examples/02_congestion_resolution.py @@ -1,4 +1,3 @@ - from inire.geometry.collision import CollisionEngine from inire.geometry.primitives import Port from inire.router.astar import AStarRouter @@ -9,7 +8,7 @@ from inire.utils.visualization import plot_routing_results def main() -> None: - print("Running Example 02: Congestion Resolution (Crossing)...") + print("Running Example 02: Congestion Resolution (Triple Crossing)...") # 1. Setup Environment (Open space) bounds = (0, 0, 100, 100) @@ -22,23 +21,24 @@ def main() -> None: pf = PathFinder(router, evaluator) # 2. Define Netlist - # Two nets that MUST cross. - # Since crossings are illegal in single-layer routing, one net must detour around the other. + # Three nets that all converge on the same central area. + # Negotiated Congestion must find non-overlapping paths for all of them. netlist = { "horizontal": (Port(10, 50, 0), Port(90, 50, 0)), - "vertical": (Port(50, 10, 90), Port(50, 90, 90)), + "vertical_up": (Port(45, 10, 90), Port(45, 90, 90)), + "vertical_down": (Port(55, 90, 270), Port(55, 10, 270)), } - net_widths = {"horizontal": 2.0, "vertical": 2.0} + net_widths = {nid: 2.0 for nid in netlist} # 3. Route with Negotiated Congestion # We increase the base penalty to encourage faster divergence - pf.base_congestion_penalty = 500.0 + pf.base_congestion_penalty = 1000.0 results = pf.route_all(netlist, net_widths) # 4. Check Results all_valid = all(r.is_valid for r in results.values()) if all_valid: - print("Success! Congestion resolved (one net detoured).") + print("Success! Congestion resolved for all nets.") else: print("Some nets failed or have collisions.") for nid, res in results.items(): diff --git a/examples/03_locked_paths.py b/examples/03_locked_paths.py index ace3bb6..d01aec1 100644 --- a/examples/03_locked_paths.py +++ b/examples/03_locked_paths.py @@ -1,4 +1,3 @@ - from inire.geometry.collision import CollisionEngine from inire.geometry.primitives import Port from inire.router.astar import AStarRouter @@ -9,68 +8,64 @@ from inire.utils.visualization import plot_routing_results def main() -> None: - print("Running Example 03: Locked Paths (Incremental Routing)...") + print("Running Example 03: Locked Paths (Incremental Routing - Bus Scenario)...") # 1. Setup Environment - bounds = (0, 0, 100, 100) + bounds = (0, 0, 120, 120) engine = CollisionEngine(clearance=2.0) danger_map = DangerMap(bounds=bounds) - danger_map.precompute([]) # No initial obstacles + danger_map.precompute([]) # Start with empty space - evaluator = CostEvaluator(engine, danger_map) - router = AStarRouter(evaluator) + evaluator = CostEvaluator(engine, danger_map, greedy_h_weight=1.2) + router = AStarRouter(evaluator, node_limit=200000) pf = PathFinder(router, evaluator) - # 2. Phase 1: Route a "Critical" Net - # This net gets priority and takes the best path. - netlist_phase1 = { - "critical_net": (Port(10, 50, 0), Port(90, 50, 0)), + # 2. Phase 1: Route a "Bus" of 3 parallel nets + # We give them a small jog to make the locked geometry more interesting + netlist_p1 = { + "bus_0": (Port(10, 40, 0), Port(110, 45, 0)), + "bus_1": (Port(10, 50, 0), Port(110, 55, 0)), + "bus_2": (Port(10, 60, 0), Port(110, 65, 0)), } - print("Phase 1: Routing critical_net...") - results1 = pf.route_all(netlist_phase1, {"critical_net": 3.0}) # Wider trace + print("Phase 1: Routing bus (3 nets)...") + results_p1 = pf.route_all(netlist_p1, {nid: 2.0 for nid in netlist_p1}) - if not results1["critical_net"].is_valid: - print("Error: Phase 1 failed.") - return + # Lock all Phase 1 nets + path_polys = [] + for nid, res in results_p1.items(): + if res.is_valid: + print(f" Locking {nid}...") + engine.lock_net(nid) + path_polys.extend([p for comp in res.path for p in comp.geometry]) + else: + print(f" Warning: {nid} failed to route correctly.") - # 3. Lock the Critical Net - # This converts the dynamic path into a static obstacle in the collision engine. - print("Locking critical_net...") - engine.lock_net("critical_net") - - # Update danger map to reflect the new obstacle (optional but recommended for heuristics) - # Extract polygons from result - path_polys = [p for comp in results1["critical_net"].path for p in comp.geometry] + # Update danger map with the newly locked geometry + print("Updating DangerMap with locked paths...") danger_map.precompute(path_polys) - # 4. Phase 2: Route a Secondary Net - # This net must route *around* the locked critical_net. - # Start and end points force a crossing path if it were straight. - netlist_phase2 = { - "secondary_net": (Port(50, 10, 90), Port(50, 90, 90)), + # 3. Phase 2: Route secondary nets that must navigate around the locked bus + # These nets cross the bus vertically. + netlist_p2 = { + "cross_left": (Port(30, 10, 90), Port(30, 110, 90)), + "cross_right": (Port(80, 110, 270), Port(80, 10, 270)), # Top to bottom } + + print("Phase 2: Routing crossing nets around locked bus...") + # We use a slightly different width for variety + results_p2 = pf.route_all(netlist_p2, {nid: 1.5 for nid in netlist_p2}) - print("Phase 2: Routing secondary_net around locked path...") - results2 = pf.route_all(netlist_phase2, {"secondary_net": 2.0}) - - if results2["secondary_net"].is_valid: - print("Success! Secondary net routed around locked path.") - else: - print("Failed to route secondary net.") + # 4. Check Results + for nid, res in results_p2.items(): + status = "Success" if res.is_valid else "Failed" + print(f" {nid:12}: {status}, collisions={res.collisions}") # 5. Visualize - # Combine results and netlists for plotting - all_results = {**results1, **results2} - all_netlists = {**netlist_phase1, **netlist_phase2} - - # Note: 'critical_net' is now in engine.static_obstacles internally, - # but for visualization we plot it from the result object to see it clearly. - # We pass an empty list for 'static_obstacles' to plot_routing_results - # because we want to see the path colored, not grayed out as an obstacle. + all_results = {**results_p1, **results_p2} + all_netlists = {**netlist_p1, **netlist_p2} fig, ax = plot_routing_results(all_results, [], bounds, netlist=all_netlists) fig.savefig("examples/locked.png") - print("Saved plot to examples/locked.png") diff --git a/examples/congestion.png b/examples/congestion.png index 775d78b..509e11a 100644 Binary files a/examples/congestion.png and b/examples/congestion.png differ diff --git a/examples/locked.png b/examples/locked.png index 8c45ebf..0fbcf32 100644 Binary files a/examples/locked.png and b/examples/locked.png differ diff --git a/examples/simple_route.png b/examples/simple_route.png index 400488d..98f7b4b 100644 Binary files a/examples/simple_route.png and b/examples/simple_route.png differ