namespace StellaOps.ElkSharp; internal static partial class ElkEdgeRouterIterative { private static CandidateSolution RefineHybridWinningSolution( CandidateSolution best, ElkPositionedNode[] nodes, ElkLayoutDirection direction, double minLineClearance, bool preferLowWaveRuntimePolish = false) { static string DescribeSolution(CandidateSolution solution) { return $"score={solution.Score.Value:F0} retry={DescribeRetryState(solution.RetryState)}"; } var current = best; ElkLayoutDiagnostics.LogProgress($"Hybrid winner refinement start: {DescribeSolution(current)}"); if (current.RetryState.UnderNodeViolations > 0) { current = ApplyFinalDirectUnderNodePolish(current, nodes, minLineClearance); ElkLayoutDiagnostics.LogProgress($"Hybrid winner refinement after under-node polish: {DescribeSolution(current)}"); } if (current.RetryState.UnderNodeViolations > 0 || current.RetryState.TargetApproachJoinViolations > 0) { current = ApplyFinalProtectedLocalBundlePolish(current, nodes, minLineClearance); ElkLayoutDiagnostics.LogProgress($"Hybrid winner refinement after local-bundle polish: {DescribeSolution(current)}"); } if (current.RetryState.SharedLaneViolations > 0 || current.RetryState.TargetApproachJoinViolations > 0) { current = ApplyFinalSharedLanePolish( current, nodes, direction, minLineClearance, preferLeanTerminalCleanup: preferLowWaveRuntimePolish); ElkLayoutDiagnostics.LogProgress($"Hybrid winner refinement after shared-lane polish: {DescribeSolution(current)}"); } if (current.RetryState.BoundarySlotViolations > 0 || current.RetryState.GatewaySourceExitViolations > 0 || current.RetryState.EntryAngleViolations > 0) { current = ApplyFinalBoundarySlotPolish(current, nodes, direction, minLineClearance, maxRounds: 1); ElkLayoutDiagnostics.LogProgress($"Hybrid winner refinement after boundary-slot polish: {DescribeSolution(current)}"); } if (current.RetryState.ExcessiveDetourViolations > 0 || (!preferLowWaveRuntimePolish && current.RetryState.GatewaySourceExitViolations > 0)) { current = ApplyWinnerDetourPolish(current, nodes, minLineClearance); ElkLayoutDiagnostics.LogProgress($"Hybrid winner refinement after detour polish: {DescribeSolution(current)}"); } if (HasHybridHardRulePressure(current.RetryState)) { current = preferLowWaveRuntimePolish ? ApplyHybridLeanPostSlotHardRulePolish(current, nodes, direction, minLineClearance) : ApplyFinalPostSlotHardRulePolish(current, nodes, direction, minLineClearance, maxRounds: 1); ElkLayoutDiagnostics.LogProgress($"Hybrid winner refinement after post-slot hard-rule polish: {DescribeSolution(current)}"); } // Final gateway backtracking repair: run NormalizeBoundaryAngles one // last time to catch gateway target overshoots that earlier pipeline // steps may have re-introduced. Accept with net-total comparison. if (current.RetryState.TargetApproachBacktrackingViolations > 0 || current.RetryState.EntryAngleViolations > 0) { var finalNormalized = ElkEdgePostProcessor.NormalizeBoundaryAngles(current.Edges, nodes); finalNormalized = ElkEdgePostProcessor.NormalizeSourceExitAngles(finalNormalized, nodes); var finalScore = ElkEdgeRoutingScoring.ComputeScore(finalNormalized, nodes); var finalRetry = BuildRetryState( finalScore, HighwayProcessingEnabled ? ElkEdgeRouterHighway.DetectRemainingBrokenHighways(finalNormalized, nodes).Count : 0); var currentHard = CountTotalHardViolations(current.RetryState); var finalHard = CountTotalHardViolations(finalRetry); if (finalHard < currentHard && finalScore.NodeCrossings <= current.Score.NodeCrossings) { current = current with { Score = finalScore, RetryState = finalRetry, Edges = finalNormalized }; ElkLayoutDiagnostics.LogProgress($"Hybrid winner refinement after final normalization: {DescribeSolution(current)}"); } } // Targeted under-node elevation with net-total promotion. // ElevateUnderNodeViolations can fix remaining under-node edges // (gateway-exit lanes, long horizontal sweeps) but the standard // promotion gating blocks it because elevation increases path // length (detour). Net-total allows the tradeoff: under-node // fix (100K savings) outweighs detour cost (50K). if (current.RetryState.UnderNodeViolations > 0) { var elevated = ElkEdgePostProcessor.ElevateUnderNodeViolations( current.Edges, nodes, minLineClearance); elevated = ElkEdgePostProcessor.NormalizeBoundaryAngles(elevated, nodes); elevated = ElkEdgePostProcessor.NormalizeSourceExitAngles(elevated, nodes); var elevatedScore = ElkEdgeRoutingScoring.ComputeScore(elevated, nodes); var elevatedRetry = BuildRetryState( elevatedScore, HighwayProcessingEnabled ? ElkEdgeRouterHighway.DetectRemainingBrokenHighways(elevated, nodes).Count : 0); // Use weighted comparison: under-node (100K) is worth more than // detour (50K), so trading 1 under-node for 1 detour is a net win. if (elevatedScore.Value > current.Score.Value && elevatedScore.NodeCrossings <= current.Score.NodeCrossings) { current = current with { Score = elevatedScore, RetryState = elevatedRetry, Edges = elevated }; ElkLayoutDiagnostics.LogProgress($"Hybrid winner refinement after under-node elevation: {DescribeSolution(current)}"); } } return current; } private static bool HasHybridHardRulePressure(RoutingRetryState retryState) { return retryState.RemainingShortHighways > 0 || retryState.RepeatCollectorCorridorViolations > 0 || retryState.RepeatCollectorNodeClearanceViolations > 0 || retryState.TargetApproachJoinViolations > 0 || retryState.TargetApproachBacktrackingViolations > 0 || retryState.ExcessiveDetourViolations > 0 || retryState.SharedLaneViolations > 0 || retryState.BoundarySlotViolations > 0 || retryState.BelowGraphViolations > 0 || retryState.UnderNodeViolations > 0 || retryState.EntryAngleViolations > 0 || retryState.GatewaySourceExitViolations > 0; } }