Project

General

Profile

Download (7.74 KB) Statistics
| Branch: | Tag: | Revision:
1
/*******************************************************************************
2
 * Copyright (c) 2003, 2010 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
 *******************************************************************************/
11
package org.eclipse.draw2d.graph;
12

    
13
import java.util.Iterator;
14
import java.util.Stack;
15

    
16
/**
17
 * Assigns the final rank assignment for a DirectedGraph with an initial
18
 * feasible spanning tree.
19
 * 
20
 * @author Randy Hudson
21
 * @since 2.1.2
22
 */
23
class RankAssignmentSolver extends SpanningTreeVisitor {
24

    
25
	DirectedGraph graph;
26
	EdgeList spanningTree;
27
	boolean searchDirection;
28

    
29
	int depthFirstCutValue(Edge edge, int count) {
30
		Node n = getTreeTail(edge);
31
		setTreeMin(n, count);
32
		int cutvalue = 0;
33
		int multiplier = (edge.target == n) ? 1 : -1;
34
		EdgeList list;
35

    
36
		list = n.outgoing;
37
		Edge e;
38
		for (int i = 0; i < list.size(); i++) {
39
			e = list.getEdge(i);
40
			if (e.tree && e != edge) {
41
				count = depthFirstCutValue(e, count);
42
				cutvalue += (e.cut - e.weight) * multiplier;
43
			} else {
44
				cutvalue -= e.weight * multiplier;
45
			}
46
		}
47
		list = n.incoming;
48
		for (int i = 0; i < list.size(); i++) {
49
			e = list.getEdge(i);
50
			if (e.tree && e != edge) {
51
				count = depthFirstCutValue(e, count);
52
				cutvalue -= (e.cut - e.weight) * multiplier;
53
			} else {
54
				cutvalue += e.weight * multiplier;
55
			}
56
		}
57

    
58
		edge.cut = cutvalue;
59
		if (cutvalue < 0)
60
			spanningTree.add(edge);
61
		setTreeMax(n, count);
62
		return count + 1;
63
	}
64

    
65
	/**
66
	 * returns the Edge which should be entered.
67
	 * 
68
	 * @param branch
69
	 * @return Edge
70
	 */
71
	Edge enter(Node branch) {
72
		Node n;
73
		Edge result = null;
74
		int minSlack = Integer.MAX_VALUE;
75
		boolean incoming = getParentEdge(branch).target != branch;
76
		// searchDirection = !searchDirection;
77
		for (int i = 0; i < graph.nodes.size(); i++) {
78
			if (searchDirection)
79
				n = graph.nodes.getNode(i);
80
			else
81
				n = graph.nodes.getNode(graph.nodes.size() - 1 - i);
82
			if (subtreeContains(branch, n)) {
83
				EdgeList edges;
84
				if (incoming)
85
					edges = n.incoming;
86
				else
87
					edges = n.outgoing;
88
				for (int j = 0; j < edges.size(); j++) {
89
					Edge e = edges.getEdge(j);
90
					if (!subtreeContains(branch, e.opposite(n)) && !e.tree
91
							&& e.getSlack() < minSlack) {
92
						result = e;
93
						minSlack = e.getSlack();
94
					}
95
				}
96
			}
97
		}
98
		return result;
99
	}
100

    
101
	int getTreeMax(Node n) {
102
		return n.workingInts[1];
103
	}
104

    
105
	int getTreeMin(Node n) {
106
		return n.workingInts[0];
107
	}
108

    
109
	void initCutValues() {
110
		Node root = graph.nodes.getNode(0);
111
		spanningTree = new EdgeList();
112
		Edge e;
113
		setTreeMin(root, 1);
114
		setTreeMax(root, 1);
115

    
116
		for (int i = 0; i < root.outgoing.size(); i++) {
117
			e = root.outgoing.getEdge(i);
118
			if (!getSpanningTreeChildren(root).contains(e))
119
				continue;
120
			setTreeMax(root, depthFirstCutValue(e, getTreeMax(root)));
121
		}
122
		for (int i = 0; i < root.incoming.size(); i++) {
123
			e = root.incoming.getEdge(i);
124
			if (!getSpanningTreeChildren(root).contains(e))
125
				continue;
126
			setTreeMax(root, depthFirstCutValue(e, getTreeMax(root)));
127
		}
128
	}
129

    
130
	Edge leave() {
131
		Edge result = null;
132
		Edge e;
133
		int minCut = 0;
134
		int weight = -1;
135
		for (int i = 0; i < spanningTree.size(); i++) {
136
			e = spanningTree.getEdge(i);
137
			if (e.cut < minCut) {
138
				result = e;
139
				minCut = result.cut;
140
				weight = result.weight;
141
			} else if (e.cut == minCut && e.weight > weight) {
142
				result = e;
143
				weight = result.weight;
144
			}
145
		}
146
		return result;
147
	}
148

    
149
	void networkSimplexLoop() {
150
		Edge leave, enter;
151
		int count = 0;
152
		while ((leave = leave()) != null && count < 900) {
153

    
154
			count++;
155

    
156
			Node leaveTail = getTreeTail(leave);
157
			Node leaveHead = getTreeHead(leave);
158

    
159
			enter = enter(leaveTail);
160
			if (enter == null)
161
				break;
162

    
163
			// Break the "leave" edge from the spanning tree
164
			getSpanningTreeChildren(leaveHead).remove(leave);
165
			setParentEdge(leaveTail, null);
166
			leave.tree = false;
167
			spanningTree.remove(leave);
168

    
169
			Node enterTail = enter.source;
170
			if (!subtreeContains(leaveTail, enterTail))
171
				// Oops, wrong end of the edge
172
				enterTail = enter.target;
173
			Node enterHead = enter.opposite(enterTail);
174

    
175
			// Prepare enterTail by making it the root of its sub-tree
176
			updateSubgraph(enterTail);
177

    
178
			// Add "enter" edge to the spanning tree
179
			getSpanningTreeChildren(enterHead).add(enter);
180
			setParentEdge(enterTail, enter);
181
			enter.tree = true;
182

    
183
			repairCutValues(enter);
184

    
185
			Node commonAncestor = enterHead;
186

    
187
			while (!subtreeContains(commonAncestor, leaveHead)) {
188
				repairCutValues(getParentEdge(commonAncestor));
189
				commonAncestor = getTreeParent(commonAncestor);
190
			}
191
			while (leaveHead != commonAncestor) {
192
				repairCutValues(getParentEdge(leaveHead));
193
				leaveHead = getTreeParent(leaveHead);
194
			}
195
			updateMinMax(commonAncestor, getTreeMin(commonAncestor));
196
			tightenEdge(enter);
197
		}
198
	}
199

    
200
	void repairCutValues(Edge edge) {
201
		spanningTree.remove(edge);
202
		Node n = getTreeTail(edge);
203
		int cutvalue = 0;
204
		int multiplier = (edge.target == n) ? 1 : -1;
205
		EdgeList list;
206

    
207
		list = n.outgoing;
208
		Edge e;
209
		for (int i = 0; i < list.size(); i++) {
210
			e = list.getEdge(i);
211
			if (e.tree && e != edge)
212
				cutvalue += (e.cut - e.weight) * multiplier;
213
			else
214
				cutvalue -= e.weight * multiplier;
215
		}
216
		list = n.incoming;
217
		for (int i = 0; i < list.size(); i++) {
218
			e = list.getEdge(i);
219
			if (e.tree && e != edge)
220
				cutvalue -= (e.cut - e.weight) * multiplier;
221
			else
222
				cutvalue += e.weight * multiplier;
223
		}
224

    
225
		edge.cut = cutvalue;
226
		if (cutvalue < 0)
227
			spanningTree.add(edge);
228
	}
229

    
230
	void setTreeMax(Node n, int value) {
231
		n.workingInts[1] = value;
232
	}
233

    
234
	void setTreeMin(Node n, int value) {
235
		n.workingInts[0] = value;
236
	}
237

    
238
	boolean subtreeContains(Node parent, Node child) {
239
		return parent.workingInts[0] <= child.workingInts[1]
240
				&& child.workingInts[1] <= parent.workingInts[1];
241
	}
242

    
243
	void tightenEdge(Edge edge) {
244
		Node tail = getTreeTail(edge);
245
		int delta = edge.getSlack();
246
		if (tail == edge.target)
247
			delta = -delta;
248
		Node n;
249
		for (int i = 0; i < graph.nodes.size(); i++) {
250
			n = graph.nodes.getNode(i);
251
			if (subtreeContains(tail, n))
252
				n.rank += delta;
253
		}
254
	}
255

    
256
	int updateMinMax(Node root, int count) {
257
		setTreeMin(root, count);
258
		EdgeList edges = getSpanningTreeChildren(root);
259
		for (int i = 0; i < edges.size(); i++)
260
			count = updateMinMax(getTreeTail(edges.getEdge(i)), count);
261
		setTreeMax(root, count);
262
		return count + 1;
263
	}
264

    
265
	void updateSubgraph(Node root) {
266
		Edge flip = getParentEdge(root);
267
		if (flip != null) {
268
			Node rootParent = getTreeParent(root);
269
			getSpanningTreeChildren(rootParent).remove(flip);
270
			updateSubgraph(rootParent);
271
			setParentEdge(root, null);
272
			setParentEdge(rootParent, flip);
273
			repairCutValues(flip);
274
			getSpanningTreeChildren(root).add(flip);
275
		}
276
	}
277

    
278
	public void visit(DirectedGraph graph) {
279
		this.graph = graph;
280
		initCutValues();
281
		networkSimplexLoop();
282
		if (graph.forestRoot == null)
283
			graph.nodes.normalizeRanks();
284
		else
285
			normalizeForest();
286
	}
287

    
288
	private void normalizeForest() {
289
		NodeList tree = new NodeList();
290
		graph.nodes.resetFlags();
291
		graph.forestRoot.flag = true;
292
		EdgeList rootEdges = graph.forestRoot.outgoing;
293
		Stack stack = new Stack();
294
		for (int i = 0; i < rootEdges.size(); i++) {
295
			Node node = rootEdges.getEdge(i).target;
296
			node.flag = true;
297
			stack.push(node);
298
			while (!stack.isEmpty()) {
299
				node = (Node) stack.pop();
300
				tree.add(node);
301
				Iterator neighbors = node.iteratorNeighbors();
302
				while (neighbors.hasNext()) {
303
					Node neighbor = (Node) neighbors.next();
304
					if (!neighbor.flag) {
305
						neighbor.flag = true;
306
						stack.push(neighbor);
307
					}
308
				}
309
			}
310
			tree.normalizeRanks();
311
			tree.clear();
312
		}
313
	}
314

    
315
}
(32-32/49)