Files
git.stella-ops.org/src/__Libraries/StellaOps.ElkSharp/ElkEdgeRouterIterative.LocalRepair.RetryBudgets.cs

141 lines
4.2 KiB
C#

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<ElkRoutedEdge> baselineEdges,
IReadOnlyCollection<ElkPositionedNode> 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;
}
}