use of org.openkilda.pce.model.Edge in project open-kilda by telstra.
the class BestWeightAndShortestPathFinder method findNPathsBetweenSwitches.
/**
* Find N (or less) best paths. To find N paths Yen's algorithm is used.
*
* @return an list of N (or less) best paths.
*/
private List<List<Edge>> findNPathsBetweenSwitches(AvailableNetwork network, SwitchId startSwitchId, SwitchId endSwitchId, int count, WeightFunction weightFunction, Function<Node, FindOneDirectionPathResult> getPath) throws UnroutableFlowException {
Node start = network.getSwitch(startSwitchId);
Node end = network.getSwitch(endSwitchId);
if (start == null || end == null) {
throw new UnroutableFlowException(format("Switch %s doesn't have links with enough bandwidth", start == null ? startSwitchId : endSwitchId));
}
// Determine the shortest path from the start to the end.
List<List<Edge>> bestPaths = new ArrayList<>();
List<Edge> firstPath = getPath.apply(start).getFoundPath();
if (firstPath.isEmpty()) {
return new ArrayList<>();
}
bestPaths.add(getPath.apply(start).getFoundPath());
// Initialize the set to store the potential kth shortest path.
// Use LinkedHashSet to have deterministic results.
Set<List<Edge>> potentialKthShortestPaths = new LinkedHashSet<>();
for (int k = 1; k < count; k++) {
List<Edge> bestPath = bestPaths.get(k - 1);
for (int i = 0; i < bestPath.size(); i++) {
// Spur node is retrieved from the previous k-shortest path.
Node spurNode = bestPath.get(i).getSrcSwitch();
// The sequence of edges from the start to the spur node (without spur node).
List<Edge> rootPath = new ArrayList<>(bestPath.subList(0, i));
Set<Edge> removedEdges = new HashSet<>();
// Remove the links that are part of the previous shortest paths which share the same root path.
for (List<Edge> path : bestPaths) {
if (path.size() > i && rootPath.equals(path.subList(0, i)) && spurNode.equals(path.get(i).getSrcSwitch())) {
removedEdges.add(path.get(i));
removeEdge(path.get(i));
}
}
for (Edge edge : rootPath) {
edge.getSrcSwitch().remove();
}
// Calculate the spur path from the spur node to the end.
List<Edge> pathFromSpurNode = getPath.apply(spurNode).getFoundPath();
if (!pathFromSpurNode.isEmpty()) {
List<Edge> totalPath = new ArrayList<>(rootPath);
// Entire path is made up of the root path and spur path.
totalPath.addAll(pathFromSpurNode);
// Add the potential k-shortest path to the heap.
potentialKthShortestPaths.add(totalPath);
}
// Add back the edges and nodes that were removed from the graph.
for (Edge edge : removedEdges) {
restoreEdge(edge);
}
for (Edge edge : rootPath) {
edge.getSrcSwitch().restore();
}
}
if (potentialKthShortestPaths.isEmpty()) {
break;
}
// Add the lowest weight path becomes the k-shortest path.
List<Edge> newBestPath = getBestPotentialKthShortestPath(potentialKthShortestPaths, bestPaths, weightFunction);
bestPaths.add(newBestPath);
}
return bestPaths;
}
use of org.openkilda.pce.model.Edge in project open-kilda by telstra.
the class BestWeightAndShortestPathFinderTest method shouldReturnTheShortestPath.
@Test
public void shouldReturnTheShortestPath() throws UnroutableFlowException {
AvailableNetwork network = buildTestNetwork();
BestWeightAndShortestPathFinder pathFinder = new BestWeightAndShortestPathFinder(ALLOWED_DEPTH);
Pair<List<Edge>, List<Edge>> pairPath = pathFinder.findPathWithMinWeight(network, SWITCH_ID_E, SWITCH_ID_F, WEIGHT_FUNCTION).getFoundPath();
List<Edge> fpath = pairPath.getLeft();
assertThat(fpath, Matchers.hasSize(2));
assertEquals(SWITCH_ID_E, fpath.get(0).getSrcSwitch().getSwitchId());
assertEquals(SWITCH_ID_F, fpath.get(1).getDestSwitch().getSwitchId());
List<Edge> rpath = pairPath.getRight();
assertThat(rpath, Matchers.hasSize(2));
assertEquals(SWITCH_ID_F, rpath.get(0).getSrcSwitch().getSwitchId());
assertEquals(SWITCH_ID_E, rpath.get(1).getDestSwitch().getSwitchId());
}
use of org.openkilda.pce.model.Edge in project open-kilda by telstra.
the class BestWeightAndShortestPathFinderTest method shouldFindSymmetricPath.
@Test
public void shouldFindSymmetricPath() throws UnroutableFlowException {
AvailableNetwork network = buildLinearNetworkWithPairLinks();
BestWeightAndShortestPathFinder pathFinder = new BestWeightAndShortestPathFinder(2);
Pair<List<Edge>, List<Edge>> pathPair = pathFinder.findPathWithMinWeight(network, SWITCH_ID_1, SWITCH_ID_3, WEIGHT_FUNCTION).getFoundPath();
List<Edge> forward = pathPair.getLeft();
List<Edge> reverse = Lists.reverse(pathPair.getRight());
List<Boolean> validation = IntStream.range(0, forward.size()).mapToObj(i -> Objects.equals(forward.get(i).getSrcPort(), reverse.get(i).getDestPort())).collect(Collectors.toList());
assertFalse(validation.contains(false));
}
use of org.openkilda.pce.model.Edge in project open-kilda by telstra.
the class AvailableNetworkFactory method addIslAsEdge.
private void addIslAsEdge(IslImmutableView isl, AvailableNetwork network) {
Node srcSwitch = network.getOrAddNode(isl.getSrcSwitchId(), isl.getSrcPop());
Node dstSwitch = network.getOrAddNode(isl.getDestSwitchId(), isl.getDestPop());
Edge edge = Edge.builder().srcSwitch(srcSwitch).srcPort(isl.getSrcPort()).destSwitch(dstSwitch).destPort(isl.getDestPort()).cost(isl.getCost()).latency(isl.getLatency()).underMaintenance(isl.isUnderMaintenance()).unstable(isl.isUnstable()).availableBandwidth(isl.getAvailableBandwidth()).build();
network.addEdge(edge);
}
use of org.openkilda.pce.model.Edge in project open-kilda by telstra.
the class BestWeightAndShortestPathFinder method removeEdge.
private void removeEdge(Edge edge) {
edge.getSrcSwitch().getOutgoingLinks().remove(edge);
edge.getDestSwitch().getIncomingLinks().remove(edge);
Edge reverseEdge = edge.swap();
reverseEdge.getSrcSwitch().getOutgoingLinks().remove(reverseEdge);
reverseEdge.getDestSwitch().getIncomingLinks().remove(reverseEdge);
}
Aggregations