From 2c3aa90544e283160835486ffb5c82f4e68ccaa4 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Thu, 2 Apr 2026 17:10:00 -0700 Subject: [PATCH] Limit late reroutes to conflicting nets --- docs/iteration_trace.json | 1026 ++++------------------- docs/iteration_trace.md | 94 +-- docs/optimization_pass_01_log.md | 22 + docs/performance.md | 36 +- docs/performance_baseline.json | 108 +-- inire/router/_router.py | 27 +- inire/tests/test_api.py | 62 ++ inire/tests/test_astar.py | 1 + inire/tests/test_example_performance.py | 2 +- 9 files changed, 376 insertions(+), 1002 deletions(-) diff --git a/docs/iteration_trace.json b/docs/iteration_trace.json index ef7f3a2..72295bc 100644 --- a/docs/iteration_trace.json +++ b/docs/iteration_trace.json @@ -1,5 +1,5 @@ { - "generated_at": "2026-04-02T16:11:39-07:00", + "generated_at": "2026-04-02T16:46:00-07:00", "generator": "scripts/record_iteration_trace.py", "scenarios": [ { @@ -507,9 +507,9 @@ { "completed_nets": 6, "conflict_edges": 2, - "congestion_candidate_ids": 961, - "congestion_check_calls": 517, - "congestion_exact_pair_checks": 812, + "congestion_candidate_ids": 627, + "congestion_check_calls": 332, + "congestion_exact_pair_checks": 513, "congestion_penalty": 384.15999999999997, "iteration": 4, "net_attempts": [ @@ -533,46 +533,6 @@ "pruned_hard_collision": 0, "reached_target": true }, - { - "congestion_check_calls": 26, - "guidance_seed_present": true, - "net_id": "net_09", - "nodes_expanded": 9, - "pruned_closed_set": 1, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 20, - "guidance_seed_present": true, - "net_id": "net_05", - "nodes_expanded": 3, - "pruned_closed_set": 0, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 46, - "guidance_seed_present": true, - "net_id": "net_08", - "nodes_expanded": 12, - "pruned_closed_set": 4, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 22, - "guidance_seed_present": true, - "net_id": "net_03", - "nodes_expanded": 6, - "pruned_closed_set": 0, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, { "congestion_check_calls": 30, "guidance_seed_present": true, @@ -583,26 +543,6 @@ "pruned_hard_collision": 0, "reached_target": true }, - { - "congestion_check_calls": 51, - "guidance_seed_present": true, - "net_id": "net_02", - "nodes_expanded": 12, - "pruned_closed_set": 3, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 20, - "guidance_seed_present": true, - "net_id": "net_04", - "nodes_expanded": 3, - "pruned_closed_set": 0, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, { "congestion_check_calls": 80, "guidance_seed_present": true, @@ -614,217 +554,86 @@ "reached_target": true } ], - "nodes_expanded": 126, + "nodes_expanded": 81, "routed_net_ids": [ "net_00", "net_06", - "net_09", - "net_05", - "net_08", - "net_03", "net_07", - "net_02", - "net_04", "net_01" ], "total_dynamic_collisions": 10 - }, - { - "completed_nets": 6, - "conflict_edges": 2, - "congestion_candidate_ids": 3805, - "congestion_check_calls": 1704, - "congestion_exact_pair_checks": 3043, - "congestion_penalty": 537.824, - "iteration": 5, - "net_attempts": [ - { - "congestion_check_calls": 26, - "guidance_seed_present": true, - "net_id": "net_00", - "nodes_expanded": 9, - "pruned_closed_set": 1, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 66, - "guidance_seed_present": true, - "net_id": "net_01", - "nodes_expanded": 15, - "pruned_closed_set": 2, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 20, - "guidance_seed_present": true, - "net_id": "net_04", - "nodes_expanded": 3, - "pruned_closed_set": 0, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 26, - "guidance_seed_present": true, - "net_id": "net_09", - "nodes_expanded": 9, - "pruned_closed_set": 1, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 109, - "guidance_seed_present": true, - "net_id": "net_02", - "nodes_expanded": 21, - "pruned_closed_set": 5, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 20, - "guidance_seed_present": true, - "net_id": "net_05", - "nodes_expanded": 3, - "pruned_closed_set": 0, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 46, - "guidance_seed_present": true, - "net_id": "net_08", - "nodes_expanded": 12, - "pruned_closed_set": 4, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 85, - "guidance_seed_present": true, - "net_id": "net_07", - "nodes_expanded": 16, - "pruned_closed_set": 3, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 511, - "guidance_seed_present": true, - "net_id": "net_06", - "nodes_expanded": 137, - "pruned_closed_set": 13, - "pruned_cost": 73, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 795, - "guidance_seed_present": true, - "net_id": "net_03", - "nodes_expanded": 236, - "pruned_closed_set": 28, - "pruned_cost": 149, - "pruned_hard_collision": 0, - "reached_target": true - } - ], - "nodes_expanded": 461, - "routed_net_ids": [ - "net_00", - "net_01", - "net_04", - "net_09", - "net_02", - "net_05", - "net_08", - "net_07", - "net_06", - "net_03" - ], - "total_dynamic_collisions": 10 } ], "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_cache_misses": 2736, + "congestion_candidate_ids": 5785, + "congestion_candidate_nets": 6163, + "congestion_candidate_precheck_hits": 1383, + "congestion_candidate_precheck_misses": 1418, + "congestion_candidate_precheck_skips": 34, + "congestion_check_calls": 2736, + "congestion_exact_pair_checks": 4780, + "congestion_grid_net_cache_hits": 1356, + "congestion_grid_net_cache_misses": 2608, + "congestion_grid_span_cache_hits": 1247, + "congestion_grid_span_cache_misses": 1308, "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": 205681291, + "congestion_net_envelope_cache_hits": 1452, + "congestion_net_envelope_cache_misses": 2720, + "congestion_presence_cache_hits": 1541, + "congestion_presence_cache_misses": 1642, + "congestion_presence_skips": 382, + "danger_map_cache_hits": 11547, + "danger_map_cache_misses": 6063, + "danger_map_lookup_calls": 17610, + "danger_map_query_calls": 6063, + "danger_map_total_ns": 174709728, "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 471, - "dynamic_path_objects_removed": 423, + "dynamic_path_objects_added": 399, + "dynamic_path_objects_removed": 351, "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, + "guidance_bonus_applied": 6750.0, + "guidance_bonus_applied_bend90": 2250.0, + "guidance_bonus_applied_sbend": 375.0, + "guidance_bonus_applied_straight": 4125.0, + "guidance_match_moves": 108, + "guidance_match_moves_bend90": 36, + "guidance_match_moves_sbend": 6, + "guidance_match_moves_straight": 66, "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, + "iteration_conflict_edges": 37, + "iteration_conflicting_nets": 32, + "iteration_reverified_nets": 50, + "iteration_reverify_calls": 5, + "move_cache_abs_hits": 1200, + "move_cache_abs_misses": 5338, + "move_cache_rel_hits": 4768, + "move_cache_rel_misses": 570, + "moves_added": 5853, + "moves_generated": 6538, + "nets_carried_forward": 6, + "nets_reached_target": 44, + "nets_routed": 44, + "nodes_expanded": 1258, "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_closed_set": 374, + "pruned_cost": 311, "pruned_hard_collision": 0, - "ray_cast_calls": 5477, - "ray_cast_calls_expand_forward": 1704, - "ray_cast_calls_expand_snap": 46, + "ray_cast_calls": 4310, + "ray_cast_calls_expand_forward": 1214, + "ray_cast_calls_expand_snap": 39, "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 3721, + "ray_cast_calls_straight_static": 3051, "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_candidate_bounds": 159, "ray_cast_exact_geometry_checks": 0, "refine_path_calls": 10, "refinement_candidate_side_extents": 0, @@ -834,18 +643,18 @@ "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": 232913892, + "route_iterations": 5, + "score_component_calls": 6181, + "score_component_total_ns": 195118641, "static_net_tree_rebuilds": 1, "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 2482, + "static_safe_cache_hits": 1170, "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, + "verify_dynamic_candidate_nets": 1822, + "verify_dynamic_exact_pair_checks": 504, + "verify_path_report_calls": 164, + "verify_static_buffer_ops": 779, "visibility_builds": 0, "visibility_corner_hits_exact": 0, "visibility_corner_index_builds": 1, @@ -856,7 +665,7 @@ "visibility_point_queries": 0, "visibility_tangent_candidate_corner_checks": 6, "visibility_tangent_candidate_ray_tests": 6, - "visibility_tangent_candidate_scans": 1704, + "visibility_tangent_candidate_scans": 1214, "warm_start_paths_built": 0, "warm_start_paths_used": 0 }, @@ -1247,9 +1056,9 @@ { "completed_nets": 4, "conflict_edges": 3, - "congestion_candidate_ids": 801, - "congestion_check_calls": 382, - "congestion_exact_pair_checks": 651, + "congestion_candidate_ids": 557, + "congestion_check_calls": 250, + "congestion_exact_pair_checks": 428, "congestion_penalty": 274.4, "iteration": 3, "net_attempts": [ @@ -1263,26 +1072,6 @@ "pruned_hard_collision": 0, "reached_target": true }, - { - "congestion_check_calls": 20, - "guidance_seed_present": true, - "net_id": "net_05", - "nodes_expanded": 3, - "pruned_closed_set": 0, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 58, - "guidance_seed_present": true, - "net_id": "net_01", - "nodes_expanded": 13, - "pruned_closed_set": 4, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, { "congestion_check_calls": 49, "guidance_seed_present": true, @@ -1293,16 +1082,6 @@ "pruned_hard_collision": 0, "reached_target": true }, - { - "congestion_check_calls": 20, - "guidance_seed_present": true, - "net_id": "net_04", - "nodes_expanded": 3, - "pruned_closed_set": 0, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, { "congestion_check_calls": 36, "guidance_seed_present": true, @@ -1333,16 +1112,6 @@ "pruned_hard_collision": 0, "reached_target": true }, - { - "congestion_check_calls": 34, - "guidance_seed_present": true, - "net_id": "net_00", - "nodes_expanded": 11, - "pruned_closed_set": 1, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, { "congestion_check_calls": 30, "guidance_seed_present": true, @@ -1354,17 +1123,13 @@ "reached_target": true } ], - "nodes_expanded": 84, + "nodes_expanded": 54, "routed_net_ids": [ "net_06", - "net_05", - "net_01", "net_09", - "net_04", "net_03", "net_02", "net_08", - "net_00", "net_07" ], "total_dynamic_collisions": 15 @@ -1372,9 +1137,9 @@ { "completed_nets": 6, "conflict_edges": 2, - "congestion_candidate_ids": 1334, - "congestion_check_calls": 673, - "congestion_exact_pair_checks": 1072, + "congestion_candidate_ids": 1126, + "congestion_check_calls": 550, + "congestion_exact_pair_checks": 884, "congestion_penalty": 384.15999999999997, "iteration": 4, "net_attempts": [ @@ -1398,26 +1163,6 @@ "pruned_hard_collision": 0, "reached_target": true }, - { - "congestion_check_calls": 26, - "guidance_seed_present": true, - "net_id": "net_00", - "nodes_expanded": 9, - "pruned_closed_set": 1, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 48, - "guidance_seed_present": true, - "net_id": "net_01", - "nodes_expanded": 12, - "pruned_closed_set": 4, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, { "congestion_check_calls": 91, "guidance_seed_present": true, @@ -1438,16 +1183,6 @@ "pruned_hard_collision": 0, "reached_target": true }, - { - "congestion_check_calls": 20, - "guidance_seed_present": true, - "net_id": "net_04", - "nodes_expanded": 3, - "pruned_closed_set": 0, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, { "congestion_check_calls": 32, "guidance_seed_present": true, @@ -1459,37 +1194,23 @@ "reached_target": true }, { - "congestion_check_calls": 20, - "guidance_seed_present": true, - "net_id": "net_05", - "nodes_expanded": 3, - "pruned_closed_set": 0, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 201, + "congestion_check_calls": 192, "guidance_seed_present": true, "net_id": "net_03", - "nodes_expanded": 55, + "nodes_expanded": 54, "pruned_closed_set": 7, "pruned_cost": 21, "pruned_hard_collision": 0, "reached_target": true } ], - "nodes_expanded": 170, + "nodes_expanded": 142, "routed_net_ids": [ "net_06", "net_07", - "net_00", - "net_01", "net_08", "net_09", - "net_04", "net_02", - "net_05", "net_03" ], "total_dynamic_collisions": 10 @@ -1497,9 +1218,9 @@ { "completed_nets": 6, "conflict_edges": 2, - "congestion_candidate_ids": 3718, - "congestion_check_calls": 1671, - "congestion_exact_pair_checks": 2992, + "congestion_candidate_ids": 3377, + "congestion_check_calls": 1477, + "congestion_exact_pair_checks": 2666, "congestion_penalty": 537.824, "iteration": 5, "net_attempts": [ @@ -1523,16 +1244,6 @@ "pruned_hard_collision": 0, "reached_target": true }, - { - "congestion_check_calls": 48, - "guidance_seed_present": true, - "net_id": "net_01", - "nodes_expanded": 12, - "pruned_closed_set": 4, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, { "congestion_check_calls": 86, "guidance_seed_present": true, @@ -1544,527 +1255,96 @@ "reached_target": true }, { - "congestion_check_calls": 20, - "guidance_seed_present": true, - "net_id": "net_04", - "nodes_expanded": 3, - "pruned_closed_set": 0, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 803, + "congestion_check_calls": 795, "guidance_seed_present": true, "net_id": "net_03", - "nodes_expanded": 239, + "nodes_expanded": 236, "pruned_closed_set": 28, "pruned_cost": 149, "pruned_hard_collision": 0, "reached_target": true - }, - { - "congestion_check_calls": 46, - "guidance_seed_present": true, - "net_id": "net_08", - "nodes_expanded": 12, - "pruned_closed_set": 4, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 26, - "guidance_seed_present": true, - "net_id": "net_00", - "nodes_expanded": 9, - "pruned_closed_set": 1, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 26, - "guidance_seed_present": true, - "net_id": "net_09", - "nodes_expanded": 9, - "pruned_closed_set": 1, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 20, - "guidance_seed_present": true, - "net_id": "net_05", - "nodes_expanded": 3, - "pruned_closed_set": 0, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true } ], - "nodes_expanded": 457, + "nodes_expanded": 406, "routed_net_ids": [ "net_07", "net_06", - "net_01", "net_02", - "net_04", - "net_03", - "net_08", - "net_00", - "net_09", - "net_05" + "net_03" ], "total_dynamic_collisions": 10 - }, - { - "completed_nets": 4, - "conflict_edges": 4, - "congestion_candidate_ids": 218513, - "congestion_check_calls": 89671, - "congestion_exact_pair_checks": 171925, - "congestion_penalty": 752.9535999999999, - "iteration": 6, - "net_attempts": [ - { - "congestion_check_calls": 20, - "guidance_seed_present": true, - "net_id": "net_05", - "nodes_expanded": 3, - "pruned_closed_set": 0, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 97, - "guidance_seed_present": true, - "net_id": "net_02", - "nodes_expanded": 19, - "pruned_closed_set": 4, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 26, - "guidance_seed_present": true, - "net_id": "net_09", - "nodes_expanded": 9, - "pruned_closed_set": 1, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 26, - "guidance_seed_present": true, - "net_id": "net_00", - "nodes_expanded": 9, - "pruned_closed_set": 1, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 20, - "guidance_seed_present": true, - "net_id": "net_04", - "nodes_expanded": 3, - "pruned_closed_set": 0, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 48, - "guidance_seed_present": true, - "net_id": "net_01", - "nodes_expanded": 12, - "pruned_closed_set": 4, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 96, - "guidance_seed_present": true, - "net_id": "net_07", - "nodes_expanded": 18, - "pruned_closed_set": 3, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 46, - "guidance_seed_present": true, - "net_id": "net_08", - "nodes_expanded": 12, - "pruned_closed_set": 4, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 45308, - "guidance_seed_present": true, - "net_id": "net_03", - "nodes_expanded": 11409, - "pruned_closed_set": 12159, - "pruned_cost": 1513, - "pruned_hard_collision": 49, - "reached_target": true - }, - { - "congestion_check_calls": 43984, - "guidance_seed_present": true, - "net_id": "net_06", - "nodes_expanded": 10794, - "pruned_closed_set": 11293, - "pruned_cost": 1256, - "pruned_hard_collision": 54, - "reached_target": true - } - ], - "nodes_expanded": 22288, - "routed_net_ids": [ - "net_05", - "net_02", - "net_09", - "net_00", - "net_04", - "net_01", - "net_07", - "net_08", - "net_03", - "net_06" - ], - "total_dynamic_collisions": 8 - }, - { - "completed_nets": 4, - "conflict_edges": 4, - "congestion_candidate_ids": 34309, - "congestion_check_calls": 29419, - "congestion_exact_pair_checks": 28603, - "congestion_penalty": 1054.13504, - "iteration": 7, - "net_attempts": [ - { - "congestion_check_calls": 13979, - "guidance_seed_present": true, - "net_id": "net_03", - "nodes_expanded": 7675, - "pruned_closed_set": 5308, - "pruned_cost": 423, - "pruned_hard_collision": 214, - "reached_target": true - }, - { - "congestion_check_calls": 146, - "guidance_seed_present": true, - "net_id": "net_07", - "nodes_expanded": 40, - "pruned_closed_set": 5, - "pruned_cost": 24, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 149, - "guidance_seed_present": true, - "net_id": "net_05", - "nodes_expanded": 55, - "pruned_closed_set": 37, - "pruned_cost": 64, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 26, - "guidance_seed_present": true, - "net_id": "net_09", - "nodes_expanded": 9, - "pruned_closed_set": 1, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 26, - "guidance_seed_present": true, - "net_id": "net_00", - "nodes_expanded": 9, - "pruned_closed_set": 1, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 1269, - "guidance_seed_present": true, - "net_id": "net_02", - "nodes_expanded": 283, - "pruned_closed_set": 117, - "pruned_cost": 49, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 13573, - "guidance_seed_present": true, - "net_id": "net_06", - "nodes_expanded": 7598, - "pruned_closed_set": 4816, - "pruned_cost": 509, - "pruned_hard_collision": 705, - "reached_target": true - }, - { - "congestion_check_calls": 52, - "guidance_seed_present": true, - "net_id": "net_01", - "nodes_expanded": 9, - "pruned_closed_set": 2, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 139, - "guidance_seed_present": true, - "net_id": "net_04", - "nodes_expanded": 48, - "pruned_closed_set": 29, - "pruned_cost": 53, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 60, - "guidance_seed_present": true, - "net_id": "net_08", - "nodes_expanded": 11, - "pruned_closed_set": 2, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - } - ], - "nodes_expanded": 15737, - "routed_net_ids": [ - "net_03", - "net_07", - "net_05", - "net_09", - "net_00", - "net_02", - "net_06", - "net_01", - "net_04", - "net_08" - ], - "total_dynamic_collisions": 8 - }, - { - "completed_nets": 4, - "conflict_edges": 4, - "congestion_candidate_ids": 49314, - "congestion_check_calls": 41803, - "congestion_exact_pair_checks": 41198, - "congestion_penalty": 1475.7890559999998, - "iteration": 8, - "net_attempts": [ - { - "congestion_check_calls": 14281, - "guidance_seed_present": true, - "net_id": "net_03", - "nodes_expanded": 8009, - "pruned_closed_set": 5594, - "pruned_cost": 454, - "pruned_hard_collision": 506, - "reached_target": true - }, - { - "congestion_check_calls": 60, - "guidance_seed_present": true, - "net_id": "net_08", - "nodes_expanded": 11, - "pruned_closed_set": 2, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 1614, - "guidance_seed_present": true, - "net_id": "net_02", - "nodes_expanded": 382, - "pruned_closed_set": 131, - "pruned_cost": 69, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 52, - "guidance_seed_present": true, - "net_id": "net_01", - "nodes_expanded": 9, - "pruned_closed_set": 2, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 26, - "guidance_seed_present": true, - "net_id": "net_00", - "nodes_expanded": 9, - "pruned_closed_set": 1, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 25302, - "guidance_seed_present": true, - "net_id": "net_06", - "nodes_expanded": 12970, - "pruned_closed_set": 9624, - "pruned_cost": 416, - "pruned_hard_collision": 595, - "reached_target": true - }, - { - "congestion_check_calls": 148, - "guidance_seed_present": true, - "net_id": "net_07", - "nodes_expanded": 41, - "pruned_closed_set": 5, - "pruned_cost": 24, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 149, - "guidance_seed_present": true, - "net_id": "net_05", - "nodes_expanded": 55, - "pruned_closed_set": 37, - "pruned_cost": 64, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 139, - "guidance_seed_present": true, - "net_id": "net_04", - "nodes_expanded": 48, - "pruned_closed_set": 29, - "pruned_cost": 53, - "pruned_hard_collision": 0, - "reached_target": true - }, - { - "congestion_check_calls": 32, - "guidance_seed_present": true, - "net_id": "net_09", - "nodes_expanded": 9, - "pruned_closed_set": 1, - "pruned_cost": 0, - "pruned_hard_collision": 0, - "reached_target": true - } - ], - "nodes_expanded": 21543, - "routed_net_ids": [ - "net_03", - "net_08", - "net_02", - "net_01", - "net_00", - "net_06", - "net_07", - "net_05", - "net_04", - "net_09" - ], - "total_dynamic_collisions": 8 } ], "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_cache_hits": 8, + "congestion_cache_misses": 3881, + "congestion_candidate_ids": 9232, + "congestion_candidate_nets": 8483, + "congestion_candidate_precheck_hits": 2207, + "congestion_candidate_precheck_misses": 1793, + "congestion_candidate_precheck_skips": 111, + "congestion_check_calls": 3881, + "congestion_exact_pair_checks": 7234, + "congestion_grid_net_cache_hits": 2169, + "congestion_grid_net_cache_misses": 3238, + "congestion_grid_span_cache_hits": 1997, + "congestion_grid_span_cache_misses": 1628, "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": 4580111255, + "congestion_net_envelope_cache_hits": 2311, + "congestion_net_envelope_cache_misses": 3376, + "congestion_presence_cache_hits": 2443, + "congestion_presence_cache_misses": 2009, + "congestion_presence_skips": 452, + "danger_map_cache_hits": 14603, + "danger_map_cache_misses": 6814, + "danger_map_lookup_calls": 21417, + "danger_map_query_calls": 6814, + "danger_map_total_ns": 181736341, "dynamic_grid_rebuilds": 0, - "dynamic_path_objects_added": 683, - "dynamic_path_objects_removed": 637, + "dynamic_path_objects_added": 397, + "dynamic_path_objects_removed": 350, "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, + "guidance_bonus_applied": 8062.5, + "guidance_bonus_applied_bend90": 3187.5, + "guidance_bonus_applied_sbend": 250.0, + "guidance_bonus_applied_straight": 4625.0, + "guidance_match_moves": 129, + "guidance_match_moves_bend90": 51, + "guidance_match_moves_sbend": 4, + "guidance_match_moves_straight": 74, + "hard_collision_cache_hits": 0, + "iteration_conflict_edges": 39, + "iteration_conflicting_nets": 39, + "iteration_reverified_nets": 60, + "iteration_reverify_calls": 6, + "move_cache_abs_hits": 1915, + "move_cache_abs_misses": 6136, + "move_cache_rel_hits": 5505, + "move_cache_rel_misses": 631, + "moves_added": 7121, + "moves_generated": 8051, + "nets_carried_forward": 14, + "nets_reached_target": 46, + "nets_routed": 46, + "nodes_expanded": 1582, "pair_local_search_accepts": 2, "pair_local_search_attempts": 3, - "pair_local_search_nodes_expanded": 38, + "pair_local_search_nodes_expanded": 39, "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, + "pruned_closed_set": 399, + "pruned_cost": 531, + "pruned_hard_collision": 0, + "ray_cast_calls": 5077, + "ray_cast_calls_expand_forward": 1536, + "ray_cast_calls_expand_snap": 13, "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 103738, + "ray_cast_calls_straight_static": 3522, "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_calls_visibility_tangent": 6, + "ray_cast_candidate_bounds": 316, "ray_cast_exact_geometry_checks": 0, "refine_path_calls": 10, "refinement_candidate_side_extents": 0, @@ -2074,18 +1354,18 @@ "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": 5292565462, + "route_iterations": 6, + "score_component_calls": 7670, + "score_component_total_ns": 205617403, "static_net_tree_rebuilds": 1, "static_raw_tree_rebuilds": 1, - "static_safe_cache_hits": 120231, + "static_safe_cache_hits": 1869, "static_tree_rebuilds": 1, "timeout_events": 0, - "verify_dynamic_candidate_nets": 2985, - "verify_dynamic_exact_pair_checks": 760, - "verify_path_report_calls": 250, - "verify_static_buffer_ops": 1321, + "verify_dynamic_candidate_nets": 1906, + "verify_dynamic_exact_pair_checks": 571, + "verify_path_report_calls": 176, + "verify_static_buffer_ops": 813, "visibility_builds": 0, "visibility_corner_hits_exact": 0, "visibility_corner_index_builds": 1, @@ -2094,9 +1374,9 @@ "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, + "visibility_tangent_candidate_corner_checks": 6, + "visibility_tangent_candidate_ray_tests": 6, + "visibility_tangent_candidate_scans": 1536, "warm_start_paths_built": 0, "warm_start_paths_used": 0 }, diff --git a/docs/iteration_trace.md b/docs/iteration_trace.md index ab4bbad..febbce1 100644 --- a/docs/iteration_trace.md +++ b/docs/iteration_trace.md @@ -1,6 +1,6 @@ # Iteration Trace -Generated at 2026-04-02T16:11:39-07:00 by `scripts/record_iteration_trace.py`. +Generated at 2026-04-02T16:46:00-07:00 by `scripts/record_iteration_trace.py`. ## example_07_large_scale_routing_no_warm_start @@ -12,34 +12,33 @@ Results: 10 valid / 10 reached / 10 total. | 1 | 140.0 | 10 | 2 | 12 | 54 | 253 | 974 | 2378 | 1998 | | 2 | 196.0 | 10 | 4 | 5 | 22 | 253 | 993 | 1928 | 1571 | | 3 | 274.4 | 10 | 6 | 2 | 10 | 100 | 437 | 852 | 698 | -| 4 | 384.2 | 10 | 6 | 2 | 10 | 126 | 517 | 961 | 812 | -| 5 | 537.8 | 10 | 6 | 2 | 10 | 461 | 1704 | 3805 | 3043 | +| 4 | 384.2 | 4 | 6 | 2 | 10 | 81 | 332 | 627 | 513 | Top nets by iteration-attributed nodes expanded: -- `net_03`: 383 -- `net_06`: 292 -- `net_09`: 260 -- `net_00`: 210 -- `net_02`: 190 -- `net_08`: 168 -- `net_01`: 162 -- `net_07`: 61 -- `net_04`: 19 -- `net_05`: 19 +- `net_09`: 242 +- `net_00`: 201 +- `net_02`: 157 +- `net_06`: 155 +- `net_01`: 147 +- `net_08`: 144 +- `net_03`: 141 +- `net_07`: 45 +- `net_04`: 13 +- `net_05`: 13 Top nets by iteration-attributed congestion checks: -- `net_03`: 1242 -- `net_06`: 1080 -- `net_02`: 674 -- `net_01`: 534 -- `net_08`: 262 -- `net_00`: 229 -- `net_07`: 228 -- `net_09`: 176 -- `net_04`: 100 -- `net_05`: 100 +- `net_06`: 569 +- `net_02`: 514 +- `net_01`: 468 +- `net_03`: 425 +- `net_00`: 203 +- `net_08`: 170 +- `net_07`: 143 +- `net_09`: 124 +- `net_04`: 60 +- `net_05`: 60 ## example_07_large_scale_routing_no_warm_start_seed43 @@ -50,36 +49,33 @@ Results: 10 valid / 10 reached / 10 total. | 0 | 100.0 | 10 | 1 | 16 | 50 | 571 | 0 | 0 | 0 | | 1 | 140.0 | 10 | 1 | 13 | 53 | 269 | 961 | 2562 | 2032 | | 2 | 196.0 | 10 | 4 | 3 | 15 | 140 | 643 | 1610 | 1224 | -| 3 | 274.4 | 10 | 4 | 3 | 15 | 84 | 382 | 801 | 651 | -| 4 | 384.2 | 10 | 6 | 2 | 10 | 170 | 673 | 1334 | 1072 | -| 5 | 537.8 | 10 | 6 | 2 | 10 | 457 | 1671 | 3718 | 2992 | -| 6 | 753.0 | 10 | 4 | 4 | 8 | 22288 | 89671 | 218513 | 171925 | -| 7 | 1054.1 | 10 | 4 | 4 | 8 | 15737 | 29419 | 34309 | 28603 | -| 8 | 1475.8 | 10 | 4 | 4 | 8 | 21543 | 41803 | 49314 | 41198 | +| 3 | 274.4 | 6 | 4 | 3 | 15 | 54 | 250 | 557 | 428 | +| 4 | 384.2 | 6 | 6 | 2 | 10 | 142 | 550 | 1126 | 884 | +| 5 | 537.8 | 4 | 6 | 2 | 10 | 406 | 1477 | 3377 | 2666 | Top nets by iteration-attributed nodes expanded: -- `net_06`: 31604 -- `net_03`: 27532 -- `net_02`: 763 -- `net_09`: 286 -- `net_07`: 239 -- `net_00`: 233 -- `net_08`: 218 -- `net_05`: 134 -- `net_01`: 132 -- `net_04`: 118 +- `net_03`: 435 +- `net_09`: 250 +- `net_06`: 242 +- `net_00`: 177 +- `net_08`: 172 +- `net_07`: 140 +- `net_02`: 79 +- `net_01`: 65 +- `net_05`: 12 +- `net_04`: 10 Top nets by iteration-attributed congestion checks: -- `net_06`: 83752 -- `net_03`: 75019 -- `net_02`: 3270 -- `net_07`: 844 -- `net_08`: 540 -- `net_01`: 441 -- `net_05`: 425 -- `net_04`: 398 -- `net_09`: 288 -- `net_00`: 246 +- `net_03`: 1434 +- `net_06`: 893 +- `net_07`: 454 +- `net_08`: 328 +- `net_02`: 290 +- `net_09`: 178 +- `net_01`: 135 +- `net_00`: 82 +- `net_05`: 47 +- `net_04`: 40 diff --git a/docs/optimization_pass_01_log.md b/docs/optimization_pass_01_log.md index c8fab8f..71badd0 100644 --- a/docs/optimization_pass_01_log.md +++ b/docs/optimization_pass_01_log.md @@ -3640,3 +3640,25 @@ Findings: - The pathological `seed 43` basin is not front-loaded. It matches the solved `seed 42` path through iteration `5`, then falls into three extra iterations with only `4` completed nets and `4` conflict edges. - The late blowup is concentrated in two nets, not the whole routing set: `net_06` contributes `31604` attributed nodes and `83752` congestion checks, while `net_03` contributes `27532` nodes and `75019` congestion checks. - This points the next optimization work at late-iteration reroute behavior for a small subset of nets rather than another global congestion or pair-local-search change. + +## Step 65 stop after fully reached two-edge plateau + +Measured on 2026-04-02T16:21:02-07:00. + +Findings: + +- Added a narrow late-iteration stop rule: once every net already reaches target and the best snapshot is down to the final `<=2` dynamic-conflict-edge basin, stop after the first no-improvement iteration and hand off to bounded pair-local repair. +- The solved seed-42 no-warm canary improved from `6` to `5` negotiated-congestion iterations and dropped from about `1764` to `1303` nodes and from `4625` to `2921` congestion checks, while staying `10/10/10`. +- The former seed-43 pathological basin collapsed from about `50s`, `61259` nodes, and `165223` congestion checks to about `2.53s`, `1691` nodes, and `4330` congestion checks, still finishing `10/10/10`. +- Guardrails held unchanged: warmed `example_07` stayed `10/10/10`, and `example_05_orientation_stress` stayed `3/3/3`. + +## Step 66 reroute only current conflict nets in late all-reached phase + +Measured on 2026-04-02T16:46:00-07:00. + +Findings: + +- Once all nets already reach target and the live conflict graph is down to `<=3` edges, the next negotiated iteration now reroutes only the currently conflicting nets instead of all nets. +- The solved seed-42 no-warm canary stayed `10/10/10` and improved from `50` routed nets / `1303` nodes / `2921` congestion checks to `44` routed nets / `1258` nodes / `2736` congestion checks. +- The seed-43 no-warm canary stayed `10/10/10` and improved from `60` routed nets / `1691` nodes / `4330` congestion checks to `46` routed nets / `1582` nodes / `3881` congestion checks. +- Guardrails held: warmed `example_07` stayed `10/10/10`, and `example_05_orientation_stress` stayed `3/3/3` while trimming slightly to `5` routed nets, `297` nodes, and `146` congestion checks. diff --git a/docs/performance.md b/docs/performance.md index 9159243..57d9f76 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -5,39 +5,29 @@ Generated on 2026-04-02 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. +The default baseline table below covers the standard example corpus only. The heavier no-warm `example_07` canaries remain performance-only and are tracked through targeted diffs plus the 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`. -Use `scripts/record_iteration_trace.py` when you want a seed-42 vs seed-43 negotiated-congestion attribution run; the current tracked output lives in `docs/iteration_trace.json` and `docs/iteration_trace.md`. +Use `scripts/characterize_pair_local_search.py` for the tracked no-warm sweep in `docs/pair_local_characterization.json` and `docs/pair_local_characterization.md`. +Use `scripts/record_iteration_trace.py` for the current seed-42 vs seed-43 negotiated-congestion attribution in `docs/iteration_trace.json` and `docs/iteration_trace.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.0038 | 1 | 1 | 1 | 1 | 1 | 2 | 10 | 11 | 7 | 0 | 0 | 0 | 4 | +| example_02_congestion_resolution | 0.3614 | 3 | 3 | 3 | 1 | 3 | 366 | 1164 | 1413 | 668 | 0 | 0 | 0 | 38 | +| example_03_locked_paths | 0.1953 | 2 | 2 | 2 | 2 | 2 | 191 | 657 | 904 | 307 | 0 | 0 | 0 | 16 | +| example_04_sbends_and_radii | 0.0277 | 2 | 2 | 2 | 1 | 2 | 15 | 70 | 123 | 65 | 0 | 0 | 0 | 8 | +| example_05_orientation_stress | 0.2537 | 3 | 3 | 3 | 2 | 5 | 297 | 1274 | 1680 | 689 | 0 | 0 | 146 | 17 | +| example_06_bend_collision_models | 0.2103 | 3 | 3 | 3 | 3 | 3 | 240 | 682 | 1026 | 629 | 0 | 0 | 0 | 12 | +| example_07_large_scale_routing | 0.2074 | 10 | 10 | 10 | 1 | 10 | 78 | 383 | 372 | 227 | 0 | 0 | 0 | 40 | +| example_08_custom_bend_geometry | 0.0186 | 2 | 2 | 2 | 2 | 2 | 18 | 56 | 78 | 56 | 0 | 0 | 0 | 8 | +| example_09_unroutable_best_effort | 0.0079 | 1 | 0 | 0 | 1 | 1 | 3 | 13 | 16 | 10 | 0 | 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. - -The tracked iteration trace adds one more diagnosis target: `example_07_large_scale_routing_no_warm_start_seed43`. That seed now remains performance-only, and its blowup is concentrated in late iterations rather than the initial basin. In the current trace, seed `43` matches seed `42` through iteration `5`, then spends three extra iterations with `4` completed nets while `net_03` and `net_06` dominate both `nodes_expanded` and `congestion_check_calls`. +The current accepted branch keeps the post-loop pair-local scratch reroute and now also narrows late negotiated reroutes to the current conflict set once all nets already reach target and only a few conflict edges remain. That keeps both no-warm `example_07` seeds at `10/10/10` while reducing main-loop work before pair-local repair. Tracked metric keys: diff --git a/docs/performance_baseline.json b/docs/performance_baseline.json index a0477d3..6dd6ae2 100644 --- a/docs/performance_baseline.json +++ b/docs/performance_baseline.json @@ -3,7 +3,7 @@ "generator": "scripts/record_performance_baseline.py", "scenarios": [ { - "duration_s": 0.003964120987802744, + "duration_s": 0.003825429128482938, "metrics": { "congestion_cache_hits": 0, "congestion_cache_misses": 0, @@ -85,7 +85,7 @@ "refinement_windows_considered": 0, "route_iterations": 1, "score_component_calls": 11, - "score_component_total_ns": 18064, + "score_component_total_ns": 16571, "static_net_tree_rebuilds": 1, "static_raw_tree_rebuilds": 0, "static_safe_cache_hits": 1, @@ -115,7 +115,7 @@ "valid_results": 1 }, { - "duration_s": 0.3377689190674573, + "duration_s": 0.36141274496912956, "metrics": { "congestion_cache_hits": 0, "congestion_cache_misses": 0, @@ -197,7 +197,7 @@ "refinement_windows_considered": 10, "route_iterations": 1, "score_component_calls": 976, - "score_component_total_ns": 1140704, + "score_component_total_ns": 1143187, "static_net_tree_rebuilds": 3, "static_raw_tree_rebuilds": 0, "static_safe_cache_hits": 1, @@ -227,7 +227,7 @@ "valid_results": 3 }, { - "duration_s": 0.1929313091095537, + "duration_s": 0.19532882701605558, "metrics": { "congestion_cache_hits": 0, "congestion_cache_misses": 0, @@ -309,7 +309,7 @@ "refinement_windows_considered": 2, "route_iterations": 2, "score_component_calls": 504, - "score_component_total_ns": 565410, + "score_component_total_ns": 565663, "static_net_tree_rebuilds": 2, "static_raw_tree_rebuilds": 1, "static_safe_cache_hits": 1, @@ -339,7 +339,7 @@ "valid_results": 2 }, { - "duration_s": 0.02791503700427711, + "duration_s": 0.027705274987965822, "metrics": { "congestion_cache_hits": 0, "congestion_cache_misses": 0, @@ -421,7 +421,7 @@ "refinement_windows_considered": 0, "route_iterations": 1, "score_component_calls": 90, - "score_component_total_ns": 100083, + "score_component_total_ns": 96756, "static_net_tree_rebuilds": 2, "static_raw_tree_rebuilds": 0, "static_safe_cache_hits": 1, @@ -451,73 +451,73 @@ "valid_results": 2 }, { - "duration_s": 0.23665715800598264, + "duration_s": 0.25367443496361375, "metrics": { - "congestion_cache_hits": 4, - "congestion_cache_misses": 149, + "congestion_cache_hits": 3, + "congestion_cache_misses": 146, "congestion_candidate_ids": 32, "congestion_candidate_nets": 23, - "congestion_candidate_precheck_hits": 131, - "congestion_candidate_precheck_misses": 22, + "congestion_candidate_precheck_hits": 129, + "congestion_candidate_precheck_misses": 20, "congestion_candidate_precheck_skips": 0, - "congestion_check_calls": 149, + "congestion_check_calls": 146, "congestion_exact_pair_checks": 30, "congestion_grid_net_cache_hits": 16, - "congestion_grid_net_cache_misses": 28, + "congestion_grid_net_cache_misses": 26, "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, + "congestion_net_envelope_cache_hits": 127, + "congestion_net_envelope_cache_misses": 39, + "congestion_presence_cache_hits": 196, + "congestion_presence_cache_misses": 27, + "congestion_presence_skips": 74, "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_path_objects_added": 48, + "dynamic_path_objects_removed": 36, "dynamic_tree_rebuilds": 0, - "guidance_bonus_applied": 687.5, + "guidance_bonus_applied": 562.5, "guidance_bonus_applied_bend90": 500.0, "guidance_bonus_applied_sbend": 0.0, - "guidance_bonus_applied_straight": 187.5, - "guidance_match_moves": 11, + "guidance_bonus_applied_straight": 62.5, + "guidance_match_moves": 9, "guidance_match_moves_bend90": 8, "guidance_match_moves_sbend": 0, - "guidance_match_moves_straight": 3, + "guidance_match_moves_straight": 1, "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_hits": 374, "move_cache_abs_misses": 1306, "move_cache_rel_hits": 1204, "move_cache_rel_misses": 102, - "moves_added": 696, - "moves_generated": 1691, - "nets_carried_forward": 0, - "nets_reached_target": 6, - "nets_routed": 6, - "nodes_expanded": 299, + "moves_added": 689, + "moves_generated": 1680, + "nets_carried_forward": 1, + "nets_reached_target": 5, + "nets_routed": 5, + "nodes_expanded": 297, "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, + "pruned_cost": 533, "pruned_hard_collision": 14, - "ray_cast_calls": 1284, - "ray_cast_calls_expand_forward": 293, - "ray_cast_calls_expand_snap": 3, + "ray_cast_calls": 1274, + "ray_cast_calls_expand_forward": 292, + "ray_cast_calls_expand_snap": 2, "ray_cast_calls_other": 0, - "ray_cast_calls_straight_static": 979, + "ray_cast_calls_straight_static": 971, "ray_cast_calls_visibility_build": 0, "ray_cast_calls_visibility_query": 0, "ray_cast_calls_visibility_tangent": 9, @@ -532,16 +532,16 @@ "refinement_static_bounds_checked": 0, "refinement_windows_considered": 0, "route_iterations": 2, - "score_component_calls": 1245, - "score_component_total_ns": 1260961, + "score_component_calls": 1234, + "score_component_total_ns": 1311211, "static_net_tree_rebuilds": 3, "static_raw_tree_rebuilds": 0, - "static_safe_cache_hits": 9, + "static_safe_cache_hits": 8, "static_tree_rebuilds": 1, "timeout_events": 0, "verify_dynamic_candidate_nets": 8, "verify_dynamic_exact_pair_checks": 12, - "verify_path_report_calls": 18, + "verify_path_report_calls": 17, "verify_static_buffer_ops": 0, "visibility_builds": 0, "visibility_corner_hits_exact": 0, @@ -553,7 +553,7 @@ "visibility_point_queries": 0, "visibility_tangent_candidate_corner_checks": 70, "visibility_tangent_candidate_ray_tests": 9, - "visibility_tangent_candidate_scans": 293, + "visibility_tangent_candidate_scans": 292, "warm_start_paths_built": 2, "warm_start_paths_used": 2 }, @@ -563,7 +563,7 @@ "valid_results": 3 }, { - "duration_s": 0.19982667709700763, + "duration_s": 0.21031348290853202, "metrics": { "congestion_cache_hits": 0, "congestion_cache_misses": 0, @@ -589,7 +589,7 @@ "danger_map_cache_misses": 731, "danger_map_lookup_calls": 1914, "danger_map_query_calls": 731, - "danger_map_total_ns": 18959782, + "danger_map_total_ns": 19983976, "dynamic_grid_rebuilds": 0, "dynamic_path_objects_added": 54, "dynamic_path_objects_removed": 36, @@ -645,7 +645,7 @@ "refinement_windows_considered": 0, "route_iterations": 3, "score_component_calls": 842, - "score_component_total_ns": 21338709, + "score_component_total_ns": 22474166, "static_net_tree_rebuilds": 3, "static_raw_tree_rebuilds": 3, "static_safe_cache_hits": 141, @@ -675,7 +675,7 @@ "valid_results": 3 }, { - "duration_s": 0.20046633295714855, + "duration_s": 0.20740868314169347, "metrics": { "congestion_cache_hits": 0, "congestion_cache_misses": 0, @@ -701,7 +701,7 @@ "danger_map_cache_misses": 448, "danger_map_lookup_calls": 681, "danger_map_query_calls": 448, - "danger_map_total_ns": 11017087, + "danger_map_total_ns": 11224403, "dynamic_grid_rebuilds": 0, "dynamic_path_objects_added": 132, "dynamic_path_objects_removed": 88, @@ -757,7 +757,7 @@ "refinement_windows_considered": 0, "route_iterations": 1, "score_component_calls": 291, - "score_component_total_ns": 11869917, + "score_component_total_ns": 12117666, "static_net_tree_rebuilds": 10, "static_raw_tree_rebuilds": 1, "static_safe_cache_hits": 6, @@ -787,7 +787,7 @@ "valid_results": 10 }, { - "duration_s": 0.01759456400759518, + "duration_s": 0.018604618962854147, "metrics": { "congestion_cache_hits": 0, "congestion_cache_misses": 0, @@ -869,7 +869,7 @@ "refinement_windows_considered": 0, "route_iterations": 2, "score_component_calls": 72, - "score_component_total_ns": 85864, + "score_component_total_ns": 87655, "static_net_tree_rebuilds": 2, "static_raw_tree_rebuilds": 0, "static_safe_cache_hits": 2, @@ -899,7 +899,7 @@ "valid_results": 2 }, { - "duration_s": 0.005838233977556229, + "duration_s": 0.00794802000746131, "metrics": { "congestion_cache_hits": 0, "congestion_cache_misses": 0, @@ -925,7 +925,7 @@ "danger_map_cache_misses": 20, "danger_map_lookup_calls": 30, "danger_map_query_calls": 20, - "danger_map_total_ns": 523870, + "danger_map_total_ns": 675454, "dynamic_grid_rebuilds": 0, "dynamic_path_objects_added": 2, "dynamic_path_objects_removed": 1, @@ -981,7 +981,7 @@ "refinement_windows_considered": 0, "route_iterations": 1, "score_component_calls": 14, - "score_component_total_ns": 563611, + "score_component_total_ns": 722637, "static_net_tree_rebuilds": 1, "static_raw_tree_rebuilds": 1, "static_safe_cache_hits": 0, diff --git a/inire/router/_router.py b/inire/router/_router.py index 3f1f400..920d6b6 100644 --- a/inire/router/_router.py +++ b/inire/router/_router.py @@ -52,6 +52,7 @@ class _RoutingState: last_conflict_signature: tuple[tuple[str, str], ...] last_conflict_edge_count: int repeated_conflict_count: int + pair_local_plateau_count: int @dataclass(slots=True) @@ -217,6 +218,7 @@ class PathFinder: last_conflict_signature=(), last_conflict_edge_count=0, repeated_conflict_count=0, + pair_local_plateau_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) @@ -949,22 +951,43 @@ class PathFinder: iteration_callback: Callable[[int, dict[str, RoutingResult]], None] | None, ) -> bool: congestion = self.context.options.congestion + reroute_net_ids = set(state.ordered_net_ids) for iteration in range(congestion.max_iterations): review = self._run_iteration( state, iteration, - set(state.ordered_net_ids), + reroute_net_ids, iteration_callback, ) if review is None: return True - self._update_best_iteration(state, review) + improved = self._update_best_iteration(state, review) if not any( result.outcome in {"colliding", "partial", "unroutable"} for result in state.results.values() ): return False + all_reached_target = ( + len(state.results) == len(state.ordered_net_ids) + and all(result.reached_target for result in state.results.values()) + ) + reroute_net_ids = set(state.ordered_net_ids) + if all_reached_target and 0 < len(review.conflict_edges) <= 3: + reroute_net_ids = set(review.conflicting_nets) + if improved: + state.pair_local_plateau_count = 0 + elif all_reached_target and state.best_conflict_edges <= 2: + # Once all nets reach target and the best snapshot is already in the + # final <=2-edge basin, later negotiated reroutes tend to churn. + # Hand off to the bounded pair-local repair instead of exploring + # additional late iterations that are not improving the best state. + state.pair_local_plateau_count += 1 + if state.pair_local_plateau_count >= 1: + return False + else: + state.pair_local_plateau_count = 0 + current_signature = tuple(sorted(review.conflict_edges)) repeated = ( bool(current_signature) diff --git a/inire/tests/test_api.py b/inire/tests/test_api.py index b58bce1..a724e90 100644 --- a/inire/tests/test_api.py +++ b/inire/tests/test_api.py @@ -352,6 +352,68 @@ def test_reverify_iterations_stop_early_on_stalled_conflict_graph() -> None: assert run.metrics.route_iterations < 10 +def test_reverify_iterations_limit_late_reroutes_to_conflicting_nets(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), + NetSpec("netC", Port(10, 20, 0), Port(90, 20, 0), width=2.0), + ), + ) + options = RoutingOptions( + congestion=CongestionOptions(max_iterations=10, warm_start_enabled=False), + refinement=RefinementOptions(enabled=False), + ) + evaluator = CostEvaluator(RoutingWorld(clearance=2.0), DangerMap(bounds=problem.bounds)) + pathfinder = PathFinder(AStarContext(evaluator, problem, options)) + colliding_a = RoutingResult( + net_id="netA", + path=(Straight.generate(Port(10, 50, 0), 80.0, 2.0, dilation=1.0),), + reached_target=True, + report=RoutingReport(dynamic_collision_count=1, total_length=80.0), + ) + colliding_b = RoutingResult( + net_id="netB", + path=(Straight.generate(Port(50, 10, 90), 80.0, 2.0, dilation=1.0),), + reached_target=True, + report=RoutingReport(dynamic_collision_count=1, total_length=80.0), + ) + completed_c = RoutingResult( + net_id="netC", + path=(Straight.generate(Port(10, 20, 0), 80.0, 2.0, dilation=1.0),), + reached_target=True, + report=RoutingReport(total_length=80.0), + ) + iterations_seen: list[int] = [] + reroute_sets: list[set[str]] = [] + + def fake_run_iteration(self, state, iteration, reroute_net_ids, iteration_callback): + _ = self + _ = iteration_callback + iterations_seen.append(iteration) + reroute_sets.append(set(reroute_net_ids)) + state.results = {"netA": colliding_a, "netB": colliding_b, "netC": completed_c} + return _IterationReview( + conflicting_nets={"netA", "netB"}, + conflict_edges={("netA", "netB")}, + completed_net_ids={"netC"}, + total_dynamic_collisions=2, + ) + + monkeypatch.setattr(PathFinder, "_run_iteration", fake_run_iteration) + monkeypatch.setattr(PathFinder, "_verify_results", lambda self, state: dict(state.results)) + monkeypatch.setattr(PathFinder, "_run_pair_local_search", lambda self, state: None) + + results = pathfinder.route_all() + + assert iterations_seen == [0, 1] + assert reroute_sets == [{"netA", "netB", "netC"}, {"netA", "netB"}] + assert results["netA"].outcome == "colliding" + assert results["netB"].outcome == "colliding" + assert results["netC"].outcome == "completed" + + def test_route_all_restores_best_iteration_snapshot(monkeypatch: pytest.MonkeyPatch) -> None: problem = RoutingProblem( bounds=(0, 0, 100, 100), diff --git a/inire/tests/test_astar.py b/inire/tests/test_astar.py index 3a0382c..0fc106f 100644 --- a/inire/tests/test_astar.py +++ b/inire/tests/test_astar.py @@ -288,6 +288,7 @@ def test_pair_local_context_clones_live_static_obstacles() -> None: last_conflict_signature=(), last_conflict_edge_count=0, repeated_conflict_count=0, + pair_local_plateau_count=0, ) local_context = finder._build_pair_local_context(state, {}, ("pair_a", "pair_b")) diff --git a/inire/tests/test_example_performance.py b/inire/tests/test_example_performance.py index 26d5504..adf7bfb 100644 --- a/inire/tests/test_example_performance.py +++ b/inire/tests/test_example_performance.py @@ -22,7 +22,7 @@ RUN_PERFORMANCE = os.environ.get("INIRE_RUN_PERFORMANCE") == "1" PERFORMANCE_REPEATS = 3 REGRESSION_FACTOR = 1.5 NO_WARM_START_REGRESSION_SECONDS = 15.0 -NO_WARM_START_SEED43_REGRESSION_SECONDS = 120.0 +NO_WARM_START_SEED43_REGRESSION_SECONDS = 20.0 # Baselines are measured from clean 6a28dcf-style runs without plotting. BASELINE_SECONDS = {