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

org.fabric3.util.graph.CycleDetectorImpl Maven / Gradle / Ivy

The newest version!
/*
 * Fabric3
 * Copyright (c) 2009-2015 Metaform Systems
 *
 * 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.
 * Portions originally based on Apache Tuscany 2007
 * licensed under the Apache 2.0 license.
 */
package org.fabric3.util.graph;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
 * Detects cycles in a directed graph.
 */
public class CycleDetectorImpl implements CycleDetector {
    private DepthFirstTraverser traverser;

    public CycleDetectorImpl() {
        traverser = new DepthFirstTraverserImpl<>();
    }

    public boolean hasCycles(DirectedGraph graph) {
        for (Vertex vertex : graph.getVertices()) {
            if (isCycle(graph, vertex)) {
                return true;
            }
        }
        return false;
    }

    public DirectedGraph findCycleSubgraph(DirectedGraph graph) {
        DirectedGraph subGraph = new DirectedGraphImpl<>();
        for (Edge edge : graph.getEdges()) {
            if (isPath(graph, edge.getSink(), edge.getSource())) {
                subGraph.add(edge);
            }
        }
        return subGraph;
    }

    public List> findCycles(DirectedGraph graph) {
        List> cycles = new ArrayList<>();
        for (Edge edge : graph.getEdges()) {
            List> path = getPath(graph, edge.getSink(), edge.getSource());
            if (!path.isEmpty()) {
                Cycle cycle = searchCycle(cycles, edge);
                if (cycle == null) {
                    cycle = new Cycle<>();
                    cycle.setOriginPath(path);
                    cycles.add(cycle);
                } else {
                    cycle.setBackPath(path);
                }
            }
        }
        return cycles;
    }

    private Cycle searchCycle(List> cycles, Edge edge) {
        for (Cycle cycle : cycles) {
            List> path = cycle.getOriginPath();
            Vertex vertex = path.get(0);
            if (vertex.equals(edge.getSink())) {
                return cycle;
            }
        }
        return null;
    }

    private boolean isCycle(DirectedGraph graph, Vertex from) {
        Set> edges = graph.getOutgoingEdges(from);
        for (Edge edge : edges) {
            Vertex opposite = edge.getOppositeVertex(from);
            if (isPath(graph, opposite, from)) {
                // cycle found
                return true;
            }
        }
        return false;
    }


    /**
     * Returns true if a path exists between two vertices.
     *
     * @param graph the graph to search
     * @param start the starting vertex
     * @param end   the ending vertex
     * @return true if a path exists between two vertices
     */
    private boolean isPath(DirectedGraph graph, Vertex start, Vertex end) {
        return !getPath(graph, start, end).isEmpty();
    }

    /**
     * Returns the ordered list of vertices traversed for a path defined by the given start and end vertices. If no path exists, an empty colleciton
     * is returned.
     *
     * @param graph the graph to search
     * @param start the starting vertex
     * @param end   the ending vertex
     * @return the ordered collection of vertices or an empty collection if no path exists
     */
    private List> getPath(DirectedGraph graph, Vertex start, Vertex end) {
        List> path = traverser.traversePath(graph, start, end);
        // reverse the order to it goes from source to end destination
        Collections.reverse(path);
        return path;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy