Skip to content

Commit

Permalink
Merge pull request #228 from rustedgrail/master
Browse files Browse the repository at this point in the history
pass1 and pass2 no longer cause a stack overflow for large graphs
  • Loading branch information
cpettitt committed Feb 6, 2018
2 parents 9596cec + ee72d87 commit c6cacf7
Showing 1 changed file with 37 additions and 26 deletions.
63 changes: 37 additions & 26 deletions lib/position/bk.js
Expand Up @@ -211,36 +211,47 @@ function horizontalCompaction(g, layering, root, align, reverseSep) {
// coordinates. The second sweep removes unused space by moving blocks to the
// greatest coordinates without violating separation.
var xs = {},
blockG = buildBlockGraph(g, layering, root, reverseSep);

// First pass, assign smallest coordinates via DFS
var visited = {};
function pass1(v) {
if (!_.has(visited, v)) {
visited[v] = true;
xs[v] = _.reduce(blockG.inEdges(v), function(max, e) {
pass1(e.v);
return Math.max(max, xs[e.v] + blockG.edge(e));
}, 0);
blockG = buildBlockGraph(g, layering, root, reverseSep),
borderType = reverseSep ? "borderLeft" : "borderRight";

function iterate(setXsFunc, nextNodesFunc) {
var stack = blockG.nodes();
var elem = stack.pop();
var visited = {};
while (elem) {
if (visited[elem]) {
setXsFunc(elem);
} else {
visited[elem] = true;
stack.push(elem);
stack = stack.concat(nextNodesFunc(elem));
}

elem = stack.pop();
}
}
_.forEach(blockG.nodes(), pass1);

var borderType = reverseSep ? "borderLeft" : "borderRight";
function pass2(v) {
if (visited[v] !== 2) {
visited[v]++;
var node = g.node(v);
var min = _.reduce(blockG.outEdges(v), function(min, e) {
pass2(e.w);
return Math.min(min, xs[e.w] - blockG.edge(e));
}, Number.POSITIVE_INFINITY);
if (min !== Number.POSITIVE_INFINITY && node.borderType !== borderType) {
xs[v] = Math.max(xs[v], min);
}

// First pass, assign smallest coordinates
function pass1(elem) {
xs[elem] = blockG.inEdges(elem).reduce(function(acc, e) {
return Math.max(acc, xs[e.v] + blockG.edge(e));
}, 0);
}

// Second pass, assign greatest coordinates
function pass2(elem) {
var min = blockG.outEdges(elem).reduce(function(acc, e) {
return Math.min(acc, xs[e.w] - blockG.edge(e));
}, Number.POSITIVE_INFINITY);

var node = g.node(elem);
if (min !== Number.POSITIVE_INFINITY && node.borderType !== borderType) {
xs[elem] = Math.max(xs[elem], min);
}
}
_.forEach(blockG.nodes(), pass2);

iterate(pass1, _.bind(blockG.predecessors, blockG));
iterate(pass2, _.bind(blockG.successors, blockG));

// Assign x coordinates to all nodes
_.forEach(align, function(v) {
Expand Down

0 comments on commit c6cacf7

Please sign in to comment.