Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2015-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.graph;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Set;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.HashSet;
import java.util.stream.Collectors;
/**
* Suurballe shortest-path graph search algorithm capable of finding both
* a shortest path, as well as a backup shortest path, between a source and a destination
* such that the sum of the path lengths is minimized.
*/
public class SuurballeGraphSearch> extends DijkstraGraphSearch {
@Override
protected Result internalSearch(Graph graph, V src, V dst,
EdgeWeigher weigher, int maxPaths) {
// FIXME: This method needs to be refactored as it is difficult to follow and debug.
// FIXME: There is a defect here triggered by 3+ edges between the same vertices,
// which makes an attempt to produce looping paths. Protection against
// this was added to AbstractGraphPathSearch, but the root issue remains here.
// FIXME: There is a defect here where not all paths are truly disjoint.
// This class needs to filter its own results to make sure that the
// paths are indeed disjoint. Temporary fix for this is provided, but
// the issue needs to be addressed through refactoring.
EdgeWeigher weightf = weigher;
DefaultResult firstDijkstraS = (DefaultResult) super.internalSearch(
graph, src, dst, weigher, ALL_PATHS);
DefaultResult firstDijkstra = (DefaultResult) super.internalSearch(
graph, src, null, weigher, ALL_PATHS);
//choose an arbitrary shortest path to run Suurballe on
Path shortPath = null;
if (firstDijkstraS.paths().isEmpty()) {
return firstDijkstraS;
}
DisjointPathResult result = new DisjointPathResult(firstDijkstra, src, dst, maxPaths);
for (Path p: firstDijkstraS.paths()) {
shortPath = p;
//transforms the graph so tree edges have 0 weight
EdgeWeigher modified = new EdgeWeigher() {
@Override
public Weight weight(E edge) {
return edge instanceof ReverseEdge ?
weightf.getInitialWeight() :
(weightf.weight(edge).isNegative() ?
new ScalarWeight(-1.0) :
weightf.weight(edge).merge(firstDijkstra.cost(edge.src()))
.subtract(firstDijkstra.cost(edge.dst())));
}
@Override
public Weight getInitialWeight() {
return weightf.getInitialWeight();
}
@Override
public Weight getNonViableWeight() {
return weightf.getNonViableWeight();
}
};
EdgeWeigher modified2 = new EdgeWeigher() {
@Override
public Weight weight(E edge) {
return weightf.weight(edge).merge(firstDijkstra.cost(edge.src()))
.subtract(firstDijkstra.cost(edge.dst()));
}
@Override
public Weight getInitialWeight() {
return weightf.getInitialWeight();
}
@Override
public Weight getNonViableWeight() {
return weightf.getNonViableWeight();
}
};
//create a residual graph g' by removing all src vertices and reversing 0 length path edges
MutableGraph gt = mutableCopy(graph);
Map revToEdge = new HashMap<>();
graph.getEdgesTo(src).forEach(gt::removeEdge);
for (E edge: shortPath.edges()) {
gt.removeEdge(edge);
Edge reverse = new ReverseEdge(edge);
revToEdge.put((E) reverse, edge);
gt.addEdge((E) reverse);
}
//rerun dijkstra on the temporary graph to get a second path
Result secondDijkstra = new DijkstraGraphSearch()
.search(gt, src, dst, modified, ALL_PATHS);
Path residualShortPath = null;
if (secondDijkstra.paths().isEmpty()) {
result.dpps.add(new DisjointPathPair<>(shortPath, null));
continue;
}
for (Path p2: secondDijkstra.paths()) {
residualShortPath = p2;
MutableGraph roundTrip = mutableCopy(graph);
List tmp = roundTrip.getEdges().stream().collect(Collectors.toList());
tmp.forEach(roundTrip::removeEdge);
shortPath.edges().forEach(roundTrip::addEdge);
if (residualShortPath != null) {
for (Edge edge: residualShortPath.edges()) {
if (edge instanceof ReverseEdge) {
roundTrip.removeEdge(revToEdge.get(edge));
} else {
roundTrip.addEdge((E) edge);
}
}
}
//Actually build the final result
DefaultResult lastSearch = (DefaultResult)
super.internalSearch(roundTrip, src, dst, weigher, ALL_PATHS);
Path primary = lastSearch.paths().iterator().next();
primary.edges().forEach(roundTrip::removeEdge);
Set> backups = super.internalSearch(roundTrip, src, dst,
weigher, ALL_PATHS).paths();
// Find first backup path that does not share any nodes with the primary
for (Path backup : backups) {
if (isDisjoint(primary, backup)) {
result.dpps.add(new DisjointPathPair<>(primary, backup));
break;
}
}
}
}
for (int i = result.dpps.size() - 1; i > 0; i--) {
if (result.dpps.get(i).size() <= 1) {
result.dpps.remove(i);
}
}
result.buildPaths();
return result;
}
private boolean isDisjoint(Path a, Path b) {
return Sets.intersection(vertices(a), vertices(b)).isEmpty();
}
private Set vertices(Path p) {
Set set = new HashSet<>();
p.edges().forEach(e -> set.add(e.src()));
set.remove(p.src());
return set;
}
/**
* Creates a mutable copy of an immutable graph.
*
* @param graph immutable graph
* @return mutable copy
*/
private MutableGraph mutableCopy(Graph graph) {
return new MutableAdjacencyListsGraph<>(graph.getVertexes(), graph.getEdges());
}
private static final class ReverseEdge extends AbstractEdge {
private ReverseEdge(Edge edge) {
super(edge.dst(), edge.src());
}
@Override
public String toString() {
return "ReversedEdge " + "src=" + src() + " dst=" + dst();
}
}
// Auxiliary result for disjoint path search
private final class DisjointPathResult implements AbstractGraphPathSearch.Result {
private final Result searchResult;
private final V src, dst;
private final int maxPaths;
private final List> dpps = new ArrayList<>();
private final Set> disjointPaths = new HashSet<>();
private DisjointPathResult(Result searchResult, V src, V dst, int maxPaths) {
this.searchResult = searchResult;
this.src = src;
this.dst = dst;
this.maxPaths = maxPaths;
}
@Override
public V src() {
return src;
}
@Override
public V dst() {
return dst;
}
@Override
public Set> paths() {
return disjointPaths;
}
private void buildPaths() {
int paths = 0;
for (DisjointPathPair path: dpps) {
disjointPaths.add(path);
paths++;
if (paths == maxPaths) {
break;
}
}
}
@Override
public Map> parents() {
return searchResult.parents();
}
@Override
public Map costs() {
return searchResult.costs();
}
}
}