Coverage Report - net.sourceforge.combean.graph.alg.partition.SCCByDFSImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
SCCByDFSImpl
78%
25/32
33%
4/12
1,412
SCCByDFSImpl$SCCVisitor
98%
42/43
88%
7/8
1,412
 
 1  
 /*
 2  
     This file is part of Combean.
 3  
 
 4  
     Combean is free software; you can redistribute it and/or modify
 5  
     it under the terms of the GNU General Public License as published by
 6  
     the Free Software Foundation; either version 2 of the License, or
 7  
     (at your option) any later version.
 8  
 
 9  
     Combean is distributed in the hope that it will be useful,
 10  
     but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12  
     GNU General Public License for more details.
 13  
 
 14  
     You should have received a copy of the GNU General Public License
 15  
     along with Combean; if not, write to the Free Software
 16  
     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 17  
 */
 18  
 /*
 19  
  * Created on 10.02.2005
 20  
  *
 21  
  */
 22  
 package net.sourceforge.combean.graph.alg.partition;
 23  
 
 24  
 import net.sourceforge.combean.graph.alg.traversal.DFSNodeStackVisitor;
 25  
 import net.sourceforge.combean.graph.alg.traversal.RecursiveDFSImpl;
 26  
 import net.sourceforge.combean.graph.containers.NodeNumberingAdvisor;
 27  
 import net.sourceforge.combean.interfaces.graph.Edge;
 28  
 import net.sourceforge.combean.interfaces.graph.Graph;
 29  
 import net.sourceforge.combean.interfaces.graph.Node;
 30  
 import net.sourceforge.combean.interfaces.graph.alg.partition.NodePartitionVisitor;
 31  
 import net.sourceforge.combean.interfaces.graph.alg.traverse.DepthFirstSearch;
 32  
 import net.sourceforge.combean.interfaces.graph.containers.NodeNumbering;
 33  
 import net.sourceforge.combean.interfaces.graph.prop.GlobalNodesGraphProp;
 34  
 import net.sourceforge.combean.interfaces.graph.prop.NeighborhoodGraphProp;
 35  
 import net.sourceforge.combean.util.except.UnsupportedMethodException;
 36  
 
 37  
 /**
 38  
  * Find strongly connected components by DFS (Tarjan's algorithm for SCCs).
 39  
  * 
 40  
  * @author schickin
 41  
  *
 42  
  */
 43  3
 public final class SCCByDFSImpl extends AbstractSCCImpl {
 44  
   
 45  
     // the graph to work with
 46  12
     private NeighborhoodGraphProp graph = null;
 47  12
     private GlobalNodesGraphProp globalNodes = null;
 48  
     
 49  
     // the DFS helper algorithm
 50  12
     private DepthFirstSearch dfs = null;
 51  12
     private SCCVisitor sccVis = null;
 52  
     
 53  
     // helper data structures for the DFS
 54  
 
 55  
     // store lowest dfs number of a node reachable via at least one tree edge
 56  12
     private NodeNumbering lowNum = null;
 57  
 
 58  
     private class SCCVisitor extends DFSNodeStackVisitor {
 59  
         
 60  12
         private SCCByDFSImpl sccAlg = null;
 61  12
         private NeighborhoodGraphProp g = null;
 62  
 
 63  12
         private boolean sccOpened = false;
 64  
         
 65  
         /**
 66  
          * @param sccAlg the algorithm for which the visitor works
 67  
          */
 68  12
         SCCVisitor(SCCByDFSImpl sccAlg) {
 69  12
             super();
 70  12
             this.sccAlg = sccAlg;
 71  12
         }
 72  
 
 73  
         /**
 74  
          * Update the low numbering of v, assuming that w is a neighbor of w
 75  
          * that w already has its correct low numbering
 76  
          * 
 77  
          * @param v
 78  
          * @param w
 79  
          */
 80  
         private void adjustLowNum(Node v, Node w) {
 81  78
             int lowV = this.sccAlg.getLowNumbering().getNumber(v);
 82  78
             int lowW = this.sccAlg.getLowNumbering().getNumber(w);
 83  78
             if (lowW < lowV) {
 84  48
                 this.sccAlg.getLowNumbering().setNumber(v, lowW);
 85  
             }
 86  78
         }
 87  
 
 88  
         /* (non-Javadoc)
 89  
          * @see net.sourceforge.combean.interfaces.graph.alg.traverse.DFSVisitor#leaveNode(net.sourceforge.combean.interfaces.graph.Node)
 90  
          */
 91  
         public final void leaveNode(Node v) {
 92  78
             super.leaveNode(v);
 93  78
             NodePartitionVisitor vis = this.sccAlg.getVisitor();
 94  78
             if (!this.sccOpened) {
 95  30
                 vis.startPartition();
 96  30
                 this.sccOpened = true;
 97  
             }
 98  78
             vis.addNode(v);
 99  78
             int dfsV = getDfsNum(v);
 100  78
             int lowV = this.sccAlg.getLowNumbering().getNumber(v);
 101  78
             if (dfsV == lowV) {
 102  30
                 vis.endPartition();
 103  30
                 this.sccOpened = false;
 104  
             }
 105  78
         }
 106  
         
 107  
         /* (non-Javadoc)
 108  
          * @see net.sourceforge.combean.interfaces.graph.alg.traverse.DFSVisitor#leaveNeighbor(net.sourceforge.combean.interfaces.graph.Node, net.sourceforge.combean.interfaces.graph.Edge)
 109  
          */
 110  
         public final void leaveNeighbor(Edge e, Node from) {
 111  66
             super.leaveNeighbor(e,from);
 112  66
             Node w = this.g.getOtherNode(e, from);
 113  66
             adjustLowNum(from, w);
 114  66
         }
 115  
 
 116  
         /* (non-Javadoc)
 117  
          * @see net.sourceforge.combean.interfaces.graph.alg.traverse.TraversalVisitor#init(net.sourceforge.combean.interfaces.graph.Graph)
 118  
          */
 119  
         public void init(Graph g) {
 120  12
             super.init(g);
 121  12
             this.g = (NeighborhoodGraphProp) g;
 122  12
             this.sccAlg.getLowNumbering().init(g);
 123  12
             this.sccOpened = false;
 124  12
         }
 125  
         
 126  
         /* (non-Javadoc)
 127  
          * @see net.sourceforge.combean.interfaces.graph.alg.traverse.TraversalVisitor#initLocal(net.sourceforge.combean.interfaces.graph.Graph, net.sourceforge.combean.interfaces.graph.Node)
 128  
          */
 129  
         public void initLocal(Graph g, Node startNode) {
 130  
             /*
 131  
              we only look for SCCs globally
 132  
             */
 133  0
             throw new UnsupportedMethodException();
 134  
         }
 135  
         
 136  
         /* (non-Javadoc)
 137  
          * @see net.sourceforge.combean.interfaces.graph.alg.traverse.TraversalVisitor#visitNode(net.sourceforge.combean.interfaces.graph.Node)
 138  
          */
 139  
         public void visitNode(Node v) {
 140  78
              super.visitNode(v);
 141  78
              this.sccAlg.getLowNumbering().setNumber(v, getDfsNum(v));
 142  78
         }
 143  
         
 144  
         /* (non-Javadoc)
 145  
          * @see net.sourceforge.combean.interfaces.graph.alg.traverse.TraversalVisitor#reopenNeighbor(net.sourceforge.combean.interfaces.graph.Edge, net.sourceforge.combean.interfaces.graph.Node)
 146  
          */
 147  
         public final void reopenNeighbor(Edge e, Node from) {
 148  12
             super.reopenNeighbor(e,from);
 149  12
             Node w = this.g.getOtherNode(e, from);
 150  12
             int dfsW = this.sccAlg.getDfsNumbering().getNumber(w);
 151  12
             if (dfsW < 0) {
 152  12
                 adjustLowNum(from, w);
 153  
             }
 154  12
         }
 155  
     }
 156  
     
 157  
     /**
 158  
      * constructor
 159  
      */
 160  
     public SCCByDFSImpl() {
 161  12
         super();
 162  
         // access graph in order to satisfy the compiler
 163  12
         assert this.globalNodes != null;
 164  12
         assert this.graph != null;
 165  12
     }
 166  
 
 167  
     /**
 168  
      * @return Returns the dfs numbering.
 169  
      */
 170  
     public final NodeNumbering getDfsNumbering() {
 171  12
         return this.sccVis.getDfsNumbering();
 172  
     }
 173  
     
 174  
     /**
 175  
      * Set the dfs numbering. If left unset, the NodeNumberingAdvisor will
 176  
      * be consulted.
 177  
      * 
 178  
      * @param dfsNum The dfs numbering to set.
 179  
      */
 180  
     public final void setDfsNumbering(NodeNumbering dfsNum) {
 181  0
         this.sccVis.setDfsNumbering(dfsNum);
 182  0
     }
 183  
 
 184  
     /**
 185  
      * @return Returns the low numbering.
 186  
      */
 187  
     public final NodeNumbering getLowNumbering() {
 188  372
         return this.lowNum;
 189  
     }
 190  
 
 191  
     /**
 192  
      * Set the low numbering. If left unset, the NodeNumberingAdvisor will
 193  
      * be consulted.
 194  
      * 
 195  
      * @param lowNum The low numbering to set.
 196  
      */
 197  
     public final void setLowNumbering(NodeNumbering lowNum) {
 198  0
         this.lowNum = lowNum;
 199  0
     }
 200  
 
 201  
     /**
 202  
      * @return Returns the dfs algorithm.
 203  
      */
 204  
     public final DepthFirstSearch getDfs() {
 205  0
         return this.dfs;
 206  
     }
 207  
     
 208  
     /**
 209  
      * Set the DFS helper algorithm. If left unset RecursiveDFSImpl will be used
 210  
      * @see net.sourceforge.combean.graph.alg.traversal.RecursiveDFSImpl
 211  
      * 
 212  
      * @param dfs The dfs algorithm to set.
 213  
      */
 214  
     public final void setDfs(DepthFirstSearch dfs) {
 215  0
         this.dfs = dfs;
 216  0
     }
 217  
 
 218  
     /* (non-Javadoc)
 219  
      * @see net.sourceforge.combean.interfaces.graph.alg.GraphAlgorithm#run()
 220  
      */
 221  
     public void run() {
 222  12
         getVisitor().init(getGraph());
 223  12
         initDFS();
 224  12
         this.dfs.run();
 225  12
         getVisitor().finish();
 226  12
     }
 227  
     
 228  
     private final void initDFS() {
 229  12
         if (this.lowNum == null) {
 230  12
             this.lowNum = NodeNumberingAdvisor.getFastestNodeNumbering(getGraph());
 231  
         }
 232  12
         if (this.dfs == null) {
 233  12
             this.dfs = new RecursiveDFSImpl();
 234  
         }
 235  12
         this.sccVis = new SCCVisitor(this);
 236  12
         this.dfs.setGraph(getGraph());
 237  12
         this.dfs.setDFSVisitor(this.sccVis);
 238  12
     }
 239  
 }