You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
4.3 KiB
138 lines
4.3 KiB
/*
|
|
* Initializes ranks for the input graph using the longest path algorithm. This
|
|
* algorithm scales well and is fast in practice, it yields rather poor
|
|
* solutions. Nodes are pushed to the lowest layer possible, leaving the bottom
|
|
* ranks wide and leaving edges longer than necessary. However, due to its
|
|
* speed, this algorithm is good for getting an initial ranking that can be fed
|
|
* into other algorithms.
|
|
*
|
|
* This algorithm does not normalize layers because it will be used by other
|
|
* algorithms in most cases. If using this algorithm directly, be sure to
|
|
* run normalize at the end.
|
|
*
|
|
* Pre-conditions:
|
|
*
|
|
* 1. Input graph is a DAG.
|
|
* 2. Input graph node labels can be assigned properties.
|
|
*
|
|
* Post-conditions:
|
|
*
|
|
* 1. Each node will be assign an (unnormalized) "rank" property.
|
|
*/
|
|
const longestPath = (g) => {
|
|
const visited = {};
|
|
const dfs = (v) => {
|
|
var _a;
|
|
const label = g.getNode(v);
|
|
if (!label)
|
|
return 0;
|
|
if (visited[v]) {
|
|
return label.data.rank;
|
|
}
|
|
visited[v] = true;
|
|
let rank;
|
|
(_a = g.getRelatedEdges(v, 'out')) === null || _a === void 0 ? void 0 : _a.forEach((e) => {
|
|
const wRank = dfs(e.target);
|
|
const minLen = e.data.minlen;
|
|
const r = wRank - minLen;
|
|
if (r) {
|
|
if (rank === undefined || r < rank) {
|
|
rank = r;
|
|
}
|
|
}
|
|
});
|
|
if (!rank) {
|
|
rank = 0;
|
|
}
|
|
label.data.rank = rank;
|
|
return rank;
|
|
};
|
|
g.getAllNodes()
|
|
.filter((n) => g.getRelatedEdges(n.id, 'in').length === 0)
|
|
.forEach((source) => dfs(source.id));
|
|
};
|
|
const longestPathWithLayer = (g) => {
|
|
// 用longest path,找出最深的点
|
|
const visited = {};
|
|
let minRank;
|
|
const dfs = (v) => {
|
|
var _a;
|
|
const label = g.getNode(v);
|
|
if (!label)
|
|
return 0;
|
|
if (visited[v]) {
|
|
return label.data.rank;
|
|
}
|
|
visited[v] = true;
|
|
let rank;
|
|
(_a = g.getRelatedEdges(v, 'out')) === null || _a === void 0 ? void 0 : _a.forEach((e) => {
|
|
const wRank = dfs(e.target);
|
|
const minLen = e.data.minlen;
|
|
const r = wRank - minLen;
|
|
if (r) {
|
|
if (rank === undefined || r < rank) {
|
|
rank = r;
|
|
}
|
|
}
|
|
});
|
|
if (!rank) {
|
|
rank = 0;
|
|
}
|
|
if (minRank === undefined || rank < minRank) {
|
|
minRank = rank;
|
|
}
|
|
label.data.rank = rank;
|
|
return rank;
|
|
};
|
|
g.getAllNodes()
|
|
.filter((n) => g.getRelatedEdges(n.id, 'in').length === 0)
|
|
.forEach((source) => {
|
|
if (source)
|
|
dfs(source.id);
|
|
});
|
|
if (minRank === undefined) {
|
|
minRank = 0;
|
|
}
|
|
// minRank += 1; // NOTE: 最小的层级是dummy root,+1
|
|
// forward一遍,赋值层级
|
|
const forwardVisited = {};
|
|
const dfsForward = (v, nextRank) => {
|
|
var _a;
|
|
const label = g.getNode(v);
|
|
const currRank = !isNaN(label.data.layer) ? label.data.layer : nextRank;
|
|
// 没有指定,取最大值
|
|
if (label.data.rank === undefined || label.data.rank < currRank) {
|
|
label.data.rank = currRank;
|
|
}
|
|
if (forwardVisited[v])
|
|
return;
|
|
forwardVisited[v] = true;
|
|
// DFS遍历子节点
|
|
(_a = g.getRelatedEdges(v, 'out')) === null || _a === void 0 ? void 0 : _a.forEach((e) => {
|
|
dfsForward(e.target, currRank + e.data.minlen);
|
|
});
|
|
};
|
|
// 指定层级的,更新下游
|
|
g.getAllNodes().forEach((n) => {
|
|
const label = n.data;
|
|
if (!label)
|
|
return;
|
|
if (!isNaN(label.layer)) {
|
|
dfsForward(n.id, label.layer); // 默认的dummy root所在层的rank是-1
|
|
}
|
|
else {
|
|
label.rank -= minRank;
|
|
}
|
|
});
|
|
};
|
|
/*
|
|
* Returns the amount of slack for the given edge. The slack is defined as the
|
|
* difference between the length of the edge and its minimum length.
|
|
*/
|
|
const slack = (g, e) => {
|
|
return (g.getNode(e.target).data.rank -
|
|
g.getNode(e.source).data.rank -
|
|
e.data.minlen);
|
|
};
|
|
export { longestPath, longestPathWithLayer, slack };
|
|
//# sourceMappingURL=util.js.map
|