Parcourir la source

ENH: DependencyGraph: Enhanced the topologicalSort() method to be able to
sort subgraphs. This can be used to print the dependencies for general
DAGs, not only for connected graphs with one sink (CTKCore).

Sascha Zelzer il y a 14 ans
Parent
commit
1e0f827a5f
2 fichiers modifiés avec 89 ajouts et 4 suppressions
  1. 86 2
      Libs/Core/ctkDependencyGraph.cpp
  2. 3 2
      Libs/Core/ctkDependencyGraph.h

+ 86 - 2
Libs/Core/ctkDependencyGraph.cpp

@@ -60,7 +60,17 @@ public:
   int edge(int vertice, int degree);
 
   void verticesWithIndegree(int indegree, QList<int>& list);
-  
+
+  int subgraphSize(int rootId);
+  void subgraphSizeRec(int rootId, QSet<int>& uniqueVertices);
+
+  void subgraphInsert(ctkDependencyGraph& subgraph, int rootId,
+                      QHash<int,int>& subgraphIdToGlobal, QHash<int,int>& globalIdToSubgraph);
+
+  int getOrGenerateSubgraphId(QHash<int, int>& subgraphIdToGlobal,
+                      QHash<int, int>& globalIdToSubgraph,
+                      int globalId);
+
   /// See http://en.wikipedia.org/wiki/Adjacency_list
   QVarLengthArray<QVarLengthArray<int,MAXDEGREE>*, MAXV+1> Edges;
   QVarLengthArray<int, MAXV+1> OutDegree;
@@ -264,6 +274,64 @@ void ctkDependencyGraph::ctkInternal::verticesWithIndegree(int indegree, QList<i
       }
     }
 }
+
+void ctkDependencyGraph::ctkInternal::subgraphSizeRec(int rootId, QSet<int>& uniqueVertices)
+{
+  Q_ASSERT(rootId > 0);
+
+  for (int i = 0; i < this->OutDegree[rootId]; ++i)
+    {
+    int child = this->edge(rootId, i);
+    uniqueVertices << child;
+    subgraphSizeRec(child, uniqueVertices);
+    }
+}
+
+int ctkDependencyGraph::ctkInternal::subgraphSize(int rootId)
+{
+  Q_ASSERT(rootId > 0);
+
+  QSet<int> vertices;
+  vertices << rootId;
+  this->subgraphSizeRec(rootId, vertices);
+  return vertices.size();
+}
+
+void ctkDependencyGraph::ctkInternal::subgraphInsert(
+    ctkDependencyGraph& subgraph, int rootId,
+    QHash<int,int>& subgraphIdToGlobal, QHash<int,int>& globalIdToSubgraph)
+{
+  int from = this->getOrGenerateSubgraphId(subgraphIdToGlobal, globalIdToSubgraph, rootId);
+  for (int i = 0; i < this->OutDegree[rootId]; ++i)
+  {
+    int childId = this->edge(rootId, i);
+    int to = this->getOrGenerateSubgraphId(subgraphIdToGlobal, globalIdToSubgraph,
+                                           childId);
+
+    subgraph.insertEdge(from, to);
+    this->subgraphInsert(subgraph, childId, subgraphIdToGlobal, globalIdToSubgraph);
+  }
+}
+
+int ctkDependencyGraph::ctkInternal::getOrGenerateSubgraphId(
+    QHash<int, int>& subgraphIdToGlobal,
+    QHash<int, int>& globalIdToSubgraph,
+    int globalId)
+{
+  // If needed, generate vertex id
+  int subgraphId = -1;
+  if (!globalIdToSubgraph.keys().contains(globalId))
+    {
+    subgraphId = globalIdToSubgraph.keys().size() + 1;
+    globalIdToSubgraph[globalId] = subgraphId;
+    subgraphIdToGlobal[subgraphId] = globalId;
+    }
+  else
+    {
+    subgraphId = globalIdToSubgraph[globalId];
+    }
+  return subgraphId;
+}
     
 //----------------------------------------------------------------------------
 // ctkDependencyGraph methods
@@ -494,8 +562,24 @@ void ctkDependencyGraph::findPath(int from, int to, QList<int>& path)
 }
 
 //----------------------------------------------------------------------------
-bool ctkDependencyGraph::topologicalSort(QList<int>& sorted)
+bool ctkDependencyGraph::topologicalSort(QList<int>& sorted, int rootId)
 {
+  if (rootId > 0)
+    {
+    ctkDependencyGraph subgraph(this->Internal->subgraphSize(rootId));
+    QHash<int,int> subgraphIdToGlobal;
+    QHash<int,int> globalIdToSubgraph;
+    this->Internal->subgraphInsert(subgraph, rootId, subgraphIdToGlobal, globalIdToSubgraph);
+
+    QList<int> subgraphSorted;
+    bool result = subgraph.topologicalSort(subgraphSorted);
+    foreach(int subgraphId, subgraphSorted)
+      {
+      sorted << subgraphIdToGlobal[subgraphId];
+      }
+    return result;
+    }
+
   QVarLengthArray<int, MAXV> outdegree; // outdegree of each vertex
   QQueue<int> zeroout;	  // vertices of outdegree 0
 	int x, y;			        // current and next vertex

+ 3 - 2
Libs/Core/ctkDependencyGraph.h

@@ -85,10 +85,11 @@ public:
   /// Called each time an edge is visited
   virtual void processEdge(int /*from*/, int /*to*/){}
   
-  /// Perform a topological search
+  /// Perform a topological sort
   /// Return false if the graph contains cycles
+  /// If a rootId is given, the subgraph starting at the root id is sorted
   /// See cycleDetected, cycleOrigin, cycleEnd
-  bool topologicalSort(QList<int>& sorted);
+  bool topologicalSort(QList<int>& sorted, int rootId = -1);
 
   /// Retrieve all vertices with indegree 0
   void sourceVertices(QList<int>& sources);