diff --git a/DOCS.md b/DOCS.md index d70cd8c..2534a17 100644 --- a/DOCS.md +++ b/DOCS.md @@ -128,65 +128,8 @@ Use `RoutingProblem.initial_paths` to provide semantic per-net seeds. Seeds are | Field | Default | Description | | :-- | :-- | :-- | | `capture_expanded` | `False` | Record expanded nodes for diagnostics and visualization. | -| `capture_conflict_trace` | `False` | Capture authoritative post-reverify conflict trace entries for debugging negotiated-congestion failures. | -| `capture_frontier_trace` | `False` | Run an analysis-only reroute for reached-but-colliding nets and capture prune causes near their final conflict hotspots. | -## 7. Conflict Trace - -`RoutingRunResult.conflict_trace` is an immutable tuple of post-reverify conflict snapshots. It is empty unless `RoutingOptions.diagnostics.capture_conflict_trace=True`. - -Trace types: - -- `ConflictTraceEntry` - - `stage`: `"iteration"`, `"restored_best"`, or `"final"` - - `iteration`: Iteration index for `"iteration"` entries, otherwise `None` - - `completed_net_ids`: Nets with collision-free reached-target paths at that stage - - `conflict_edges`: Undirected dynamic-conflict net pairs seen after full reverify - - `nets`: Per-net trace payloads in routing-order order -- `NetConflictTrace` - - `net_id` - - `outcome` - - `reached_target` - - `report` - - `conflicting_net_ids`: Dynamic conflicting nets for that stage - - `component_conflicts`: Dynamic component-pair overlaps for that stage -- `ComponentConflictTrace` - - `other_net_id` - - `self_component_index` - - `other_component_index` - -The conflict trace only records dynamic net-vs-net component overlaps. Static-obstacle and self-collision details remain count-only in `RoutingReport`. - -Use `scripts/record_conflict_trace.py` to capture JSON and Markdown trace artifacts for the built-in trace scenarios. The default target is `example_07_large_scale_routing_no_warm_start`. - -## 8. Frontier Trace - -`RoutingRunResult.frontier_trace` is an immutable tuple of per-net post-run frontier analyses. It is empty unless `RoutingOptions.diagnostics.capture_frontier_trace=True`. - -Trace types: - -- `NetFrontierTrace` - - `net_id` - - `hotspot_bounds`: Buffered bounds around the net's final dynamic component-overlap hotspots - - `pruned_closed_set` - - `pruned_hard_collision` - - `pruned_self_collision` - - `pruned_cost` - - `samples`: First traced prune events near those hotspots -- `FrontierPruneSample` - - `reason`: `"closed_set"`, `"hard_collision"`, `"self_collision"`, or `"cost"` - - `move_type` - - `hotspot_index` - - `parent_state` - - `end_state` - -The frontier trace is observational only. It reruns only the final reached-but-colliding nets in analysis mode, with scratch metrics, after the routed result is already fixed. - -Use `scripts/record_frontier_trace.py` to capture JSON and Markdown frontier-prune artifacts for the built-in trace scenarios. The default target is `example_07_large_scale_routing_no_warm_start`. - -Separately from the observational trace tooling, the router may run a bounded post-loop pair-local scratch reroute before refinement when the restored best snapshot ends with final two-net reached-target dynamic conflicts. That repair phase is part of normal routing behavior and is reported through the `pair_local_search_*` counters below. - -## 9. RouteMetrics +## 7. RouteMetrics `RoutingRunResult.metrics` is an immutable per-run snapshot. @@ -205,20 +148,11 @@ Separately from the observational trace tooling, the router may run a bounded po - `warm_start_paths_used`: Number of routing attempts satisfied directly from an initial or warm-start path. - `refine_path_calls`: Number of completed paths passed through the post-route refiner. - `timeout_events`: Number of timeout exits encountered during the run. -- `iteration_reverify_calls`: Number of end-of-iteration full reverify passes against the final installed dynamic geometry. -- `iteration_reverified_nets`: Number of reached-target nets reverified at iteration boundaries. -- `iteration_conflicting_nets`: Total unique nets found in end-of-iteration dynamic conflicts. -- `iteration_conflict_edges`: Total undirected dynamic-conflict edges observed at iteration boundaries. -- `nets_carried_forward`: Number of nets retained unchanged between iterations. ### Cache Counters - `move_cache_abs_hits` / `move_cache_abs_misses`: Absolute move-geometry cache activity. - `move_cache_rel_hits` / `move_cache_rel_misses`: Relative move-geometry cache activity. -- `guidance_match_moves`: Number of moves that matched the reroute guidance seed and received the guidance bonus. -- `guidance_match_moves_straight`, `guidance_match_moves_bend90`, `guidance_match_moves_sbend`: Guidance-match counts split by move type. -- `guidance_bonus_applied`: Total reroute-guidance bonus subtracted from move costs across the run. -- `guidance_bonus_applied_straight`, `guidance_bonus_applied_bend90`, `guidance_bonus_applied_sbend`: Guidance bonus totals split by move type. - `static_safe_cache_hits`: Reuse count for the static-safe admission cache. - `hard_collision_cache_hits`: Reuse count for the hard-collision cache. - `congestion_cache_hits` / `congestion_cache_misses`: Per-search congestion-cache activity. @@ -231,50 +165,29 @@ Separately from the observational trace tooling, the router may run a bounded po - `static_tree_rebuilds`: Number of static dilated-obstacle STRtree rebuilds. - `static_raw_tree_rebuilds`: Number of raw static-obstacle STRtree rebuilds used for verification. - `static_net_tree_rebuilds`: Number of net-width-specific static STRtree rebuilds. -- `visibility_corner_index_builds`: Number of lazy corner-index rebuilds. -- `visibility_builds`: Number of exact corner-visibility graph rebuilds. -- `visibility_corner_pairs_checked`: Number of corner-pair visibility probes considered while building the exact graph. -- `visibility_corner_queries_exact` / `visibility_corner_hits_exact`: Exact-corner visibility query activity. +- `visibility_builds`: Number of static visibility-graph rebuilds. +- `visibility_corner_pairs_checked`: Number of corner-pair visibility probes considered while building that graph. +- `visibility_corner_queries` / `visibility_corner_hits`: Precomputed-corner visibility query activity. - `visibility_point_queries`, `visibility_point_cache_hits`, `visibility_point_cache_misses`: Arbitrary-point visibility query and cache activity. - `ray_cast_calls`: Number of ray-cast queries issued against static obstacles. - `ray_cast_candidate_bounds`: Total broad-phase candidate bounds considered by ray casts. - `ray_cast_exact_geometry_checks`: Total exact non-rectangular geometry checks performed by ray casts. - `congestion_check_calls`: Number of congestion broad-phase checks requested by search. -- `congestion_presence_cache_hits` / `congestion_presence_cache_misses`: Reuse of cached per-span booleans indicating whether a move polygon could overlap any other routed net at all. -- `congestion_presence_skips`: Number of moves that bypassed full congestion evaluation because the presence precheck found no other routed nets in any covered dynamic-grid span. -- `congestion_candidate_precheck_hits` / `congestion_candidate_precheck_misses`: Reuse of cached conservative per-span booleans indicating whether any candidate nets survive the net-envelope and grid-net broad phases. -- `congestion_candidate_precheck_skips`: Number of moves that bypassed full congestion evaluation because the candidate-net precheck found no surviving candidate nets after those broad phases. -- `congestion_candidate_nets`: Total candidate net ids returned by the dynamic net-envelope broad phase during routing. -- `congestion_net_envelope_cache_hits` / `congestion_net_envelope_cache_misses`: Reuse of cached dynamic net-envelope candidate sets keyed by the queried grid-cell span. -- `congestion_grid_net_cache_hits` / `congestion_grid_net_cache_misses`: Reuse of cached per-span candidate net ids gathered from dynamic grid occupancy. -- `congestion_grid_span_cache_hits` / `congestion_grid_span_cache_misses`: Reuse of cached dynamic-path candidate unions keyed by the queried grid-cell span. -- `congestion_lazy_resolutions`: Number of popped nodes whose pending congestion was resolved lazily. -- `congestion_lazy_requeues`: Number of lazily resolved nodes requeued after a positive congestion penalty was applied. -- `congestion_candidate_ids`: Total dynamic-path object ids returned by the congestion broad phase before exact confirmation. - `congestion_exact_pair_checks`: Number of exact geometry-pair checks performed while confirming congestion hits. ### Verification Counters - `verify_path_report_calls`: Number of full path-verification passes. - `verify_static_buffer_ops`: Number of static-verification `buffer()` operations. -- `verify_dynamic_candidate_nets`: Total candidate net ids returned by the dynamic net-envelope broad phase during final verification. - `verify_dynamic_exact_pair_checks`: Number of exact geometry-pair checks performed during dynamic-path verification. -### Local Search Counters - -- `pair_local_search_pairs_considered`: Number of final reached-target conflict pairs considered by the bounded post-loop pair-local-search phase. -- `pair_local_search_attempts`: Number of pair-local-search reroute attempts executed across all considered pairs. -- `pair_local_search_accepts`: Number of pair-local-search attempts accepted into the whole routed result set. -- `pair_local_search_nodes_expanded`: Total A* node expansions spent inside pair-local-search attempts. - -## 10. Internal Modules +## 8. Internal Modules Lower-level search and collision modules are semi-private implementation details. They remain accessible through deep imports for advanced use, but they are unstable and may change without notice. The stable supported entrypoint is `route(problem, options=...)`. The current implementation structure is summarized in **[docs/architecture.md](docs/architecture.md)**. The committed example-corpus counter baseline is tracked in **[docs/performance.md](docs/performance.md)**. -Use `scripts/diff_performance_baseline.py` to compare a fresh local run against that baseline. Use `scripts/record_conflict_trace.py` for opt-in conflict-hotspot traces, `scripts/record_frontier_trace.py` for hotspot-adjacent prune traces, and `scripts/characterize_pair_local_search.py` to sweep example_07-style no-warm runs for pair-local repair behavior. The counter baseline is currently observational and is not enforced as a CI gate. -## 11. Tuning Notes +## 9. Tuning Notes ### Speed vs. optimality diff --git a/docs/architecture.md b/docs/architecture.md index 5e147d1..3855199 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -16,7 +16,7 @@ - `inire/geometry/primitives.py`: Integer Manhattan ports and small transform helpers. - `inire/geometry/components.py`: `Straight`, `Bend90`, and `SBend` geometry generation. - `inire/geometry/collision.py`: Routing-world collision, congestion, ray-cast, and path-verification logic. -- `inire/geometry/static_obstacle_index.py` and `inire/geometry/dynamic_path_index.py`: Spatial-index management for static obstacles and routed paths, including dynamic per-object indices, per-net grid occupancy, congestion grid membership, and per-net dynamic envelopes. +- `inire/geometry/static_obstacle_index.py` and `inire/geometry/dynamic_path_index.py`: Spatial-index management for static obstacles and routed paths. - `inire/router/_search.py`, `_astar_moves.py`, `_astar_admission.py`, `_astar_types.py`: The state-lattice A* search loop and move admission pipeline. - `inire/router/_router.py`: The negotiated-congestion driver and refinement orchestration. - `inire/router/refiner.py`: Post-route path simplification for completed paths. @@ -39,10 +39,7 @@ The search state is a snapped Manhattan `(x, y, r)` port. From each state the ro - Static obstacles and routed paths are treated as single-layer geometry; automatic crossings are not supported. - The danger-map implementation uses sampled obstacle-boundary points and a KD-tree, not a dense distance-transform grid. -- The visibility subsystem keeps a lazy static corner index for default `tangent_corner` guidance and only builds the exact corner-to-corner graph on demand for `exact_corner` queries. - `use_tiered_strategy` can swap in a cheaper bend proxy on the first congestion iteration. -- Negotiated congestion now re-verifies every reached-target path at the end of each iteration against the final installed dynamic geometry, and it stops early if the conflict graph stalls for consecutive iterations. -- After best-snapshot restoration, the router runs a bounded pair-local scratch reroute on final two-net reached-target conflict pairs. That repair phase clones static obstacles from the live collision world, treats all outside-pair geometry as fixed blockers, tries both pair orders, and only keeps the result if whole-set reverify improves. - Final `RoutingResult` validity is determined by explicit post-route verification, not only by search-time pruning. ## Performance Visibility diff --git a/docs/conflict_trace.json b/docs/conflict_trace.json deleted file mode 100644 index 90fc817..0000000 --- a/docs/conflict_trace.json +++ /dev/null @@ -1,2533 +0,0 @@ -{ - "generated_at": "2026-04-02T14:24:39-07:00", - "generator": "scripts/record_conflict_trace.py", - "scenarios": [ - { - "conflict_trace": [ - { - "completed_net_ids": [ - "net_04" - ], - "conflict_edges": [ - [ - "net_00", - "net_01" - ], - [ - "net_00", - "net_02" - ], - [ - "net_00", - "net_03" - ], - [ - "net_00", - "net_04" - ], - [ - "net_01", - "net_02" - ], - [ - "net_01", - "net_03" - ], - [ - "net_02", - "net_03" - ], - [ - "net_03", - "net_04" - ], - [ - "net_05", - "net_06" - ], - [ - "net_05", - "net_09" - ], - [ - "net_06", - "net_07" - ], - [ - "net_06", - "net_08" - ], - [ - "net_06", - "net_09" - ], - [ - "net_07", - "net_08" - ], - [ - "net_07", - "net_09" - ], - [ - "net_08", - "net_09" - ] - ], - "iteration": 0, - "nets": [ - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_06", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_07", - "self_component_index": 1 - }, - { - "other_component_index": 0, - "other_net_id": "net_09", - "self_component_index": 1 - }, - { - "other_component_index": 2, - "other_net_id": "net_06", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_07", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_09", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_06", - "net_07", - "net_09" - ], - "net_id": "net_08", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 6, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1138.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_05", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_07", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_08", - "self_component_index": 1 - }, - { - "other_component_index": 0, - "other_net_id": "net_09", - "self_component_index": 1 - }, - { - "other_component_index": 2, - "other_net_id": "net_07", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_08", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_07", - "self_component_index": 3 - }, - { - "other_component_index": 2, - "other_net_id": "net_08", - "self_component_index": 3 - }, - { - "other_component_index": 2, - "other_net_id": "net_09", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_05", - "net_07", - "net_08", - "net_09" - ], - "net_id": "net_06", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 9, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 980.0796326794897 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 0, - "other_net_id": "net_00", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_01", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_02", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_04", - "self_component_index": 1 - }, - { - "other_component_index": 2, - "other_net_id": "net_02", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_00", - "self_component_index": 3 - }, - { - "other_component_index": 2, - "other_net_id": "net_01", - "self_component_index": 3 - }, - { - "other_component_index": 2, - "other_net_id": "net_02", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_00", - "net_01", - "net_02", - "net_04" - ], - "net_id": "net_03", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 8, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 970.0796326794897 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_01", - "self_component_index": 0 - }, - { - "other_component_index": 1, - "other_net_id": "net_02", - "self_component_index": 0 - }, - { - "other_component_index": 1, - "other_net_id": "net_03", - "self_component_index": 0 - }, - { - "other_component_index": 1, - "other_net_id": "net_04", - "self_component_index": 1 - } - ], - "conflicting_net_ids": [ - "net_01", - "net_02", - "net_03", - "net_04" - ], - "net_id": "net_00", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 4, - "self_collision_count": 1, - "static_collision_count": 0, - "total_length": 1621.236812357892 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_06", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_08", - "self_component_index": 1 - }, - { - "other_component_index": 0, - "other_net_id": "net_09", - "self_component_index": 1 - }, - { - "other_component_index": 2, - "other_net_id": "net_06", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_08", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_08", - "self_component_index": 3 - }, - { - "other_component_index": 2, - "other_net_id": "net_09", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_06", - "net_08", - "net_09" - ], - "net_id": "net_07", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 7, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1059.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 0, - "other_net_id": "net_00", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_02", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_03", - "self_component_index": 1 - }, - { - "other_component_index": 2, - "other_net_id": "net_02", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_00", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_00", - "net_02", - "net_03" - ], - "net_id": "net_01", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 5, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1128.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_06", - "self_component_index": 0 - }, - { - "other_component_index": 1, - "other_net_id": "net_07", - "self_component_index": 0 - }, - { - "other_component_index": 1, - "other_net_id": "net_08", - "self_component_index": 0 - } - ], - "conflicting_net_ids": [ - "net_06", - "net_07", - "net_08" - ], - "net_id": "net_09", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 3, - "self_collision_count": 1, - "static_collision_count": 0, - "total_length": 1631.236812357892 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 0, - "other_net_id": "net_00", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_01", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_03", - "self_component_index": 1 - }, - { - "other_component_index": 2, - "other_net_id": "net_01", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_03", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_00", - "self_component_index": 3 - }, - { - "other_component_index": 2, - "other_net_id": "net_01", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_00", - "net_01", - "net_03" - ], - "net_id": "net_02", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 7, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1049.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_04", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 909.9977565924808 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_09", - "self_component_index": 1 - } - ], - "conflicting_net_ids": [ - "net_09" - ], - "net_id": "net_05", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 1, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 914.6410526793834 - } - } - ], - "stage": "iteration" - }, - { - "completed_net_ids": [ - "net_04", - "net_05" - ], - "conflict_edges": [ - [ - "net_00", - "net_01" - ], - [ - "net_00", - "net_02" - ], - [ - "net_00", - "net_03" - ], - [ - "net_01", - "net_02" - ], - [ - "net_01", - "net_03" - ], - [ - "net_02", - "net_03" - ], - [ - "net_06", - "net_07" - ], - [ - "net_06", - "net_08" - ], - [ - "net_06", - "net_09" - ], - [ - "net_07", - "net_08" - ], - [ - "net_07", - "net_09" - ], - [ - "net_08", - "net_09" - ] - ], - "iteration": 1, - "nets": [ - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_04", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 909.9977565924808 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 0, - "other_net_id": "net_07", - "self_component_index": 2 - }, - { - "other_component_index": 0, - "other_net_id": "net_08", - "self_component_index": 2 - }, - { - "other_component_index": 0, - "other_net_id": "net_09", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_07", - "self_component_index": 5 - }, - { - "other_component_index": 2, - "other_net_id": "net_08", - "self_component_index": 5 - }, - { - "other_component_index": 2, - "other_net_id": "net_09", - "self_component_index": 5 - } - ], - "conflicting_net_ids": [ - "net_07", - "net_08", - "net_09" - ], - "net_id": "net_06", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 6, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 980.0796326794897 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 2, - "other_net_id": "net_03", - "self_component_index": 0 - }, - { - "other_component_index": 1, - "other_net_id": "net_00", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_02", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_00", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_02", - "self_component_index": 2 - }, - { - "other_component_index": 5, - "other_net_id": "net_03", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_00", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_00", - "net_02", - "net_03" - ], - "net_id": "net_01", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 7, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1128.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 2, - "other_net_id": "net_06", - "self_component_index": 0 - }, - { - "other_component_index": 1, - "other_net_id": "net_07", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_08", - "self_component_index": 1 - }, - { - "other_component_index": 5, - "other_net_id": "net_06", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_07", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_08", - "self_component_index": 2 - } - ], - "conflicting_net_ids": [ - "net_06", - "net_07", - "net_08" - ], - "net_id": "net_09", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 6, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1217.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_05", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 914.6410526793834 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 2, - "other_net_id": "net_03", - "self_component_index": 0 - }, - { - "other_component_index": 1, - "other_net_id": "net_00", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_01", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_00", - "self_component_index": 2 - }, - { - "other_component_index": 1, - "other_net_id": "net_01", - "self_component_index": 2 - }, - { - "other_component_index": 5, - "other_net_id": "net_03", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_00", - "self_component_index": 3 - }, - { - "other_component_index": 2, - "other_net_id": "net_01", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_00", - "net_01", - "net_03" - ], - "net_id": "net_02", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 8, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1049.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 2, - "other_net_id": "net_03", - "self_component_index": 0 - }, - { - "other_component_index": 1, - "other_net_id": "net_01", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_02", - "self_component_index": 1 - }, - { - "other_component_index": 2, - "other_net_id": "net_01", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_02", - "self_component_index": 2 - }, - { - "other_component_index": 5, - "other_net_id": "net_03", - "self_component_index": 2 - } - ], - "conflicting_net_ids": [ - "net_01", - "net_02", - "net_03" - ], - "net_id": "net_00", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 6, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1207.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 0, - "other_net_id": "net_00", - "self_component_index": 2 - }, - { - "other_component_index": 0, - "other_net_id": "net_01", - "self_component_index": 2 - }, - { - "other_component_index": 0, - "other_net_id": "net_02", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_00", - "self_component_index": 5 - }, - { - "other_component_index": 2, - "other_net_id": "net_01", - "self_component_index": 5 - }, - { - "other_component_index": 2, - "other_net_id": "net_02", - "self_component_index": 5 - } - ], - "conflicting_net_ids": [ - "net_00", - "net_01", - "net_02" - ], - "net_id": "net_03", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 6, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 970.0796326794897 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 2, - "other_net_id": "net_06", - "self_component_index": 0 - }, - { - "other_component_index": 1, - "other_net_id": "net_08", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_09", - "self_component_index": 1 - }, - { - "other_component_index": 5, - "other_net_id": "net_06", - "self_component_index": 2 - }, - { - "other_component_index": 1, - "other_net_id": "net_08", - "self_component_index": 2 - }, - { - "other_component_index": 1, - "other_net_id": "net_09", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_08", - "self_component_index": 3 - }, - { - "other_component_index": 2, - "other_net_id": "net_09", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_06", - "net_08", - "net_09" - ], - "net_id": "net_07", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 8, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1059.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 2, - "other_net_id": "net_06", - "self_component_index": 0 - }, - { - "other_component_index": 1, - "other_net_id": "net_07", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_09", - "self_component_index": 1 - }, - { - "other_component_index": 5, - "other_net_id": "net_06", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_07", - "self_component_index": 2 - }, - { - "other_component_index": 1, - "other_net_id": "net_09", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_09", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_06", - "net_07", - "net_09" - ], - "net_id": "net_08", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 7, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1138.0796326794896 - } - } - ], - "stage": "iteration" - }, - { - "completed_net_ids": [ - "net_04", - "net_05", - "net_08", - "net_09" - ], - "conflict_edges": [ - [ - "net_00", - "net_01" - ], - [ - "net_00", - "net_02" - ], - [ - "net_00", - "net_03" - ], - [ - "net_01", - "net_02" - ], - [ - "net_06", - "net_07" - ] - ], - "iteration": 2, - "nets": [ - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_05", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 914.6410526793834 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 0, - "other_net_id": "net_00", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_01", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_01", - "self_component_index": 3 - }, - { - "other_component_index": 3, - "other_net_id": "net_01", - "self_component_index": 4 - }, - { - "other_component_index": 2, - "other_net_id": "net_00", - "self_component_index": 5 - } - ], - "conflicting_net_ids": [ - "net_00", - "net_01" - ], - "net_id": "net_02", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 5, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1049.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_04", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 909.9977565924808 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 0, - "other_net_id": "net_00", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_02", - "self_component_index": 2 - }, - { - "other_component_index": 3, - "other_net_id": "net_02", - "self_component_index": 3 - }, - { - "other_component_index": 2, - "other_net_id": "net_00", - "self_component_index": 5 - } - ], - "conflicting_net_ids": [ - "net_00", - "net_02" - ], - "net_id": "net_01", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 4, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1128.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_08", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1138.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_09", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1217.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_00", - "self_component_index": 2 - }, - { - "other_component_index": 1, - "other_net_id": "net_00", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_00" - ], - "net_id": "net_03", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 2, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 970.0796326794897 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_07", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_07", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_07", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_07" - ], - "net_id": "net_06", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 3, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 980.0796326794897 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_06", - "self_component_index": 1 - }, - { - "other_component_index": 2, - "other_net_id": "net_06", - "self_component_index": 2 - } - ], - "conflicting_net_ids": [ - "net_06" - ], - "net_id": "net_07", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 2, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1059.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 2, - "other_net_id": "net_01", - "self_component_index": 0 - }, - { - "other_component_index": 2, - "other_net_id": "net_02", - "self_component_index": 0 - }, - { - "other_component_index": 2, - "other_net_id": "net_03", - "self_component_index": 1 - }, - { - "other_component_index": 5, - "other_net_id": "net_01", - "self_component_index": 2 - }, - { - "other_component_index": 5, - "other_net_id": "net_02", - "self_component_index": 2 - }, - { - "other_component_index": 3, - "other_net_id": "net_03", - "self_component_index": 2 - } - ], - "conflicting_net_ids": [ - "net_01", - "net_02", - "net_03" - ], - "net_id": "net_00", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 6, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1207.0796326794896 - } - } - ], - "stage": "iteration" - }, - { - "completed_net_ids": [ - "net_02", - "net_03", - "net_04", - "net_05", - "net_08", - "net_09" - ], - "conflict_edges": [ - [ - "net_00", - "net_01" - ], - [ - "net_06", - "net_07" - ] - ], - "iteration": 3, - "nets": [ - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_02", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1049.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 2, - "other_net_id": "net_00", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_00", - "self_component_index": 3 - }, - { - "other_component_index": 3, - "other_net_id": "net_00", - "self_component_index": 4 - } - ], - "conflicting_net_ids": [ - "net_00" - ], - "net_id": "net_01", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 3, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1128.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_09", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1217.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 2, - "other_net_id": "net_01", - "self_component_index": 2 - }, - { - "other_component_index": 3, - "other_net_id": "net_01", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_01" - ], - "net_id": "net_00", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 2, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1207.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_06", - "self_component_index": 1 - }, - { - "other_component_index": 2, - "other_net_id": "net_06", - "self_component_index": 2 - } - ], - "conflicting_net_ids": [ - "net_06" - ], - "net_id": "net_07", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 2, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1059.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_05", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 914.6410526793834 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_04", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 909.9977565924808 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_07", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_07", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_07", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_07" - ], - "net_id": "net_06", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 3, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 980.0796326794897 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_03", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 970.0796326794897 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_08", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1138.0796326794896 - } - } - ], - "stage": "iteration" - }, - { - "completed_net_ids": [ - "net_00", - "net_03", - "net_04", - "net_05", - "net_08", - "net_09" - ], - "conflict_edges": [ - [ - "net_01", - "net_02" - ], - [ - "net_06", - "net_07" - ] - ], - "iteration": 4, - "nets": [ - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_00", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1207.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_07", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_07", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_07", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_07" - ], - "net_id": "net_06", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 3, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 980.0796326794897 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_09", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1217.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_05", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 914.6410526793834 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_08", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1138.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_03", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 970.0796326794897 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_06", - "self_component_index": 1 - }, - { - "other_component_index": 2, - "other_net_id": "net_06", - "self_component_index": 2 - } - ], - "conflicting_net_ids": [ - "net_06" - ], - "net_id": "net_07", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 2, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1059.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 3, - "other_net_id": "net_01", - "self_component_index": 2 - }, - { - "other_component_index": 3, - "other_net_id": "net_01", - "self_component_index": 3 - }, - { - "other_component_index": 4, - "other_net_id": "net_01", - "self_component_index": 4 - } - ], - "conflicting_net_ids": [ - "net_01" - ], - "net_id": "net_02", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 3, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1049.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_04", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 909.9977565924808 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 2, - "other_net_id": "net_02", - "self_component_index": 3 - }, - { - "other_component_index": 3, - "other_net_id": "net_02", - "self_component_index": 4 - } - ], - "conflicting_net_ids": [ - "net_02" - ], - "net_id": "net_01", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 2, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1128.0796326794896 - } - } - ], - "stage": "iteration" - }, - { - "completed_net_ids": [ - "net_00", - "net_01", - "net_04", - "net_05", - "net_08", - "net_09" - ], - "conflict_edges": [ - [ - "net_02", - "net_03" - ], - [ - "net_06", - "net_07" - ] - ], - "iteration": 5, - "nets": [ - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_00", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1207.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_01", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1128.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_04", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 909.9977565924808 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_09", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1217.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_03", - "self_component_index": 1 - }, - { - "other_component_index": 2, - "other_net_id": "net_03", - "self_component_index": 2 - } - ], - "conflicting_net_ids": [ - "net_03" - ], - "net_id": "net_02", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 2, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1049.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_05", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 914.6410526793834 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_08", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1138.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_06", - "self_component_index": 1 - }, - { - "other_component_index": 2, - "other_net_id": "net_06", - "self_component_index": 2 - } - ], - "conflicting_net_ids": [ - "net_06" - ], - "net_id": "net_07", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 2, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1059.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_07", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_07", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_07", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_07" - ], - "net_id": "net_06", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 3, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 980.0796326794897 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_02", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_02", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_02", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_02" - ], - "net_id": "net_03", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 3, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 970.0796326794897 - } - } - ], - "stage": "iteration" - }, - { - "completed_net_ids": [ - "net_02", - "net_03", - "net_04", - "net_05", - "net_08", - "net_09" - ], - "conflict_edges": [ - [ - "net_00", - "net_01" - ], - [ - "net_06", - "net_07" - ] - ], - "iteration": null, - "nets": [ - { - "component_conflicts": [ - { - "other_component_index": 2, - "other_net_id": "net_01", - "self_component_index": 2 - }, - { - "other_component_index": 3, - "other_net_id": "net_01", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_01" - ], - "net_id": "net_00", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 2, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1207.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 2, - "other_net_id": "net_00", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_00", - "self_component_index": 3 - }, - { - "other_component_index": 3, - "other_net_id": "net_00", - "self_component_index": 4 - } - ], - "conflicting_net_ids": [ - "net_00" - ], - "net_id": "net_01", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 3, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1128.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_04", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 909.9977565924808 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_09", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1217.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_02", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1049.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_05", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 914.6410526793834 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_08", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1138.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_06", - "self_component_index": 1 - }, - { - "other_component_index": 2, - "other_net_id": "net_06", - "self_component_index": 2 - } - ], - "conflicting_net_ids": [ - "net_06" - ], - "net_id": "net_07", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 2, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1059.0796326794896 - } - }, - { - "component_conflicts": [ - { - "other_component_index": 1, - "other_net_id": "net_07", - "self_component_index": 1 - }, - { - "other_component_index": 1, - "other_net_id": "net_07", - "self_component_index": 2 - }, - { - "other_component_index": 2, - "other_net_id": "net_07", - "self_component_index": 3 - } - ], - "conflicting_net_ids": [ - "net_07" - ], - "net_id": "net_06", - "outcome": "colliding", - "reached_target": true, - "report": { - "dynamic_collision_count": 3, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 980.0796326794897 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_03", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 970.0796326794897 - } - } - ], - "stage": "restored_best" - }, - { - "completed_net_ids": [ - "net_00", - "net_01", - "net_02", - "net_03", - "net_04", - "net_05", - "net_06", - "net_07", - "net_08", - "net_09" - ], - "conflict_edges": [], - "iteration": null, - "nets": [ - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_00", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1207.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_01", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1128.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_04", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 909.9977565924808 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_09", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1217.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_02", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1049.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_05", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 914.6410526793834 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_08", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1138.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_07", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1059.0796326794896 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_06", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 980.0796326794897 - } - }, - { - "component_conflicts": [], - "conflicting_net_ids": [], - "net_id": "net_03", - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 970.0796326794897 - } - } - ], - "stage": "final" - } - ], - "metrics": { - "congestion_cache_hits": 31, - "congestion_cache_misses": 4625, - "congestion_candidate_ids": 9924, - "congestion_candidate_nets": 9979, - "congestion_candidate_precheck_hits": 2562, - "congestion_candidate_precheck_misses": 2165, - "congestion_candidate_precheck_skips": 71, - "congestion_check_calls": 4625, - "congestion_exact_pair_checks": 8122, - "congestion_grid_net_cache_hits": 2457, - "congestion_grid_net_cache_misses": 3942, - "congestion_grid_span_cache_hits": 2283, - "congestion_grid_span_cache_misses": 1948, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 2673, - "congestion_net_envelope_cache_misses": 4139, - "congestion_presence_cache_hits": 2858, - "congestion_presence_cache_misses": 2556, - "congestion_presence_skips": 687, - "danger_map_cache_hits": 16878, - "danger_map_cache_misses": 7425, - "danger_map_lookup_calls": 24303, - "danger_map_query_calls": 7425, - "danger_map_total_ns": 222763960, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 471, - "dynamic_path_objects_removed": 423, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 11000.0, - "guidance_bonus_applied_bend90": 3500.0, - "guidance_bonus_applied_sbend": 625.0, - "guidance_bonus_applied_straight": 6875.0, - "guidance_match_moves": 176, - "guidance_match_moves_bend90": 56, - "guidance_match_moves_sbend": 10, - "guidance_match_moves_straight": 110, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 39, - "iteration_conflicting_nets": 36, - "iteration_reverified_nets": 60, - "iteration_reverify_calls": 6, - "move_cache_abs_hits": 2559, - "move_cache_abs_misses": 6494, - "move_cache_rel_hits": 5872, - "move_cache_rel_misses": 622, - "moves_added": 8081, - "moves_generated": 9053, - "nets_carried_forward": 0, - "nets_reached_target": 60, - "nets_routed": 60, - "nodes_expanded": 1764, - "pair_local_search_accepts": 2, - "pair_local_search_attempts": 2, - "pair_local_search_nodes_expanded": 68, - "pair_local_search_pairs_considered": 2, - "path_cost_calls": 0, - "pruned_closed_set": 439, - "pruned_cost": 533, - "pruned_hard_collision": 0, - "ray_cast_calls": 5477, - "ray_cast_calls_expand_forward": 1704, - "ray_cast_calls_expand_snap": 46, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 3721, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 6, - "ray_cast_candidate_bounds": 305, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 10, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 6, - "score_component_calls": 8634, - "score_component_total_ns": 252458856, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 2482, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 2106, - "verify_dynamic_exact_pair_checks": 558, - "verify_path_report_calls": 190, - "verify_static_buffer_ops": 895, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 6, - "visibility_tangent_candidate_ray_tests": 6, - "visibility_tangent_candidate_scans": 1704, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "name": "example_07_large_scale_routing_no_warm_start", - "summary": { - "reached_targets": 10, - "results_by_net": { - "net_00": { - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1207.0796326794896 - } - }, - "net_01": { - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1128.0796326794896 - } - }, - "net_02": { - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1049.0796326794896 - } - }, - "net_03": { - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 970.0796326794897 - } - }, - "net_04": { - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 909.9977565924808 - } - }, - "net_05": { - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 914.6410526793834 - } - }, - "net_06": { - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 980.0796326794897 - } - }, - "net_07": { - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1059.0796326794896 - } - }, - "net_08": { - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1138.0796326794896 - } - }, - "net_09": { - "outcome": "completed", - "reached_target": true, - "report": { - "dynamic_collision_count": 0, - "self_collision_count": 0, - "static_collision_count": 0, - "total_length": 1217.0796326794896 - } - } - }, - "total_results": 10, - "valid_results": 10 - } - } - ] -} diff --git a/docs/conflict_trace.md b/docs/conflict_trace.md deleted file mode 100644 index 75d3c8b..0000000 --- a/docs/conflict_trace.md +++ /dev/null @@ -1,57 +0,0 @@ -# Conflict Trace - -Generated at 2026-04-02T14:24:39-07:00 by `scripts/record_conflict_trace.py`. - -## example_07_large_scale_routing_no_warm_start - -Results: 10 valid / 10 reached / 10 total. - -| Stage | Iteration | Conflicting Nets | Conflict Edges | Completed Nets | -| :-- | --: | --: | --: | --: | -| iteration | 0 | 9 | 16 | 1 | -| iteration | 1 | 8 | 12 | 2 | -| iteration | 2 | 6 | 5 | 4 | -| iteration | 3 | 4 | 2 | 6 | -| iteration | 4 | 4 | 2 | 6 | -| iteration | 5 | 4 | 2 | 6 | -| restored_best | | 4 | 2 | 6 | -| final | | 0 | 0 | 10 | - -Top nets by traced dynamic-collision stages: - -- `net_06`: 7 -- `net_07`: 7 -- `net_01`: 6 -- `net_00`: 5 -- `net_02`: 5 -- `net_03`: 4 -- `net_08`: 2 -- `net_09`: 2 -- `net_05`: 1 - -Top net pairs by frequency: - -- `net_06` <-> `net_07`: 7 -- `net_00` <-> `net_01`: 5 -- `net_01` <-> `net_02`: 4 -- `net_00` <-> `net_02`: 3 -- `net_00` <-> `net_03`: 3 -- `net_02` <-> `net_03`: 3 -- `net_01` <-> `net_03`: 2 -- `net_06` <-> `net_08`: 2 -- `net_06` <-> `net_09`: 2 -- `net_07` <-> `net_08`: 2 - -Top component pairs by frequency: - -- `net_06[2]` <-> `net_07[2]`: 6 -- `net_06[3]` <-> `net_07[2]`: 6 -- `net_06[1]` <-> `net_07[1]`: 6 -- `net_06[2]` <-> `net_07[1]`: 5 -- `net_00[2]` <-> `net_01[3]`: 4 -- `net_01[2]` <-> `net_02[2]`: 3 -- `net_01[2]` <-> `net_02[3]`: 3 -- `net_00[2]` <-> `net_01[2]`: 3 -- `net_07[3]` <-> `net_08[2]`: 2 -- `net_02[1]` <-> `net_03[1]`: 2 - diff --git a/docs/frontier_trace.json b/docs/frontier_trace.json deleted file mode 100644 index 130350c..0000000 --- a/docs/frontier_trace.json +++ /dev/null @@ -1,120 +0,0 @@ -{ - "generated_at": "2026-04-02T14:24:39-07:00", - "generator": "scripts/record_frontier_trace.py", - "scenarios": [ - { - "frontier_trace": [], - "metrics": { - "congestion_cache_hits": 31, - "congestion_cache_misses": 4625, - "congestion_candidate_ids": 9924, - "congestion_candidate_nets": 9979, - "congestion_candidate_precheck_hits": 2562, - "congestion_candidate_precheck_misses": 2165, - "congestion_candidate_precheck_skips": 71, - "congestion_check_calls": 4625, - "congestion_exact_pair_checks": 8122, - "congestion_grid_net_cache_hits": 2457, - "congestion_grid_net_cache_misses": 3942, - "congestion_grid_span_cache_hits": 2283, - "congestion_grid_span_cache_misses": 1948, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 2673, - "congestion_net_envelope_cache_misses": 4139, - "congestion_presence_cache_hits": 2858, - "congestion_presence_cache_misses": 2556, - "congestion_presence_skips": 687, - "danger_map_cache_hits": 16878, - "danger_map_cache_misses": 7425, - "danger_map_lookup_calls": 24303, - "danger_map_query_calls": 7425, - "danger_map_total_ns": 212814061, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 471, - "dynamic_path_objects_removed": 423, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 11000.0, - "guidance_bonus_applied_bend90": 3500.0, - "guidance_bonus_applied_sbend": 625.0, - "guidance_bonus_applied_straight": 6875.0, - "guidance_match_moves": 176, - "guidance_match_moves_bend90": 56, - "guidance_match_moves_sbend": 10, - "guidance_match_moves_straight": 110, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 39, - "iteration_conflicting_nets": 36, - "iteration_reverified_nets": 60, - "iteration_reverify_calls": 6, - "move_cache_abs_hits": 2559, - "move_cache_abs_misses": 6494, - "move_cache_rel_hits": 5872, - "move_cache_rel_misses": 622, - "moves_added": 8081, - "moves_generated": 9053, - "nets_carried_forward": 0, - "nets_reached_target": 60, - "nets_routed": 60, - "nodes_expanded": 1764, - "pair_local_search_accepts": 2, - "pair_local_search_attempts": 2, - "pair_local_search_nodes_expanded": 68, - "pair_local_search_pairs_considered": 2, - "path_cost_calls": 0, - "pruned_closed_set": 439, - "pruned_cost": 533, - "pruned_hard_collision": 0, - "ray_cast_calls": 5477, - "ray_cast_calls_expand_forward": 1704, - "ray_cast_calls_expand_snap": 46, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 3721, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 6, - "ray_cast_candidate_bounds": 305, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 10, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 6, - "score_component_calls": 8634, - "score_component_total_ns": 241025335, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 2482, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 2106, - "verify_dynamic_exact_pair_checks": 558, - "verify_path_report_calls": 190, - "verify_static_buffer_ops": 895, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 6, - "visibility_tangent_candidate_ray_tests": 6, - "visibility_tangent_candidate_scans": 1704, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "name": "example_07_large_scale_routing_no_warm_start", - "summary": { - "reached_targets": 10, - "total_results": 10, - "valid_results": 10 - } - } - ] -} diff --git a/docs/frontier_trace.md b/docs/frontier_trace.md deleted file mode 100644 index 4351f37..0000000 --- a/docs/frontier_trace.md +++ /dev/null @@ -1,23 +0,0 @@ -# Frontier Trace - -Generated at 2026-04-02T14:24:39-07:00 by `scripts/record_frontier_trace.py`. - -## example_07_large_scale_routing_no_warm_start - -Results: 10 valid / 10 reached / 10 total. - -| Net | Hotspots | Closed-Set | Hard Collision | Self Collision | Cost | Samples | -| :-- | --: | --: | --: | --: | --: | --: | - -Prune totals by reason: - -- None - -Top traced hotspots by sample count: - -- None - -Per-net sampled reason/move breakdown: - -- None - diff --git a/docs/optimization_pass_01_log.md b/docs/optimization_pass_01_log.md deleted file mode 100644 index 2f5c5e7..0000000 --- a/docs/optimization_pass_01_log.md +++ /dev/null @@ -1,3631 +0,0 @@ -# Optimization Pass 01 Log - -This log records the step-by-step measurements for the first visibility-focused optimization pass. -Each section is appended after a discrete code change using `scripts/diff_performance_baseline.py`. -## Step 0 - Pre-optimization baseline - -Measured on 2026-03-31T18:02:56-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Current default tangent-corner routing still pays for eager exact visibility-graph construction. -- Visibility-build ray casts dominate all three hotspot scenarios before any routing changes. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_04_sbends_and_radii | duration_s | 1.9938 | 2.0940 | +0.1002 | -| example_04_sbends_and_radii | nodes_expanded | 15.0000 | 15.0000 | +0.0000 | -| example_04_sbends_and_radii | visibility_builds | 3.0000 | 3.0000 | +0.0000 | -| example_04_sbends_and_radii | visibility_corner_pairs_checked | 18148.0000 | 18148.0000 | +0.0000 | -| example_04_sbends_and_radii | ray_cast_calls | 18218.0000 | 18218.0000 | +0.0000 | -| example_04_sbends_and_radii | ray_cast_calls_visibility_build | 18148.0000 | 18148.0000 | +0.0000 | -| example_04_sbends_and_radii | ray_cast_exact_geometry_checks | 21265.0000 | 21265.0000 | +0.0000 | -| example_04_sbends_and_radii | ray_cast_candidate_bounds | 50717.0000 | 50717.0000 | +0.0000 | -| example_06_bend_collision_models | duration_s | 4.1186 | 4.2483 | +0.1297 | -| example_06_bend_collision_models | nodes_expanded | 240.0000 | 240.0000 | +0.0000 | -| example_06_bend_collision_models | visibility_builds | 6.0000 | 6.0000 | +0.0000 | -| example_06_bend_collision_models | visibility_corner_pairs_checked | 39848.0000 | 39848.0000 | +0.0000 | -| example_06_bend_collision_models | ray_cast_calls | 40530.0000 | 40530.0000 | +0.0000 | -| example_06_bend_collision_models | ray_cast_calls_visibility_build | 39848.0000 | 39848.0000 | +0.0000 | -| example_06_bend_collision_models | ray_cast_exact_geometry_checks | 36858.0000 | 36858.0000 | +0.0000 | -| example_06_bend_collision_models | ray_cast_candidate_bounds | 121732.0000 | 121732.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 1.3734 | 1.4031 | +0.0297 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | visibility_builds | 11.0000 | 11.0000 | +0.0000 | -| example_07_large_scale_routing | visibility_corner_pairs_checked | 10768.0000 | 10768.0000 | +0.0000 | -| example_07_large_scale_routing | ray_cast_calls | 11151.0000 | 11151.0000 | +0.0000 | -| example_07_large_scale_routing | ray_cast_calls_visibility_build | 10768.0000 | 10768.0000 | +0.0000 | -| example_07_large_scale_routing | ray_cast_exact_geometry_checks | 11651.0000 | 11651.0000 | +0.0000 | -| example_07_large_scale_routing | ray_cast_candidate_bounds | 21198.0000 | 21198.0000 | +0.0000 | -## Step 1 - Lazy visibility state split - -Measured on 2026-03-31T18:05:49-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Corner-index rebuilds are now measured separately from exact visibility-graph builds. -- Default tangent-corner routing still triggers exact graph work at query time, so visibility-build counters remain hot in this step. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_04_sbends_and_radii | duration_s | 1.9938 | 0.2543 | -1.7395 | -| example_04_sbends_and_radii | nodes_expanded | 15.0000 | 15.0000 | +0.0000 | -| example_04_sbends_and_radii | visibility_corner_index_builds | - | 2.0000 | - | -| example_04_sbends_and_radii | visibility_builds | 3.0000 | 2.0000 | -1.0000 | -| example_04_sbends_and_radii | visibility_corner_pairs_checked | 18148.0000 | 1892.0000 | -16256.0000 | -| example_04_sbends_and_radii | ray_cast_calls | 18218.0000 | 1962.0000 | -16256.0000 | -| example_04_sbends_and_radii | ray_cast_calls_visibility_build | 18148.0000 | 1892.0000 | -16256.0000 | -| example_04_sbends_and_radii | ray_cast_exact_geometry_checks | 21265.0000 | 2445.0000 | -18820.0000 | -| example_04_sbends_and_radii | ray_cast_candidate_bounds | 50717.0000 | 3864.0000 | -46853.0000 | -| example_06_bend_collision_models | duration_s | 4.1186 | 0.2055 | -3.9131 | -| example_06_bend_collision_models | nodes_expanded | 240.0000 | 240.0000 | +0.0000 | -| example_06_bend_collision_models | visibility_corner_index_builds | - | 3.0000 | - | -| example_06_bend_collision_models | visibility_builds | 6.0000 | 3.0000 | -3.0000 | -| example_06_bend_collision_models | visibility_corner_pairs_checked | 39848.0000 | 396.0000 | -39452.0000 | -| example_06_bend_collision_models | ray_cast_calls | 40530.0000 | 1078.0000 | -39452.0000 | -| example_06_bend_collision_models | ray_cast_calls_visibility_build | 39848.0000 | 396.0000 | -39452.0000 | -| example_06_bend_collision_models | ray_cast_exact_geometry_checks | 36858.0000 | 0.0000 | -36858.0000 | -| example_06_bend_collision_models | ray_cast_candidate_bounds | 121732.0000 | 877.0000 | -120855.0000 | -| example_07_large_scale_routing | duration_s | 1.3734 | 1.3958 | +0.0224 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | visibility_corner_index_builds | - | 10.0000 | - | -| example_07_large_scale_routing | visibility_builds | 11.0000 | 10.0000 | -1.0000 | -| example_07_large_scale_routing | visibility_corner_pairs_checked | 10768.0000 | 10768.0000 | +0.0000 | -| example_07_large_scale_routing | ray_cast_calls | 11151.0000 | 11151.0000 | +0.0000 | -| example_07_large_scale_routing | ray_cast_calls_visibility_build | 10768.0000 | 10768.0000 | +0.0000 | -| example_07_large_scale_routing | ray_cast_exact_geometry_checks | 11651.0000 | 11651.0000 | +0.0000 | -| example_07_large_scale_routing | ray_cast_candidate_bounds | 21198.0000 | 21198.0000 | +0.0000 | -## Step 2 - Tangent-corner cheap path - -Measured on 2026-03-31T18:06:53-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Default tangent-corner expansion now uses only the corner index and never requests the exact corner graph. -- The expected win is zero visibility-build ray casts in the hotspot trio while keeping node counts stable. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_04_sbends_and_radii | duration_s | 1.9938 | 0.0280 | -1.9659 | -| example_04_sbends_and_radii | nodes_expanded | 15.0000 | 15.0000 | +0.0000 | -| example_04_sbends_and_radii | visibility_corner_index_builds | - | 2.0000 | - | -| example_04_sbends_and_radii | visibility_builds | 3.0000 | 0.0000 | -3.0000 | -| example_04_sbends_and_radii | visibility_corner_pairs_checked | 18148.0000 | 0.0000 | -18148.0000 | -| example_04_sbends_and_radii | ray_cast_calls | 18218.0000 | 70.0000 | -18148.0000 | -| example_04_sbends_and_radii | ray_cast_calls_visibility_build | 18148.0000 | 0.0000 | -18148.0000 | -| example_04_sbends_and_radii | ray_cast_exact_geometry_checks | 21265.0000 | 0.0000 | -21265.0000 | -| example_04_sbends_and_radii | ray_cast_candidate_bounds | 50717.0000 | 4.0000 | -50713.0000 | -| example_06_bend_collision_models | duration_s | 4.1186 | 0.1900 | -3.9286 | -| example_06_bend_collision_models | nodes_expanded | 240.0000 | 240.0000 | +0.0000 | -| example_06_bend_collision_models | visibility_corner_index_builds | - | 3.0000 | - | -| example_06_bend_collision_models | visibility_builds | 6.0000 | 0.0000 | -6.0000 | -| example_06_bend_collision_models | visibility_corner_pairs_checked | 39848.0000 | 0.0000 | -39848.0000 | -| example_06_bend_collision_models | ray_cast_calls | 40530.0000 | 682.0000 | -39848.0000 | -| example_06_bend_collision_models | ray_cast_calls_visibility_build | 39848.0000 | 0.0000 | -39848.0000 | -| example_06_bend_collision_models | ray_cast_exact_geometry_checks | 36858.0000 | 0.0000 | -36858.0000 | -| example_06_bend_collision_models | ray_cast_candidate_bounds | 121732.0000 | 97.0000 | -121635.0000 | -| example_07_large_scale_routing | duration_s | 1.3734 | 0.2042 | -1.1693 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | visibility_corner_index_builds | - | 10.0000 | - | -| example_07_large_scale_routing | visibility_builds | 11.0000 | 0.0000 | -11.0000 | -| example_07_large_scale_routing | visibility_corner_pairs_checked | 10768.0000 | 0.0000 | -10768.0000 | -| example_07_large_scale_routing | ray_cast_calls | 11151.0000 | 383.0000 | -10768.0000 | -| example_07_large_scale_routing | ray_cast_calls_visibility_build | 10768.0000 | 0.0000 | -10768.0000 | -| example_07_large_scale_routing | ray_cast_exact_geometry_checks | 11651.0000 | 150.0000 | -11501.0000 | -| example_07_large_scale_routing | ray_cast_candidate_bounds | 21198.0000 | 683.0000 | -20515.0000 | -## Step 3 - Final optimized baseline - -Measured on 2026-03-31T18:08:19-07:00. -Baseline: `/tmp/inire_pre_optimization_baseline.json`. - -Findings: - -- Committed baseline artifacts were regenerated from the optimized router after the tangent-corner change landed. -- The hotspot trio now reaches the same node counts with zero exact visibility-graph builds in default tangent-corner mode. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_04_sbends_and_radii | duration_s | 1.9938 | 0.0279 | -1.9659 | -| example_04_sbends_and_radii | nodes_expanded | 15.0000 | 15.0000 | +0.0000 | -| example_04_sbends_and_radii | visibility_corner_index_builds | - | 2.0000 | - | -| example_04_sbends_and_radii | visibility_builds | 3.0000 | 0.0000 | -3.0000 | -| example_04_sbends_and_radii | visibility_corner_pairs_checked | 18148.0000 | 0.0000 | -18148.0000 | -| example_04_sbends_and_radii | ray_cast_calls | 18218.0000 | 70.0000 | -18148.0000 | -| example_04_sbends_and_radii | ray_cast_calls_visibility_build | 18148.0000 | 0.0000 | -18148.0000 | -| example_04_sbends_and_radii | ray_cast_exact_geometry_checks | 21265.0000 | 0.0000 | -21265.0000 | -| example_04_sbends_and_radii | ray_cast_candidate_bounds | 50717.0000 | 4.0000 | -50713.0000 | -| example_06_bend_collision_models | duration_s | 4.1186 | 0.1900 | -3.9286 | -| example_06_bend_collision_models | nodes_expanded | 240.0000 | 240.0000 | +0.0000 | -| example_06_bend_collision_models | visibility_corner_index_builds | - | 3.0000 | - | -| example_06_bend_collision_models | visibility_builds | 6.0000 | 0.0000 | -6.0000 | -| example_06_bend_collision_models | visibility_corner_pairs_checked | 39848.0000 | 0.0000 | -39848.0000 | -| example_06_bend_collision_models | ray_cast_calls | 40530.0000 | 682.0000 | -39848.0000 | -| example_06_bend_collision_models | ray_cast_calls_visibility_build | 39848.0000 | 0.0000 | -39848.0000 | -| example_06_bend_collision_models | ray_cast_exact_geometry_checks | 36858.0000 | 0.0000 | -36858.0000 | -| example_06_bend_collision_models | ray_cast_candidate_bounds | 121732.0000 | 97.0000 | -121635.0000 | -| example_07_large_scale_routing | duration_s | 1.3734 | 0.2004 | -1.1730 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | visibility_corner_index_builds | - | 10.0000 | - | -| example_07_large_scale_routing | visibility_builds | 11.0000 | 0.0000 | -11.0000 | -| example_07_large_scale_routing | visibility_corner_pairs_checked | 10768.0000 | 0.0000 | -10768.0000 | -| example_07_large_scale_routing | ray_cast_calls | 11151.0000 | 383.0000 | -10768.0000 | -| example_07_large_scale_routing | ray_cast_calls_visibility_build | 10768.0000 | 0.0000 | -10768.0000 | -| example_07_large_scale_routing | ray_cast_exact_geometry_checks | 11651.0000 | 150.0000 | -11501.0000 | -| example_07_large_scale_routing | ray_cast_candidate_bounds | 21198.0000 | 683.0000 | -20515.0000 | -## Step 4 - Tangent candidate scan baseline - -Measured on 2026-03-31T18:33:15-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- The next hotspot is tangent-corner candidate scanning, especially example_02 and example_07. -- This baseline captures current candidate-check volume before narrowing the corner-index query window. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_02_congestion_resolution | duration_s | 0.3365 | 0.3321 | -0.0044 | -| example_02_congestion_resolution | nodes_expanded | 366.0000 | 366.0000 | +0.0000 | -| example_02_congestion_resolution | visibility_tangent_candidate_scans | 363.0000 | 363.0000 | +0.0000 | -| example_02_congestion_resolution | visibility_tangent_candidate_corner_checks | 18991.0000 | 18991.0000 | +0.0000 | -| example_02_congestion_resolution | visibility_tangent_candidate_ray_tests | 253.0000 | 253.0000 | +0.0000 | -| example_02_congestion_resolution | ray_cast_calls | 1164.0000 | 1164.0000 | +0.0000 | -| example_02_congestion_resolution | danger_map_lookup_calls | 2208.0000 | 2208.0000 | +0.0000 | -| example_02_congestion_resolution | score_component_calls | 976.0000 | 976.0000 | +0.0000 | -| example_05_orientation_stress | duration_s | 0.2503 | 0.2404 | -0.0099 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | visibility_tangent_candidate_scans | 280.0000 | 280.0000 | +0.0000 | -| example_05_orientation_stress | visibility_tangent_candidate_corner_checks | 1483.0000 | 1483.0000 | +0.0000 | -| example_05_orientation_stress | visibility_tangent_candidate_ray_tests | 9.0000 | 9.0000 | +0.0000 | -| example_05_orientation_stress | ray_cast_calls | 1243.0000 | 1243.0000 | +0.0000 | -| example_05_orientation_stress | danger_map_lookup_calls | 2079.0000 | 2079.0000 | +0.0000 | -| example_05_orientation_stress | score_component_calls | 1198.0000 | 1198.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.2034 | 0.1962 | -0.0072 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | visibility_tangent_candidate_scans | 68.0000 | 68.0000 | +0.0000 | -| example_07_large_scale_routing | visibility_tangent_candidate_corner_checks | 34735.0000 | 34735.0000 | +0.0000 | -| example_07_large_scale_routing | visibility_tangent_candidate_ray_tests | 77.0000 | 77.0000 | +0.0000 | -| example_07_large_scale_routing | ray_cast_calls | 383.0000 | 383.0000 | +0.0000 | -| example_07_large_scale_routing | danger_map_lookup_calls | 681.0000 | 681.0000 | +0.0000 | -| example_07_large_scale_routing | score_component_calls | 291.0000 | 291.0000 | +0.0000 | -## Step 5 - Tangent candidate strip query - -Measured on 2026-03-31T18:34:10-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Tangent-corner candidate collection now queries orientation-aware radius strips instead of scanning a full square around each search state. -- The main acceptance signal is lower tangent corner checks with unchanged node counts and route outcomes. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_02_congestion_resolution | duration_s | 0.3365 | 0.3361 | -0.0004 | -| example_02_congestion_resolution | nodes_expanded | 366.0000 | 366.0000 | +0.0000 | -| example_02_congestion_resolution | visibility_tangent_candidate_scans | 363.0000 | 363.0000 | +0.0000 | -| example_02_congestion_resolution | visibility_tangent_candidate_corner_checks | 18991.0000 | 873.0000 | -18118.0000 | -| example_02_congestion_resolution | visibility_tangent_candidate_ray_tests | 253.0000 | 253.0000 | +0.0000 | -| example_02_congestion_resolution | ray_cast_calls | 1164.0000 | 1164.0000 | +0.0000 | -| example_02_congestion_resolution | danger_map_lookup_calls | 2208.0000 | 2208.0000 | +0.0000 | -| example_02_congestion_resolution | score_component_calls | 976.0000 | 976.0000 | +0.0000 | -| example_05_orientation_stress | duration_s | 0.2503 | 0.2500 | -0.0003 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | visibility_tangent_candidate_scans | 280.0000 | 280.0000 | +0.0000 | -| example_05_orientation_stress | visibility_tangent_candidate_corner_checks | 1483.0000 | 70.0000 | -1413.0000 | -| example_05_orientation_stress | visibility_tangent_candidate_ray_tests | 9.0000 | 9.0000 | +0.0000 | -| example_05_orientation_stress | ray_cast_calls | 1243.0000 | 1243.0000 | +0.0000 | -| example_05_orientation_stress | danger_map_lookup_calls | 2079.0000 | 2079.0000 | +0.0000 | -| example_05_orientation_stress | score_component_calls | 1198.0000 | 1198.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.2034 | 0.1874 | -0.0160 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | visibility_tangent_candidate_scans | 68.0000 | 68.0000 | +0.0000 | -| example_07_large_scale_routing | visibility_tangent_candidate_corner_checks | 34735.0000 | 321.0000 | -34414.0000 | -| example_07_large_scale_routing | visibility_tangent_candidate_ray_tests | 77.0000 | 77.0000 | +0.0000 | -| example_07_large_scale_routing | ray_cast_calls | 383.0000 | 383.0000 | +0.0000 | -| example_07_large_scale_routing | danger_map_lookup_calls | 681.0000 | 681.0000 | +0.0000 | -| example_07_large_scale_routing | score_component_calls | 291.0000 | 291.0000 | +0.0000 | -## Step 6 - Empty danger-map fast path - -Measured on 2026-03-31T18:50:25-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Scoring now skips danger-map sampling when the KD-tree is empty, which should primarily help obstacle-free scenarios. -- The no-warm-start example_07 variant is included as a canary; it is not part of the default baseline corpus, so baseline values may be absent on first measurement. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_02_congestion_resolution | duration_s | 0.3325 | 0.3260 | -0.0065 | -| example_02_congestion_resolution | nodes_expanded | 366.0000 | 366.0000 | +0.0000 | -| example_02_congestion_resolution | score_component_calls | 976.0000 | 976.0000 | +0.0000 | -| example_02_congestion_resolution | danger_map_lookup_calls | 2208.0000 | 0.0000 | -2208.0000 | -| example_02_congestion_resolution | danger_map_cache_hits | 1433.0000 | 0.0000 | -1433.0000 | -| example_02_congestion_resolution | danger_map_cache_misses | 775.0000 | 0.0000 | -775.0000 | -| example_02_congestion_resolution | warm_start_paths_built | 3.0000 | 3.0000 | +0.0000 | -| example_02_congestion_resolution | warm_start_paths_used | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | duration_s | 0.2404 | 0.2375 | -0.0029 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | score_component_calls | 1198.0000 | 1198.0000 | +0.0000 | -| example_05_orientation_stress | danger_map_lookup_calls | 2079.0000 | 0.0000 | -2079.0000 | -| example_05_orientation_stress | danger_map_cache_hits | 1386.0000 | 0.0000 | -1386.0000 | -| example_05_orientation_stress | danger_map_cache_misses | 693.0000 | 0.0000 | -693.0000 | -| example_05_orientation_stress | warm_start_paths_built | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | warm_start_paths_used | 2.0000 | 2.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | added | - | - | - | -## Step 7 - Verification baseline - -Measured on 2026-03-31T19:00:03-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- The next low-risk optimization target is redundant verification during refinement, especially in example_02. -- The no-warm-start example_07 canary stays in the measurement set even though it is not part of the default baseline corpus. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_02_congestion_resolution | duration_s | 0.3220 | 0.3304 | +0.0084 | -| example_02_congestion_resolution | verify_path_report_calls | 35.0000 | 35.0000 | +0.0000 | -| example_02_congestion_resolution | refine_path_calls | 3.0000 | 3.0000 | +0.0000 | -| example_02_congestion_resolution | refinement_candidates_verified | 26.0000 | 26.0000 | +0.0000 | -| example_02_congestion_resolution | refinement_candidates_accepted | 2.0000 | 2.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | warm_start_paths_built | 3.0000 | 3.0000 | +0.0000 | -| example_02_congestion_resolution | warm_start_paths_used | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | duration_s | 0.2340 | 0.2348 | +0.0008 | -| example_05_orientation_stress | verify_path_report_calls | 12.0000 | 12.0000 | +0.0000 | -| example_05_orientation_stress | refine_path_calls | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | refinement_candidates_verified | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | refinement_candidates_accepted | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 412.0000 | 412.0000 | +0.0000 | -| example_05_orientation_stress | warm_start_paths_built | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | warm_start_paths_used | 2.0000 | 2.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | added | - | - | - | -## Step 8 - Deferred refinement verification - -Measured on 2026-03-31T19:02:46-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Per-net verification inside _refine_results() is now deferred to the final verification pass to avoid verifying the same refined path twice. -- The main expected signal is fewer verify_path_report_calls with unchanged route outcomes. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_02_congestion_resolution | duration_s | 0.3220 | 0.3273 | +0.0052 | -| example_02_congestion_resolution | verify_path_report_calls | 35.0000 | 32.0000 | -3.0000 | -| example_02_congestion_resolution | refine_path_calls | 3.0000 | 3.0000 | +0.0000 | -| example_02_congestion_resolution | refinement_candidates_verified | 26.0000 | 26.0000 | +0.0000 | -| example_02_congestion_resolution | refinement_candidates_accepted | 2.0000 | 2.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | warm_start_paths_built | 3.0000 | 3.0000 | +0.0000 | -| example_02_congestion_resolution | warm_start_paths_used | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | duration_s | 0.2340 | 0.2350 | +0.0011 | -| example_05_orientation_stress | verify_path_report_calls | 12.0000 | 9.0000 | -3.0000 | -| example_05_orientation_stress | refine_path_calls | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | refinement_candidates_verified | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | refinement_candidates_accepted | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 412.0000 | 412.0000 | +0.0000 | -| example_05_orientation_stress | warm_start_paths_built | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | warm_start_paths_used | 2.0000 | 2.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | added | - | - | - | -## Step 9 - Dynamic rtree for congestion and verification - -Measured on 2026-03-31T20:12:56-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Dynamic congestion confirmation and dynamic-path verification now use the mutable rtree index instead of rebuilding a transient STRtree. -- The expected signal is dynamic_tree_rebuilds dropping to zero on the normal corpus while route outcomes stay unchanged. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_02_congestion_resolution | duration_s | 0.3211 | 0.3273 | +0.0062 | -| example_02_congestion_resolution | dynamic_tree_rebuilds | 6.0000 | 0.0000 | -6.0000 | -| example_02_congestion_resolution | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | verify_path_report_calls | 32.0000 | 32.0000 | +0.0000 | -| example_02_congestion_resolution | verify_dynamic_exact_pair_checks | 90.0000 | 130.0000 | +40.0000 | -| example_05_orientation_stress | duration_s | 0.2351 | 0.2324 | -0.0028 | -| example_05_orientation_stress | dynamic_tree_rebuilds | 10.0000 | 0.0000 | -10.0000 | -| example_05_orientation_stress | congestion_check_calls | 412.0000 | 412.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 66.0000 | 68.0000 | +2.0000 | -| example_05_orientation_stress | verify_path_report_calls | 9.0000 | 9.0000 | +0.0000 | -| example_05_orientation_stress | verify_dynamic_exact_pair_checks | 2.0000 | 4.0000 | +2.0000 | -| example_07_large_scale_routing_no_warm_start | added | - | - | - | -## Step 10 - Incremental dynamic congestion grid - -Measured on 2026-03-31T20:29:38-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Dynamic path removal is now net-owned and the congestion grid is updated incrementally instead of being invalidated and rebuilt. -- The expected signal is dynamic_grid_rebuilds dropping to zero and better performance on congestion-heavy or no-warm-start routing. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2394 | 0.2605 | +0.0211 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 412.0000 | 412.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 68.0000 | 68.0000 | +0.0000 | -| example_05_orientation_stress | congestion_cache_hits | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | congestion_cache_misses | 412.0000 | 412.0000 | +0.0000 | -| example_05_orientation_stress | dynamic_grid_rebuilds | 3.0000 | 0.0000 | -3.0000 | -| example_05_orientation_stress | dynamic_path_objects_added | 37.0000 | 37.0000 | +0.0000 | -| example_05_orientation_stress | dynamic_path_objects_removed | 25.0000 | 25.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | added | - | - | - | -## Step 11 - Per-polygon congestion broad phase - -Measured on 2026-03-31T20:36:35-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Congestion candidate collection now scans per dilated polygon bounds instead of the move-wide union bounds. -- The main expected signal is fewer broad-phase candidate ids, especially on large dynamic-path states such as example_07 without warm start. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2541 | 0.2488 | -0.0053 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 412.0000 | 412.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | - | 83.0000 | - | -| example_05_orientation_stress | congestion_exact_pair_checks | 68.0000 | 70.0000 | +2.0000 | -| example_05_orientation_stress | congestion_cache_hits | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | congestion_cache_misses | 412.0000 | 412.0000 | +0.0000 | -| example_05_orientation_stress | dynamic_grid_rebuilds | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | dynamic_path_objects_added | 37.0000 | 37.0000 | +0.0000 | -| example_05_orientation_stress | dynamic_path_objects_removed | 25.0000 | 25.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1984 | 0.1867 | -0.0118 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_cache_hits | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | dynamic_grid_rebuilds | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | dynamic_path_objects_added | 88.0000 | 88.0000 | +0.0000 | -| example_07_large_scale_routing | dynamic_path_objects_removed | 44.0000 | 44.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | added | - | - | - | -## Step 12 - Cheap exact congestion predicates - -Measured on 2026-03-31T20:47:00-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Congestion and dynamic verification now use non-constructive overlap predicates instead of building intersection geometries for every exact pair check. -- The no-warm-start example_07 canary now reports its current metrics directly in the log, which makes the congestion hot path measurable even though it is not part of the committed baseline corpus. -- The canary runtime dropped materially with unchanged node and congestion counts, which confirms that exact confirmation cost was a major part of the remaining congestion overhead. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2541 | 0.2682 | +0.0141 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 412.0000 | 412.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | - | 83.0000 | - | -| example_05_orientation_stress | congestion_exact_pair_checks | 68.0000 | 70.0000 | +2.0000 | -| example_05_orientation_stress | congestion_cache_hits | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | congestion_cache_misses | 412.0000 | 412.0000 | +0.0000 | -| example_05_orientation_stress | dynamic_grid_rebuilds | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | dynamic_path_objects_added | 37.0000 | 37.0000 | +0.0000 | -| example_05_orientation_stress | dynamic_path_objects_removed | 25.0000 | 25.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 109.2839 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 173498.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 641300.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 1737551.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 1192907.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_hits | - | 5379.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_misses | - | 641300.0000 | - | -| example_07_large_scale_routing_no_warm_start | dynamic_grid_rebuilds | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | dynamic_path_objects_added | - | 1601.0000 | - | -| example_07_large_scale_routing_no_warm_start | dynamic_path_objects_removed | - | 1462.0000 | - | -## Step 13 - Relevant-polygon exact congestion checks - -Measured on 2026-03-31T21:03:00-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Congestion candidate tracking now remembers which dilated move polygons produced each candidate object, so exact confirmation no longer retests candidates against unrelated polygons. -- This slice was largely neutral in aggregate counters: the no-warm-start canary still spent most of its time in congestion, which means the next win had to come from reducing how often congestion is queried at all. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2523 | 0.2753 | +0.0230 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 412.0000 | 412.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 83.0000 | 83.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 70.0000 | 70.0000 | +0.0000 | -| example_05_orientation_stress | congestion_cache_hits | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | congestion_cache_misses | 412.0000 | 412.0000 | +0.0000 | -| example_05_orientation_stress | dynamic_grid_rebuilds | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | dynamic_path_objects_added | 37.0000 | 37.0000 | +0.0000 | -| example_05_orientation_stress | dynamic_path_objects_removed | 25.0000 | 25.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 104.0661 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 173498.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 641300.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 1737551.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 1208409.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_hits | - | 5379.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_misses | - | 641300.0000 | - | -| example_07_large_scale_routing_no_warm_start | dynamic_grid_rebuilds | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | dynamic_path_objects_added | - | 1601.0000 | - | -| example_07_large_scale_routing_no_warm_start | dynamic_path_objects_removed | - | 1462.0000 | - | -## Step 14 - Self-collision before congestion - -Measured on 2026-03-31T21:08:00-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Moves that self-intersect the ancestor chain are now rejected before congestion scoring, so the search no longer spends congestion work on moves that will be discarded anyway. -- This is the first slice that materially cut congestion volume on the no-warm-start example_07 canary. -- Relative to Step 13, the canary dropped from `641300` to `529038` congestion checks, from `1737551` to `1164421` candidate ids, and from `1208409` to `838008` exact pair checks while runtime improved from `104.07s` to `102.02s`. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2523 | 0.2662 | +0.0139 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 412.0000 | 412.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 83.0000 | 83.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 70.0000 | 70.0000 | +0.0000 | -| example_05_orientation_stress | congestion_cache_hits | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | congestion_cache_misses | 412.0000 | 412.0000 | +0.0000 | -| example_05_orientation_stress | dynamic_grid_rebuilds | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | dynamic_path_objects_added | 37.0000 | 37.0000 | +0.0000 | -| example_05_orientation_stress | dynamic_path_objects_removed | 25.0000 | 25.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 102.0202 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 173498.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 529038.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 1164421.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 838008.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_hits | - | 3933.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_misses | - | 529038.0000 | - | -| example_07_large_scale_routing_no_warm_start | dynamic_grid_rebuilds | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | dynamic_path_objects_added | - | 1601.0000 | - | -| example_07_large_scale_routing_no_warm_start | dynamic_path_objects_removed | - | 1462.0000 | - | -## Step 15 - Uncongested dominance before congestion - -Measured on 2026-03-31T21:18:00-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Admission now computes the uncongested component score before congestion and prunes moves that are already closed-set-dominated even with zero congestion penalty. -- This slice materially reduced congestion misses without increasing `score_component_calls`, so it removed congestion work instead of shifting it into scoring. -- Relative to Step 14, the no-warm-start example_07 canary dropped from `529038` to `344747` congestion checks, from `1164421` to `375624` candidate ids, and from `838008` to `314367` exact pair checks while runtime improved from `102.02s` to `88.86s`. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2494 | 0.2619 | +0.0125 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 412.0000 | 213.0000 | -199.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 83.0000 | 19.0000 | -64.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 70.0000 | 18.0000 | -52.0000 | -| example_05_orientation_stress | congestion_cache_hits | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | congestion_cache_misses | 412.0000 | 213.0000 | -199.0000 | -| example_05_orientation_stress | dynamic_grid_rebuilds | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | dynamic_path_objects_added | 37.0000 | 37.0000 | +0.0000 | -| example_05_orientation_stress | dynamic_path_objects_removed | 25.0000 | 25.0000 | +0.0000 | -| example_05_orientation_stress | score_component_calls | 1198.0000 | 1198.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 88.8639 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 173498.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 344747.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 375624.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 314367.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_hits | - | 3300.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_misses | - | 344747.0000 | - | -| example_07_large_scale_routing_no_warm_start | dynamic_grid_rebuilds | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | dynamic_path_objects_added | - | 1601.0000 | - | -| example_07_large_scale_routing_no_warm_start | dynamic_path_objects_removed | - | 1462.0000 | - | -| example_07_large_scale_routing_no_warm_start | score_component_calls | - | 534994.0000 | - | -## Step 16 - Lazy congestion on pop (rejected) - -Measured on 2026-03-31T23:55:00-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Congestion resolution was moved from move generation to node pop, with penalized nodes requeued after their overlap count was resolved. -- The first cut reduced raw congestion misses on the no-warm-start example_07 canary from `344747` to `331308`, but runtime still regressed to about `99.00s` and nodes expanded rose to `184853`. -- Tightening lazy-requeue bookkeeping did not recover the search-order penalty. A later measurement pushed the same canary to `153.63s`, `247887` expanded nodes, `427874` congestion misses, and `166395` lazy requeues. -- This pass was rejected and reverted. The remaining congestion misses appear structural, but optimistic unresolved nodes created too much extra search churn. -## Step 17 - Grid-span congestion broad-phase cache - -Measured on 2026-03-31T22:44:31-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Congestion broad-phase candidate unions are now cached by queried grid-cell span within a single A* run. -- The exact overlap cache still misses at the previous rate, but the new grid-span cache hits heavily on repeated local congestion probes. -- Relative to the reverted Step 15 state, the no-warm-start example_07 canary improved from about 87.20s to 84.71s with unchanged nodes expanded and congestion check calls. -- The canary's broad-phase work also dropped modestly, from 375624 to 364731 candidate ids and from 314367 to 305397 exact pair checks. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2386 | 0.2380 | -0.0007 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | moves_generated | 1624.0000 | 1624.0000 | +0.0000 | -| example_05_orientation_stress | moves_added | 681.0000 | 681.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 213.0000 | 213.0000 | +0.0000 | -| example_05_orientation_stress | congestion_cache_hits | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | congestion_cache_misses | 213.0000 | 213.0000 | +0.0000 | -| example_05_orientation_stress | congestion_grid_span_cache_hits | - | 133.0000 | - | -| example_05_orientation_stress | congestion_grid_span_cache_misses | - | 22.0000 | - | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 19.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 18.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1885 | 0.1841 | -0.0044 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | moves_generated | 372.0000 | 372.0000 | +0.0000 | -| example_07_large_scale_routing | moves_added | 227.0000 | 227.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_cache_hits | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_grid_span_cache_hits | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_grid_span_cache_misses | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 84.8404 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 173498.0000 | - | -| example_07_large_scale_routing_no_warm_start | moves_generated | - | 857732.0000 | - | -| example_07_large_scale_routing_no_warm_start | moves_added | - | 348559.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 344747.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_hits | - | 3300.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_misses | - | 344747.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_grid_span_cache_hits | - | 199762.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_grid_span_cache_misses | - | 26740.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 364731.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 305397.0000 | - | -## Step 18 - Net-envelope maintenance and counters - -Measured on 2026-03-31T23:05:08-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Added per-net dynamic envelope state and public counters without changing congestion or verification query behavior yet. -- The expected result for this slice is unchanged routing behavior; the new envelope counters should stay at zero until the broad phase starts using them. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2312 | 0.2343 | +0.0031 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 213.0000 | 213.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | - | 0.0000 | - | -| example_05_orientation_stress | congestion_net_envelope_cache_hits | - | 0.0000 | - | -| example_05_orientation_stress | congestion_net_envelope_cache_misses | - | 0.0000 | - | -| example_05_orientation_stress | congestion_grid_span_cache_hits | 133.0000 | 133.0000 | +0.0000 | -| example_05_orientation_stress | congestion_grid_span_cache_misses | 22.0000 | 22.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 19.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 18.0000 | +0.0000 | -| example_05_orientation_stress | verify_dynamic_candidate_nets | - | 0.0000 | - | -| example_07_large_scale_routing | duration_s | 0.1858 | 0.1833 | -0.0026 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_net_envelope_cache_hits | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_net_envelope_cache_misses | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_grid_span_cache_hits | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_grid_span_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | verify_dynamic_candidate_nets | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 84.6663 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 173498.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 344747.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_net_envelope_cache_hits | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_net_envelope_cache_misses | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_grid_span_cache_hits | - | 199762.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_grid_span_cache_misses | - | 26740.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 364731.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 305397.0000 | - | -| example_07_large_scale_routing_no_warm_start | verify_dynamic_candidate_nets | - | 0.0000 | - | -## Step 19 - Route-time net-envelope broad phase - -Measured on 2026-03-31T23:10:12-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Congestion checks now query per-net dynamic envelopes before descending into cached per-object candidate sets. -- Search order is unchanged in this slice; the acceptance signal is lower candidate-net and exact-pair work at the same node count. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2312 | 0.2443 | +0.0131 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 213.0000 | 213.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | - | 15.0000 | - | -| example_05_orientation_stress | congestion_net_envelope_cache_hits | - | 133.0000 | - | -| example_05_orientation_stress | congestion_net_envelope_cache_misses | - | 22.0000 | - | -| example_05_orientation_stress | congestion_grid_span_cache_hits | 133.0000 | 11.0000 | -122.0000 | -| example_05_orientation_stress | congestion_grid_span_cache_misses | 22.0000 | 4.0000 | -18.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 19.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 18.0000 | +0.0000 | -| example_05_orientation_stress | verify_dynamic_candidate_nets | - | 0.0000 | - | -| example_07_large_scale_routing | duration_s | 0.1858 | 0.1940 | +0.0081 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_net_envelope_cache_hits | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_net_envelope_cache_misses | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_grid_span_cache_hits | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_grid_span_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | verify_dynamic_candidate_nets | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 85.7274 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 173498.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 344747.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 557244.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_net_envelope_cache_hits | - | 199762.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_net_envelope_cache_misses | - | 26740.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_grid_span_cache_hits | - | 193229.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_grid_span_cache_misses | - | 25872.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 364731.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 305397.0000 | - | -| example_07_large_scale_routing_no_warm_start | verify_dynamic_candidate_nets | - | 0.0000 | - | -## Step 20 - Verification net-envelope broad phase - -Measured on 2026-03-31T23:14:19-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Final verification now queries dynamic net envelopes before descending into per-object overlap checks. -- This slice should leave routing search metrics stable and reduce dynamic verification scans when non-overlapping nets are present. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2312 | 0.2370 | +0.0058 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 213.0000 | 213.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | - | 15.0000 | - | -| example_05_orientation_stress | congestion_net_envelope_cache_hits | - | 133.0000 | - | -| example_05_orientation_stress | congestion_net_envelope_cache_misses | - | 22.0000 | - | -| example_05_orientation_stress | congestion_grid_span_cache_hits | 133.0000 | 11.0000 | -122.0000 | -| example_05_orientation_stress | congestion_grid_span_cache_misses | 22.0000 | 4.0000 | -18.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 19.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 18.0000 | +0.0000 | -| example_05_orientation_stress | verify_dynamic_candidate_nets | - | 3.0000 | - | -| example_05_orientation_stress | verify_dynamic_exact_pair_checks | 4.0000 | 4.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1858 | 0.1843 | -0.0016 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_net_envelope_cache_hits | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_net_envelope_cache_misses | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_grid_span_cache_hits | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_grid_span_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | verify_dynamic_candidate_nets | - | 158.0000 | - | -| example_07_large_scale_routing | verify_dynamic_exact_pair_checks | 27.0000 | 24.0000 | -3.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 85.5035 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 173498.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 344747.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 557244.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_net_envelope_cache_hits | - | 199762.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_net_envelope_cache_misses | - | 26740.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_grid_span_cache_hits | - | 193229.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_grid_span_cache_misses | - | 25872.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 364731.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 305397.0000 | - | -| example_07_large_scale_routing_no_warm_start | verify_dynamic_candidate_nets | - | 3723.0000 | - | -| example_07_large_scale_routing_no_warm_start | verify_dynamic_exact_pair_checks | - | 1428.0000 | - | -## Step 21 - Per-net grid occupancy before object descent - -Measured on 2026-03-31T23:45:12-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Congestion checks now cache candidate net ids from dynamic grid occupancy before building the heavier per-span object unions. -- On the no-warm-start example_07 canary, candidate nets fell materially from the prior net-envelope pass while nodes expanded and congestion check calls stayed flat. -- Object-level candidate ids and exact pair checks stayed essentially unchanged, so the next likely win is a finer-grained dynamic structure per long net rather than more cache layering. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2327 | 0.2399 | +0.0072 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 213.0000 | 213.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 15.0000 | +0.0000 | -| example_05_orientation_stress | congestion_net_envelope_cache_hits | 133.0000 | 133.0000 | +0.0000 | -| example_05_orientation_stress | congestion_net_envelope_cache_misses | 22.0000 | 22.0000 | +0.0000 | -| example_05_orientation_stress | congestion_grid_net_cache_hits | - | 11.0000 | - | -| example_05_orientation_stress | congestion_grid_net_cache_misses | - | 4.0000 | - | -| example_05_orientation_stress | congestion_grid_span_cache_hits | 11.0000 | 11.0000 | +0.0000 | -| example_05_orientation_stress | congestion_grid_span_cache_misses | 4.0000 | 4.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 19.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 18.0000 | +0.0000 | -| example_05_orientation_stress | verify_dynamic_candidate_nets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | verify_dynamic_exact_pair_checks | 4.0000 | 4.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1865 | 0.1881 | +0.0015 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_net_envelope_cache_hits | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_net_envelope_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_grid_net_cache_hits | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_grid_net_cache_misses | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_grid_span_cache_hits | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_grid_span_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | verify_dynamic_candidate_nets | 158.0000 | 158.0000 | +0.0000 | -| example_07_large_scale_routing | verify_dynamic_exact_pair_checks | 24.0000 | 24.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 85.4211 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 173498.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 344747.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 386147.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_net_envelope_cache_hits | - | 199762.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_net_envelope_cache_misses | - | 26740.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_grid_net_cache_hits | - | 193229.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_grid_net_cache_misses | - | 25872.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_grid_span_cache_hits | - | 189741.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_grid_span_cache_misses | - | 25579.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 364731.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 305397.0000 | - | -| example_07_large_scale_routing_no_warm_start | verify_dynamic_candidate_nets | - | 3723.0000 | - | -| example_07_large_scale_routing_no_warm_start | verify_dynamic_exact_pair_checks | - | 1436.0000 | - | -## Step 22 - Segmented per-net dynamic envelopes (rejected) - -Measured on 2026-04-01T00:02:00-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Dynamic objects were grouped into small per-net segment envelopes and congestion/verification descended through those groups before raw object checks. -- This was the first pass aimed at reducing object-level confirmation work directly, but it regressed the no-warm-start example_07 canary instead of helping it. -- Relative to the accepted per-net grid-occupancy state, the canary worsened from about `85.36s` to `99.81s`, from `173498` to `187339` expanded nodes, from `344747` to `378630` congestion checks, and from `364731` to `392058` candidate ids. -- The segment layer appears to have increased search churn and broad-phase overhead enough to outweigh any local pruning benefit, so this pass was rejected and reverted. -## Step 23 - End-of-iteration reverify only - -Measured on 2026-04-01T19:00:59-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Added full end-of-iteration reverify using final installed geometry before deciding whether negotiated congestion should continue. -- This slice still reroutes every net every iteration; it only changes conflict truth and iteration metrics. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_02_congestion_resolution | duration_s | 0.3241 | 0.3359 | +0.0118 | -| example_02_congestion_resolution | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_02_congestion_resolution | nets_routed | 3.0000 | 3.0000 | +0.0000 | -| example_02_congestion_resolution | nets_carried_forward | - | 0.0000 | - | -| example_02_congestion_resolution | nodes_expanded | 366.0000 | 366.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | iteration_reverify_calls | - | 1.0000 | - | -| example_02_congestion_resolution | iteration_reverified_nets | - | 3.0000 | - | -| example_02_congestion_resolution | iteration_conflicting_nets | - | 0.0000 | - | -| example_02_congestion_resolution | iteration_conflict_edges | - | 0.0000 | - | -| example_02_congestion_resolution | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | duration_s | 0.2283 | 0.2312 | +0.0029 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nets_carried_forward | - | 0.0000 | - | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 213.0000 | 213.0000 | +0.0000 | -| example_05_orientation_stress | congestion_cache_misses | 213.0000 | 213.0000 | +0.0000 | -| example_05_orientation_stress | iteration_reverify_calls | - | 2.0000 | - | -| example_05_orientation_stress | iteration_reverified_nets | - | 6.0000 | - | -| example_05_orientation_stress | iteration_conflicting_nets | - | 2.0000 | - | -| example_05_orientation_stress | iteration_conflict_edges | - | 1.0000 | - | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 15.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 19.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 18.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1888 | 0.1921 | +0.0032 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nets_carried_forward | - | 0.0000 | - | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | iteration_reverify_calls | - | 1.0000 | - | -| example_07_large_scale_routing | iteration_reverified_nets | - | 10.0000 | - | -| example_07_large_scale_routing | iteration_conflicting_nets | - | 0.0000 | - | -| example_07_large_scale_routing | iteration_conflict_edges | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 85.3822 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 15.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 150.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_carried_forward | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 173498.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 344747.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_misses | - | 344747.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_reverify_calls | - | 15.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_reverified_nets | - | 150.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_conflicting_nets | - | 145.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_conflict_edges | - | 165.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 386147.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 364731.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 305397.0000 | - | -## Step 24 - Early stop on stalled conflict graph - -Measured on 2026-04-01T19:16:22-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Rejected selective reroute working-set policies after they made the no-warm-start canary dramatically slower. -- Kept end-of-iteration reverify and now stop negotiated-congestion once the final conflict graph repeats twice with no structural change. -- On the no-warm-start canary this cut runtime from about 85.9s to 5.45s, with route iterations dropping from 15 to 4 and congestion checks from 344747 to 12096. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_02_congestion_resolution | duration_s | 0.3241 | 0.3460 | +0.0219 | -| example_02_congestion_resolution | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_02_congestion_resolution | nets_routed | 3.0000 | 3.0000 | +0.0000 | -| example_02_congestion_resolution | nets_carried_forward | - | 0.0000 | - | -| example_02_congestion_resolution | nodes_expanded | 366.0000 | 366.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | iteration_reverify_calls | - | 1.0000 | - | -| example_02_congestion_resolution | iteration_reverified_nets | - | 3.0000 | - | -| example_02_congestion_resolution | iteration_conflicting_nets | - | 0.0000 | - | -| example_02_congestion_resolution | iteration_conflict_edges | - | 0.0000 | - | -| example_02_congestion_resolution | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | duration_s | 0.2283 | 0.3251 | +0.0968 | -| example_05_orientation_stress | route_iterations | 2.0000 | 3.0000 | +1.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 9.0000 | +3.0000 | -| example_05_orientation_stress | nets_carried_forward | - | 0.0000 | - | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 571.0000 | +285.0000 | -| example_05_orientation_stress | congestion_check_calls | 213.0000 | 306.0000 | +93.0000 | -| example_05_orientation_stress | congestion_cache_misses | 213.0000 | 306.0000 | +93.0000 | -| example_05_orientation_stress | iteration_reverify_calls | - | 3.0000 | - | -| example_05_orientation_stress | iteration_reverified_nets | - | 9.0000 | - | -| example_05_orientation_stress | iteration_conflicting_nets | - | 6.0000 | - | -| example_05_orientation_stress | iteration_conflict_edges | - | 3.0000 | - | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 92.0000 | +77.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 80.0000 | +61.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 68.0000 | +50.0000 | -| example_07_large_scale_routing | duration_s | 0.1888 | 0.1998 | +0.0110 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nets_carried_forward | - | 0.0000 | - | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | iteration_reverify_calls | - | 1.0000 | - | -| example_07_large_scale_routing | iteration_reverified_nets | - | 10.0000 | - | -| example_07_large_scale_routing | iteration_conflicting_nets | - | 0.0000 | - | -| example_07_large_scale_routing | iteration_conflict_edges | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 5.4956 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_carried_forward | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4580.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 12096.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_misses | - | 12096.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_reverify_calls | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_reverified_nets | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_conflicting_nets | - | 34.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_conflict_edges | - | 52.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 24413.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 21820.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 18030.0000 | - | -## Step 25 - Finalize stalled conflict stop - -Measured on 2026-04-01T19:17:59-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Removed the leftover full-reroute pre-eviction from the rejected working-set experiment so normal multi-net cases keep their previous search behavior. -- Accepted state: end-of-iteration reverify plus early termination when the conflict graph repeats twice without structural change. -- The no-warm-start example_07 canary now runs in about 5.8s with 4 iterations and 9865 congestion checks, while example_05 returns to 2 iterations and 213 congestion checks. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_02_congestion_resolution | duration_s | 0.3241 | 0.3451 | +0.0209 | -| example_02_congestion_resolution | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_02_congestion_resolution | nets_routed | 3.0000 | 3.0000 | +0.0000 | -| example_02_congestion_resolution | nets_carried_forward | - | 0.0000 | - | -| example_02_congestion_resolution | nodes_expanded | 366.0000 | 366.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | iteration_reverify_calls | - | 1.0000 | - | -| example_02_congestion_resolution | iteration_reverified_nets | - | 3.0000 | - | -| example_02_congestion_resolution | iteration_conflicting_nets | - | 0.0000 | - | -| example_02_congestion_resolution | iteration_conflict_edges | - | 0.0000 | - | -| example_02_congestion_resolution | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | duration_s | 0.2283 | 0.2433 | +0.0150 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nets_carried_forward | - | 0.0000 | - | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 213.0000 | 213.0000 | +0.0000 | -| example_05_orientation_stress | congestion_cache_misses | 213.0000 | 213.0000 | +0.0000 | -| example_05_orientation_stress | iteration_reverify_calls | - | 2.0000 | - | -| example_05_orientation_stress | iteration_reverified_nets | - | 6.0000 | - | -| example_05_orientation_stress | iteration_conflicting_nets | - | 2.0000 | - | -| example_05_orientation_stress | iteration_conflict_edges | - | 1.0000 | - | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 15.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 19.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 18.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1888 | 0.1982 | +0.0094 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nets_carried_forward | - | 0.0000 | - | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | iteration_reverify_calls | - | 1.0000 | - | -| example_07_large_scale_routing | iteration_reverified_nets | - | 10.0000 | - | -| example_07_large_scale_routing | iteration_conflicting_nets | - | 0.0000 | - | -| example_07_large_scale_routing | iteration_conflict_edges | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 5.7283 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_carried_forward | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 6567.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 9865.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_misses | - | 9865.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_reverify_calls | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_reverified_nets | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_conflicting_nets | - | 35.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_conflict_edges | - | 52.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 12879.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 13342.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 11116.0000 | - | -## Step 24 - Conflict-directed reroute working set - -Measured on 2026-04-01T19:30:43-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Later iterations now reroute only unresolved nets plus a deterministic greedy cover of the end-of-iteration conflict graph. -- Repeated conflict signatures widen the working set to all conflicting nets and then all nets once if the graph keeps stalling. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_02_congestion_resolution | duration_s | 0.3241 | 0.3261 | +0.0020 | -| example_02_congestion_resolution | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_02_congestion_resolution | nets_routed | 3.0000 | 3.0000 | +0.0000 | -| example_02_congestion_resolution | nets_carried_forward | - | 0.0000 | - | -| example_02_congestion_resolution | nodes_expanded | 366.0000 | 366.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | iteration_reverify_calls | - | 1.0000 | - | -| example_02_congestion_resolution | iteration_reverified_nets | - | 3.0000 | - | -| example_02_congestion_resolution | iteration_conflicting_nets | - | 0.0000 | - | -| example_02_congestion_resolution | iteration_conflict_edges | - | 0.0000 | - | -| example_02_congestion_resolution | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | duration_s | 0.2283 | 0.2246 | -0.0037 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 5.0000 | -1.0000 | -| example_05_orientation_stress | nets_carried_forward | - | 1.0000 | - | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 284.0000 | -2.0000 | -| example_05_orientation_stress | congestion_check_calls | 213.0000 | 207.0000 | -6.0000 | -| example_05_orientation_stress | congestion_cache_misses | 213.0000 | 207.0000 | -6.0000 | -| example_05_orientation_stress | iteration_reverify_calls | - | 2.0000 | - | -| example_05_orientation_stress | iteration_reverified_nets | - | 6.0000 | - | -| example_05_orientation_stress | iteration_conflicting_nets | - | 2.0000 | - | -| example_05_orientation_stress | iteration_conflict_edges | - | 1.0000 | - | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 15.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 19.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 18.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1888 | 0.1884 | -0.0004 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nets_carried_forward | - | 0.0000 | - | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | iteration_reverify_calls | - | 1.0000 | - | -| example_07_large_scale_routing | iteration_reverified_nets | - | 10.0000 | - | -| example_07_large_scale_routing | iteration_conflicting_nets | - | 0.0000 | - | -| example_07_large_scale_routing | iteration_conflict_edges | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 1626.2304 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 13.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 108.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_carried_forward | - | 13.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 1559998.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3699692.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_misses | - | 3699692.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_reverify_calls | - | 12.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_reverified_nets | - | 120.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_conflicting_nets | - | 113.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_conflict_edges | - | 138.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 3444090.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 2987961.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 2440828.0000 | - | -## Step 26 rejected - Progressive freezing reverted - -Measured on 2026-04-01T20:20:32-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- The progressive-freezing experiment was reverted after bounded no-warm-start probes reached only 2 valid routes after 4 iterations and consumed the one-shot thaw without restoring correctness. -- The tree below is the restored pre-freezing state so later passes can continue from the last accepted congestion baseline. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_02_congestion_resolution | duration_s | 0.3384 | 0.3500 | +0.0115 | -| example_02_congestion_resolution | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_02_congestion_resolution | nets_routed | 3.0000 | 3.0000 | +0.0000 | -| example_02_congestion_resolution | nets_carried_forward | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | nodes_expanded | 366.0000 | 366.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | iteration_reverify_calls | 1.0000 | 1.0000 | +0.0000 | -| example_02_congestion_resolution | iteration_conflicting_nets | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | iteration_conflict_edges | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | duration_s | 0.2366 | 0.2547 | +0.0180 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nets_carried_forward | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 213.0000 | 213.0000 | +0.0000 | -| example_05_orientation_stress | iteration_reverify_calls | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | iteration_conflicting_nets | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | iteration_conflict_edges | 1.0000 | 1.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 15.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 19.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 18.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1994 | 0.2061 | +0.0067 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nets_carried_forward | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | iteration_reverify_calls | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | iteration_conflicting_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | iteration_conflict_edges | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 5.9146 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_carried_forward | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 6567.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 9865.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_reverify_calls | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_conflicting_nets | - | 35.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_conflict_edges | - | 52.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 12879.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 13342.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 11116.0000 | - | -## Step 26 - Progressive freezing and frozen hard prunes - -Measured on 2026-04-01T20:33:10-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Completed nets are now frozen after end-of-iteration reverify, later iterations reroute only the remaining unlocked nets, and overlaps with frozen nets are rejected as hard collisions. -- This slice also tracks best-so-far iteration quality so later slices can safely restore the strongest partial solution. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_02_congestion_resolution | duration_s | 0.3384 | 0.3202 | -0.0182 | -| example_02_congestion_resolution | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_02_congestion_resolution | nets_routed | 3.0000 | 3.0000 | +0.0000 | -| example_02_congestion_resolution | nets_carried_forward | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | frozen_nets_promoted | - | 3.0000 | - | -| example_02_congestion_resolution | frozen_nets_thawed | - | 0.0000 | - | -| example_02_congestion_resolution | frozen_net_hard_prunes | - | 0.0000 | - | -| example_02_congestion_resolution | best_iteration_completed_nets | - | 3.0000 | - | -| example_02_congestion_resolution | best_iteration_conflict_edges | - | 0.0000 | - | -| example_02_congestion_resolution | best_iteration_dynamic_collisions | - | 0.0000 | - | -| example_02_congestion_resolution | nodes_expanded | 366.0000 | 366.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | duration_s | 0.2366 | 11.5966 | +11.3600 | -| example_05_orientation_stress | route_iterations | 2.0000 | 6.0000 | +4.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 14.0000 | +8.0000 | -| example_05_orientation_stress | nets_carried_forward | 0.0000 | 4.0000 | +4.0000 | -| example_05_orientation_stress | frozen_nets_promoted | - | 2.0000 | - | -| example_05_orientation_stress | frozen_nets_thawed | - | 1.0000 | - | -| example_05_orientation_stress | frozen_net_hard_prunes | - | 865.0000 | - | -| example_05_orientation_stress | best_iteration_completed_nets | - | 1.0000 | - | -| example_05_orientation_stress | best_iteration_conflict_edges | - | 1.0000 | - | -| example_05_orientation_stress | best_iteration_dynamic_collisions | - | 2.0000 | - | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 14395.0000 | +14109.0000 | -| example_05_orientation_stress | congestion_check_calls | 213.0000 | 24765.0000 | +24552.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 8658.0000 | +8643.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 10770.0000 | +10751.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 8579.0000 | +8561.0000 | -| example_07_large_scale_routing | duration_s | 0.1994 | 0.1901 | -0.0092 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nets_carried_forward | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | frozen_nets_promoted | - | 10.0000 | - | -| example_07_large_scale_routing | frozen_nets_thawed | - | 0.0000 | - | -| example_07_large_scale_routing | frozen_net_hard_prunes | - | 0.0000 | - | -| example_07_large_scale_routing | best_iteration_completed_nets | - | 10.0000 | - | -| example_07_large_scale_routing | best_iteration_conflict_edges | - | 0.0000 | - | -| example_07_large_scale_routing | best_iteration_dynamic_collisions | - | 0.0000 | - | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 2136.7523 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 8.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 62.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_carried_forward | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | frozen_nets_promoted | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | frozen_nets_thawed | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | frozen_net_hard_prunes | - | 76321.0000 | - | -| example_07_large_scale_routing_no_warm_start | best_iteration_completed_nets | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | best_iteration_conflict_edges | - | 12.0000 | - | -| example_07_large_scale_routing_no_warm_start | best_iteration_dynamic_collisions | - | 50.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 1849024.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 4049028.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 4889029.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 4032868.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 3215112.0000 | - | -## Step 26 - Progressive freezing and frozen hard prunes - -Measured on 2026-04-01T20:36:40-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Completed nets are frozen after end-of-iteration reverify, later iterations reroute only the remaining unlocked nets, and overlaps with frozen nets are rejected as hard collisions. -- The router also restores the strongest reverified iteration snapshot before final refinement and verification. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_02_congestion_resolution | duration_s | 0.3384 | 0.3401 | +0.0017 | -| example_02_congestion_resolution | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_02_congestion_resolution | nets_routed | 3.0000 | 3.0000 | +0.0000 | -| example_02_congestion_resolution | nets_carried_forward | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | frozen_nets_promoted | - | 3.0000 | - | -| example_02_congestion_resolution | frozen_nets_thawed | - | 0.0000 | - | -| example_02_congestion_resolution | frozen_net_hard_prunes | - | 0.0000 | - | -| example_02_congestion_resolution | best_iteration_completed_nets | - | 3.0000 | - | -| example_02_congestion_resolution | best_iteration_conflict_edges | - | 0.0000 | - | -| example_02_congestion_resolution | best_iteration_dynamic_collisions | - | 0.0000 | - | -| example_02_congestion_resolution | nodes_expanded | 366.0000 | 366.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | iteration_reverify_calls | 1.0000 | 1.0000 | +0.0000 | -| example_02_congestion_resolution | iteration_conflicting_nets | 0.0000 | 0.0000 | +0.0000 | -| example_02_congestion_resolution | iteration_conflict_edges | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | duration_s | 0.2366 | 12.3369 | +12.1002 | -| example_05_orientation_stress | route_iterations | 2.0000 | 6.0000 | +4.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 14.0000 | +8.0000 | -| example_05_orientation_stress | nets_carried_forward | 0.0000 | 4.0000 | +4.0000 | -| example_05_orientation_stress | frozen_nets_promoted | - | 2.0000 | - | -| example_05_orientation_stress | frozen_nets_thawed | - | 1.0000 | - | -| example_05_orientation_stress | frozen_net_hard_prunes | - | 865.0000 | - | -| example_05_orientation_stress | best_iteration_completed_nets | - | 1.0000 | - | -| example_05_orientation_stress | best_iteration_conflict_edges | - | 1.0000 | - | -| example_05_orientation_stress | best_iteration_dynamic_collisions | - | 2.0000 | - | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 14395.0000 | +14109.0000 | -| example_05_orientation_stress | congestion_check_calls | 213.0000 | 24765.0000 | +24552.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 8658.0000 | +8643.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 10770.0000 | +10751.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 8579.0000 | +8561.0000 | -| example_05_orientation_stress | iteration_reverify_calls | 2.0000 | 6.0000 | +4.0000 | -| example_05_orientation_stress | iteration_conflicting_nets | 2.0000 | 12.0000 | +10.0000 | -| example_05_orientation_stress | iteration_conflict_edges | 1.0000 | 6.0000 | +5.0000 | -| example_07_large_scale_routing | duration_s | 0.1994 | 0.1978 | -0.0016 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nets_carried_forward | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | frozen_nets_promoted | - | 10.0000 | - | -| example_07_large_scale_routing | frozen_nets_thawed | - | 0.0000 | - | -| example_07_large_scale_routing | frozen_net_hard_prunes | - | 0.0000 | - | -| example_07_large_scale_routing | best_iteration_completed_nets | - | 10.0000 | - | -| example_07_large_scale_routing | best_iteration_conflict_edges | - | 0.0000 | - | -| example_07_large_scale_routing | best_iteration_dynamic_collisions | - | 0.0000 | - | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | iteration_reverify_calls | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | iteration_conflicting_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | iteration_conflict_edges | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 1500.4410 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 7.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 60.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_carried_forward | - | 8.0000 | - | -| example_07_large_scale_routing_no_warm_start | frozen_nets_promoted | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | frozen_nets_thawed | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | frozen_net_hard_prunes | - | 37879.0000 | - | -| example_07_large_scale_routing_no_warm_start | best_iteration_completed_nets | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | best_iteration_conflict_edges | - | 12.0000 | - | -| example_07_large_scale_routing_no_warm_start | best_iteration_dynamic_collisions | - | 50.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 1282078.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 2860073.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 3432589.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 2740129.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 2266598.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_reverify_calls | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_conflicting_nets | - | 51.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_conflict_edges | - | 77.0000 | - | -## Step 27 - Congestion presence precheck - -Measured on 2026-04-01T20:49:16-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- A cached per-span presence precheck now skips full congestion evaluation when a move's dilated polygons only cover dynamic-grid cells with no other routed nets. -- The goal of this slice is to reduce congestion_check_calls without changing search outcomes or the dynamic exact-check path. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2366 | 0.2573 | +0.0206 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 213.0000 | 155.0000 | -58.0000 | -| example_05_orientation_stress | congestion_presence_cache_hits | - | 185.0000 | - | -| example_05_orientation_stress | congestion_presence_cache_misses | - | 30.0000 | - | -| example_05_orientation_stress | congestion_presence_skips | - | 58.0000 | - | -| example_05_orientation_stress | congestion_cache_hits | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | congestion_cache_misses | 213.0000 | 155.0000 | -58.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 15.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 19.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 18.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1994 | 0.1977 | -0.0017 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_presence_cache_hits | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_presence_cache_misses | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_presence_skips | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_cache_hits | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 5.6221 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 6567.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 4549.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_presence_cache_hits | - | 7568.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_presence_cache_misses | - | 2480.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_presence_skips | - | 5482.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_hits | - | 16.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_misses | - | 4549.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 12879.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 13342.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 11116.0000 | - | -## Step 28 - Candidate-net congestion precheck - -Measured on 2026-04-01T20:59:46-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- After the dynamic-grid occupancy precheck passes, search now asks whether any candidate nets survive the existing envelope and grid-net filters before paying for full congestion evaluation. -- This slice should reduce congestion_check_calls further if many occupied spans still have no candidate nets after the broad phases. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2491 | 0.2500 | +0.0009 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 155.0000 | 18.0000 | -137.0000 | -| example_05_orientation_stress | congestion_presence_cache_hits | 185.0000 | 185.0000 | +0.0000 | -| example_05_orientation_stress | congestion_presence_cache_misses | 30.0000 | 30.0000 | +0.0000 | -| example_05_orientation_stress | congestion_presence_skips | 58.0000 | 58.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_precheck_hits | - | 135.0000 | - | -| example_05_orientation_stress | congestion_candidate_precheck_misses | - | 22.0000 | - | -| example_05_orientation_stress | congestion_candidate_precheck_skips | - | 139.0000 | - | -| example_05_orientation_stress | congestion_cache_hits | 2.0000 | 0.0000 | -2.0000 | -| example_05_orientation_stress | congestion_cache_misses | 155.0000 | 18.0000 | -137.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 14.0000 | -1.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 18.0000 | -1.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 17.0000 | -1.0000 | -| example_07_large_scale_routing | duration_s | 0.1978 | 0.1941 | -0.0037 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_presence_cache_hits | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_presence_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_presence_skips | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_precheck_hits | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_candidate_precheck_misses | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_candidate_precheck_skips | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_cache_hits | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 89.2302 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 9.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 90.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 113735.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 136225.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_presence_cache_hits | - | 217089.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_presence_cache_misses | - | 18365.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_presence_skips | - | 86782.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_precheck_hits | - | 135690.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_precheck_misses | - | 12826.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_precheck_skips | - | 10244.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_hits | - | 1893.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_misses | - | 136225.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 243951.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 228721.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 190301.0000 | - | -## Step 28b - Candidate-net congestion precheck (corrected) - -Measured on 2026-04-01T21:00:54-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- The first candidate-net precheck attempt cached exact-bounds results by span and was not safe; this corrected slice uses a conservative span-based precheck. -- Acceptance requires the no-warm-start canary to stay near the current 4-iteration / 40-net routed shape while still reducing congestion_check_calls. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2491 | 0.2461 | -0.0030 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 155.0000 | 155.0000 | +0.0000 | -| example_05_orientation_stress | congestion_presence_cache_hits | 185.0000 | 185.0000 | +0.0000 | -| example_05_orientation_stress | congestion_presence_cache_misses | 30.0000 | 30.0000 | +0.0000 | -| example_05_orientation_stress | congestion_presence_skips | 58.0000 | 58.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_precheck_hits | - | 135.0000 | - | -| example_05_orientation_stress | congestion_candidate_precheck_misses | - | 22.0000 | - | -| example_05_orientation_stress | congestion_candidate_precheck_skips | - | 0.0000 | - | -| example_05_orientation_stress | congestion_cache_hits | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | congestion_cache_misses | 155.0000 | 155.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 15.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 19.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 18.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1978 | 0.1979 | +0.0001 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_presence_cache_hits | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_presence_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_presence_skips | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_precheck_hits | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_candidate_precheck_misses | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_candidate_precheck_skips | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_cache_hits | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_cache_misses | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 5.6758 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 6567.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 4420.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_presence_cache_hits | - | 7568.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_presence_cache_misses | - | 2480.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_presence_skips | - | 5482.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_precheck_hits | - | 2828.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_precheck_misses | - | 1737.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_precheck_skips | - | 129.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_hits | - | 16.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_cache_misses | - | 4420.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 12879.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 13342.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 11116.0000 | - | -## Step 29 - Correctness-aware measurement logging - -Measured on 2026-04-01T21:18:56-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- The diff script now logs top-level outcome counts so future routing-loop changes can be judged on returned result quality as well as runtime and congestion counters. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2370 | 0.2507 | +0.0137 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 155.0000 | 155.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1950 | 0.1992 | +0.0042 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 5.7234 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 1.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 6567.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 4420.0000 | - | -## Step 30 - Best iteration snapshot restoration - -Measured on 2026-04-01T21:20:51-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- The routing loop now snapshots the strongest reverified intermediate result set and restores it before final refinement/final verification, including timeout exits. -- This slice keeps the old repeated-conflict stop rule so any quality change can be attributed to snapshot restoration alone. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2370 | 0.2437 | +0.0067 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 155.0000 | 155.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1950 | 0.1937 | -0.0013 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 5.5246 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 6567.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 4420.0000 | - | -## Step 31 - Improvement-based stagnation stop - -Measured on 2026-04-01T21:23:19-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- The negotiated-congestion loop now stops after two consecutive iterations with no improvement in the best-so-far reverified snapshot instead of using repeated conflict signatures. -- Best-snapshot restoration remains enabled, so the returned results should reflect the strongest intermediate iteration even if later iterations stall. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2370 | 0.2393 | +0.0023 | -| example_05_orientation_stress | valid_results | 3.0000 | 1.0000 | -2.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 155.0000 | 155.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1950 | 0.1884 | -0.0066 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 5.4360 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 6567.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 4420.0000 | - | -## Step 31 rejected - Improvement-based stagnation reverted - -Measured on 2026-04-01T21:25:17-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- The no-improvement stop rule was reverted because it regressed example_05 from 3 valid routes to 1 even though the no-warm-start canary stayed flat. -- The tree below is the restored best-snapshot state with the older repeated-conflict stop rule still in place. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2370 | 0.2425 | +0.0055 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 155.0000 | 155.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1950 | 0.1936 | -0.0014 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 5.5321 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 6567.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 4420.0000 | - | -## Step 32 tiered-iteration dynamic hard blocks - -Measured on 2026-04-01T21:42:45-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Treat already-routed dynamic paths as hard blockers only during iteration 0 when warm-start is disabled. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2348 | 0.2466 | +0.0118 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 155.0000 | 226.0000 | +71.0000 | -| example_05_orientation_stress | tiered_dynamic_hard_prunes | - | 0.0000 | - | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 51.0000 | +36.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 67.0000 | +48.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 56.0000 | +38.0000 | -| example_07_large_scale_routing | duration_s | 0.1945 | 0.1931 | -0.0014 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | tiered_dynamic_hard_prunes | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 8.7624 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 11200.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 5355.0000 | - | -| example_07_large_scale_routing_no_warm_start | tiered_dynamic_hard_prunes | - | 632.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 13623.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 13469.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 11346.0000 | - | -## Step 32 reverted - -Measured on 2026-04-01T21:44:47-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Reverted tiered-iteration dynamic hard blockers after regressions in example_05 and the no-warm-start example_07 canary. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2348 | 0.2462 | +0.0114 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 155.0000 | 155.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 15.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 19.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 18.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1945 | 0.1940 | -0.0005 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 5.5497 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 6567.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 4420.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 12879.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 13342.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 11116.0000 | - | - -## Step 34 rejected - -Measured on 2026-04-01T22:08:00-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Explored order/seed and reroute-heuristic sensitivity before the slice. One-iteration no-warm-start probes were flat at `1` valid route across `user`, `shortest`, `longest`, and seeds `41`-`44`; two-iteration probes were flat at `2` valid routes across the same variants. -- Implemented a conflict-weighted congestion objective that weighted overlapping nets by prior completed status, conflict degree, and dynamic collision count. -- Rejected the slice after the no-warm-start canary failed to finish within a reasonable window and ran far longer than the accepted `~5.6s` state. The code was reverted before accepting any documentation or baseline changes. -## Step 33 carry forward completed nets - -Measured on 2026-04-01T21:58:50-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- After each reverify, reroute only nets that are still colliding, partial, or unroutable; keep completed nets installed as ordinary soft blockers. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2348 | 0.2528 | +0.0179 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 5.0000 | -1.0000 | -| example_05_orientation_stress | nets_carried_forward | 0.0000 | 1.0000 | +1.0000 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 284.0000 | -2.0000 | -| example_05_orientation_stress | congestion_check_calls | 155.0000 | 152.0000 | -3.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 15.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 19.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 18.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1945 | 0.1960 | +0.0015 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nets_carried_forward | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 49.8770 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 8.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 70.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_carried_forward | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 71162.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 80342.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 152845.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 136026.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 116066.0000 | - | -## Step 33 reverted - -Measured on 2026-04-01T21:59:33-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Reverted completed-net carry-forward after the no-warm-start canary exploded in iterations, nodes, and congestion checks without improving validity. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2348 | 0.2572 | +0.0224 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nets_carried_forward | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 286.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 155.0000 | 155.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 15.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 19.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 18.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1945 | 0.2024 | +0.0079 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nets_carried_forward | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 5.6270 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_carried_forward | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 6567.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 4420.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 12879.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 13342.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 11116.0000 | - | -## Step 35 reroute seed guidance - -Measured on 2026-04-01T22:22:54-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Guide post-tiered reroutes with the previous reached-target path seed by giving matching path-prefix moves a small cost bonus. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2348 | 0.2313 | -0.0036 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 299.0000 | +13.0000 | -| example_05_orientation_stress | congestion_check_calls | 155.0000 | 149.0000 | -6.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 23.0000 | +8.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 32.0000 | +13.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 30.0000 | +12.0000 | -| example_07_large_scale_routing | duration_s | 0.1945 | 0.1881 | -0.0064 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.5099 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 9604.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10010.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8312.0000 | - | - -## Step 39 rejected - -Measured on 2026-04-01T22:58:58-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Tried adding a reroute-only uncongested `max_cost` ceiling derived from the previous reached-target path cost plus slack for two extra bends. -- Rejected the slice before running the standard performance probe because it broke the stalled-conflict guardrail: the simple crossing case in `test_reverify_iterations_stop_early_on_stalled_conflict_graph` ran all `10` iterations instead of stopping early. -- Reverted the slice and restored the accepted Step 35 full-seed guidance state. - -## Step 36 rejected - -Measured on 2026-04-01T22:31:00-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Explored adding the longest still-valid prefix of the prior reached-target path as an additional seeded start node for later reroutes. -- Rejected the slice on runtime: the no-warm-start `example_07` measurement ran far beyond the accepted Step 35 `~3.5s` state before completion, indicating the extra seeded branch was expanding too much search. -- Reverted the slice and kept only the lighter Step 35 reroute-seed-guidance behavior. -## Step 34 conflict-weighted congestion objective - -Measured on 2026-04-01T22:38:11-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Weight congestion overlap cost by prior-iteration completed status, conflict degree, and dynamic collision count instead of counting every overlapping net equally. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2348 | 0.2390 | +0.0041 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 282.0000 | -4.0000 | -| example_05_orientation_stress | congestion_check_calls | 155.0000 | 145.0000 | -10.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 15.0000 | 15.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 19.0000 | 19.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 18.0000 | 18.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1945 | 0.1918 | -0.0027 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 1795.1890 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 1.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 16.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 1501303.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 1622620.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 5074171.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 4556689.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 4129698.0000 | - | -## Step 36 reusable prefix start nodes - -Measured on 2026-04-01T22:49:16-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- On later reroutes, add the longest still-valid prefix of the previous reached-target path as an additional seeded start node while keeping the original start branch available. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2239 | 0.2249 | +0.0010 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | reroute_prefix_paths_used | - | 3.0000 | - | -| example_05_orientation_stress | reroute_prefix_components_reused | - | 8.0000 | - | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 292.0000 | -7.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 125.0000 | -24.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 22.0000 | -1.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 31.0000 | -1.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 29.0000 | -1.0000 | -| example_07_large_scale_routing | duration_s | 0.1912 | 0.1916 | +0.0004 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reroute_prefix_paths_used | - | 0.0000 | - | -| example_07_large_scale_routing | reroute_prefix_components_reused | - | 0.0000 | - | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 229.2009 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 9.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 90.0000 | - | -| example_07_large_scale_routing_no_warm_start | reroute_prefix_paths_used | - | 65.0000 | - | -| example_07_large_scale_routing_no_warm_start | reroute_prefix_components_reused | - | 172.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 350958.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 470234.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 929523.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 853594.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 712783.0000 | - | -## Step 37 capped guidance rejected - -Measured on 2026-04-01T22:53:55-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Exploratory probe showed a mild runtime win when reroute guidance was capped to 4 segments, but the code/test slice did not land cleanly and was reverted before acceptance. -- Restored the accepted Step 35 full-seed guidance state and remeasured the standard probe set. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2239 | 0.2304 | +0.0065 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 23.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 32.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 30.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1912 | 0.1862 | -0.0050 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.4899 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 9604.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10010.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8312.0000 | - | -## Step 38 capped reroute guidance - -Measured on 2026-04-01T22:55:29-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Cap reroute guidance seeds to the first 4 segments on later iterations; keep the existing prefix-match bonus unchanged. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2239 | 0.2388 | +0.0150 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 23.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 32.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 30.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1912 | 0.1924 | +0.0012 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.6174 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 9604.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10010.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8312.0000 | - | -## Step 38 reverted - -Measured on 2026-04-01T22:56:22-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Reverted the 4-segment reroute-guidance cap after the standard probe set showed no counter improvement and only runtime noise. -- Restored the accepted Step 35 full-seed guidance state. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2239 | 0.2463 | +0.0224 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 23.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 32.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 30.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1912 | 0.1912 | -0.0000 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.5580 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 9604.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10010.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8312.0000 | - | -## Step 40 partial straight guidance - -Measured on 2026-04-01T23:01:12-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Allow reroute guidance to consume straight seeds incrementally so split straight moves can continue following a prior reached-target path. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2239 | 0.2329 | +0.0090 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 23.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 32.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 30.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1912 | 0.1879 | -0.0033 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.5305 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 9604.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10010.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8312.0000 | - | -## Step 40 reverted - -Measured on 2026-04-01T23:02:26-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Reverted partial straight-seed guidance after the standard probe set showed no counter deltas and no correctness gain. -- Restored the accepted Step 35 full-seed exact-match guidance state. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2239 | 0.2353 | +0.0115 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 23.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 32.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 30.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1912 | 0.1897 | -0.0015 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.5522 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 9604.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10010.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8312.0000 | - | -## Step 41 guidance counters - -Measured on 2026-04-01T23:04:31-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Add public counters for reroute guidance matches and total guidance bonus applied so later guidance changes can be measured directly. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2239 | 0.2544 | +0.0306 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves | - | 11.0000 | - | -| example_05_orientation_stress | guidance_bonus_applied | - | 687.5000 | - | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 23.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 32.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 30.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1912 | 0.1940 | +0.0027 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_bonus_applied | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.7438 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves | - | 101.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied | - | 6312.5000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 9604.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10010.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8312.0000 | - | -## Step 42 scaled guidance bonus - -Measured on 2026-04-02T00:18:11-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Scale reroute guidance bonus by matched move cost, capped at 50% of the move's own cost, so matched straights no longer become nearly free. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2300 | 0.2276 | -0.0024 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 275.0000 | -24.0000 | -| example_05_orientation_stress | guidance_match_moves | 11.0000 | 10.0000 | -1.0000 | -| example_05_orientation_stress | guidance_bonus_applied | 687.5000 | 368.6994 | -318.8006 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 120.0000 | -29.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 15.0000 | -8.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 19.0000 | -13.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 18.0000 | -12.0000 | -| example_07_large_scale_routing | duration_s | 0.2043 | 0.1861 | -0.0182 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 4.0027 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4747.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves | - | 101.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied | - | 2854.9698 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 4010.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 11537.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 12027.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 9988.0000 | - | -## Step 42 reverted - -Measured on 2026-04-02T00:19:47-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Reverted the scaled guidance bonus after the no-warm-start example_07 canary regressed in runtime, nodes, and congestion work without any validity gain. -- Restored the accepted fixed-bonus Step 35 guidance behavior. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2300 | 0.2339 | +0.0039 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves | 11.0000 | 11.0000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied | 687.5000 | 687.5000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 23.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 32.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 30.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.2043 | 0.1895 | -0.0148 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.5410 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves | - | 101.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied | - | 6312.5000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 9604.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10010.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8312.0000 | - | -## Step 43 guidance counters by move type - -Measured on 2026-04-02T00:24:23-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Split guidance matches and total applied bonus by move type so the next selective-guidance slice can target the dominant match class on the no-warm-start canary. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2300 | 0.2329 | +0.0030 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves | 11.0000 | 11.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_straight | - | 3.0000 | - | -| example_05_orientation_stress | guidance_match_moves_bend90 | - | 8.0000 | - | -| example_05_orientation_stress | guidance_match_moves_sbend | - | 0.0000 | - | -| example_05_orientation_stress | guidance_bonus_applied | 687.5000 | 687.5000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_straight | - | 187.5000 | - | -| example_05_orientation_stress | guidance_bonus_applied_bend90 | - | 500.0000 | - | -| example_05_orientation_stress | guidance_bonus_applied_sbend | - | 0.0000 | - | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 23.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 32.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 30.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.2043 | 0.1899 | -0.0143 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_straight | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_match_moves_bend90 | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_match_moves_sbend | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_bonus_applied | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_straight | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_bonus_applied_bend90 | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_bonus_applied_sbend | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.5484 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves | - | 101.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_straight | - | 52.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_bend90 | - | 43.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_sbend | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied | - | 6312.5000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_straight | - | 3250.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_bend90 | - | 2687.5000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_sbend | - | 375.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 9604.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10010.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8312.0000 | - | -## Step 50 terminal repair rejected - -Measured on 2026-04-02T10:18:00-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Added a bounded terminal repair phase for reached-but-colliding nets after best-snapshot restoration, with up to two sequential repair sweeps and completed nets treated as hard blockers during repair reroutes. -- The slice stayed within the node and congestion guardrails, but it did not improve the only important outcome: the no-warm-start `example_07` canary remained at `2/10/10`. -- Rejected the slice and reverted the code. The tree was restored to the accepted fixed-guidance branch without refreshing `docs/performance.md` or `docs/performance_baseline.json`. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2275 | 0.2400 | +0.0125 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | terminal_repair_sweeps | - | 0.0000 | - | -| example_05_orientation_stress | terminal_repair_nets_considered | - | 0.0000 | - | -| example_05_orientation_stress | terminal_repair_nets_accepted | - | 0.0000 | - | -| example_05_orientation_stress | terminal_repair_nets_rejected | - | 0.0000 | - | -| example_05_orientation_stress | terminal_repair_completed_promotions | - | 0.0000 | - | -| example_05_orientation_stress | repair_frozen_net_prunes | - | 0.0000 | - | -| example_07_large_scale_routing | duration_s | 0.1907 | 0.1969 | +0.0062 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | terminal_repair_sweeps | - | 0.0000 | - | -| example_07_large_scale_routing | terminal_repair_nets_considered | - | 0.0000 | - | -| example_07_large_scale_routing | terminal_repair_nets_accepted | - | 0.0000 | - | -| example_07_large_scale_routing | terminal_repair_nets_rejected | - | 0.0000 | - | -| example_07_large_scale_routing | terminal_repair_completed_promotions | - | 0.0000 | - | -| example_07_large_scale_routing | repair_frozen_net_prunes | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 6.5413 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 56.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 10691.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 4805.0000 | - | -| example_07_large_scale_routing_no_warm_start | terminal_repair_sweeps | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | terminal_repair_nets_considered | - | 16.0000 | - | -| example_07_large_scale_routing_no_warm_start | terminal_repair_nets_accepted | - | 8.0000 | - | -| example_07_large_scale_routing_no_warm_start | terminal_repair_nets_rejected | - | 8.0000 | - | -| example_07_large_scale_routing_no_warm_start | terminal_repair_completed_promotions | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | repair_frozen_net_prunes | - | 300.0000 | - | -## Step 50 rejected - -Measured on 2026-04-02T10:02:00-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Tried per-net incumbent acceptance with a second accepted-state reverify after each full candidate iteration. -- Rejected the slice immediately: the no-warm-start `example_07` canary stayed at `2/10/10` valid but regressed to `179.0440s`, `8` iterations, `80` nets routed, `234493` expanded nodes, and `255901` congestion checks. -- Reverted the code and restored the prior accepted fixed-guidance state without refreshing the committed baseline artifacts. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2275 | 0.2406 | +0.0132 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | iteration_candidate_results_accepted | - | 5.0000 | - | -| example_05_orientation_stress | iteration_incumbent_results_kept | - | 1.0000 | - | -| example_05_orientation_stress | iteration_accept_reverify_calls | - | 2.0000 | - | -| example_07_large_scale_routing | duration_s | 0.1907 | 0.2029 | +0.0122 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | iteration_candidate_results_accepted | - | 10.0000 | - | -| example_07_large_scale_routing | iteration_incumbent_results_kept | - | 0.0000 | - | -| example_07_large_scale_routing | iteration_accept_reverify_calls | - | 1.0000 | - | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 179.0440 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 8.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 80.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 234493.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 255901.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_candidate_results_accepted | - | 30.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_incumbent_results_kept | - | 50.0000 | - | -| example_07_large_scale_routing_no_warm_start | iteration_accept_reverify_calls | - | 8.0000 | - | -## Step 44 selective straight guidance - -Measured on 2026-04-02T00:25:53-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Keep full reroute guidance bonus for bend90 and sbend matches, but cut straight-match bonus in half. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2300 | 0.2361 | +0.0061 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves | 11.0000 | 11.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_straight | - | 3.0000 | - | -| example_05_orientation_stress | guidance_match_moves_bend90 | - | 8.0000 | - | -| example_05_orientation_stress | guidance_match_moves_sbend | - | 0.0000 | - | -| example_05_orientation_stress | guidance_bonus_applied | 687.5000 | 593.7500 | -93.7500 | -| example_05_orientation_stress | guidance_bonus_applied_straight | - | 93.7500 | - | -| example_05_orientation_stress | guidance_bonus_applied_bend90 | - | 500.0000 | - | -| example_05_orientation_stress | guidance_bonus_applied_sbend | - | 0.0000 | - | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 23.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 32.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 30.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.2043 | 0.1912 | -0.0131 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_straight | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_match_moves_bend90 | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_match_moves_sbend | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_bonus_applied | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_straight | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_bonus_applied_bend90 | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_bonus_applied_sbend | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 4.0413 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4747.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves | - | 101.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_straight | - | 52.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_bend90 | - | 43.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_sbend | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied | - | 4687.5000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_straight | - | 1625.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_bend90 | - | 2687.5000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_sbend | - | 375.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3721.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 10835.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 11093.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 9328.0000 | - | -## Step 45 selective bend guidance - -Measured on 2026-04-02T00:27:37-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Restore full straight guidance, but cut bend90-match bonus in half while keeping sbend matches at full bonus. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2300 | 0.2211 | -0.0089 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 272.0000 | -27.0000 | -| example_05_orientation_stress | guidance_match_moves | 11.0000 | 10.0000 | -1.0000 | -| example_05_orientation_stress | guidance_match_moves_straight | - | 3.0000 | - | -| example_05_orientation_stress | guidance_match_moves_bend90 | - | 7.0000 | - | -| example_05_orientation_stress | guidance_match_moves_sbend | - | 0.0000 | - | -| example_05_orientation_stress | guidance_bonus_applied | 687.5000 | 406.2500 | -281.2500 | -| example_05_orientation_stress | guidance_bonus_applied_straight | - | 187.5000 | - | -| example_05_orientation_stress | guidance_bonus_applied_bend90 | - | 218.7500 | - | -| example_05_orientation_stress | guidance_bonus_applied_sbend | - | 0.0000 | - | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 108.0000 | -41.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 15.0000 | -8.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 19.0000 | -13.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 18.0000 | -12.0000 | -| example_07_large_scale_routing | duration_s | 0.2043 | 0.1873 | -0.0170 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_straight | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_match_moves_bend90 | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_match_moves_sbend | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_bonus_applied | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_straight | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_bonus_applied_bend90 | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_bonus_applied_sbend | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.5628 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4320.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves | - | 101.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_straight | - | 52.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_bend90 | - | 43.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_sbend | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied | - | 4968.7500 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_straight | - | 3250.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_bend90 | - | 1343.7500 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_sbend | - | 375.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3594.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 10245.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10859.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8944.0000 | - | -## Step 45 reverted - -Measured on 2026-04-02T00:29:03-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Reverted bend-selective guidance after the no-warm-start canary still regressed in nodes and congestion work without any validity gain. -- Restored the accepted fixed-bonus guidance state while keeping the move-type counters. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2300 | 0.2387 | +0.0088 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves | 11.0000 | 11.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_straight | - | 3.0000 | - | -| example_05_orientation_stress | guidance_match_moves_bend90 | - | 8.0000 | - | -| example_05_orientation_stress | guidance_match_moves_sbend | - | 0.0000 | - | -| example_05_orientation_stress | guidance_bonus_applied | 687.5000 | 687.5000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_straight | - | 187.5000 | - | -| example_05_orientation_stress | guidance_bonus_applied_bend90 | - | 500.0000 | - | -| example_05_orientation_stress | guidance_bonus_applied_sbend | - | 0.0000 | - | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 23.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 32.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 30.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.2043 | 0.1906 | -0.0137 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_straight | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_match_moves_bend90 | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_match_moves_sbend | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_bonus_applied | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_straight | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_bonus_applied_bend90 | - | 0.0000 | - | -| example_07_large_scale_routing | guidance_bonus_applied_sbend | - | 0.0000 | - | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.5968 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves | - | 101.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_straight | - | 52.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_bend90 | - | 43.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_sbend | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied | - | 6312.5000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_straight | - | 3250.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_bend90 | - | 2687.5000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_sbend | - | 375.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 9604.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10010.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8312.0000 | - | -## Step 46 later-iteration guidance decay - -Measured on 2026-04-02T00:38:26-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Keep the first reroute guidance bonus unchanged, then halve the guidance bonus on iteration 2 and later reroutes. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2275 | 0.2316 | +0.0041 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves | 11.0000 | 11.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_straight | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_bend90 | 8.0000 | 8.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied | 687.5000 | 687.5000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_straight | 187.5000 | 187.5000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_bend90 | 500.0000 | 500.0000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 23.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 32.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 30.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1907 | 0.1923 | +0.0016 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_straight | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_bend90 | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_straight | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_bend90 | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 4.1601 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4850.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves | - | 101.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_straight | - | 52.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_bend90 | - | 43.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_sbend | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied | - | 4093.7500 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_straight | - | 2125.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_bend90 | - | 1718.7500 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_sbend | - | 250.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3917.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 11398.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 11839.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 9870.0000 | - | -## Step 46 reverted - -Measured on 2026-04-02T00:39:37-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Reverted later-iteration guidance decay after the no-warm-start canary regressed in runtime, nodes, and congestion work with no validity gain. -- Restored the accepted fixed-bonus guidance state while keeping the move-type counters. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2275 | 0.2379 | +0.0105 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves | 11.0000 | 11.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_straight | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_bend90 | 8.0000 | 8.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied | 687.5000 | 687.5000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_straight | 187.5000 | 187.5000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_bend90 | 500.0000 | 500.0000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 23.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 32.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 30.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1907 | 0.2109 | +0.0202 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_straight | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_bend90 | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_straight | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_bend90 | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.6956 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves | - | 101.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_straight | - | 52.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_bend90 | - | 43.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_sbend | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied | - | 6312.5000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_straight | - | 3250.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_bend90 | - | 2687.5000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_sbend | - | 375.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 9604.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10010.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8312.0000 | - | -## Step 47 conflict-aware guidance decay - -Measured on 2026-04-02T00:44:37-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Reduce reroute guidance bonus only when the net's own prior reached-target path still had dynamic collisions; keep full bonus for already-clean prior paths. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2275 | 0.2439 | +0.0164 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 286.0000 | -13.0000 | -| example_05_orientation_stress | guidance_match_moves | 11.0000 | 10.0000 | -1.0000 | -| example_05_orientation_stress | guidance_match_moves_straight | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_bend90 | 8.0000 | 7.0000 | -1.0000 | -| example_05_orientation_stress | guidance_match_moves_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied | 687.5000 | 500.0000 | -187.5000 | -| example_05_orientation_stress | guidance_bonus_applied_straight | 187.5000 | 171.8750 | -15.6250 | -| example_05_orientation_stress | guidance_bonus_applied_bend90 | 500.0000 | 328.1250 | -171.8750 | -| example_05_orientation_stress | guidance_bonus_applied_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 130.0000 | -19.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 15.0000 | -8.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 19.0000 | -13.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 18.0000 | -12.0000 | -| example_07_large_scale_routing | duration_s | 0.1907 | 0.1986 | +0.0079 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_straight | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_bend90 | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_straight | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_bend90 | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 4.0364 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4421.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves | - | 101.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_straight | - | 52.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_bend90 | - | 43.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_sbend | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied | - | 4890.6250 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_straight | - | 2515.6250 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_bend90 | - | 2015.6250 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_sbend | - | 359.3750 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3565.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 10202.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10558.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8814.0000 | - | -## Step 47 reverted - -Measured on 2026-04-02T00:45:52-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Reverted conflict-aware guidance decay after the no-warm-start canary still regressed in runtime, nodes, and congestion work without any validity gain. -- Restored the accepted fixed-bonus guidance state while keeping the move-type counters. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2275 | 0.2330 | +0.0056 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves | 11.0000 | 11.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_straight | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_bend90 | 8.0000 | 8.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied | 687.5000 | 687.5000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_straight | 187.5000 | 187.5000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_bend90 | 500.0000 | 500.0000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 23.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 32.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 30.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1907 | 0.1878 | -0.0029 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_straight | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_bend90 | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_straight | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_bend90 | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.5878 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves | - | 101.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_straight | - | 52.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_bend90 | - | 43.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_sbend | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied | - | 6312.5000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_straight | - | 3250.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_bend90 | - | 2687.5000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_sbend | - | 375.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 9604.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10010.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8312.0000 | - | -## Step 48 best reverified guidance source - -Measured on 2026-04-02T08:41:26-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Prefer the best reverified per-net path snapshot as the reroute guidance seed, falling back to the most recent reached-target path only when no best snapshot exists. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2275 | 0.2347 | +0.0073 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves | 11.0000 | 11.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_straight | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_bend90 | 8.0000 | 8.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied | 687.5000 | 687.5000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_straight | 187.5000 | 187.5000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_bend90 | 500.0000 | 500.0000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 23.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 32.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 30.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1907 | 0.1934 | +0.0027 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_straight | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_bend90 | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_straight | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_bend90 | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.5687 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves | - | 101.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_straight | - | 52.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_bend90 | - | 43.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_sbend | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied | - | 6312.5000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_straight | - | 3250.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_bend90 | - | 2687.5000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_sbend | - | 375.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 9604.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10010.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8312.0000 | - | -## Step 49 per-net best reverified guidance - -Measured on 2026-04-02T08:43:09-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Track the best reverified reached-target path per net, ranked by dynamic collisions, total collisions, then total length, and prefer that path as reroute guidance. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2275 | 0.2432 | +0.0158 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves | 11.0000 | 11.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_straight | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_bend90 | 8.0000 | 8.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied | 687.5000 | 687.5000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_straight | 187.5000 | 187.5000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_bend90 | 500.0000 | 500.0000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 23.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 32.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 30.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1907 | 0.1923 | +0.0016 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_straight | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_bend90 | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_straight | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_bend90 | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 4.7028 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 5664.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves | - | 95.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_straight | - | 49.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_bend90 | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_sbend | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied | - | 5937.5000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_straight | - | 3062.5000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_bend90 | - | 2500.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_sbend | - | 375.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3406.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 9679.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10059.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8361.0000 | - | -## Step 49 reverted - -Measured on 2026-04-02T08:44:09-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Reverted per-net best reverified guidance after the no-warm-start canary regressed sharply in runtime and nodes without any validity gain. -- Restored the accepted fixed-bonus guidance state while keeping the move-type counters. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2275 | 0.2367 | +0.0093 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves | 11.0000 | 11.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_straight | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_bend90 | 8.0000 | 8.0000 | +0.0000 | -| example_05_orientation_stress | guidance_match_moves_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied | 687.5000 | 687.5000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_straight | 187.5000 | 187.5000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_bend90 | 500.0000 | 500.0000 | +0.0000 | -| example_05_orientation_stress | guidance_bonus_applied_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_nets | 23.0000 | 23.0000 | +0.0000 | -| example_05_orientation_stress | congestion_candidate_ids | 32.0000 | 32.0000 | +0.0000 | -| example_05_orientation_stress | congestion_exact_pair_checks | 30.0000 | 30.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1907 | 0.1904 | -0.0003 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_straight | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_bend90 | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_match_moves_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_straight | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_bend90 | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | guidance_bonus_applied_sbend | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_nets | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_candidate_ids | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_exact_pair_checks | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.6154 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves | - | 101.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_straight | - | 52.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_bend90 | - | 43.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_match_moves_sbend | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied | - | 6312.5000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_straight | - | 3250.0000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_bend90 | - | 2687.5000 | - | -| example_07_large_scale_routing_no_warm_start | guidance_bonus_applied_sbend | - | 375.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_nets | - | 9604.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_candidate_ids | - | 10010.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_exact_pair_checks | - | 8312.0000 | - | -## Step 51 conflict trace instrumentation - -Measured on 2026-04-02T11:20:41-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Added opt-in conflict-trace capture and a separate recorder script without changing routing policy. -- The no-warm-start canary still finishes 2/10/10 with 4 iterations; tracing shows the same conflict structure at iteration, restored-best, and final stages. -- Recurring hotspot edges cluster in two groups: net_00-net_03 and net_06-net_09. -- Recurring component pairs also repeat across all traced stages, which points to stable geometric bottlenecks rather than seed noise. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2275 | 0.2338 | +0.0064 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1907 | 0.1896 | -0.0011 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.5423 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -## Step 52 prefix-preserving hotspot repair rejected - -Measured on 2026-04-02T11:45:37-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Tried a bounded post-loop hotspot repair that preserved clean prefixes and rerouted only conflicted suffixes. -- The no-warm-start canary stayed at 2/10/10 and the repair counters showed zero accepted repairs, so the slice did not move correctness. -- The experiment temporarily raised the canary to 4258 nodes with one repair pass, two clusters attempted, and eight nets considered before it was reverted. -- The tree is restored to the accepted fixed-guidance state: example_07_no_warm_start is back at 2 valid, 10 reached, 4250 nodes, and 3388 congestion checks. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2275 | 0.2384 | +0.0110 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1907 | 0.1909 | +0.0002 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.5590 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -## Step 53 cluster repack repair rejected - -Measured on 2026-04-02T12:04:21-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Tried bounded post-loop clique reroute against frozen outside geometry. -- No-warm-start canary stayed 2/10/10. -- Final conflict edges improved 12 -> 10, but correctness did not improve and search cost rose materially. -- Tree restored to the accepted fixed-guidance state after revert. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2275 | 0.2364 | +0.0089 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1907 | 0.1915 | +0.0008 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.5998 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -## Step 54 hotspot keep-out repair rejected - -Measured on 2026-04-02T12:22:14-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Tried bounded post-loop clique reroute with temporary hotspot keep-out obstacles and frozen outside geometry. -- The no-warm-start canary failed a bounded probe: a single-scenario diff run timed out at 20 seconds, far above the accepted ~3.5 second state. -- Because the slice was clearly losing on runtime before showing any correctness gain, it was reverted. -- Tree restored to the accepted fixed-guidance branch after revert. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2275 | 0.2490 | +0.0216 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1907 | 0.2004 | +0.0097 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.8387 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -## Step 55 bounded portfolio rerun rejected - -Measured on 2026-04-02T12:50:58-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Tried a conservative top-level best-of-three portfolio for warm-start-disabled runs using alternate shuffle/order settings. -- The no-warm-start canary was unchanged at 2/10/10, 4250 nodes, and 3388 congestion checks. -- Because the added control-path complexity produced no correctness or cost improvement, the slice was reverted. -- Tree restored to the accepted fixed-guidance branch after revert. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2275 | 0.2408 | +0.0133 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1907 | 0.1953 | +0.0046 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.6741 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -## Step 56 frontier hotspot instrumentation - -Measured on 2026-04-02T13:00:47-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Added opt-in frontier_trace diagnostics and recorder tooling without changing routing behavior. -- No-warm-start canary stayed on the accepted 2/10/10, 4250-node, 3388-congestion-check shape. -- Frontier trace shows hotspot-adjacent prunes are dominated by cost (3412) and closed-set (626), with zero hard-collision prunes near the traced hotspots. -- Self-collision pruning is concentrated in net_02 (455 traced self-collision prunes); the other hotspot nets are mostly cost- and closed-set-limited. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2275 | 0.2300 | +0.0026 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1907 | 0.1891 | -0.0016 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.5576 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -## Step 57 frontier hotspot readout refinement - -Measured on 2026-04-02T13:11:47-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Extended frontier_trace reporting with per-net sampled reason x move_type and hotspot splits. -- net_02 samples split across hotspots 0 and 6 and include heavy straight self-collision pruning; sampled mix is 36 cost, 23 self-collision, 5 closed-set. -- net_03 and net_06 are almost entirely straight-move cost prunes at hotspot 0; their few traced bend90 samples are closed-set dominated, not geometry-blocked. -- The sampled cost prunes are overshoot moves well outside the 0..1000 board bounds, so the current cost bucket is largely boundary-rejection rather than local corridor pricing. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2275 | 0.2365 | +0.0090 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.1907 | 0.1927 | +0.0020 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 3.6435 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 4.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 40.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 4250.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 3388.0000 | - | -## Step 58 large no-warm straight-bound cap - -Measured on 2026-04-02T13:22:28-07:00. -Baseline: `/tmp/inire_pre_step58_baseline.json`. - -Findings: - -- Applied a board-boundary cap to straight candidate reach only for large warm-start-disabled multi-net runs. -- The no-warm-start example_07 canary improved from 2/10/10 to 6/10/10. -- Nodes fell from 4250 to 1764 and runtime fell to about 1.95s, while congestion checks rose modestly from 3388 to 4625 as the search converged through six lighter iterations. -- Warmed example_07 stayed 10/10/10 and example_05 kept identical routing counters and validity. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2348 | 0.2387 | +0.0038 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 286.0000 | 299.0000 | +13.0000 | -| example_05_orientation_stress | congestion_check_calls | 155.0000 | 149.0000 | -6.0000 | -| example_07_large_scale_routing | duration_s | 0.1945 | 0.1944 | -0.0000 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 1.9279 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 60.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 1764.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 4625.0000 | - | -## Step 59 pair-local exact-conflict repair rejected - -Measured on 2026-04-02T13:50:00-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Tried a bounded post-loop two-net repair portfolio on the final conflict pairs, with ranked vs reversed reroute order and optional exact-overlap keep-outs. -- The no-warm-start canary stayed at `6/10/10`; the repair phase accepted `0` whole-set improvements across `8` attempts on `2` pairs. -- Cost regressed sharply during the failed slice to about `9.56s`, `11126` expanded nodes, and `9087` congestion checks, with `4257` frozen-net hard prunes. -- The slice was reverted and the tree restored to the accepted straight-boundary-cap branch. - -## Step 60 trimmed exploratory straight heuristics rejected - -Measured on 2026-04-02T14:00:00-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Tried removing the generic `max_reach / 2` and `max_reach - 5` straight candidates only for the same large no-warm runs that use the accepted straight-boundary cap. -- The no-warm-start canary regressed from `6/10/10` to `2/10/10` and runtime climbed to about `26s`. -- Search work exploded to about `27619` expanded nodes and `53804` congestion checks, so the generic exploratory straight candidates are still necessary for the accepted branch. -- The slice was reverted and the tree restored to the accepted straight-boundary-cap branch. - -## Step 61 staggered bend-anchor diversification rejected - -Measured on 2026-04-02T14:10:00-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Tried adding deterministic staggered pre-bend straight candidates for odd-indexed nets only in the large no-warm regime to separate the remaining colliding pairs. -- The no-warm-start canary regressed from `6/10/10` to `3/10/10` and runtime rose to about `8.6s`. -- The heuristic fired heavily (`1051` staggered bend-anchor candidates and `785` staggered visible candidates) but search still got worse, with about `6724` expanded nodes and `21577` congestion checks. -- The slice was reverted and the tree restored to the accepted straight-boundary-cap branch. -## Step 62 pair-local scratch reroute accepted - -Measured on 2026-04-02T14:15:04-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Built a bounded post-loop pair-local reroute that treats all outside-pair nets as frozen static blockers in a scratch routing world. The no-warm-start example_07 canary improved from 6/10/10 to 9/10/10 with two accepted pair repairs and only 33 extra search expansions. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2591 | 0.2440 | -0.0151 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | pair_local_search_pairs_considered | - | 0.0000 | - | -| example_05_orientation_stress | pair_local_search_attempts | - | 0.0000 | - | -| example_05_orientation_stress | pair_local_search_accepts | - | 0.0000 | - | -| example_05_orientation_stress | pair_local_search_nodes_expanded | - | 0.0000 | - | -| example_07_large_scale_routing | duration_s | 0.2027 | 0.2029 | +0.0002 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | pair_local_search_pairs_considered | - | 0.0000 | - | -| example_07_large_scale_routing | pair_local_search_attempts | - | 0.0000 | - | -| example_07_large_scale_routing | pair_local_search_accepts | - | 0.0000 | - | -| example_07_large_scale_routing | pair_local_search_nodes_expanded | - | 0.0000 | - | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 2.1244 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 9.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 60.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 1764.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 4625.0000 | - | -| example_07_large_scale_routing_no_warm_start | pair_local_search_pairs_considered | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | pair_local_search_attempts | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | pair_local_search_accepts | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | pair_local_search_nodes_expanded | - | 33.0000 | - | -## Step 63 pair-local static obstacle cloning fix - -Measured on 2026-04-02T14:24:40-07:00. -Baseline: `docs/performance_baseline.json`. - -Findings: - -- Fixed the scratch pair-local routing world to clone static obstacles from the live collision engine instead of the RoutingProblem wrapper. That removed the false-clean net_00 reroute and lifted the no-warm-start example_07 canary from 9/10/10 to 10/10/10 with the same main search workload. - -# Performance Baseline Diff - -| Scenario | Metric | Baseline | Current | Delta | -| :-- | :-- | --: | --: | --: | -| example_05_orientation_stress | duration_s | 0.2361 | 0.2495 | +0.0134 | -| example_05_orientation_stress | valid_results | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | reached_targets | 3.0000 | 3.0000 | +0.0000 | -| example_05_orientation_stress | route_iterations | 2.0000 | 2.0000 | +0.0000 | -| example_05_orientation_stress | nets_routed | 6.0000 | 6.0000 | +0.0000 | -| example_05_orientation_stress | nodes_expanded | 299.0000 | 299.0000 | +0.0000 | -| example_05_orientation_stress | congestion_check_calls | 149.0000 | 149.0000 | +0.0000 | -| example_05_orientation_stress | pair_local_search_pairs_considered | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | pair_local_search_attempts | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | pair_local_search_accepts | 0.0000 | 0.0000 | +0.0000 | -| example_05_orientation_stress | pair_local_search_nodes_expanded | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | duration_s | 0.2025 | 0.2059 | +0.0034 | -| example_07_large_scale_routing | valid_results | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | reached_targets | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | route_iterations | 1.0000 | 1.0000 | +0.0000 | -| example_07_large_scale_routing | nets_routed | 10.0000 | 10.0000 | +0.0000 | -| example_07_large_scale_routing | nodes_expanded | 78.0000 | 78.0000 | +0.0000 | -| example_07_large_scale_routing | congestion_check_calls | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | pair_local_search_pairs_considered | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | pair_local_search_attempts | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | pair_local_search_accepts | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing | pair_local_search_nodes_expanded | 0.0000 | 0.0000 | +0.0000 | -| example_07_large_scale_routing_no_warm_start | duration_s | - | 2.1497 | - | -| example_07_large_scale_routing_no_warm_start | valid_results | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | reached_targets | - | 10.0000 | - | -| example_07_large_scale_routing_no_warm_start | route_iterations | - | 6.0000 | - | -| example_07_large_scale_routing_no_warm_start | nets_routed | - | 60.0000 | - | -| example_07_large_scale_routing_no_warm_start | nodes_expanded | - | 1764.0000 | - | -| example_07_large_scale_routing_no_warm_start | congestion_check_calls | - | 4625.0000 | - | -| example_07_large_scale_routing_no_warm_start | pair_local_search_pairs_considered | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | pair_local_search_attempts | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | pair_local_search_accepts | - | 2.0000 | - | -| example_07_large_scale_routing_no_warm_start | pair_local_search_nodes_expanded | - | 68.0000 | - | diff --git a/docs/pair_local_characterization.json b/docs/pair_local_characterization.json deleted file mode 100644 index 160ca48..0000000 --- a/docs/pair_local_characterization.json +++ /dev/null @@ -1,2108 +0,0 @@ -{ - "cases": [ - { - "duration_s": 0.5461949198506773, - "metrics": { - "congestion_cache_hits": 8, - "congestion_cache_misses": 674, - "congestion_candidate_ids": 1105, - "congestion_candidate_nets": 1045, - "congestion_candidate_precheck_hits": 266, - "congestion_candidate_precheck_misses": 416, - "congestion_candidate_precheck_skips": 0, - "congestion_check_calls": 674, - "congestion_exact_pair_checks": 952, - "congestion_grid_net_cache_hits": 287, - "congestion_grid_net_cache_misses": 755, - "congestion_grid_span_cache_hits": 251, - "congestion_grid_span_cache_misses": 375, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 308, - "congestion_net_envelope_cache_misses": 807, - "congestion_presence_cache_hits": 282, - "congestion_presence_cache_misses": 475, - "congestion_presence_skips": 75, - "danger_map_cache_hits": 3159, - "danger_map_cache_misses": 1632, - "danger_map_lookup_calls": 4791, - "danger_map_query_calls": 1632, - "danger_map_total_ns": 46195989, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 131, - "dynamic_path_objects_removed": 106, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 3312.5, - "guidance_bonus_applied_bend90": 1187.5, - "guidance_bonus_applied_sbend": 375.0, - "guidance_bonus_applied_straight": 1750.0, - "guidance_match_moves": 53, - "guidance_match_moves_bend90": 19, - "guidance_match_moves_sbend": 6, - "guidance_match_moves_straight": 28, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 18, - "iteration_conflicting_nets": 21, - "iteration_reverified_nets": 24, - "iteration_reverify_calls": 4, - "move_cache_abs_hits": 459, - "move_cache_abs_misses": 2216, - "move_cache_rel_hits": 2062, - "move_cache_rel_misses": 154, - "moves_added": 1597, - "moves_generated": 2675, - "nets_carried_forward": 0, - "nets_reached_target": 24, - "nets_routed": 24, - "nodes_expanded": 500, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 0, - "pruned_closed_set": 174, - "pruned_cost": 904, - "pruned_hard_collision": 0, - "ray_cast_calls": 1780, - "ray_cast_calls_expand_forward": 476, - "ray_cast_calls_expand_snap": 0, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 1300, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 4, - "ray_cast_candidate_bounds": 86, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 1, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 4, - "score_component_calls": 2501, - "score_component_total_ns": 52377581, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 444, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 296, - "verify_dynamic_exact_pair_checks": 320, - "verify_path_report_calls": 60, - "verify_static_buffer_ops": 256, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 4, - "visibility_tangent_candidate_ray_tests": 4, - "visibility_tangent_candidate_scans": 476, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 6, - "repeat": 0, - "seed": 41, - "summary": { - "reached_targets": 6, - "total_results": 6, - "valid_results": 1 - } - }, - { - "duration_s": 0.5255939338821918, - "metrics": { - "congestion_cache_hits": 8, - "congestion_cache_misses": 674, - "congestion_candidate_ids": 1105, - "congestion_candidate_nets": 1045, - "congestion_candidate_precheck_hits": 266, - "congestion_candidate_precheck_misses": 416, - "congestion_candidate_precheck_skips": 0, - "congestion_check_calls": 674, - "congestion_exact_pair_checks": 952, - "congestion_grid_net_cache_hits": 287, - "congestion_grid_net_cache_misses": 755, - "congestion_grid_span_cache_hits": 251, - "congestion_grid_span_cache_misses": 375, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 308, - "congestion_net_envelope_cache_misses": 807, - "congestion_presence_cache_hits": 282, - "congestion_presence_cache_misses": 475, - "congestion_presence_skips": 75, - "danger_map_cache_hits": 3159, - "danger_map_cache_misses": 1632, - "danger_map_lookup_calls": 4791, - "danger_map_query_calls": 1632, - "danger_map_total_ns": 42685332, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 131, - "dynamic_path_objects_removed": 106, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 3312.5, - "guidance_bonus_applied_bend90": 1187.5, - "guidance_bonus_applied_sbend": 375.0, - "guidance_bonus_applied_straight": 1750.0, - "guidance_match_moves": 53, - "guidance_match_moves_bend90": 19, - "guidance_match_moves_sbend": 6, - "guidance_match_moves_straight": 28, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 18, - "iteration_conflicting_nets": 21, - "iteration_reverified_nets": 24, - "iteration_reverify_calls": 4, - "move_cache_abs_hits": 459, - "move_cache_abs_misses": 2216, - "move_cache_rel_hits": 2062, - "move_cache_rel_misses": 154, - "moves_added": 1597, - "moves_generated": 2675, - "nets_carried_forward": 0, - "nets_reached_target": 24, - "nets_routed": 24, - "nodes_expanded": 500, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 0, - "pruned_closed_set": 174, - "pruned_cost": 904, - "pruned_hard_collision": 0, - "ray_cast_calls": 1780, - "ray_cast_calls_expand_forward": 476, - "ray_cast_calls_expand_snap": 0, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 1300, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 4, - "ray_cast_candidate_bounds": 86, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 1, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 4, - "score_component_calls": 2501, - "score_component_total_ns": 48631281, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 444, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 296, - "verify_dynamic_exact_pair_checks": 320, - "verify_path_report_calls": 60, - "verify_static_buffer_ops": 256, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 4, - "visibility_tangent_candidate_ray_tests": 4, - "visibility_tangent_candidate_scans": 476, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 6, - "repeat": 1, - "seed": 41, - "summary": { - "reached_targets": 6, - "total_results": 6, - "valid_results": 1 - } - }, - { - "duration_s": 0.5240974249318242, - "metrics": { - "congestion_cache_hits": 8, - "congestion_cache_misses": 683, - "congestion_candidate_ids": 1119, - "congestion_candidate_nets": 1059, - "congestion_candidate_precheck_hits": 271, - "congestion_candidate_precheck_misses": 420, - "congestion_candidate_precheck_skips": 0, - "congestion_check_calls": 683, - "congestion_exact_pair_checks": 974, - "congestion_grid_net_cache_hits": 294, - "congestion_grid_net_cache_misses": 761, - "congestion_grid_span_cache_hits": 257, - "congestion_grid_span_cache_misses": 378, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 315, - "congestion_net_envelope_cache_misses": 813, - "congestion_presence_cache_hits": 287, - "congestion_presence_cache_misses": 479, - "congestion_presence_skips": 75, - "danger_map_cache_hits": 3186, - "danger_map_cache_misses": 1632, - "danger_map_lookup_calls": 4818, - "danger_map_query_calls": 1632, - "danger_map_total_ns": 42252659, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 131, - "dynamic_path_objects_removed": 106, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 3312.5, - "guidance_bonus_applied_bend90": 1187.5, - "guidance_bonus_applied_sbend": 375.0, - "guidance_bonus_applied_straight": 1750.0, - "guidance_match_moves": 53, - "guidance_match_moves_bend90": 19, - "guidance_match_moves_sbend": 6, - "guidance_match_moves_straight": 28, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 18, - "iteration_conflicting_nets": 21, - "iteration_reverified_nets": 24, - "iteration_reverify_calls": 4, - "move_cache_abs_hits": 472, - "move_cache_abs_misses": 2216, - "move_cache_rel_hits": 2062, - "move_cache_rel_misses": 154, - "moves_added": 1606, - "moves_generated": 2688, - "nets_carried_forward": 0, - "nets_reached_target": 24, - "nets_routed": 24, - "nodes_expanded": 503, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 0, - "pruned_closed_set": 174, - "pruned_cost": 908, - "pruned_hard_collision": 0, - "ray_cast_calls": 1783, - "ray_cast_calls_expand_forward": 479, - "ray_cast_calls_expand_snap": 0, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 1300, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 4, - "ray_cast_candidate_bounds": 86, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 1, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 4, - "score_component_calls": 2514, - "score_component_total_ns": 48076710, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 457, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 292, - "verify_dynamic_exact_pair_checks": 324, - "verify_path_report_calls": 60, - "verify_static_buffer_ops": 256, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 4, - "visibility_tangent_candidate_ray_tests": 4, - "visibility_tangent_candidate_scans": 479, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 6, - "repeat": 0, - "seed": 42, - "summary": { - "reached_targets": 6, - "total_results": 6, - "valid_results": 1 - } - }, - { - "duration_s": 0.547705102013424, - "metrics": { - "congestion_cache_hits": 8, - "congestion_cache_misses": 683, - "congestion_candidate_ids": 1119, - "congestion_candidate_nets": 1059, - "congestion_candidate_precheck_hits": 271, - "congestion_candidate_precheck_misses": 420, - "congestion_candidate_precheck_skips": 0, - "congestion_check_calls": 683, - "congestion_exact_pair_checks": 974, - "congestion_grid_net_cache_hits": 294, - "congestion_grid_net_cache_misses": 761, - "congestion_grid_span_cache_hits": 257, - "congestion_grid_span_cache_misses": 378, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 315, - "congestion_net_envelope_cache_misses": 813, - "congestion_presence_cache_hits": 287, - "congestion_presence_cache_misses": 479, - "congestion_presence_skips": 75, - "danger_map_cache_hits": 3186, - "danger_map_cache_misses": 1632, - "danger_map_lookup_calls": 4818, - "danger_map_query_calls": 1632, - "danger_map_total_ns": 43365736, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 131, - "dynamic_path_objects_removed": 106, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 3312.5, - "guidance_bonus_applied_bend90": 1187.5, - "guidance_bonus_applied_sbend": 375.0, - "guidance_bonus_applied_straight": 1750.0, - "guidance_match_moves": 53, - "guidance_match_moves_bend90": 19, - "guidance_match_moves_sbend": 6, - "guidance_match_moves_straight": 28, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 18, - "iteration_conflicting_nets": 21, - "iteration_reverified_nets": 24, - "iteration_reverify_calls": 4, - "move_cache_abs_hits": 472, - "move_cache_abs_misses": 2216, - "move_cache_rel_hits": 2062, - "move_cache_rel_misses": 154, - "moves_added": 1606, - "moves_generated": 2688, - "nets_carried_forward": 0, - "nets_reached_target": 24, - "nets_routed": 24, - "nodes_expanded": 503, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 0, - "pruned_closed_set": 174, - "pruned_cost": 908, - "pruned_hard_collision": 0, - "ray_cast_calls": 1783, - "ray_cast_calls_expand_forward": 479, - "ray_cast_calls_expand_snap": 0, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 1300, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 4, - "ray_cast_candidate_bounds": 86, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 1, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 4, - "score_component_calls": 2514, - "score_component_total_ns": 49498429, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 457, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 292, - "verify_dynamic_exact_pair_checks": 324, - "verify_path_report_calls": 60, - "verify_static_buffer_ops": 256, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 4, - "visibility_tangent_candidate_ray_tests": 4, - "visibility_tangent_candidate_scans": 479, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 6, - "repeat": 1, - "seed": 42, - "summary": { - "reached_targets": 6, - "total_results": 6, - "valid_results": 1 - } - }, - { - "duration_s": 0.5199470021761954, - "metrics": { - "congestion_cache_hits": 8, - "congestion_cache_misses": 654, - "congestion_candidate_ids": 1048, - "congestion_candidate_nets": 995, - "congestion_candidate_precheck_hits": 250, - "congestion_candidate_precheck_misses": 412, - "congestion_candidate_precheck_skips": 0, - "congestion_check_calls": 654, - "congestion_exact_pair_checks": 915, - "congestion_grid_net_cache_hits": 272, - "congestion_grid_net_cache_misses": 746, - "congestion_grid_span_cache_hits": 234, - "congestion_grid_span_cache_misses": 372, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 293, - "congestion_net_envelope_cache_misses": 796, - "congestion_presence_cache_hits": 261, - "congestion_presence_cache_misses": 466, - "congestion_presence_skips": 65, - "danger_map_cache_hits": 3103, - "danger_map_cache_misses": 1598, - "danger_map_lookup_calls": 4701, - "danger_map_query_calls": 1598, - "danger_map_total_ns": 41631872, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 131, - "dynamic_path_objects_removed": 106, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 3312.5, - "guidance_bonus_applied_bend90": 1187.5, - "guidance_bonus_applied_sbend": 375.0, - "guidance_bonus_applied_straight": 1750.0, - "guidance_match_moves": 53, - "guidance_match_moves_bend90": 19, - "guidance_match_moves_sbend": 6, - "guidance_match_moves_straight": 28, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 18, - "iteration_conflicting_nets": 21, - "iteration_reverified_nets": 24, - "iteration_reverify_calls": 4, - "move_cache_abs_hits": 451, - "move_cache_abs_misses": 2192, - "move_cache_rel_hits": 2038, - "move_cache_rel_misses": 154, - "moves_added": 1567, - "moves_generated": 2643, - "nets_carried_forward": 0, - "nets_reached_target": 24, - "nets_routed": 24, - "nodes_expanded": 493, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 0, - "pruned_closed_set": 172, - "pruned_cost": 904, - "pruned_hard_collision": 0, - "ray_cast_calls": 1763, - "ray_cast_calls_expand_forward": 469, - "ray_cast_calls_expand_snap": 0, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 1290, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 4, - "ray_cast_candidate_bounds": 80, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 1, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 4, - "score_component_calls": 2471, - "score_component_total_ns": 47519774, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 436, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 293, - "verify_dynamic_exact_pair_checks": 317, - "verify_path_report_calls": 60, - "verify_static_buffer_ops": 256, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 4, - "visibility_tangent_candidate_ray_tests": 4, - "visibility_tangent_candidate_scans": 469, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 6, - "repeat": 0, - "seed": 43, - "summary": { - "reached_targets": 6, - "total_results": 6, - "valid_results": 1 - } - }, - { - "duration_s": 0.5160259250551462, - "metrics": { - "congestion_cache_hits": 8, - "congestion_cache_misses": 654, - "congestion_candidate_ids": 1048, - "congestion_candidate_nets": 995, - "congestion_candidate_precheck_hits": 250, - "congestion_candidate_precheck_misses": 412, - "congestion_candidate_precheck_skips": 0, - "congestion_check_calls": 654, - "congestion_exact_pair_checks": 915, - "congestion_grid_net_cache_hits": 272, - "congestion_grid_net_cache_misses": 746, - "congestion_grid_span_cache_hits": 234, - "congestion_grid_span_cache_misses": 372, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 293, - "congestion_net_envelope_cache_misses": 796, - "congestion_presence_cache_hits": 261, - "congestion_presence_cache_misses": 466, - "congestion_presence_skips": 65, - "danger_map_cache_hits": 3103, - "danger_map_cache_misses": 1598, - "danger_map_lookup_calls": 4701, - "danger_map_query_calls": 1598, - "danger_map_total_ns": 41135911, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 131, - "dynamic_path_objects_removed": 106, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 3312.5, - "guidance_bonus_applied_bend90": 1187.5, - "guidance_bonus_applied_sbend": 375.0, - "guidance_bonus_applied_straight": 1750.0, - "guidance_match_moves": 53, - "guidance_match_moves_bend90": 19, - "guidance_match_moves_sbend": 6, - "guidance_match_moves_straight": 28, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 18, - "iteration_conflicting_nets": 21, - "iteration_reverified_nets": 24, - "iteration_reverify_calls": 4, - "move_cache_abs_hits": 451, - "move_cache_abs_misses": 2192, - "move_cache_rel_hits": 2038, - "move_cache_rel_misses": 154, - "moves_added": 1567, - "moves_generated": 2643, - "nets_carried_forward": 0, - "nets_reached_target": 24, - "nets_routed": 24, - "nodes_expanded": 493, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 0, - "pruned_closed_set": 172, - "pruned_cost": 904, - "pruned_hard_collision": 0, - "ray_cast_calls": 1763, - "ray_cast_calls_expand_forward": 469, - "ray_cast_calls_expand_snap": 0, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 1290, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 4, - "ray_cast_candidate_bounds": 80, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 1, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 4, - "score_component_calls": 2471, - "score_component_total_ns": 47047772, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 436, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 293, - "verify_dynamic_exact_pair_checks": 317, - "verify_path_report_calls": 60, - "verify_static_buffer_ops": 256, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 4, - "visibility_tangent_candidate_ray_tests": 4, - "visibility_tangent_candidate_scans": 469, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 6, - "repeat": 1, - "seed": 43, - "summary": { - "reached_targets": 6, - "total_results": 6, - "valid_results": 1 - } - }, - { - "duration_s": 1.8817617469467223, - "metrics": { - "congestion_cache_hits": 31, - "congestion_cache_misses": 4313, - "congestion_candidate_ids": 7976, - "congestion_candidate_nets": 7240, - "congestion_candidate_precheck_hits": 2327, - "congestion_candidate_precheck_misses": 2036, - "congestion_candidate_precheck_skips": 19, - "congestion_check_calls": 4313, - "congestion_exact_pair_checks": 6217, - "congestion_grid_net_cache_hits": 2369, - "congestion_grid_net_cache_misses": 3714, - "congestion_grid_span_cache_hits": 2055, - "congestion_grid_span_cache_misses": 1837, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 2527, - "congestion_net_envelope_cache_misses": 3896, - "congestion_presence_cache_hits": 2955, - "congestion_presence_cache_misses": 2536, - "congestion_presence_skips": 1126, - "danger_map_cache_hits": 16937, - "danger_map_cache_misses": 6391, - "danger_map_lookup_calls": 23328, - "danger_map_query_calls": 6391, - "danger_map_total_ns": 192446411, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 450, - "dynamic_path_objects_removed": 416, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 10812.5, - "guidance_bonus_applied_bend90": 3125.0, - "guidance_bonus_applied_sbend": 750.0, - "guidance_bonus_applied_straight": 6937.5, - "guidance_match_moves": 173, - "guidance_match_moves_bend90": 50, - "guidance_match_moves_sbend": 12, - "guidance_match_moves_straight": 111, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 33, - "iteration_conflicting_nets": 38, - "iteration_reverified_nets": 56, - "iteration_reverify_calls": 7, - "move_cache_abs_hits": 2874, - "move_cache_abs_misses": 5680, - "move_cache_rel_hits": 4979, - "move_cache_rel_misses": 701, - "moves_added": 7771, - "moves_generated": 8554, - "nets_carried_forward": 0, - "nets_reached_target": 56, - "nets_routed": 56, - "nodes_expanded": 1558, - "pair_local_search_accepts": 2, - "pair_local_search_attempts": 3, - "pair_local_search_nodes_expanded": 38, - "pair_local_search_pairs_considered": 2, - "path_cost_calls": 0, - "pruned_closed_set": 461, - "pruned_cost": 322, - "pruned_hard_collision": 0, - "ray_cast_calls": 4910, - "ray_cast_calls_expand_forward": 1502, - "ray_cast_calls_expand_snap": 39, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 3363, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 6, - "ray_cast_candidate_bounds": 237, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 8, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 7, - "score_component_calls": 8098, - "score_component_total_ns": 218008329, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 2788, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 1244, - "verify_dynamic_exact_pair_checks": 464, - "verify_path_report_calls": 144, - "verify_static_buffer_ops": 732, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 6, - "visibility_tangent_candidate_ray_tests": 6, - "visibility_tangent_candidate_scans": 1502, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 8, - "repeat": 0, - "seed": 41, - "summary": { - "reached_targets": 8, - "total_results": 8, - "valid_results": 8 - } - }, - { - "duration_s": 1.8618457240518183, - "metrics": { - "congestion_cache_hits": 31, - "congestion_cache_misses": 4313, - "congestion_candidate_ids": 7976, - "congestion_candidate_nets": 7240, - "congestion_candidate_precheck_hits": 2327, - "congestion_candidate_precheck_misses": 2036, - "congestion_candidate_precheck_skips": 19, - "congestion_check_calls": 4313, - "congestion_exact_pair_checks": 6217, - "congestion_grid_net_cache_hits": 2369, - "congestion_grid_net_cache_misses": 3714, - "congestion_grid_span_cache_hits": 2055, - "congestion_grid_span_cache_misses": 1837, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 2527, - "congestion_net_envelope_cache_misses": 3896, - "congestion_presence_cache_hits": 2955, - "congestion_presence_cache_misses": 2536, - "congestion_presence_skips": 1126, - "danger_map_cache_hits": 16937, - "danger_map_cache_misses": 6391, - "danger_map_lookup_calls": 23328, - "danger_map_query_calls": 6391, - "danger_map_total_ns": 172147520, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 450, - "dynamic_path_objects_removed": 416, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 10812.5, - "guidance_bonus_applied_bend90": 3125.0, - "guidance_bonus_applied_sbend": 750.0, - "guidance_bonus_applied_straight": 6937.5, - "guidance_match_moves": 173, - "guidance_match_moves_bend90": 50, - "guidance_match_moves_sbend": 12, - "guidance_match_moves_straight": 111, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 33, - "iteration_conflicting_nets": 38, - "iteration_reverified_nets": 56, - "iteration_reverify_calls": 7, - "move_cache_abs_hits": 2874, - "move_cache_abs_misses": 5680, - "move_cache_rel_hits": 4979, - "move_cache_rel_misses": 701, - "moves_added": 7771, - "moves_generated": 8554, - "nets_carried_forward": 0, - "nets_reached_target": 56, - "nets_routed": 56, - "nodes_expanded": 1558, - "pair_local_search_accepts": 2, - "pair_local_search_attempts": 3, - "pair_local_search_nodes_expanded": 38, - "pair_local_search_pairs_considered": 2, - "path_cost_calls": 0, - "pruned_closed_set": 461, - "pruned_cost": 322, - "pruned_hard_collision": 0, - "ray_cast_calls": 4910, - "ray_cast_calls_expand_forward": 1502, - "ray_cast_calls_expand_snap": 39, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 3363, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 6, - "ray_cast_candidate_bounds": 237, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 8, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 7, - "score_component_calls": 8098, - "score_component_total_ns": 197998309, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 2788, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 1244, - "verify_dynamic_exact_pair_checks": 464, - "verify_path_report_calls": 144, - "verify_static_buffer_ops": 732, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 6, - "visibility_tangent_candidate_ray_tests": 6, - "visibility_tangent_candidate_scans": 1502, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 8, - "repeat": 1, - "seed": 41, - "summary": { - "reached_targets": 8, - "total_results": 8, - "valid_results": 8 - } - }, - { - "duration_s": 1.4850338851101696, - "metrics": { - "congestion_cache_hits": 37, - "congestion_cache_misses": 3799, - "congestion_candidate_ids": 7050, - "congestion_candidate_nets": 6725, - "congestion_candidate_precheck_hits": 1823, - "congestion_candidate_precheck_misses": 2035, - "congestion_candidate_precheck_skips": 22, - "congestion_check_calls": 3799, - "congestion_exact_pair_checks": 5684, - "congestion_grid_net_cache_hits": 1836, - "congestion_grid_net_cache_misses": 3693, - "congestion_grid_span_cache_hits": 1591, - "congestion_grid_span_cache_misses": 1804, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 1992, - "congestion_net_envelope_cache_misses": 3901, - "congestion_presence_cache_hits": 2321, - "congestion_presence_cache_misses": 2616, - "congestion_presence_skips": 1079, - "danger_map_cache_hits": 16398, - "danger_map_cache_misses": 5274, - "danger_map_lookup_calls": 21672, - "danger_map_query_calls": 5274, - "danger_map_total_ns": 142151688, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 435, - "dynamic_path_objects_removed": 400, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 14187.5, - "guidance_bonus_applied_bend90": 4187.5, - "guidance_bonus_applied_sbend": 875.0, - "guidance_bonus_applied_straight": 9125.0, - "guidance_match_moves": 227, - "guidance_match_moves_bend90": 67, - "guidance_match_moves_sbend": 14, - "guidance_match_moves_straight": 146, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 31, - "iteration_conflicting_nets": 35, - "iteration_reverified_nets": 64, - "iteration_reverify_calls": 8, - "move_cache_abs_hits": 3181, - "move_cache_abs_misses": 4740, - "move_cache_rel_hits": 4171, - "move_cache_rel_misses": 569, - "moves_added": 7220, - "moves_generated": 7921, - "nets_carried_forward": 0, - "nets_reached_target": 64, - "nets_routed": 64, - "nodes_expanded": 1440, - "pair_local_search_accepts": 1, - "pair_local_search_attempts": 1, - "pair_local_search_nodes_expanded": 19, - "pair_local_search_pairs_considered": 1, - "path_cost_calls": 0, - "pruned_closed_set": 407, - "pruned_cost": 294, - "pruned_hard_collision": 0, - "ray_cast_calls": 4201, - "ray_cast_calls_expand_forward": 1376, - "ray_cast_calls_expand_snap": 46, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 2773, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 6, - "ray_cast_candidate_bounds": 187, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 8, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 8, - "score_component_calls": 7518, - "score_component_total_ns": 164933249, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 3079, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 1295, - "verify_dynamic_exact_pair_checks": 415, - "verify_path_report_calls": 152, - "verify_static_buffer_ops": 755, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 6, - "visibility_tangent_candidate_ray_tests": 6, - "visibility_tangent_candidate_scans": 1376, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 8, - "repeat": 0, - "seed": 42, - "summary": { - "reached_targets": 8, - "total_results": 8, - "valid_results": 8 - } - }, - { - "duration_s": 1.4636062050703913, - "metrics": { - "congestion_cache_hits": 37, - "congestion_cache_misses": 3799, - "congestion_candidate_ids": 7050, - "congestion_candidate_nets": 6725, - "congestion_candidate_precheck_hits": 1823, - "congestion_candidate_precheck_misses": 2035, - "congestion_candidate_precheck_skips": 22, - "congestion_check_calls": 3799, - "congestion_exact_pair_checks": 5684, - "congestion_grid_net_cache_hits": 1836, - "congestion_grid_net_cache_misses": 3693, - "congestion_grid_span_cache_hits": 1591, - "congestion_grid_span_cache_misses": 1804, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 1992, - "congestion_net_envelope_cache_misses": 3901, - "congestion_presence_cache_hits": 2321, - "congestion_presence_cache_misses": 2616, - "congestion_presence_skips": 1079, - "danger_map_cache_hits": 16398, - "danger_map_cache_misses": 5274, - "danger_map_lookup_calls": 21672, - "danger_map_query_calls": 5274, - "danger_map_total_ns": 142480011, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 435, - "dynamic_path_objects_removed": 400, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 14187.5, - "guidance_bonus_applied_bend90": 4187.5, - "guidance_bonus_applied_sbend": 875.0, - "guidance_bonus_applied_straight": 9125.0, - "guidance_match_moves": 227, - "guidance_match_moves_bend90": 67, - "guidance_match_moves_sbend": 14, - "guidance_match_moves_straight": 146, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 31, - "iteration_conflicting_nets": 35, - "iteration_reverified_nets": 64, - "iteration_reverify_calls": 8, - "move_cache_abs_hits": 3181, - "move_cache_abs_misses": 4740, - "move_cache_rel_hits": 4171, - "move_cache_rel_misses": 569, - "moves_added": 7220, - "moves_generated": 7921, - "nets_carried_forward": 0, - "nets_reached_target": 64, - "nets_routed": 64, - "nodes_expanded": 1440, - "pair_local_search_accepts": 1, - "pair_local_search_attempts": 1, - "pair_local_search_nodes_expanded": 19, - "pair_local_search_pairs_considered": 1, - "path_cost_calls": 0, - "pruned_closed_set": 407, - "pruned_cost": 294, - "pruned_hard_collision": 0, - "ray_cast_calls": 4201, - "ray_cast_calls_expand_forward": 1376, - "ray_cast_calls_expand_snap": 46, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 2773, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 6, - "ray_cast_candidate_bounds": 187, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 8, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 8, - "score_component_calls": 7518, - "score_component_total_ns": 165301696, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 3079, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 1295, - "verify_dynamic_exact_pair_checks": 415, - "verify_path_report_calls": 152, - "verify_static_buffer_ops": 755, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 6, - "visibility_tangent_candidate_ray_tests": 6, - "visibility_tangent_candidate_scans": 1376, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 8, - "repeat": 1, - "seed": 42, - "summary": { - "reached_targets": 8, - "total_results": 8, - "valid_results": 8 - } - }, - { - "duration_s": 1.065187250962481, - "metrics": { - "congestion_cache_hits": 10, - "congestion_cache_misses": 1844, - "congestion_candidate_ids": 3568, - "congestion_candidate_nets": 3390, - "congestion_candidate_precheck_hits": 757, - "congestion_candidate_precheck_misses": 1113, - "congestion_candidate_precheck_skips": 16, - "congestion_check_calls": 1844, - "congestion_exact_pair_checks": 2796, - "congestion_grid_net_cache_hits": 772, - "congestion_grid_net_cache_misses": 2030, - "congestion_grid_span_cache_hits": 678, - "congestion_grid_span_cache_misses": 1016, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 838, - "congestion_net_envelope_cache_misses": 2135, - "congestion_presence_cache_hits": 850, - "congestion_presence_cache_misses": 1349, - "congestion_presence_skips": 329, - "danger_map_cache_hits": 9125, - "danger_map_cache_misses": 4333, - "danger_map_lookup_calls": 13458, - "danger_map_query_calls": 4333, - "danger_map_total_ns": 126835582, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 256, - "dynamic_path_objects_removed": 218, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 5625.0, - "guidance_bonus_applied_bend90": 2000.0, - "guidance_bonus_applied_sbend": 500.0, - "guidance_bonus_applied_straight": 3125.0, - "guidance_match_moves": 90, - "guidance_match_moves_bend90": 32, - "guidance_match_moves_sbend": 8, - "guidance_match_moves_straight": 50, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 27, - "iteration_conflicting_nets": 26, - "iteration_reverified_nets": 40, - "iteration_reverify_calls": 5, - "move_cache_abs_hits": 1094, - "move_cache_abs_misses": 3955, - "move_cache_rel_hits": 3487, - "move_cache_rel_misses": 468, - "moves_added": 4475, - "moves_generated": 5049, - "nets_carried_forward": 0, - "nets_reached_target": 40, - "nets_routed": 40, - "nodes_expanded": 939, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 0, - "pruned_closed_set": 319, - "pruned_cost": 255, - "pruned_hard_collision": 0, - "ray_cast_calls": 3212, - "ray_cast_calls_expand_forward": 899, - "ray_cast_calls_expand_snap": 20, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 2287, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 6, - "ray_cast_candidate_bounds": 140, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 8, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 5, - "score_component_calls": 4741, - "score_component_total_ns": 141872767, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 1057, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 751, - "verify_dynamic_exact_pair_checks": 363, - "verify_path_report_calls": 96, - "verify_static_buffer_ops": 436, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 6, - "visibility_tangent_candidate_ray_tests": 6, - "visibility_tangent_candidate_scans": 899, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 8, - "repeat": 0, - "seed": 43, - "summary": { - "reached_targets": 8, - "total_results": 8, - "valid_results": 8 - } - }, - { - "duration_s": 1.0501909658778459, - "metrics": { - "congestion_cache_hits": 10, - "congestion_cache_misses": 1844, - "congestion_candidate_ids": 3568, - "congestion_candidate_nets": 3390, - "congestion_candidate_precheck_hits": 757, - "congestion_candidate_precheck_misses": 1113, - "congestion_candidate_precheck_skips": 16, - "congestion_check_calls": 1844, - "congestion_exact_pair_checks": 2796, - "congestion_grid_net_cache_hits": 772, - "congestion_grid_net_cache_misses": 2030, - "congestion_grid_span_cache_hits": 678, - "congestion_grid_span_cache_misses": 1016, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 838, - "congestion_net_envelope_cache_misses": 2135, - "congestion_presence_cache_hits": 850, - "congestion_presence_cache_misses": 1349, - "congestion_presence_skips": 329, - "danger_map_cache_hits": 9125, - "danger_map_cache_misses": 4333, - "danger_map_lookup_calls": 13458, - "danger_map_query_calls": 4333, - "danger_map_total_ns": 112792178, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 256, - "dynamic_path_objects_removed": 218, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 5625.0, - "guidance_bonus_applied_bend90": 2000.0, - "guidance_bonus_applied_sbend": 500.0, - "guidance_bonus_applied_straight": 3125.0, - "guidance_match_moves": 90, - "guidance_match_moves_bend90": 32, - "guidance_match_moves_sbend": 8, - "guidance_match_moves_straight": 50, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 27, - "iteration_conflicting_nets": 26, - "iteration_reverified_nets": 40, - "iteration_reverify_calls": 5, - "move_cache_abs_hits": 1094, - "move_cache_abs_misses": 3955, - "move_cache_rel_hits": 3487, - "move_cache_rel_misses": 468, - "moves_added": 4475, - "moves_generated": 5049, - "nets_carried_forward": 0, - "nets_reached_target": 40, - "nets_routed": 40, - "nodes_expanded": 939, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 0, - "pruned_closed_set": 319, - "pruned_cost": 255, - "pruned_hard_collision": 0, - "ray_cast_calls": 3212, - "ray_cast_calls_expand_forward": 899, - "ray_cast_calls_expand_snap": 20, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 2287, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 6, - "ray_cast_candidate_bounds": 140, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 8, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 5, - "score_component_calls": 4741, - "score_component_total_ns": 127782063, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 1057, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 751, - "verify_dynamic_exact_pair_checks": 363, - "verify_path_report_calls": 96, - "verify_static_buffer_ops": 436, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 6, - "visibility_tangent_candidate_ray_tests": 6, - "visibility_tangent_candidate_scans": 899, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 8, - "repeat": 1, - "seed": 43, - "summary": { - "reached_targets": 8, - "total_results": 8, - "valid_results": 8 - } - }, - { - "duration_s": 2.861715276958421, - "metrics": { - "congestion_cache_hits": 181, - "congestion_cache_misses": 6208, - "congestion_candidate_ids": 14969, - "congestion_candidate_nets": 14477, - "congestion_candidate_precheck_hits": 4046, - "congestion_candidate_precheck_misses": 2450, - "congestion_candidate_precheck_skips": 107, - "congestion_check_calls": 6208, - "congestion_exact_pair_checks": 12175, - "congestion_grid_net_cache_hits": 3733, - "congestion_grid_net_cache_misses": 4394, - "congestion_grid_span_cache_hits": 3484, - "congestion_grid_span_cache_misses": 2188, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 4110, - "congestion_net_envelope_cache_misses": 4614, - "congestion_presence_cache_hits": 4474, - "congestion_presence_cache_misses": 2857, - "congestion_presence_skips": 835, - "danger_map_cache_hits": 21570, - "danger_map_cache_misses": 8484, - "danger_map_lookup_calls": 30054, - "danger_map_query_calls": 8484, - "danger_map_total_ns": 229555102, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 470, - "dynamic_path_objects_removed": 422, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 12937.5, - "guidance_bonus_applied_bend90": 4187.5, - "guidance_bonus_applied_sbend": 750.0, - "guidance_bonus_applied_straight": 8000.0, - "guidance_match_moves": 207, - "guidance_match_moves_bend90": 67, - "guidance_match_moves_sbend": 12, - "guidance_match_moves_straight": 128, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 43, - "iteration_conflicting_nets": 43, - "iteration_reverified_nets": 60, - "iteration_reverify_calls": 6, - "move_cache_abs_hits": 3714, - "move_cache_abs_misses": 7526, - "move_cache_rel_hits": 6718, - "move_cache_rel_misses": 808, - "moves_added": 9950, - "moves_generated": 11240, - "nets_carried_forward": 0, - "nets_reached_target": 60, - "nets_routed": 60, - "nodes_expanded": 2223, - "pair_local_search_accepts": 2, - "pair_local_search_attempts": 3, - "pair_local_search_nodes_expanded": 41, - "pair_local_search_pairs_considered": 2, - "path_cost_calls": 0, - "pruned_closed_set": 566, - "pruned_cost": 724, - "pruned_hard_collision": 0, - "ray_cast_calls": 6546, - "ray_cast_calls_expand_forward": 2163, - "ray_cast_calls_expand_snap": 43, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 4334, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 6, - "ray_cast_candidate_bounds": 438, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 8, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 6, - "score_component_calls": 10742, - "score_component_total_ns": 262906657, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 3614, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 1812, - "verify_dynamic_exact_pair_checks": 590, - "verify_path_report_calls": 160, - "verify_static_buffer_ops": 771, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 6, - "visibility_tangent_candidate_ray_tests": 6, - "visibility_tangent_candidate_scans": 2163, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 10, - "repeat": 0, - "seed": 41, - "summary": { - "reached_targets": 10, - "total_results": 10, - "valid_results": 8 - } - }, - { - "duration_s": 2.8281878910493106, - "metrics": { - "congestion_cache_hits": 181, - "congestion_cache_misses": 6208, - "congestion_candidate_ids": 14969, - "congestion_candidate_nets": 14477, - "congestion_candidate_precheck_hits": 4046, - "congestion_candidate_precheck_misses": 2450, - "congestion_candidate_precheck_skips": 107, - "congestion_check_calls": 6208, - "congestion_exact_pair_checks": 12175, - "congestion_grid_net_cache_hits": 3733, - "congestion_grid_net_cache_misses": 4394, - "congestion_grid_span_cache_hits": 3484, - "congestion_grid_span_cache_misses": 2188, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 4110, - "congestion_net_envelope_cache_misses": 4614, - "congestion_presence_cache_hits": 4474, - "congestion_presence_cache_misses": 2857, - "congestion_presence_skips": 835, - "danger_map_cache_hits": 21570, - "danger_map_cache_misses": 8484, - "danger_map_lookup_calls": 30054, - "danger_map_query_calls": 8484, - "danger_map_total_ns": 223711146, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 470, - "dynamic_path_objects_removed": 422, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 12937.5, - "guidance_bonus_applied_bend90": 4187.5, - "guidance_bonus_applied_sbend": 750.0, - "guidance_bonus_applied_straight": 8000.0, - "guidance_match_moves": 207, - "guidance_match_moves_bend90": 67, - "guidance_match_moves_sbend": 12, - "guidance_match_moves_straight": 128, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 43, - "iteration_conflicting_nets": 43, - "iteration_reverified_nets": 60, - "iteration_reverify_calls": 6, - "move_cache_abs_hits": 3714, - "move_cache_abs_misses": 7526, - "move_cache_rel_hits": 6718, - "move_cache_rel_misses": 808, - "moves_added": 9950, - "moves_generated": 11240, - "nets_carried_forward": 0, - "nets_reached_target": 60, - "nets_routed": 60, - "nodes_expanded": 2223, - "pair_local_search_accepts": 2, - "pair_local_search_attempts": 3, - "pair_local_search_nodes_expanded": 41, - "pair_local_search_pairs_considered": 2, - "path_cost_calls": 0, - "pruned_closed_set": 566, - "pruned_cost": 724, - "pruned_hard_collision": 0, - "ray_cast_calls": 6546, - "ray_cast_calls_expand_forward": 2163, - "ray_cast_calls_expand_snap": 43, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 4334, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 6, - "ray_cast_candidate_bounds": 438, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 8, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 6, - "score_component_calls": 10742, - "score_component_total_ns": 257092830, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 3614, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 1812, - "verify_dynamic_exact_pair_checks": 590, - "verify_path_report_calls": 160, - "verify_static_buffer_ops": 771, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 6, - "visibility_tangent_candidate_ray_tests": 6, - "visibility_tangent_candidate_scans": 2163, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 10, - "repeat": 1, - "seed": 41, - "summary": { - "reached_targets": 10, - "total_results": 10, - "valid_results": 8 - } - }, - { - "duration_s": 2.035589807201177, - "metrics": { - "congestion_cache_hits": 31, - "congestion_cache_misses": 4625, - "congestion_candidate_ids": 9924, - "congestion_candidate_nets": 9979, - "congestion_candidate_precheck_hits": 2562, - "congestion_candidate_precheck_misses": 2165, - "congestion_candidate_precheck_skips": 71, - "congestion_check_calls": 4625, - "congestion_exact_pair_checks": 8122, - "congestion_grid_net_cache_hits": 2457, - "congestion_grid_net_cache_misses": 3942, - "congestion_grid_span_cache_hits": 2283, - "congestion_grid_span_cache_misses": 1948, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 2673, - "congestion_net_envelope_cache_misses": 4139, - "congestion_presence_cache_hits": 2858, - "congestion_presence_cache_misses": 2556, - "congestion_presence_skips": 687, - "danger_map_cache_hits": 16878, - "danger_map_cache_misses": 7425, - "danger_map_lookup_calls": 24303, - "danger_map_query_calls": 7425, - "danger_map_total_ns": 197092109, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 471, - "dynamic_path_objects_removed": 423, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 11000.0, - "guidance_bonus_applied_bend90": 3500.0, - "guidance_bonus_applied_sbend": 625.0, - "guidance_bonus_applied_straight": 6875.0, - "guidance_match_moves": 176, - "guidance_match_moves_bend90": 56, - "guidance_match_moves_sbend": 10, - "guidance_match_moves_straight": 110, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 39, - "iteration_conflicting_nets": 36, - "iteration_reverified_nets": 60, - "iteration_reverify_calls": 6, - "move_cache_abs_hits": 2559, - "move_cache_abs_misses": 6494, - "move_cache_rel_hits": 5872, - "move_cache_rel_misses": 622, - "moves_added": 8081, - "moves_generated": 9053, - "nets_carried_forward": 0, - "nets_reached_target": 60, - "nets_routed": 60, - "nodes_expanded": 1764, - "pair_local_search_accepts": 2, - "pair_local_search_attempts": 2, - "pair_local_search_nodes_expanded": 68, - "pair_local_search_pairs_considered": 2, - "path_cost_calls": 0, - "pruned_closed_set": 439, - "pruned_cost": 533, - "pruned_hard_collision": 0, - "ray_cast_calls": 5477, - "ray_cast_calls_expand_forward": 1704, - "ray_cast_calls_expand_snap": 46, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 3721, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 6, - "ray_cast_candidate_bounds": 305, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 10, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 6, - "score_component_calls": 8634, - "score_component_total_ns": 223430894, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 2482, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 1756, - "verify_dynamic_exact_pair_checks": 510, - "verify_path_report_calls": 160, - "verify_static_buffer_ops": 751, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 6, - "visibility_tangent_candidate_ray_tests": 6, - "visibility_tangent_candidate_scans": 1704, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 10, - "repeat": 0, - "seed": 42, - "summary": { - "reached_targets": 10, - "total_results": 10, - "valid_results": 10 - } - }, - { - "duration_s": 2.0052393269725144, - "metrics": { - "congestion_cache_hits": 31, - "congestion_cache_misses": 4625, - "congestion_candidate_ids": 9924, - "congestion_candidate_nets": 9979, - "congestion_candidate_precheck_hits": 2562, - "congestion_candidate_precheck_misses": 2165, - "congestion_candidate_precheck_skips": 71, - "congestion_check_calls": 4625, - "congestion_exact_pair_checks": 8122, - "congestion_grid_net_cache_hits": 2457, - "congestion_grid_net_cache_misses": 3942, - "congestion_grid_span_cache_hits": 2283, - "congestion_grid_span_cache_misses": 1948, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 2673, - "congestion_net_envelope_cache_misses": 4139, - "congestion_presence_cache_hits": 2858, - "congestion_presence_cache_misses": 2556, - "congestion_presence_skips": 687, - "danger_map_cache_hits": 16878, - "danger_map_cache_misses": 7425, - "danger_map_lookup_calls": 24303, - "danger_map_query_calls": 7425, - "danger_map_total_ns": 196041391, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 471, - "dynamic_path_objects_removed": 423, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 11000.0, - "guidance_bonus_applied_bend90": 3500.0, - "guidance_bonus_applied_sbend": 625.0, - "guidance_bonus_applied_straight": 6875.0, - "guidance_match_moves": 176, - "guidance_match_moves_bend90": 56, - "guidance_match_moves_sbend": 10, - "guidance_match_moves_straight": 110, - "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 39, - "iteration_conflicting_nets": 36, - "iteration_reverified_nets": 60, - "iteration_reverify_calls": 6, - "move_cache_abs_hits": 2559, - "move_cache_abs_misses": 6494, - "move_cache_rel_hits": 5872, - "move_cache_rel_misses": 622, - "moves_added": 8081, - "moves_generated": 9053, - "nets_carried_forward": 0, - "nets_reached_target": 60, - "nets_routed": 60, - "nodes_expanded": 1764, - "pair_local_search_accepts": 2, - "pair_local_search_attempts": 2, - "pair_local_search_nodes_expanded": 68, - "pair_local_search_pairs_considered": 2, - "path_cost_calls": 0, - "pruned_closed_set": 439, - "pruned_cost": 533, - "pruned_hard_collision": 0, - "ray_cast_calls": 5477, - "ray_cast_calls_expand_forward": 1704, - "ray_cast_calls_expand_snap": 46, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 3721, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 6, - "ray_cast_candidate_bounds": 305, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 10, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 6, - "score_component_calls": 8634, - "score_component_total_ns": 222749506, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 2482, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 1756, - "verify_dynamic_exact_pair_checks": 510, - "verify_path_report_calls": 160, - "verify_static_buffer_ops": 751, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 6, - "visibility_tangent_candidate_ray_tests": 6, - "visibility_tangent_candidate_scans": 1704, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 10, - "repeat": 1, - "seed": 42, - "summary": { - "reached_targets": 10, - "total_results": 10, - "valid_results": 10 - } - }, - { - "duration_s": 50.18633775901981, - "metrics": { - "congestion_cache_hits": 1713, - "congestion_cache_misses": 165223, - "congestion_candidate_ids": 312161, - "congestion_candidate_nets": 300960, - "congestion_candidate_precheck_hits": 159843, - "congestion_candidate_precheck_misses": 7810, - "congestion_candidate_precheck_skips": 717, - "congestion_check_calls": 165223, - "congestion_exact_pair_checks": 249697, - "congestion_grid_net_cache_hits": 152369, - "congestion_grid_net_cache_misses": 13481, - "congestion_grid_span_cache_hits": 144618, - "congestion_grid_span_cache_misses": 6885, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 160549, - "congestion_net_envelope_cache_misses": 14205, - "congestion_presence_cache_hits": 186369, - "congestion_presence_cache_misses": 9324, - "congestion_presence_skips": 27588, - "danger_map_cache_hits": 453553, - "danger_map_cache_misses": 140744, - "danger_map_lookup_calls": 594297, - "danger_map_query_calls": 140744, - "danger_map_total_ns": 4360608337, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 683, - "dynamic_path_objects_removed": 637, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 23437.5, - "guidance_bonus_applied_bend90": 8437.5, - "guidance_bonus_applied_sbend": 1000.0, - "guidance_bonus_applied_straight": 14000.0, - "guidance_match_moves": 375, - "guidance_match_moves_bend90": 135, - "guidance_match_moves_sbend": 16, - "guidance_match_moves_straight": 224, - "hard_collision_cache_hits": 859, - "iteration_conflict_edges": 51, - "iteration_conflicting_nets": 57, - "iteration_reverified_nets": 90, - "iteration_reverify_calls": 9, - "move_cache_abs_hits": 140734, - "move_cache_abs_misses": 183345, - "move_cache_rel_hits": 180943, - "move_cache_rel_misses": 2402, - "moves_added": 197062, - "moves_generated": 324079, - "nets_carried_forward": 0, - "nets_reached_target": 90, - "nets_routed": 90, - "nodes_expanded": 61259, - "pair_local_search_accepts": 2, - "pair_local_search_attempts": 3, - "pair_local_search_nodes_expanded": 38, - "pair_local_search_pairs_considered": 2, - "path_cost_calls": 0, - "pruned_closed_set": 49632, - "pruned_cost": 5502, - "pruned_hard_collision": 2123, - "ray_cast_calls": 166977, - "ray_cast_calls_expand_forward": 61169, - "ray_cast_calls_expand_snap": 735, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 103738, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 1335, - "ray_cast_candidate_bounds": 11494, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 10, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 9, - "score_component_calls": 203601, - "score_component_total_ns": 5065858683, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 120231, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 2653, - "verify_dynamic_exact_pair_checks": 714, - "verify_path_report_calls": 220, - "verify_static_buffer_ops": 1185, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 1405, - "visibility_tangent_candidate_ray_tests": 1335, - "visibility_tangent_candidate_scans": 61169, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 10, - "repeat": 0, - "seed": 43, - "summary": { - "reached_targets": 10, - "total_results": 10, - "valid_results": 10 - } - }, - { - "duration_s": 50.40192667697556, - "metrics": { - "congestion_cache_hits": 1713, - "congestion_cache_misses": 165223, - "congestion_candidate_ids": 312161, - "congestion_candidate_nets": 300960, - "congestion_candidate_precheck_hits": 159843, - "congestion_candidate_precheck_misses": 7810, - "congestion_candidate_precheck_skips": 717, - "congestion_check_calls": 165223, - "congestion_exact_pair_checks": 249697, - "congestion_grid_net_cache_hits": 152369, - "congestion_grid_net_cache_misses": 13481, - "congestion_grid_span_cache_hits": 144618, - "congestion_grid_span_cache_misses": 6885, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 160549, - "congestion_net_envelope_cache_misses": 14205, - "congestion_presence_cache_hits": 186369, - "congestion_presence_cache_misses": 9324, - "congestion_presence_skips": 27588, - "danger_map_cache_hits": 453553, - "danger_map_cache_misses": 140744, - "danger_map_lookup_calls": 594297, - "danger_map_query_calls": 140744, - "danger_map_total_ns": 4932050184, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 683, - "dynamic_path_objects_removed": 637, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 23437.5, - "guidance_bonus_applied_bend90": 8437.5, - "guidance_bonus_applied_sbend": 1000.0, - "guidance_bonus_applied_straight": 14000.0, - "guidance_match_moves": 375, - "guidance_match_moves_bend90": 135, - "guidance_match_moves_sbend": 16, - "guidance_match_moves_straight": 224, - "hard_collision_cache_hits": 859, - "iteration_conflict_edges": 51, - "iteration_conflicting_nets": 57, - "iteration_reverified_nets": 90, - "iteration_reverify_calls": 9, - "move_cache_abs_hits": 140734, - "move_cache_abs_misses": 183345, - "move_cache_rel_hits": 180943, - "move_cache_rel_misses": 2402, - "moves_added": 197062, - "moves_generated": 324079, - "nets_carried_forward": 0, - "nets_reached_target": 90, - "nets_routed": 90, - "nodes_expanded": 61259, - "pair_local_search_accepts": 2, - "pair_local_search_attempts": 3, - "pair_local_search_nodes_expanded": 38, - "pair_local_search_pairs_considered": 2, - "path_cost_calls": 0, - "pruned_closed_set": 49632, - "pruned_cost": 5502, - "pruned_hard_collision": 2123, - "ray_cast_calls": 166977, - "ray_cast_calls_expand_forward": 61169, - "ray_cast_calls_expand_snap": 735, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 103738, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 1335, - "ray_cast_candidate_bounds": 11494, - "ray_cast_exact_geometry_checks": 0, - "refine_path_calls": 10, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, - "route_iterations": 9, - "score_component_calls": 203601, - "score_component_total_ns": 5635427939, - "static_net_tree_rebuilds": 1, - "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 120231, - "static_tree_rebuilds": 1, - "timeout_events": 0, - "verify_dynamic_candidate_nets": 2653, - "verify_dynamic_exact_pair_checks": 714, - "verify_path_report_calls": 220, - "verify_static_buffer_ops": 1185, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, - "visibility_point_cache_hits": 0, - "visibility_point_cache_misses": 0, - "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 1405, - "visibility_tangent_candidate_ray_tests": 1335, - "visibility_tangent_candidate_scans": 61169, - "warm_start_paths_built": 0, - "warm_start_paths_used": 0 - }, - "num_nets": 10, - "repeat": 1, - "seed": 43, - "summary": { - "reached_targets": 10, - "total_results": 10, - "valid_results": 10 - } - } - ], - "generated_at": "2026-04-02T15:53:29-07:00", - "generator": "scripts/characterize_pair_local_search.py", - "grid": { - "num_nets": [ - 6, - 8, - 10 - ], - "repeats": 2, - "seeds": [ - 41, - 42, - 43 - ] - }, - "recommended_smoke_scenario": null -} diff --git a/docs/pair_local_characterization.md b/docs/pair_local_characterization.md deleted file mode 100644 index 753cbdf..0000000 --- a/docs/pair_local_characterization.md +++ /dev/null @@ -1,30 +0,0 @@ -# Pair-Local Search Characterization - -Generated at 2026-04-02T15:53:29-07:00 by `scripts/characterize_pair_local_search.py`. - -Grid: `num_nets=[6, 8, 10]`, `seed=[41, 42, 43]`, repeats=2. - -| Nets | Seed | Repeat | Duration (s) | Valid | Reached | Pair Pairs | Pair Accepts | Pair Nodes | Nodes | Checks | -| :-- | :-- | :-- | --: | --: | --: | --: | --: | --: | --: | --: | -| 6 | 41 | 0 | 0.5462 | 1 | 6 | 0 | 0 | 0 | 500 | 674 | -| 6 | 41 | 1 | 0.5256 | 1 | 6 | 0 | 0 | 0 | 500 | 674 | -| 6 | 42 | 0 | 0.5241 | 1 | 6 | 0 | 0 | 0 | 503 | 683 | -| 6 | 42 | 1 | 0.5477 | 1 | 6 | 0 | 0 | 0 | 503 | 683 | -| 6 | 43 | 0 | 0.5199 | 1 | 6 | 0 | 0 | 0 | 493 | 654 | -| 6 | 43 | 1 | 0.5160 | 1 | 6 | 0 | 0 | 0 | 493 | 654 | -| 8 | 41 | 0 | 1.8818 | 8 | 8 | 2 | 2 | 38 | 1558 | 4313 | -| 8 | 41 | 1 | 1.8618 | 8 | 8 | 2 | 2 | 38 | 1558 | 4313 | -| 8 | 42 | 0 | 1.4850 | 8 | 8 | 1 | 1 | 19 | 1440 | 3799 | -| 8 | 42 | 1 | 1.4636 | 8 | 8 | 1 | 1 | 19 | 1440 | 3799 | -| 8 | 43 | 0 | 1.0652 | 8 | 8 | 0 | 0 | 0 | 939 | 1844 | -| 8 | 43 | 1 | 1.0502 | 8 | 8 | 0 | 0 | 0 | 939 | 1844 | -| 10 | 41 | 0 | 2.8617 | 8 | 10 | 2 | 2 | 41 | 2223 | 6208 | -| 10 | 41 | 1 | 2.8282 | 8 | 10 | 2 | 2 | 41 | 2223 | 6208 | -| 10 | 42 | 0 | 2.0356 | 10 | 10 | 2 | 2 | 68 | 1764 | 4625 | -| 10 | 42 | 1 | 2.0052 | 10 | 10 | 2 | 2 | 68 | 1764 | 4625 | -| 10 | 43 | 0 | 50.1863 | 10 | 10 | 2 | 2 | 38 | 61259 | 165223 | -| 10 | 43 | 1 | 50.4019 | 10 | 10 | 2 | 2 | 38 | 61259 | 165223 | - -## Recommendation - -No smaller stable pair-local smoke scenario satisfied the rule `valid_results == total_results`, `pair_local_search_accepts >= 1`, and `duration_s <= 1.0` across all repeats. diff --git a/docs/performance.md b/docs/performance.md index 7085214..3144243 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -1,41 +1,25 @@ # Performance Baseline -Generated on 2026-04-02 by `scripts/record_performance_baseline.py`. +Generated on 2026-03-31 by `scripts/record_performance_baseline.py`. The full machine-readable snapshot lives in `docs/performance_baseline.json`. -Use `scripts/diff_performance_baseline.py` to compare a fresh run against that snapshot. - -The default baseline table below covers the standard example corpus only. The heavier `example_07_large_scale_routing_no_warm_start` canary remains performance-only and is tracked through targeted diffs plus the conflict/frontier trace artifacts. - -Use `scripts/characterize_pair_local_search.py` when you want a small parameter sweep over example_07-style no-warm runs instead of a single canary reading. -The current tracked sweep output lives in `docs/pair_local_characterization.json` and `docs/pair_local_characterization.md`. | Scenario | Duration (s) | Total | Valid | Reached | Iter | Nets Routed | Nodes | Ray Casts | Moves Gen | Moves Added | Dyn Tree | Visibility Builds | Congestion Checks | Verify Calls | | :-- | --: | --: | --: | --: | --: | --: | --: | --: | --: | --: | --: | --: | --: | --: | -| example_01_simple_route | 0.0040 | 1 | 1 | 1 | 1 | 1 | 2 | 10 | 11 | 7 | 0 | 0 | 0 | 4 | -| example_02_congestion_resolution | 0.3378 | 3 | 3 | 3 | 1 | 3 | 366 | 1164 | 1413 | 668 | 0 | 0 | 0 | 38 | -| example_03_locked_paths | 0.1929 | 2 | 2 | 2 | 2 | 2 | 191 | 657 | 904 | 307 | 0 | 0 | 0 | 16 | -| example_04_sbends_and_radii | 0.0279 | 2 | 2 | 2 | 1 | 2 | 15 | 70 | 123 | 65 | 0 | 0 | 0 | 8 | -| example_05_orientation_stress | 0.2367 | 3 | 3 | 3 | 2 | 6 | 299 | 1284 | 1691 | 696 | 0 | 0 | 149 | 18 | -| example_06_bend_collision_models | 0.1998 | 3 | 3 | 3 | 3 | 3 | 240 | 682 | 1026 | 629 | 0 | 0 | 0 | 12 | -| example_07_large_scale_routing | 0.2005 | 10 | 10 | 10 | 1 | 10 | 78 | 383 | 372 | 227 | 0 | 0 | 0 | 40 | -| example_08_custom_bend_geometry | 0.0176 | 2 | 2 | 2 | 2 | 2 | 18 | 56 | 78 | 56 | 0 | 0 | 0 | 8 | -| example_09_unroutable_best_effort | 0.0058 | 1 | 0 | 0 | 1 | 1 | 3 | 13 | 16 | 10 | 0 | 0 | 0 | 1 | +| example_01_simple_route | 0.0042 | 1 | 1 | 1 | 1 | 1 | 2 | 22 | 11 | 7 | 2 | 2 | 0 | 3 | +| example_02_congestion_resolution | 0.3335 | 3 | 3 | 3 | 1 | 3 | 366 | 1176 | 1413 | 668 | 8 | 4 | 0 | 35 | +| example_03_locked_paths | 0.1810 | 2 | 2 | 2 | 2 | 2 | 191 | 681 | 904 | 307 | 5 | 4 | 0 | 14 | +| example_04_sbends_and_radii | 2.0151 | 2 | 2 | 2 | 1 | 2 | 15 | 18218 | 123 | 65 | 4 | 3 | 0 | 6 | +| example_05_orientation_stress | 0.2438 | 3 | 3 | 3 | 2 | 6 | 286 | 1243 | 1624 | 681 | 12 | 3 | 412 | 12 | +| example_06_bend_collision_models | 4.1636 | 3 | 3 | 3 | 3 | 3 | 240 | 40530 | 1026 | 629 | 6 | 6 | 0 | 9 | +| example_07_large_scale_routing | 1.3759 | 10 | 10 | 10 | 1 | 10 | 78 | 11151 | 372 | 227 | 20 | 11 | 0 | 30 | +| example_08_custom_bend_geometry | 0.2437 | 2 | 2 | 2 | 2 | 2 | 18 | 2308 | 78 | 56 | 4 | 4 | 0 | 6 | +| example_09_unroutable_best_effort | 0.0052 | 1 | 0 | 0 | 1 | 1 | 3 | 13 | 16 | 10 | 1 | 0 | 0 | 1 | ## Full Counter Set Each scenario entry in `docs/performance_baseline.json` records the full `RouteMetrics` snapshot, including cache, index, congestion, and verification counters. -These counters are currently observational only and are not enforced as CI regression gates. - -For the current accepted branch, the most important performance-only canary is `example_07_large_scale_routing_no_warm_start`, which now finishes `10/10/10` after a bounded post-loop pair-local scratch reroute. The relevant counters for that phase are: - -- `pair_local_search_pairs_considered` -- `pair_local_search_attempts` -- `pair_local_search_accepts` -- `pair_local_search_nodes_expanded` - -The latest tracked characterization sweep confirms there is no smaller stable pair-local smoke case under the `<=1.0s` rule, so the 10-net no-warm-start canary remains the primary regression target for this behavior. Tracked metric keys: -nodes_expanded, moves_generated, moves_added, pruned_closed_set, pruned_hard_collision, pruned_cost, route_iterations, nets_routed, nets_reached_target, warm_start_paths_built, warm_start_paths_used, refine_path_calls, timeout_events, iteration_reverify_calls, iteration_reverified_nets, iteration_conflicting_nets, iteration_conflict_edges, nets_carried_forward, score_component_calls, score_component_total_ns, path_cost_calls, danger_map_lookup_calls, danger_map_cache_hits, danger_map_cache_misses, danger_map_query_calls, danger_map_total_ns, move_cache_abs_hits, move_cache_abs_misses, move_cache_rel_hits, move_cache_rel_misses, guidance_match_moves, guidance_match_moves_straight, guidance_match_moves_bend90, guidance_match_moves_sbend, guidance_bonus_applied, guidance_bonus_applied_straight, guidance_bonus_applied_bend90, guidance_bonus_applied_sbend, static_safe_cache_hits, hard_collision_cache_hits, congestion_cache_hits, congestion_cache_misses, congestion_presence_cache_hits, congestion_presence_cache_misses, congestion_presence_skips, congestion_candidate_precheck_hits, congestion_candidate_precheck_misses, congestion_candidate_precheck_skips, congestion_grid_net_cache_hits, congestion_grid_net_cache_misses, congestion_grid_span_cache_hits, congestion_grid_span_cache_misses, congestion_candidate_nets, congestion_net_envelope_cache_hits, congestion_net_envelope_cache_misses, dynamic_path_objects_added, dynamic_path_objects_removed, dynamic_tree_rebuilds, dynamic_grid_rebuilds, static_tree_rebuilds, static_raw_tree_rebuilds, static_net_tree_rebuilds, visibility_corner_index_builds, visibility_builds, visibility_corner_pairs_checked, visibility_corner_queries_exact, visibility_corner_hits_exact, visibility_point_queries, visibility_point_cache_hits, visibility_point_cache_misses, visibility_tangent_candidate_scans, visibility_tangent_candidate_corner_checks, visibility_tangent_candidate_ray_tests, ray_cast_calls, ray_cast_calls_straight_static, ray_cast_calls_expand_snap, ray_cast_calls_expand_forward, ray_cast_calls_visibility_build, ray_cast_calls_visibility_query, ray_cast_calls_visibility_tangent, ray_cast_calls_other, ray_cast_candidate_bounds, ray_cast_exact_geometry_checks, congestion_check_calls, congestion_lazy_resolutions, congestion_lazy_requeues, congestion_candidate_ids, congestion_exact_pair_checks, verify_path_report_calls, verify_static_buffer_ops, verify_dynamic_candidate_nets, verify_dynamic_exact_pair_checks, refinement_windows_considered, refinement_static_bounds_checked, refinement_dynamic_bounds_checked, refinement_candidate_side_extents, refinement_candidates_built, refinement_candidates_verified, refinement_candidates_accepted, pair_local_search_pairs_considered, pair_local_search_attempts, pair_local_search_accepts, pair_local_search_nodes_expanded +nodes_expanded, moves_generated, moves_added, pruned_closed_set, pruned_hard_collision, pruned_cost, route_iterations, nets_routed, nets_reached_target, warm_start_paths_built, warm_start_paths_used, refine_path_calls, timeout_events, move_cache_abs_hits, move_cache_abs_misses, move_cache_rel_hits, move_cache_rel_misses, static_safe_cache_hits, hard_collision_cache_hits, congestion_cache_hits, congestion_cache_misses, dynamic_path_objects_added, dynamic_path_objects_removed, dynamic_tree_rebuilds, dynamic_grid_rebuilds, static_tree_rebuilds, static_raw_tree_rebuilds, static_net_tree_rebuilds, visibility_builds, visibility_corner_pairs_checked, visibility_corner_queries, visibility_corner_hits, visibility_point_queries, visibility_point_cache_hits, visibility_point_cache_misses, ray_cast_calls, ray_cast_candidate_bounds, ray_cast_exact_geometry_checks, congestion_check_calls, congestion_exact_pair_checks, verify_path_report_calls, verify_static_buffer_ops, verify_dynamic_exact_pair_checks diff --git a/docs/performance_baseline.json b/docs/performance_baseline.json index a0477d3..0c3c030 100644 --- a/docs/performance_baseline.json +++ b/docs/performance_baseline.json @@ -1,111 +1,51 @@ { - "generated_on": "2026-04-02", + "generated_on": "2026-03-31", "generator": "scripts/record_performance_baseline.py", "scenarios": [ { - "duration_s": 0.003964120987802744, + "duration_s": 0.0041740520391613245, "metrics": { "congestion_cache_hits": 0, "congestion_cache_misses": 0, - "congestion_candidate_ids": 0, - "congestion_candidate_nets": 0, - "congestion_candidate_precheck_hits": 0, - "congestion_candidate_precheck_misses": 0, - "congestion_candidate_precheck_skips": 0, "congestion_check_calls": 0, "congestion_exact_pair_checks": 0, - "congestion_grid_net_cache_hits": 0, - "congestion_grid_net_cache_misses": 0, - "congestion_grid_span_cache_hits": 0, - "congestion_grid_span_cache_misses": 0, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 0, - "congestion_net_envelope_cache_misses": 0, - "congestion_presence_cache_hits": 0, - "congestion_presence_cache_misses": 0, - "congestion_presence_skips": 0, - "danger_map_cache_hits": 0, - "danger_map_cache_misses": 0, - "danger_map_lookup_calls": 0, - "danger_map_query_calls": 0, - "danger_map_total_ns": 0, "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 3, - "dynamic_path_objects_removed": 2, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 0.0, - "guidance_bonus_applied_bend90": 0.0, - "guidance_bonus_applied_sbend": 0.0, - "guidance_bonus_applied_straight": 0.0, - "guidance_match_moves": 0, - "guidance_match_moves_bend90": 0, - "guidance_match_moves_sbend": 0, - "guidance_match_moves_straight": 0, + "dynamic_path_objects_added": 2, + "dynamic_path_objects_removed": 1, + "dynamic_tree_rebuilds": 2, "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 0, - "iteration_conflicting_nets": 0, - "iteration_reverified_nets": 1, - "iteration_reverify_calls": 1, "move_cache_abs_hits": 1, "move_cache_abs_misses": 10, "move_cache_rel_hits": 0, "move_cache_rel_misses": 10, "moves_added": 7, "moves_generated": 11, - "nets_carried_forward": 0, "nets_reached_target": 1, "nets_routed": 1, "nodes_expanded": 2, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 0, "pruned_closed_set": 0, "pruned_cost": 4, "pruned_hard_collision": 0, - "ray_cast_calls": 10, - "ray_cast_calls_expand_forward": 1, - "ray_cast_calls_expand_snap": 1, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 8, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 0, - "ray_cast_candidate_bounds": 0, + "ray_cast_calls": 22, + "ray_cast_candidate_bounds": 12, "ray_cast_exact_geometry_checks": 0, "refine_path_calls": 1, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, "route_iterations": 1, - "score_component_calls": 11, - "score_component_total_ns": 18064, "static_net_tree_rebuilds": 1, "static_raw_tree_rebuilds": 0, "static_safe_cache_hits": 1, - "static_tree_rebuilds": 0, + "static_tree_rebuilds": 1, "timeout_events": 0, - "verify_dynamic_candidate_nets": 0, "verify_dynamic_exact_pair_checks": 0, - "verify_path_report_calls": 4, + "verify_path_report_calls": 3, "verify_static_buffer_ops": 0, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, + "visibility_builds": 2, + "visibility_corner_hits": 0, + "visibility_corner_pairs_checked": 12, + "visibility_corner_queries": 0, "visibility_point_cache_hits": 0, "visibility_point_cache_misses": 0, "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 0, - "visibility_tangent_candidate_ray_tests": 0, - "visibility_tangent_candidate_scans": 1, "warm_start_paths_built": 1, "warm_start_paths_used": 1 }, @@ -115,109 +55,49 @@ "valid_results": 1 }, { - "duration_s": 0.3377689190674573, + "duration_s": 0.3335385399404913, "metrics": { "congestion_cache_hits": 0, "congestion_cache_misses": 0, - "congestion_candidate_ids": 0, - "congestion_candidate_nets": 0, - "congestion_candidate_precheck_hits": 0, - "congestion_candidate_precheck_misses": 0, - "congestion_candidate_precheck_skips": 0, "congestion_check_calls": 0, "congestion_exact_pair_checks": 0, - "congestion_grid_net_cache_hits": 0, - "congestion_grid_net_cache_misses": 0, - "congestion_grid_span_cache_hits": 0, - "congestion_grid_span_cache_misses": 0, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 0, - "congestion_net_envelope_cache_misses": 0, - "congestion_presence_cache_hits": 0, - "congestion_presence_cache_misses": 0, - "congestion_presence_skips": 0, - "danger_map_cache_hits": 0, - "danger_map_cache_misses": 0, - "danger_map_lookup_calls": 0, - "danger_map_query_calls": 0, - "danger_map_total_ns": 0, "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 49, - "dynamic_path_objects_removed": 34, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 0.0, - "guidance_bonus_applied_bend90": 0.0, - "guidance_bonus_applied_sbend": 0.0, - "guidance_bonus_applied_straight": 0.0, - "guidance_match_moves": 0, - "guidance_match_moves_bend90": 0, - "guidance_match_moves_sbend": 0, - "guidance_match_moves_straight": 0, + "dynamic_path_objects_added": 32, + "dynamic_path_objects_removed": 17, + "dynamic_tree_rebuilds": 8, "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 0, - "iteration_conflicting_nets": 0, - "iteration_reverified_nets": 3, - "iteration_reverify_calls": 1, "move_cache_abs_hits": 12, "move_cache_abs_misses": 1401, "move_cache_rel_hits": 1293, "move_cache_rel_misses": 108, "moves_added": 668, "moves_generated": 1413, - "nets_carried_forward": 0, "nets_reached_target": 3, "nets_routed": 3, "nodes_expanded": 366, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 14, "pruned_closed_set": 157, "pruned_cost": 208, "pruned_hard_collision": 380, - "ray_cast_calls": 1164, - "ray_cast_calls_expand_forward": 363, - "ray_cast_calls_expand_snap": 19, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 529, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 253, - "ray_cast_candidate_bounds": 913, + "ray_cast_calls": 1176, + "ray_cast_candidate_bounds": 925, "ray_cast_exact_geometry_checks": 136, "refine_path_calls": 3, - "refinement_candidate_side_extents": 26, - "refinement_candidates_accepted": 2, - "refinement_candidates_built": 26, - "refinement_candidates_verified": 26, - "refinement_dynamic_bounds_checked": 20, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 10, "route_iterations": 1, - "score_component_calls": 976, - "score_component_total_ns": 1140704, "static_net_tree_rebuilds": 3, "static_raw_tree_rebuilds": 0, "static_safe_cache_hits": 1, "static_tree_rebuilds": 2, "timeout_events": 0, - "verify_dynamic_candidate_nets": 88, - "verify_dynamic_exact_pair_checks": 86, - "verify_path_report_calls": 38, + "verify_dynamic_exact_pair_checks": 90, + "verify_path_report_calls": 35, "verify_static_buffer_ops": 0, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 3, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, + "visibility_builds": 4, + "visibility_corner_hits": 0, + "visibility_corner_pairs_checked": 12, + "visibility_corner_queries": 0, "visibility_point_cache_hits": 0, "visibility_point_cache_misses": 0, "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 873, - "visibility_tangent_candidate_ray_tests": 253, - "visibility_tangent_candidate_scans": 363, "warm_start_paths_built": 3, "warm_start_paths_used": 3 }, @@ -227,109 +107,49 @@ "valid_results": 3 }, { - "duration_s": 0.1929313091095537, + "duration_s": 0.1809853739105165, "metrics": { "congestion_cache_hits": 0, "congestion_cache_misses": 0, - "congestion_candidate_ids": 0, - "congestion_candidate_nets": 0, - "congestion_candidate_precheck_hits": 0, - "congestion_candidate_precheck_misses": 0, - "congestion_candidate_precheck_skips": 0, "congestion_check_calls": 0, "congestion_exact_pair_checks": 0, - "congestion_grid_net_cache_hits": 0, - "congestion_grid_net_cache_misses": 0, - "congestion_grid_span_cache_hits": 0, - "congestion_grid_span_cache_misses": 0, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 0, - "congestion_net_envelope_cache_misses": 0, - "congestion_presence_cache_hits": 0, - "congestion_presence_cache_misses": 0, - "congestion_presence_skips": 0, - "danger_map_cache_hits": 0, - "danger_map_cache_misses": 0, - "danger_map_lookup_calls": 0, - "danger_map_query_calls": 0, - "danger_map_total_ns": 0, "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 27, - "dynamic_path_objects_removed": 20, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 0.0, - "guidance_bonus_applied_bend90": 0.0, - "guidance_bonus_applied_sbend": 0.0, - "guidance_bonus_applied_straight": 0.0, - "guidance_match_moves": 0, - "guidance_match_moves_bend90": 0, - "guidance_match_moves_sbend": 0, - "guidance_match_moves_straight": 0, + "dynamic_path_objects_added": 17, + "dynamic_path_objects_removed": 10, + "dynamic_tree_rebuilds": 5, "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 0, - "iteration_conflicting_nets": 0, - "iteration_reverified_nets": 2, - "iteration_reverify_calls": 2, "move_cache_abs_hits": 1, "move_cache_abs_misses": 903, "move_cache_rel_hits": 821, "move_cache_rel_misses": 82, "moves_added": 307, "moves_generated": 904, - "nets_carried_forward": 0, "nets_reached_target": 2, "nets_routed": 2, "nodes_expanded": 191, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 9, "pruned_closed_set": 97, "pruned_cost": 140, "pruned_hard_collision": 181, - "ray_cast_calls": 657, - "ray_cast_calls_expand_forward": 189, - "ray_cast_calls_expand_snap": 8, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 407, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 53, - "ray_cast_candidate_bounds": 155, + "ray_cast_calls": 681, + "ray_cast_candidate_bounds": 179, "ray_cast_exact_geometry_checks": 0, "refine_path_calls": 2, - "refinement_candidate_side_extents": 8, - "refinement_candidates_accepted": 1, - "refinement_candidates_built": 8, - "refinement_candidates_verified": 8, - "refinement_dynamic_bounds_checked": 2, - "refinement_static_bounds_checked": 2, - "refinement_windows_considered": 2, "route_iterations": 2, - "score_component_calls": 504, - "score_component_total_ns": 565410, "static_net_tree_rebuilds": 2, "static_raw_tree_rebuilds": 1, "static_safe_cache_hits": 1, - "static_tree_rebuilds": 1, + "static_tree_rebuilds": 2, "timeout_events": 0, - "verify_dynamic_candidate_nets": 9, - "verify_dynamic_exact_pair_checks": 9, - "verify_path_report_calls": 16, - "verify_static_buffer_ops": 81, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 2, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, + "verify_dynamic_exact_pair_checks": 0, + "verify_path_report_calls": 14, + "verify_static_buffer_ops": 69, + "visibility_builds": 4, + "visibility_corner_hits": 0, + "visibility_corner_pairs_checked": 24, + "visibility_corner_queries": 0, "visibility_point_cache_hits": 0, "visibility_point_cache_misses": 0, "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 56, - "visibility_tangent_candidate_ray_tests": 53, - "visibility_tangent_candidate_scans": 189, "warm_start_paths_built": 2, "warm_start_paths_used": 2 }, @@ -339,109 +159,49 @@ "valid_results": 2 }, { - "duration_s": 0.02791503700427711, + "duration_s": 2.0151148419827223, "metrics": { "congestion_cache_hits": 0, "congestion_cache_misses": 0, - "congestion_candidate_ids": 0, - "congestion_candidate_nets": 0, - "congestion_candidate_precheck_hits": 0, - "congestion_candidate_precheck_misses": 0, - "congestion_candidate_precheck_skips": 0, "congestion_check_calls": 0, "congestion_exact_pair_checks": 0, - "congestion_grid_net_cache_hits": 0, - "congestion_grid_net_cache_misses": 0, - "congestion_grid_span_cache_hits": 0, - "congestion_grid_span_cache_misses": 0, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 0, - "congestion_net_envelope_cache_misses": 0, - "congestion_presence_cache_hits": 0, - "congestion_presence_cache_misses": 0, - "congestion_presence_skips": 0, - "danger_map_cache_hits": 0, - "danger_map_cache_misses": 0, - "danger_map_lookup_calls": 0, - "danger_map_query_calls": 0, - "danger_map_total_ns": 0, "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 21, - "dynamic_path_objects_removed": 14, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 0.0, - "guidance_bonus_applied_bend90": 0.0, - "guidance_bonus_applied_sbend": 0.0, - "guidance_bonus_applied_straight": 0.0, - "guidance_match_moves": 0, - "guidance_match_moves_bend90": 0, - "guidance_match_moves_sbend": 0, - "guidance_match_moves_straight": 0, + "dynamic_path_objects_added": 14, + "dynamic_path_objects_removed": 7, + "dynamic_tree_rebuilds": 4, "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 0, - "iteration_conflicting_nets": 0, - "iteration_reverified_nets": 2, - "iteration_reverify_calls": 1, "move_cache_abs_hits": 1, "move_cache_abs_misses": 122, "move_cache_rel_hits": 80, "move_cache_rel_misses": 42, "moves_added": 65, "moves_generated": 123, - "nets_carried_forward": 0, "nets_reached_target": 2, "nets_routed": 2, "nodes_expanded": 15, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 0, "pruned_closed_set": 2, "pruned_cost": 25, "pruned_hard_collision": 16, - "ray_cast_calls": 70, - "ray_cast_calls_expand_forward": 13, - "ray_cast_calls_expand_snap": 1, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 56, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 0, - "ray_cast_candidate_bounds": 4, - "ray_cast_exact_geometry_checks": 0, + "ray_cast_calls": 18218, + "ray_cast_candidate_bounds": 50717, + "ray_cast_exact_geometry_checks": 21265, "refine_path_calls": 2, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, "route_iterations": 1, - "score_component_calls": 90, - "score_component_total_ns": 100083, "static_net_tree_rebuilds": 2, "static_raw_tree_rebuilds": 0, "static_safe_cache_hits": 1, - "static_tree_rebuilds": 1, + "static_tree_rebuilds": 2, "timeout_events": 0, - "verify_dynamic_candidate_nets": 9, "verify_dynamic_exact_pair_checks": 0, - "verify_path_report_calls": 8, + "verify_path_report_calls": 6, "verify_static_buffer_ops": 0, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 2, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, + "visibility_builds": 3, + "visibility_corner_hits": 0, + "visibility_corner_pairs_checked": 18148, + "visibility_corner_queries": 0, "visibility_point_cache_hits": 0, "visibility_point_cache_misses": 0, "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 50, - "visibility_tangent_candidate_ray_tests": 0, - "visibility_tangent_candidate_scans": 13, "warm_start_paths_built": 2, "warm_start_paths_used": 2 }, @@ -451,109 +211,49 @@ "valid_results": 2 }, { - "duration_s": 0.23665715800598264, + "duration_s": 0.2437819039914757, "metrics": { - "congestion_cache_hits": 4, - "congestion_cache_misses": 149, - "congestion_candidate_ids": 32, - "congestion_candidate_nets": 23, - "congestion_candidate_precheck_hits": 131, - "congestion_candidate_precheck_misses": 22, - "congestion_candidate_precheck_skips": 0, - "congestion_check_calls": 149, - "congestion_exact_pair_checks": 30, - "congestion_grid_net_cache_hits": 16, - "congestion_grid_net_cache_misses": 28, - "congestion_grid_span_cache_hits": 15, - "congestion_grid_span_cache_misses": 7, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 128, - "congestion_net_envelope_cache_misses": 43, - "congestion_presence_cache_hits": 200, - "congestion_presence_cache_misses": 30, - "congestion_presence_skips": 77, - "danger_map_cache_hits": 0, - "danger_map_cache_misses": 0, - "danger_map_lookup_calls": 0, - "danger_map_query_calls": 0, - "danger_map_total_ns": 0, - "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 49, - "dynamic_path_objects_removed": 37, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 687.5, - "guidance_bonus_applied_bend90": 500.0, - "guidance_bonus_applied_sbend": 0.0, - "guidance_bonus_applied_straight": 187.5, - "guidance_match_moves": 11, - "guidance_match_moves_bend90": 8, - "guidance_match_moves_sbend": 0, - "guidance_match_moves_straight": 3, + "congestion_cache_hits": 2, + "congestion_cache_misses": 412, + "congestion_check_calls": 412, + "congestion_exact_pair_checks": 66, + "dynamic_grid_rebuilds": 3, + "dynamic_path_objects_added": 37, + "dynamic_path_objects_removed": 25, + "dynamic_tree_rebuilds": 12, "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 1, - "iteration_conflicting_nets": 2, - "iteration_reverified_nets": 6, - "iteration_reverify_calls": 2, - "move_cache_abs_hits": 385, - "move_cache_abs_misses": 1306, - "move_cache_rel_hits": 1204, + "move_cache_abs_hits": 253, + "move_cache_abs_misses": 1371, + "move_cache_rel_hits": 1269, "move_cache_rel_misses": 102, - "moves_added": 696, - "moves_generated": 1691, - "nets_carried_forward": 0, + "moves_added": 681, + "moves_generated": 1624, "nets_reached_target": 6, "nets_routed": 6, - "nodes_expanded": 299, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 2, - "pruned_closed_set": 159, - "pruned_cost": 537, + "nodes_expanded": 286, + "pruned_closed_set": 139, + "pruned_cost": 505, "pruned_hard_collision": 14, - "ray_cast_calls": 1284, - "ray_cast_calls_expand_forward": 293, - "ray_cast_calls_expand_snap": 3, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 979, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 9, + "ray_cast_calls": 1243, "ray_cast_candidate_bounds": 45, "ray_cast_exact_geometry_checks": 43, "refine_path_calls": 3, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, "route_iterations": 2, - "score_component_calls": 1245, - "score_component_total_ns": 1260961, "static_net_tree_rebuilds": 3, "static_raw_tree_rebuilds": 0, - "static_safe_cache_hits": 9, + "static_safe_cache_hits": 3, "static_tree_rebuilds": 1, "timeout_events": 0, - "verify_dynamic_candidate_nets": 8, - "verify_dynamic_exact_pair_checks": 12, - "verify_path_report_calls": 18, + "verify_dynamic_exact_pair_checks": 2, + "verify_path_report_calls": 12, "verify_static_buffer_ops": 0, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 3, + "visibility_builds": 3, + "visibility_corner_hits": 0, "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, + "visibility_corner_queries": 0, "visibility_point_cache_hits": 0, "visibility_point_cache_misses": 0, "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 70, - "visibility_tangent_candidate_ray_tests": 9, - "visibility_tangent_candidate_scans": 293, "warm_start_paths_built": 2, "warm_start_paths_used": 2 }, @@ -563,109 +263,49 @@ "valid_results": 3 }, { - "duration_s": 0.19982667709700763, + "duration_s": 4.163613382959738, "metrics": { "congestion_cache_hits": 0, "congestion_cache_misses": 0, - "congestion_candidate_ids": 0, - "congestion_candidate_nets": 0, - "congestion_candidate_precheck_hits": 0, - "congestion_candidate_precheck_misses": 0, - "congestion_candidate_precheck_skips": 0, "congestion_check_calls": 0, "congestion_exact_pair_checks": 0, - "congestion_grid_net_cache_hits": 0, - "congestion_grid_net_cache_misses": 0, - "congestion_grid_span_cache_hits": 0, - "congestion_grid_span_cache_misses": 0, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 0, - "congestion_net_envelope_cache_misses": 0, - "congestion_presence_cache_hits": 0, - "congestion_presence_cache_misses": 0, - "congestion_presence_skips": 0, - "danger_map_cache_hits": 1183, - "danger_map_cache_misses": 731, - "danger_map_lookup_calls": 1914, - "danger_map_query_calls": 731, - "danger_map_total_ns": 18959782, "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 54, - "dynamic_path_objects_removed": 36, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 0.0, - "guidance_bonus_applied_bend90": 0.0, - "guidance_bonus_applied_sbend": 0.0, - "guidance_bonus_applied_straight": 0.0, - "guidance_match_moves": 0, - "guidance_match_moves_bend90": 0, - "guidance_match_moves_sbend": 0, - "guidance_match_moves_straight": 0, + "dynamic_path_objects_added": 36, + "dynamic_path_objects_removed": 18, + "dynamic_tree_rebuilds": 6, "hard_collision_cache_hits": 18, - "iteration_conflict_edges": 0, - "iteration_conflicting_nets": 0, - "iteration_reverified_nets": 3, - "iteration_reverify_calls": 3, "move_cache_abs_hits": 186, "move_cache_abs_misses": 840, "move_cache_rel_hits": 702, "move_cache_rel_misses": 138, "moves_added": 629, "moves_generated": 1026, - "nets_carried_forward": 0, "nets_reached_target": 3, "nets_routed": 3, "nodes_expanded": 240, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 0, "pruned_closed_set": 108, "pruned_cost": 204, "pruned_hard_collision": 85, - "ray_cast_calls": 682, - "ray_cast_calls_expand_forward": 237, - "ray_cast_calls_expand_snap": 3, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 408, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 34, - "ray_cast_candidate_bounds": 97, - "ray_cast_exact_geometry_checks": 0, + "ray_cast_calls": 40530, + "ray_cast_candidate_bounds": 121732, + "ray_cast_exact_geometry_checks": 36858, "refine_path_calls": 3, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, "route_iterations": 3, - "score_component_calls": 842, - "score_component_total_ns": 21338709, "static_net_tree_rebuilds": 3, "static_raw_tree_rebuilds": 3, "static_safe_cache_hits": 141, - "static_tree_rebuilds": 3, + "static_tree_rebuilds": 6, "timeout_events": 0, - "verify_dynamic_candidate_nets": 0, "verify_dynamic_exact_pair_checks": 0, - "verify_path_report_calls": 12, - "verify_static_buffer_ops": 72, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 3, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, + "verify_path_report_calls": 9, + "verify_static_buffer_ops": 54, + "visibility_builds": 6, + "visibility_corner_hits": 0, + "visibility_corner_pairs_checked": 39848, + "visibility_corner_queries": 0, "visibility_point_cache_hits": 0, "visibility_point_cache_misses": 0, "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 84, - "visibility_tangent_candidate_ray_tests": 34, - "visibility_tangent_candidate_scans": 237, "warm_start_paths_built": 3, "warm_start_paths_used": 3 }, @@ -675,109 +315,49 @@ "valid_results": 3 }, { - "duration_s": 0.20046633295714855, + "duration_s": 1.375933071016334, "metrics": { "congestion_cache_hits": 0, "congestion_cache_misses": 0, - "congestion_candidate_ids": 0, - "congestion_candidate_nets": 0, - "congestion_candidate_precheck_hits": 0, - "congestion_candidate_precheck_misses": 0, - "congestion_candidate_precheck_skips": 0, "congestion_check_calls": 0, "congestion_exact_pair_checks": 0, - "congestion_grid_net_cache_hits": 0, - "congestion_grid_net_cache_misses": 0, - "congestion_grid_span_cache_hits": 0, - "congestion_grid_span_cache_misses": 0, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 0, - "congestion_net_envelope_cache_misses": 0, - "congestion_presence_cache_hits": 0, - "congestion_presence_cache_misses": 0, - "congestion_presence_skips": 0, - "danger_map_cache_hits": 233, - "danger_map_cache_misses": 448, - "danger_map_lookup_calls": 681, - "danger_map_query_calls": 448, - "danger_map_total_ns": 11017087, "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 132, - "dynamic_path_objects_removed": 88, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 0.0, - "guidance_bonus_applied_bend90": 0.0, - "guidance_bonus_applied_sbend": 0.0, - "guidance_bonus_applied_straight": 0.0, - "guidance_match_moves": 0, - "guidance_match_moves_bend90": 0, - "guidance_match_moves_sbend": 0, - "guidance_match_moves_straight": 0, + "dynamic_path_objects_added": 88, + "dynamic_path_objects_removed": 44, + "dynamic_tree_rebuilds": 20, "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 0, - "iteration_conflicting_nets": 0, - "iteration_reverified_nets": 10, - "iteration_reverify_calls": 1, "move_cache_abs_hits": 6, "move_cache_abs_misses": 366, "move_cache_rel_hits": 275, "move_cache_rel_misses": 91, "moves_added": 227, "moves_generated": 372, - "nets_carried_forward": 0, "nets_reached_target": 10, "nets_routed": 10, "nodes_expanded": 78, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 0, "pruned_closed_set": 20, "pruned_cost": 64, "pruned_hard_collision": 61, - "ray_cast_calls": 383, - "ray_cast_calls_expand_forward": 68, - "ray_cast_calls_expand_snap": 6, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 232, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 77, - "ray_cast_candidate_bounds": 683, - "ray_cast_exact_geometry_checks": 150, + "ray_cast_calls": 11151, + "ray_cast_candidate_bounds": 21198, + "ray_cast_exact_geometry_checks": 11651, "refine_path_calls": 10, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, "route_iterations": 1, - "score_component_calls": 291, - "score_component_total_ns": 11869917, "static_net_tree_rebuilds": 10, "static_raw_tree_rebuilds": 1, "static_safe_cache_hits": 6, "static_tree_rebuilds": 10, "timeout_events": 0, - "verify_dynamic_candidate_nets": 370, - "verify_dynamic_exact_pair_checks": 56, - "verify_path_report_calls": 40, - "verify_static_buffer_ops": 176, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 10, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, + "verify_dynamic_exact_pair_checks": 0, + "verify_path_report_calls": 30, + "verify_static_buffer_ops": 132, + "visibility_builds": 11, + "visibility_corner_hits": 0, + "visibility_corner_pairs_checked": 10768, + "visibility_corner_queries": 0, "visibility_point_cache_hits": 0, "visibility_point_cache_misses": 0, "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 321, - "visibility_tangent_candidate_ray_tests": 77, - "visibility_tangent_candidate_scans": 68, "warm_start_paths_built": 10, "warm_start_paths_used": 10 }, @@ -787,109 +367,49 @@ "valid_results": 10 }, { - "duration_s": 0.01759456400759518, + "duration_s": 0.2436628290452063, "metrics": { "congestion_cache_hits": 0, "congestion_cache_misses": 0, - "congestion_candidate_ids": 0, - "congestion_candidate_nets": 0, - "congestion_candidate_precheck_hits": 0, - "congestion_candidate_precheck_misses": 0, - "congestion_candidate_precheck_skips": 0, "congestion_check_calls": 0, "congestion_exact_pair_checks": 0, - "congestion_grid_net_cache_hits": 0, - "congestion_grid_net_cache_misses": 0, - "congestion_grid_span_cache_hits": 0, - "congestion_grid_span_cache_misses": 0, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 0, - "congestion_net_envelope_cache_misses": 0, - "congestion_presence_cache_hits": 0, - "congestion_presence_cache_misses": 0, - "congestion_presence_skips": 0, - "danger_map_cache_hits": 0, - "danger_map_cache_misses": 0, - "danger_map_lookup_calls": 0, - "danger_map_query_calls": 0, - "danger_map_total_ns": 0, "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 18, - "dynamic_path_objects_removed": 12, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 0.0, - "guidance_bonus_applied_bend90": 0.0, - "guidance_bonus_applied_sbend": 0.0, - "guidance_bonus_applied_straight": 0.0, - "guidance_match_moves": 0, - "guidance_match_moves_bend90": 0, - "guidance_match_moves_sbend": 0, - "guidance_match_moves_straight": 0, + "dynamic_path_objects_added": 12, + "dynamic_path_objects_removed": 6, + "dynamic_tree_rebuilds": 4, "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 0, - "iteration_conflicting_nets": 0, - "iteration_reverified_nets": 2, - "iteration_reverify_calls": 2, "move_cache_abs_hits": 2, "move_cache_abs_misses": 76, "move_cache_rel_hits": 32, "move_cache_rel_misses": 44, "moves_added": 56, "moves_generated": 78, - "nets_carried_forward": 0, "nets_reached_target": 2, "nets_routed": 2, "nodes_expanded": 18, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 0, "pruned_closed_set": 6, "pruned_cost": 16, "pruned_hard_collision": 0, - "ray_cast_calls": 56, - "ray_cast_calls_expand_forward": 16, - "ray_cast_calls_expand_snap": 2, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 38, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 0, - "ray_cast_candidate_bounds": 0, - "ray_cast_exact_geometry_checks": 0, + "ray_cast_calls": 2308, + "ray_cast_candidate_bounds": 3802, + "ray_cast_exact_geometry_checks": 1904, "refine_path_calls": 2, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, "route_iterations": 2, - "score_component_calls": 72, - "score_component_total_ns": 85864, "static_net_tree_rebuilds": 2, "static_raw_tree_rebuilds": 0, "static_safe_cache_hits": 2, - "static_tree_rebuilds": 0, + "static_tree_rebuilds": 2, "timeout_events": 0, - "verify_dynamic_candidate_nets": 0, "verify_dynamic_exact_pair_checks": 0, - "verify_path_report_calls": 8, + "verify_path_report_calls": 6, "verify_static_buffer_ops": 0, - "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 2, - "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, + "visibility_builds": 4, + "visibility_corner_hits": 0, + "visibility_corner_pairs_checked": 2252, + "visibility_corner_queries": 0, "visibility_point_cache_hits": 0, "visibility_point_cache_misses": 0, "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 0, - "visibility_tangent_candidate_ray_tests": 0, - "visibility_tangent_candidate_scans": 16, "warm_start_paths_built": 2, "warm_start_paths_used": 2 }, @@ -899,109 +419,49 @@ "valid_results": 2 }, { - "duration_s": 0.005838233977556229, + "duration_s": 0.0052433289820328355, "metrics": { "congestion_cache_hits": 0, "congestion_cache_misses": 0, - "congestion_candidate_ids": 0, - "congestion_candidate_nets": 0, - "congestion_candidate_precheck_hits": 0, - "congestion_candidate_precheck_misses": 0, - "congestion_candidate_precheck_skips": 0, "congestion_check_calls": 0, "congestion_exact_pair_checks": 0, - "congestion_grid_net_cache_hits": 0, - "congestion_grid_net_cache_misses": 0, - "congestion_grid_span_cache_hits": 0, - "congestion_grid_span_cache_misses": 0, - "congestion_lazy_requeues": 0, - "congestion_lazy_resolutions": 0, - "congestion_net_envelope_cache_hits": 0, - "congestion_net_envelope_cache_misses": 0, - "congestion_presence_cache_hits": 0, - "congestion_presence_cache_misses": 0, - "congestion_presence_skips": 0, - "danger_map_cache_hits": 10, - "danger_map_cache_misses": 20, - "danger_map_lookup_calls": 30, - "danger_map_query_calls": 20, - "danger_map_total_ns": 523870, "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 2, - "dynamic_path_objects_removed": 1, - "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 0.0, - "guidance_bonus_applied_bend90": 0.0, - "guidance_bonus_applied_sbend": 0.0, - "guidance_bonus_applied_straight": 0.0, - "guidance_match_moves": 0, - "guidance_match_moves_bend90": 0, - "guidance_match_moves_sbend": 0, - "guidance_match_moves_straight": 0, + "dynamic_path_objects_added": 1, + "dynamic_path_objects_removed": 0, + "dynamic_tree_rebuilds": 1, "hard_collision_cache_hits": 0, - "iteration_conflict_edges": 0, - "iteration_conflicting_nets": 0, - "iteration_reverified_nets": 0, - "iteration_reverify_calls": 1, "move_cache_abs_hits": 0, "move_cache_abs_misses": 16, "move_cache_rel_hits": 2, "move_cache_rel_misses": 14, "moves_added": 10, "moves_generated": 16, - "nets_carried_forward": 0, "nets_reached_target": 0, "nets_routed": 1, "nodes_expanded": 3, - "pair_local_search_accepts": 0, - "pair_local_search_attempts": 0, - "pair_local_search_nodes_expanded": 0, - "pair_local_search_pairs_considered": 0, - "path_cost_calls": 0, "pruned_closed_set": 0, "pruned_cost": 4, "pruned_hard_collision": 2, "ray_cast_calls": 13, - "ray_cast_calls_expand_forward": 3, - "ray_cast_calls_expand_snap": 0, - "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 10, - "ray_cast_calls_visibility_build": 0, - "ray_cast_calls_visibility_query": 0, - "ray_cast_calls_visibility_tangent": 0, "ray_cast_candidate_bounds": 5, "ray_cast_exact_geometry_checks": 0, "refine_path_calls": 0, - "refinement_candidate_side_extents": 0, - "refinement_candidates_accepted": 0, - "refinement_candidates_built": 0, - "refinement_candidates_verified": 0, - "refinement_dynamic_bounds_checked": 0, - "refinement_static_bounds_checked": 0, - "refinement_windows_considered": 0, "route_iterations": 1, - "score_component_calls": 14, - "score_component_total_ns": 563611, "static_net_tree_rebuilds": 1, "static_raw_tree_rebuilds": 1, "static_safe_cache_hits": 0, - "static_tree_rebuilds": 1, + "static_tree_rebuilds": 0, "timeout_events": 0, - "verify_dynamic_candidate_nets": 0, "verify_dynamic_exact_pair_checks": 0, "verify_path_report_calls": 1, "verify_static_buffer_ops": 1, "visibility_builds": 0, - "visibility_corner_hits_exact": 0, - "visibility_corner_index_builds": 1, + "visibility_corner_hits": 0, "visibility_corner_pairs_checked": 0, - "visibility_corner_queries_exact": 0, + "visibility_corner_queries": 0, "visibility_point_cache_hits": 0, "visibility_point_cache_misses": 0, "visibility_point_queries": 0, - "visibility_tangent_candidate_corner_checks": 0, - "visibility_tangent_candidate_ray_tests": 0, - "visibility_tangent_candidate_scans": 3, "warm_start_paths_built": 0, "warm_start_paths_used": 0 }, diff --git a/inire/__init__.py b/inire/__init__.py index 9c63046..f6ee2d5 100644 --- a/inire/__init__.py +++ b/inire/__init__.py @@ -14,15 +14,7 @@ from .model import ( RoutingProblem as RoutingProblem, SearchOptions as SearchOptions, ) # noqa: PLC0414 -from .results import ( # noqa: PLC0414 - ComponentConflictTrace as ComponentConflictTrace, - ConflictTraceEntry as ConflictTraceEntry, - FrontierPruneSample as FrontierPruneSample, - NetConflictTrace as NetConflictTrace, - NetFrontierTrace as NetFrontierTrace, - RoutingResult as RoutingResult, - RoutingRunResult as RoutingRunResult, -) +from .results import RoutingResult as RoutingResult, RoutingRunResult as RoutingRunResult # noqa: PLC0414 from .seeds import Bend90Seed as Bend90Seed, PathSeed as PathSeed, SBendSeed as SBendSeed, StraightSeed as StraightSeed # noqa: PLC0414 __author__ = 'Jan Petykiewicz' @@ -45,23 +37,16 @@ def route( results_by_net=results, metrics=finder.metrics.snapshot(), expanded_nodes=tuple(finder.accumulated_expanded_nodes), - conflict_trace=tuple(finder.conflict_trace), - frontier_trace=tuple(finder.frontier_trace), ) __all__ = [ "Bend90Seed", "CongestionOptions", - "ComponentConflictTrace", - "ConflictTraceEntry", "DiagnosticsOptions", "NetSpec", - "NetConflictTrace", - "NetFrontierTrace", "ObjectiveWeights", "PathSeed", "Port", - "FrontierPruneSample", "RefinementOptions", "RoutingOptions", "RoutingProblem", diff --git a/inire/geometry/collision.py b/inire/geometry/collision.py index 60b008a..acc7398 100644 --- a/inire/geometry/collision.py +++ b/inire/geometry/collision.py @@ -1,6 +1,5 @@ from __future__ import annotations -from dataclasses import dataclass from typing import TYPE_CHECKING import numpy @@ -29,50 +28,6 @@ def _intersection_distance(origin: Port, geometry: BaseGeometry) -> float: return float(numpy.sqrt((geometry.coords[0][0] - origin.x) ** 2 + (geometry.coords[0][1] - origin.y) ** 2)) -def _bounds_overlap( - left: tuple[float, float, float, float], - right: tuple[float, float, float, float], -) -> bool: - return ( - left[0] < right[2] - and left[2] > right[0] - and left[1] < right[3] - and left[3] > right[1] - ) - - -def _has_non_touching_overlap(left: BaseGeometry, right: BaseGeometry) -> bool: - return left.intersects(right) and not left.touches(right) - - -def _span_to_bounds( - gx_min: int, - gy_min: int, - gx_max: int, - gy_max: int, - cell_size: float, -) -> tuple[float, float, float, float]: - return ( - gx_min * cell_size, - gy_min * cell_size, - (gx_max + 1) * cell_size, - (gy_max + 1) * cell_size, - ) - - -@dataclass(frozen=True, slots=True) -class PathVerificationDetail: - report: RoutingReport - conflicting_net_ids: tuple[str, ...] = () - component_conflicts: tuple[tuple[int, str, int], ...] = () - - -@dataclass(frozen=True, slots=True) -class DynamicCongestionDetail: - soft_overlap_count: int = 0 - hits_frozen_net: bool = False - - class RoutingWorld: """ Internal spatial state for collision detection, congestion, and verification. @@ -141,34 +96,14 @@ class RoutingWorld: def _ensure_dynamic_grid(self) -> None: self._dynamic_paths.ensure_grid() - def add_path( - self, - net_id: str, - geometry: Sequence[Polygon], - dilated_geometry: Sequence[Polygon], - component_indexes: Sequence[int] | None = None, - ) -> None: - self._dynamic_paths.add_path( - net_id, - geometry, - dilated_geometry=dilated_geometry, - component_indexes=component_indexes, - ) + def add_path(self, net_id: str, geometry: Sequence[Polygon], dilated_geometry: Sequence[Polygon]) -> None: + self._dynamic_paths.add_path(net_id, geometry, dilated_geometry=dilated_geometry) def remove_path(self, net_id: str) -> None: self._dynamic_paths.remove_path(net_id) - def has_dynamic_paths(self) -> bool: - return bool(self._dynamic_paths.geometries) - def check_move_straight_static(self, start_port: Port, length: float, net_width: float) -> bool: - reach = self.ray_cast( - start_port, - start_port.r, - max_dist=length + 0.01, - net_width=net_width, - caller="straight_static", - ) + reach = self.ray_cast(start_port, start_port.r, max_dist=length + 0.01, net_width=net_width) return reach < length - 0.001 def _is_in_safety_zone_fast(self, idx: int, start_port: Port | None, end_port: Port | None) -> bool: @@ -294,390 +229,105 @@ class RoutingWorld: return False - def _check_real_congestion( - self, - result: ComponentResult, - candidates_by_net: dict[str, dict[int, tuple[int, ...]]], - frozen_net_ids: frozenset[str] = frozenset(), - ) -> DynamicCongestionDetail: - if not candidates_by_net: - return DynamicCongestionDetail() - + def _check_real_congestion(self, result: ComponentResult, net_id: str) -> int: dynamic_paths = self._dynamic_paths - geometries_to_test = result.dilated_collision_geometry + self._ensure_dynamic_tree() + if dynamic_paths.tree is None: + return 0 - real_hits_count = 0 - for other_net_id, other_obj_ids in candidates_by_net.items(): - found_real = False - for obj_id, test_geometry_indexes in other_obj_ids.items(): - tree_geometry = dynamic_paths.dilated[obj_id] - for test_geometry_index in test_geometry_indexes: - test_geometry = geometries_to_test[test_geometry_index] - if self.metrics is not None: - self.metrics.total_congestion_exact_pair_checks += 1 - if _has_non_touching_overlap(test_geometry, tree_geometry): - found_real = True - break - if found_real: - break - if found_real: - if other_net_id in frozen_net_ids: - return DynamicCongestionDetail( - soft_overlap_count=real_hits_count, - hits_frozen_net=True, - ) - real_hits_count += 1 - - return DynamicCongestionDetail(soft_overlap_count=real_hits_count) - - def _collect_congestion_candidates( - self, - result: ComponentResult, - net_id: str, - net_envelope_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]] | None = None, - grid_net_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]] | None = None, - broad_phase_cache: dict[tuple[str, int, int, int, int], dict[str, tuple[int, ...]]] | None = None, - ) -> dict[str, dict[int, tuple[int, ...]]]: - dynamic_paths = self._dynamic_paths - if not dynamic_paths.dilated: - return {} - - self._ensure_dynamic_grid() - if not dynamic_paths.grid: - return {} - - candidates_by_net: dict[str, dict[int, set[int]]] = {} - for test_geometry_index, test_bounds in enumerate(result.dilated_bounds): - if not self._has_possible_congestion_in_grid(test_bounds, net_id): - continue - envelope_net_ids = self._get_net_envelope_candidates( - test_bounds, - net_id, - net_envelope_cache, - ) - if not envelope_net_ids: - continue - grid_net_ids = self._get_grid_span_net_candidates( - test_bounds, - net_id, - grid_net_cache, - ) - if not grid_net_ids: - continue - candidate_net_ids = tuple(sorted(set(envelope_net_ids) & set(grid_net_ids))) - if not candidate_net_ids: - continue - grid_candidates = self._get_grid_span_candidates( - test_bounds, - net_id, - broad_phase_cache, - ) - for other_net_id in candidate_net_ids: - if self.metrics is not None: - self.metrics.total_congestion_candidate_nets += 1 - obj_ids = grid_candidates.get(other_net_id) - if not obj_ids: - continue - for obj_id in obj_ids: - if not _bounds_overlap(test_bounds, dynamic_paths.dilated_bounds[obj_id]): - continue - if self.metrics is not None: - self.metrics.total_congestion_candidate_ids += 1 - candidate_indexes = candidates_by_net.setdefault(other_net_id, {}).setdefault(obj_id, set()) - candidate_indexes.add(test_geometry_index) - - return { - other_net_id: { - obj_id: tuple(sorted(test_geometry_indexes)) - for obj_id, test_geometry_indexes in sorted(obj_ids.items()) - } - for other_net_id, obj_ids in candidates_by_net.items() - } - - def _has_possible_congestion_in_grid( - self, - bounds: tuple[float, float, float, float], - net_id: str, - ) -> bool: - gx_min, gy_min, gx_max, gy_max = grid_cell_span(bounds, self.grid_cell_size) - dynamic_paths = self._dynamic_paths - - if gx_min == gx_max and gy_min == gy_max: - net_counts = dynamic_paths.grid_net_counts.get((gx_min, gy_min)) - return bool(net_counts and (len(net_counts) > 1 or net_id not in net_counts)) - - for gx in range(gx_min, gx_max + 1): - for gy in range(gy_min, gy_max + 1): - net_counts = dynamic_paths.grid_net_counts.get((gx, gy)) - if net_counts and (len(net_counts) > 1 or net_id not in net_counts): - return True - return False - - def has_possible_move_congestion( - self, - result: ComponentResult, - net_id: str, - presence_cache: dict[tuple[str, int, int, int, int], bool] | None = None, - ) -> bool: - dynamic_paths = self._dynamic_paths - if not dynamic_paths.dilated: - return False - - self._ensure_dynamic_grid() - if not dynamic_paths.grid: - return False - - for bounds in result.dilated_bounds: - gx_min, gy_min, gx_max, gy_max = grid_cell_span(bounds, self.grid_cell_size) - cache_key = (net_id, gx_min, gy_min, gx_max, gy_max) - if presence_cache is not None and cache_key in presence_cache: - if self.metrics is not None: - self.metrics.total_congestion_presence_cache_hits += 1 - has_possible = presence_cache[cache_key] - else: - if self.metrics is not None: - self.metrics.total_congestion_presence_cache_misses += 1 - has_possible = self._has_possible_congestion_in_grid(bounds, net_id) - if presence_cache is not None: - presence_cache[cache_key] = has_possible - if has_possible: - return True - return False - - def has_candidate_move_congestion( - self, - result: ComponentResult, - net_id: str, - candidate_precheck_cache: dict[tuple[str, int, int, int, int], bool] | None = None, - net_envelope_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]] | None = None, - grid_net_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]] | None = None, - ) -> bool: - dynamic_paths = self._dynamic_paths - if not dynamic_paths.dilated: - return False - - for bounds in result.dilated_bounds: - gx_min, gy_min, gx_max, gy_max = grid_cell_span(bounds, self.grid_cell_size) - cache_key = (net_id, gx_min, gy_min, gx_max, gy_max) - if candidate_precheck_cache is not None and cache_key in candidate_precheck_cache: - if self.metrics is not None: - self.metrics.total_congestion_candidate_precheck_hits += 1 - has_candidates = candidate_precheck_cache[cache_key] - else: - if self.metrics is not None: - self.metrics.total_congestion_candidate_precheck_misses += 1 - span_bounds = _span_to_bounds(gx_min, gy_min, gx_max, gy_max, self.grid_cell_size) - envelope_net_ids = self._get_net_envelope_candidates( - span_bounds, - net_id, - net_envelope_cache, - ) - if not envelope_net_ids: - has_candidates = False - else: - grid_net_ids = self._get_grid_span_net_candidates( - span_bounds, - net_id, - grid_net_cache, - ) - if not grid_net_ids: - has_candidates = False - else: - has_candidates = bool(set(envelope_net_ids) & set(grid_net_ids)) - if candidate_precheck_cache is not None: - candidate_precheck_cache[cache_key] = has_candidates - if has_candidates: - return True - return False - - def _get_grid_span_candidates( - self, - bounds: tuple[float, float, float, float], - net_id: str, - broad_phase_cache: dict[tuple[str, int, int, int, int], dict[str, tuple[int, ...]]] | None, - ) -> dict[str, tuple[int, ...]]: - gx_min, gy_min, gx_max, gy_max = grid_cell_span(bounds, self.grid_cell_size) - cache_key = (net_id, gx_min, gy_min, gx_max, gy_max) - if broad_phase_cache is not None and cache_key in broad_phase_cache: - if self.metrics is not None: - self.metrics.total_congestion_grid_span_cache_hits += 1 - return broad_phase_cache[cache_key] - - if self.metrics is not None: - self.metrics.total_congestion_grid_span_cache_misses += 1 - - dynamic_paths = self._dynamic_paths - candidates_by_net: dict[str, set[int]] = {} - for gx in range(gx_min, gx_max + 1): - for gy in range(gy_min, gy_max + 1): - for other_net_id, obj_ids in dynamic_paths.grid_net_obj_ids.get((gx, gy), {}).items(): - if other_net_id == net_id: - continue - candidates_by_net.setdefault(other_net_id, set()).update(obj_ids) - - frozen = { - other_net_id: tuple(sorted(obj_ids)) - for other_net_id, obj_ids in sorted(candidates_by_net.items()) - } - if broad_phase_cache is not None: - broad_phase_cache[cache_key] = frozen - return frozen - - def _get_grid_span_net_candidates( - self, - bounds: tuple[float, float, float, float], - net_id: str, - grid_net_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]] | None, - ) -> tuple[str, ...]: - gx_min, gy_min, gx_max, gy_max = grid_cell_span(bounds, self.grid_cell_size) - cache_key = (net_id, gx_min, gy_min, gx_max, gy_max) - if grid_net_cache is not None and cache_key in grid_net_cache: - if self.metrics is not None: - self.metrics.total_congestion_grid_net_cache_hits += 1 - return grid_net_cache[cache_key] - - if self.metrics is not None: - self.metrics.total_congestion_grid_net_cache_misses += 1 - - dynamic_paths = self._dynamic_paths - candidate_net_ids: set[str] = set() - for gx in range(gx_min, gx_max + 1): - for gy in range(gy_min, gy_max + 1): - for other_net_id in dynamic_paths.grid_net_obj_ids.get((gx, gy), {}): - if other_net_id != net_id: - candidate_net_ids.add(other_net_id) - - frozen = tuple(sorted(candidate_net_ids)) - if grid_net_cache is not None: - grid_net_cache[cache_key] = frozen - return frozen - - def _get_net_envelope_candidates( - self, - bounds: tuple[float, float, float, float], - net_id: str, - net_envelope_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]] | None, - ) -> tuple[str, ...]: - dynamic_paths = self._dynamic_paths - gx_min, gy_min, gx_max, gy_max = grid_cell_span(bounds, self.grid_cell_size) - cache_key = (net_id, gx_min, gy_min, gx_max, gy_max) - if net_envelope_cache is not None and cache_key in net_envelope_cache: - if self.metrics is not None: - self.metrics.total_congestion_net_envelope_cache_hits += 1 - cached_net_ids = net_envelope_cache[cache_key] - else: - if self.metrics is not None: - self.metrics.total_congestion_net_envelope_cache_misses += 1 - span_bounds = _span_to_bounds(gx_min, gy_min, gx_max, gy_max, self.grid_cell_size) - cached_net_ids = tuple( - sorted( - dynamic_paths.net_envelope_obj_to_net[obj_id] - for obj_id in dynamic_paths.net_envelope_index.intersection(span_bounds) - if dynamic_paths.net_envelope_obj_to_net[obj_id] != net_id - ) - ) - if net_envelope_cache is not None: - net_envelope_cache[cache_key] = cached_net_ids - - return tuple( - other_net_id - for other_net_id in cached_net_ids - if _bounds_overlap(bounds, dynamic_paths.net_envelopes[other_net_id]) + total_bounds = result.total_dilated_bounds + dynamic_bounds = dynamic_paths.bounds_array + possible_total = ( + (total_bounds[0] < dynamic_bounds[:, 2]) + & (total_bounds[2] > dynamic_bounds[:, 0]) + & (total_bounds[1] < dynamic_bounds[:, 3]) + & (total_bounds[3] > dynamic_bounds[:, 1]) ) - def _get_verify_net_envelope_candidates( - self, - bounds: tuple[float, float, float, float], - net_id: str, - ) -> tuple[str, ...]: - dynamic_paths = self._dynamic_paths - candidate_net_ids: list[str] = [] - for obj_id in dynamic_paths.net_envelope_index.intersection(bounds): - other_net_id = dynamic_paths.net_envelope_obj_to_net[obj_id] - if other_net_id == net_id: - continue - if not _bounds_overlap(bounds, dynamic_paths.net_envelopes[other_net_id]): - continue - candidate_net_ids.append(other_net_id) - if self.metrics is not None: - self.metrics.total_verify_dynamic_candidate_nets += len(candidate_net_ids) - return tuple(candidate_net_ids) + valid_hits_mask = dynamic_paths.net_ids_array != net_id + if not numpy.any(possible_total & valid_hits_mask): + return 0 - def _get_verify_grid_span_obj_ids( - self, - bounds: tuple[float, float, float, float], - other_net_id: str, - ) -> tuple[int, ...]: - dynamic_paths = self._dynamic_paths - gx_min, gy_min, gx_max, gy_max = grid_cell_span(bounds, self.grid_cell_size) - obj_ids: set[int] = set() - for gx in range(gx_min, gx_max + 1): - for gy in range(gy_min, gy_max + 1): - obj_ids.update(dynamic_paths.grid_net_obj_ids.get((gx, gy), {}).get(other_net_id, ())) - return tuple(sorted(obj_ids)) + geometries_to_test = result.dilated_collision_geometry + res_indices, tree_indices = dynamic_paths.tree.query(geometries_to_test, predicate="intersects") + if tree_indices.size == 0: + return 0 - def check_move_congestion( - self, - result: ComponentResult, - net_id: str, - net_envelope_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]] | None = None, - grid_net_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]] | None = None, - broad_phase_cache: dict[tuple[str, int, int, int, int], dict[str, tuple[int, ...]]] | None = None, - ) -> int: - return self.check_move_congestion_detail( - result, - net_id, - net_envelope_cache=net_envelope_cache, - grid_net_cache=grid_net_cache, - broad_phase_cache=broad_phase_cache, - ).soft_overlap_count + hit_net_ids = numpy.take(dynamic_paths.net_ids_array, tree_indices) + unique_other_nets = numpy.unique(hit_net_ids[hit_net_ids != net_id]) + if unique_other_nets.size == 0: + return 0 - def check_move_congestion_detail( - self, - result: ComponentResult, - net_id: str, - *, - frozen_net_ids: frozenset[str] = frozenset(), - net_envelope_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]] | None = None, - grid_net_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]] | None = None, - broad_phase_cache: dict[tuple[str, int, int, int, int], dict[str, tuple[int, ...]]] | None = None, - ) -> DynamicCongestionDetail: + tree_geometries = dynamic_paths.tree.geometries + real_hits_count = 0 + for other_net_id in unique_other_nets: + other_mask = hit_net_ids == other_net_id + sub_tree_indices = tree_indices[other_mask] + sub_res_indices = res_indices[other_mask] + + found_real = False + for index in range(len(sub_tree_indices)): + if self.metrics is not None: + self.metrics.total_congestion_exact_pair_checks += 1 + test_geometry = geometries_to_test[sub_res_indices[index]] + tree_geometry = tree_geometries[sub_tree_indices[index]] + if not test_geometry.touches(tree_geometry) and test_geometry.intersection(tree_geometry).area > 1e-7: + found_real = True + break + + if found_real: + real_hits_count += 1 + + return real_hits_count + + def check_move_congestion(self, result: ComponentResult, net_id: str) -> int: if self.metrics is not None: self.metrics.total_congestion_check_calls += 1 dynamic_paths = self._dynamic_paths if not dynamic_paths.geometries: - return DynamicCongestionDetail() + return 0 - candidates_by_net = self._collect_congestion_candidates( - result, - net_id, - net_envelope_cache, - grid_net_cache, - broad_phase_cache, - ) - if not candidates_by_net: - return DynamicCongestionDetail() - return self._check_real_congestion( - result, - candidates_by_net, - frozen_net_ids=frozen_net_ids, - ) + total_bounds = result.total_dilated_bounds + self._ensure_dynamic_grid() + dynamic_grid = dynamic_paths.grid + if not dynamic_grid: + return 0 - def verify_path_details( - self, - net_id: str, - components: Sequence[ComponentResult], - *, - capture_component_conflicts: bool = False, - ) -> PathVerificationDetail: + gx_min, gy_min, gx_max, gy_max = grid_cell_span(total_bounds, self.grid_cell_size) + + if gx_min == gx_max and gy_min == gy_max: + cell = (gx_min, gy_min) + if cell in dynamic_grid: + for obj_id in dynamic_grid[cell]: + if dynamic_paths.geometries[obj_id][0] != net_id: + return self._check_real_congestion(result, net_id) + return 0 + + any_possible = False + for gx in range(gx_min, gx_max + 1): + for gy in range(gy_min, gy_max + 1): + cell = (gx, gy) + if cell in dynamic_grid: + for obj_id in dynamic_grid[cell]: + if dynamic_paths.geometries[obj_id][0] != net_id: + any_possible = True + break + if any_possible: + break + if any_possible: + break + + if not any_possible: + return 0 + return self._check_real_congestion(result, net_id) + + def verify_path_report(self, net_id: str, components: Sequence[ComponentResult]) -> RoutingReport: if self.metrics is not None: self.metrics.total_verify_path_report_calls += 1 static_collision_count = 0 dynamic_collision_count = 0 self_collision_count = 0 total_length = sum(component.length for component in components) - conflicting_net_ids: set[str] = set() - component_conflicts: set[tuple[int, str, int]] = set() static_obstacles = self._static_obstacles dynamic_paths = self._dynamic_paths @@ -700,78 +350,52 @@ class RoutingWorld: if not self._is_in_safety_zone(polygon, obj_id, None, None): static_collision_count += 1 - if dynamic_paths.dilated: - for component_index, component in enumerate(components): + self._ensure_dynamic_tree() + if dynamic_paths.tree is not None: + tree_geometries = dynamic_paths.tree.geometries + for component in components: test_geometries = component.dilated_physical_geometry + res_indices, tree_indices = dynamic_paths.tree.query(test_geometries, predicate="intersects") + if tree_indices.size == 0: + continue + + hit_net_ids = numpy.take(dynamic_paths.net_ids_array, tree_indices) component_hits = [] - for new_geometry in test_geometries: - for hit_net_id in self._get_verify_net_envelope_candidates(new_geometry.bounds, str(net_id)): - for obj_id in self._get_verify_grid_span_obj_ids(new_geometry.bounds, hit_net_id): - if not _bounds_overlap(new_geometry.bounds, dynamic_paths.dilated_bounds[obj_id]): - continue - if self.metrics is not None: - self.metrics.total_verify_dynamic_exact_pair_checks += 1 - tree_geometry = dynamic_paths.dilated[obj_id] - if _has_non_touching_overlap(new_geometry, tree_geometry): - component_hits.append(hit_net_id) - if capture_component_conflicts: - component_conflicts.add( - ( - component_index, - hit_net_id, - dynamic_paths.component_indexes[obj_id], - ) - ) - break + for index in range(len(tree_indices)): + if hit_net_ids[index] == str(net_id): + continue + + if self.metrics is not None: + self.metrics.total_verify_dynamic_exact_pair_checks += 1 + new_geometry = test_geometries[res_indices[index]] + tree_geometry = tree_geometries[tree_indices[index]] + if not new_geometry.touches(tree_geometry) and new_geometry.intersection(tree_geometry).area > 1e-7: + component_hits.append(hit_net_ids[index]) if component_hits: - unique_hits = tuple(sorted(set(component_hits))) - dynamic_collision_count += len(unique_hits) - conflicting_net_ids.update(unique_hits) + dynamic_collision_count += len(numpy.unique(component_hits)) for index, component in enumerate(components): for other_index in range(index + 2, len(components)): if components_overlap(component, components[other_index], prefer_actual=True): self_collision_count += 1 - return PathVerificationDetail( - report=RoutingReport( - static_collision_count=static_collision_count, - dynamic_collision_count=dynamic_collision_count, - self_collision_count=self_collision_count, - total_length=total_length, - ), - conflicting_net_ids=tuple(sorted(conflicting_net_ids)), - component_conflicts=tuple(sorted(component_conflicts)), + return RoutingReport( + static_collision_count=static_collision_count, + dynamic_collision_count=dynamic_collision_count, + self_collision_count=self_collision_count, + total_length=total_length, ) - def verify_path_report(self, net_id: str, components: Sequence[ComponentResult]) -> RoutingReport: - return self.verify_path_details(net_id, components).report - def ray_cast( self, origin: Port, angle_deg: float, max_dist: float = 2000.0, net_width: float | None = None, - caller: str = "other", ) -> float: if self.metrics is not None: self.metrics.total_ray_cast_calls += 1 - if caller == "straight_static": - self.metrics.total_ray_cast_calls_straight_static += 1 - elif caller == "expand_snap": - self.metrics.total_ray_cast_calls_expand_snap += 1 - elif caller == "expand_forward": - self.metrics.total_ray_cast_calls_expand_forward += 1 - elif caller == "visibility_build": - self.metrics.total_ray_cast_calls_visibility_build += 1 - elif caller == "visibility_query": - self.metrics.total_ray_cast_calls_visibility_query += 1 - elif caller == "visibility_tangent": - self.metrics.total_ray_cast_calls_visibility_tangent += 1 - else: - self.metrics.total_ray_cast_calls_other += 1 static_obstacles = self._static_obstacles tree: STRtree | None is_rect_array: numpy.ndarray | None diff --git a/inire/geometry/dynamic_path_index.py b/inire/geometry/dynamic_path_index.py index 70d4b9f..0985f53 100644 --- a/inire/geometry/dynamic_path_index.py +++ b/inire/geometry/dynamic_path_index.py @@ -21,20 +21,10 @@ class DynamicPathIndex: "engine", "index", "geometries", - "component_indexes", "dilated", - "dilated_bounds", - "net_envelope_index", - "net_envelopes", - "net_envelope_obj_ids", - "net_envelope_obj_to_net", "tree", "obj_ids", "grid", - "grid_net_obj_ids", - "grid_net_counts", - "obj_cells", - "net_to_obj_ids", "id_counter", "net_ids_array", "bounds_array", @@ -44,71 +34,17 @@ class DynamicPathIndex: self.engine = engine self.index = rtree.index.Index() self.geometries: dict[int, tuple[str, Polygon]] = {} - self.component_indexes: dict[int, int] = {} self.dilated: dict[int, Polygon] = {} - self.dilated_bounds: dict[int, tuple[float, float, float, float]] = {} - self.net_envelope_index = rtree.index.Index() - self.net_envelopes: dict[str, tuple[float, float, float, float]] = {} - self.net_envelope_obj_ids: dict[str, int] = {} - self.net_envelope_obj_to_net: dict[int, str] = {} self.tree: STRtree | None = None self.obj_ids: numpy.ndarray = numpy.array([], dtype=numpy.int32) self.grid: dict[tuple[int, int], list[int]] = {} - self.grid_net_obj_ids: dict[tuple[int, int], dict[str, set[int]]] = {} - self.grid_net_counts: dict[tuple[int, int], dict[str, int]] = {} - self.obj_cells: dict[int, tuple[tuple[int, int], ...]] = {} - self.net_to_obj_ids: dict[str, set[int]] = {} self.id_counter = 0 self.net_ids_array = numpy.array([], dtype=object) self.bounds_array = numpy.array([], dtype=numpy.float64).reshape(0, 4) - def _combine_net_bounds(self, obj_ids: set[int]) -> tuple[float, float, float, float]: - first_obj_id = next(iter(obj_ids)) - minx, miny, maxx, maxy = self.dilated_bounds[first_obj_id] - for obj_id in obj_ids: - bounds = self.dilated_bounds[obj_id] - minx = min(minx, bounds[0]) - miny = min(miny, bounds[1]) - maxx = max(maxx, bounds[2]) - maxy = max(maxy, bounds[3]) - return (minx, miny, maxx, maxy) - - def _set_net_envelope(self, net_id: str, bounds: tuple[float, float, float, float]) -> None: - old_bounds = self.net_envelopes.get(net_id) - if old_bounds is not None: - obj_id = self.net_envelope_obj_ids[net_id] - self.net_envelope_index.delete(obj_id, old_bounds) - else: - obj_id = len(self.net_envelope_obj_ids) - while obj_id in self.net_envelope_obj_to_net: - obj_id += 1 - self.net_envelope_obj_ids[net_id] = obj_id - self.net_envelope_obj_to_net[obj_id] = net_id - - self.net_envelopes[net_id] = bounds - self.net_envelope_index.insert(self.net_envelope_obj_ids[net_id], bounds) - - def _clear_net_envelope(self, net_id: str) -> None: - old_bounds = self.net_envelopes.pop(net_id, None) - obj_id = self.net_envelope_obj_ids.pop(net_id, None) - if old_bounds is None or obj_id is None: - return - self.net_envelope_index.delete(obj_id, old_bounds) - self.net_envelope_obj_to_net.pop(obj_id, None) - - def _refresh_net_envelope(self, net_id: str) -> None: - obj_ids = self.net_to_obj_ids.get(net_id) - if not obj_ids: - self._clear_net_envelope(net_id) - return - self._set_net_envelope(net_id, self._combine_net_bounds(obj_ids)) - def invalidate_queries(self) -> None: self.tree = None self.grid = {} - self.grid_net_obj_ids = {} - self.grid_net_counts = {} - self.obj_cells = {} def ensure_tree(self) -> None: if self.tree is None and self.dilated: @@ -129,105 +65,33 @@ class DynamicPathIndex: self.engine.metrics.total_dynamic_grid_rebuilds += 1 cell_size = self.engine.grid_cell_size for obj_id, polygon in self.dilated.items(): - self._register_grid_membership(obj_id, self.geometries[obj_id][0], polygon.bounds, cell_size=cell_size) + for cell in iter_grid_cells(polygon.bounds, cell_size): + self.grid.setdefault(cell, []).append(obj_id) - def _register_grid_membership( - self, - obj_id: int, - net_id: str, - bounds: tuple[float, float, float, float], - *, - cell_size: float, - ) -> None: - cells = tuple(iter_grid_cells(bounds, cell_size)) - self.obj_cells[obj_id] = cells - for cell in cells: - self.grid.setdefault(cell, []).append(obj_id) - net_obj_ids = self.grid_net_obj_ids.setdefault(cell, {}) - net_obj_ids.setdefault(net_id, set()).add(obj_id) - net_counts = self.grid_net_counts.setdefault(cell, {}) - net_counts[net_id] = net_counts.get(net_id, 0) + 1 - - def _unregister_grid_membership(self, obj_id: int, net_id: str) -> None: - cells = self.obj_cells.pop(obj_id, ()) - for cell in cells: - obj_ids = self.grid.get(cell) - if obj_ids is not None: - try: - obj_ids.remove(obj_id) - except ValueError: - pass - if not obj_ids: - self.grid.pop(cell, None) - net_obj_ids = self.grid_net_obj_ids.get(cell) - if net_obj_ids is not None: - member_ids = net_obj_ids.get(net_id) - if member_ids is not None: - member_ids.discard(obj_id) - if not member_ids: - net_obj_ids.pop(net_id, None) - if not net_obj_ids: - self.grid_net_obj_ids.pop(cell, None) - net_counts = self.grid_net_counts.get(cell) - if net_counts is not None: - remaining = net_counts.get(net_id, 0) - 1 - if remaining > 0: - net_counts[net_id] = remaining - else: - net_counts.pop(net_id, None) - if not net_counts: - self.grid_net_counts.pop(cell, None) - - def add_path( - self, - net_id: str, - geometry: Sequence[Polygon], - dilated_geometry: Sequence[Polygon], - component_indexes: Sequence[int] | None = None, - ) -> None: + def add_path(self, net_id: str, geometry: Sequence[Polygon], dilated_geometry: Sequence[Polygon]) -> None: + self.invalidate_queries() if self.engine.metrics is not None: self.engine.metrics.total_dynamic_path_objects_added += len(geometry) - cell_size = self.engine.grid_cell_size for index, polygon in enumerate(geometry): obj_id = self.id_counter self.id_counter += 1 dilated = dilated_geometry[index] - dilated_bounds = dilated.bounds self.geometries[obj_id] = (net_id, polygon) - self.component_indexes[obj_id] = index if component_indexes is None else component_indexes[index] self.dilated[obj_id] = dilated - self.dilated_bounds[obj_id] = dilated_bounds - self.index.insert(obj_id, dilated_bounds) - self.net_to_obj_ids.setdefault(net_id, set()).add(obj_id) - self._register_grid_membership(obj_id, net_id, dilated_bounds, cell_size=cell_size) - self._refresh_net_envelope(net_id) - self.tree = None + self.index.insert(obj_id, dilated.bounds) def remove_path(self, net_id: str) -> None: - to_remove = list(self.net_to_obj_ids.get(net_id, ())) + to_remove = [obj_id for obj_id, (existing_net_id, _) in self.geometries.items() if existing_net_id == net_id] self.remove_obj_ids(to_remove) def remove_obj_ids(self, obj_ids: list[int]) -> None: if not obj_ids: return + self.invalidate_queries() if self.engine.metrics is not None: self.engine.metrics.total_dynamic_path_objects_removed += len(obj_ids) - affected_nets: set[str] = set() for obj_id in obj_ids: - net_id, _ = self.geometries[obj_id] - affected_nets.add(net_id) - self._unregister_grid_membership(obj_id, net_id) - self.index.delete(obj_id, self.dilated_bounds[obj_id]) + self.index.delete(obj_id, self.dilated[obj_id].bounds) del self.geometries[obj_id] - del self.component_indexes[obj_id] del self.dilated[obj_id] - del self.dilated_bounds[obj_id] - obj_id_set = self.net_to_obj_ids.get(net_id) - if obj_id_set is not None: - obj_id_set.discard(obj_id) - if not obj_id_set: - self.net_to_obj_ids.pop(net_id, None) - for net_id in affected_nets: - self._refresh_net_envelope(net_id) - self.tree = None diff --git a/inire/model.py b/inire/model.py index 5860102..05e923a 100644 --- a/inire/model.py +++ b/inire/model.py @@ -105,8 +105,6 @@ class RefinementOptions: @dataclass(frozen=True, slots=True) class DiagnosticsOptions: capture_expanded: bool = False - capture_conflict_trace: bool = False - capture_frontier_trace: bool = False @dataclass(frozen=True, slots=True) diff --git a/inire/results.py b/inire/results.py index 88dd3a3..0ac5a29 100644 --- a/inire/results.py +++ b/inire/results.py @@ -12,8 +12,6 @@ if TYPE_CHECKING: RoutingOutcome = Literal["completed", "colliding", "partial", "unroutable"] -ConflictTraceStage = Literal["iteration", "restored_best", "final"] -FrontierTraceReason = Literal["closed_set", "hard_collision", "self_collision", "cost"] @dataclass(frozen=True, slots=True) @@ -32,52 +30,6 @@ class RoutingReport: return self.collision_count == 0 -@dataclass(frozen=True, slots=True) -class ComponentConflictTrace: - other_net_id: str - self_component_index: int - other_component_index: int - - -@dataclass(frozen=True, slots=True) -class NetConflictTrace: - net_id: str - outcome: RoutingOutcome - reached_target: bool - report: RoutingReport - conflicting_net_ids: tuple[str, ...] = () - component_conflicts: tuple[ComponentConflictTrace, ...] = () - - -@dataclass(frozen=True, slots=True) -class ConflictTraceEntry: - stage: ConflictTraceStage - iteration: int | None - completed_net_ids: tuple[str, ...] - conflict_edges: tuple[tuple[str, str], ...] - nets: tuple[NetConflictTrace, ...] - - -@dataclass(frozen=True, slots=True) -class FrontierPruneSample: - reason: FrontierTraceReason - move_type: str - hotspot_index: int - parent_state: tuple[int, int, int] - end_state: tuple[int, int, int] - - -@dataclass(frozen=True, slots=True) -class NetFrontierTrace: - net_id: str - hotspot_bounds: tuple[tuple[float, float, float, float], ...] - pruned_closed_set: int - pruned_hard_collision: int - pruned_self_collision: int - pruned_cost: int - samples: tuple[FrontierPruneSample, ...] = () - - @dataclass(frozen=True, slots=True) class RouteMetrics: nodes_expanded: int @@ -93,48 +45,14 @@ class RouteMetrics: warm_start_paths_used: int refine_path_calls: int timeout_events: int - iteration_reverify_calls: int - iteration_reverified_nets: int - iteration_conflicting_nets: int - iteration_conflict_edges: int - nets_carried_forward: int - score_component_calls: int - score_component_total_ns: int - path_cost_calls: int - danger_map_lookup_calls: int - danger_map_cache_hits: int - danger_map_cache_misses: int - danger_map_query_calls: int - danger_map_total_ns: int move_cache_abs_hits: int move_cache_abs_misses: int move_cache_rel_hits: int move_cache_rel_misses: int - guidance_match_moves: int - guidance_match_moves_straight: int - guidance_match_moves_bend90: int - guidance_match_moves_sbend: int - guidance_bonus_applied: float - guidance_bonus_applied_straight: float - guidance_bonus_applied_bend90: float - guidance_bonus_applied_sbend: float static_safe_cache_hits: int hard_collision_cache_hits: int congestion_cache_hits: int congestion_cache_misses: int - congestion_presence_cache_hits: int - congestion_presence_cache_misses: int - congestion_presence_skips: int - congestion_candidate_precheck_hits: int - congestion_candidate_precheck_misses: int - congestion_candidate_precheck_skips: int - congestion_grid_net_cache_hits: int - congestion_grid_net_cache_misses: int - congestion_grid_span_cache_hits: int - congestion_grid_span_cache_misses: int - congestion_candidate_nets: int - congestion_net_envelope_cache_hits: int - congestion_net_envelope_cache_misses: int dynamic_path_objects_added: int dynamic_path_objects_removed: int dynamic_tree_rebuilds: int @@ -142,47 +60,21 @@ class RouteMetrics: static_tree_rebuilds: int static_raw_tree_rebuilds: int static_net_tree_rebuilds: int - visibility_corner_index_builds: int visibility_builds: int visibility_corner_pairs_checked: int - visibility_corner_queries_exact: int - visibility_corner_hits_exact: int + visibility_corner_queries: int + visibility_corner_hits: int visibility_point_queries: int visibility_point_cache_hits: int visibility_point_cache_misses: int - visibility_tangent_candidate_scans: int - visibility_tangent_candidate_corner_checks: int - visibility_tangent_candidate_ray_tests: int ray_cast_calls: int - ray_cast_calls_straight_static: int - ray_cast_calls_expand_snap: int - ray_cast_calls_expand_forward: int - ray_cast_calls_visibility_build: int - ray_cast_calls_visibility_query: int - ray_cast_calls_visibility_tangent: int - ray_cast_calls_other: int ray_cast_candidate_bounds: int ray_cast_exact_geometry_checks: int congestion_check_calls: int - congestion_lazy_resolutions: int - congestion_lazy_requeues: int - congestion_candidate_ids: int congestion_exact_pair_checks: int verify_path_report_calls: int verify_static_buffer_ops: int - verify_dynamic_candidate_nets: int verify_dynamic_exact_pair_checks: int - refinement_windows_considered: int - refinement_static_bounds_checked: int - refinement_dynamic_bounds_checked: int - refinement_candidate_side_extents: int - refinement_candidates_built: int - refinement_candidates_verified: int - refinement_candidates_accepted: int - pair_local_search_pairs_considered: int - pair_local_search_attempts: int - pair_local_search_accepts: int - pair_local_search_nodes_expanded: int @dataclass(frozen=True, slots=True) @@ -229,5 +121,3 @@ class RoutingRunResult: results_by_net: dict[str, RoutingResult] metrics: RouteMetrics expanded_nodes: tuple[tuple[int, int, int], ...] = () - conflict_trace: tuple[ConflictTraceEntry, ...] = () - frontier_trace: tuple[NetFrontierTrace, ...] = () diff --git a/inire/router/_astar_admission.py b/inire/router/_astar_admission.py index bb07505..088b526 100644 --- a/inire/router/_astar_admission.py +++ b/inire/router/_astar_admission.py @@ -26,11 +26,6 @@ def process_move( context: AStarContext, metrics: AStarMetrics, congestion_cache: dict[tuple, int], - congestion_presence_cache: dict[tuple[str, int, int, int, int], bool], - congestion_candidate_precheck_cache: dict[tuple[str, int, int, int, int], bool], - congestion_net_envelope_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]], - congestion_grid_net_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]], - congestion_grid_span_cache: dict[tuple[str, int, int, int, int], dict[str, tuple[int, ...]]], config: SearchRunConfig, move_class: MoveKind, params: tuple, @@ -114,11 +109,6 @@ def process_move( context, metrics, congestion_cache, - congestion_presence_cache, - congestion_candidate_precheck_cache, - congestion_net_envelope_cache, - congestion_grid_net_cache, - congestion_grid_span_cache, config, move_class, abs_key, @@ -136,23 +126,15 @@ def add_node( context: AStarContext, metrics: AStarMetrics, congestion_cache: dict[tuple, int], - congestion_presence_cache: dict[tuple[str, int, int, int, int], bool], - congestion_candidate_precheck_cache: dict[tuple[str, int, int, int, int], bool], - congestion_net_envelope_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]], - congestion_grid_net_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]], - congestion_grid_span_cache: dict[tuple[str, int, int, int, int], dict[str, tuple[int, ...]]], config: SearchRunConfig, move_type: MoveKind, cache_key: tuple, ) -> None: - frontier_trace = config.frontier_trace metrics.moves_generated += 1 metrics.total_moves_generated += 1 state = result.end_port.as_tuple() new_lower_bound_g = parent.g_cost + result.length if state in closed_set and closed_set[state] <= new_lower_bound_g + TOLERANCE_LINEAR: - if frontier_trace is not None: - frontier_trace.record("closed_set", move_type, parent.port.as_tuple(), state, result.total_dilated_bounds) metrics.pruned_closed_set += 1 metrics.total_pruned_closed_set += 1 return @@ -161,8 +143,6 @@ def add_node( end_p = result.end_port if cache_key in context.hard_collision_set: - if frontier_trace is not None: - frontier_trace.record("hard_collision", move_type, parent.port.as_tuple(), state, result.total_dilated_bounds) context.metrics.total_hard_collision_cache_hits += 1 metrics.pruned_hard_collision += 1 metrics.total_pruned_hard_collision += 1 @@ -179,100 +159,41 @@ def add_node( collision_found = ce.check_move_static(result, start_port=parent_p, end_port=end_p) if collision_found: context.hard_collision_set.add(cache_key) - if frontier_trace is not None: - frontier_trace.record("hard_collision", move_type, parent.port.as_tuple(), state, result.total_dilated_bounds) metrics.pruned_hard_collision += 1 metrics.total_pruned_hard_collision += 1 return context.static_safe_cache.add(cache_key) + total_overlaps = 0 + if not config.skip_congestion: + if cache_key in congestion_cache: + context.metrics.total_congestion_cache_hits += 1 + total_overlaps = congestion_cache[cache_key] + else: + context.metrics.total_congestion_cache_misses += 1 + total_overlaps = context.cost_evaluator.collision_engine.check_move_congestion(result, net_id) + congestion_cache[cache_key] = total_overlaps + if config.self_collision_check and component_hits_ancestor_chain(result, parent): - if frontier_trace is not None: - frontier_trace.record("self_collision", move_type, parent.port.as_tuple(), state, result.total_dilated_bounds) return move_cost = context.cost_evaluator.score_component( result, start_port=parent_p, ) - next_seed_index = None - if ( - config.guidance_seed is not None - and parent.seed_index is not None - and parent.seed_index < len(config.guidance_seed) - and result.move_spec == config.guidance_seed[parent.seed_index] - ): - context.metrics.total_guidance_match_moves += 1 - if result.move_type == "straight": - context.metrics.total_guidance_match_moves_straight += 1 - applied_bonus = config.guidance_bonus - context.metrics.total_guidance_bonus_applied_straight += applied_bonus - elif result.move_type == "bend90": - context.metrics.total_guidance_match_moves_bend90 += 1 - applied_bonus = config.guidance_bonus - context.metrics.total_guidance_bonus_applied_bend90 += applied_bonus - else: - context.metrics.total_guidance_match_moves_sbend += 1 - applied_bonus = config.guidance_bonus - context.metrics.total_guidance_bonus_applied_sbend += applied_bonus - context.metrics.total_guidance_bonus_applied += applied_bonus - move_cost = max(0.001, move_cost - applied_bonus) - next_seed_index = parent.seed_index + 1 + move_cost += total_overlaps * context.congestion_penalty if config.max_cost is not None and parent.g_cost + move_cost > config.max_cost: - if frontier_trace is not None: - frontier_trace.record("cost", move_type, parent.port.as_tuple(), state, result.total_dilated_bounds) metrics.pruned_cost += 1 metrics.total_pruned_cost += 1 return if move_cost > 1e12: - if frontier_trace is not None: - frontier_trace.record("cost", move_type, parent.port.as_tuple(), state, result.total_dilated_bounds) metrics.pruned_cost += 1 metrics.total_pruned_cost += 1 return - if state in closed_set and closed_set[state] <= parent.g_cost + move_cost + TOLERANCE_LINEAR: - if frontier_trace is not None: - frontier_trace.record("closed_set", move_type, parent.port.as_tuple(), state, result.total_dilated_bounds) - metrics.pruned_closed_set += 1 - metrics.total_pruned_closed_set += 1 - return - - total_overlaps = 0 - if not config.skip_congestion and context.cost_evaluator.collision_engine.has_dynamic_paths(): - ce = context.cost_evaluator.collision_engine - if ce.has_possible_move_congestion(result, net_id, congestion_presence_cache): - if ce.has_candidate_move_congestion( - result, - net_id, - congestion_candidate_precheck_cache, - congestion_net_envelope_cache, - congestion_grid_net_cache, - ): - if cache_key in congestion_cache: - context.metrics.total_congestion_cache_hits += 1 - total_overlaps = congestion_cache[cache_key] - else: - context.metrics.total_congestion_cache_misses += 1 - total_overlaps = ce.check_move_congestion( - result, - net_id, - net_envelope_cache=congestion_net_envelope_cache, - grid_net_cache=congestion_grid_net_cache, - broad_phase_cache=congestion_grid_span_cache, - ) - congestion_cache[cache_key] = total_overlaps - else: - context.metrics.total_congestion_candidate_precheck_skips += 1 - else: - context.metrics.total_congestion_presence_skips += 1 - move_cost += total_overlaps * context.congestion_penalty - g_cost = parent.g_cost + move_cost if state in closed_set and closed_set[state] <= g_cost + TOLERANCE_LINEAR: - if frontier_trace is not None: - frontier_trace.record("closed_set", move_type, parent.port.as_tuple(), state, result.total_dilated_bounds) metrics.pruned_closed_set += 1 metrics.total_pruned_closed_set += 1 return @@ -282,16 +203,6 @@ def add_node( target, min_bend_radius=context.min_bend_radius, ) - heapq.heappush( - open_set, - AStarNode( - result.end_port, - g_cost, - h_cost, - parent, - result, - seed_index=next_seed_index, - ), - ) + heapq.heappush(open_set, AStarNode(result.end_port, g_cost, h_cost, parent, result)) metrics.moves_added += 1 metrics.total_moves_added += 1 diff --git a/inire/router/_astar_moves.py b/inire/router/_astar_moves.py index 8b8a60c..56aae96 100644 --- a/inire/router/_astar_moves.py +++ b/inire/router/_astar_moves.py @@ -18,27 +18,6 @@ def _quantized_lengths(values: list[float], max_reach: float) -> list[int]: return sorted((v for v in out if v > 0), reverse=True) -def _distance_to_bounds_in_heading( - current: Port, - bounds: tuple[float, float, float, float], -) -> float: - min_x, min_y, max_x, max_y = bounds - if current.r == 0: - return max(0.0, max_x - current.x) - if current.r == 90: - return max(0.0, max_y - current.y) - if current.r == 180: - return max(0.0, current.x - min_x) - return max(0.0, current.y - min_y) - - -def _should_cap_straights_to_bounds(context: AStarContext) -> bool: - return ( - not context.options.congestion.warm_start_enabled - and len(context.problem.nets) >= 8 - ) - - def _sbend_forward_span(offset: float, radius: float) -> float | None: abs_offset = abs(offset) if abs_offset <= TOLERANCE_LINEAR or radius <= 0 or abs_offset >= 2.0 * radius: @@ -84,25 +63,19 @@ def _visible_straight_candidates( return [] visibility_manager = context.visibility_manager - visibility_manager.ensure_corner_index_current() - context.metrics.total_visibility_tangent_candidate_scans += 1 + visibility_manager._ensure_current() max_bend_radius = max(search_options.bend_radii, default=0.0) if max_bend_radius <= 0 or not visibility_manager.corners: return [] reach = max_reach + max_bend_radius - candidate_ids = visibility_manager.get_tangent_corner_candidates( - current, - min_forward=search_options.min_straight_length, - max_forward=reach, - radii=search_options.bend_radii, - ) + bounds = (current.x - reach, current.y - reach, current.x + reach, current.y + reach) + candidate_ids = list(visibility_manager.corner_index.intersection(bounds)) if not candidate_ids: return [] scored: list[tuple[float, float, float, float, float]] = [] for idx in candidate_ids: - context.metrics.total_visibility_tangent_candidate_corner_checks += 1 cx, cy = visibility_manager.corners[idx] dx = cx - current.x dy = cy - current.y @@ -128,15 +101,8 @@ def _visible_straight_candidates( collision_engine = context.cost_evaluator.collision_engine tangent_candidates: set[int] = set() for _, dist, length, dx, dy in sorted(scored)[:4]: - context.metrics.total_visibility_tangent_candidate_ray_tests += 1 angle = math.degrees(math.atan2(dy, dx)) - corner_reach = collision_engine.ray_cast( - current, - angle, - max_dist=dist + 0.05, - net_width=net_width, - caller="visibility_tangent", - ) + corner_reach = collision_engine.ray_cast(current, angle, max_dist=dist + 0.05, net_width=net_width) if corner_reach < dist - 0.01: continue qlen = int(round(length)) @@ -166,11 +132,6 @@ def expand_moves( context: AStarContext, metrics: AStarMetrics, congestion_cache: dict[tuple, int], - congestion_presence_cache: dict[tuple[str, int, int, int, int], bool], - congestion_candidate_precheck_cache: dict[tuple[str, int, int, int, int], bool], - congestion_net_envelope_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]], - congestion_grid_net_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]], - congestion_grid_span_cache: dict[tuple[str, int, int, int, int], dict[str, tuple[int, ...]]], config: SearchRunConfig, ) -> None: search_options = context.options.search @@ -195,13 +156,7 @@ def expand_moves( dy_local = perp_t if proj_t > 0 and abs(perp_t) < 1e-6 and cp.r == target.r: - max_reach = context.cost_evaluator.collision_engine.ray_cast( - cp, - cp.r, - proj_t + 1.0, - net_width=net_width, - caller="expand_snap", - ) + max_reach = context.cost_evaluator.collision_engine.ray_cast(cp, cp.r, proj_t + 1.0, net_width=net_width) if max_reach >= proj_t - 0.01 and ( prev_straight_length is None or proj_t < prev_straight_length - TOLERANCE_LINEAR ): @@ -215,25 +170,12 @@ def expand_moves( context, metrics, congestion_cache, - congestion_presence_cache, - congestion_candidate_precheck_cache, - congestion_net_envelope_cache, - congestion_grid_net_cache, - congestion_grid_span_cache, config, "straight", (int(round(proj_t)),), ) - max_reach = context.cost_evaluator.collision_engine.ray_cast( - cp, - cp.r, - search_options.max_straight_length, - net_width=net_width, - caller="expand_forward", - ) - if _should_cap_straights_to_bounds(context): - max_reach = min(max_reach, _distance_to_bounds_in_heading(cp, context.problem.bounds)) + max_reach = context.cost_evaluator.collision_engine.ray_cast(cp, cp.r, search_options.max_straight_length, net_width=net_width) candidate_lengths = [ search_options.min_straight_length, max_reach, @@ -279,11 +221,6 @@ def expand_moves( context, metrics, congestion_cache, - congestion_presence_cache, - congestion_candidate_precheck_cache, - congestion_net_envelope_cache, - congestion_grid_net_cache, - congestion_grid_span_cache, config, "straight", (length,), @@ -312,11 +249,6 @@ def expand_moves( context, metrics, congestion_cache, - congestion_presence_cache, - congestion_candidate_precheck_cache, - congestion_net_envelope_cache, - congestion_grid_net_cache, - congestion_grid_span_cache, config, "bend90", (radius, direction), @@ -345,17 +277,12 @@ def expand_moves( current, target, net_width, - net_id, - open_set, - closed_set, + net_id, + open_set, + closed_set, context, metrics, congestion_cache, - congestion_presence_cache, - congestion_candidate_precheck_cache, - congestion_net_envelope_cache, - congestion_grid_net_cache, - congestion_grid_span_cache, config, "sbend", (offset, radius), diff --git a/inire/router/_astar_types.py b/inire/router/_astar_types.py index 83fa899..0092cbd 100644 --- a/inire/router/_astar_types.py +++ b/inire/router/_astar_types.py @@ -1,6 +1,6 @@ from __future__ import annotations -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import TYPE_CHECKING from inire.model import resolve_bend_geometry @@ -12,51 +12,6 @@ if TYPE_CHECKING: from inire.geometry.primitives import Port from inire.model import RoutingOptions, RoutingProblem from inire.router.cost import CostEvaluator - from inire.seeds import PathSegmentSeed - - -@dataclass(slots=True) -class FrontierTraceCollector: - hotspot_bounds: tuple[tuple[float, float, float, float], ...] - sample_limit: int = 64 - pruned_closed_set: int = 0 - pruned_hard_collision: int = 0 - pruned_self_collision: int = 0 - pruned_cost: int = 0 - samples: list[tuple[str, str, int, tuple[int, int, int], tuple[int, int, int]]] = field(default_factory=list) - - def _matching_hotspot_index(self, bounds: tuple[float, float, float, float]) -> int | None: - for idx, hotspot_bounds in enumerate(self.hotspot_bounds): - if ( - bounds[0] < hotspot_bounds[2] - and bounds[2] > hotspot_bounds[0] - and bounds[1] < hotspot_bounds[3] - and bounds[3] > hotspot_bounds[1] - ): - return idx - return None - - def record( - self, - reason: str, - move_type: str, - parent_state: tuple[int, int, int], - end_state: tuple[int, int, int], - bounds: tuple[float, float, float, float], - ) -> None: - hotspot_index = self._matching_hotspot_index(bounds) - if hotspot_index is None: - return - if reason == "closed_set": - self.pruned_closed_set += 1 - elif reason == "hard_collision": - self.pruned_hard_collision += 1 - elif reason == "self_collision": - self.pruned_self_collision += 1 - else: - self.pruned_cost += 1 - if len(self.samples) < self.sample_limit: - self.samples.append((reason, move_type, hotspot_index, parent_state, end_state)) @dataclass(frozen=True, slots=True) @@ -65,9 +20,6 @@ class SearchRunConfig: bend_physical_geometry: BendPhysicalGeometry bend_clip_margin: float | None node_limit: int - guidance_seed: tuple[PathSegmentSeed, ...] | None = None - guidance_bonus: float = 0.0 - frontier_trace: FrontierTraceCollector | None = None return_partial: bool = False store_expanded: bool = False skip_congestion: bool = False @@ -81,9 +33,6 @@ class SearchRunConfig: *, bend_collision_type: BendCollisionModel | None = None, node_limit: int | None = None, - guidance_seed: tuple[PathSegmentSeed, ...] | None = None, - guidance_bonus: float = 0.0, - frontier_trace: FrontierTraceCollector | None = None, return_partial: bool = False, store_expanded: bool = False, skip_congestion: bool = False, @@ -100,9 +49,6 @@ class SearchRunConfig: bend_physical_geometry=bend_physical_geometry, bend_clip_margin=search.bend_clip_margin, node_limit=search.node_limit if node_limit is None else node_limit, - guidance_seed=guidance_seed, - guidance_bonus=float(guidance_bonus), - frontier_trace=frontier_trace, return_partial=return_partial, store_expanded=store_expanded, skip_congestion=skip_congestion, @@ -112,18 +58,7 @@ class SearchRunConfig: class AStarNode: - __slots__ = ( - "port", - "g_cost", - "h_cost", - "fh_cost", - "parent", - "component_result", - "base_move_cost", - "cache_key", - "seed_index", - "congestion_resolved", - ) + __slots__ = ("port", "g_cost", "h_cost", "fh_cost", "parent", "component_result") def __init__( self, @@ -132,11 +67,6 @@ class AStarNode: h_cost: float, parent: AStarNode | None = None, component_result: ComponentResult | None = None, - *, - base_move_cost: float = 0.0, - cache_key: tuple | None = None, - seed_index: int | None = None, - congestion_resolved: bool = True, ) -> None: self.port = port self.g_cost = g_cost @@ -144,10 +74,6 @@ class AStarNode: self.fh_cost = (g_cost + h_cost, h_cost) self.parent = parent self.component_result = component_result - self.base_move_cost = base_move_cost - self.cache_key = cache_key - self.seed_index = seed_index - self.congestion_resolved = congestion_resolved def __lt__(self, other: AStarNode) -> bool: return self.fh_cost < other.fh_cost @@ -168,48 +94,14 @@ class AStarMetrics: "total_warm_start_paths_used", "total_refine_path_calls", "total_timeout_events", - "total_iteration_reverify_calls", - "total_iteration_reverified_nets", - "total_iteration_conflicting_nets", - "total_iteration_conflict_edges", - "total_nets_carried_forward", - "total_score_component_calls", - "total_score_component_total_ns", - "total_path_cost_calls", - "total_danger_map_lookup_calls", - "total_danger_map_cache_hits", - "total_danger_map_cache_misses", - "total_danger_map_query_calls", - "total_danger_map_total_ns", "total_move_cache_abs_hits", "total_move_cache_abs_misses", "total_move_cache_rel_hits", "total_move_cache_rel_misses", - "total_guidance_match_moves", - "total_guidance_match_moves_straight", - "total_guidance_match_moves_bend90", - "total_guidance_match_moves_sbend", - "total_guidance_bonus_applied", - "total_guidance_bonus_applied_straight", - "total_guidance_bonus_applied_bend90", - "total_guidance_bonus_applied_sbend", "total_static_safe_cache_hits", "total_hard_collision_cache_hits", "total_congestion_cache_hits", "total_congestion_cache_misses", - "total_congestion_presence_cache_hits", - "total_congestion_presence_cache_misses", - "total_congestion_presence_skips", - "total_congestion_candidate_precheck_hits", - "total_congestion_candidate_precheck_misses", - "total_congestion_candidate_precheck_skips", - "total_congestion_grid_net_cache_hits", - "total_congestion_grid_net_cache_misses", - "total_congestion_grid_span_cache_hits", - "total_congestion_grid_span_cache_misses", - "total_congestion_candidate_nets", - "total_congestion_net_envelope_cache_hits", - "total_congestion_net_envelope_cache_misses", "total_dynamic_path_objects_added", "total_dynamic_path_objects_removed", "total_dynamic_tree_rebuilds", @@ -217,47 +109,21 @@ class AStarMetrics: "total_static_tree_rebuilds", "total_static_raw_tree_rebuilds", "total_static_net_tree_rebuilds", - "total_visibility_corner_index_builds", "total_visibility_builds", "total_visibility_corner_pairs_checked", - "total_visibility_corner_queries_exact", - "total_visibility_corner_hits_exact", + "total_visibility_corner_queries", + "total_visibility_corner_hits", "total_visibility_point_queries", "total_visibility_point_cache_hits", "total_visibility_point_cache_misses", - "total_visibility_tangent_candidate_scans", - "total_visibility_tangent_candidate_corner_checks", - "total_visibility_tangent_candidate_ray_tests", "total_ray_cast_calls", - "total_ray_cast_calls_straight_static", - "total_ray_cast_calls_expand_snap", - "total_ray_cast_calls_expand_forward", - "total_ray_cast_calls_visibility_build", - "total_ray_cast_calls_visibility_query", - "total_ray_cast_calls_visibility_tangent", - "total_ray_cast_calls_other", "total_ray_cast_candidate_bounds", "total_ray_cast_exact_geometry_checks", "total_congestion_check_calls", - "total_congestion_lazy_resolutions", - "total_congestion_lazy_requeues", - "total_congestion_candidate_ids", "total_congestion_exact_pair_checks", "total_verify_path_report_calls", "total_verify_static_buffer_ops", - "total_verify_dynamic_candidate_nets", "total_verify_dynamic_exact_pair_checks", - "total_refinement_windows_considered", - "total_refinement_static_bounds_checked", - "total_refinement_dynamic_bounds_checked", - "total_refinement_candidate_side_extents", - "total_refinement_candidates_built", - "total_refinement_candidates_verified", - "total_refinement_candidates_accepted", - "total_pair_local_search_pairs_considered", - "total_pair_local_search_attempts", - "total_pair_local_search_accepts", - "total_pair_local_search_nodes_expanded", "last_expanded_nodes", "nodes_expanded", "moves_generated", @@ -281,48 +147,14 @@ class AStarMetrics: self.total_warm_start_paths_used = 0 self.total_refine_path_calls = 0 self.total_timeout_events = 0 - self.total_iteration_reverify_calls = 0 - self.total_iteration_reverified_nets = 0 - self.total_iteration_conflicting_nets = 0 - self.total_iteration_conflict_edges = 0 - self.total_nets_carried_forward = 0 - self.total_score_component_calls = 0 - self.total_score_component_total_ns = 0 - self.total_path_cost_calls = 0 - self.total_danger_map_lookup_calls = 0 - self.total_danger_map_cache_hits = 0 - self.total_danger_map_cache_misses = 0 - self.total_danger_map_query_calls = 0 - self.total_danger_map_total_ns = 0 self.total_move_cache_abs_hits = 0 self.total_move_cache_abs_misses = 0 self.total_move_cache_rel_hits = 0 self.total_move_cache_rel_misses = 0 - self.total_guidance_match_moves = 0 - self.total_guidance_match_moves_straight = 0 - self.total_guidance_match_moves_bend90 = 0 - self.total_guidance_match_moves_sbend = 0 - self.total_guidance_bonus_applied = 0.0 - self.total_guidance_bonus_applied_straight = 0.0 - self.total_guidance_bonus_applied_bend90 = 0.0 - self.total_guidance_bonus_applied_sbend = 0.0 self.total_static_safe_cache_hits = 0 self.total_hard_collision_cache_hits = 0 self.total_congestion_cache_hits = 0 self.total_congestion_cache_misses = 0 - self.total_congestion_presence_cache_hits = 0 - self.total_congestion_presence_cache_misses = 0 - self.total_congestion_presence_skips = 0 - self.total_congestion_candidate_precheck_hits = 0 - self.total_congestion_candidate_precheck_misses = 0 - self.total_congestion_candidate_precheck_skips = 0 - self.total_congestion_grid_net_cache_hits = 0 - self.total_congestion_grid_net_cache_misses = 0 - self.total_congestion_grid_span_cache_hits = 0 - self.total_congestion_grid_span_cache_misses = 0 - self.total_congestion_candidate_nets = 0 - self.total_congestion_net_envelope_cache_hits = 0 - self.total_congestion_net_envelope_cache_misses = 0 self.total_dynamic_path_objects_added = 0 self.total_dynamic_path_objects_removed = 0 self.total_dynamic_tree_rebuilds = 0 @@ -330,47 +162,21 @@ class AStarMetrics: self.total_static_tree_rebuilds = 0 self.total_static_raw_tree_rebuilds = 0 self.total_static_net_tree_rebuilds = 0 - self.total_visibility_corner_index_builds = 0 self.total_visibility_builds = 0 self.total_visibility_corner_pairs_checked = 0 - self.total_visibility_corner_queries_exact = 0 - self.total_visibility_corner_hits_exact = 0 + self.total_visibility_corner_queries = 0 + self.total_visibility_corner_hits = 0 self.total_visibility_point_queries = 0 self.total_visibility_point_cache_hits = 0 self.total_visibility_point_cache_misses = 0 - self.total_visibility_tangent_candidate_scans = 0 - self.total_visibility_tangent_candidate_corner_checks = 0 - self.total_visibility_tangent_candidate_ray_tests = 0 self.total_ray_cast_calls = 0 - self.total_ray_cast_calls_straight_static = 0 - self.total_ray_cast_calls_expand_snap = 0 - self.total_ray_cast_calls_expand_forward = 0 - self.total_ray_cast_calls_visibility_build = 0 - self.total_ray_cast_calls_visibility_query = 0 - self.total_ray_cast_calls_visibility_tangent = 0 - self.total_ray_cast_calls_other = 0 self.total_ray_cast_candidate_bounds = 0 self.total_ray_cast_exact_geometry_checks = 0 self.total_congestion_check_calls = 0 - self.total_congestion_lazy_resolutions = 0 - self.total_congestion_lazy_requeues = 0 - self.total_congestion_candidate_ids = 0 self.total_congestion_exact_pair_checks = 0 self.total_verify_path_report_calls = 0 self.total_verify_static_buffer_ops = 0 - self.total_verify_dynamic_candidate_nets = 0 self.total_verify_dynamic_exact_pair_checks = 0 - self.total_refinement_windows_considered = 0 - self.total_refinement_static_bounds_checked = 0 - self.total_refinement_dynamic_bounds_checked = 0 - self.total_refinement_candidate_side_extents = 0 - self.total_refinement_candidates_built = 0 - self.total_refinement_candidates_verified = 0 - self.total_refinement_candidates_accepted = 0 - self.total_pair_local_search_pairs_considered = 0 - self.total_pair_local_search_attempts = 0 - self.total_pair_local_search_accepts = 0 - self.total_pair_local_search_nodes_expanded = 0 self.last_expanded_nodes: list[tuple[int, int, int]] = [] self.nodes_expanded = 0 self.moves_generated = 0 @@ -393,48 +199,14 @@ class AStarMetrics: self.total_warm_start_paths_used = 0 self.total_refine_path_calls = 0 self.total_timeout_events = 0 - self.total_iteration_reverify_calls = 0 - self.total_iteration_reverified_nets = 0 - self.total_iteration_conflicting_nets = 0 - self.total_iteration_conflict_edges = 0 - self.total_nets_carried_forward = 0 - self.total_score_component_calls = 0 - self.total_score_component_total_ns = 0 - self.total_path_cost_calls = 0 - self.total_danger_map_lookup_calls = 0 - self.total_danger_map_cache_hits = 0 - self.total_danger_map_cache_misses = 0 - self.total_danger_map_query_calls = 0 - self.total_danger_map_total_ns = 0 self.total_move_cache_abs_hits = 0 self.total_move_cache_abs_misses = 0 self.total_move_cache_rel_hits = 0 self.total_move_cache_rel_misses = 0 - self.total_guidance_match_moves = 0 - self.total_guidance_match_moves_straight = 0 - self.total_guidance_match_moves_bend90 = 0 - self.total_guidance_match_moves_sbend = 0 - self.total_guidance_bonus_applied = 0.0 - self.total_guidance_bonus_applied_straight = 0.0 - self.total_guidance_bonus_applied_bend90 = 0.0 - self.total_guidance_bonus_applied_sbend = 0.0 self.total_static_safe_cache_hits = 0 self.total_hard_collision_cache_hits = 0 self.total_congestion_cache_hits = 0 self.total_congestion_cache_misses = 0 - self.total_congestion_presence_cache_hits = 0 - self.total_congestion_presence_cache_misses = 0 - self.total_congestion_presence_skips = 0 - self.total_congestion_candidate_precheck_hits = 0 - self.total_congestion_candidate_precheck_misses = 0 - self.total_congestion_candidate_precheck_skips = 0 - self.total_congestion_grid_net_cache_hits = 0 - self.total_congestion_grid_net_cache_misses = 0 - self.total_congestion_grid_span_cache_hits = 0 - self.total_congestion_grid_span_cache_misses = 0 - self.total_congestion_candidate_nets = 0 - self.total_congestion_net_envelope_cache_hits = 0 - self.total_congestion_net_envelope_cache_misses = 0 self.total_dynamic_path_objects_added = 0 self.total_dynamic_path_objects_removed = 0 self.total_dynamic_tree_rebuilds = 0 @@ -442,47 +214,21 @@ class AStarMetrics: self.total_static_tree_rebuilds = 0 self.total_static_raw_tree_rebuilds = 0 self.total_static_net_tree_rebuilds = 0 - self.total_visibility_corner_index_builds = 0 self.total_visibility_builds = 0 self.total_visibility_corner_pairs_checked = 0 - self.total_visibility_corner_queries_exact = 0 - self.total_visibility_corner_hits_exact = 0 + self.total_visibility_corner_queries = 0 + self.total_visibility_corner_hits = 0 self.total_visibility_point_queries = 0 self.total_visibility_point_cache_hits = 0 self.total_visibility_point_cache_misses = 0 - self.total_visibility_tangent_candidate_scans = 0 - self.total_visibility_tangent_candidate_corner_checks = 0 - self.total_visibility_tangent_candidate_ray_tests = 0 self.total_ray_cast_calls = 0 - self.total_ray_cast_calls_straight_static = 0 - self.total_ray_cast_calls_expand_snap = 0 - self.total_ray_cast_calls_expand_forward = 0 - self.total_ray_cast_calls_visibility_build = 0 - self.total_ray_cast_calls_visibility_query = 0 - self.total_ray_cast_calls_visibility_tangent = 0 - self.total_ray_cast_calls_other = 0 self.total_ray_cast_candidate_bounds = 0 self.total_ray_cast_exact_geometry_checks = 0 self.total_congestion_check_calls = 0 - self.total_congestion_lazy_resolutions = 0 - self.total_congestion_lazy_requeues = 0 - self.total_congestion_candidate_ids = 0 self.total_congestion_exact_pair_checks = 0 self.total_verify_path_report_calls = 0 self.total_verify_static_buffer_ops = 0 - self.total_verify_dynamic_candidate_nets = 0 self.total_verify_dynamic_exact_pair_checks = 0 - self.total_refinement_windows_considered = 0 - self.total_refinement_static_bounds_checked = 0 - self.total_refinement_dynamic_bounds_checked = 0 - self.total_refinement_candidate_side_extents = 0 - self.total_refinement_candidates_built = 0 - self.total_refinement_candidates_verified = 0 - self.total_refinement_candidates_accepted = 0 - self.total_pair_local_search_pairs_considered = 0 - self.total_pair_local_search_attempts = 0 - self.total_pair_local_search_accepts = 0 - self.total_pair_local_search_nodes_expanded = 0 def reset_per_route(self) -> None: self.nodes_expanded = 0 @@ -508,48 +254,14 @@ class AStarMetrics: warm_start_paths_used=self.total_warm_start_paths_used, refine_path_calls=self.total_refine_path_calls, timeout_events=self.total_timeout_events, - iteration_reverify_calls=self.total_iteration_reverify_calls, - iteration_reverified_nets=self.total_iteration_reverified_nets, - iteration_conflicting_nets=self.total_iteration_conflicting_nets, - iteration_conflict_edges=self.total_iteration_conflict_edges, - nets_carried_forward=self.total_nets_carried_forward, - score_component_calls=self.total_score_component_calls, - score_component_total_ns=self.total_score_component_total_ns, - path_cost_calls=self.total_path_cost_calls, - danger_map_lookup_calls=self.total_danger_map_lookup_calls, - danger_map_cache_hits=self.total_danger_map_cache_hits, - danger_map_cache_misses=self.total_danger_map_cache_misses, - danger_map_query_calls=self.total_danger_map_query_calls, - danger_map_total_ns=self.total_danger_map_total_ns, move_cache_abs_hits=self.total_move_cache_abs_hits, move_cache_abs_misses=self.total_move_cache_abs_misses, move_cache_rel_hits=self.total_move_cache_rel_hits, move_cache_rel_misses=self.total_move_cache_rel_misses, - guidance_match_moves=self.total_guidance_match_moves, - guidance_match_moves_straight=self.total_guidance_match_moves_straight, - guidance_match_moves_bend90=self.total_guidance_match_moves_bend90, - guidance_match_moves_sbend=self.total_guidance_match_moves_sbend, - guidance_bonus_applied=self.total_guidance_bonus_applied, - guidance_bonus_applied_straight=self.total_guidance_bonus_applied_straight, - guidance_bonus_applied_bend90=self.total_guidance_bonus_applied_bend90, - guidance_bonus_applied_sbend=self.total_guidance_bonus_applied_sbend, static_safe_cache_hits=self.total_static_safe_cache_hits, hard_collision_cache_hits=self.total_hard_collision_cache_hits, congestion_cache_hits=self.total_congestion_cache_hits, congestion_cache_misses=self.total_congestion_cache_misses, - congestion_presence_cache_hits=self.total_congestion_presence_cache_hits, - congestion_presence_cache_misses=self.total_congestion_presence_cache_misses, - congestion_presence_skips=self.total_congestion_presence_skips, - congestion_candidate_precheck_hits=self.total_congestion_candidate_precheck_hits, - congestion_candidate_precheck_misses=self.total_congestion_candidate_precheck_misses, - congestion_candidate_precheck_skips=self.total_congestion_candidate_precheck_skips, - congestion_grid_net_cache_hits=self.total_congestion_grid_net_cache_hits, - congestion_grid_net_cache_misses=self.total_congestion_grid_net_cache_misses, - congestion_grid_span_cache_hits=self.total_congestion_grid_span_cache_hits, - congestion_grid_span_cache_misses=self.total_congestion_grid_span_cache_misses, - congestion_candidate_nets=self.total_congestion_candidate_nets, - congestion_net_envelope_cache_hits=self.total_congestion_net_envelope_cache_hits, - congestion_net_envelope_cache_misses=self.total_congestion_net_envelope_cache_misses, dynamic_path_objects_added=self.total_dynamic_path_objects_added, dynamic_path_objects_removed=self.total_dynamic_path_objects_removed, dynamic_tree_rebuilds=self.total_dynamic_tree_rebuilds, @@ -557,47 +269,21 @@ class AStarMetrics: static_tree_rebuilds=self.total_static_tree_rebuilds, static_raw_tree_rebuilds=self.total_static_raw_tree_rebuilds, static_net_tree_rebuilds=self.total_static_net_tree_rebuilds, - visibility_corner_index_builds=self.total_visibility_corner_index_builds, visibility_builds=self.total_visibility_builds, visibility_corner_pairs_checked=self.total_visibility_corner_pairs_checked, - visibility_corner_queries_exact=self.total_visibility_corner_queries_exact, - visibility_corner_hits_exact=self.total_visibility_corner_hits_exact, + visibility_corner_queries=self.total_visibility_corner_queries, + visibility_corner_hits=self.total_visibility_corner_hits, visibility_point_queries=self.total_visibility_point_queries, visibility_point_cache_hits=self.total_visibility_point_cache_hits, visibility_point_cache_misses=self.total_visibility_point_cache_misses, - visibility_tangent_candidate_scans=self.total_visibility_tangent_candidate_scans, - visibility_tangent_candidate_corner_checks=self.total_visibility_tangent_candidate_corner_checks, - visibility_tangent_candidate_ray_tests=self.total_visibility_tangent_candidate_ray_tests, ray_cast_calls=self.total_ray_cast_calls, - ray_cast_calls_straight_static=self.total_ray_cast_calls_straight_static, - ray_cast_calls_expand_snap=self.total_ray_cast_calls_expand_snap, - ray_cast_calls_expand_forward=self.total_ray_cast_calls_expand_forward, - ray_cast_calls_visibility_build=self.total_ray_cast_calls_visibility_build, - ray_cast_calls_visibility_query=self.total_ray_cast_calls_visibility_query, - ray_cast_calls_visibility_tangent=self.total_ray_cast_calls_visibility_tangent, - ray_cast_calls_other=self.total_ray_cast_calls_other, ray_cast_candidate_bounds=self.total_ray_cast_candidate_bounds, ray_cast_exact_geometry_checks=self.total_ray_cast_exact_geometry_checks, congestion_check_calls=self.total_congestion_check_calls, - congestion_lazy_resolutions=self.total_congestion_lazy_resolutions, - congestion_lazy_requeues=self.total_congestion_lazy_requeues, - congestion_candidate_ids=self.total_congestion_candidate_ids, congestion_exact_pair_checks=self.total_congestion_exact_pair_checks, verify_path_report_calls=self.total_verify_path_report_calls, verify_static_buffer_ops=self.total_verify_static_buffer_ops, - verify_dynamic_candidate_nets=self.total_verify_dynamic_candidate_nets, verify_dynamic_exact_pair_checks=self.total_verify_dynamic_exact_pair_checks, - refinement_windows_considered=self.total_refinement_windows_considered, - refinement_static_bounds_checked=self.total_refinement_static_bounds_checked, - refinement_dynamic_bounds_checked=self.total_refinement_dynamic_bounds_checked, - refinement_candidate_side_extents=self.total_refinement_candidate_side_extents, - refinement_candidates_built=self.total_refinement_candidates_built, - refinement_candidates_verified=self.total_refinement_candidates_verified, - refinement_candidates_accepted=self.total_refinement_candidates_accepted, - pair_local_search_pairs_considered=self.total_pair_local_search_pairs_considered, - pair_local_search_attempts=self.total_pair_local_search_attempts, - pair_local_search_accepts=self.total_pair_local_search_accepts, - pair_local_search_nodes_expanded=self.total_pair_local_search_nodes_expanded, ) diff --git a/inire/router/_router.py b/inire/router/_router.py index 367e721..801e1b8 100644 --- a/inire/router/_router.py +++ b/inire/router/_router.py @@ -5,23 +5,11 @@ import time from dataclasses import dataclass from typing import TYPE_CHECKING -from inire.geometry.collision import RoutingWorld -from inire.model import NetOrder, NetSpec, RoutingProblem, resolve_bend_geometry -from inire.results import ( - ComponentConflictTrace, - ConflictTraceEntry, - FrontierPruneSample, - NetConflictTrace, - NetFrontierTrace, - RoutingOutcome, - RoutingReport, - RoutingResult, -) -from inire.router._astar_types import AStarContext, AStarMetrics, FrontierTraceCollector, SearchRunConfig +from inire.model import NetOrder, NetSpec, resolve_bend_geometry +from inire.results import RoutingOutcome, RoutingReport, RoutingResult +from inire.router._astar_types import AStarContext, AStarMetrics, SearchRunConfig from inire.router._search import route_astar from inire.router._seed_materialization import materialize_path_seed -from inire.router.cost import CostEvaluator -from inire.router.danger_map import DangerMap from inire.router.refiner import PathRefiner if TYPE_CHECKING: @@ -29,7 +17,6 @@ if TYPE_CHECKING: from shapely.geometry import Polygon - from inire.geometry.collision import PathVerificationDetail from inire.geometry.components import ComponentResult @@ -43,27 +30,6 @@ class _RoutingState: timeout_s: float initial_paths: dict[str, tuple[ComponentResult, ...]] | None accumulated_expanded_nodes: list[tuple[int, int, int]] - best_results: dict[str, RoutingResult] - best_completed_nets: int - best_conflict_edges: int - best_dynamic_collisions: int - last_conflict_signature: tuple[tuple[str, str], ...] - last_conflict_edge_count: int - repeated_conflict_count: int - - -@dataclass(slots=True) -class _IterationReview: - conflicting_nets: set[str] - conflict_edges: set[tuple[str, str]] - completed_net_ids: set[str] - total_dynamic_collisions: int - - -@dataclass(frozen=True, slots=True) -class _PairLocalTarget: - net_ids: tuple[str, str] - class PathFinder: __slots__ = ( @@ -71,8 +37,6 @@ class PathFinder: "metrics", "refiner", "accumulated_expanded_nodes", - "conflict_trace", - "frontier_trace", ) def __init__( @@ -84,27 +48,16 @@ class PathFinder: self.metrics = self.context.metrics if metrics is None else metrics self.context.metrics = self.metrics self.context.cost_evaluator.collision_engine.metrics = self.metrics - if self.context.cost_evaluator.danger_map is not None: - self.context.cost_evaluator.danger_map.metrics = self.metrics self.refiner = PathRefiner(self.context) self.accumulated_expanded_nodes: list[tuple[int, int, int]] = [] - self.conflict_trace: list[ConflictTraceEntry] = [] - self.frontier_trace: list[NetFrontierTrace] = [] def _install_path(self, net_id: str, path: Sequence[ComponentResult]) -> None: all_geoms: list[Polygon] = [] all_dilated: list[Polygon] = [] - component_indexes: list[int] = [] - for component_index, result in enumerate(path): + for result in path: all_geoms.extend(result.collision_geometry) all_dilated.extend(result.dilated_collision_geometry) - component_indexes.extend([component_index] * len(result.collision_geometry)) - self.context.cost_evaluator.collision_engine.add_path( - net_id, - all_geoms, - dilated_geometry=all_dilated, - component_indexes=component_indexes, - ) + self.context.cost_evaluator.collision_engine.add_path(net_id, all_geoms, dilated_geometry=all_dilated) def _routing_order( self, @@ -181,13 +134,6 @@ class PathFinder: timeout_s=max(60.0, 10.0 * num_nets * congestion.max_iterations), initial_paths=initial_paths, accumulated_expanded_nodes=[], - best_results={}, - best_completed_nets=-1, - best_conflict_edges=10**9, - best_dynamic_collisions=10**9, - last_conflict_signature=(), - last_conflict_edge_count=0, - repeated_conflict_count=0, ) if state.initial_paths is None and congestion.warm_start_enabled: state.initial_paths = self._build_greedy_warm_start_paths(net_specs, congestion.net_order) @@ -214,536 +160,9 @@ class PathFinder: net_width=net.width, search=search, clearance=self.context.cost_evaluator.collision_engine.clearance, - ) + ) return initial_paths - def _replace_installed_paths(self, state: _RoutingState, results: dict[str, RoutingResult]) -> None: - for net_id in state.ordered_net_ids: - self.context.cost_evaluator.collision_engine.remove_path(net_id) - for net_id in state.ordered_net_ids: - result = results.get(net_id) - if result and result.path: - self._install_path(net_id, result.path) - - def _update_best_iteration(self, state: _RoutingState, review: _IterationReview) -> bool: - completed_nets = len(review.completed_net_ids) - conflict_edges = len(review.conflict_edges) - dynamic_collisions = review.total_dynamic_collisions - is_better = ( - completed_nets > state.best_completed_nets - or ( - completed_nets == state.best_completed_nets - and ( - conflict_edges < state.best_conflict_edges - or ( - conflict_edges == state.best_conflict_edges - and dynamic_collisions < state.best_dynamic_collisions - ) - ) - ) - ) - if not is_better: - return False - - state.best_results = dict(state.results) - state.best_completed_nets = completed_nets - state.best_conflict_edges = conflict_edges - state.best_dynamic_collisions = dynamic_collisions - return True - - def _restore_best_iteration(self, state: _RoutingState) -> None: - if not state.best_results: - return - state.results = dict(state.best_results) - self._replace_installed_paths(state, state.results) - - def _capture_conflict_trace_entry( - self, - state: _RoutingState, - *, - stage: str, - iteration: int | None, - results: dict[str, RoutingResult], - details_by_net: dict[str, PathVerificationDetail], - review: _IterationReview, - ) -> None: - if not self.context.options.diagnostics.capture_conflict_trace: - return - - nets = [] - for net_id in state.ordered_net_ids: - result = results.get(net_id) - if result is None: - result = RoutingResult(net_id=net_id, path=(), reached_target=False) - detail = details_by_net.get(net_id) - component_conflicts = () - conflicting_net_ids = () - if detail is not None: - conflicting_net_ids = detail.conflicting_net_ids - component_conflicts = tuple( - ComponentConflictTrace( - other_net_id=other_net_id, - self_component_index=self_component_index, - other_component_index=other_component_index, - ) - for self_component_index, other_net_id, other_component_index in detail.component_conflicts - ) - nets.append( - NetConflictTrace( - net_id=net_id, - outcome=result.outcome, - reached_target=result.reached_target, - report=result.report, - conflicting_net_ids=tuple(conflicting_net_ids), - component_conflicts=component_conflicts, - ) - ) - - self.conflict_trace.append( - ConflictTraceEntry( - stage=stage, # type: ignore[arg-type] - iteration=iteration, - completed_net_ids=tuple(sorted(review.completed_net_ids)), - conflict_edges=tuple(sorted(review.conflict_edges)), - nets=tuple(nets), - ) - ) - - def _build_frontier_hotspot_bounds( - self, - state: _RoutingState, - net_id: str, - details_by_net: dict[str, PathVerificationDetail], - ) -> tuple[tuple[float, float, float, float], ...]: - result = state.results.get(net_id) - detail = details_by_net.get(net_id) - if result is None or detail is None or not result.path: - return () - - hotspot_bounds: list[tuple[float, float, float, float]] = [] - seen: set[tuple[float, float, float, float]] = set() - margin = max(5.0, self.context.cost_evaluator.collision_engine.clearance * 2.0) - - for self_component_index, other_net_id, other_component_index in detail.component_conflicts: - other_result = state.results.get(other_net_id) - if other_result is None or not other_result.path: - continue - if self_component_index >= len(result.path) or other_component_index >= len(other_result.path): - continue - left_component = result.path[self_component_index] - right_component = other_result.path[other_component_index] - overlap_found = False - for left_poly in left_component.dilated_physical_geometry: - for right_poly in right_component.dilated_physical_geometry: - if not left_poly.intersects(right_poly) or left_poly.touches(right_poly): - continue - overlap = left_poly.intersection(right_poly) - if overlap.is_empty: - continue - buffered = overlap.buffer(margin, join_style="mitre").bounds - if buffered not in seen: - seen.add(buffered) - hotspot_bounds.append(buffered) - overlap_found = True - if overlap_found: - continue - - left_bounds = left_component.total_dilated_bounds - right_bounds = right_component.total_dilated_bounds - if ( - left_bounds[0] < right_bounds[2] - and left_bounds[2] > right_bounds[0] - and left_bounds[1] < right_bounds[3] - and left_bounds[3] > right_bounds[1] - ): - buffered = ( - max(left_bounds[0], right_bounds[0]) - margin, - max(left_bounds[1], right_bounds[1]) - margin, - min(left_bounds[2], right_bounds[2]) + margin, - min(left_bounds[3], right_bounds[3]) + margin, - ) - if buffered not in seen: - seen.add(buffered) - hotspot_bounds.append(buffered) - - return tuple(hotspot_bounds) - - def _analyze_results( - self, - ordered_net_ids: Sequence[str], - results: dict[str, RoutingResult], - *, - capture_component_conflicts: bool, - count_iteration_metrics: bool, - ) -> tuple[dict[str, RoutingResult], dict[str, PathVerificationDetail], _IterationReview]: - if count_iteration_metrics: - self.metrics.total_iteration_reverify_calls += 1 - conflict_edges: set[tuple[str, str]] = set() - conflicting_nets: set[str] = set() - completed_net_ids: set[str] = set() - total_dynamic_collisions = 0 - analyzed_results = dict(results) - details_by_net: dict[str, PathVerificationDetail] = {} - - for net_id in ordered_net_ids: - result = results.get(net_id) - if not result or not result.path or not result.reached_target: - continue - - if count_iteration_metrics: - self.metrics.total_iteration_reverified_nets += 1 - detail = self.context.cost_evaluator.collision_engine.verify_path_details( - net_id, - result.path, - capture_component_conflicts=capture_component_conflicts, - ) - details_by_net[net_id] = detail - analyzed_results[net_id] = RoutingResult( - net_id=net_id, - path=result.path, - reached_target=result.reached_target, - report=detail.report, - ) - total_dynamic_collisions += detail.report.dynamic_collision_count - if analyzed_results[net_id].outcome == "completed": - completed_net_ids.add(net_id) - if not detail.conflicting_net_ids: - continue - conflicting_nets.add(net_id) - for other_net_id in detail.conflicting_net_ids: - conflicting_nets.add(other_net_id) - if other_net_id == net_id: - continue - conflict_edges.add(tuple(sorted((net_id, other_net_id)))) - - if count_iteration_metrics: - self.metrics.total_iteration_conflicting_nets += len(conflicting_nets) - self.metrics.total_iteration_conflict_edges += len(conflict_edges) - return ( - analyzed_results, - details_by_net, - _IterationReview( - conflicting_nets=conflicting_nets, - conflict_edges=conflict_edges, - completed_net_ids=completed_net_ids, - total_dynamic_collisions=total_dynamic_collisions, - ), - ) - - def _capture_frontier_trace( - self, - state: _RoutingState, - final_results: dict[str, RoutingResult], - ) -> None: - if not self.context.options.diagnostics.capture_frontier_trace: - return - - self.frontier_trace = [] - state.results = dict(final_results) - state.results, details_by_net, _ = self._analyze_results( - state.ordered_net_ids, - state.results, - capture_component_conflicts=True, - count_iteration_metrics=False, - ) - - original_metrics = self.metrics - original_context_metrics = self.context.metrics - original_engine_metrics = self.context.cost_evaluator.collision_engine.metrics - original_danger_metrics = None - if self.context.cost_evaluator.danger_map is not None: - original_danger_metrics = self.context.cost_evaluator.danger_map.metrics - - try: - for net_id in state.ordered_net_ids: - result = state.results.get(net_id) - detail = details_by_net.get(net_id) - if result is None or detail is None or not result.reached_target: - continue - if detail.report.dynamic_collision_count == 0 or not detail.component_conflicts: - continue - - hotspot_bounds = self._build_frontier_hotspot_bounds(state, net_id, details_by_net) - if not hotspot_bounds: - continue - - scratch_metrics = AStarMetrics() - self.context.metrics = scratch_metrics - self.context.cost_evaluator.collision_engine.metrics = scratch_metrics - if self.context.cost_evaluator.danger_map is not None: - self.context.cost_evaluator.danger_map.metrics = scratch_metrics - - guidance_seed = result.as_seed().segments if result.path else None - guidance_bonus = 0.0 - if guidance_seed: - guidance_bonus = max(10.0, self.context.options.objective.bend_penalty * 0.25) - collector = FrontierTraceCollector(hotspot_bounds=hotspot_bounds) - run_config = SearchRunConfig.from_options( - self.context.options, - return_partial=True, - store_expanded=False, - guidance_seed=guidance_seed, - guidance_bonus=guidance_bonus, - frontier_trace=collector, - self_collision_check=(net_id in state.needs_self_collision_check), - node_limit=self.context.options.search.node_limit, - ) - - self.context.cost_evaluator.collision_engine.remove_path(net_id) - try: - route_astar( - state.net_specs[net_id].start, - state.net_specs[net_id].target, - state.net_specs[net_id].width, - context=self.context, - metrics=scratch_metrics, - net_id=net_id, - config=run_config, - ) - finally: - if result.path: - self._install_path(net_id, result.path) - - self.frontier_trace.append( - NetFrontierTrace( - net_id=net_id, - hotspot_bounds=hotspot_bounds, - pruned_closed_set=collector.pruned_closed_set, - pruned_hard_collision=collector.pruned_hard_collision, - pruned_self_collision=collector.pruned_self_collision, - pruned_cost=collector.pruned_cost, - samples=tuple( - FrontierPruneSample( - reason=reason, # type: ignore[arg-type] - move_type=move_type, - hotspot_index=hotspot_index, - parent_state=parent_state, - end_state=end_state, - ) - for reason, move_type, hotspot_index, parent_state, end_state in collector.samples - ), - ) - ) - finally: - self.metrics = original_metrics - self.context.metrics = original_context_metrics - self.context.cost_evaluator.collision_engine.metrics = original_engine_metrics - if self.context.cost_evaluator.danger_map is not None: - self.context.cost_evaluator.danger_map.metrics = original_danger_metrics - - def _whole_set_is_better( - self, - candidate_results: dict[str, RoutingResult], - candidate_review: _IterationReview, - incumbent_results: dict[str, RoutingResult], - incumbent_review: _IterationReview, - ) -> bool: - candidate_completed = len(candidate_review.completed_net_ids) - incumbent_completed = len(incumbent_review.completed_net_ids) - if candidate_completed != incumbent_completed: - return candidate_completed > incumbent_completed - - candidate_edges = len(candidate_review.conflict_edges) - incumbent_edges = len(incumbent_review.conflict_edges) - if candidate_edges != incumbent_edges: - return candidate_edges < incumbent_edges - - if candidate_review.total_dynamic_collisions != incumbent_review.total_dynamic_collisions: - return candidate_review.total_dynamic_collisions < incumbent_review.total_dynamic_collisions - - candidate_length = sum( - result.report.total_length - for result in candidate_results.values() - if result.reached_target - ) - incumbent_length = sum( - result.report.total_length - for result in incumbent_results.values() - if result.reached_target - ) - if abs(candidate_length - incumbent_length) > 1e-6: - return candidate_length < incumbent_length - return False - - def _collect_pair_local_targets( - self, - state: _RoutingState, - results: dict[str, RoutingResult], - review: _IterationReview, - ) -> list[_PairLocalTarget]: - if not review.conflict_edges: - return [] - order_index = {net_id: idx for idx, net_id in enumerate(state.ordered_net_ids)} - seen_net_ids: set[str] = set() - targets: list[_PairLocalTarget] = [] - for left_net_id, right_net_id in sorted(review.conflict_edges): - if left_net_id in seen_net_ids or right_net_id in seen_net_ids: - return [] - left_result = results.get(left_net_id) - right_result = results.get(right_net_id) - if ( - left_result is None - or right_result is None - or not left_result.reached_target - or not right_result.reached_target - ): - continue - seen_net_ids.update((left_net_id, right_net_id)) - targets.append(_PairLocalTarget(net_ids=(left_net_id, right_net_id))) - targets.sort(key=lambda target: min(order_index[target.net_ids[0]], order_index[target.net_ids[1]])) - return targets - - def _build_pair_local_context( - self, - state: _RoutingState, - incumbent_results: dict[str, RoutingResult], - pair_net_ids: tuple[str, str], - ) -> AStarContext: - problem = self.context.problem - objective = self.context.options.objective - static_obstacles = tuple(self.context.cost_evaluator.collision_engine._static_obstacles.geometries.values()) - engine = RoutingWorld( - clearance=self.context.cost_evaluator.collision_engine.clearance, - safety_zone_radius=self.context.cost_evaluator.collision_engine.safety_zone_radius, - ) - for obstacle in static_obstacles: - engine.add_static_obstacle(obstacle) - for net_id in state.ordered_net_ids: - if net_id in pair_net_ids: - continue - result = incumbent_results.get(net_id) - if result is None or not result.path: - continue - for component in result.path: - for polygon in component.physical_geometry: - engine.add_static_obstacle(polygon) - - danger_map = DangerMap(bounds=problem.bounds) - danger_map.precompute(list(static_obstacles)) - evaluator = CostEvaluator( - engine, - danger_map, - unit_length_cost=objective.unit_length_cost, - greedy_h_weight=self.context.cost_evaluator.greedy_h_weight, - bend_penalty=objective.bend_penalty, - sbend_penalty=objective.sbend_penalty, - danger_weight=objective.danger_weight, - ) - return AStarContext( - evaluator, - RoutingProblem( - bounds=problem.bounds, - nets=tuple(state.net_specs[net_id] for net_id in state.ordered_net_ids), - static_obstacles=static_obstacles, - clearance=problem.clearance, - safety_zone_radius=problem.safety_zone_radius, - ), - self.context.options, - metrics=AStarMetrics(), - ) - - def _run_pair_local_attempt( - self, - state: _RoutingState, - incumbent_results: dict[str, RoutingResult], - pair_order: tuple[str, str], - ) -> tuple[dict[str, RoutingResult], int] | None: - local_context = self._build_pair_local_context(state, incumbent_results, pair_order) - local_results = dict(incumbent_results) - - for net_id in pair_order: - net = state.net_specs[net_id] - guidance_result = incumbent_results.get(net_id) - guidance_seed = None - guidance_bonus = 0.0 - if guidance_result and guidance_result.reached_target and guidance_result.path: - guidance_seed = guidance_result.as_seed().segments - guidance_bonus = max(10.0, self.context.options.objective.bend_penalty * 0.25) - - run_config = SearchRunConfig.from_options( - self.context.options, - return_partial=False, - skip_congestion=True, - self_collision_check=(net_id in state.needs_self_collision_check), - guidance_seed=guidance_seed, - guidance_bonus=guidance_bonus, - node_limit=self.context.options.search.node_limit, - ) - path = route_astar( - net.start, - net.target, - net.width, - context=local_context, - metrics=local_context.metrics, - net_id=net_id, - config=run_config, - ) - if not path or path[-1].end_port != net.target: - return None - - report = local_context.cost_evaluator.collision_engine.verify_path_report(net_id, path) - if not report.is_valid: - return None - local_results[net_id] = RoutingResult( - net_id=net_id, - path=tuple(path), - reached_target=True, - report=report, - ) - for component in path: - for polygon in component.physical_geometry: - local_context.cost_evaluator.collision_engine.add_static_obstacle(polygon) - local_context.clear_static_caches() - - return local_results, local_context.metrics.total_nodes_expanded - - def _run_pair_local_search(self, state: _RoutingState) -> None: - state.results, _details_by_net, review = self._analyze_results( - state.ordered_net_ids, - state.results, - capture_component_conflicts=True, - count_iteration_metrics=False, - ) - targets = self._collect_pair_local_targets(state, state.results, review) - if not targets: - return - - for target in targets[:2]: - self.metrics.total_pair_local_search_pairs_considered += 1 - incumbent_results = dict(state.results) - incumbent_review = review - accepted = False - for pair_order in (target.net_ids, target.net_ids[::-1]): - self.metrics.total_pair_local_search_attempts += 1 - candidate = self._run_pair_local_attempt(state, incumbent_results, pair_order) - if candidate is None: - continue - candidate_results, nodes_expanded = candidate - self.metrics.total_pair_local_search_nodes_expanded += nodes_expanded - self._replace_installed_paths(state, candidate_results) - candidate_results, _candidate_details_by_net, candidate_review = self._analyze_results( - state.ordered_net_ids, - candidate_results, - capture_component_conflicts=True, - count_iteration_metrics=False, - ) - if self._whole_set_is_better( - candidate_results, - candidate_review, - incumbent_results, - incumbent_review, - ): - self.metrics.total_pair_local_search_accepts += 1 - state.results = candidate_results - review = candidate_review - accepted = True - break - self._replace_installed_paths(state, incumbent_results) - - if not accepted: - state.results = incumbent_results - self._replace_installed_paths(state, incumbent_results) - def _route_net_once( self, state: _RoutingState, @@ -763,25 +182,16 @@ class PathFinder: else: coll_model, _ = resolve_bend_geometry(search) skip_congestion = False - guidance_seed = None - guidance_bonus = 0.0 if congestion.use_tiered_strategy and iteration == 0: skip_congestion = True if coll_model == "arc": coll_model = "clipped_bbox" - elif iteration > 0: - guidance_result = state.results.get(net_id) - if guidance_result and guidance_result.reached_target and guidance_result.path: - guidance_seed = guidance_result.as_seed().segments - guidance_bonus = max(10.0, self.context.options.objective.bend_penalty * 0.25) run_config = SearchRunConfig.from_options( self.context.options, bend_collision_type=coll_model, return_partial=True, store_expanded=diagnostics.capture_expanded, - guidance_seed=guidance_seed, - guidance_bonus=guidance_bonus, skip_congestion=skip_congestion, self_collision_check=(net_id in state.needs_self_collision_check), node_limit=search.node_limit, @@ -823,49 +233,29 @@ class PathFinder: self, state: _RoutingState, iteration: int, - reroute_net_ids: set[str], iteration_callback: Callable[[int, dict[str, RoutingResult]], None] | None, - ) -> _IterationReview | None: + ) -> dict[str, RoutingOutcome] | None: + outcomes: dict[str, RoutingOutcome] = {} congestion = self.context.options.congestion self.metrics.total_route_iterations += 1 self.metrics.reset_per_route() + if congestion.shuffle_nets and (iteration > 0 or state.initial_paths is None): iteration_seed = (congestion.seed + iteration) if congestion.seed is not None else None random.Random(iteration_seed).shuffle(state.ordered_net_ids) - routed_net_ids = [net_id for net_id in state.ordered_net_ids if net_id in reroute_net_ids] - self.metrics.total_nets_carried_forward += len(state.ordered_net_ids) - len(routed_net_ids) - - for net_id in routed_net_ids: + for net_id in state.ordered_net_ids: if time.monotonic() - state.start_time > state.timeout_s: self.metrics.total_timeout_events += 1 return None result = self._route_net_once(state, iteration, net_id) state.results[net_id] = result - - review = self._reverify_iteration_results(state) + outcomes[net_id] = result.outcome if iteration_callback: iteration_callback(iteration, state.results) - return review - - def _reverify_iteration_results(self, state: _RoutingState) -> _IterationReview: - state.results, details_by_net, review = self._analyze_results( - state.ordered_net_ids, - state.results, - capture_component_conflicts=self.context.options.diagnostics.capture_conflict_trace, - count_iteration_metrics=True, - ) - self._capture_conflict_trace_entry( - state, - stage="iteration", - iteration=self.metrics.total_route_iterations - 1, - results=state.results, - details_by_net=details_by_net, - review=review, - ) - return review + return outcomes def _run_iterations( self, @@ -874,33 +264,10 @@ class PathFinder: ) -> bool: congestion = self.context.options.congestion for iteration in range(congestion.max_iterations): - review = self._run_iteration( - state, - iteration, - set(state.ordered_net_ids), - iteration_callback, - ) - if review is None: + outcomes = self._run_iteration(state, iteration, iteration_callback) + if outcomes is None: return True - self._update_best_iteration(state, review) - if not any( - result.outcome in {"colliding", "partial", "unroutable"} - for result in state.results.values() - ): - return False - - current_signature = tuple(sorted(review.conflict_edges)) - repeated = ( - bool(current_signature) - and ( - current_signature == state.last_conflict_signature - or len(current_signature) == state.last_conflict_edge_count - ) - ) - state.repeated_conflict_count = state.repeated_conflict_count + 1 if repeated else 0 - state.last_conflict_signature = current_signature - state.last_conflict_edge_count = len(current_signature) - if state.repeated_conflict_count >= 2: + if not any(outcome in {"colliding", "partial", "unroutable"} for outcome in outcomes.values()): return False self.context.congestion_penalty *= congestion.multiplier return False @@ -918,49 +285,27 @@ class PathFinder: self.context.cost_evaluator.collision_engine.remove_path(net_id) refined_path = self.refiner.refine_path(net_id, net.start, net.width, result.path) self._install_path(net_id, refined_path) - # Defer full verification until _verify_results() so we do not - # verify the same refined path twice in one route_all() call. + report = self.context.cost_evaluator.collision_engine.verify_path_report(net_id, refined_path) state.results[net_id] = RoutingResult( net_id=net_id, path=tuple(refined_path), reached_target=result.reached_target, - report=result.report, + report=report, ) def _verify_results(self, state: _RoutingState) -> dict[str, RoutingResult]: final_results: dict[str, RoutingResult] = {} - details_by_net: dict[str, PathVerificationDetail] = {} for net in self.context.problem.nets: result = state.results.get(net.net_id) if not result or not result.path: final_results[net.net_id] = RoutingResult(net_id=net.net_id, path=(), reached_target=False) continue - detail = self.context.cost_evaluator.collision_engine.verify_path_details( - net.net_id, - result.path, - capture_component_conflicts=self.context.options.diagnostics.capture_conflict_trace, - ) - details_by_net[net.net_id] = detail + report = self.context.cost_evaluator.collision_engine.verify_path_report(net.net_id, result.path) final_results[net.net_id] = RoutingResult( net_id=net.net_id, path=result.path, reached_target=result.reached_target, - report=detail.report, - ) - if self.context.options.diagnostics.capture_conflict_trace: - _, _, review = self._analyze_results( - state.ordered_net_ids, - final_results, - capture_component_conflicts=True, - count_iteration_metrics=False, - ) - self._capture_conflict_trace_entry( - state, - stage="final", - iteration=None, - results=final_results, - details_by_net=details_by_net, - review=review, + report=report, ) return final_results @@ -971,38 +316,15 @@ class PathFinder: ) -> dict[str, RoutingResult]: self.context.congestion_penalty = self.context.options.congestion.base_penalty self.accumulated_expanded_nodes = [] - self.conflict_trace = [] - self.frontier_trace = [] self.metrics.reset_totals() self.metrics.reset_per_route() state = self._prepare_state() timed_out = self._run_iterations(state, iteration_callback) self.accumulated_expanded_nodes = list(state.accumulated_expanded_nodes) - self._restore_best_iteration(state) - if self.context.options.diagnostics.capture_conflict_trace: - state.results, details_by_net, review = self._analyze_results( - state.ordered_net_ids, - state.results, - capture_component_conflicts=True, - count_iteration_metrics=False, - ) - self._capture_conflict_trace_entry( - state, - stage="restored_best", - iteration=None, - results=state.results, - details_by_net=details_by_net, - review=review, - ) if timed_out: - final_results = self._verify_results(state) - self._capture_frontier_trace(state, final_results) - return final_results + return self._verify_results(state) - self._run_pair_local_search(state) self._refine_results(state) - final_results = self._verify_results(state) - self._capture_frontier_trace(state, final_results) - return final_results + return self._verify_results(state) diff --git a/inire/router/_search.py b/inire/router/_search.py index 92fc540..8e7a0ab 100644 --- a/inire/router/_search.py +++ b/inire/router/_search.py @@ -41,17 +41,11 @@ def route_astar( open_set: list[_AStarNode] = [] closed_set: dict[tuple[int, int, int], float] = {} congestion_cache: dict[tuple, int] = {} - congestion_presence_cache: dict[tuple[str, int, int, int, int], bool] = {} - congestion_candidate_precheck_cache: dict[tuple[str, int, int, int, int], bool] = {} - congestion_net_envelope_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]] = {} - congestion_grid_net_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]] = {} - congestion_grid_span_cache: dict[tuple[str, int, int, int, int], dict[str, tuple[int, ...]]] = {} start_node = _AStarNode( start, 0.0, context.cost_evaluator.h_manhattan(start, target, min_bend_radius=context.min_bend_radius), - seed_index=0 if config.guidance_seed else None, ) heapq.heappush(open_set, start_node) best_node = start_node @@ -95,11 +89,6 @@ def route_astar( context, metrics, congestion_cache, - congestion_presence_cache, - congestion_candidate_precheck_cache, - congestion_net_envelope_cache, - congestion_grid_net_cache, - congestion_grid_span_cache, config=config, ) diff --git a/inire/router/cost.py b/inire/router/cost.py index 3bb4765..eaf9d66 100644 --- a/inire/router/cost.py +++ b/inire/router/cost.py @@ -1,6 +1,5 @@ from __future__ import annotations -from time import perf_counter_ns from typing import TYPE_CHECKING import numpy as np @@ -131,16 +130,10 @@ class CostEvaluator: start_port: Port | None = None, weights: ObjectiveWeights | None = None, ) -> float: - metrics = self.collision_engine.metrics - if metrics is not None: - metrics.total_score_component_calls += 1 - start_ns = perf_counter_ns() active_weights = self._resolve_weights(weights) danger_map = self.danger_map end_port = component.end_port if danger_map is not None and not danger_map.is_within_bounds(end_port.x, end_port.y): - if metrics is not None: - metrics.total_score_component_total_ns += perf_counter_ns() - start_ns return 1e15 move_radius = None @@ -152,8 +145,7 @@ class CostEvaluator: weights=active_weights, ) - # Skip danger sampling entirely when there are no static obstacles in the KD-tree. - if danger_map is not None and active_weights.danger_weight and danger_map.tree is not None: + if danger_map is not None and active_weights.danger_weight: cost_s = danger_map.get_cost(start_port.x, start_port.y) if start_port else 0.0 cost_e = danger_map.get_cost(end_port.x, end_port.y) if start_port: @@ -163,8 +155,6 @@ class CostEvaluator: total_cost += component.length * active_weights.danger_weight * (cost_s + cost_m + cost_e) / 3.0 else: total_cost += component.length * active_weights.danger_weight * cost_e - if metrics is not None: - metrics.total_score_component_total_ns += perf_counter_ns() - start_ns return total_cost def component_penalty( @@ -191,9 +181,6 @@ class CostEvaluator: *, weights: ObjectiveWeights | None = None, ) -> float: - metrics = self.collision_engine.metrics - if metrics is not None: - metrics.total_path_cost_calls += 1 active_weights = self._resolve_weights(weights) total = 0.0 current_port = start_port diff --git a/inire/router/danger_map.py b/inire/router/danger_map.py index c9ca9d3..12b3b14 100644 --- a/inire/router/danger_map.py +++ b/inire/router/danger_map.py @@ -1,7 +1,6 @@ from __future__ import annotations from collections import OrderedDict -from time import perf_counter_ns from typing import TYPE_CHECKING import numpy @@ -9,7 +8,6 @@ from scipy.spatial import cKDTree if TYPE_CHECKING: from shapely.geometry import Polygon - from inire.router._astar_types import AStarMetrics _COST_CACHE_SIZE = 100000 @@ -20,7 +18,7 @@ class DangerMap: A proximity cost evaluator using a KD-Tree of obstacle boundary points. Scales with obstacle perimeter rather than design area. """ - __slots__ = ('minx', 'miny', 'maxx', 'maxy', 'resolution', 'safety_threshold', 'k', 'tree', '_cost_cache', 'metrics') + __slots__ = ('minx', 'miny', 'maxx', 'maxy', 'resolution', 'safety_threshold', 'k', 'tree', '_cost_cache') def __init__( self, @@ -44,7 +42,6 @@ class DangerMap: self.k = k self.tree: cKDTree | None = None self._cost_cache: OrderedDict[tuple[int, int], float] = OrderedDict() - self.metrics: AStarMetrics | None = None def precompute(self, obstacles: list[Polygon]) -> None: """ @@ -85,28 +82,17 @@ class DangerMap: Get the proximity cost at a specific coordinate using the KD-Tree. Coordinates are quantized to 1nm to improve cache performance. """ - metrics = self.metrics - if metrics is not None: - metrics.total_danger_map_lookup_calls += 1 - start_ns = perf_counter_ns() qx_milli = int(round(x * 1000)) qy_milli = int(round(y * 1000)) key = (qx_milli, qy_milli) if key in self._cost_cache: - if metrics is not None: - metrics.total_danger_map_cache_hits += 1 - metrics.total_danger_map_total_ns += perf_counter_ns() - start_ns self._cost_cache.move_to_end(key) return self._cost_cache[key] - if metrics is not None: - metrics.total_danger_map_cache_misses += 1 cost = self._compute_cost_quantized(qx_milli, qy_milli) self._cost_cache[key] = cost if len(self._cost_cache) > _COST_CACHE_SIZE: self._cost_cache.popitem(last=False) - if metrics is not None: - metrics.total_danger_map_total_ns += perf_counter_ns() - start_ns return cost def _compute_cost_quantized(self, qx_milli: int, qy_milli: int) -> float: @@ -116,8 +102,6 @@ class DangerMap: return 1e15 if self.tree is None: return 0.0 - if self.metrics is not None: - self.metrics.total_danger_map_query_calls += 1 dist, _ = self.tree.query([qx, qy], distance_upper_bound=self.safety_threshold) if dist >= self.safety_threshold: return 0.0 diff --git a/inire/router/refiner.py b/inire/router/refiner.py index 5f3a6c2..ee9c9e9 100644 --- a/inire/router/refiner.py +++ b/inire/router/refiner.py @@ -128,7 +128,6 @@ class PathRefiner: x_max = max(0.0, float(local_dx)) + 0.01 for bounds in self.collision_engine.iter_static_obstacle_bounds(query_bounds): - self.context.metrics.total_refinement_static_bounds_checked += 1 local_corners = ( self._to_local_xy(start, bounds[0], bounds[1]), self._to_local_xy(start, bounds[0], bounds[3]), @@ -145,7 +144,6 @@ class PathRefiner: negative_anchors.add(obs_min_y) for bounds in self.collision_engine.iter_dynamic_path_bounds(query_bounds): - self.context.metrics.total_refinement_dynamic_bounds_checked += 1 local_corners = ( self._to_local_xy(start, bounds[0], bounds[1]), self._to_local_xy(start, bounds[0], bounds[3]), @@ -168,7 +166,6 @@ class PathRefiner: if anchor < min(0.0, float(local_dy)) + 0.01: direct_extents.add(anchor - pad) - self.context.metrics.total_refinement_candidate_side_extents += len(direct_extents) return sorted(direct_extents, key=lambda value: (abs(value), value)) def _build_same_orientation_dogleg( @@ -246,7 +243,6 @@ class PathRefiner: local_dx, _ = self._to_local(window_start, window_end) if local_dx < 4.0 * min_radius - 0.01: continue - self.context.metrics.total_refinement_windows_considered += 1 windows.append((start_idx, end_idx)) return windows @@ -274,15 +270,12 @@ class PathRefiner: replacement = self._build_same_orientation_dogleg(window_start, window_end, net_width, radius, side_extent) if replacement is None: continue - self.context.metrics.total_refinement_candidates_built += 1 candidate_path = path[:start_idx] + replacement + path[end_idx:] - self.context.metrics.total_refinement_candidates_verified += 1 report = self.collision_engine.verify_path_report(net_id, candidate_path) if not report.is_valid: continue candidate_cost = self.path_cost(candidate_path) if candidate_cost + 1e-6 < best_candidate_cost: - self.context.metrics.total_refinement_candidates_accepted += 1 best_candidate_cost = candidate_cost best_path = candidate_path diff --git a/inire/router/visibility.py b/inire/router/visibility.py index ea4b610..4fc51ed 100644 --- a/inire/router/visibility.py +++ b/inire/router/visibility.py @@ -16,15 +16,7 @@ class VisibilityManager: """ Manages corners of static obstacles for sparse A* / Visibility Graph jumps. """ - __slots__ = ( - "collision_engine", - "corners", - "corner_index", - "_corner_graph", - "_point_visibility_cache", - "_corner_index_version", - "_corner_graph_version", - ) + __slots__ = ("collision_engine", "corners", "corner_index", "_corner_graph", "_point_visibility_cache", "_built_static_version") def __init__(self, collision_engine: RoutingWorld) -> None: self.collision_engine = collision_engine @@ -32,8 +24,8 @@ class VisibilityManager: self.corner_index = rtree.index.Index() self._corner_graph: dict[int, list[tuple[float, float, float]]] = {} self._point_visibility_cache: dict[tuple[int, int, int], list[tuple[float, float, float]]] = {} - self._corner_index_version = -1 - self._corner_graph_version = -1 + self._built_static_version = -1 + self._build() def clear_cache(self) -> None: """ @@ -43,31 +35,19 @@ class VisibilityManager: self.corner_index = rtree.index.Index() self._corner_graph = {} self._point_visibility_cache = {} - self._corner_index_version = -1 - self._corner_graph_version = -1 - - def ensure_corner_index_current(self) -> None: - if self._corner_index_version != self.collision_engine.get_static_version(): - self._build_corner_index() - - def ensure_corner_graph_current(self) -> None: - self.ensure_corner_index_current() - static_version = self.collision_engine.get_static_version() - if self._corner_graph_version != static_version: - self._build_corner_graph() + self._build() def _ensure_current(self) -> None: - self.ensure_corner_graph_current() + if self._built_static_version != self.collision_engine.get_static_version(): + self.clear_cache() - def _build_corner_index(self) -> None: + def _build(self) -> None: + """ + Extract corners and pre-compute corner-to-corner visibility. + """ if self.collision_engine.metrics is not None: - self.collision_engine.metrics.total_visibility_corner_index_builds += 1 - self.corners = [] - self.corner_index = rtree.index.Index() - self._corner_graph = {} - self._point_visibility_cache = {} - self._corner_graph_version = -1 - self._corner_index_version = self.collision_engine.get_static_version() + self.collision_engine.metrics.total_visibility_builds += 1 + self._built_static_version = self.collision_engine.get_static_version() raw_corners = [] for poly in self.collision_engine.iter_static_dilated_geometries(): coords = list(poly.exterior.coords) @@ -83,6 +63,7 @@ class VisibilityManager: if not raw_corners: return + # Deduplicate repeated corner coordinates seen = set() for x, y in raw_corners: sx, sy = round(x, 3), round(y, 3) @@ -90,27 +71,15 @@ class VisibilityManager: seen.add((sx, sy)) self.corners.append((sx, sy)) + # Build spatial index for corners for i, (x, y) in enumerate(self.corners): self.corner_index.insert(i, (x, y, x, y)) - def _build_corner_graph(self) -> None: - """ - Pre-compute corner-to-corner visibility from the current corner index. - """ - self.ensure_corner_index_current() - if self.collision_engine.metrics is not None: - self.collision_engine.metrics.total_visibility_builds += 1 - self._corner_graph = {} - self._corner_graph_version = self.collision_engine.get_static_version() - - if not self.corners: - return - # Pre-compute visibility graph between corners num_corners = len(self.corners) if num_corners > 200: - # Limit pre-computation if too many corners - return + # Limit pre-computation if too many corners + return for i in range(num_corners): self._corner_graph[i] = [] @@ -124,12 +93,11 @@ class VisibilityManager: dx, dy = cx - p1.x, cy - p1.y dist = numpy.sqrt(dx**2 + dy**2) angle = numpy.degrees(numpy.arctan2(dy, dx)) - reach = self.collision_engine.ray_cast(p1, angle, max_dist=dist + 0.05, caller="visibility_build") + reach = self.collision_engine.ray_cast(p1, angle, max_dist=dist + 0.05) if reach >= dist - 0.01: self._corner_graph[i].append((cx, cy, dist)) def _corner_idx_at(self, origin: Port) -> int | None: - self.ensure_corner_index_current() ox, oy = round(origin.x, 3), round(origin.y, 3) nearby = list(self.corner_index.intersection((ox - 0.001, oy - 0.001, ox + 0.001, oy + 0.001))) for idx in nearby: @@ -138,49 +106,6 @@ class VisibilityManager: return idx return None - def get_tangent_corner_candidates( - self, - origin: Port, - *, - min_forward: float, - max_forward: float, - radii: tuple[float, ...], - tolerance: float = 2.0, - ) -> list[int]: - self.ensure_corner_index_current() - if max_forward <= min_forward or not radii or not self.corners: - return [] - - candidate_ids: set[int] = set() - x0 = float(origin.x) - y0 = float(origin.y) - - def _add_hits(bounds: tuple[float, float, float, float]) -> None: - min_x, min_y, max_x, max_y = bounds - if min_x > max_x or min_y > max_y: - return - candidate_ids.update(self.corner_index.intersection(bounds)) - - for radius in radii: - if origin.r == 0: - x_bounds = (x0 + min_forward, x0 + max_forward) - _add_hits((x_bounds[0], y0 + radius - tolerance, x_bounds[1], y0 + radius + tolerance)) - _add_hits((x_bounds[0], y0 - radius - tolerance, x_bounds[1], y0 - radius + tolerance)) - elif origin.r == 180: - x_bounds = (x0 - max_forward, x0 - min_forward) - _add_hits((x_bounds[0], y0 + radius - tolerance, x_bounds[1], y0 + radius + tolerance)) - _add_hits((x_bounds[0], y0 - radius - tolerance, x_bounds[1], y0 - radius + tolerance)) - elif origin.r == 90: - y_bounds = (y0 + min_forward, y0 + max_forward) - _add_hits((x0 + radius - tolerance, y_bounds[0], x0 + radius + tolerance, y_bounds[1])) - _add_hits((x0 - radius - tolerance, y_bounds[0], x0 - radius + tolerance, y_bounds[1])) - else: - y_bounds = (y0 - max_forward, y0 - min_forward) - _add_hits((x0 + radius - tolerance, y_bounds[0], x0 + radius + tolerance, y_bounds[1])) - _add_hits((x0 - radius - tolerance, y_bounds[0], x0 - radius + tolerance, y_bounds[1])) - - return sorted(candidate_ids) - def get_point_visibility(self, origin: Port, max_dist: float = 1000.0) -> list[tuple[float, float, float]]: """ Find visible corners from an arbitrary point. @@ -188,13 +113,11 @@ class VisibilityManager: """ if self.collision_engine.metrics is not None: self.collision_engine.metrics.total_visibility_point_queries += 1 - self.ensure_corner_index_current() + self._ensure_current() if max_dist < 0: return [] corner_idx = self._corner_idx_at(origin) - if corner_idx is not None: - self.ensure_corner_graph_current() if corner_idx is not None and corner_idx in self._corner_graph: return [corner for corner in self._corner_graph[corner_idx] if corner[2] <= max_dist] @@ -220,7 +143,7 @@ class VisibilityManager: continue angle = numpy.degrees(numpy.arctan2(dy, dx)) - reach = self.collision_engine.ray_cast(origin, angle, max_dist=dist + 0.05, caller="visibility_query") + reach = self.collision_engine.ray_cast(origin, angle, max_dist=dist + 0.05) if reach >= dist - 0.01: visible.append((cx, cy, dist)) @@ -233,14 +156,14 @@ class VisibilityManager: This avoids the expensive arbitrary-point visibility scan in hot search paths. """ if self.collision_engine.metrics is not None: - self.collision_engine.metrics.total_visibility_corner_queries_exact += 1 - self.ensure_corner_graph_current() + self.collision_engine.metrics.total_visibility_corner_queries += 1 + self._ensure_current() if max_dist < 0: return [] corner_idx = self._corner_idx_at(origin) if corner_idx is not None and corner_idx in self._corner_graph: if self.collision_engine.metrics is not None: - self.collision_engine.metrics.total_visibility_corner_hits_exact += 1 + self.collision_engine.metrics.total_visibility_corner_hits += 1 return [corner for corner in self._corner_graph[corner_idx] if corner[2] <= max_dist] return [] diff --git a/inire/tests/example_scenarios.py b/inire/tests/example_scenarios.py index c7feb84..02cab01 100644 --- a/inire/tests/example_scenarios.py +++ b/inire/tests/example_scenarios.py @@ -15,7 +15,6 @@ from inire import ( RoutingOptions, RoutingProblem, RoutingResult, - RoutingRunResult, SearchOptions, ) from inire.geometry.collision import RoutingWorld @@ -35,7 +34,6 @@ _OBJECTIVE_FIELDS = set(ObjectiveWeights.__dataclass_fields__) ScenarioOutcome = tuple[float, int, int, int] ScenarioRun = Callable[[], ScenarioOutcome] ScenarioSnapshotRun = Callable[[], "ScenarioSnapshot"] -TraceScenarioRun = Callable[[], RoutingRunResult] @dataclass(frozen=True, slots=True) @@ -81,19 +79,6 @@ def _make_snapshot( ) -def _make_run_result( - results: dict[str, RoutingResult], - pathfinder: PathFinder, -) -> RoutingRunResult: - return RoutingRunResult( - results_by_net=results, - metrics=pathfinder.metrics.snapshot(), - expanded_nodes=tuple(pathfinder.accumulated_expanded_nodes), - conflict_trace=tuple(pathfinder.conflict_trace), - frontier_trace=tuple(pathfinder.frontier_trace), - ) - - def _sum_metrics(metrics_list: tuple[RouteMetrics, ...]) -> RouteMetrics: metric_names = RouteMetrics.__dataclass_fields__ return RouteMetrics( @@ -333,24 +318,6 @@ def run_example_05() -> ScenarioOutcome: return snapshot_example_05().as_outcome() -def trace_example_05() -> RoutingRunResult: - 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)), - } - widths = dict.fromkeys(netlist, 2.0) - _, _, _, pathfinder = _build_routing_stack( - bounds=(0, 0, 200, 200), - netlist=netlist, - widths=widths, - evaluator_kwargs={"bend_penalty": 50.0}, - request_kwargs={"bend_radii": [20.0], "capture_conflict_trace": True, "capture_frontier_trace": True}, - ) - results = pathfinder.route_all() - return _make_run_result(results, pathfinder) - - def snapshot_example_06() -> ScenarioSnapshot: bounds = (-20, -20, 170, 170) obstacles = [ @@ -411,40 +378,12 @@ def run_example_06() -> ScenarioOutcome: def snapshot_example_07() -> ScenarioSnapshot: - return _snapshot_example_07_variant( - "example_07_large_scale_routing", - warm_start_enabled=True, - ) - - -def snapshot_example_07_no_warm_start() -> ScenarioSnapshot: - return _snapshot_example_07_variant( - "example_07_large_scale_routing_no_warm_start", - warm_start_enabled=False, - ) - - -def trace_example_07() -> RoutingRunResult: - return _trace_example_07_variant(warm_start_enabled=True) - - -def trace_example_07_no_warm_start() -> RoutingRunResult: - return _trace_example_07_variant(warm_start_enabled=False) - - -def _build_example_07_variant_stack( - *, - num_nets: int, - seed: int, - warm_start_enabled: bool, - capture_conflict_trace: bool = False, - capture_frontier_trace: bool = False, -) -> tuple[CostEvaluator, AStarMetrics, PathFinder]: bounds = (0, 0, 1000, 1000) obstacles = [ box(450, 0, 550, 400), box(450, 600, 550, 1000), ] + num_nets = 10 start_x = 50 start_y_base = 500 - (num_nets * 10.0) / 2.0 end_x = 950 @@ -479,31 +418,10 @@ def _build_example_07_variant_stack( "multiplier": 1.4, "net_order": "shortest", "capture_expanded": True, - "capture_conflict_trace": capture_conflict_trace, - "capture_frontier_trace": capture_frontier_trace, "shuffle_nets": True, - "seed": seed, - "warm_start_enabled": warm_start_enabled, + "seed": 42, }, ) - return evaluator, metrics, pathfinder - - -def _run_example_07_variant( - *, - num_nets: int, - seed: int, - warm_start_enabled: bool, - capture_conflict_trace: bool = False, - capture_frontier_trace: bool = False, -) -> RoutingRunResult: - evaluator, metrics, pathfinder = _build_example_07_variant_stack( - num_nets=num_nets, - seed=seed, - warm_start_enabled=warm_start_enabled, - capture_conflict_trace=capture_conflict_trace, - capture_frontier_trace=capture_frontier_trace, - ) def iteration_callback(idx: int, current_results: dict[str, RoutingResult]) -> None: _ = current_results @@ -511,36 +429,10 @@ def _run_example_07_variant( evaluator.greedy_h_weight = new_greedy metrics.reset_per_route() - results = pathfinder.route_all(iteration_callback=iteration_callback) - return _make_run_result(results, pathfinder) - - -def _snapshot_example_07_variant( - name: str, - *, - warm_start_enabled: bool, -) -> ScenarioSnapshot: t0 = perf_counter() - run = _run_example_07_variant( - num_nets=10, - seed=42, - warm_start_enabled=warm_start_enabled, - ) + results = pathfinder.route_all(iteration_callback=iteration_callback) t1 = perf_counter() - return _make_snapshot(name, run.results_by_net, t1 - t0, run.metrics) - - -def _trace_example_07_variant( - *, - warm_start_enabled: bool, -) -> RoutingRunResult: - return _run_example_07_variant( - num_nets=10, - seed=42, - warm_start_enabled=warm_start_enabled, - capture_conflict_trace=True, - capture_frontier_trace=True, - ) + return _make_snapshot("example_07_large_scale_routing", results, t1 - t0, pathfinder.metrics.snapshot()) def run_example_07() -> ScenarioOutcome: @@ -642,19 +534,6 @@ SCENARIO_SNAPSHOTS: tuple[tuple[str, ScenarioSnapshotRun], ...] = ( ("example_09_unroutable_best_effort", snapshot_example_09), ) -PERFORMANCE_SCENARIO_SNAPSHOTS: tuple[tuple[str, ScenarioSnapshotRun], ...] = ( - ("example_07_large_scale_routing_no_warm_start", snapshot_example_07_no_warm_start), -) - -TRACE_SCENARIO_RUNS: tuple[tuple[str, TraceScenarioRun], ...] = ( - ("example_05_orientation_stress", trace_example_05), - ("example_07_large_scale_routing", trace_example_07), -) - -TRACE_PERFORMANCE_SCENARIO_RUNS: tuple[tuple[str, TraceScenarioRun], ...] = ( - ("example_07_large_scale_routing_no_warm_start", trace_example_07_no_warm_start), -) - def capture_all_scenario_snapshots() -> tuple[ScenarioSnapshot, ...]: return tuple(run() for _, run in SCENARIO_SNAPSHOTS) diff --git a/inire/tests/test_api.py b/inire/tests/test_api.py index 0e9fdb3..d25df09 100644 --- a/inire/tests/test_api.py +++ b/inire/tests/test_api.py @@ -16,12 +16,8 @@ from inire import ( route, ) from inire.geometry.components import Straight -from inire.geometry.collision import RoutingWorld -from inire.results import RoutingReport, RoutingResult -from inire.router._astar_types import AStarContext -from inire.router._router import PathFinder, _IterationReview -from inire.router.cost import CostEvaluator -from inire.router.danger_map import DangerMap + + def test_root_module_exports_only_stable_surface() -> None: import inire @@ -52,8 +48,6 @@ def test_route_problem_smoke() -> None: assert set(run.results_by_net) == {"net1"} assert run.results_by_net["net1"].is_valid - assert run.conflict_trace == () - assert run.frontier_trace == () def test_route_problem_supports_configs_and_debug_data() -> None: @@ -83,353 +77,14 @@ def test_route_problem_supports_configs_and_debug_data() -> None: assert run.expanded_nodes assert run.metrics.nodes_expanded > 0 assert run.metrics.route_iterations >= 1 - assert run.metrics.iteration_reverify_calls >= 1 - assert run.metrics.iteration_reverified_nets >= 0 - assert run.metrics.iteration_conflicting_nets >= 0 - assert run.metrics.iteration_conflict_edges >= 0 - assert run.metrics.nets_carried_forward >= 0 assert run.metrics.nets_routed >= 1 assert run.metrics.move_cache_abs_misses >= 0 assert run.metrics.ray_cast_calls >= 0 assert run.metrics.dynamic_tree_rebuilds >= 0 - assert run.metrics.visibility_corner_index_builds >= 0 assert run.metrics.visibility_builds >= 0 - assert run.metrics.guidance_match_moves >= 0 - assert run.metrics.guidance_match_moves_straight >= 0 - assert run.metrics.guidance_match_moves_bend90 >= 0 - assert run.metrics.guidance_match_moves_sbend >= 0 - assert run.metrics.guidance_bonus_applied >= 0.0 - assert run.metrics.guidance_bonus_applied_straight >= 0.0 - assert run.metrics.guidance_bonus_applied_bend90 >= 0.0 - assert run.metrics.guidance_bonus_applied_sbend >= 0.0 - assert run.metrics.congestion_grid_span_cache_hits >= 0 - assert run.metrics.congestion_grid_span_cache_misses >= 0 - assert run.metrics.congestion_presence_cache_hits >= 0 - assert run.metrics.congestion_presence_cache_misses >= 0 - assert run.metrics.congestion_presence_skips >= 0 - assert run.metrics.congestion_candidate_precheck_hits >= 0 - assert run.metrics.congestion_candidate_precheck_misses >= 0 - assert run.metrics.congestion_candidate_precheck_skips >= 0 - assert run.metrics.congestion_candidate_nets >= 0 - assert run.metrics.congestion_net_envelope_cache_hits >= 0 - assert run.metrics.congestion_net_envelope_cache_misses >= 0 - assert run.metrics.congestion_grid_net_cache_hits >= 0 - assert run.metrics.congestion_grid_net_cache_misses >= 0 - assert run.metrics.congestion_lazy_resolutions >= 0 - assert run.metrics.congestion_lazy_requeues >= 0 - assert run.metrics.congestion_candidate_ids >= 0 - assert run.metrics.verify_dynamic_candidate_nets >= 0 assert run.metrics.verify_path_report_calls >= 0 - assert run.metrics.pair_local_search_pairs_considered >= 0 - assert run.metrics.pair_local_search_attempts >= 0 - assert run.metrics.pair_local_search_accepts >= 0 - assert run.metrics.pair_local_search_nodes_expanded >= 0 -def test_iteration_callback_observes_reverified_conflicts() -> None: - problem = RoutingProblem( - bounds=(0, 0, 100, 100), - nets=( - NetSpec("horizontal", Port(10, 50, 0), Port(90, 50, 0), width=2.0), - NetSpec("vertical", Port(50, 10, 90), Port(50, 90, 90), width=2.0), - ), - ) - options = RoutingOptions( - congestion=CongestionOptions(max_iterations=1, warm_start_enabled=False), - refinement=RefinementOptions(enabled=False), - ) - evaluator = CostEvaluator(RoutingWorld(clearance=2.0), DangerMap(bounds=problem.bounds)) - pathfinder = PathFinder(AStarContext(evaluator, problem, options)) - snapshots: list[dict[str, str]] = [] - - def callback(iteration: int, current_results: dict[str, object]) -> None: - _ = iteration - snapshots.append({net_id: result.outcome for net_id, result in current_results.items()}) - - results = pathfinder.route_all(iteration_callback=callback) - - assert snapshots == [{"horizontal": "colliding", "vertical": "colliding"}] - assert results["horizontal"].outcome == "colliding" - assert results["vertical"].outcome == "colliding" - - -def test_capture_conflict_trace_preserves_route_outputs() -> None: - problem = RoutingProblem( - bounds=(0, 0, 100, 100), - nets=( - NetSpec("horizontal", Port(10, 50, 0), Port(90, 50, 0), width=2.0), - NetSpec("vertical", Port(50, 10, 90), Port(50, 90, 90), width=2.0), - ), - ) - base_options = RoutingOptions( - congestion=CongestionOptions(max_iterations=1, warm_start_enabled=False), - refinement=RefinementOptions(enabled=False), - ) - - run_without_trace = route(problem, options=base_options) - run_with_trace = route( - problem, - options=RoutingOptions( - congestion=base_options.congestion, - refinement=base_options.refinement, - diagnostics=DiagnosticsOptions(capture_conflict_trace=True), - ), - ) - - assert {net_id: result.outcome for net_id, result in run_without_trace.results_by_net.items()} == { - net_id: result.outcome for net_id, result in run_with_trace.results_by_net.items() - } - assert [entry.stage for entry in run_with_trace.conflict_trace] == ["iteration", "restored_best", "final"] - - -def test_capture_conflict_trace_records_component_pairs() -> None: - problem = RoutingProblem( - bounds=(0, 0, 100, 100), - nets=( - NetSpec("horizontal", Port(10, 50, 0), Port(90, 50, 0), width=2.0), - NetSpec("vertical", Port(50, 10, 90), Port(50, 90, 90), width=2.0), - ), - ) - options = RoutingOptions( - congestion=CongestionOptions(max_iterations=1, warm_start_enabled=False), - refinement=RefinementOptions(enabled=False), - diagnostics=DiagnosticsOptions(capture_conflict_trace=True), - ) - - run = route(problem, options=options) - final_entry = run.conflict_trace[-1] - trace_by_net = {net.net_id: net for net in final_entry.nets} - - assert final_entry.stage == "final" - assert final_entry.conflict_edges == (("horizontal", "vertical"),) - assert trace_by_net["horizontal"].component_conflicts[0].other_net_id == "vertical" - assert trace_by_net["horizontal"].component_conflicts[0].self_component_index == 0 - assert trace_by_net["horizontal"].component_conflicts[0].other_component_index == 0 - assert trace_by_net["vertical"].component_conflicts[0].other_net_id == "horizontal" - assert trace_by_net["vertical"].component_conflicts[0].self_component_index == 0 - assert trace_by_net["vertical"].component_conflicts[0].other_component_index == 0 - - -def test_capture_frontier_trace_preserves_route_outputs() -> None: - problem = RoutingProblem( - bounds=(0, 0, 100, 100), - nets=( - NetSpec("horizontal", Port(10, 50, 0), Port(90, 50, 0), width=2.0), - NetSpec("vertical", Port(50, 10, 90), Port(50, 90, 90), width=2.0), - ), - ) - base_options = RoutingOptions( - congestion=CongestionOptions(max_iterations=1, warm_start_enabled=False), - refinement=RefinementOptions(enabled=False), - ) - - run_without_trace = route(problem, options=base_options) - run_with_trace = route( - problem, - options=RoutingOptions( - congestion=base_options.congestion, - refinement=base_options.refinement, - diagnostics=DiagnosticsOptions(capture_frontier_trace=True), - ), - ) - - assert {net_id: result.outcome for net_id, result in run_without_trace.results_by_net.items()} == { - net_id: result.outcome for net_id, result in run_with_trace.results_by_net.items() - } - assert {trace.net_id for trace in run_with_trace.frontier_trace} == {"horizontal", "vertical"} - - -def test_capture_frontier_trace_records_prune_reasons() -> None: - problem = RoutingProblem( - bounds=(0, 0, 100, 100), - nets=( - NetSpec("horizontal", Port(10, 50, 0), Port(90, 50, 0), width=2.0), - NetSpec("vertical", Port(50, 10, 90), Port(50, 90, 90), width=2.0), - ), - ) - run = route( - problem, - options=RoutingOptions( - congestion=CongestionOptions(max_iterations=1, warm_start_enabled=False), - refinement=RefinementOptions(enabled=False), - diagnostics=DiagnosticsOptions(capture_frontier_trace=True), - ), - ) - - trace_by_net = {entry.net_id: entry for entry in run.frontier_trace} - assert trace_by_net["horizontal"].hotspot_bounds - assert ( - trace_by_net["horizontal"].pruned_closed_set - + trace_by_net["horizontal"].pruned_hard_collision - + trace_by_net["horizontal"].pruned_self_collision - + trace_by_net["horizontal"].pruned_cost - ) > 0 - assert trace_by_net["horizontal"].samples - - -def test_reverify_iterations_stop_early_on_stalled_conflict_graph() -> None: - problem = RoutingProblem( - bounds=(0, 0, 100, 100), - nets=( - NetSpec("horizontal", Port(10, 50, 0), Port(90, 50, 0), width=2.0), - NetSpec("vertical", Port(50, 10, 90), Port(50, 90, 90), width=2.0), - ), - ) - options = RoutingOptions( - congestion=CongestionOptions(max_iterations=10, warm_start_enabled=False), - refinement=RefinementOptions(enabled=False), - ) - - run = route(problem, options=options) - - assert run.metrics.route_iterations < 10 - - -def test_route_all_restores_best_iteration_snapshot(monkeypatch: pytest.MonkeyPatch) -> None: - problem = RoutingProblem( - bounds=(0, 0, 100, 100), - nets=( - NetSpec("netA", Port(10, 50, 0), Port(90, 50, 0), width=2.0), - NetSpec("netB", Port(50, 10, 90), Port(50, 90, 90), width=2.0), - ), - ) - options = RoutingOptions( - congestion=CongestionOptions(max_iterations=2, warm_start_enabled=False), - refinement=RefinementOptions(enabled=False), - ) - evaluator = CostEvaluator(RoutingWorld(clearance=2.0), DangerMap(bounds=problem.bounds)) - pathfinder = PathFinder(AStarContext(evaluator, problem, options)) - best_result = RoutingResult( - net_id="netA", - path=(Straight.generate(Port(10, 50, 0), 80.0, 2.0, dilation=1.0),), - reached_target=True, - report=RoutingReport(), - ) - missing_result = RoutingResult(net_id="netA", path=(), reached_target=False) - unroutable_b = RoutingResult(net_id="netB", path=(), reached_target=False) - - def fake_run_iteration(self, state, iteration, reroute_net_ids, iteration_callback): - _ = self - _ = reroute_net_ids - _ = iteration_callback - if iteration == 0: - state.results = {"netA": best_result, "netB": unroutable_b} - return _IterationReview( - conflicting_nets={"netA", "netB"}, - conflict_edges={("netA", "netB")}, - completed_net_ids={"netA"}, - total_dynamic_collisions=1, - ) - state.results = {"netA": missing_result, "netB": unroutable_b} - return _IterationReview( - conflicting_nets={"netA", "netB"}, - conflict_edges={("netA", "netB")}, - completed_net_ids=set(), - total_dynamic_collisions=2, - ) - - monkeypatch.setattr(PathFinder, "_run_iteration", fake_run_iteration) - monkeypatch.setattr(PathFinder, "_verify_results", lambda self, state: dict(state.results)) - - results = pathfinder.route_all() - - assert results["netA"].outcome == "completed" - assert results["netB"].outcome == "unroutable" - - -def test_route_all_restores_best_iteration_snapshot_on_timeout(monkeypatch: pytest.MonkeyPatch) -> None: - problem = RoutingProblem( - bounds=(0, 0, 100, 100), - nets=(NetSpec("netA", Port(10, 50, 0), Port(90, 50, 0), width=2.0),), - ) - options = RoutingOptions( - congestion=CongestionOptions(max_iterations=2, warm_start_enabled=False), - refinement=RefinementOptions(enabled=False), - ) - evaluator = CostEvaluator(RoutingWorld(clearance=2.0), DangerMap(bounds=problem.bounds)) - pathfinder = PathFinder(AStarContext(evaluator, problem, options)) - best_result = RoutingResult( - net_id="netA", - path=(Straight.generate(Port(10, 50, 0), 80.0, 2.0, dilation=1.0),), - reached_target=True, - report=RoutingReport(), - ) - worse_result = RoutingResult(net_id="netA", path=(), reached_target=False) - - def fake_run_iterations(self, state, iteration_callback): - _ = iteration_callback - _ = self - state.results = {"netA": best_result} - pathfinder._update_best_iteration( - state, - _IterationReview( - conflicting_nets=set(), - conflict_edges=set(), - completed_net_ids={"netA"}, - total_dynamic_collisions=0, - ), - ) - state.results = {"netA": worse_result} - return True - - monkeypatch.setattr(PathFinder, "_run_iterations", fake_run_iterations) - monkeypatch.setattr(PathFinder, "_verify_results", lambda self, state: dict(state.results)) - - results = pathfinder.route_all() - - assert results["netA"].outcome == "completed" - - -def test_capture_conflict_trace_records_restored_best_stage(monkeypatch: pytest.MonkeyPatch) -> None: - problem = RoutingProblem( - bounds=(0, 0, 100, 100), - nets=(NetSpec("netA", Port(10, 50, 0), Port(90, 50, 0), width=2.0),), - ) - options = RoutingOptions( - congestion=CongestionOptions(max_iterations=2, warm_start_enabled=False), - refinement=RefinementOptions(enabled=False), - diagnostics=DiagnosticsOptions(capture_conflict_trace=True), - ) - evaluator = CostEvaluator(RoutingWorld(clearance=2.0), DangerMap(bounds=problem.bounds)) - pathfinder = PathFinder(AStarContext(evaluator, problem, options)) - best_result = RoutingResult( - net_id="netA", - path=(Straight.generate(Port(10, 50, 0), 80.0, 2.0, dilation=1.0),), - reached_target=True, - report=RoutingReport(), - ) - worse_result = RoutingResult(net_id="netA", path=(), reached_target=False) - - def fake_run_iteration(self, state, iteration, reroute_net_ids, iteration_callback): - _ = self - _ = reroute_net_ids - _ = iteration_callback - if iteration == 0: - state.results = {"netA": best_result} - return _IterationReview( - conflicting_nets=set(), - conflict_edges=set(), - completed_net_ids={"netA"}, - total_dynamic_collisions=0, - ) - state.results = {"netA": worse_result} - return _IterationReview( - conflicting_nets=set(), - conflict_edges=set(), - completed_net_ids=set(), - total_dynamic_collisions=0, - ) - - monkeypatch.setattr(PathFinder, "_run_iteration", fake_run_iteration) - - pathfinder.route_all() - - assert [entry.stage for entry in pathfinder.conflict_trace] == [ - "restored_best", - "final", - ] - restored_entry = pathfinder.conflict_trace[0] - assert restored_entry.nets[0].outcome == "completed" def test_route_problem_locked_routes_become_static_obstacles() -> None: locked = (Straight.generate(Port(10, 50, 0), 80.0, 2.0, dilation=1.0),) problem = RoutingProblem( diff --git a/inire/tests/test_astar.py b/inire/tests/test_astar.py index 3a0382c..3d637b9 100644 --- a/inire/tests/test_astar.py +++ b/inire/tests/test_astar.py @@ -1,22 +1,16 @@ import math + import pytest from shapely.geometry import Polygon -from inire import CongestionOptions, NetSpec, RoutingProblem, RoutingOptions, RoutingResult, SearchOptions +from inire import RoutingProblem, RoutingOptions, RoutingResult, SearchOptions from inire.geometry.components import Bend90, Straight from inire.geometry.collision import RoutingWorld from inire.geometry.primitives import Port -from inire.router._astar_types import AStarContext, AStarNode, SearchRunConfig -from inire.router._astar_admission import add_node -from inire.router._astar_moves import ( - _distance_to_bounds_in_heading, - _should_cap_straights_to_bounds, -) -from inire.router._router import PathFinder, _RoutingState +from inire.router._astar_types import AStarContext, SearchRunConfig from inire.router._search import route_astar from inire.router.cost import CostEvaluator from inire.router.danger_map import DangerMap -from inire.seeds import StraightSeed BOUNDS = (0, -50, 150, 150) @@ -220,84 +214,6 @@ def test_astar_context_keeps_evaluator_weights_separate(basic_evaluator: CostEva assert basic_evaluator.h_manhattan(Port(0, 0, 0), Port(10, 10, 0)) > 0.0 -def test_distance_to_bounds_in_heading_is_directional() -> None: - bounds = (0, 0, 100, 200) - - assert _distance_to_bounds_in_heading(Port(20, 30, 0), bounds) == pytest.approx(80.0) - assert _distance_to_bounds_in_heading(Port(20, 30, 90), bounds) == pytest.approx(170.0) - assert _distance_to_bounds_in_heading(Port(20, 30, 180), bounds) == pytest.approx(20.0) - assert _distance_to_bounds_in_heading(Port(20, 30, 270), bounds) == pytest.approx(30.0) - - -def test_should_cap_straights_to_bounds_only_for_large_no_warm_runs(basic_evaluator: CostEvaluator) -> None: - large_context = AStarContext( - basic_evaluator, - RoutingProblem( - bounds=(0, 0, 1000, 1000), - nets=tuple( - NetSpec(f"net{i}", Port(0, i * 10, 0), Port(10, i * 10, 0), width=2.0) - for i in range(8) - ), - ), - RoutingOptions( - congestion=CongestionOptions(warm_start_enabled=False), - ), - ) - small_context = _build_context(basic_evaluator, bounds=BOUNDS) - - assert _should_cap_straights_to_bounds(large_context) - assert not _should_cap_straights_to_bounds(small_context) - - -def test_pair_local_context_clones_live_static_obstacles() -> None: - obstacle = Polygon([(20, -20), (40, -20), (40, 20), (20, 20)]) - engine = RoutingWorld(clearance=2.0) - engine.add_static_obstacle(obstacle) - danger_map = DangerMap(bounds=BOUNDS) - danger_map.precompute([obstacle]) - evaluator = CostEvaluator(engine, danger_map, bend_penalty=50.0, sbend_penalty=150.0) - finder = PathFinder( - AStarContext( - evaluator, - RoutingProblem( - bounds=BOUNDS, - nets=( - NetSpec("pair_a", Port(0, 0, 0), Port(60, 0, 0), width=2.0), - NetSpec("pair_b", Port(0, 10, 0), Port(60, 10, 0), width=2.0), - ), - ), - RoutingOptions(), - ) - ) - state = _RoutingState( - net_specs={ - "pair_a": NetSpec("pair_a", Port(0, 0, 0), Port(60, 0, 0), width=2.0), - "pair_b": NetSpec("pair_b", Port(0, 10, 0), Port(60, 10, 0), width=2.0), - }, - ordered_net_ids=["pair_a", "pair_b"], - results={}, - needs_self_collision_check=set(), - start_time=0.0, - timeout_s=1.0, - initial_paths=None, - accumulated_expanded_nodes=[], - best_results={}, - best_completed_nets=-1, - best_conflict_edges=10**9, - best_dynamic_collisions=10**9, - last_conflict_signature=(), - last_conflict_edge_count=0, - repeated_conflict_count=0, - ) - - local_context = finder._build_pair_local_context(state, {}, ("pair_a", "pair_b")) - - assert finder.context.problem.static_obstacles == () - assert len(local_context.problem.static_obstacles) == 1 - assert len(local_context.cost_evaluator.collision_engine._static_obstacles.geometries) == 1 - assert next(iter(local_context.problem.static_obstacles)).equals(obstacle) - - def test_route_astar_bend_collision_override_does_not_persist(basic_evaluator: CostEvaluator) -> None: context = _build_context(basic_evaluator, bounds=BOUNDS, bend_radii=(10.0,), bend_collision_type="arc") @@ -385,27 +301,6 @@ def test_route_astar_supports_all_visibility_guidance_modes( assert validation["connectivity_ok"] -def test_tangent_corner_mode_avoids_exact_visibility_graph_builds(basic_evaluator: CostEvaluator) -> None: - obstacle = Polygon([(30, 10), (50, 10), (50, 40), (30, 40)]) - basic_evaluator.collision_engine.add_static_obstacle(obstacle) - basic_evaluator.danger_map.precompute([obstacle]) - context = _build_context( - basic_evaluator, - bounds=BOUNDS, - bend_radii=(10.0,), - sbend_radii=(), - max_straight_length=150.0, - visibility_guidance="tangent_corner", - ) - - path = _route(context, Port(0, 0, 0), Port(80, 50, 0)) - - assert path is not None - assert context.metrics.total_visibility_builds == 0 - assert context.metrics.total_visibility_corner_pairs_checked == 0 - assert context.metrics.total_ray_cast_calls_visibility_build == 0 - - def test_route_astar_repeated_searches_succeed_with_small_cache_limit(basic_evaluator: CostEvaluator) -> None: context = AStarContext( basic_evaluator, @@ -423,244 +318,3 @@ def test_route_astar_repeated_searches_succeed_with_small_cache_limit(basic_eval path = _route(context, start, target) assert path is not None assert path[-1].end_port == target - - -def test_self_collision_prunes_before_congestion_check(basic_evaluator: CostEvaluator) -> None: - context = _build_context(basic_evaluator, bounds=BOUNDS) - root = AStarNode(Port(0, 0, 0), 0.0, 0.0) - parent_result = Straight.generate(Port(0, 0, 0), 10.0, width=2.0, dilation=1.0) - parent = AStarNode(parent_result.end_port, g_cost=10.0, h_cost=0.0, parent=root, component_result=parent_result) - open_set: list[AStarNode] = [] - closed_set: dict[tuple[int, int, int], float] = {} - - add_node( - parent, - parent_result, - target=Port(20, 0, 0), - net_width=2.0, - net_id="netA", - open_set=open_set, - closed_set=closed_set, - context=context, - metrics=context.metrics, - congestion_cache={}, - congestion_presence_cache={}, - congestion_candidate_precheck_cache={}, - congestion_net_envelope_cache={}, - congestion_grid_net_cache={}, - congestion_grid_span_cache={}, - config=SearchRunConfig.from_options(context.options, self_collision_check=True), - move_type="straight", - cache_key=("overlap",), - ) - - assert not open_set - assert context.metrics.total_congestion_check_calls == 0 - assert context.metrics.total_congestion_cache_misses == 0 - - -def test_closed_set_dominance_prunes_before_congestion_check(basic_evaluator: CostEvaluator) -> None: - context = _build_context(basic_evaluator, bounds=BOUNDS) - root = AStarNode(Port(0, 0, 0), 0.0, 0.0) - result = Straight.generate(Port(0, 0, 0), 10.0, width=2.0, dilation=1.0) - open_set: list[AStarNode] = [] - closed_set = {result.end_port.as_tuple(): context.cost_evaluator.score_component(result, start_port=root.port)} - - add_node( - root, - result, - target=Port(20, 0, 0), - net_width=2.0, - net_id="netA", - open_set=open_set, - closed_set=closed_set, - context=context, - metrics=context.metrics, - congestion_cache={}, - congestion_presence_cache={}, - congestion_candidate_precheck_cache={}, - congestion_net_envelope_cache={}, - congestion_grid_net_cache={}, - congestion_grid_span_cache={}, - config=SearchRunConfig.from_options(context.options), - move_type="straight", - cache_key=("dominated",), - ) - - assert not open_set - assert context.metrics.total_congestion_check_calls == 0 - assert context.metrics.total_congestion_cache_misses == 0 - - -def test_no_dynamic_paths_skips_congestion_check(basic_evaluator: CostEvaluator) -> None: - context = _build_context(basic_evaluator, bounds=BOUNDS) - root = AStarNode(Port(0, 0, 0), 0.0, 0.0) - result = Straight.generate(Port(0, 0, 0), 10.0, width=2.0, dilation=1.0) - open_set: list[AStarNode] = [] - closed_set: dict[tuple[int, int, int], float] = {} - - add_node( - root, - result, - target=Port(20, 0, 0), - net_width=2.0, - net_id="netA", - open_set=open_set, - closed_set=closed_set, - context=context, - metrics=context.metrics, - congestion_cache={}, - congestion_presence_cache={}, - congestion_candidate_precheck_cache={}, - congestion_net_envelope_cache={}, - congestion_grid_net_cache={}, - congestion_grid_span_cache={}, - config=SearchRunConfig.from_options(context.options), - move_type="straight", - cache_key=("no-dynamic",), - ) - - assert open_set - assert context.metrics.total_congestion_check_calls == 0 - assert context.metrics.total_congestion_cache_misses == 0 - - -def test_guidance_seed_matching_move_reduces_cost_and_advances_seed_index( - basic_evaluator: CostEvaluator, -) -> None: - context = _build_context(basic_evaluator, bounds=BOUNDS) - root = AStarNode(Port(0, 0, 0), 0.0, 0.0, seed_index=0) - result = Straight.generate(Port(0, 0, 0), 10.0, width=2.0, dilation=1.0) - open_set: list[AStarNode] = [] - unguided_open_set: list[AStarNode] = [] - closed_set: dict[tuple[int, int, int], float] = {} - - add_node( - root, - result, - target=Port(20, 0, 0), - net_width=2.0, - net_id="netA", - open_set=open_set, - closed_set=closed_set, - context=context, - metrics=context.metrics, - congestion_cache={}, - congestion_presence_cache={}, - congestion_candidate_precheck_cache={}, - congestion_net_envelope_cache={}, - congestion_grid_net_cache={}, - congestion_grid_span_cache={}, - config=SearchRunConfig.from_options( - context.options, - guidance_seed=(StraightSeed(length=10.0),), - guidance_bonus=5.0, - ), - move_type="straight", - cache_key=("guided",), - ) - add_node( - AStarNode(Port(0, 0, 0), 0.0, 0.0), - result, - target=Port(20, 0, 0), - net_width=2.0, - net_id="netA", - open_set=unguided_open_set, - closed_set={}, - context=context, - metrics=context.metrics, - congestion_cache={}, - congestion_presence_cache={}, - congestion_candidate_precheck_cache={}, - congestion_net_envelope_cache={}, - congestion_grid_net_cache={}, - congestion_grid_span_cache={}, - config=SearchRunConfig.from_options(context.options), - move_type="straight", - cache_key=("unguided",), - ) - - assert open_set - assert unguided_open_set - guided_node = open_set[0] - unguided_node = unguided_open_set[0] - assert guided_node.seed_index == 1 - assert guided_node.g_cost < unguided_node.g_cost - assert context.metrics.total_guidance_match_moves == 1 - assert context.metrics.total_guidance_match_moves_straight == 1 - assert context.metrics.total_guidance_match_moves_bend90 == 0 - assert context.metrics.total_guidance_match_moves_sbend == 0 - assert context.metrics.total_guidance_bonus_applied == pytest.approx(5.0) - assert context.metrics.total_guidance_bonus_applied_straight == pytest.approx(5.0) - assert context.metrics.total_guidance_bonus_applied_bend90 == pytest.approx(0.0) - assert context.metrics.total_guidance_bonus_applied_sbend == pytest.approx(0.0) - - -def test_guidance_seed_bend90_keeps_full_bonus( - basic_evaluator: CostEvaluator, -) -> None: - context = _build_context(basic_evaluator, bounds=BOUNDS) - root = AStarNode(Port(0, 0, 0), 0.0, 0.0, seed_index=0) - result = Bend90.generate(Port(0, 0, 0), 10.0, width=2.0, direction="CCW", dilation=1.0) - open_set: list[AStarNode] = [] - unguided_open_set: list[AStarNode] = [] - - add_node( - root, - result, - target=Port(10, 10, 90), - net_width=2.0, - net_id="netA", - open_set=open_set, - closed_set={}, - context=context, - metrics=context.metrics, - congestion_cache={}, - congestion_presence_cache={}, - congestion_candidate_precheck_cache={}, - congestion_net_envelope_cache={}, - congestion_grid_net_cache={}, - congestion_grid_span_cache={}, - config=SearchRunConfig.from_options( - context.options, - guidance_seed=(result.move_spec,), - guidance_bonus=5.0, - ), - move_type="bend90", - cache_key=("guided-bend90",), - ) - add_node( - AStarNode(Port(0, 0, 0), 0.0, 0.0), - result, - target=Port(10, 10, 90), - net_width=2.0, - net_id="netA", - open_set=unguided_open_set, - closed_set={}, - context=context, - metrics=context.metrics, - congestion_cache={}, - congestion_presence_cache={}, - congestion_candidate_precheck_cache={}, - congestion_net_envelope_cache={}, - congestion_grid_net_cache={}, - congestion_grid_span_cache={}, - config=SearchRunConfig.from_options(context.options), - move_type="bend90", - cache_key=("unguided-bend90",), - ) - - assert open_set - assert unguided_open_set - guided_node = open_set[0] - unguided_node = unguided_open_set[0] - assert guided_node.seed_index == 1 - assert unguided_node.g_cost - guided_node.g_cost == pytest.approx(5.0) - assert context.metrics.total_guidance_match_moves == 1 - assert context.metrics.total_guidance_match_moves_straight == 0 - assert context.metrics.total_guidance_match_moves_bend90 == 1 - assert context.metrics.total_guidance_match_moves_sbend == 0 - assert context.metrics.total_guidance_bonus_applied == pytest.approx(5.0) - assert context.metrics.total_guidance_bonus_applied_straight == pytest.approx(0.0) - assert context.metrics.total_guidance_bonus_applied_bend90 == pytest.approx(5.0) - assert context.metrics.total_guidance_bonus_applied_sbend == pytest.approx(0.0) diff --git a/inire/tests/test_collision.py b/inire/tests/test_collision.py index e016061..284055d 100644 --- a/inire/tests/test_collision.py +++ b/inire/tests/test_collision.py @@ -1,11 +1,6 @@ -from shapely.geometry import box - from inire.geometry.collision import RoutingWorld -from inire.geometry.components import ComponentResult from inire.geometry.components import Straight from inire.geometry.primitives import Port -from inire.router._astar_types import AStarMetrics -from inire.seeds import StraightSeed def _install_static_straight( @@ -87,7 +82,6 @@ def test_check_move_static_clearance() -> None: def test_verify_path_report_preserves_long_net_id() -> None: engine = RoutingWorld(clearance=2.0) - engine.metrics = AStarMetrics() net_id = "net_abcdefghijklmnopqrstuvwxyz_0123456789" path = [Straight.generate(Port(0, 0, 0), 20.0, width=2.0, dilation=1.0)] geoms = [poly for component in path for poly in component.collision_geometry] @@ -97,12 +91,10 @@ def test_verify_path_report_preserves_long_net_id() -> None: report = engine.verify_path_report(net_id, path) assert report.dynamic_collision_count == 0 - assert engine.metrics.total_verify_dynamic_candidate_nets == 0 def test_verify_path_report_distinguishes_long_net_ids_with_shared_prefix() -> None: engine = RoutingWorld(clearance=2.0) - engine.metrics = AStarMetrics() shared_prefix = "net_shared_prefix_abcdefghijklmnopqrstuvwxyz_" net_a = f"{shared_prefix}A" net_b = f"{shared_prefix}B" @@ -123,111 +115,6 @@ def test_verify_path_report_distinguishes_long_net_ids_with_shared_prefix() -> N report = engine.verify_path_report(net_a, path_a) assert report.dynamic_collision_count == 1 - assert engine.metrics.total_verify_dynamic_candidate_nets == 1 - - -def test_verify_path_report_uses_net_envelopes_before_dynamic_object_scan() -> None: - engine = RoutingWorld(clearance=2.0) - engine.metrics = AStarMetrics() - path_a = [Straight.generate(Port(0, 0, 0), 20.0, width=2.0, dilation=1.0)] - path_b = [Straight.generate(Port(0, 0, 0), 20.0, width=2.0, dilation=1.0)] - path_far = [Straight.generate(Port(100, 100, 0), 20.0, width=2.0, dilation=1.0)] - - engine.add_path( - "netB", - [poly for component in path_b for poly in component.collision_geometry], - dilated_geometry=[poly for component in path_b for poly in component.dilated_collision_geometry], - ) - engine.add_path( - "netFar", - [poly for component in path_far for poly in component.collision_geometry], - dilated_geometry=[poly for component in path_far for poly in component.dilated_collision_geometry], - ) - - report = engine.verify_path_report("netA", path_a) - - assert report.dynamic_collision_count == 1 - assert engine.metrics.total_verify_dynamic_candidate_nets == 1 - assert engine.metrics.total_verify_dynamic_exact_pair_checks == 1 - - -def test_verify_path_details_returns_conflicting_net_ids() -> None: - engine = RoutingWorld(clearance=2.0) - engine.metrics = AStarMetrics() - path_a = [Straight.generate(Port(0, 0, 0), 20.0, width=2.0, dilation=1.0)] - path_b = [Straight.generate(Port(0, 0, 0), 20.0, width=2.0, dilation=1.0)] - - engine.add_path( - "netB", - [poly for component in path_b for poly in component.collision_geometry], - dilated_geometry=[poly for component in path_b for poly in component.dilated_collision_geometry], - ) - - detail = engine.verify_path_details("netA", path_a) - - assert detail.report.dynamic_collision_count == 1 - assert detail.conflicting_net_ids == ("netB",) - - -def test_verify_path_details_reports_component_conflicts() -> None: - engine = RoutingWorld(clearance=2.0) - engine.metrics = AStarMetrics() - path_a = [Straight.generate(Port(0, 0, 0), 20.0, width=2.0, dilation=1.0)] - path_b = [ - Straight.generate(Port(100, 0, 0), 10.0, width=2.0, dilation=1.0), - Straight.generate(Port(0, 0, 0), 20.0, width=2.0, dilation=1.0), - ] - - engine.add_path( - "netB", - [poly for component in path_b for poly in component.collision_geometry], - dilated_geometry=[poly for component in path_b for poly in component.dilated_collision_geometry], - component_indexes=[0] * len(path_b[0].collision_geometry) + [1] * len(path_b[1].collision_geometry), - ) - - detail = engine.verify_path_details("netA", path_a, capture_component_conflicts=True) - - assert detail.conflicting_net_ids == ("netB",) - assert detail.component_conflicts == ((0, "netB", 1),) - - -def test_verify_path_details_deduplicates_component_conflicts() -> None: - engine = RoutingWorld(clearance=2.0) - engine.metrics = AStarMetrics() - query_component = ComponentResult( - start_port=Port(0, 0, 0), - collision_geometry=[box(0, 0, 10, 10), box(12, 0, 22, 10)], - end_port=Port(22, 0, 0), - length=22.0, - move_type="straight", - move_spec=StraightSeed(22.0), - physical_geometry=[box(0, 0, 10, 10), box(12, 0, 22, 10)], - dilated_collision_geometry=[box(0, 0, 10, 10), box(12, 0, 22, 10)], - dilated_physical_geometry=[box(0, 0, 10, 10), box(12, 0, 22, 10)], - ) - blocker_component = ComponentResult( - start_port=Port(0, 0, 0), - collision_geometry=[box(5, 0, 17, 10)], - end_port=Port(17, 0, 0), - length=12.0, - move_type="straight", - move_spec=StraightSeed(12.0), - physical_geometry=[box(5, 0, 17, 10)], - dilated_collision_geometry=[box(5, 0, 17, 10)], - dilated_physical_geometry=[box(5, 0, 17, 10)], - ) - - engine.add_path( - "netB", - blocker_component.collision_geometry, - dilated_geometry=blocker_component.dilated_collision_geometry, - component_indexes=[0], - ) - - detail = engine.verify_path_details("netA", [query_component], capture_component_conflicts=True) - - assert detail.conflicting_net_ids == ("netB",) - assert detail.component_conflicts == ((0, "netB", 0),) def test_remove_path_clears_dynamic_path() -> None: @@ -242,247 +129,3 @@ def test_remove_path_clears_dynamic_path() -> None: engine.remove_path("netA") assert list(engine._dynamic_paths.geometries.values()) == [] assert len(engine._static_obstacles.geometries) == 0 - - -def test_dynamic_grid_updates_incrementally_on_add_and_remove() -> None: - engine = RoutingWorld(clearance=2.0) - engine.metrics = AStarMetrics() - path_a = [Straight.generate(Port(0, 0, 0), 20.0, width=2.0, dilation=1.0)] - path_b = [Straight.generate(Port(0, 4, 0), 20.0, width=2.0, dilation=1.0)] - - engine.add_path( - "netA", - [poly for component in path_a for poly in component.collision_geometry], - dilated_geometry=[poly for component in path_a for poly in component.dilated_collision_geometry], - ) - engine.add_path( - "netB", - [poly for component in path_b for poly in component.collision_geometry], - dilated_geometry=[poly for component in path_b for poly in component.dilated_collision_geometry], - ) - - dynamic_paths = engine._dynamic_paths - assert dynamic_paths.net_to_obj_ids["netA"] - assert dynamic_paths.net_to_obj_ids["netB"] - assert dynamic_paths.grid - assert engine.metrics.total_dynamic_grid_rebuilds == 0 - - engine.remove_path("netA") - - assert "netA" not in dynamic_paths.net_to_obj_ids - assert "netB" in dynamic_paths.net_to_obj_ids - assert engine.metrics.total_dynamic_grid_rebuilds == 0 - assert "netA" not in dynamic_paths.grid_net_obj_ids.get((0, -1), {}) - assert "netB" in dynamic_paths.grid_net_obj_ids.get((0, 0), {}) - - -def test_dynamic_net_envelopes_update_incrementally_on_add_and_remove() -> None: - engine = RoutingWorld(clearance=2.0) - engine.metrics = AStarMetrics() - path_a = [Straight.generate(Port(0, 0, 0), 20.0, width=2.0, dilation=1.0)] - path_b = [Straight.generate(Port(0, 40, 0), 10.0, width=2.0, dilation=1.0)] - - engine.add_path( - "netA", - [poly for component in path_a for poly in component.collision_geometry], - dilated_geometry=[poly for component in path_a for poly in component.dilated_collision_geometry], - ) - engine.add_path( - "netB", - [poly for component in path_b for poly in component.collision_geometry], - dilated_geometry=[poly for component in path_b for poly in component.dilated_collision_geometry], - ) - - dynamic_paths = engine._dynamic_paths - assert set(dynamic_paths.net_envelopes) == {"netA", "netB"} - assert dynamic_paths.net_envelopes["netA"] == (-1.0, -2.0, 21.0, 2.0) - assert dynamic_paths.net_envelopes["netB"] == (-1.0, 38.0, 11.0, 42.0) - assert engine.metrics.total_dynamic_tree_rebuilds == 0 - - net_b_envelope_obj_id = dynamic_paths.net_envelope_obj_ids["netB"] - assert list(dynamic_paths.net_envelope_index.intersection((-5.0, 35.0, 15.0, 45.0))) == [net_b_envelope_obj_id] - - engine.remove_path("netA") - - assert "netA" not in dynamic_paths.net_envelopes - assert "netA" not in dynamic_paths.net_envelope_obj_ids - assert "netB" in dynamic_paths.net_envelopes - assert engine.metrics.total_dynamic_tree_rebuilds == 0 - - - -def test_congestion_query_uses_per_polygon_bounds() -> None: - engine = RoutingWorld(clearance=2.0) - engine.metrics = AStarMetrics() - - blocker = Straight.generate(Port(40, 4, 90), 2.0, width=2.0, dilation=1.0) - engine.add_path( - "netB", - [poly for poly in blocker.collision_geometry], - dilated_geometry=[poly for poly in blocker.dilated_collision_geometry], - ) - - move = ComponentResult( - start_port=Port(0, 0, 0), - collision_geometry=[box(0, 0, 10, 10), box(90, 0, 100, 10)], - end_port=Port(100, 0, 0), - length=100.0, - move_type="straight", - move_spec=StraightSeed(100.0), - physical_geometry=[box(0, 0, 10, 10), box(90, 0, 100, 10)], - dilated_collision_geometry=[box(0, 0, 10, 10), box(90, 0, 100, 10)], - dilated_physical_geometry=[box(0, 0, 10, 10), box(90, 0, 100, 10)], - ) - - assert engine.check_move_congestion(move, "netA") == 0 - assert engine.metrics.total_congestion_candidate_nets == 0 - assert engine.metrics.total_congestion_candidate_ids == 0 - assert engine.metrics.total_congestion_exact_pair_checks == 0 - - -def test_congestion_touching_geometries_do_not_count_as_overlap() -> None: - engine = RoutingWorld(clearance=2.0) - engine.metrics = AStarMetrics() - - existing = Straight.generate(Port(0, 0, 0), 10.0, width=2.0, dilation=1.0) - touching = Straight.generate(Port(12, 0, 0), 10.0, width=2.0, dilation=1.0) - - engine.add_path( - "netB", - [poly for poly in existing.collision_geometry], - dilated_geometry=[poly for poly in existing.dilated_collision_geometry], - ) - - assert engine.check_move_congestion(touching, "netA") == 0 - - -def test_congestion_exact_checks_only_touch_relevant_move_polygons() -> None: - engine = RoutingWorld(clearance=2.0) - engine.metrics = AStarMetrics() - - blocker = Straight.generate(Port(0, 0, 0), 10.0, width=2.0, dilation=1.0) - engine.add_path( - "netB", - [poly for poly in blocker.collision_geometry], - dilated_geometry=[poly for poly in blocker.dilated_collision_geometry], - ) - - move = ComponentResult( - start_port=Port(0, 0, 0), - collision_geometry=[box(0, -2, 10, 2), box(90, -2, 100, 2)], - end_port=Port(100, 0, 0), - length=100.0, - move_type="straight", - move_spec=StraightSeed(100.0), - physical_geometry=[box(0, -2, 10, 2), box(90, -2, 100, 2)], - dilated_collision_geometry=[box(0, -2, 10, 2), box(90, -2, 100, 2)], - dilated_physical_geometry=[box(0, -2, 10, 2), box(90, -2, 100, 2)], - ) - - assert engine.check_move_congestion(move, "netA") == 1 - assert engine.metrics.total_congestion_candidate_nets == 1 - assert engine.metrics.total_congestion_candidate_ids == 1 - assert engine.metrics.total_congestion_exact_pair_checks == 1 - -def test_congestion_grid_span_cache_reuses_broad_phase_candidates() -> None: - engine = RoutingWorld(clearance=2.0) - engine.metrics = AStarMetrics() - net_envelope_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]] = {} - grid_net_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]] = {} - cache: dict[tuple[str, int, int, int, int], dict[str, tuple[int, ...]]] = {} - - blocker = Straight.generate(Port(15, 0, 0), 20.0, width=2.0, dilation=1.0) - engine.add_path( - "netB", - [poly for poly in blocker.collision_geometry], - dilated_geometry=[poly for poly in blocker.dilated_collision_geometry], - ) - - move_a = Straight.generate(Port(5, 0, 0), 20.0, width=2.0, dilation=1.0) - move_b = Straight.generate(Port(7, 0, 0), 20.0, width=2.0, dilation=1.0) - - assert engine.check_move_congestion( - move_a, - "netA", - net_envelope_cache=net_envelope_cache, - grid_net_cache=grid_net_cache, - broad_phase_cache=cache, - ) == 1 - assert engine.check_move_congestion( - move_b, - "netA", - net_envelope_cache=net_envelope_cache, - grid_net_cache=grid_net_cache, - broad_phase_cache=cache, - ) == 1 - assert engine.metrics.total_congestion_candidate_nets == 2 - assert engine.metrics.total_congestion_net_envelope_cache_misses == 1 - assert engine.metrics.total_congestion_net_envelope_cache_hits == 1 - assert engine.metrics.total_congestion_grid_net_cache_misses == 1 - assert engine.metrics.total_congestion_grid_net_cache_hits == 1 - assert engine.metrics.total_congestion_grid_span_cache_misses == 1 - assert engine.metrics.total_congestion_grid_span_cache_hits == 1 - - -def test_has_possible_move_congestion_uses_presence_cache_and_skips_empty_spans() -> None: - engine = RoutingWorld(clearance=2.0) - engine.metrics = AStarMetrics() - presence_cache: dict[tuple[str, int, int, int, int], bool] = {} - - blocker = Straight.generate(Port(10, 0, 0), 20.0, width=2.0, dilation=1.0) - engine.add_path( - "netB", - [poly for poly in blocker.collision_geometry], - dilated_geometry=[poly for poly in blocker.dilated_collision_geometry], - ) - empty_move = Straight.generate(Port(200, 0, 0), 20.0, width=2.0, dilation=1.0) - - assert not engine.has_possible_move_congestion(empty_move, "netA", presence_cache) - assert not engine.has_possible_move_congestion(empty_move, "netA", presence_cache) - assert engine.metrics.total_congestion_presence_cache_misses == 1 - assert engine.metrics.total_congestion_presence_cache_hits == 1 - - occupied_move = Straight.generate(Port(0, 0, 0), 20.0, width=2.0, dilation=1.0) - - assert engine.has_possible_move_congestion(occupied_move, "netA") - - -def test_has_candidate_move_congestion_uses_candidate_precheck_cache() -> None: - engine = RoutingWorld(clearance=2.0) - engine.metrics = AStarMetrics() - candidate_precheck_cache: dict[tuple[str, int, int, int, int], bool] = {} - net_envelope_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]] = {} - grid_net_cache: dict[tuple[str, int, int, int, int], tuple[str, ...]] = {} - - blocker = Straight.generate(Port(10, 0, 0), 20.0, width=2.0, dilation=1.0) - engine.add_path( - "netB", - [poly for poly in blocker.collision_geometry], - dilated_geometry=[poly for poly in blocker.dilated_collision_geometry], - ) - empty_move = Straight.generate(Port(200, 0, 0), 20.0, width=2.0, dilation=1.0) - occupied_move = Straight.generate(Port(0, 0, 0), 20.0, width=2.0, dilation=1.0) - - assert not engine.has_candidate_move_congestion( - empty_move, - "netA", - candidate_precheck_cache, - net_envelope_cache, - grid_net_cache, - ) - assert not engine.has_candidate_move_congestion( - empty_move, - "netA", - candidate_precheck_cache, - net_envelope_cache, - grid_net_cache, - ) - assert engine.has_candidate_move_congestion( - occupied_move, - "netA", - candidate_precheck_cache, - net_envelope_cache, - grid_net_cache, - ) - assert engine.metrics.total_congestion_candidate_precheck_misses >= 2 - assert engine.metrics.total_congestion_candidate_precheck_hits >= 1 diff --git a/inire/tests/test_example_performance.py b/inire/tests/test_example_performance.py index d572228..2d44d11 100644 --- a/inire/tests/test_example_performance.py +++ b/inire/tests/test_example_performance.py @@ -6,7 +6,7 @@ from typing import TYPE_CHECKING import pytest -from inire.tests.example_scenarios import SCENARIOS, ScenarioOutcome, snapshot_example_07_no_warm_start +from inire.tests.example_scenarios import SCENARIOS, ScenarioOutcome if TYPE_CHECKING: from collections.abc import Callable @@ -15,7 +15,6 @@ if TYPE_CHECKING: RUN_PERFORMANCE = os.environ.get("INIRE_RUN_PERFORMANCE") == "1" PERFORMANCE_REPEATS = 3 REGRESSION_FACTOR = 1.5 -NO_WARM_START_REGRESSION_SECONDS = 15.0 # Baselines are measured from clean 6a28dcf-style runs without plotting. BASELINE_SECONDS = { @@ -68,20 +67,3 @@ def test_example_like_runtime_regression(scenario: tuple[str, Callable[[], Scena f"{REGRESSION_FACTOR:.1f}x baseline {BASELINE_SECONDS[name]:.4f}s " f"from timings {timings!r}" ) - - -@pytest.mark.performance -@pytest.mark.skipif(not RUN_PERFORMANCE, reason="set INIRE_RUN_PERFORMANCE=1 to run runtime regression checks") -def test_example_07_no_warm_start_runtime_regression() -> None: - snapshot = snapshot_example_07_no_warm_start() - - assert snapshot.total_results == 10 - assert snapshot.valid_results == 10 - assert snapshot.reached_targets == 10 - assert snapshot.metrics.warm_start_paths_built == 0 - assert snapshot.metrics.warm_start_paths_used == 0 - assert snapshot.duration_s <= NO_WARM_START_REGRESSION_SECONDS, ( - "example_07_large_scale_routing_no_warm_start runtime " - f"{snapshot.duration_s:.4f}s exceeded guardrail " - f"{NO_WARM_START_REGRESSION_SECONDS:.1f}s" - ) diff --git a/inire/tests/test_example_regressions.py b/inire/tests/test_example_regressions.py index a7c3b73..e78fcab 100644 --- a/inire/tests/test_example_regressions.py +++ b/inire/tests/test_example_regressions.py @@ -14,16 +14,7 @@ from inire import ( ) from inire.router._stack import build_routing_stack from inire.seeds import Bend90Seed, PathSeed, StraightSeed -from inire.tests.example_scenarios import ( - SCENARIOS, - _build_evaluator, - _build_pathfinder, - _net_specs, - AStarMetrics, - snapshot_example_05, - snapshot_example_07_no_warm_start, - trace_example_07_no_warm_start, -) +from inire.tests.example_scenarios import SCENARIOS, _build_evaluator, _build_pathfinder, _net_specs, AStarMetrics EXPECTED_OUTCOMES = { @@ -45,43 +36,6 @@ def test_examples_match_legacy_expected_outcomes(name: str, run) -> None: assert outcome[1:] == EXPECTED_OUTCOMES[name] -def test_example_05_avoids_dynamic_tree_rebuilds() -> None: - snapshot = snapshot_example_05() - - assert snapshot.valid_results == 3 - assert snapshot.metrics.dynamic_tree_rebuilds == 0 - - -def test_example_07_no_warm_start_canary_improves_validity() -> None: - snapshot = snapshot_example_07_no_warm_start() - - assert snapshot.total_results == 10 - assert snapshot.reached_targets == 10 - assert snapshot.valid_results == 10 - assert snapshot.metrics.warm_start_paths_built == 0 - assert snapshot.metrics.warm_start_paths_used == 0 - assert snapshot.metrics.pair_local_search_pairs_considered >= 1 - assert snapshot.metrics.pair_local_search_accepts >= 1 - assert snapshot.metrics.pair_local_search_nodes_expanded <= 128 - assert snapshot.metrics.nodes_expanded <= 2500 - assert snapshot.metrics.congestion_check_calls <= 6000 - - -def test_example_07_no_warm_start_trace_finishes_without_conflict_edges() -> None: - run = trace_example_07_no_warm_start() - - assert len(run.results_by_net) == 10 - assert sum(result.is_valid for result in run.results_by_net.values()) == 10 - assert sum(result.reached_target for result in run.results_by_net.values()) == 10 - assert run.metrics.pair_local_search_pairs_considered >= 1 - assert run.metrics.pair_local_search_accepts >= 1 - - final_entry = run.conflict_trace[-1] - assert final_entry.stage == "final" - assert len(final_entry.completed_net_ids) == 10 - assert final_entry.conflict_edges == () - - def test_example_06_clipped_bbox_margin_restores_legacy_seed() -> None: bounds = (-20, -20, 170, 170) obstacles = ( diff --git a/inire/tests/test_performance_reporting.py b/inire/tests/test_performance_reporting.py index b594308..ebf7f60 100644 --- a/inire/tests/test_performance_reporting.py +++ b/inire/tests/test_performance_reporting.py @@ -16,38 +16,10 @@ def test_snapshot_example_01_exposes_metrics() -> None: assert snapshot.metrics.route_iterations >= 1 assert snapshot.metrics.nets_routed >= 1 assert snapshot.metrics.nodes_expanded > 0 - assert snapshot.metrics.score_component_calls >= 0 - assert snapshot.metrics.danger_map_lookup_calls >= 0 assert snapshot.metrics.move_cache_abs_misses >= 0 - assert snapshot.metrics.guidance_match_moves >= 0 - assert snapshot.metrics.guidance_match_moves_straight >= 0 - assert snapshot.metrics.guidance_match_moves_bend90 >= 0 - assert snapshot.metrics.guidance_match_moves_sbend >= 0 - assert snapshot.metrics.guidance_bonus_applied >= 0.0 - assert snapshot.metrics.guidance_bonus_applied_straight >= 0.0 - assert snapshot.metrics.guidance_bonus_applied_bend90 >= 0.0 - assert snapshot.metrics.guidance_bonus_applied_sbend >= 0.0 assert snapshot.metrics.ray_cast_calls >= 0 - assert snapshot.metrics.ray_cast_calls_expand_forward >= 0 assert snapshot.metrics.dynamic_tree_rebuilds >= 0 - assert snapshot.metrics.visibility_corner_index_builds >= 0 assert snapshot.metrics.visibility_builds >= 0 - assert snapshot.metrics.congestion_grid_span_cache_hits >= 0 - assert snapshot.metrics.congestion_grid_span_cache_misses >= 0 - assert snapshot.metrics.congestion_candidate_nets >= 0 - assert snapshot.metrics.congestion_net_envelope_cache_hits >= 0 - assert snapshot.metrics.congestion_net_envelope_cache_misses >= 0 - assert snapshot.metrics.congestion_grid_net_cache_hits >= 0 - assert snapshot.metrics.congestion_grid_net_cache_misses >= 0 - assert snapshot.metrics.congestion_lazy_resolutions >= 0 - assert snapshot.metrics.congestion_lazy_requeues >= 0 - assert snapshot.metrics.congestion_candidate_ids >= 0 - assert snapshot.metrics.verify_dynamic_candidate_nets >= 0 - assert snapshot.metrics.refinement_candidates_verified >= 0 - assert snapshot.metrics.pair_local_search_pairs_considered >= 0 - assert snapshot.metrics.pair_local_search_attempts >= 0 - assert snapshot.metrics.pair_local_search_accepts >= 0 - assert snapshot.metrics.pair_local_search_nodes_expanded >= 0 def test_record_performance_baseline_script_writes_selected_scenario(tmp_path: Path) -> None: @@ -71,236 +43,3 @@ def test_record_performance_baseline_script_writes_selected_scenario(tmp_path: P assert payload["generator"] == "scripts/record_performance_baseline.py" assert [entry["name"] for entry in payload["scenarios"]] == ["example_01_simple_route"] assert (tmp_path / "performance.md").exists() - - -def test_diff_performance_baseline_script_writes_selected_scenario(tmp_path: Path) -> None: - repo_root = Path(__file__).resolve().parents[2] - record_script = repo_root / "scripts" / "record_performance_baseline.py" - diff_script = repo_root / "scripts" / "diff_performance_baseline.py" - baseline_dir = tmp_path / "baseline" - baseline_dir.mkdir() - output_path = tmp_path / "diff.md" - - subprocess.run( - [ - sys.executable, - str(record_script), - "--output-dir", - str(baseline_dir), - "--scenario", - "example_01_simple_route", - ], - check=True, - ) - subprocess.run( - [ - sys.executable, - str(diff_script), - "--baseline", - str(baseline_dir / "performance_baseline.json"), - "--include-performance-only", - "--scenario", - "example_01_simple_route", - "--output", - str(output_path), - ], - check=True, - ) - - report = output_path.read_text() - assert "Performance Baseline Diff" in report - assert "example_01_simple_route" in report - - -def test_diff_performance_baseline_script_can_append_measurement_log(tmp_path: Path) -> None: - repo_root = Path(__file__).resolve().parents[2] - record_script = repo_root / "scripts" / "record_performance_baseline.py" - diff_script = repo_root / "scripts" / "diff_performance_baseline.py" - baseline_dir = tmp_path / "baseline" - baseline_dir.mkdir() - log_path = tmp_path / "optimization.md" - - subprocess.run( - [ - sys.executable, - str(record_script), - "--output-dir", - str(baseline_dir), - "--scenario", - "example_01_simple_route", - ], - check=True, - ) - subprocess.run( - [ - sys.executable, - str(diff_script), - "--baseline", - str(baseline_dir / "performance_baseline.json"), - "--include-performance-only", - "--scenario", - "example_01_simple_route", - "--metric", - "duration_s", - "--metric", - "valid_results", - "--metric", - "nodes_expanded", - "--metric", - "visibility_corner_index_builds", - "--label", - "Step 0 - Baseline", - "--notes", - "Tooling smoke test.", - "--log", - str(log_path), - ], - check=True, - ) - - report = log_path.read_text() - assert "Step 0 - Baseline" in report - assert "Tooling smoke test." in report - assert "| example_01_simple_route | duration_s |" in report - assert "| example_01_simple_route | valid_results |" in report - assert "| example_01_simple_route | visibility_corner_index_builds |" in report - - -def test_diff_performance_baseline_script_renders_current_metrics_for_added_scenario(tmp_path: Path) -> None: - repo_root = Path(__file__).resolve().parents[2] - record_script = repo_root / "scripts" / "record_performance_baseline.py" - diff_script = repo_root / "scripts" / "diff_performance_baseline.py" - baseline_dir = tmp_path / "baseline" - baseline_dir.mkdir() - output_path = tmp_path / "diff_added.md" - - subprocess.run( - [ - sys.executable, - str(record_script), - "--output-dir", - str(baseline_dir), - "--scenario", - "example_01_simple_route", - ], - check=True, - ) - subprocess.run( - [ - sys.executable, - str(diff_script), - "--baseline", - str(baseline_dir / "performance_baseline.json"), - "--include-performance-only", - "--scenario", - "example_07_large_scale_routing_no_warm_start", - "--metric", - "duration_s", - "--metric", - "nodes_expanded", - "--output", - str(output_path), - ], - check=True, - ) - - report = output_path.read_text() - assert "| example_07_large_scale_routing_no_warm_start | duration_s | - |" in report - assert "| example_07_large_scale_routing_no_warm_start | nodes_expanded | - |" in report - - -def test_record_conflict_trace_script_writes_selected_scenario(tmp_path: Path) -> None: - repo_root = Path(__file__).resolve().parents[2] - script_path = repo_root / "scripts" / "record_conflict_trace.py" - - subprocess.run( - [ - sys.executable, - str(script_path), - "--output-dir", - str(tmp_path), - "--scenario", - "example_05_orientation_stress", - ], - check=True, - ) - - payload = json.loads((tmp_path / "conflict_trace.json").read_text()) - assert payload["generated_at"] - assert payload["generator"] == "scripts/record_conflict_trace.py" - assert [entry["name"] for entry in payload["scenarios"]] == ["example_05_orientation_stress"] - assert (tmp_path / "conflict_trace.md").exists() - - -def test_record_conflict_trace_script_supports_performance_only_scenario(tmp_path: Path) -> None: - repo_root = Path(__file__).resolve().parents[2] - script_path = repo_root / "scripts" / "record_conflict_trace.py" - - subprocess.run( - [ - sys.executable, - str(script_path), - "--output-dir", - str(tmp_path), - "--include-performance-only", - "--scenario", - "example_07_large_scale_routing_no_warm_start", - ], - check=True, - ) - - payload = json.loads((tmp_path / "conflict_trace.json").read_text()) - assert [entry["name"] for entry in payload["scenarios"]] == ["example_07_large_scale_routing_no_warm_start"] - - -def test_record_frontier_trace_script_writes_selected_scenario(tmp_path: Path) -> None: - repo_root = Path(__file__).resolve().parents[2] - script_path = repo_root / "scripts" / "record_frontier_trace.py" - - subprocess.run( - [ - sys.executable, - str(script_path), - "--output-dir", - str(tmp_path), - "--scenario", - "example_05_orientation_stress", - ], - check=True, - ) - - payload = json.loads((tmp_path / "frontier_trace.json").read_text()) - assert payload["generated_at"] - assert payload["generator"] == "scripts/record_frontier_trace.py" - assert [entry["name"] for entry in payload["scenarios"]] == ["example_05_orientation_stress"] - assert (tmp_path / "frontier_trace.md").exists() - - -def test_characterize_pair_local_search_script_writes_outputs(tmp_path: Path) -> None: - repo_root = Path(__file__).resolve().parents[2] - script_path = repo_root / "scripts" / "characterize_pair_local_search.py" - - subprocess.run( - [ - sys.executable, - str(script_path), - "--output-dir", - str(tmp_path), - "--num-nets", - "6", - "--seeds", - "41", - "--repeats", - "1", - ], - check=True, - ) - - payload = json.loads((tmp_path / "pair_local_characterization.json").read_text()) - assert payload["generated_at"] - assert payload["generator"] == "scripts/characterize_pair_local_search.py" - assert payload["grid"]["num_nets"] == [6] - assert payload["grid"]["seeds"] == [41] - assert payload["grid"]["repeats"] == 1 - assert len(payload["cases"]) == 1 - assert (tmp_path / "pair_local_characterization.md").exists() diff --git a/inire/tests/test_visibility.py b/inire/tests/test_visibility.py index ff20439..0e2100f 100644 --- a/inire/tests/test_visibility.py +++ b/inire/tests/test_visibility.py @@ -2,7 +2,6 @@ from shapely.geometry import box from inire.geometry.collision import RoutingWorld from inire.geometry.primitives import Port -from inire.router._astar_types import AStarMetrics from inire.router.visibility import VisibilityManager @@ -19,111 +18,3 @@ def test_point_visibility_cache_respects_max_distance() -> None: assert len(near_corners) == 3 assert len(far_corners) > len(near_corners) assert any(corner[0] >= 100.0 for corner in far_corners) - - -def test_visibility_manager_is_lazy_until_queried() -> None: - engine = RoutingWorld(clearance=0.0) - engine.metrics = AStarMetrics() - engine.add_static_obstacle(box(10, 20, 20, 30)) - - visibility = VisibilityManager(engine) - - assert visibility.corners == [] - assert engine.metrics.total_visibility_corner_index_builds == 0 - assert engine.metrics.total_visibility_builds == 0 - - visibility.ensure_corner_index_current() - - assert visibility.corners - assert engine.metrics.total_visibility_corner_index_builds == 1 - assert engine.metrics.total_visibility_builds == 0 - - -def test_exact_corner_visibility_builds_graph_once_per_static_version() -> None: - engine = RoutingWorld(clearance=0.0) - engine.metrics = AStarMetrics() - engine.add_static_obstacle(box(10, 20, 20, 30)) - visibility = VisibilityManager(engine) - origin = Port(10, 20, 0) - - first = visibility.get_corner_visibility(origin, max_dist=100.0) - second = visibility.get_corner_visibility(origin, max_dist=100.0) - - assert second == first - assert engine.metrics.total_visibility_corner_index_builds == 1 - assert engine.metrics.total_visibility_builds == 1 - - -def test_clear_cache_invalidates_without_rebuilding_and_static_change_rebuilds_lazily() -> None: - engine = RoutingWorld(clearance=0.0) - engine.metrics = AStarMetrics() - engine.add_static_obstacle(box(10, 20, 20, 30)) - visibility = VisibilityManager(engine) - - visibility.get_corner_visibility(Port(10, 20, 0), max_dist=100.0) - assert engine.metrics.total_visibility_corner_index_builds == 1 - assert engine.metrics.total_visibility_builds == 1 - - visibility.clear_cache() - - assert visibility.corners == [] - assert engine.metrics.total_visibility_corner_index_builds == 1 - assert engine.metrics.total_visibility_builds == 1 - - engine.add_static_obstacle(box(40, 20, 50, 30)) - - visible = visibility.get_corner_visibility(Port(10, 20, 0), max_dist=100.0) - - assert visible == [] - assert engine.metrics.total_visibility_corner_index_builds == 2 - assert engine.metrics.total_visibility_builds == 2 - - -def test_tangent_corner_candidate_query_matches_bruteforce_filter() -> None: - engine = RoutingWorld(clearance=0.0) - engine.add_static_obstacle(box(10, 20, 20, 30)) - engine.add_static_obstacle(box(-35, -15, -25, -5)) - engine.add_static_obstacle(box(35, -40, 45, -30)) - visibility = VisibilityManager(engine) - radii = (10.0, 20.0) - min_forward = 5.0 - max_forward = 60.0 - tolerance = 2.0 - - for origin in ( - Port(0, 0, 0), - Port(0, 0, 90), - Port(0, 0, 180), - Port(0, 0, 270), - ): - candidate_ids = set( - visibility.get_tangent_corner_candidates( - origin, - min_forward=min_forward, - max_forward=max_forward, - radii=radii, - tolerance=tolerance, - ) - ) - expected_ids: set[int] = set() - if origin.r == 0: - cos_v, sin_v = 1.0, 0.0 - elif origin.r == 90: - cos_v, sin_v = 0.0, 1.0 - elif origin.r == 180: - cos_v, sin_v = -1.0, 0.0 - else: - cos_v, sin_v = 0.0, -1.0 - - for idx, (cx, cy) in enumerate(visibility.corners): - dx = cx - origin.x - dy = cy - origin.y - local_x = dx * cos_v + dy * sin_v - local_y = -dx * sin_v + dy * cos_v - if local_x <= min_forward or local_x > max_forward + 0.01: - continue - nearest_radius = min(radii, key=lambda radius: abs(abs(local_y) - radius)) - if abs(abs(local_y) - nearest_radius) <= tolerance: - expected_ids.add(idx) - - assert candidate_ids == expected_ids diff --git a/scripts/characterize_pair_local_search.py b/scripts/characterize_pair_local_search.py deleted file mode 100644 index 5b575e3..0000000 --- a/scripts/characterize_pair_local_search.py +++ /dev/null @@ -1,177 +0,0 @@ -#!/usr/bin/env python3 -from __future__ import annotations - -import argparse -import json -from dataclasses import asdict -from datetime import datetime -from pathlib import Path -from time import perf_counter - -from inire.tests.example_scenarios import _run_example_07_variant - - -def _parse_csv_ints(raw: str) -> tuple[int, ...]: - return tuple(int(part) for part in raw.split(",") if part.strip()) - - -def _run_case(num_nets: int, seed: int) -> dict[str, object]: - t0 = perf_counter() - run = _run_example_07_variant( - num_nets=num_nets, - seed=seed, - warm_start_enabled=False, - ) - duration_s = perf_counter() - t0 - return { - "duration_s": duration_s, - "summary": { - "total_results": len(run.results_by_net), - "valid_results": sum(1 for result in run.results_by_net.values() if result.is_valid), - "reached_targets": sum(1 for result in run.results_by_net.values() if result.reached_target), - }, - "metrics": asdict(run.metrics), - } - - -def _is_smoke_candidate(entry: dict[str, object]) -> bool: - summary = entry["summary"] - metrics = entry["metrics"] - return ( - summary["valid_results"] == summary["total_results"] - and metrics["pair_local_search_accepts"] >= 1 - and entry["duration_s"] <= 1.0 - ) - - -def _select_smoke_case(cases: list[dict[str, object]]) -> dict[str, object] | None: - grouped: dict[tuple[int, int], list[dict[str, object]]] = {} - for case in cases: - key = (case["num_nets"], case["seed"]) - grouped.setdefault(key, []).append(case) - - candidates = [] - for (num_nets, seed), repeats in grouped.items(): - if repeats and all(_is_smoke_candidate(repeat) for repeat in repeats): - candidates.append({"num_nets": num_nets, "seed": seed}) - if not candidates: - return None - candidates.sort(key=lambda item: (item["num_nets"], item["seed"])) - return candidates[0] - - -def _render_markdown(payload: dict[str, object]) -> str: - lines = [ - "# Pair-Local Search Characterization", - "", - f"Generated at {payload['generated_at']} by `{payload['generator']}`.", - "", - f"Grid: `num_nets={payload['grid']['num_nets']}`, `seed={payload['grid']['seeds']}`, repeats={payload['grid']['repeats']}.", - "", - "| Nets | Seed | Repeat | Duration (s) | Valid | Reached | Pair Pairs | Pair Accepts | Pair Nodes | Nodes | Checks |", - "| :-- | :-- | :-- | --: | --: | --: | --: | --: | --: | --: | --: |", - ] - for case in payload["cases"]: - summary = case["summary"] - metrics = case["metrics"] - lines.append( - "| " - f"{case['num_nets']} | " - f"{case['seed']} | " - f"{case['repeat']} | " - f"{case['duration_s']:.4f} | " - f"{summary['valid_results']} | " - f"{summary['reached_targets']} | " - f"{metrics['pair_local_search_pairs_considered']} | " - f"{metrics['pair_local_search_accepts']} | " - f"{metrics['pair_local_search_nodes_expanded']} | " - f"{metrics['nodes_expanded']} | " - f"{metrics['congestion_check_calls']} |" - ) - - lines.extend(["", "## Recommendation", ""]) - recommended = payload["recommended_smoke_scenario"] - if recommended is None: - lines.append( - "No smaller stable pair-local smoke scenario satisfied the rule " - "`valid_results == total_results`, `pair_local_search_accepts >= 1`, and `duration_s <= 1.0` across all repeats." - ) - else: - lines.append( - f"Recommended smoke scenario: `num_nets={recommended['num_nets']}`, `seed={recommended['seed']}`." - ) - return "\n".join(lines) - - -def main() -> None: - parser = argparse.ArgumentParser(description="Characterize pair-local search across example_07-style no-warm runs.") - parser.add_argument( - "--num-nets", - default="6,8,10", - help="Comma-separated num_nets values to sweep. Default: 6,8,10.", - ) - parser.add_argument( - "--seeds", - default="41,42,43", - help="Comma-separated seed values to sweep. Default: 41,42,43.", - ) - parser.add_argument( - "--repeats", - type=int, - default=2, - help="Number of repeated runs per (num_nets, seed). Default: 2.", - ) - parser.add_argument( - "--output-dir", - type=Path, - default=None, - help="Directory to write pair_local_characterization.json and .md into. Defaults to /docs.", - ) - args = parser.parse_args() - - repo_root = Path(__file__).resolve().parents[1] - output_dir = repo_root / "docs" if args.output_dir is None else args.output_dir.resolve() - output_dir.mkdir(exist_ok=True) - - num_nets_values = _parse_csv_ints(args.num_nets) - seed_values = _parse_csv_ints(args.seeds) - - cases: list[dict[str, object]] = [] - for num_nets in num_nets_values: - for seed in seed_values: - for repeat in range(args.repeats): - case = _run_case(num_nets, seed) - case["num_nets"] = num_nets - case["seed"] = seed - case["repeat"] = repeat - cases.append(case) - - payload = { - "generated_at": datetime.now().astimezone().isoformat(timespec="seconds"), - "generator": "scripts/characterize_pair_local_search.py", - "grid": { - "num_nets": list(num_nets_values), - "seeds": list(seed_values), - "repeats": args.repeats, - }, - "cases": cases, - "recommended_smoke_scenario": _select_smoke_case(cases), - } - - json_path = output_dir / "pair_local_characterization.json" - markdown_path = output_dir / "pair_local_characterization.md" - json_path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n") - markdown_path.write_text(_render_markdown(payload) + "\n") - - if json_path.is_relative_to(repo_root): - print(f"Wrote {json_path.relative_to(repo_root)}") - else: - print(f"Wrote {json_path}") - if markdown_path.is_relative_to(repo_root): - print(f"Wrote {markdown_path.relative_to(repo_root)}") - else: - print(f"Wrote {markdown_path}") - - -if __name__ == "__main__": - main() diff --git a/scripts/diff_performance_baseline.py b/scripts/diff_performance_baseline.py deleted file mode 100644 index 352022b..0000000 --- a/scripts/diff_performance_baseline.py +++ /dev/null @@ -1,237 +0,0 @@ -#!/usr/bin/env python3 -from __future__ import annotations - -import argparse -import json -from dataclasses import asdict -from datetime import datetime -from pathlib import Path - -from inire.tests.example_scenarios import PERFORMANCE_SCENARIO_SNAPSHOTS, SCENARIO_SNAPSHOTS -from inire.results import RouteMetrics - - -SUMMARY_KEYS = ( - "duration_s", - "valid_results", - "reached_targets", - "route_iterations", - "nets_routed", - "nodes_expanded", - "ray_cast_calls", - "moves_generated", - "moves_added", - "congestion_check_calls", - "verify_path_report_calls", -) - - -def _snapshot_registry(include_performance_only: bool) -> tuple[tuple[str, object], ...]: - if not include_performance_only: - return SCENARIO_SNAPSHOTS - return SCENARIO_SNAPSHOTS + PERFORMANCE_SCENARIO_SNAPSHOTS - - -def _available_metric_names() -> tuple[str, ...]: - return ( - "duration_s", - "total_results", - "valid_results", - "reached_targets", - *RouteMetrics.__dataclass_fields__.keys(), - ) - - -def _current_snapshots( - selected_scenarios: tuple[str, ...] | None, - *, - include_performance_only: bool, -) -> dict[str, dict[str, object]]: - allowed = None if selected_scenarios is None else set(selected_scenarios) - snapshots: dict[str, dict[str, object]] = {} - for name, run in _snapshot_registry(include_performance_only): - if allowed is not None and name not in allowed: - continue - snapshots[name] = asdict(run()) - return snapshots - - -def _load_baseline(path: Path, selected_scenarios: tuple[str, ...] | None) -> dict[str, dict[str, object]]: - payload = json.loads(path.read_text()) - allowed = None if selected_scenarios is None else set(selected_scenarios) - return { - entry["name"]: entry - for entry in payload["scenarios"] - if allowed is None or entry["name"] in allowed - } - - -def _metric_value(snapshot: dict[str, object], key: str) -> float | None: - if key in {"duration_s", "total_results", "valid_results", "reached_targets"}: - return float(snapshot[key]) - if key not in snapshot["metrics"]: - return None - return float(snapshot["metrics"][key]) - - -def _validate_metrics(metric_names: tuple[str, ...]) -> None: - valid_names = set(_available_metric_names()) - unknown = [name for name in metric_names if name not in valid_names] - if unknown: - raise SystemExit( - f"Unknown metric name(s): {', '.join(sorted(unknown))}. " - f"Valid names are: {', '.join(_available_metric_names())}" - ) - - -def _render_report( - baseline: dict[str, dict[str, object]], - current: dict[str, dict[str, object]], - metric_names: tuple[str, ...], -) -> str: - scenario_names = sorted(set(baseline) | set(current)) - lines = [ - "# Performance Baseline Diff", - "", - "| Scenario | Metric | Baseline | Current | Delta |", - "| :-- | :-- | --: | --: | --: |", - ] - for scenario in scenario_names: - base_snapshot = baseline.get(scenario) - curr_snapshot = current.get(scenario) - if base_snapshot is None: - if curr_snapshot is None: - lines.append(f"| {scenario} | added | - | - | - |") - continue - for key in metric_names: - curr_value = _metric_value(curr_snapshot, key) - if curr_value is None: - lines.append(f"| {scenario} | {key} | - | - | - |") - continue - lines.append(f"| {scenario} | {key} | - | {curr_value:.4f} | - |") - continue - if curr_snapshot is None: - lines.append(f"| {scenario} | missing | - | - | - |") - continue - for key in metric_names: - base_value = _metric_value(base_snapshot, key) - curr_value = _metric_value(curr_snapshot, key) - if base_value is None: - lines.append( - f"| {scenario} | {key} | - | {curr_value:.4f} | - |" - ) - continue - if curr_value is None: - lines.append( - f"| {scenario} | {key} | {base_value:.4f} | - | - |" - ) - continue - lines.append( - f"| {scenario} | {key} | {base_value:.4f} | {curr_value:.4f} | {curr_value - base_value:+.4f} |" - ) - return "\n".join(lines) + "\n" - - -def _render_log_entry( - *, - baseline_path: Path, - label: str, - notes: tuple[str, ...], - report: str, -) -> str: - lines = [ - f"## {label}", - "", - f"Measured on {datetime.now().astimezone().isoformat(timespec='seconds')}.", - f"Baseline: `{baseline_path}`.", - "", - ] - if notes: - lines.extend(["Findings:", ""]) - lines.extend(f"- {note}" for note in notes) - lines.append("") - lines.append(report.rstrip()) - lines.append("") - return "\n".join(lines) - - -def main() -> None: - parser = argparse.ArgumentParser(description="Diff the committed performance baseline against a fresh run.") - parser.add_argument( - "--baseline", - type=Path, - default=Path("docs/performance_baseline.json"), - help="Baseline JSON to compare against.", - ) - parser.add_argument( - "--output", - type=Path, - default=None, - help="Optional file to write the report to. Defaults to stdout.", - ) - parser.add_argument( - "--scenario", - action="append", - dest="scenarios", - default=[], - help="Optional scenario name to include. May be passed more than once.", - ) - parser.add_argument( - "--metric", - action="append", - dest="metrics", - default=[], - help="Optional metric to include. May be passed more than once. Defaults to the summary metric set.", - ) - parser.add_argument( - "--label", - default="Measurement", - help="Section label to use when appending to a log file.", - ) - parser.add_argument( - "--notes", - action="append", - dest="notes", - default=[], - help="Optional short finding to append under the measurement section. May be passed more than once.", - ) - parser.add_argument( - "--log", - type=Path, - default=None, - help="Optional Markdown log file to append the rendered report to.", - ) - parser.add_argument( - "--include-performance-only", - action="store_true", - help="Include performance-only snapshot scenarios that are excluded from the default baseline corpus.", - ) - args = parser.parse_args() - - selected = tuple(args.scenarios) if args.scenarios else None - metrics = tuple(args.metrics) if args.metrics else SUMMARY_KEYS - _validate_metrics(metrics) - baseline = _load_baseline(args.baseline, selected) - current = _current_snapshots(selected, include_performance_only=args.include_performance_only) - report = _render_report(baseline, current, metrics) - - if args.output is not None: - args.output.write_text(report) - print(f"Wrote {args.output}") - elif args.log is None: - print(report, end="") - - if args.log is not None: - entry = _render_log_entry( - baseline_path=args.baseline, - label=args.label, - notes=tuple(args.notes), - report=report, - ) - with args.log.open("a", encoding="utf-8") as handle: - handle.write(entry) - print(f"Appended {args.log}") - - -if __name__ == "__main__": - main() diff --git a/scripts/record_conflict_trace.py b/scripts/record_conflict_trace.py deleted file mode 100644 index 2baaf9c..0000000 --- a/scripts/record_conflict_trace.py +++ /dev/null @@ -1,228 +0,0 @@ -#!/usr/bin/env python3 -from __future__ import annotations - -import argparse -import json -from collections import Counter -from dataclasses import asdict -from datetime import datetime -from pathlib import Path - -from inire.results import RoutingRunResult -from inire.tests.example_scenarios import TRACE_PERFORMANCE_SCENARIO_RUNS, TRACE_SCENARIO_RUNS - - -def _trace_registry(include_performance_only: bool) -> tuple[tuple[str, object], ...]: - if include_performance_only: - return TRACE_SCENARIO_RUNS + TRACE_PERFORMANCE_SCENARIO_RUNS - return TRACE_SCENARIO_RUNS - - -def _selected_runs( - selected_scenarios: tuple[str, ...] | None, - *, - include_performance_only: bool, -) -> tuple[tuple[str, object], ...]: - if selected_scenarios is None: - return (("example_07_large_scale_routing_no_warm_start", dict(TRACE_PERFORMANCE_SCENARIO_RUNS)["example_07_large_scale_routing_no_warm_start"]),) - - registry = dict(TRACE_SCENARIO_RUNS + TRACE_PERFORMANCE_SCENARIO_RUNS) - allowed_standard = dict(_trace_registry(include_performance_only)) - runs = [] - for name in selected_scenarios: - if name in allowed_standard: - runs.append((name, allowed_standard[name])) - continue - if name in registry: - runs.append((name, registry[name])) - continue - valid = ", ".join(sorted(registry)) - raise SystemExit(f"Unknown trace scenario: {name}. Valid scenarios: {valid}") - return tuple(runs) - - -def _result_summary(run: RoutingRunResult) -> dict[str, object]: - return { - "total_results": len(run.results_by_net), - "valid_results": sum(1 for result in run.results_by_net.values() if result.is_valid), - "reached_targets": sum(1 for result in run.results_by_net.values() if result.reached_target), - "results_by_net": { - net_id: { - "outcome": result.outcome, - "reached_target": result.reached_target, - "report": asdict(result.report), - } - for net_id, result in run.results_by_net.items() - }, - } - - -def _build_payload( - selected_scenarios: tuple[str, ...] | None, - *, - include_performance_only: bool, -) -> dict[str, object]: - scenarios = [] - for name, run in _selected_runs(selected_scenarios, include_performance_only=include_performance_only): - result = run() - scenarios.append( - { - "name": name, - "summary": _result_summary(result), - "metrics": asdict(result.metrics), - "conflict_trace": [asdict(entry) for entry in result.conflict_trace], - } - ) - return { - "generated_at": datetime.now().astimezone().isoformat(timespec="seconds"), - "generator": "scripts/record_conflict_trace.py", - "scenarios": scenarios, - } - - -def _count_stage_nets(entry: dict[str, object]) -> int: - return sum( - 1 - for net in entry["nets"] - if net["report"]["dynamic_collision_count"] > 0 - ) - - -def _canonical_component_pair( - net_id: str, - self_component_index: int, - other_net_id: str, - other_component_index: int, -) -> tuple[tuple[str, int], tuple[str, int]]: - left = (net_id, self_component_index) - right = (other_net_id, other_component_index) - if left <= right: - return (left, right) - return (right, left) - - -def _render_markdown(payload: dict[str, object]) -> str: - lines = [ - "# Conflict Trace", - "", - f"Generated at {payload['generated_at']} by `{payload['generator']}`.", - "", - ] - - for scenario in payload["scenarios"]: - lines.extend( - [ - f"## {scenario['name']}", - "", - f"Results: {scenario['summary']['valid_results']} valid / " - f"{scenario['summary']['reached_targets']} reached / " - f"{scenario['summary']['total_results']} total.", - "", - "| Stage | Iteration | Conflicting Nets | Conflict Edges | Completed Nets |", - "| :-- | --: | --: | --: | --: |", - ] - ) - - net_stage_counts: Counter[str] = Counter() - edge_counts: Counter[tuple[str, str]] = Counter() - component_pair_counts: Counter[tuple[tuple[str, int], tuple[str, int]]] = Counter() - trace_entries = scenario["conflict_trace"] - for entry in trace_entries: - lines.append( - "| " - f"{entry['stage']} | " - f"{'' if entry['iteration'] is None else entry['iteration']} | " - f"{_count_stage_nets(entry)} | " - f"{len(entry['conflict_edges'])} | " - f"{len(entry['completed_net_ids'])} |" - ) - seen_component_pairs: set[tuple[tuple[str, int], tuple[str, int]]] = set() - for edge in entry["conflict_edges"]: - edge_counts[tuple(edge)] += 1 - for net in entry["nets"]: - if net["report"]["dynamic_collision_count"] > 0: - net_stage_counts[net["net_id"]] += 1 - for component_conflict in net["component_conflicts"]: - pair = _canonical_component_pair( - net["net_id"], - component_conflict["self_component_index"], - component_conflict["other_net_id"], - component_conflict["other_component_index"], - ) - seen_component_pairs.add(pair) - for pair in seen_component_pairs: - component_pair_counts[pair] += 1 - - lines.extend(["", "Top nets by traced dynamic-collision stages:", ""]) - if net_stage_counts: - for net_id, count in net_stage_counts.most_common(10): - lines.append(f"- `{net_id}`: {count}") - else: - lines.append("- None") - - lines.extend(["", "Top net pairs by frequency:", ""]) - if edge_counts: - for (left, right), count in edge_counts.most_common(10): - lines.append(f"- `{left}` <-> `{right}`: {count}") - else: - lines.append("- None") - - lines.extend(["", "Top component pairs by frequency:", ""]) - if component_pair_counts: - for pair, count in component_pair_counts.most_common(10): - (left_net, left_index), (right_net, right_index) = pair - lines.append(f"- `{left_net}[{left_index}]` <-> `{right_net}[{right_index}]`: {count}") - else: - lines.append("- None") - - lines.append("") - - return "\n".join(lines) - - -def main() -> None: - parser = argparse.ArgumentParser(description="Record conflict-trace artifacts for selected trace scenarios.") - parser.add_argument( - "--scenario", - action="append", - dest="scenarios", - default=[], - help="Optional trace scenario name to include. May be passed more than once.", - ) - parser.add_argument( - "--include-performance-only", - action="store_true", - help="Include performance-only trace scenarios when selecting from the standard registry.", - ) - parser.add_argument( - "--output-dir", - type=Path, - default=None, - help="Directory to write conflict_trace.json and conflict_trace.md into. Defaults to /docs.", - ) - args = parser.parse_args() - - repo_root = Path(__file__).resolve().parents[1] - output_dir = repo_root / "docs" if args.output_dir is None else args.output_dir.resolve() - output_dir.mkdir(exist_ok=True) - - selected = tuple(args.scenarios) if args.scenarios else None - payload = _build_payload(selected, include_performance_only=args.include_performance_only) - json_path = output_dir / "conflict_trace.json" - markdown_path = output_dir / "conflict_trace.md" - - json_path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n") - markdown_path.write_text(_render_markdown(payload) + "\n") - - if json_path.is_relative_to(repo_root): - print(f"Wrote {json_path.relative_to(repo_root)}") - else: - print(f"Wrote {json_path}") - if markdown_path.is_relative_to(repo_root): - print(f"Wrote {markdown_path.relative_to(repo_root)}") - else: - print(f"Wrote {markdown_path}") - - -if __name__ == "__main__": - main() diff --git a/scripts/record_frontier_trace.py b/scripts/record_frontier_trace.py deleted file mode 100644 index e101c90..0000000 --- a/scripts/record_frontier_trace.py +++ /dev/null @@ -1,205 +0,0 @@ -#!/usr/bin/env python3 -from __future__ import annotations - -import argparse -import json -from collections import Counter -from dataclasses import asdict -from datetime import datetime -from pathlib import Path - -from inire.tests.example_scenarios import TRACE_PERFORMANCE_SCENARIO_RUNS, TRACE_SCENARIO_RUNS - - -def _trace_registry(include_performance_only: bool) -> tuple[tuple[str, object], ...]: - if include_performance_only: - return TRACE_SCENARIO_RUNS + TRACE_PERFORMANCE_SCENARIO_RUNS - return TRACE_SCENARIO_RUNS - - -def _selected_runs( - selected_scenarios: tuple[str, ...] | None, - *, - include_performance_only: bool, -) -> tuple[tuple[str, object], ...]: - if selected_scenarios is None: - default_registry = dict(TRACE_PERFORMANCE_SCENARIO_RUNS) - return (("example_07_large_scale_routing_no_warm_start", default_registry["example_07_large_scale_routing_no_warm_start"]),) - - registry = dict(TRACE_SCENARIO_RUNS + TRACE_PERFORMANCE_SCENARIO_RUNS) - allowed_standard = dict(_trace_registry(include_performance_only)) - runs = [] - for name in selected_scenarios: - if name in allowed_standard: - runs.append((name, allowed_standard[name])) - continue - if name in registry: - runs.append((name, registry[name])) - continue - valid = ", ".join(sorted(registry)) - raise SystemExit(f"Unknown trace scenario: {name}. Valid scenarios: {valid}") - return tuple(runs) - - -def _build_payload( - selected_scenarios: tuple[str, ...] | None, - *, - include_performance_only: bool, -) -> dict[str, object]: - scenarios = [] - for name, run in _selected_runs(selected_scenarios, include_performance_only=include_performance_only): - result = run() - scenarios.append( - { - "name": name, - "summary": { - "total_results": len(result.results_by_net), - "valid_results": sum(1 for entry in result.results_by_net.values() if entry.is_valid), - "reached_targets": sum(1 for entry in result.results_by_net.values() if entry.reached_target), - }, - "metrics": asdict(result.metrics), - "frontier_trace": [asdict(entry) for entry in result.frontier_trace], - } - ) - return { - "generated_at": datetime.now().astimezone().isoformat(timespec="seconds"), - "generator": "scripts/record_frontier_trace.py", - "scenarios": scenarios, - } - - -def _render_markdown(payload: dict[str, object]) -> str: - lines = [ - "# Frontier Trace", - "", - f"Generated at {payload['generated_at']} by `{payload['generator']}`.", - "", - ] - - for scenario in payload["scenarios"]: - lines.extend( - [ - f"## {scenario['name']}", - "", - f"Results: {scenario['summary']['valid_results']} valid / " - f"{scenario['summary']['reached_targets']} reached / " - f"{scenario['summary']['total_results']} total.", - "", - "| Net | Hotspots | Closed-Set | Hard Collision | Self Collision | Cost | Samples |", - "| :-- | --: | --: | --: | --: | --: | --: |", - ] - ) - - reason_counts: Counter[str] = Counter() - hotspot_counts: Counter[tuple[str, int]] = Counter() - for net_trace in scenario["frontier_trace"]: - sample_count = len(net_trace["samples"]) - lines.append( - "| " - f"{net_trace['net_id']} | " - f"{len(net_trace['hotspot_bounds'])} | " - f"{net_trace['pruned_closed_set']} | " - f"{net_trace['pruned_hard_collision']} | " - f"{net_trace['pruned_self_collision']} | " - f"{net_trace['pruned_cost']} | " - f"{sample_count} |" - ) - reason_counts["closed_set"] += net_trace["pruned_closed_set"] - reason_counts["hard_collision"] += net_trace["pruned_hard_collision"] - reason_counts["self_collision"] += net_trace["pruned_self_collision"] - reason_counts["cost"] += net_trace["pruned_cost"] - for sample in net_trace["samples"]: - hotspot_counts[(net_trace["net_id"], sample["hotspot_index"])] += 1 - - lines.extend(["", "Prune totals by reason:", ""]) - if reason_counts: - for reason, count in reason_counts.most_common(): - lines.append(f"- `{reason}`: {count}") - else: - lines.append("- None") - - lines.extend(["", "Top traced hotspots by sample count:", ""]) - if hotspot_counts: - for (net_id, hotspot_index), count in hotspot_counts.most_common(10): - lines.append(f"- `{net_id}` hotspot `{hotspot_index}`: {count}") - else: - lines.append("- None") - - lines.extend(["", "Per-net sampled reason/move breakdown:", ""]) - if scenario["frontier_trace"]: - for net_trace in scenario["frontier_trace"]: - reason_move_counts: Counter[tuple[str, str]] = Counter() - hotspot_sample_counts: Counter[int] = Counter() - for sample in net_trace["samples"]: - reason_move_counts[(sample["reason"], sample["move_type"])] += 1 - hotspot_sample_counts[sample["hotspot_index"]] += 1 - lines.append(f"- `{net_trace['net_id']}`") - if reason_move_counts: - top_pairs = ", ".join( - f"`{reason}` x `{move}` = {count}" - for (reason, move), count in reason_move_counts.most_common(3) - ) - lines.append(f" sampled reasons: {top_pairs}") - else: - lines.append(" sampled reasons: none") - if hotspot_sample_counts: - top_hotspots = ", ".join( - f"`{hotspot}` = {count}" for hotspot, count in hotspot_sample_counts.most_common(3) - ) - lines.append(f" hotspot samples: {top_hotspots}") - else: - lines.append(" hotspot samples: none") - else: - lines.append("- None") - - lines.append("") - - return "\n".join(lines) - - -def main() -> None: - parser = argparse.ArgumentParser(description="Record frontier-trace artifacts for selected trace scenarios.") - parser.add_argument( - "--scenario", - action="append", - dest="scenarios", - default=[], - help="Optional trace scenario name to include. May be passed more than once.", - ) - parser.add_argument( - "--include-performance-only", - action="store_true", - help="Include performance-only trace scenarios when selecting from the standard registry.", - ) - parser.add_argument( - "--output-dir", - type=Path, - default=None, - help="Directory to write frontier_trace.json and frontier_trace.md into. Defaults to /docs.", - ) - args = parser.parse_args() - - repo_root = Path(__file__).resolve().parents[1] - output_dir = repo_root / "docs" if args.output_dir is None else args.output_dir.resolve() - output_dir.mkdir(exist_ok=True) - - selected = tuple(args.scenarios) if args.scenarios else None - payload = _build_payload(selected, include_performance_only=args.include_performance_only) - json_path = output_dir / "frontier_trace.json" - markdown_path = output_dir / "frontier_trace.md" - - json_path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n") - markdown_path.write_text(_render_markdown(payload) + "\n") - - if json_path.is_relative_to(repo_root): - print(f"Wrote {json_path.relative_to(repo_root)}") - else: - print(f"Wrote {json_path}") - if markdown_path.is_relative_to(repo_root): - print(f"Wrote {markdown_path.relative_to(repo_root)}") - else: - print(f"Wrote {markdown_path}") - - -if __name__ == "__main__": - main() diff --git a/scripts/record_performance_baseline.py b/scripts/record_performance_baseline.py index 14944bb..8d731be 100644 --- a/scripts/record_performance_baseline.py +++ b/scripts/record_performance_baseline.py @@ -7,7 +7,7 @@ from dataclasses import asdict from datetime import date from pathlib import Path -from inire.tests.example_scenarios import PERFORMANCE_SCENARIO_SNAPSHOTS, SCENARIO_SNAPSHOTS +from inire.tests.example_scenarios import SCENARIO_SNAPSHOTS SUMMARY_METRICS = ( @@ -24,20 +24,10 @@ SUMMARY_METRICS = ( ) -def _snapshot_registry(include_performance_only: bool) -> tuple[tuple[str, object], ...]: - if not include_performance_only: - return SCENARIO_SNAPSHOTS - return SCENARIO_SNAPSHOTS + PERFORMANCE_SCENARIO_SNAPSHOTS - - -def _build_payload( - selected_scenarios: tuple[str, ...] | None = None, - *, - include_performance_only: bool = False, -) -> dict[str, object]: +def _build_payload(selected_scenarios: tuple[str, ...] | None = None) -> dict[str, object]: allowed = None if selected_scenarios is None else set(selected_scenarios) snapshots = [] - for name, run in _snapshot_registry(include_performance_only): + for name, run in SCENARIO_SNAPSHOTS: if allowed is not None and name not in allowed: continue snapshots.append(run()) @@ -56,7 +46,6 @@ def _render_markdown(payload: dict[str, object]) -> str: f"Generated on {payload['generated_on']} by `{payload['generator']}`.", "", "The full machine-readable snapshot lives in `docs/performance_baseline.json`.", - "Use `scripts/diff_performance_baseline.py` to compare a fresh run against that snapshot.", "", "| Scenario | Duration (s) | Total | Valid | Reached | Iter | Nets Routed | Nodes | Ray Casts | Moves Gen | Moves Added | Dyn Tree | Visibility Builds | Congestion Checks | Verify Calls |", "| :-- | --: | --: | --: | --: | --: | --: | --: | --: | --: | --: | --: | --: | --: | --: |", @@ -88,7 +77,6 @@ def _render_markdown(payload: dict[str, object]) -> str: "## Full Counter Set", "", "Each scenario entry in `docs/performance_baseline.json` records the full `RouteMetrics` snapshot, including cache, index, congestion, and verification counters.", - "These counters are currently observational only and are not enforced as CI regression gates.", "", "Tracked metric keys:", "", @@ -113,11 +101,6 @@ def main() -> None: default=[], help="Optional scenario name to include. May be passed more than once.", ) - parser.add_argument( - "--include-performance-only", - action="store_true", - help="Include performance-only snapshot scenarios that are excluded from the default baseline corpus.", - ) args = parser.parse_args() repo_root = Path(__file__).resolve().parents[1] @@ -125,7 +108,7 @@ def main() -> None: docs_dir.mkdir(exist_ok=True) selected = tuple(args.scenarios) if args.scenarios else None - payload = _build_payload(selected, include_performance_only=args.include_performance_only) + payload = _build_payload(selected) json_path = docs_dir / "performance_baseline.json" markdown_path = docs_dir / "performance.md"