using System.Diagnostics; namespace StellaOps.ElkSharp; internal static partial class ElkEdgeRouterIterative { /// /// Creates a worst-case retry state used as the initial "best" baseline /// in the strategy evaluation loop. /// private static RoutingRetryState BuildMaxRetryState() { return new RoutingRetryState( RemainingShortHighways: int.MaxValue, RepeatCollectorCorridorViolations: int.MaxValue, RepeatCollectorNodeClearanceViolations: int.MaxValue, TargetApproachJoinViolations: int.MaxValue, TargetApproachBacktrackingViolations: int.MaxValue, ExcessiveDetourViolations: int.MaxValue, SharedLaneViolations: int.MaxValue, BoundarySlotViolations: int.MaxValue, BelowGraphViolations: int.MaxValue, UnderNodeViolations: int.MaxValue, LongDiagonalViolations: int.MaxValue, ProximityViolations: int.MaxValue, EntryAngleViolations: int.MaxValue, GatewaySourceExitViolations: int.MaxValue, LabelProximityViolations: int.MaxValue, EdgeCrossings: int.MaxValue); } /// /// Checks stagnation conditions: repeated repair focus, repeated plateau /// fingerprints, and blocking cycle detection. Returns the stagnation /// outcome reason or null if the attempt should continue. /// private static string? DetectStrategyStagnation( RepairPlan? repairPlan, RoutingRetryState retryState, RoutingRetryState bestAttemptRetryState, int attempt, ref string? lastRepairFocusFingerprint, ref int repeatedRepairFocusCount, ref string? lastPlateauFingerprint, ref int repeatedPlateauFingerprintCount, List recentBlockingCycleFingerprints) { var repairFocusFingerprint = BuildRepairFocusFingerprint(repairPlan); if (!string.IsNullOrEmpty(repairFocusFingerprint)) { if (string.Equals(repairFocusFingerprint, lastRepairFocusFingerprint, StringComparison.Ordinal)) { repeatedRepairFocusCount++; } else { lastRepairFocusFingerprint = repairFocusFingerprint; repeatedRepairFocusCount = 0; } if (repeatedRepairFocusCount >= 1 && attempt >= 3) { return $"stalled-same-focus({DescribeRetryState(retryState)})@attempt{attempt + 1}"; } } else { lastRepairFocusFingerprint = null; repeatedRepairFocusCount = 0; } var plateauFingerprint = BuildPlateauFingerprint(retryState, repairPlan); if (string.Equals(plateauFingerprint, lastPlateauFingerprint, StringComparison.Ordinal)) { repeatedPlateauFingerprintCount++; } else { lastPlateauFingerprint = plateauFingerprint; repeatedPlateauFingerprintCount = 0; } if (repeatedPlateauFingerprintCount >= 2 && attempt >= 3) { return $"stalled-repeat({DescribeRetryState(retryState)})@attempt{attempt + 1}"; } var blockingCycleFingerprint = BuildBlockingCycleFingerprint(retryState, repairPlan); if (ShouldStopForBlockingCycle( recentBlockingCycleFingerprints, blockingCycleFingerprint, retryState, bestAttemptRetryState, attempt)) { return $"stalled-cycle({DescribeRetryState(retryState)})@attempt{attempt + 1}"; } AppendRecentFingerprint(recentBlockingCycleFingerprints, blockingCycleFingerprint, 4); return null; } /// /// Determines the retry/accept decision for a strategy attempt based on /// violation categories. Returns the attempt outcome string and whether /// the loop should continue, break, or accept. /// private static (string Outcome, bool ShouldContinue, bool IsValid) DecideStrategyAttemptOutcome( EdgeRoutingScore score, RoutingRetryState retryState, int maxAllowedNodeCrossings, int attempt, int maxAttempts, StrategyWorkItem workItem, RoutingStrategy strategy) { if (score.NodeCrossings > maxAllowedNodeCrossings) { strategy.AdaptForViolations(score, attempt, retryState); return ($"hard-violation(nc={score.NodeCrossings}>{maxAllowedNodeCrossings})@attempt{attempt + 1}", true, false); } if (retryState.RemainingShortHighways > 0 || retryState.RepeatCollectorCorridorViolations > 0 || retryState.RepeatCollectorNodeClearanceViolations > 0 || retryState.TargetApproachJoinViolations > 0 || retryState.TargetApproachBacktrackingViolations > 0 || retryState.SharedLaneViolations > 0 || retryState.BelowGraphViolations > 0 || retryState.UnderNodeViolations > 0 || retryState.LongDiagonalViolations > 0 || retryState.EntryAngleViolations > 0 || retryState.GatewaySourceExitViolations > 0) { if (ShouldRetryForPrimaryViolations(retryState, attempt, maxAttempts)) { strategy.AdaptForViolations(score, attempt, retryState); return ($"retry({DescribeRetryState(retryState)})@attempt{attempt + 1}", true, false); } return ($"invalid({DescribeRetryState(retryState)})@attempt{attempt + 1}", false, false); } if (retryState.RequiresLengthRetry) { if (ShouldRetryForPrimaryViolations(retryState, attempt, maxAttempts)) { strategy.AdaptForViolations(score, attempt, retryState); return ($"retry({DescribeRetryState(retryState)})@attempt{attempt + 1}", true, false); } return ($"invalid({DescribeRetryState(retryState)})@attempt{attempt + 1}", false, false); } if (retryState.RequiresQualityRetry && ShouldRetryForPrimaryViolations(retryState, attempt, maxAttempts)) { strategy.AdaptForViolations(score, attempt, retryState); return ($"retry({DescribeRetryState(retryState)})@attempt{attempt + 1}", true, false); } if (ShouldRetryForEdgeCrossings(retryState, attempt, maxAttempts)) { strategy.AdaptForViolations(score, attempt, retryState); return ($"retry(edge-crossings={retryState.EdgeCrossings})@attempt{attempt + 1}", true, false); } var residualSoftViolations = retryState.RequiresQualityRetry || retryState.EdgeCrossings > 0; var validOutcome = residualSoftViolations ? $"valid-soft({DescribeRetryState(retryState)})@attempt{attempt + 1}" : $"valid@attempt{attempt + 1}"; return (validOutcome, false, true); } }