summaryrefslogtreecommitdiffstats
path: root/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/SuurballeGraphSearch.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/utils/misc/src/main/java/org/onlab/graph/SuurballeGraphSearch.java')
-rw-r--r--framework/src/onos/utils/misc/src/main/java/org/onlab/graph/SuurballeGraphSearch.java193
1 files changed, 193 insertions, 0 deletions
diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/SuurballeGraphSearch.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/SuurballeGraphSearch.java
new file mode 100644
index 00000000..76591c82
--- /dev/null
+++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/SuurballeGraphSearch.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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 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<V extends Vertex, E extends Edge<V>> extends DijkstraGraphSearch<V, E> {
+
+ @Override
+ public Result<V, E> search(Graph<V, E> graph, V src, V dst,
+ EdgeWeight<V, E> weight, int maxPaths) {
+
+ if (weight == null) {
+ weight = edge -> 1;
+ }
+
+ List<DisjointPathPair<V, E>> dpps = new ArrayList<>();
+
+ final EdgeWeight weightf = weight;
+ DefaultResult firstDijkstraS = (DefaultResult) super.search(graph, src, dst, weight, ALL_PATHS);
+ DefaultResult firstDijkstra = (DefaultResult) super.search(graph, src, null, weight, ALL_PATHS);
+
+ //choose an arbitrary shortest path to run Suurballe on
+ Path<V, E> shortPath = null;
+ if (firstDijkstraS.paths().size() == 0) {
+ return firstDijkstraS;
+ }
+ for (Path p: firstDijkstraS.paths()) {
+ shortPath = p;
+ //transforms the graph so tree edges have 0 weight
+ EdgeWeight<V, Edge<V>> modified = edge -> {
+ if (classE().isInstance(edge)) {
+ return weightf.weight((E) (edge)) + firstDijkstra.cost(edge.src())
+ - firstDijkstra.cost(edge.dst());
+ }
+ return 0;
+ };
+ EdgeWeight<V, E> modified2 = edge ->
+ weightf.weight(edge) + firstDijkstra.cost(edge.src()) - firstDijkstra.cost(edge.dst());
+
+ //create a residual graph g' by removing all src vertices and reversing 0 length path edges
+ MutableGraph<V, Edge<V>> gt = mutableCopy(graph);
+
+ Map<Edge<V>, E> revToEdge = new HashMap<>();
+ graph.getEdgesTo(src).forEach(gt::removeEdge);
+ for (E edge: shortPath.edges()) {
+ gt.removeEdge(edge);
+ Edge<V> reverse = new Edge<V>() {
+ final Edge<V> orig = edge;
+ public V src() {
+ return orig.dst();
+ }
+ public V dst() {
+ return orig.src();
+ }
+ public String toString() {
+ return "ReversedEdge " + "src=" + src() + " dst=" + dst();
+ }
+ };
+ revToEdge.put(reverse, edge);
+ gt.addEdge(reverse);
+ }
+
+ //rerun dijkstra on the temporary graph to get a second path
+ Result<V, Edge<V>> secondDijkstra;
+ secondDijkstra = new DijkstraGraphSearch<V, Edge<V>>().search(gt, src, dst, modified, ALL_PATHS);
+
+ Path<V, Edge<V>> residualShortPath = null;
+ if (secondDijkstra.paths().size() == 0) {
+ dpps.add(new DisjointPathPair<V, E>(shortPath, null));
+ continue;
+ }
+
+ for (Path p2: secondDijkstra.paths()) {
+ residualShortPath = p2;
+
+ MutableGraph<V, E> roundTrip = mutableCopy(graph);
+
+ List<E> tmp = roundTrip.getEdges().stream().collect(Collectors.toList());
+
+ tmp.forEach(roundTrip::removeEdge);
+
+ shortPath.edges().forEach(roundTrip::addEdge);
+
+ if (residualShortPath != null) {
+ for (Edge<V> edge: residualShortPath.edges()) {
+ if (classE().isInstance(edge)) {
+ roundTrip.addEdge((E) edge);
+ } else {
+ roundTrip.removeEdge(revToEdge.get(edge));
+ }
+ }
+ }
+ //Actually build the final result
+ DefaultResult lastSearch = (DefaultResult) super.search(roundTrip, src, dst, weight, ALL_PATHS);
+ Path<V, E> path1 = lastSearch.paths().iterator().next();
+ path1.edges().forEach(roundTrip::removeEdge);
+
+ Set<Path<V, E>> bckpaths = super.search(roundTrip, src, dst, weight, ALL_PATHS).paths();
+ Path<V, E> backup = null;
+ if (bckpaths.size() != 0) {
+ backup = bckpaths.iterator().next();
+ }
+
+ dpps.add(new DisjointPathPair<>(path1, backup));
+ }
+ }
+
+ for (int i = dpps.size() - 1; i > 0; i--) {
+ if (dpps.get(i).size() <= 1) {
+ dpps.remove(i);
+ }
+ }
+
+ return new Result<V, E>() {
+ final DefaultResult search = firstDijkstra;
+
+ public V src() {
+ return src;
+ }
+ public V dst() {
+ return dst;
+ }
+ public Set<Path<V, E>> paths() {
+ Set<Path<V, E>> pathsD = new HashSet<>();
+ int paths = 0;
+ for (DisjointPathPair<V, E> path: dpps) {
+ pathsD.add((Path<V, E>) path);
+ paths++;
+ if (paths == maxPaths) {
+ break;
+ }
+ }
+ return pathsD;
+ }
+ public Map<V, Double> costs() {
+ return search.costs();
+ }
+ public Map<V, Set<E>> parents() {
+ return search.parents();
+ }
+ };
+ }
+
+ private Class<?> clazzV;
+
+ public Class<?> classV() {
+ return clazzV;
+ }
+
+ private Class<?> clazzE;
+
+ public Class<?> classE() {
+ return clazzE;
+ }
+ /**
+ * Creates a mutable copy of an immutable graph.
+ *
+ * @param graph immutable graph
+ * @return mutable copy
+ */
+ public MutableGraph mutableCopy(Graph<V, E> graph) {
+ clazzV = graph.getVertexes().iterator().next().getClass();
+ clazzE = graph.getEdges().iterator().next().getClass();
+ return new MutableAdjacencyListsGraph<V, E>(graph.getVertexes(), graph.getEdges());
+ }
+}
+