All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.onlab.graph.SuurballeGraphSearch Maven / Gradle / Ivy

There is a newer version: 2.7.0
Show newest version
/*
 * 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> extends DijkstraGraphSearch {

    @Override
    public Result search(Graph graph, V src, V dst,
                               EdgeWeight weight, int maxPaths) {

        if (weight == null) {
            weight = edge -> 1;
        }

        List> 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 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> modified = edge -> {
                if (classE().isInstance(edge)) {
                    return weightf.weight((E) (edge)) + firstDijkstra.cost(edge.src())
                            - firstDijkstra.cost(edge.dst());
                }
                return 0;
            };
            EdgeWeight 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> gt = mutableCopy(graph);

            Map, E> revToEdge = new HashMap<>();
            graph.getEdgesTo(src).forEach(gt::removeEdge);
            for (E edge: shortPath.edges()) {
                gt.removeEdge(edge);
                Edge reverse = new Edge() {
                    final Edge 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> secondDijkstra;
            secondDijkstra = new DijkstraGraphSearch>().search(gt, src, dst, modified, ALL_PATHS);

            Path> residualShortPath = null;
            if (secondDijkstra.paths().size() == 0) {
                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 (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 path1 = lastSearch.paths().iterator().next();
                path1.edges().forEach(roundTrip::removeEdge);

                Set> bckpaths = super.search(roundTrip, src, dst, weight, ALL_PATHS).paths();
                Path 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() {
            final DefaultResult search = firstDijkstra;

            public V src() {
                return src;
            }
            public V dst() {
                return dst;
            }
            public Set> paths() {
                Set> pathsD = new HashSet<>();
                int paths = 0;
                for (DisjointPathPair path: dpps) {
                    pathsD.add((Path) path);
                    paths++;
                    if (paths == maxPaths) {
                        break;
                    }
                }
                return pathsD;
            }
            public Map costs() {
                return search.costs();
            }
            public Map> 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 graph) {
        clazzV = graph.getVertexes().iterator().next().getClass();
        clazzE = graph.getEdges().iterator().next().getClass();
        return new MutableAdjacencyListsGraph(graph.getVertexes(), graph.getEdges());
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy