Refactor ElkSharp hybrid routing and document speed path
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
|
||||
namespace StellaOps.ElkSharp;
|
||||
|
||||
internal static partial class ElkEdgeRouterIterative
|
||||
{
|
||||
private static CandidateSolution ApplyFinalSharedLanePolish(
|
||||
CandidateSolution solution,
|
||||
ElkPositionedNode[] nodes,
|
||||
ElkLayoutDirection direction,
|
||||
double minLineClearance,
|
||||
bool preferLeanTerminalCleanup = false)
|
||||
{
|
||||
var current = solution;
|
||||
if (current.RetryState.SharedLaneViolations <= 0)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
var maxRounds = preferLeanTerminalCleanup ? 1 : 3;
|
||||
for (var round = 0; round < maxRounds; round++)
|
||||
{
|
||||
var sharedLaneSeverity = new Dictionary<string, int>(StringComparer.Ordinal);
|
||||
ElkEdgeRoutingScoring.CountSharedLaneViolations(current.Edges, nodes, sharedLaneSeverity, 10);
|
||||
if (sharedLaneSeverity.Count == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var improved = false;
|
||||
foreach (var edgeId in sharedLaneSeverity
|
||||
.OrderByDescending(pair => pair.Value)
|
||||
.ThenBy(pair => pair.Key, StringComparer.Ordinal)
|
||||
.Select(pair => pair.Key))
|
||||
{
|
||||
var focusEdgeIds = ExpandSharedLanePolishFocus(current.Edges, nodes, edgeId).ToArray();
|
||||
if (focusEdgeIds.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var directCandidate = ElkEdgePostProcessor.SeparateSharedLaneConflicts(
|
||||
current.Edges,
|
||||
nodes,
|
||||
minLineClearance,
|
||||
focusEdgeIds);
|
||||
var directClosureCandidate = preferLeanTerminalCleanup
|
||||
? ApplyHybridTerminalRuleCleanupRound(
|
||||
directCandidate,
|
||||
nodes,
|
||||
direction,
|
||||
minLineClearance,
|
||||
focusEdgeIds)
|
||||
: CloseRemainingTerminalViolations(
|
||||
directCandidate,
|
||||
nodes,
|
||||
direction,
|
||||
minLineClearance,
|
||||
focusEdgeIds);
|
||||
var closureCandidate = preferLeanTerminalCleanup
|
||||
? ApplyHybridTerminalRuleCleanupRound(
|
||||
current.Edges,
|
||||
nodes,
|
||||
direction,
|
||||
minLineClearance,
|
||||
focusEdgeIds)
|
||||
: CloseRemainingTerminalViolations(
|
||||
current.Edges,
|
||||
nodes,
|
||||
direction,
|
||||
minLineClearance,
|
||||
focusEdgeIds);
|
||||
var aggressiveCandidate = ApplyAggressiveSharedLaneClosure(
|
||||
current.Edges,
|
||||
nodes,
|
||||
direction,
|
||||
minLineClearance,
|
||||
focusEdgeIds);
|
||||
var directRetryState = BuildRetryState(
|
||||
ElkEdgeRoutingScoring.ComputeScore(directCandidate, nodes),
|
||||
HighwayProcessingEnabled
|
||||
? ElkEdgeRouterHighway.DetectRemainingBrokenHighways(directCandidate, nodes).Count
|
||||
: 0);
|
||||
var directClosureRetryState = BuildRetryState(
|
||||
ElkEdgeRoutingScoring.ComputeScore(directClosureCandidate, nodes),
|
||||
HighwayProcessingEnabled
|
||||
? ElkEdgeRouterHighway.DetectRemainingBrokenHighways(directClosureCandidate, nodes).Count
|
||||
: 0);
|
||||
var closureRetryState = BuildRetryState(
|
||||
ElkEdgeRoutingScoring.ComputeScore(closureCandidate, nodes),
|
||||
HighwayProcessingEnabled
|
||||
? ElkEdgeRouterHighway.DetectRemainingBrokenHighways(closureCandidate, nodes).Count
|
||||
: 0);
|
||||
var aggressiveRetryState = BuildRetryState(
|
||||
ElkEdgeRoutingScoring.ComputeScore(aggressiveCandidate, nodes),
|
||||
HighwayProcessingEnabled
|
||||
? ElkEdgeRouterHighway.DetectRemainingBrokenHighways(aggressiveCandidate, nodes).Count
|
||||
: 0);
|
||||
ElkLayoutDiagnostics.LogProgress(
|
||||
$"Winner shared-lane focus edge={edgeId} focus=[{string.Join(", ", focusEdgeIds)}] " +
|
||||
$"direct={DescribeRetryState(directRetryState)} " +
|
||||
$"direct-closure={DescribeRetryState(directClosureRetryState)} " +
|
||||
$"closure={DescribeRetryState(closureRetryState)} " +
|
||||
$"aggressive={DescribeRetryState(aggressiveRetryState)}");
|
||||
var candidateEdges = ChoosePreferredSharedLanePolishLayout(directCandidate, directClosureCandidate, nodes);
|
||||
candidateEdges = ChoosePreferredSharedLanePolishLayout(candidateEdges, closureCandidate, nodes);
|
||||
candidateEdges = ChoosePreferredSharedLanePolishLayout(candidateEdges, aggressiveCandidate, nodes);
|
||||
candidateEdges = ChoosePreferredSharedLanePolishLayout(current.Edges, candidateEdges, nodes);
|
||||
|
||||
var candidateScore = ElkEdgeRoutingScoring.ComputeScore(candidateEdges, nodes);
|
||||
var candidateRetryState = BuildRetryState(
|
||||
candidateScore,
|
||||
HighwayProcessingEnabled
|
||||
? ElkEdgeRouterHighway.DetectRemainingBrokenHighways(candidateEdges, nodes).Count
|
||||
: 0);
|
||||
|
||||
var improvedSharedLanes = candidateRetryState.SharedLaneViolations < current.RetryState.SharedLaneViolations;
|
||||
if (HasBlockingSharedLanePromotionRegression(candidateRetryState, current.RetryState)
|
||||
|| (!improvedSharedLanes
|
||||
&& !IsBetterCandidate(candidateScore, candidateRetryState, current.Score, current.RetryState)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
current = current with
|
||||
{
|
||||
Score = candidateScore,
|
||||
RetryState = candidateRetryState,
|
||||
Edges = candidateEdges,
|
||||
};
|
||||
improved = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!improved)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user