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

org.jgrapht.alg.connectivity.ConnectivityInspector Maven / Gradle / Ivy

The newest version!
/*
 * (C) Copyright 2003-2023, by Barak Naveh and Contributors.
 *
 * JGraphT : a free Java graph-theory library
 *
 * See the CONTRIBUTORS.md file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0, or the
 * GNU Lesser General Public License v2.1 or later
 * which is available at
 * http://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR LGPL-2.1-or-later
 */
package org.jgrapht.alg.connectivity;

import org.jgrapht.*;
import org.jgrapht.event.*;
import org.jgrapht.graph.*;
import org.jgrapht.traverse.*;
import org.jgrapht.util.*;

import java.util.*;

/**
 * Allows obtaining various connectivity aspects of a graph. The inspected graph is specified
 * at construction time and cannot be modified. Currently, the inspector supports connected
 * components for an undirected graph and weakly connected components for a directed graph. To find
 * strongly connected components, use {@link KosarajuStrongConnectivityInspector} instead.
 *
 * 

* The inspector methods work in a lazy fashion: no computation is performed unless immediately * necessary. Computation are done once and results and cached within this class for future need. *

* *

* The inspector is also a {@link org.jgrapht.event.GraphListener}. If added as a listener to the * inspected graph, the inspector will amend internal cached results instead of recomputing them. It * is efficient when a few modifications are applied to a large graph. If many modifications are * expected it will not be efficient due to added overhead on graph update operations. If inspector * is added as listener to a graph other than the one it inspects, results are undefined. *

* * @param the graph vertex type * @param the graph edge type * * @author Barak Naveh * @author John V. Sichi */ public class ConnectivityInspector implements GraphListener { private List> connectedSets; private Map> vertexToConnectedSet; private Graph graph; /** * Creates a connectivity inspector for the specified graph. * * @param g the graph for which a connectivity inspector to be created. */ public ConnectivityInspector(Graph g) { init(); this.graph = Objects.requireNonNull(g); if (g.getType().isDirected()) this.graph = new AsUndirectedGraph<>(g); } /** * Test if the inspected graph is connected. A graph is connected when there is a path between * every pair of vertices. In a connected graph, there are no unreachable vertices. When the * inspected graph is a directed graph, this method returns true if and only if the * inspected graph is weakly connected. An empty graph is not considered * connected. * * @return true if and only if inspected graph is connected. */ public boolean isConnected() { return lazyFindConnectedSets().size() == 1; } /** * Returns a set of all vertices that are in the maximally connected component together with the * specified vertex. For more on maximally connected component, see * * http://www.nist.gov/dads/HTML/maximallyConnectedComponent.html. * * @param vertex the vertex for which the connected set to be returned. * * @return a set of all vertices that are in the maximally connected component together with the * specified vertex. */ public Set connectedSetOf(V vertex) { Set connectedSet = vertexToConnectedSet.get(vertex); if (connectedSet == null) { connectedSet = new HashSet<>(); BreadthFirstIterator i = new BreadthFirstIterator<>(graph, vertex); while (i.hasNext()) { connectedSet.add(i.next()); } vertexToConnectedSet.put(vertex, connectedSet); } return connectedSet; } /** * Returns a list of Set s, where each set contains all vertices that are in the * same maximally connected component. All graph vertices occur in exactly one set. For more on * maximally connected component, see * * http://www.nist.gov/dads/HTML/maximallyConnectedComponent.html. * * @return Returns a list of Set s, where each set contains all vertices that are * in the same maximally connected component. */ public List> connectedSets() { return lazyFindConnectedSets(); } /** * @see GraphListener#edgeAdded(GraphEdgeChangeEvent) */ @Override public void edgeAdded(GraphEdgeChangeEvent e) { V source = e.getEdgeSource(); V target = e.getEdgeTarget(); Set sourceSet = connectedSetOf(source); Set targetSet = connectedSetOf(target); // If source and target are in the same set, do nothing, otherwise, merge sets if (sourceSet != targetSet) { Set merge = CollectionUtil.newHashSetWithExpectedSize(sourceSet.size() + targetSet.size()); merge.addAll(sourceSet); merge.addAll(targetSet); connectedSets.remove(sourceSet); connectedSets.remove(targetSet); connectedSets.add(merge); for (V v : merge) vertexToConnectedSet.put(v, merge); } } /** * @see GraphListener#edgeRemoved(GraphEdgeChangeEvent) */ @Override public void edgeRemoved(GraphEdgeChangeEvent e) { init(); // for now invalidate cached results, in the future need to // amend them. If the edge is a bridge, 2 components need to be split. } /** * Tests whether two vertices lay respectively in the same connected component (undirected * graph), or in the same weakly connected component (directed graph). * * @param sourceVertex one end of the path. * @param targetVertex another end of the path. * * @return true if and only if the source and target vertex are in the same * connected component (undirected graph), or in the same weakly connected component * (directed graph). */ public boolean pathExists(V sourceVertex, V targetVertex) { return connectedSetOf(sourceVertex).contains(targetVertex); } /** * @see VertexSetListener#vertexAdded(GraphVertexChangeEvent) */ @Override public void vertexAdded(GraphVertexChangeEvent e) { Set component = new HashSet<>(); component.add(e.getVertex()); connectedSets.add(component); vertexToConnectedSet.put(e.getVertex(), component); } /** * @see VertexSetListener#vertexRemoved(GraphVertexChangeEvent) */ @Override public void vertexRemoved(GraphVertexChangeEvent e) { init(); // for now invalidate cached results, in the future need to // amend them. If the vertex is an articulation point, two // components need to be split } private void init() { connectedSets = null; vertexToConnectedSet = new HashMap<>(); } private List> lazyFindConnectedSets() { if (connectedSets == null) { connectedSets = new ArrayList<>(); Set vertexSet = graph.vertexSet(); if (!vertexSet.isEmpty()) { BreadthFirstIterator i = new BreadthFirstIterator<>(graph); i.addTraversalListener(new MyTraversalListener()); while (i.hasNext()) { i.next(); } } } return connectedSets; } /** * A traversal listener that groups all vertices according to to their containing connected set. * * @author Barak Naveh */ private class MyTraversalListener extends TraversalListenerAdapter { private Set currentConnectedSet; /** * @see TraversalListenerAdapter#connectedComponentFinished(ConnectedComponentTraversalEvent) */ @Override public void connectedComponentFinished(ConnectedComponentTraversalEvent e) { connectedSets.add(currentConnectedSet); } /** * @see TraversalListenerAdapter#connectedComponentStarted(ConnectedComponentTraversalEvent) */ @Override public void connectedComponentStarted(ConnectedComponentTraversalEvent e) { currentConnectedSet = new HashSet<>(); } /** * @see TraversalListenerAdapter#vertexTraversed(VertexTraversalEvent) */ @Override public void vertexTraversed(VertexTraversalEvent e) { V v = e.getVertex(); currentConnectedSet.add(v); vertexToConnectedSet.put(v, currentConnectedSet); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy