blob: cdc1fc3e461403925d2b7a26611761c4f887aacb [file] [log] [blame]
library graphlib.layout.parent_dummy_chains;
import "dart:math" as Math;
import "../graph.dart" show Graph, Edge;
parentDummyChains(Graph g) {
var postorderNums = postorder(g);
g.graph()["dummyChains"].forEach((v) {
Map node = g.node(v);
Edge edgeObj = node["edgeObj"];
Map pathData = findPath(g, postorderNums, edgeObj.v, edgeObj.w);
var path = pathData["path"],
lca = pathData["lca"],
pathIdx = 0,
pathV = path[pathIdx],
ascending = true;
while (v != edgeObj.w) {
node = g.node(v);
if (ascending) {
while ((pathV = path[pathIdx]) != lca &&
g.node(pathV)["maxRank"] < node["rank"]) {
pathIdx++;
}
if (pathV == lca) {
ascending = false;
}
}
if (!ascending) {
while (pathIdx < path.length - 1 &&
g.node(pathV = path[pathIdx + 1]).minRank <= node["rank"]) {
pathIdx++;
}
pathV = path[pathIdx];
}
g.setParent(v, pathV);
v = g.successors(v).first;
}
});
}
/// Find a path from v to w through the lowest common ancestor (LCA). Return the
/// full path and the LCA.
Map findPath(Graph g, postorderNums, v, w) {
var vPath = [],
wPath = [],
low = Math.min(postorderNums[v]["low"], postorderNums[w]["low"]),
lim = Math.max(postorderNums[v]["lim"], postorderNums[w]["lim"]),
parent,
lca;
// Traverse up from v to find the LCA
parent = v;
do {
parent = g.parent(parent);
vPath.add(parent);
} while (parent &&
(postorderNums[parent]["low"] > low || lim > postorderNums[parent]["lim"]));
lca = parent;
// Traverse from w to LCA
parent = w;
while ((parent = g.parent(parent)) != lca) {
wPath.add(parent);
}
return { "path": vPath.concat(wPath.reverse()), "lca": lca };
}
Map postorder(Graph g) {
var result = {},
lim = 0;
dfs(v) {
var low = lim;
g.children(v).forEach(dfs);
result[v] = { "low": low, "lim": lim++ };
}
g.children().forEach(dfs);
return result;
}