misc doc updates
13
DOCS.md
|
|
@ -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 |
|
||||||
| :--- | :--- | :--- | :--- |
|
| :--- | :--- | :--- | :--- |
|
||||||
|
|
|
||||||
30
README.md
|
|
@ -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.
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
|
@ -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__":
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
|
|
@ -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__":
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
|
|
@ -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__":
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
|
|
@ -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__":
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
|
|
@ -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__":
|
||||||
|
|
|
||||||
|
|
@ -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."""
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||