// GraphTea Project: http://github.com/graphtheorysoftware/GraphTea // Copyright (C) 2012 Graph Theory Software Foundation: http://GraphTheorySoftware.com // Copyright (C) 2008 Mathematical Science Department of Sharif University of Technology // Distributed under the terms of the GNU Lesser General Public License (LGPL): http://www.gnu.org/licenses/ package graphtea.library.algorithms.graphdecomposition; import graphtea.library.BaseEdge; import graphtea.library.BaseGraph; import graphtea.library.BaseVertex; import graphtea.library.algorithms.Algorithm; import graphtea.library.algorithms.AutomatedAlgorithm; import graphtea.library.algorithms.util.EventUtils; import graphtea.library.event.GraphRequest; import graphtea.library.util.Pair; import java.util.HashSet; import java.util.Iterator; import java.util.Stack; import java.util.Vector; /** * This Method find the biconnected components of a * graph. * Which are the maximal subgraphs without any cut vertices. * * @author Azin Azadi :returning biconnected compoenents * @author Soroush Sabet */ public class BiconnectedComponents <VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>> extends Algorithm implements AutomatedAlgorithm { //PreWorkPostWorkHandler handler = new PreWorkPostWorkHandler<VertexType>(); Integer[] DFS_Number; Integer[] High; int[] parent; Vector<Pair<Vector<VertexType>, Vector<EdgeType>>> BiC = new Vector<>(); Vector<HashSet<VertexType>> ret; int DFS_N; private VertexType root; /** * The initialization, before searching for biconnected * components. * Here, DFS_N is the number assigned to vertices in process * of dfs traversal, although in decreasing order. * High[v] denotes the highest vertex, reachable from v or * it's children in the dfs tree. * * @param g is the input graph. */ private void init(BaseGraph<VertexType, EdgeType> g) { DFS_Number = new Integer[g.getVerticesCount()]; for (int i = 0; i < g.getVerticesCount(); i++) DFS_Number[i] = 0; DFS_N = g.getVerticesCount(); High = new Integer[g.getVerticesCount()]; parent = new int[g.getVerticesCount()]; } public void doAlgorithm() { GraphRequest<VertexType, EdgeType> gr = new GraphRequest<>(); dispatchEvent(gr); BaseGraph<VertexType, EdgeType> g = gr.getGraph(); BC(g, root); // LibraryUtils.algorithmStep(this, "Biconnected Components:" + comps); } /** * This class is used to put both vertices and edges in * a stack. */ private class VE { VertexType v; EdgeType e; VE(VertexType v) { this.v = v; this.e = null; } VE(EdgeType e) { this.e = e; this.v = null; } VE() { this.v = null; this.e = null; } } int rootChilds = 0; int foundDecompositions; Stack<VE> S = new Stack<>(); //stack is initially empty /** * This method is in fact dfs, with some preworks and postworks * added to it. * It finds biconnected components of the input graph g, by * starting search from the node v. * * @param g The given graph * @param v The given vertex */ private void BC(BaseGraph<VertexType, EdgeType> g, VertexType v) { DFS_Number[v.getId()] = DFS_N; DFS_N--; S.push(new VE(v)); High[v.getId()] = DFS_Number[v.getId()]; Iterator<EdgeType> iet; iet = g.edgeIterator(v); EdgeType edge; VertexType w; while (iet.hasNext()) { edge = iet.next(); w = edge.source == v ? edge.target : edge.source; if (parent[v.getId()] != w.getId()) if (DFS_Number[w.getId()] == 0) { //w not visited before parent[w.getId()] = v.getId(); edge.setMark(true); w.setMark(true); EventUtils.algorithmStep(this, ""); BC(g, w); w.setMark(false); EventUtils.algorithmStep(this, ""); if (High[w.getId()] <= DFS_Number[v.getId()]) { //v disconnects w from the rest of the graph if (v == root) { //the root is an articulation point if and only if it has more than one child in the DFS tree rootChilds++; if (rootChilds == 1) continue; } foundDecompositions++; v.setColor(2); } High[v.getId()] = Math.max(High[v.getId()], High[w.getId()]); } else //(v,w) is a back edge or a forward edge High[v.getId()] = Math.max(High[v.getId()], DFS_Number[w.getId()]); } } public Vector<HashSet<VertexType>> biconnected_components(BaseGraph<VertexType, EdgeType> g, VertexType v, int n) { DFS_Number=new Integer[n]; High=new Integer[n]; parent=new int[n]; S = new Stack<>(); ret= new Vector<>(); for (VertexType scan : g) DFS_Number[scan.getId()] = 0; DFS_N = n; Bicon(g,v); return ret; } /** * This is the main method for developing use, wich take the graph g as * the input, and returns the biconnected components * of g in a vector. */ public void Bicon(BaseGraph<VertexType, EdgeType> g, VertexType v) { DFS_Number[v.getId()] = DFS_N; DFS_N--; S.push(new VE(v)); High[v.getId()] = DFS_Number[v.getId()]; for (VertexType w : g.getNeighbors(v)) { EdgeType vw = g.getEdges(v,w).get(0); S.push(new VE(vw)); if (parent[v.getId()]!=w.getId()){ if (DFS_Number[w.getId()]==0){ parent[w.getId()]= v.getId(); Bicon(g,w); if (High[w.getId()] <= DFS_Number[v.getId()]){ VE top=S.pop(); HashSet<VertexType> comp= new HashSet<>(); if (top.v!=null) comp.add(top.v); while (v!=top.v){ top = S.pop(); if (top.v!=null) comp.add(top.v); } ret.add(comp); S.push(new VE(v)); } High[v.getId()] = Math.max(High[v.getId()], High[w.getId()]); } else { High[v.getId()] = Math.max(High[v.getId()], DFS_Number[w.getId()]); } } } //// public Vector<BaseGraph<VertexType,EdgeType>> Bicon(BaseGraph<VertexType,EdgeType> g){ // init(g); // rootChilds = 0; // root = g.iterator().next(); // // foundDecompositions = 0; // BC(g, root); // Vector<HashSet<VertexType>> ret = new Vector<HashSet<VertexType>>(); // for (VertexType v : g) { // v.setMark(false); // } // for (VertexType v : g) { // if (!v.getMark()) { // Queue<VertexType> q = new LinkedList<VertexType>(); // HashSet<VertexType> r = new HashSet<VertexType>(); // q.add(v); // while (!q.isEmpty()) { // VertexType t = q.poll(); // t.setMark(true); // r.add(t); // if (t.getColor() != 2) // for (VertexType scan : g.getNeighbors(t)) { // if (!scan.getMark() || scan.getColor() == 2) // q.add(scan); // } // } // ret.add(r); // } // } // return ret; // } }