misc doc updates

This commit is contained in:
Jan Petykiewicz 2026-03-08 23:34:18 -07:00
commit 4714bed9a8
14 changed files with 65 additions and 28 deletions

13
DOCS.md
View file

@ -38,7 +38,18 @@ The `CostEvaluator` defines the "goodness" of a path.
--- ---
## 3. CollisionEngine Parameters ## 3. PathFinder Parameters
The `PathFinder` orchestrates multi-net routing using the Negotiated Congestion algorithm.
| Parameter | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `max_iterations` | `int` | 10 | Maximum number of rip-up and reroute iterations to resolve congestion. |
| `base_congestion_penalty` | `float` | 100.0 | Starting penalty for overlaps. This value is multiplied by `1.5` each iteration if congestion persists. |
---
## 4. CollisionEngine Parameters
| Parameter | Type | Default | Description | | Parameter | Type | Default | Description |
| :--- | :--- | :--- | :--- | | :--- | :--- | :--- | :--- |

View file

@ -39,9 +39,19 @@ danger_map = DangerMap(bounds=(0, 0, 1000, 1000))
danger_map.precompute([]) # Add polygons here for obstacles danger_map.precompute([]) # Add polygons here for obstacles
# 2. Configure Router # 2. Configure Router
evaluator = CostEvaluator(engine, danger_map) evaluator = CostEvaluator(
router = AStarRouter(evaluator) collision_engine=engine,
pf = PathFinder(router, evaluator) danger_map=danger_map,
greedy_h_weight=1.2
)
router = AStarRouter(
cost_evaluator=evaluator,
bend_penalty=10.0
)
pf = PathFinder(
router=router,
cost_evaluator=evaluator
)
# 3. Define Netlist # 3. Define Netlist
netlist = { netlist = {
@ -59,11 +69,11 @@ if results["net1"].is_valid:
Check the `examples/` directory for ready-to-run scripts demonstrating core features: Check the `examples/` directory for ready-to-run scripts demonstrating core features:
* **`examples/01_simple_route.py`**: Basic single-net routing with visualization. * **`examples/01_simple_route.py`**: Basic single-net routing with visualization. Generates `01_simple_route.png`.
* **`examples/02_congestion_resolution.py`**: Multi-net routing resolving bottlenecks using Negotiated Congestion. * **`examples/02_congestion_resolution.py`**: Multi-net routing resolving bottlenecks using Negotiated Congestion. Generates `02_congestion_resolution.png`.
* **`examples/03_locked_paths.py`**: Incremental workflow using `lock_net()` to route around previously fixed paths. * **`examples/03_locked_paths.py`**: Incremental workflow using `lock_net()` to route around previously fixed paths. Generates `03_locked_paths.png`.
* **`examples/04_sbends_and_radii.py`**: Complex paths using parametric S-bends and multiple bend radii. * **`examples/04_sbends_and_radii.py`**: Complex paths using parametric S-bends and multiple bend radii. Generates `04_sbends_and_radii.png`.
* **`examples/05_orientation_stress.py`**: Stress test for various port orientation combinations (U-turns, opposite directions). * **`examples/05_orientation_stress.py`**: Stress test for various port orientation combinations (U-turns, opposite directions). Generates `05_orientation_stress.png`.
Run an example: Run an example:
```bash ```bash
@ -79,6 +89,10 @@ python3 examples/01_simple_route.py
For multi-net problems, the **PathFinder** loop handles rip-up and reroute logic, ensuring that paths find the globally optimal configuration without crossings. For multi-net problems, the **PathFinder** loop handles rip-up and reroute logic, ensuring that paths find the globally optimal configuration without crossings.
## Configuration
`inire` is highly tunable. Every major component (Router, CostEvaluator, PathFinder) accepts explicit named arguments in its constructor to control expansion rules, cost weights, and convergence limits. See `DOCS.md` for a full parameter reference.
## License ## License
This project is licensed under the GNU Affero General Public License v3. See `LICENSE.md` for details. This project is licensed under the GNU Affero General Public License v3. See `LICENSE.md` for details.

View file

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Before After
Before After

View file

@ -50,8 +50,8 @@ def main() -> None:
# 5. Visualize # 5. Visualize
fig, ax = plot_routing_results(results, [obstacle], bounds, netlist=netlist) fig, ax = plot_routing_results(results, [obstacle], bounds, netlist=netlist)
fig.savefig("examples/simple_route.png") fig.savefig("examples/01_simple_route.png")
print("Saved plot to examples/simple_route.png") print("Saved plot to examples/01_simple_route.png")
if __name__ == "__main__": if __name__ == "__main__":

View file

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Before After
Before After

View file

@ -32,7 +32,7 @@ def main() -> None:
# 3. Route with Negotiated Congestion # 3. Route with Negotiated Congestion
# We increase the base penalty to encourage faster divergence # We increase the base penalty to encourage faster divergence
pf.base_congestion_penalty = 1000.0 pf = PathFinder(router, evaluator, base_congestion_penalty=1000.0)
results = pf.route_all(netlist, net_widths) results = pf.route_all(netlist, net_widths)
# 4. Check Results # 4. Check Results
@ -46,8 +46,8 @@ def main() -> None:
# 5. Visualize # 5. Visualize
fig, ax = plot_routing_results(results, [], bounds, netlist=netlist) fig, ax = plot_routing_results(results, [], bounds, netlist=netlist)
fig.savefig("examples/congestion.png") fig.savefig("examples/02_congestion_resolution.png")
print("Saved plot to examples/congestion.png") print("Saved plot to examples/02_congestion_resolution.png")
if __name__ == "__main__": if __name__ == "__main__":

View file

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Before After
Before After

View file

@ -65,8 +65,8 @@ def main() -> None:
all_netlists = {**netlist_p1, **netlist_p2} all_netlists = {**netlist_p1, **netlist_p2}
fig, ax = plot_routing_results(all_results, [], bounds, netlist=all_netlists) fig, ax = plot_routing_results(all_results, [], bounds, netlist=all_netlists)
fig.savefig("examples/locked.png") fig.savefig("examples/03_locked_paths.png")
print("Saved plot to examples/locked.png") print("Saved plot to examples/03_locked_paths.png")
if __name__ == "__main__": if __name__ == "__main__":

View file

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Before After
Before After

View file

@ -61,8 +61,8 @@ def main() -> None:
# 6. Visualize # 6. Visualize
fig, ax = plot_routing_results(results, [], bounds, netlist=netlist) fig, ax = plot_routing_results(results, [], bounds, netlist=netlist)
fig.savefig("examples/sbends_radii.png") fig.savefig("examples/04_sbends_and_radii.png")
print("Saved plot to examples/sbends_radii.png") print("Saved plot to examples/04_sbends_and_radii.png")
if __name__ == "__main__": if __name__ == "__main__":

View file

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Before After
Before After

View file

@ -48,8 +48,8 @@ def main() -> None:
# 5. Visualize # 5. Visualize
fig, ax = plot_routing_results(results, [], bounds, netlist=netlist) fig, ax = plot_routing_results(results, [], bounds, netlist=netlist)
fig.savefig("examples/orientation_stress.png") fig.savefig("examples/05_orientation_stress.png")
print("Saved plot to examples/orientation_stress.png") print("Saved plot to examples/05_orientation_stress.png")
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -25,11 +25,26 @@ class RoutingResult:
class PathFinder: class PathFinder:
"""Multi-net router using Negotiated Congestion.""" """Multi-net router using Negotiated Congestion."""
def __init__(self, router: AStarRouter, cost_evaluator: CostEvaluator) -> None: def __init__(
self,
router: AStarRouter,
cost_evaluator: CostEvaluator,
max_iterations: int = 10,
base_congestion_penalty: float = 100.0,
) -> None:
"""
Initialize the PathFinder.
Args:
router: The A* search engine.
cost_evaluator: The evaluator for path costs.
max_iterations: Maximum number of rip-up and reroute iterations.
base_congestion_penalty: Starting penalty for overlaps.
"""
self.router = router self.router = router
self.cost_evaluator = cost_evaluator self.cost_evaluator = cost_evaluator
self.max_iterations = 10 self.max_iterations = max_iterations
self.base_congestion_penalty = 100.0 self.base_congestion_penalty = base_congestion_penalty
def route_all(self, netlist: dict[str, tuple[Port, Port]], net_widths: dict[str, float]) -> dict[str, RoutingResult]: def route_all(self, netlist: dict[str, tuple[Port, Port]], net_widths: dict[str, float]) -> dict[str, RoutingResult]:
"""Route all nets in the netlist using Negotiated Congestion.""" """Route all nets in the netlist using Negotiated Congestion."""

View file

@ -40,8 +40,8 @@ def test_astar_sbend(basic_evaluator: CostEvaluator) -> None:
def test_pathfinder_negotiated_congestion_resolution(basic_evaluator: CostEvaluator) -> None: def test_pathfinder_negotiated_congestion_resolution(basic_evaluator: CostEvaluator) -> None:
router = AStarRouter(basic_evaluator) router = AStarRouter(basic_evaluator)
pf = PathFinder(router, basic_evaluator) # Increase base penalty to force detour immediately
pf.max_iterations = 10 pf = PathFinder(router, basic_evaluator, max_iterations=10, base_congestion_penalty=1000.0)
netlist = { netlist = {
"net1": (Port(0, 0, 0), Port(50, 0, 0)), "net1": (Port(0, 0, 0), Port(50, 0, 0)),
@ -57,9 +57,6 @@ def test_pathfinder_negotiated_congestion_resolution(basic_evaluator: CostEvalua
basic_evaluator.collision_engine.add_static_obstacle(obs_bottom) basic_evaluator.collision_engine.add_static_obstacle(obs_bottom)
basic_evaluator.danger_map.precompute([obs_top, obs_bottom]) basic_evaluator.danger_map.precompute([obs_top, obs_bottom])
# Increase base penalty to force detour immediately
pf.base_congestion_penalty = 1000.0
results = pf.route_all(netlist, net_widths) results = pf.route_all(netlist, net_widths)
assert results["net1"].is_valid assert results["net1"].is_valid