diff dwtx/draw2d/graph/SortSubgraphs.d @ 98:95307ad235d9

Added Draw2d code, still work in progress
author Frank Benoit <benoit@tionex.de>
date Sun, 03 Aug 2008 00:52:14 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/draw2d/graph/SortSubgraphs.d	Sun Aug 03 00:52:14 2008 +0200
@@ -0,0 +1,238 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.draw2d.graph.SortSubgraphs;
+
+import dwt.dwthelper.utils;
+import dwtx.dwtxhelper.Collection;
+import dwtx.draw2d.graph.GraphVisitor;
+import dwtx.draw2d.graph.NestingTree;
+import dwtx.draw2d.graph.CompoundDirectedGraph;
+import dwtx.draw2d.graph.Node;
+import dwtx.draw2d.graph.NodeList;
+import dwtx.draw2d.graph.NodePair;
+import dwtx.draw2d.graph.DirectedGraph;
+import dwtx.draw2d.graph.RankList;
+import dwtx.draw2d.graph.Rank;
+import dwtx.draw2d.graph.Subgraph;
+
+/**
+ * Performs a topological sort from left to right of the subgraphs in a compound directed
+ * graph.  This ensures that subgraphs do not intertwine.
+ * @author Randy Hudson
+ * @since 2.1.2
+ */
+class SortSubgraphs : GraphVisitor {
+
+CompoundDirectedGraph g;
+
+NestingTree[] nestingTrees;
+
+Set orderingGraphEdges;
+Set orderingGraphNodes;
+NodePair pair;
+
+public this(){
+    orderingGraphEdges = new HashSet();
+    orderingGraphNodes = new HashSet();
+    pair = new NodePair();
+}
+
+private void breakSubgraphCycles() {
+    //The stack of nodes which have no unmarked incoming edges
+    List noLefts = new ArrayList();
+
+    int index = 1;
+    //Identify all initial nodes for removal
+    for (Iterator iter = orderingGraphNodes.iterator(); iter.hasNext();) {
+        Node node = cast(Node)iter.next();
+        if (node.x is 0)
+            sortedInsert(noLefts, node);
+    }
+
+    Node cycleRoot;
+    do {
+        //Remove all leftmost nodes, updating the nodes to their right
+        while (noLefts.size() > 0) {
+            Node node = cast(Node)noLefts.remove(noLefts.size() - 1);
+            node.sortValue = index++;
+            orderingGraphNodes.remove(node);
+//          System.out.println("removed:" + node);
+            NodeList rightOf = rightOf(node);
+            if (rightOf is null)
+                continue;
+            for (int i = 0; i < rightOf.size(); i++) {
+                Node right = rightOf.getNode(i);
+                right.x--;
+                if (right.x is 0)
+                    sortedInsert(noLefts, right);
+            }
+        }
+        cycleRoot = null;
+        double min = Double.MAX_VALUE;
+        for (Iterator iter = orderingGraphNodes.iterator(); iter.hasNext();) {
+            Node node = cast(Node)iter.next();
+            if (node.sortValue < min) {
+                cycleRoot = node;
+                min = node.sortValue;
+            }
+        }
+        if (cycleRoot !is null) {
+            //break the cycle;
+            sortedInsert(noLefts, cycleRoot);
+//          System.out.println("breaking cycle with:" + cycleRoot);
+//          Display.getCurrent().beep();
+            cycleRoot.x = -1; //prevent x from ever reaching 0
+        } // else if (OGmembers.size() > 0)
+            //System.out.println("FAILED TO FIND CYCLE ROOT"); //$NON-NLS-1$
+    } while (cycleRoot !is null);
+}
+
+private void buildSubgraphOrderingGraph() {
+    RankList ranks = g.ranks;
+    nestingTrees = new NestingTree[ranks.size()];
+    for (int r = 0; r < ranks.size(); r++) {
+        NestingTree entry = NestingTree.buildNestingTreeForRank(ranks.getRank(r));
+        nestingTrees[r] = entry;
+        entry.calculateSortValues();
+        entry.recursiveSort(false);
+    }
+
+    for (int i = 0; i < nestingTrees.length; i++) {
+        NestingTree entry = nestingTrees[i];
+        buildSubgraphOrderingGraph(entry);
+    }
+}
+
+private void buildSubgraphOrderingGraph(NestingTree entry) {
+    NodePair pair = new NodePair();
+    if (entry.isLeaf)
+        return;
+    for (int i = 0; i < entry.contents.size(); i++) {
+        Object right = entry.contents.get(i);
+        if (auto r = cast(Node)right )
+            pair.n2 = r;
+        else {
+            pair.n2 = (cast(NestingTree)right).subgraph;
+            buildSubgraphOrderingGraph(cast(NestingTree)right);
+        }
+        if (pair.n1 !is null && !orderingGraphEdges.contains(pair)) {
+            orderingGraphEdges.add(pair);
+            leftToRight(pair.n1, pair.n2);
+            orderingGraphNodes.add(pair.n1);
+            orderingGraphNodes.add(pair.n2);
+            pair.n2.x++; //Using x field to count predecessors.
+            pair = new NodePair(pair.n2, null);
+        } else {
+            pair.n1 = pair.n2;
+        }
+    }
+}
+
+/**
+ * Calculates the average position P for each node and subgraph.  The average position is
+ * stored in the sortValue for each node or subgraph.
+ *
+ * Runs in approximately linear time with respect to the number of nodes, including
+ * virtual nodes.
+ */
+private void calculateSortValues() {
+    RankList ranks = g.ranks;
+
+    g.subgraphs.resetSortValues();
+    g.subgraphs.resetIndices();
+
+    /*
+     * For subgraphs, the sum of all positions is kept, along with the number of
+     * contributions, which is tracked in the subgraph's index field.
+     */
+    for (int r = 0; r < ranks.size(); r++) {
+        Rank rank = ranks.getRank(r);
+        for (int j = 0; j < rank.count(); j++) {
+            Node node = rank.getNode(j);
+            node.sortValue = node.index;
+            Subgraph parent = node.getParent();
+            while (parent !is null) {
+                parent.sortValue += node.sortValue;
+                parent.index++;
+                parent = parent.getParent();
+            }
+        }
+    }
+
+    /*
+     * For each subgraph, divide the sum of the positions by the number of contributions,
+     * to give the average position.
+     */
+    for (int i = 0; i < g.subgraphs.size(); i++) {
+        Subgraph subgraph = cast(Subgraph)g.subgraphs.get(i);
+        subgraph.sortValue /= subgraph.index;
+    }
+}
+
+private void repopulateRanks() {
+    for (int i = 0; i < nestingTrees.length; i++) {
+        Rank rank = g.ranks.getRank(i);
+        rank.clear();
+        nestingTrees[i].repopulateRank(rank);
+    }
+}
+
+private NodeList rightOf(Node left) {
+    return cast(NodeList)left.workingData[0];
+}
+
+private void leftToRight(Node left, Node right) {
+    rightOf(left).add(right);
+}
+
+void sortedInsert(List list, Node node) {
+    int insert = 0;
+    while (insert < list.size()
+      && (cast(Node)list.get(insert)).sortValue > node.sortValue)
+        insert++;
+    list.add(insert, node);
+}
+
+private void topologicalSort() {
+    for (int i = 0; i < nestingTrees.length; i++) {
+        nestingTrees[i].getSortValueFromSubgraph();
+        nestingTrees[i].recursiveSort(false);
+    }
+}
+
+void init() {
+    for (int r = 0; r < g.ranks.size(); r++) {
+        Rank rank = g.ranks.getRank(r);
+        for (int i = 0; i < rank.count(); i++) {
+            Node n = cast(Node)rank.get(i);
+            n.workingData[0] = new NodeList();
+        }
+    }
+    for (int i = 0; i < g.subgraphs.size(); i++) {
+        Subgraph s = cast(Subgraph)g.subgraphs.get(i);
+        s.workingData[0] = new NodeList();
+    }
+}
+
+public void visit(DirectedGraph dg) {
+    g = cast(CompoundDirectedGraph)dg;
+
+    init();
+    buildSubgraphOrderingGraph();
+    calculateSortValues();
+    breakSubgraphCycles();
+    topologicalSort();
+    repopulateRanks();
+}
+
+}