using System.Collections.Concurrent; using System.Diagnostics; using System.Globalization; namespace StellaOps.ElkSharp; internal static partial class ElkEdgeRouterIterative { private static bool ShouldRetryForEdgeCrossings( RoutingRetryState retryState, int attempt, int maxAdaptationsPerStrategy) { if (retryState.RequiresPrimaryRetry || retryState.EdgeCrossings <= 0) { return false; } return attempt < Math.Max(0, maxAdaptationsPerStrategy - 1); } private static int DetermineAdaptiveAttemptBudget( RoutingRetryState retryState, int maxAdaptationsPerStrategy) { var boundedMaximum = Math.Clamp(maxAdaptationsPerStrategy, 1, 12); if (retryState.RequiresBlockingRetry) { var complexBlocking = retryState.UnderNodeViolations > 0 || retryState.SharedLaneViolations > 0 || retryState.TargetApproachJoinViolations > 0 || retryState.GatewaySourceExitViolations > 0; return Math.Min(boundedMaximum, complexBlocking ? 6 : 5); } if (retryState.RequiresLengthRetry) { return Math.Min(boundedMaximum, 4); } if (retryState.RequiresQualityRetry || retryState.EdgeCrossings > 0) { return Math.Min(boundedMaximum, 3); } return 1; } private static bool ShouldStopForStagnation(int stagnantAttempts, int attempt, int maxAdaptationsPerStrategy) { if (stagnantAttempts <= 0 || attempt < 2) { return false; } var stagnationBudget = Math.Min(Math.Max(4, maxAdaptationsPerStrategy / 12), 8); return stagnantAttempts >= stagnationBudget; } private static bool ShouldRetryForPrimaryViolations( RoutingRetryState retryState, int attempt, int maxAdaptationsPerStrategy) { if (!retryState.RequiresPrimaryRetry) { return false; } return attempt < Math.Max(0, maxAdaptationsPerStrategy - 1); } private static int DetermineTargetValidSolutionCount( RoutingRetryState baselineRetryState, IterativeRoutingConfig config) { if (!baselineRetryState.RequiresPrimaryRetry) { return config.RequiredValidSolutions; } if (baselineRetryState.RequiresBlockingRetry || baselineRetryState.RequiresLengthRetry) { return Math.Min(config.RequiredValidSolutions, 3); } return Math.Min(config.RequiredValidSolutions, 2); } private static int DetermineStrategySearchBudget( RoutingRetryState baselineRetryState, IterativeRoutingConfig config) { if (!baselineRetryState.RequiresPrimaryRetry) { return int.MaxValue; } var severity = baselineRetryState.PrimaryViolationCount + baselineRetryState.EdgeCrossings; var minimumBudget = baselineRetryState.RequiresBlockingRetry || baselineRetryState.RequiresLengthRetry ? 8 : 6; var severityBudget = severity >= 20 ? 8 : severity >= 10 ? 7 : 6; return Math.Min( OrderingNames.Length, Math.Max(minimumBudget, severityBudget)); } private static bool ShouldKeepBaselineSolution( IReadOnlyCollection baselineEdges, IReadOnlyCollection nodes, RoutingRetryState baselineRetryState) { if (baselineRetryState.RepeatCollectorCorridorViolations > 0) { return false; } var hasProtectedEdgeContract = baselineEdges.Any(edge => !string.IsNullOrWhiteSpace(edge.SourcePortId) || !string.IsNullOrWhiteSpace(edge.TargetPortId) || (!string.IsNullOrWhiteSpace(edge.Kind) && edge.Kind.StartsWith("backward|", StringComparison.OrdinalIgnoreCase))); if (baselineEdges.Count <= 8 || nodes.Count <= 8 || hasProtectedEdgeContract) { return true; } return !baselineRetryState.RequiresPrimaryRetry && baselineEdges.Count <= 12; } }