Mercurial > projects > dwt-addons
comparison dwtx/draw2d/graph/TightSpanningTreeSolver.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 |
comparison
equal
deleted
inserted
replaced
96:b492ba44e44d | 98:95307ad235d9 |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2003, 2005 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module dwtx.draw2d.graph.TightSpanningTreeSolver; | |
14 | |
15 import dwt.dwthelper.utils; | |
16 import dwtx.draw2d.graph.SpanningTreeVisitor; | |
17 import dwtx.draw2d.graph.DirectedGraph; | |
18 import dwtx.draw2d.graph.Edge; | |
19 import dwtx.draw2d.graph.EdgeList; | |
20 import dwtx.draw2d.graph.Node; | |
21 import dwtx.draw2d.graph.NodeList; | |
22 | |
23 /** | |
24 * Finds a tight spanning tree from the graphs edges which induce a valid rank assignment. | |
25 * This process requires that the nodes be initially given a feasible ranking. | |
26 * @author Randy Hudson | |
27 * @since 2.1.2 | |
28 */ | |
29 class TightSpanningTreeSolver : SpanningTreeVisitor { | |
30 | |
31 protected DirectedGraph graph; | |
32 protected CandidateList candidates; | |
33 | |
34 static final class CandidateList { | |
35 private Edge[] edges; | |
36 private int size_; | |
37 | |
38 public this(){ | |
39 edges = new Edge[10]; | |
40 } | |
41 public void add(Edge edge) { | |
42 if (size_ is edges.length - 1) { | |
43 Edge newEdges[] = new Edge[edges.length * 2]; | |
44 System.arraycopy(edges, 0, newEdges, 0, edges.length); | |
45 edges = newEdges; | |
46 } | |
47 edges[size_++] = edge; | |
48 } | |
49 | |
50 public Edge getEdge(int index) { | |
51 return edges[index]; | |
52 } | |
53 | |
54 public void remove(Edge edge) { | |
55 for (int i = 0; i < size_; i++) { | |
56 if (edges[i] is edge) { | |
57 edges[i] = edges[size_ - 1]; | |
58 size_--; | |
59 return; | |
60 } | |
61 } | |
62 throw new RuntimeException("Remove called on invalid Edge"); //$NON-NLS-1$ | |
63 } | |
64 | |
65 public int size() { | |
66 return size_; | |
67 } | |
68 } | |
69 | |
70 protected NodeList members; | |
71 | |
72 public this(){ | |
73 candidates = new CandidateList(); | |
74 members = new NodeList(); | |
75 } | |
76 | |
77 public void visit(DirectedGraph graph) { | |
78 this.graph = graph; | |
79 init(); | |
80 solve(); | |
81 } | |
82 | |
83 Node addEdge(Edge edge) { | |
84 int delta = edge.getSlack(); | |
85 edge.tree = true; | |
86 Node node; | |
87 if (edge.target.flag) { | |
88 delta = -delta; | |
89 node = edge.source; | |
90 setParentEdge(node, edge); | |
91 getSpanningTreeChildren(edge.target).add(edge); | |
92 } else { | |
93 node = edge.target; | |
94 setParentEdge(node, edge); | |
95 getSpanningTreeChildren(edge.source).add(edge); | |
96 } | |
97 members.adjustRank(delta); | |
98 addNode(node); | |
99 return node; | |
100 } | |
101 | |
102 private bool isNodeReachable(Node node) { | |
103 return node.flag; | |
104 } | |
105 | |
106 private void setNodeReachable(Node node) { | |
107 node.flag = true; | |
108 } | |
109 | |
110 private bool isCandidate(Edge e) { | |
111 return e.flag; | |
112 } | |
113 | |
114 private void setCandidate(Edge e) { | |
115 e.flag = true; | |
116 } | |
117 | |
118 void addNode(Node node) { | |
119 setNodeReachable(node); | |
120 EdgeList list = node.incoming; | |
121 Edge e; | |
122 for (int i = 0; i < list.size(); i++) { | |
123 e = list.getEdge(i); | |
124 if (!isNodeReachable(e.source)) { | |
125 if (!isCandidate(e)) { | |
126 setCandidate(e); | |
127 candidates.add(e); | |
128 } | |
129 } else | |
130 candidates.remove(e); | |
131 } | |
132 | |
133 list = node.outgoing; | |
134 for (int i = 0; i < list.size(); i++) { | |
135 e = list.getEdge(i); | |
136 if (!isNodeReachable(e.target)) { | |
137 if (!isCandidate(e)) { | |
138 setCandidate(e); | |
139 candidates.add(e); | |
140 } | |
141 } else | |
142 candidates.remove(e); | |
143 } | |
144 members.add(node); | |
145 } | |
146 | |
147 void init() { | |
148 graph.edges.resetFlags(true); | |
149 graph.nodes.resetFlags(); | |
150 for (int i = 0; i < graph.nodes.size(); i++) { | |
151 Node node = cast(Node)graph.nodes.get(i); | |
152 node.workingData[0] = new EdgeList(); | |
153 } | |
154 } | |
155 | |
156 protected void solve() { | |
157 Node root = graph.nodes.getNode(0); | |
158 setParentEdge(root, null); | |
159 addNode(root); | |
160 while (members.size() < graph.nodes.size()) { | |
161 if (candidates.size() is 0) | |
162 throw new RuntimeException("graph is not fully connected");//$NON-NLS-1$ | |
163 int minSlack = Integer.MAX_VALUE, slack; | |
164 Edge minEdge = null, edge; | |
165 for (int i = 0; i < candidates.size() && minSlack > 0; i++) { | |
166 edge = candidates.getEdge(i); | |
167 slack = edge.getSlack(); | |
168 if (slack < minSlack) { | |
169 minSlack = slack; | |
170 minEdge = edge; | |
171 } | |
172 } | |
173 addEdge(minEdge); | |
174 } | |
175 graph.nodes.normalizeRanks(); | |
176 } | |
177 | |
178 } |