Mercurial > projects > dwt-addons
view 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 |
line wrap: on
line source
/******************************************************************************* * 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.TightSpanningTreeSolver; import dwt.dwthelper.utils; import dwtx.draw2d.graph.SpanningTreeVisitor; import dwtx.draw2d.graph.DirectedGraph; import dwtx.draw2d.graph.Edge; import dwtx.draw2d.graph.EdgeList; import dwtx.draw2d.graph.Node; import dwtx.draw2d.graph.NodeList; /** * Finds a tight spanning tree from the graphs edges which induce a valid rank assignment. * This process requires that the nodes be initially given a feasible ranking. * @author Randy Hudson * @since 2.1.2 */ class TightSpanningTreeSolver : SpanningTreeVisitor { protected DirectedGraph graph; protected CandidateList candidates; static final class CandidateList { private Edge[] edges; private int size_; public this(){ edges = new Edge[10]; } public void add(Edge edge) { if (size_ is edges.length - 1) { Edge newEdges[] = new Edge[edges.length * 2]; System.arraycopy(edges, 0, newEdges, 0, edges.length); edges = newEdges; } edges[size_++] = edge; } public Edge getEdge(int index) { return edges[index]; } public void remove(Edge edge) { for (int i = 0; i < size_; i++) { if (edges[i] is edge) { edges[i] = edges[size_ - 1]; size_--; return; } } throw new RuntimeException("Remove called on invalid Edge"); //$NON-NLS-1$ } public int size() { return size_; } } protected NodeList members; public this(){ candidates = new CandidateList(); members = new NodeList(); } public void visit(DirectedGraph graph) { this.graph = graph; init(); solve(); } Node addEdge(Edge edge) { int delta = edge.getSlack(); edge.tree = true; Node node; if (edge.target.flag) { delta = -delta; node = edge.source; setParentEdge(node, edge); getSpanningTreeChildren(edge.target).add(edge); } else { node = edge.target; setParentEdge(node, edge); getSpanningTreeChildren(edge.source).add(edge); } members.adjustRank(delta); addNode(node); return node; } private bool isNodeReachable(Node node) { return node.flag; } private void setNodeReachable(Node node) { node.flag = true; } private bool isCandidate(Edge e) { return e.flag; } private void setCandidate(Edge e) { e.flag = true; } void addNode(Node node) { setNodeReachable(node); EdgeList list = node.incoming; Edge e; for (int i = 0; i < list.size(); i++) { e = list.getEdge(i); if (!isNodeReachable(e.source)) { if (!isCandidate(e)) { setCandidate(e); candidates.add(e); } } else candidates.remove(e); } list = node.outgoing; for (int i = 0; i < list.size(); i++) { e = list.getEdge(i); if (!isNodeReachable(e.target)) { if (!isCandidate(e)) { setCandidate(e); candidates.add(e); } } else candidates.remove(e); } members.add(node); } void init() { graph.edges.resetFlags(true); graph.nodes.resetFlags(); for (int i = 0; i < graph.nodes.size(); i++) { Node node = cast(Node)graph.nodes.get(i); node.workingData[0] = new EdgeList(); } } protected void solve() { Node root = graph.nodes.getNode(0); setParentEdge(root, null); addNode(root); while (members.size() < graph.nodes.size()) { if (candidates.size() is 0) throw new RuntimeException("graph is not fully connected");//$NON-NLS-1$ int minSlack = Integer.MAX_VALUE, slack; Edge minEdge = null, edge; for (int i = 0; i < candidates.size() && minSlack > 0; i++) { edge = candidates.getEdge(i); slack = edge.getSlack(); if (slack < minSlack) { minSlack = slack; minEdge = edge; } } addEdge(minEdge); } graph.nodes.normalizeRanks(); } }