view org.eclipse.draw2d/src/org/eclipse/draw2d/graph/RankAssignmentSolver.d @ 16:dbfb303e8fb0

first complete successful compile (win-only)
author Frank Benoit <benoit@tionex.de>
date Wed, 18 Mar 2009 08:56:47 +0100
parents bc29606a740c
children
line wrap: on
line source

/*******************************************************************************
 * Copyright (c) 2003, 2007 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 org.eclipse.draw2d.graph.RankAssignmentSolver;

import java.lang.all;
import java.util.Stack;
import java.util.Iterator;
import org.eclipse.draw2d.graph.SpanningTreeVisitor;
import org.eclipse.draw2d.graph.EdgeList;
import org.eclipse.draw2d.graph.Edge;
import org.eclipse.draw2d.graph.Node;
import org.eclipse.draw2d.graph.DirectedGraph;
import org.eclipse.draw2d.graph.NodeList;

/**
 * Assigns the final rank assignment for a DirectedGraph with an initial feasible
 * spanning tree.
 * @author Randy Hudson
 * @since 2.1.2
 */
class RankAssignmentSolver : SpanningTreeVisitor {

DirectedGraph graph;
EdgeList spanningTree;
bool searchDirection;

int depthFirstCutValue(Edge edge, int count) {
    Node n = getTreeTail(edge);
    setTreeMin(n, count);
    int cutvalue = 0;
    int multiplier = (edge.target is n) ? 1 : -1;
    EdgeList list;

    list = n.outgoing;
    Edge e;
    for (int i = 0; i < list.size(); i++) {
        e = list.getEdge(i);
        if (e.tree && e !is edge) {
            count = depthFirstCutValue(e, count);
            cutvalue += (e.cut - e.weight) * multiplier;
        } else {
            cutvalue -= e.weight * multiplier;
        }
    }
    list = n.incoming;
    for (int i = 0; i < list.size(); i++) {
        e = list.getEdge(i);
        if (e.tree && e !is edge) {
            count = depthFirstCutValue(e, count);
            cutvalue -= (e.cut - e.weight) * multiplier;
        } else {
            cutvalue += e.weight * multiplier;
        }
    }

    edge.cut = cutvalue;
    if (cutvalue < 0)
        spanningTree.add(edge);
    setTreeMax(n, count);
    return count + 1;
}

/**
 * returns the Edge which should be entered.
 * @param branch
 * @return Edge
 */
Edge enter(Node branch) {
    Node n;
    Edge result = null;
    int minSlack = Integer.MAX_VALUE;
    bool incoming = getParentEdge(branch).target !is branch;
//  searchDirection = !searchDirection;
    for (int i = 0; i < graph.nodes.size(); i++) {
        if (searchDirection)
            n = graph.nodes.getNode(i);
        else
            n = graph.nodes.getNode(graph.nodes.size() - 1 - i);
        if (subtreeContains(branch, n)) {
            EdgeList edges;
            if (incoming)
                edges = n.incoming;
            else
                edges = n.outgoing;
            for (int j = 0; j < edges.size(); j++) {
                Edge e = edges.getEdge(j);
                if (!subtreeContains(branch, e.opposite(n))
                  && !e.tree
                  && e.getSlack() < minSlack) {
                    result = e;
                    minSlack = e.getSlack();
                }
            }
        }
    }
    return result;
}

int getTreeMax(Node n) {
    return n.workingInts[1];
}

int getTreeMin(Node n) {
    return n.workingInts[0];
}

void initCutValues() {
    Node root = graph.nodes.getNode(0);
    spanningTree = new EdgeList();
    Edge e;
    setTreeMin(root, 1);
    setTreeMax(root, 1);

    for (int i = 0; i < root.outgoing.size(); i++) {
        e = root.outgoing.getEdge(i);
        if (!getSpanningTreeChildren(root).contains(e))
            continue;
        setTreeMax(root, depthFirstCutValue(e, getTreeMax(root)));
    }
    for (int i = 0; i < root.incoming.size(); i++) {
        e = root.incoming.getEdge(i);
        if (!getSpanningTreeChildren(root).contains(e))
            continue;
        setTreeMax(root, depthFirstCutValue(e, getTreeMax(root)));
    }
}

Edge leave() {
    Edge result = null;
    Edge e;
    int minCut = 0;
    int weight = -1;
    for (int i = 0; i < spanningTree.size(); i++) {
        e = spanningTree.getEdge(i);
        if (e.cut < minCut) {
            result = e;
            minCut = result.cut;
            weight = result.weight;
        } else if (e.cut is minCut && e.weight > weight) {
            result = e;
            weight = result.weight;
        }
    }
    return result;
}

void networkSimplexLoop() {
    Edge leave_, enter_;
    int count = 0;
    while ((leave_ = leave()) !is null && count < 900) {

        count++;

        Node leaveTail = getTreeTail(leave_);
        Node leaveHead = getTreeHead(leave_);

        enter_ = enter(leaveTail);
        if (enter_ is null)
            break;

        //Break the "leave" edge from the spanning tree
        getSpanningTreeChildren(leaveHead).remove(leave_);
        setParentEdge(leaveTail, null);
        leave_.tree = false;
        spanningTree.remove(leave_);

        Node enterTail = enter_.source;
        if (!subtreeContains(leaveTail, enterTail))
            //Oops, wrong end of the edge
            enterTail = enter_.target;
        Node enterHead = enter_.opposite(enterTail);

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

        //Add "enter" edge to the spanning tree
        getSpanningTreeChildren(enterHead).add(enter_);
        setParentEdge(enterTail, enter_);
        enter_.tree = true;

        repairCutValues(enter_);

        Node commonAncestor = enterHead;

        while (!subtreeContains(commonAncestor, leaveHead)) {
            repairCutValues(getParentEdge(commonAncestor));
            commonAncestor = getTreeParent(commonAncestor);
        }
        while (leaveHead !is commonAncestor) {
            repairCutValues(getParentEdge(leaveHead));
            leaveHead = getTreeParent(leaveHead);
        }
        updateMinMax(commonAncestor, getTreeMin(commonAncestor));
        tightenEdge(enter_);
    }
}

void repairCutValues(Edge edge) {
    spanningTree.remove(edge);
    Node n = getTreeTail(edge);
    int cutvalue = 0;
    int multiplier = (edge.target is n) ? 1 : -1;
    EdgeList list;

    list = n.outgoing;
    Edge e;
    for (int i = 0; i < list.size(); i++) {
        e = list.getEdge(i);
        if (e.tree && e !is edge)
            cutvalue += (e.cut - e.weight) * multiplier;
        else
            cutvalue -= e.weight * multiplier;
    }
    list = n.incoming;
    for (int i = 0; i < list.size(); i++) {
        e = list.getEdge(i);
        if (e.tree && e !is edge)
            cutvalue -= (e.cut - e.weight) * multiplier;
        else
            cutvalue += e.weight * multiplier;
    }

    edge.cut = cutvalue;
    if (cutvalue < 0)
        spanningTree.add(edge);
}

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

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

bool subtreeContains(Node parent, Node child) {
    return parent.workingInts[0] <= child.workingInts[1]
      && child.workingInts[1] <= parent.workingInts[1];
}

void tightenEdge(Edge edge) {
    Node tail = getTreeTail(edge);
    int delta = edge.getSlack();
    if (tail is edge.target)
        delta = -delta;
    Node n;
    for (int i = 0; i < graph.nodes.size(); i++) {
        n = graph.nodes.getNode(i);
        if (subtreeContains(tail, n))
            n.rank += delta;
    }
}

int updateMinMax(Node root, int count) {
    setTreeMin(root, count);
    EdgeList edges = getSpanningTreeChildren(root);
    for (int i = 0; i < edges.size(); i++)
        count = updateMinMax(getTreeTail(edges.getEdge(i)), count);
    setTreeMax(root, count);
    return count + 1;
}

void updateSubgraph(Node root) {
    Edge flip = getParentEdge(root);
    if (flip !is null) {
        Node rootParent = getTreeParent(root);
        getSpanningTreeChildren(rootParent).remove(flip);
        updateSubgraph(rootParent);
        setParentEdge(root, null);
        setParentEdge(rootParent, flip);
        repairCutValues(flip);
        getSpanningTreeChildren(root).add(flip);
    }
}

public void visit(DirectedGraph graph) {
    this.graph = graph;
    initCutValues();
    networkSimplexLoop();
    if (graph.forestRoot is null)
        graph.nodes.normalizeRanks();
    else
        normalizeForest();
}

private void normalizeForest() {
    NodeList tree = new NodeList();
    graph.nodes.resetFlags();
    graph.forestRoot.flag = true;
    EdgeList rootEdges = graph.forestRoot.outgoing;
    Stack stack = new Stack();
    for (int i = 0; i < rootEdges.size(); i++) {
        Node node = rootEdges.getEdge(i).target;
        node.flag = true;
        stack.push(node);
        while (!stack.isEmpty()) {
            node = cast(Node) stack.pop();
            tree.add(node);
            Iterator neighbors = node.iteratorNeighbors();
            while (neighbors.hasNext()) {
                Node neighbor = cast(Node) neighbors.next();
                if (!neighbor.flag) {
                    neighbor.flag = true;
                    stack.push(neighbor);
                }
            }
        }
        tree.normalizeRanks();
        tree.clear();
    }
}

}