| | |
| | | private StationTaskTraceRegistry stationTaskTraceRegistry; |
| | | |
| | | public synchronized List<NavigateNode> calcByStationId(Integer startStationId, Integer endStationId) { |
| | | return calcByStationId(startStationId, endStationId, null, false); |
| | | return calcByStationId(startStationId, endStationId, null, null, false); |
| | | } |
| | | |
| | | public synchronized List<NavigateNode> calcByStationId(Integer startStationId, |
| | | Integer endStationId, |
| | | Double pathLenFactor) { |
| | | return calcByStationId(startStationId, endStationId, null, pathLenFactor, false); |
| | | } |
| | | |
| | | public synchronized List<NavigateNode> calcByStationId(Integer startStationId, Integer endStationId, Integer currentTaskNo) { |
| | | return calcByStationId(startStationId, endStationId, currentTaskNo, false); |
| | | return calcByStationId(startStationId, endStationId, currentTaskNo, null, false); |
| | | } |
| | | |
| | | public synchronized List<NavigateNode> calcByStationId(Integer startStationId, |
| | | Integer endStationId, |
| | | Integer currentTaskNo, |
| | | Double pathLenFactor) { |
| | | return calcByStationId(startStationId, endStationId, currentTaskNo, pathLenFactor, false); |
| | | } |
| | | |
| | | public synchronized List<NavigateNode> calcReachablePathByStationId(Integer startStationId, Integer endStationId) { |
| | | return calcByStationId(startStationId, endStationId, null, true); |
| | | return calcByStationId(startStationId, endStationId, null, null, true); |
| | | } |
| | | |
| | | public synchronized List<List<NavigateNode>> calcCandidatePathByStationId(Integer startStationId, |
| | | Integer endStationId, |
| | | Integer currentTaskNo) { |
| | | return calcCandidatePathByStationId(startStationId, endStationId, currentTaskNo, null); |
| | | } |
| | | |
| | | public synchronized List<List<NavigateNode>> calcCandidatePathByStationId(Integer startStationId, |
| | | Integer endStationId, |
| | | Integer currentTaskNo, |
| | | Double pathLenFactor) { |
| | | StationPathSearchContext context = buildStationPathSearchContext(startStationId, endStationId); |
| | | if (context.allList.isEmpty()) { |
| | | return new ArrayList<>(); |
| | |
| | | context.allList, |
| | | context.resolvedPolicy, |
| | | currentTaskNo, |
| | | pathLenFactor, |
| | | startStationId, |
| | | endStationId |
| | | ); |
| | |
| | | private synchronized List<NavigateNode> calcByStationId(Integer startStationId, |
| | | Integer endStationId, |
| | | Integer currentTaskNo, |
| | | Double pathLenFactor, |
| | | boolean reachabilityOnly) { |
| | | StationPathSearchContext context = buildStationPathSearchContext(startStationId, endStationId); |
| | | if (context.allList.isEmpty()) { |
| | |
| | | } |
| | | List<NavigateNode> list = reachabilityOnly |
| | | ? findStationReachablePath(context.allList, context.resolvedPolicy, startStationId, endStationId) |
| | | : findStationBestPathTwoStage(context.allList, context.resolvedPolicy, currentTaskNo, startStationId, endStationId); |
| | | : findStationBestPathTwoStage(context.allList, context.resolvedPolicy, currentTaskNo, pathLenFactor, startStationId, endStationId); |
| | | return normalizeStationPath(list); |
| | | } |
| | | |
| | |
| | | private List<NavigateNode> findStationBestPathTwoStage(List<List<NavigateNode>> allList, |
| | | StationPathResolvedPolicy resolvedPolicy, |
| | | Integer currentTaskNo, |
| | | Double pathLenFactor, |
| | | Integer startStationId, |
| | | Integer endStationId) { |
| | | List<List<NavigateNode>> orderedPathList = orderStationPathCandidates(allList, resolvedPolicy, currentTaskNo, startStationId, endStationId); |
| | | List<List<NavigateNode>> orderedPathList = orderStationPathCandidates(allList, resolvedPolicy, currentTaskNo, pathLenFactor, startStationId, endStationId); |
| | | if (orderedPathList.isEmpty()) { |
| | | return new ArrayList<>(); |
| | | } |
| | |
| | | private List<List<NavigateNode>> orderStationPathCandidates(List<List<NavigateNode>> allList, |
| | | StationPathResolvedPolicy resolvedPolicy, |
| | | Integer currentTaskNo, |
| | | Double pathLenFactor, |
| | | Integer startStationId, |
| | | Integer endStationId) { |
| | | if (allList == null || allList.isEmpty()) { |
| | |
| | | return new ArrayList<>(); |
| | | } |
| | | |
| | | metricsList.sort((a, b) -> compareDouble(a.staticCost, b.staticCost, a.turnCount, b.turnCount, a.pathLen, b.pathLen)); |
| | | applyPathLengthPreference(metricsList, profileConfig, globalPolicy, pathLenFactor); |
| | | metricsList.sort((a, b) -> compareStaticCandidateMetrics(a, b, pathLenFactor)); |
| | | PathCandidateMetrics preferred = metricsList.get(0); |
| | | int maxLen = (int) Math.ceil(preferred.pathLen * safeDouble(profileConfig.getS1MaxLenRatio(), 1.15d)); |
| | | int maxTurns = preferred.turnCount + safeInt(profileConfig.getS1MaxTurnDiff(), 1); |
| | |
| | | primaryMetrics = new ArrayList<>(primaryMetrics.subList(0, topK)); |
| | | } |
| | | |
| | | primaryMetrics.sort((a, b) -> compareDouble(a.dynamicCost, b.dynamicCost, a.pathLen, b.pathLen, a.turnCount, b.turnCount)); |
| | | secondaryMetrics.sort((a, b) -> compareDouble(a.dynamicCost, b.dynamicCost, a.pathLen, b.pathLen, a.turnCount, b.turnCount)); |
| | | primaryMetrics.sort((a, b) -> compareDynamicCandidateMetrics(a, b, pathLenFactor)); |
| | | secondaryMetrics.sort((a, b) -> compareDynamicCandidateMetrics(a, b, pathLenFactor)); |
| | | |
| | | List<PathCandidateMetrics> remainingMetrics = new ArrayList<>(); |
| | | for (PathCandidateMetrics metrics : metricsList) { |
| | |
| | | remainingMetrics.add(metrics); |
| | | } |
| | | } |
| | | remainingMetrics.sort((a, b) -> compareDouble(a.dynamicCost, b.dynamicCost, a.pathLen, b.pathLen, a.turnCount, b.turnCount)); |
| | | remainingMetrics.sort((a, b) -> compareDynamicCandidateMetrics(a, b, pathLenFactor)); |
| | | |
| | | List<List<NavigateNode>> orderedPathList = new ArrayList<>(); |
| | | appendCandidatePathList(orderedPathList, primaryMetrics); |
| | |
| | | double congWeightFactor = globalPolicy == null ? 1.0d : globalPolicy.congWeightFactor; |
| | | double passOtherOutStationPenaltyWeight = globalPolicy == null ? 0.0d : globalPolicy.passOtherOutStationPenaltyWeight; |
| | | |
| | | metrics.staticCost = |
| | | safeDouble(profileConfig.getS1LenWeight(), 1.0d) * lenWeightFactor * metrics.pathLen |
| | | + safeDouble(profileConfig.getS1TurnWeight(), 3.0d) * metrics.turnCount |
| | | metrics.baseLengthWeight = safeDouble(profileConfig.getS1LenWeight(), 1.0d) * lenWeightFactor; |
| | | metrics.otherStaticCost = |
| | | safeDouble(profileConfig.getS1TurnWeight(), 3.0d) * metrics.turnCount |
| | | + safeDouble(profileConfig.getS1LiftWeight(), 8.0d) * metrics.liftTransferCount |
| | | + passOtherOutStationPenaltyWeight * metrics.passOtherOutStationCount |
| | | + softDeviationWeight * metrics.softDeviationCount; |
| | |
| | | int leftLiftCount = countLiftTransferCount(left); |
| | | int rightLiftCount = countLiftTransferCount(right); |
| | | return compareDouble(leftLen, rightLen, leftTurnCount, rightTurnCount, leftLiftCount, rightLiftCount); |
| | | } |
| | | |
| | | private void applyPathLengthPreference(List<PathCandidateMetrics> metricsList, |
| | | StationPathProfileConfig profileConfig, |
| | | PathGlobalPolicy globalPolicy, |
| | | Double pathLenFactor) { |
| | | if (metricsList == null || metricsList.isEmpty()) { |
| | | return; |
| | | } |
| | | double normalizedFactor = normalizePathLenFactor(pathLenFactor); |
| | | int minPathLen = Integer.MAX_VALUE; |
| | | int maxPathLen = Integer.MIN_VALUE; |
| | | for (PathCandidateMetrics metrics : metricsList) { |
| | | if (metrics == null) { |
| | | continue; |
| | | } |
| | | minPathLen = Math.min(minPathLen, metrics.pathLen); |
| | | maxPathLen = Math.max(maxPathLen, metrics.pathLen); |
| | | } |
| | | if (minPathLen == Integer.MAX_VALUE || maxPathLen == Integer.MIN_VALUE) { |
| | | return; |
| | | } |
| | | double targetPathLen = normalizedFactor <= 0.0d || maxPathLen <= minPathLen |
| | | ? minPathLen |
| | | : minPathLen + normalizedFactor * (maxPathLen - minPathLen); |
| | | for (PathCandidateMetrics metrics : metricsList) { |
| | | if (metrics == null) { |
| | | continue; |
| | | } |
| | | metrics.pathLenPreferenceDistance = normalizedFactor <= 0.0d |
| | | ? metrics.pathLen |
| | | : Math.abs(metrics.pathLen - targetPathLen); |
| | | metrics.staticCost = metrics.baseLengthWeight * metrics.pathLenPreferenceDistance + metrics.otherStaticCost; |
| | | } |
| | | } |
| | | |
| | | private int compareStaticCandidateMetrics(PathCandidateMetrics left, |
| | | PathCandidateMetrics right, |
| | | Double pathLenFactor) { |
| | | if (left == right) { |
| | | return 0; |
| | | } |
| | | if (left == null) { |
| | | return 1; |
| | | } |
| | | if (right == null) { |
| | | return -1; |
| | | } |
| | | int result = Double.compare(left.staticCost, right.staticCost); |
| | | if (result != 0) { |
| | | return result; |
| | | } |
| | | result = Double.compare(left.pathLenPreferenceDistance, right.pathLenPreferenceDistance); |
| | | if (result != 0) { |
| | | return result; |
| | | } |
| | | result = Integer.compare(left.turnCount, right.turnCount); |
| | | if (result != 0) { |
| | | return result; |
| | | } |
| | | return comparePathLenTie(left.pathLen, right.pathLen, pathLenFactor); |
| | | } |
| | | |
| | | private int compareDynamicCandidateMetrics(PathCandidateMetrics left, |
| | | PathCandidateMetrics right, |
| | | Double pathLenFactor) { |
| | | if (left == right) { |
| | | return 0; |
| | | } |
| | | if (left == null) { |
| | | return 1; |
| | | } |
| | | if (right == null) { |
| | | return -1; |
| | | } |
| | | int result = Double.compare(left.dynamicCost, right.dynamicCost); |
| | | if (result != 0) { |
| | | return result; |
| | | } |
| | | result = Double.compare(left.pathLenPreferenceDistance, right.pathLenPreferenceDistance); |
| | | if (result != 0) { |
| | | return result; |
| | | } |
| | | result = comparePathLenTie(left.pathLen, right.pathLen, pathLenFactor); |
| | | if (result != 0) { |
| | | return result; |
| | | } |
| | | return Integer.compare(left.turnCount, right.turnCount); |
| | | } |
| | | |
| | | private int comparePathLenTie(int leftPathLen, int rightPathLen, Double pathLenFactor) { |
| | | double normalizedFactor = normalizePathLenFactor(pathLenFactor); |
| | | if (normalizedFactor <= 0.0d) { |
| | | return Integer.compare(leftPathLen, rightPathLen); |
| | | } |
| | | if (normalizedFactor >= 0.5d) { |
| | | return Integer.compare(rightPathLen, leftPathLen); |
| | | } |
| | | return Integer.compare(leftPathLen, rightPathLen); |
| | | } |
| | | |
| | | private int countLiftTransferCount(List<NavigateNode> path) { |
| | |
| | | return value == null ? defaultValue : value; |
| | | } |
| | | |
| | | private double normalizePathLenFactor(Double pathLenFactor) { |
| | | if (pathLenFactor == null) { |
| | | return 0.0d; |
| | | } |
| | | if (pathLenFactor < 0.0d) { |
| | | return 0.0d; |
| | | } |
| | | if (pathLenFactor > 1.0d) { |
| | | return 1.0d; |
| | | } |
| | | return pathLenFactor; |
| | | } |
| | | |
| | | private boolean notBlank(String text) { |
| | | return text != null && !text.trim().isEmpty(); |
| | | } |
| | |
| | | private int runBlockCount; |
| | | private int softDeviationCount; |
| | | private double loopPenalty; |
| | | private double baseLengthWeight; |
| | | private double otherStaticCost; |
| | | private double pathLenPreferenceDistance; |
| | | private double staticCost; |
| | | private double dynamicCost; |
| | | } |