using System.Collections.Concurrent; using System.Diagnostics; using System.Globalization; namespace StellaOps.ElkSharp; internal static partial class ElkEdgeRouterIterative { private static bool IsBetterCandidate( EdgeRoutingScore candidate, RoutingRetryState candidateRetryState, EdgeRoutingScore best, RoutingRetryState bestRetryState) { if (HasHardRuleRegression(candidateRetryState, bestRetryState)) { return false; } var retryComparison = CompareRetryStates(candidateRetryState, bestRetryState); if (retryComparison != 0) { return retryComparison < 0; } if (candidate.NodeCrossings != best.NodeCrossings) { return candidate.NodeCrossings < best.NodeCrossings; } return candidate.Value > best.Value; } private static bool HasHardRuleRegression(RoutingRetryState candidate, RoutingRetryState baseline) { return candidate.RemainingShortHighways > baseline.RemainingShortHighways || candidate.RepeatCollectorCorridorViolations > baseline.RepeatCollectorCorridorViolations || candidate.RepeatCollectorNodeClearanceViolations > baseline.RepeatCollectorNodeClearanceViolations || candidate.BelowGraphViolations > baseline.BelowGraphViolations || candidate.UnderNodeViolations > baseline.UnderNodeViolations || candidate.LongDiagonalViolations > baseline.LongDiagonalViolations || candidate.EntryAngleViolations > baseline.EntryAngleViolations || candidate.GatewaySourceExitViolations > baseline.GatewaySourceExitViolations || candidate.SharedLaneViolations > baseline.SharedLaneViolations || candidate.BoundarySlotViolations > baseline.BoundarySlotViolations || candidate.TargetApproachJoinViolations > baseline.TargetApproachJoinViolations || candidate.TargetApproachBacktrackingViolations > baseline.TargetApproachBacktrackingViolations || candidate.ExcessiveDetourViolations > baseline.ExcessiveDetourViolations; } private static bool HasBlockingSharedLanePromotionRegression( RoutingRetryState candidate, RoutingRetryState baseline) { var allowsTemporaryBoundarySlotTrade = candidate.SharedLaneViolations < baseline.SharedLaneViolations && baseline.BoundarySlotViolations > 0 && candidate.BoundarySlotViolations <= baseline.BoundarySlotViolations + 1; return candidate.RemainingShortHighways > baseline.RemainingShortHighways || candidate.RepeatCollectorCorridorViolations > baseline.RepeatCollectorCorridorViolations || candidate.RepeatCollectorNodeClearanceViolations > baseline.RepeatCollectorNodeClearanceViolations || candidate.BelowGraphViolations > baseline.BelowGraphViolations || candidate.UnderNodeViolations > baseline.UnderNodeViolations || candidate.LongDiagonalViolations > baseline.LongDiagonalViolations || candidate.EntryAngleViolations > baseline.EntryAngleViolations || candidate.GatewaySourceExitViolations > baseline.GatewaySourceExitViolations || candidate.SharedLaneViolations > baseline.SharedLaneViolations || (!allowsTemporaryBoundarySlotTrade && candidate.BoundarySlotViolations > baseline.BoundarySlotViolations) || candidate.TargetApproachJoinViolations > baseline.TargetApproachJoinViolations || candidate.TargetApproachBacktrackingViolations > baseline.TargetApproachBacktrackingViolations || candidate.ExcessiveDetourViolations > baseline.ExcessiveDetourViolations; } private static bool HasBlockingSetterFamilyPromotionRegression( RoutingRetryState candidate, RoutingRetryState baseline, bool localImproved) { var allowTemporaryDetourTrade = localImproved && candidate.RemainingShortHighways <= baseline.RemainingShortHighways && candidate.UnderNodeViolations <= baseline.UnderNodeViolations && candidate.ExcessiveDetourViolations <= baseline.ExcessiveDetourViolations + 1; var allowTemporaryBoundarySlotTrade = localImproved && candidate.BoundarySlotViolations <= baseline.BoundarySlotViolations + 1; return candidate.RemainingShortHighways > baseline.RemainingShortHighways || candidate.RepeatCollectorCorridorViolations > baseline.RepeatCollectorCorridorViolations || candidate.RepeatCollectorNodeClearanceViolations > baseline.RepeatCollectorNodeClearanceViolations || candidate.BelowGraphViolations > baseline.BelowGraphViolations || candidate.UnderNodeViolations > baseline.UnderNodeViolations || candidate.LongDiagonalViolations > baseline.LongDiagonalViolations || candidate.EntryAngleViolations > baseline.EntryAngleViolations || candidate.GatewaySourceExitViolations > baseline.GatewaySourceExitViolations || candidate.SharedLaneViolations > baseline.SharedLaneViolations || (!allowTemporaryBoundarySlotTrade && candidate.BoundarySlotViolations > baseline.BoundarySlotViolations) || candidate.TargetApproachJoinViolations > baseline.TargetApproachJoinViolations || candidate.TargetApproachBacktrackingViolations > baseline.TargetApproachBacktrackingViolations || (!allowTemporaryDetourTrade && candidate.ExcessiveDetourViolations > baseline.ExcessiveDetourViolations); } private static int CompareRetryStates(RoutingRetryState left, RoutingRetryState right) { if (left.RemainingShortHighways != right.RemainingShortHighways) { return left.RemainingShortHighways.CompareTo(right.RemainingShortHighways); } if (left.RepeatCollectorCorridorViolations != right.RepeatCollectorCorridorViolations) { return left.RepeatCollectorCorridorViolations.CompareTo(right.RepeatCollectorCorridorViolations); } if (left.RepeatCollectorNodeClearanceViolations != right.RepeatCollectorNodeClearanceViolations) { return left.RepeatCollectorNodeClearanceViolations.CompareTo(right.RepeatCollectorNodeClearanceViolations); } if (left.BelowGraphViolations != right.BelowGraphViolations) { return left.BelowGraphViolations.CompareTo(right.BelowGraphViolations); } if (left.UnderNodeViolations != right.UnderNodeViolations) { return left.UnderNodeViolations.CompareTo(right.UnderNodeViolations); } if (left.LongDiagonalViolations != right.LongDiagonalViolations) { return left.LongDiagonalViolations.CompareTo(right.LongDiagonalViolations); } if (left.EntryAngleViolations != right.EntryAngleViolations) { return left.EntryAngleViolations.CompareTo(right.EntryAngleViolations); } if (left.GatewaySourceExitViolations != right.GatewaySourceExitViolations) { return left.GatewaySourceExitViolations.CompareTo(right.GatewaySourceExitViolations); } if (left.SharedLaneViolations != right.SharedLaneViolations) { return left.SharedLaneViolations.CompareTo(right.SharedLaneViolations); } if (left.BoundarySlotViolations != right.BoundarySlotViolations) { return left.BoundarySlotViolations.CompareTo(right.BoundarySlotViolations); } if (left.TargetApproachJoinViolations != right.TargetApproachJoinViolations) { return left.TargetApproachJoinViolations.CompareTo(right.TargetApproachJoinViolations); } if (left.TargetApproachBacktrackingViolations != right.TargetApproachBacktrackingViolations) { return left.TargetApproachBacktrackingViolations.CompareTo(right.TargetApproachBacktrackingViolations); } if (left.ExcessiveDetourViolations != right.ExcessiveDetourViolations) { return left.ExcessiveDetourViolations.CompareTo(right.ExcessiveDetourViolations); } if (left.ProximityViolations != right.ProximityViolations) { return left.ProximityViolations.CompareTo(right.ProximityViolations); } if (left.LabelProximityViolations != right.LabelProximityViolations) { return left.LabelProximityViolations.CompareTo(right.LabelProximityViolations); } return left.EdgeCrossings.CompareTo(right.EdgeCrossings); } private static CandidateSolution SelectBestValidSolution( IReadOnlyList solutions) { var best = solutions[0]; for (var i = 1; i < solutions.Count; i++) { var candidate = solutions[i]; if (IsBetterBoundarySlotRepairCandidate( candidate.Score, candidate.RetryState, best.Score, best.RetryState) || candidate.Score.Value > best.Score.Value || (Math.Abs(candidate.Score.Value - best.Score.Value) < 0.001d && CompareRetryStates(candidate.RetryState, best.RetryState) < 0) || (Math.Abs(candidate.Score.Value - best.Score.Value) < 0.001d && CompareRetryStates(candidate.RetryState, best.RetryState) == 0 && candidate.Score.EdgeCrossings < best.Score.EdgeCrossings)) { best = candidate; } } return best; } private static CandidateSolution SelectBestFallbackSolution( IReadOnlyList solutions) { var best = solutions[0]; for (var i = 1; i < solutions.Count; i++) { var candidate = solutions[i]; if (IsBetterBoundarySlotRepairCandidate( candidate.Score, candidate.RetryState, best.Score, best.RetryState) || candidate.Score.NodeCrossings < best.Score.NodeCrossings || (candidate.Score.NodeCrossings == best.Score.NodeCrossings && CompareRetryStates(candidate.RetryState, best.RetryState) < 0) || (candidate.Score.NodeCrossings == best.Score.NodeCrossings && CompareRetryStates(candidate.RetryState, best.RetryState) == 0 && candidate.Score.EdgeCrossings < best.Score.EdgeCrossings) || (candidate.Score.NodeCrossings == best.Score.NodeCrossings && CompareRetryStates(candidate.RetryState, best.RetryState) == 0 && candidate.Score.EdgeCrossings == best.Score.EdgeCrossings && candidate.Score.Value > best.Score.Value)) { best = candidate; } } return best; } }