org.jgrapht.alg.BlockCutpointGraph Maven / Gradle / Ivy
/*
* (C) Copyright 2007-2016, by France Telecom and Contributors.
*
* JGraphT : a free Java graph-theory library
*
* This program and the accompanying materials are dual-licensed under
* either
*
* (a) the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation, or (at your option) any
* later version.
*
* or (per the licensee's choosing)
*
* (b) the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation.
*/
package org.jgrapht.alg;
import java.util.*;
import org.jgrapht.*;
import org.jgrapht.graph.*;
/**
* Definition of a block of a graph in
* MathWorld.
* Definition and lemma taken from the article
* Structure-Based
* Resilience Metrics for Service-Oriented Networks:
*
*
* - Definition 4.5 Let G(V; E) be a connected undirected graph. The block-cut point graph
* (BC graph) of G, denoted by GB(VB; EB), is the bipartite graph defined as follows. (a) VB has one
* node corresponding to each block and one node corresponding to each cut point of G. (b) Each edge
* fx; yg in EB joins a block node x to a cut point y if the block corresponding to x contains the
* cut point node corresponding to y.
* - Lemma 4.4 Let G(V; E) be a connected undirected graph. (a) Each pair of blocks of G
* share at most one node, and that node is a cutpoint. (b) The BC graph of G is a tree in which
* each leaf node corresponds to a block of G.
*
*
* @param the graph vertex type
* @param the graph edge type
*
* @author Guillaume Boulmier
* @since July 5, 2007
*/
public class BlockCutpointGraph
extends SimpleGraph, DefaultEdge>
{
private static final long serialVersionUID = -9101341117013163934L;
private Set cutpoints = new HashSet<>();
/**
* DFS (Depth-First-Search) tree.
*/
private DirectedGraph dfsTree;
private UndirectedGraph graph;
private int numOrder;
private Deque stack = new ArrayDeque<>();
private Map>> vertex2biconnectedSubgraphs = new HashMap<>();
private Map> vertex2block = new HashMap<>();
private Map vertex2numOrder = new HashMap<>();
/**
* Running time = O(m) where m is the number of edges.
*
* @param graph the input graph
*/
public BlockCutpointGraph(UndirectedGraph graph)
{
super(DefaultEdge.class);
this.graph = graph;
this.dfsTree = new SimpleDirectedGraph<>(DefaultEdge.class);
V s = graph.vertexSet().iterator().next();
this.dfsTree.addVertex(s);
dfsVisit(s, s);
if (this.dfsTree.edgesOf(s).size() > 1) {
this.cutpoints.add(s);
} else {
this.cutpoints.remove(s);
}
for (V cutpoint : this.cutpoints) {
UndirectedGraph subgraph = new SimpleGraph<>(this.graph.getEdgeFactory());
subgraph.addVertex(cutpoint);
this.vertex2block.put(cutpoint, subgraph);
addVertex(subgraph);
Set> biconnectedSubgraphs = getBiconnectedSubgraphs(cutpoint);
for (UndirectedGraph biconnectedSubgraph : biconnectedSubgraphs) {
assert (vertexSet().contains(biconnectedSubgraph));
addEdge(subgraph, biconnectedSubgraph);
}
}
}
/**
* Returns the vertex if vertex is a cutpoint, and otherwise returns the block (biconnected
* component) containing the vertex.
*
* @param vertex vertex in the initial graph.
* @return the biconnected component containing the vertex
*/
public UndirectedGraph getBlock(V vertex)
{
if (!this.graph.vertexSet().contains(vertex)) {
throw new IllegalArgumentException("No such vertex in the graph!");
}
return this.vertex2block.get(vertex);
}
/**
* Returns the cutpoints of the initial graph.
*
* @return the cutpoints of the initial graph
*/
public Set getCutpoints()
{
return this.cutpoints;
}
/**
* Returns true
if the vertex is a cutpoint, false
otherwise.
*
* @param vertex vertex in the initial graph.
* @return true
if the vertex is a cutpoint, false
otherwise.
*/
public boolean isCutpoint(V vertex)
{
if (!this.graph.vertexSet().contains(vertex)) {
throw new IllegalArgumentException("No such vertex in the graph!");
}
return this.cutpoints.contains(vertex);
}
private void biconnectedComponentFinished(V s, V n)
{
this.cutpoints.add(s);
Set vertexComponent = new HashSet<>();
Set edgeComponent = new HashSet<>();
BCGEdge edge = this.stack.removeLast();
while ((getNumOrder(edge.getSource()) >= getNumOrder(n)) && !this.stack.isEmpty()) {
edgeComponent.add(edge);
vertexComponent.add(edge.getSource());
vertexComponent.add(edge.getTarget());
edge = this.stack.removeLast();
}
edgeComponent.add(edge);
// edgeComponent is an equivalence class.
vertexComponent.add(edge.getSource());
vertexComponent.add(edge.getTarget());
VertexComponentForbiddenFunction mask =
new VertexComponentForbiddenFunction(vertexComponent);
UndirectedGraph biconnectedSubgraph = new UndirectedMaskSubgraph<>(this.graph, mask);
for (V vertex : vertexComponent) {
this.vertex2block.put(vertex, biconnectedSubgraph);
getBiconnectedSubgraphs(vertex).add(biconnectedSubgraph);
}
addVertex(biconnectedSubgraph);
}
private int dfsVisit(V s, V father)
{
this.numOrder++;
int minS = this.numOrder;
setNumOrder(s, this.numOrder);
for (E edge : this.graph.edgesOf(s)) {
V n = Graphs.getOppositeVertex(this.graph, edge, s);
if (getNumOrder(n) == 0) {
this.dfsTree.addVertex(n);
BCGEdge dfsEdge = new BCGEdge(s, n);
this.dfsTree.addEdge(s, n, dfsEdge);
this.stack.add(dfsEdge);
// minimum of the traverse orders of the "attach points" of
// the vertex n.
int minN = dfsVisit(n, s);
minS = Math.min(minN, minS);
if (minN >= getNumOrder(s)) {
// s is a cutpoint.
// it has a son whose "attach depth" is greater or equal.
biconnectedComponentFinished(s, n);
}
} else if ((getNumOrder(n) < getNumOrder(s)) && !n.equals(father)) {
BCGEdge backwardEdge = new BCGEdge(s, n);
this.stack.add(backwardEdge);
// n is an "attach point" of s. {s->n} is a backward edge.
minS = Math.min(getNumOrder(n), minS);
}
}
// minimum of the traverse orders of the "attach points" of
// the vertex s.
return minS;
}
/**
* Returns the biconnected components containing the vertex. A vertex which is not a cutpoint is
* contained in exactly one component. A cutpoint is contained is at least 2 components.
*
* @param vertex vertex in the initial graph.
*/
private Set> getBiconnectedSubgraphs(V vertex)
{
Set> biconnectedSubgraphs =
this.vertex2biconnectedSubgraphs.get(vertex);
if (biconnectedSubgraphs == null) {
biconnectedSubgraphs = new HashSet<>();
this.vertex2biconnectedSubgraphs.put(vertex, biconnectedSubgraphs);
}
return biconnectedSubgraphs;
}
/**
* Returns the traverse order of the vertex in the DFS.
*/
private int getNumOrder(V vertex)
{
assert (vertex != null);
Integer numOrder = this.vertex2numOrder.get(vertex);
if (numOrder == null) {
return 0;
} else {
return numOrder;
}
}
private void setNumOrder(V vertex, int numOrder)
{
this.vertex2numOrder.put(vertex, numOrder);
}
private class BCGEdge
extends DefaultEdge
{
/**
*/
private static final long serialVersionUID = -5115006161815760059L;
private V source;
private V target;
public BCGEdge(V source, V target)
{
super();
this.source = source;
this.target = target;
}
@Override
public V getSource()
{
return this.source;
}
@Override
public V getTarget()
{
return this.target;
}
}
private class VertexComponentForbiddenFunction
implements MaskFunctor
{
private Set vertexComponent;
public VertexComponentForbiddenFunction(Set vertexComponent)
{
this.vertexComponent = vertexComponent;
}
@Override
public boolean isEdgeMasked(E edge)
{
return false;
}
@Override
public boolean isVertexMasked(V vertex)
{
return !this.vertexComponent.contains(vertex);
}
}
}
// End BlockCutpointGraph.java
© 2015 - 2025 Weber Informatics LLC | Privacy Policy