@dagrejs/dagre 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -7
- package/dist/dagre.js +443 -445
- package/dist/dagre.min.js +52 -52
- package/index.d.ts +8 -1
- package/lib/acyclic.js +13 -13
- package/lib/add-border-segments.js +7 -7
- package/lib/coordinate-system.js +8 -8
- package/lib/data/list.js +34 -32
- package/lib/debug.js +9 -11
- package/lib/greedy-fas.js +29 -29
- package/lib/layout.js +96 -96
- package/lib/nesting-graph.js +20 -22
- package/lib/normalize.js +13 -13
- package/lib/order/add-subgraph-constraints.js +3 -3
- package/lib/order/barycenter.js +3 -3
- package/lib/order/build-layer-graph.js +8 -8
- package/lib/order/cross-count.js +11 -11
- package/lib/order/index.js +15 -15
- package/lib/order/init-order.js +7 -7
- package/lib/order/resolve-conflicts.js +12 -12
- package/lib/order/sort-subgraph.js +16 -16
- package/lib/order/sort.js +7 -7
- package/lib/parent-dummy-chains.js +19 -19
- package/lib/position/bk.js +67 -67
- package/lib/position/index.js +6 -6
- package/lib/rank/feasible-tree.js +1 -1
- package/lib/rank/network-simplex.js +4 -4
- package/lib/util.js +32 -32
- package/lib/version.js +1 -1
- package/package.json +1 -1
package/lib/nesting-graph.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
let util = require("./util");
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
|
-
run
|
|
5
|
-
cleanup
|
|
4
|
+
run,
|
|
5
|
+
cleanup,
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
/*
|
|
9
9
|
* A nesting graph creates dummy nodes for the tops and bottoms of subgraphs,
|
|
10
10
|
* adds appropriate edges to ensure that all cluster nodes are placed between
|
|
11
|
-
* these
|
|
11
|
+
* these boundaries, and ensures that the graph is connected.
|
|
12
12
|
*
|
|
13
13
|
* In addition we ensure, through the use of the minlen property, that nodes
|
|
14
14
|
* and subgraph border nodes to not end up on the same rank.
|
|
@@ -29,10 +29,10 @@ module.exports = {
|
|
|
29
29
|
* Graphs."
|
|
30
30
|
*/
|
|
31
31
|
function run(g) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
let root = util.addDummyNode(g, "root", {}, "_root");
|
|
33
|
+
let depths = treeDepths(g);
|
|
34
|
+
let height = Math.max(...Object.values(depths)) - 1; // Note: depths is an Object not an array
|
|
35
|
+
let nodeSep = 2 * height + 1;
|
|
36
36
|
|
|
37
37
|
g.graph().nestingRoot = root;
|
|
38
38
|
|
|
@@ -40,12 +40,10 @@ function run(g) {
|
|
|
40
40
|
g.edges().forEach(e => g.edge(e).minlen *= nodeSep);
|
|
41
41
|
|
|
42
42
|
// Calculate a weight that is sufficient to keep subgraphs vertically compact
|
|
43
|
-
|
|
43
|
+
let weight = sumWeights(g) + 1;
|
|
44
44
|
|
|
45
45
|
// Create border nodes and link them up
|
|
46
|
-
g.children().forEach(
|
|
47
|
-
dfs(g, root, nodeSep, weight, height, depths, child);
|
|
48
|
-
});
|
|
46
|
+
g.children().forEach(child => dfs(g, root, nodeSep, weight, height, depths, child));
|
|
49
47
|
|
|
50
48
|
// Save the multiplier for node layers for later removal of empty border
|
|
51
49
|
// layers.
|
|
@@ -53,7 +51,7 @@ function run(g) {
|
|
|
53
51
|
}
|
|
54
52
|
|
|
55
53
|
function dfs(g, root, nodeSep, weight, height, depths, v) {
|
|
56
|
-
|
|
54
|
+
let children = g.children(v);
|
|
57
55
|
if (!children.length) {
|
|
58
56
|
if (v !== root) {
|
|
59
57
|
g.setEdge(root, v, { weight: 0, minlen: nodeSep });
|
|
@@ -61,23 +59,23 @@ function dfs(g, root, nodeSep, weight, height, depths, v) {
|
|
|
61
59
|
return;
|
|
62
60
|
}
|
|
63
61
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
let top = util.addBorderNode(g, "_bt");
|
|
63
|
+
let bottom = util.addBorderNode(g, "_bb");
|
|
64
|
+
let label = g.node(v);
|
|
67
65
|
|
|
68
66
|
g.setParent(top, v);
|
|
69
67
|
label.borderTop = top;
|
|
70
68
|
g.setParent(bottom, v);
|
|
71
69
|
label.borderBottom = bottom;
|
|
72
70
|
|
|
73
|
-
children.forEach(
|
|
71
|
+
children.forEach(child => {
|
|
74
72
|
dfs(g, root, nodeSep, weight, height, depths, child);
|
|
75
73
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
74
|
+
let childNode = g.node(child);
|
|
75
|
+
let childTop = childNode.borderTop ? childNode.borderTop : child;
|
|
76
|
+
let childBottom = childNode.borderBottom ? childNode.borderBottom : child;
|
|
77
|
+
let thisWeight = childNode.borderTop ? weight : 2 * weight;
|
|
78
|
+
let minlen = childTop !== childBottom ? 1 : height - depths[v] + 1;
|
|
81
79
|
|
|
82
80
|
g.setEdge(top, childTop, {
|
|
83
81
|
weight: thisWeight,
|
package/lib/normalize.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
let util = require("./util");
|
|
4
4
|
|
|
5
5
|
module.exports = {
|
|
6
6
|
run: run,
|
|
@@ -29,19 +29,19 @@ function run(g) {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
function normalizeEdge(g, e) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
let v = e.v;
|
|
33
|
+
let vRank = g.node(v).rank;
|
|
34
|
+
let w = e.w;
|
|
35
|
+
let wRank = g.node(w).rank;
|
|
36
|
+
let name = e.name;
|
|
37
|
+
let edgeLabel = g.edge(e);
|
|
38
|
+
let labelRank = edgeLabel.labelRank;
|
|
39
39
|
|
|
40
40
|
if (wRank === vRank + 1) return;
|
|
41
41
|
|
|
42
42
|
g.removeEdge(e);
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
let dummy, attrs, i;
|
|
45
45
|
for (i = 0, ++vRank; vRank < wRank; ++i, ++vRank) {
|
|
46
46
|
edgeLabel.points = [];
|
|
47
47
|
attrs = {
|
|
@@ -67,10 +67,10 @@ function normalizeEdge(g, e) {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
function undo(g) {
|
|
70
|
-
g.graph().dummyChains.forEach(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
g.graph().dummyChains.forEach(v => {
|
|
71
|
+
let node = g.node(v);
|
|
72
|
+
let origLabel = node.edgeLabel;
|
|
73
|
+
let w;
|
|
74
74
|
g.setEdge(node.edgeObj, origLabel);
|
|
75
75
|
while (node.dummy) {
|
|
76
76
|
w = g.successors(v)[0];
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
module.exports = addSubgraphConstraints;
|
|
2
2
|
|
|
3
3
|
function addSubgraphConstraints(g, cg, vs) {
|
|
4
|
-
|
|
4
|
+
let prev = {},
|
|
5
5
|
rootPrev;
|
|
6
6
|
|
|
7
|
-
vs.forEach(
|
|
8
|
-
|
|
7
|
+
vs.forEach(v => {
|
|
8
|
+
let child = g.parent(v),
|
|
9
9
|
parent,
|
|
10
10
|
prevChild;
|
|
11
11
|
while (child) {
|
package/lib/order/barycenter.js
CHANGED
|
@@ -2,12 +2,12 @@ module.exports = barycenter;
|
|
|
2
2
|
|
|
3
3
|
function barycenter(g, movable = []) {
|
|
4
4
|
return movable.map(v => {
|
|
5
|
-
|
|
5
|
+
let inV = g.inEdges(v);
|
|
6
6
|
if (!inV.length) {
|
|
7
7
|
return { v: v };
|
|
8
8
|
} else {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
let result = inV.reduce((acc, e) => {
|
|
10
|
+
let edge = g.edge(e),
|
|
11
11
|
nodeU = g.node(e.v);
|
|
12
12
|
return {
|
|
13
13
|
sum: acc.sum + (edge.weight * nodeU.order),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
let Graph = require("@dagrejs/graphlib").Graph;
|
|
2
|
+
let util = require("../util");
|
|
3
3
|
|
|
4
4
|
module.exports = buildLayerGraph;
|
|
5
5
|
|
|
@@ -34,12 +34,12 @@ module.exports = buildLayerGraph;
|
|
|
34
34
|
* graph is not a multi-graph.
|
|
35
35
|
*/
|
|
36
36
|
function buildLayerGraph(g, rank, relationship) {
|
|
37
|
-
|
|
37
|
+
let root = createRootNode(g),
|
|
38
38
|
result = new Graph({ compound: true }).setGraph({ root: root })
|
|
39
|
-
.setDefaultNodeLabel(
|
|
39
|
+
.setDefaultNodeLabel(v => g.node(v));
|
|
40
40
|
|
|
41
|
-
g.nodes().forEach(
|
|
42
|
-
|
|
41
|
+
g.nodes().forEach(v => {
|
|
42
|
+
let node = g.node(v),
|
|
43
43
|
parent = g.parent(v);
|
|
44
44
|
|
|
45
45
|
if (node.rank === rank || node.minRank <= rank && rank <= node.maxRank) {
|
|
@@ -47,8 +47,8 @@ function buildLayerGraph(g, rank, relationship) {
|
|
|
47
47
|
result.setParent(v, parent || root);
|
|
48
48
|
|
|
49
49
|
// This assumes we have only short edges!
|
|
50
|
-
g[relationship](v).forEach(
|
|
51
|
-
|
|
50
|
+
g[relationship](v).forEach(e => {
|
|
51
|
+
let u = e.v === v ? e.w : e.v,
|
|
52
52
|
edge = result.edge(u, v),
|
|
53
53
|
weight = edge !== undefined ? edge.weight : 0;
|
|
54
54
|
result.setEdge(u, v, { weight: g.edge(e).weight + weight });
|
package/lib/order/cross-count.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
let zipObject = require("../util").zipObject;
|
|
4
4
|
|
|
5
5
|
module.exports = crossCount;
|
|
6
6
|
|
|
@@ -21,8 +21,8 @@ module.exports = crossCount;
|
|
|
21
21
|
* This algorithm is derived from Barth, et al., "Bilayer Cross Counting."
|
|
22
22
|
*/
|
|
23
23
|
function crossCount(g, layering) {
|
|
24
|
-
|
|
25
|
-
for (
|
|
24
|
+
let cc = 0;
|
|
25
|
+
for (let i = 1; i < layering.length; ++i) {
|
|
26
26
|
cc += twoLayerCrossCount(g, layering[i-1], layering[i]);
|
|
27
27
|
}
|
|
28
28
|
return cc;
|
|
@@ -32,26 +32,26 @@ function twoLayerCrossCount(g, northLayer, southLayer) {
|
|
|
32
32
|
// Sort all of the edges between the north and south layers by their position
|
|
33
33
|
// in the north layer and then the south. Map these edges to the position of
|
|
34
34
|
// their head in the south layer.
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
let southPos = zipObject(southLayer, southLayer.map((v, i) => i));
|
|
36
|
+
let southEntries = northLayer.flatMap(v => {
|
|
37
37
|
return g.outEdges(v).map(e => {
|
|
38
38
|
return { pos: southPos[e.w], weight: g.edge(e).weight };
|
|
39
39
|
}).sort((a, b) => a.pos - b.pos);
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
// Build the accumulator tree
|
|
43
|
-
|
|
43
|
+
let firstIndex = 1;
|
|
44
44
|
while (firstIndex < southLayer.length) firstIndex <<= 1;
|
|
45
|
-
|
|
45
|
+
let treeSize = 2 * firstIndex - 1;
|
|
46
46
|
firstIndex -= 1;
|
|
47
|
-
|
|
47
|
+
let tree = new Array(treeSize).fill(0);
|
|
48
48
|
|
|
49
49
|
// Calculate the weighted crossings
|
|
50
|
-
|
|
50
|
+
let cc = 0;
|
|
51
51
|
southEntries.forEach(entry => {
|
|
52
|
-
|
|
52
|
+
let index = entry.pos + firstIndex;
|
|
53
53
|
tree[index] += entry.weight;
|
|
54
|
-
|
|
54
|
+
let weightSum = 0;
|
|
55
55
|
while (index > 0) {
|
|
56
56
|
if (index % 2) {
|
|
57
57
|
weightSum += tree[index + 1];
|
package/lib/order/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
let initOrder = require("./init-order");
|
|
4
|
+
let crossCount = require("./cross-count");
|
|
5
|
+
let sortSubgraph = require("./sort-subgraph");
|
|
6
|
+
let buildLayerGraph = require("./build-layer-graph");
|
|
7
|
+
let addSubgraphConstraints = require("./add-subgraph-constraints");
|
|
8
|
+
let Graph = require("@dagrejs/graphlib").Graph;
|
|
9
|
+
let util = require("../util");
|
|
10
10
|
|
|
11
11
|
module.exports = order;
|
|
12
12
|
|
|
@@ -26,21 +26,21 @@ module.exports = order;
|
|
|
26
26
|
* algorithm.
|
|
27
27
|
*/
|
|
28
28
|
function order(g) {
|
|
29
|
-
|
|
29
|
+
let maxRank = util.maxRank(g),
|
|
30
30
|
downLayerGraphs = buildLayerGraphs(g, util.range(1, maxRank + 1), "inEdges"),
|
|
31
31
|
upLayerGraphs = buildLayerGraphs(g, util.range(maxRank - 1, -1, -1), "outEdges");
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
let layering = initOrder(g);
|
|
34
34
|
assignOrder(g, layering);
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
let bestCC = Number.POSITIVE_INFINITY,
|
|
37
37
|
best;
|
|
38
38
|
|
|
39
|
-
for (
|
|
39
|
+
for (let i = 0, lastBest = 0; lastBest < 4; ++i, ++lastBest) {
|
|
40
40
|
sweepLayerGraphs(i % 2 ? downLayerGraphs : upLayerGraphs, i % 4 >= 2);
|
|
41
41
|
|
|
42
42
|
layering = util.buildLayerMatrix(g);
|
|
43
|
-
|
|
43
|
+
let cc = crossCount(g, layering);
|
|
44
44
|
if (cc < bestCC) {
|
|
45
45
|
lastBest = 0;
|
|
46
46
|
best = Object.assign({}, layering);
|
|
@@ -58,10 +58,10 @@ function buildLayerGraphs(g, ranks, relationship) {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
function sweepLayerGraphs(layerGraphs, biasRight) {
|
|
61
|
-
|
|
61
|
+
let cg = new Graph();
|
|
62
62
|
layerGraphs.forEach(function(lg) {
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
let root = lg.graph().root;
|
|
64
|
+
let sorted = sortSubgraph(lg, root, cg, biasRight);
|
|
65
65
|
sorted.vs.forEach((v, i) => lg.node(v).order = i);
|
|
66
66
|
addSubgraphConstraints(lg, cg, sorted.vs);
|
|
67
67
|
});
|
package/lib/order/init-order.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
let util = require("../util");
|
|
4
4
|
|
|
5
5
|
module.exports = initOrder;
|
|
6
6
|
|
|
@@ -16,20 +16,20 @@ module.exports = initOrder;
|
|
|
16
16
|
* the order of its nodes.
|
|
17
17
|
*/
|
|
18
18
|
function initOrder(g) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
let visited = {};
|
|
20
|
+
let simpleNodes = g.nodes().filter(v => !g.children(v).length);
|
|
21
|
+
let maxRank = Math.max(...simpleNodes.map(v => g.node(v).rank));
|
|
22
|
+
let layers = util.range(maxRank + 1).map(() => []);
|
|
23
23
|
|
|
24
24
|
function dfs(v) {
|
|
25
25
|
if (visited[v]) return;
|
|
26
26
|
visited[v] = true;
|
|
27
|
-
|
|
27
|
+
let node = g.node(v);
|
|
28
28
|
layers[node.rank].push(v);
|
|
29
29
|
g.successors(v).forEach(dfs);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
let orderedVs = simpleNodes.sort((a, b) => g.node(a).rank - g.node(b).rank);
|
|
33
33
|
orderedVs.forEach(dfs);
|
|
34
34
|
|
|
35
35
|
return layers;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
let util = require("../util");
|
|
4
4
|
|
|
5
5
|
module.exports = resolveConflicts;
|
|
6
6
|
|
|
@@ -30,9 +30,9 @@ module.exports = resolveConflicts;
|
|
|
30
30
|
* elements in `vs`.
|
|
31
31
|
*/
|
|
32
32
|
function resolveConflicts(entries, cg) {
|
|
33
|
-
|
|
33
|
+
let mappedEntries = {};
|
|
34
34
|
entries.forEach((entry, i) => {
|
|
35
|
-
|
|
35
|
+
let tmp = mappedEntries[entry.v] = {
|
|
36
36
|
indegree: 0,
|
|
37
37
|
"in": [],
|
|
38
38
|
out: [],
|
|
@@ -46,24 +46,24 @@ function resolveConflicts(entries, cg) {
|
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
cg.edges().forEach(e => {
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
let entryV = mappedEntries[e.v];
|
|
50
|
+
let entryW = mappedEntries[e.w];
|
|
51
51
|
if (entryV !== undefined && entryW !== undefined) {
|
|
52
52
|
entryW.indegree++;
|
|
53
53
|
entryV.out.push(mappedEntries[e.w]);
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
let sourceSet = Object.values(mappedEntries).filter(entry => !entry.indegree);
|
|
58
58
|
|
|
59
59
|
return doResolveConflicts(sourceSet);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
function doResolveConflicts(sourceSet) {
|
|
63
|
-
|
|
63
|
+
let entries = [];
|
|
64
64
|
|
|
65
65
|
function handleIn(vEntry) {
|
|
66
|
-
return
|
|
66
|
+
return uEntry => {
|
|
67
67
|
if (uEntry.merged) {
|
|
68
68
|
return;
|
|
69
69
|
}
|
|
@@ -76,7 +76,7 @@ function doResolveConflicts(sourceSet) {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
function handleOut(vEntry) {
|
|
79
|
-
return
|
|
79
|
+
return wEntry => {
|
|
80
80
|
wEntry["in"].push(vEntry);
|
|
81
81
|
if (--wEntry.indegree === 0) {
|
|
82
82
|
sourceSet.push(wEntry);
|
|
@@ -85,7 +85,7 @@ function doResolveConflicts(sourceSet) {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
while (sourceSet.length) {
|
|
88
|
-
|
|
88
|
+
let entry = sourceSet.pop();
|
|
89
89
|
entries.push(entry);
|
|
90
90
|
entry["in"].reverse().forEach(handleIn(entry));
|
|
91
91
|
entry.out.forEach(handleOut(entry));
|
|
@@ -97,8 +97,8 @@ function doResolveConflicts(sourceSet) {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
function mergeEntries(target, source) {
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
let sum = 0;
|
|
101
|
+
let weight = 0;
|
|
102
102
|
|
|
103
103
|
if (target.weight) {
|
|
104
104
|
sum += target.barycenter * target.weight;
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
let barycenter = require("./barycenter");
|
|
2
|
+
let resolveConflicts = require("./resolve-conflicts");
|
|
3
|
+
let sort = require("./sort");
|
|
4
4
|
|
|
5
5
|
module.exports = sortSubgraph;
|
|
6
6
|
|
|
7
7
|
function sortSubgraph(g, v, cg, biasRight) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
let movable = g.children(v);
|
|
9
|
+
let node = g.node(v);
|
|
10
|
+
let bl = node ? node.borderLeft : undefined;
|
|
11
|
+
let br = node ? node.borderRight: undefined;
|
|
12
|
+
let subgraphs = {};
|
|
13
13
|
|
|
14
14
|
if (bl) {
|
|
15
15
|
movable = movable.filter(w => w !== bl && w !== br);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
barycenters.forEach(
|
|
18
|
+
let barycenters = barycenter(g, movable);
|
|
19
|
+
barycenters.forEach(entry => {
|
|
20
20
|
if (g.children(entry.v).length) {
|
|
21
|
-
|
|
21
|
+
let subgraphResult = sortSubgraph(g, entry.v, cg, biasRight);
|
|
22
22
|
subgraphs[entry.v] = subgraphResult;
|
|
23
23
|
if (subgraphResult.hasOwnProperty("barycenter")) {
|
|
24
24
|
mergeBarycenters(entry, subgraphResult);
|
|
@@ -26,15 +26,15 @@ function sortSubgraph(g, v, cg, biasRight) {
|
|
|
26
26
|
}
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
let entries = resolveConflicts(barycenters, cg);
|
|
30
30
|
expandSubgraphs(entries, subgraphs);
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
let result = sort(entries, biasRight);
|
|
33
33
|
|
|
34
34
|
if (bl) {
|
|
35
35
|
result.vs = [bl, result.vs, br].flat(true);
|
|
36
36
|
if (g.predecessors(bl).length) {
|
|
37
|
-
|
|
37
|
+
let blPred = g.node(g.predecessors(bl)[0]),
|
|
38
38
|
brPred = g.node(g.predecessors(br)[0]);
|
|
39
39
|
if (!result.hasOwnProperty("barycenter")) {
|
|
40
40
|
result.barycenter = 0;
|
|
@@ -50,8 +50,8 @@ function sortSubgraph(g, v, cg, biasRight) {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
function expandSubgraphs(entries, subgraphs) {
|
|
53
|
-
entries.forEach(
|
|
54
|
-
entry.vs = entry.vs.flatMap(
|
|
53
|
+
entries.forEach(entry => {
|
|
54
|
+
entry.vs = entry.vs.flatMap(v => {
|
|
55
55
|
if (subgraphs[v]) {
|
|
56
56
|
return subgraphs[v].vs;
|
|
57
57
|
}
|
package/lib/order/sort.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
let util = require("../util");
|
|
2
2
|
|
|
3
3
|
module.exports = sort;
|
|
4
4
|
|
|
5
5
|
function sort(entries, biasRight) {
|
|
6
|
-
|
|
6
|
+
let parts = util.partition(entries, entry => {
|
|
7
7
|
return entry.hasOwnProperty("barycenter");
|
|
8
8
|
});
|
|
9
|
-
|
|
9
|
+
let sortable = parts.lhs,
|
|
10
10
|
unsortable = parts.rhs.sort((a, b) => b.i - a.i),
|
|
11
11
|
vs = [],
|
|
12
12
|
sum = 0,
|
|
@@ -17,7 +17,7 @@ function sort(entries, biasRight) {
|
|
|
17
17
|
|
|
18
18
|
vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
|
|
19
19
|
|
|
20
|
-
sortable.forEach(
|
|
20
|
+
sortable.forEach(entry => {
|
|
21
21
|
vsIndex += entry.vs.length;
|
|
22
22
|
vs.push(entry.vs);
|
|
23
23
|
sum += entry.barycenter * entry.weight;
|
|
@@ -25,7 +25,7 @@ function sort(entries, biasRight) {
|
|
|
25
25
|
vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
let result = { vs: vs.flat(true) };
|
|
29
29
|
if (weight) {
|
|
30
30
|
result.barycenter = sum / weight;
|
|
31
31
|
result.weight = weight;
|
|
@@ -34,7 +34,7 @@ function sort(entries, biasRight) {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
function consumeUnsortable(vs, unsortable, index) {
|
|
37
|
-
|
|
37
|
+
let last;
|
|
38
38
|
while (unsortable.length && (last = unsortable[unsortable.length - 1]).i <= index) {
|
|
39
39
|
unsortable.pop();
|
|
40
40
|
vs.push(last.vs);
|
|
@@ -44,7 +44,7 @@ function consumeUnsortable(vs, unsortable, index) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
function compareWithBias(bias) {
|
|
47
|
-
return
|
|
47
|
+
return (entryV, entryW) => {
|
|
48
48
|
if (entryV.barycenter < entryW.barycenter) {
|
|
49
49
|
return -1;
|
|
50
50
|
} else if (entryV.barycenter > entryW.barycenter) {
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
module.exports = parentDummyChains;
|
|
2
2
|
|
|
3
3
|
function parentDummyChains(g) {
|
|
4
|
-
|
|
4
|
+
let postorderNums = postorder(g);
|
|
5
5
|
|
|
6
|
-
g.graph().dummyChains.forEach(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
g.graph().dummyChains.forEach(v => {
|
|
7
|
+
let node = g.node(v);
|
|
8
|
+
let edgeObj = node.edgeObj;
|
|
9
|
+
let pathData = findPath(g, postorderNums, edgeObj.v, edgeObj.w);
|
|
10
|
+
let path = pathData.path;
|
|
11
|
+
let lca = pathData.lca;
|
|
12
|
+
let pathIdx = 0;
|
|
13
|
+
let pathV = path[pathIdx];
|
|
14
|
+
let ascending = true;
|
|
15
15
|
|
|
16
16
|
while (v !== edgeObj.w) {
|
|
17
17
|
node = g.node(v);
|
|
@@ -44,12 +44,12 @@ function parentDummyChains(g) {
|
|
|
44
44
|
// Find a path from v to w through the lowest common ancestor (LCA). Return the
|
|
45
45
|
// full path and the LCA.
|
|
46
46
|
function findPath(g, postorderNums, v, w) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
let vPath = [];
|
|
48
|
+
let wPath = [];
|
|
49
|
+
let low = Math.min(postorderNums[v].low, postorderNums[w].low);
|
|
50
|
+
let lim = Math.max(postorderNums[v].lim, postorderNums[w].lim);
|
|
51
|
+
let parent;
|
|
52
|
+
let lca;
|
|
53
53
|
|
|
54
54
|
// Traverse up from v to find the LCA
|
|
55
55
|
parent = v;
|
|
@@ -70,11 +70,11 @@ function findPath(g, postorderNums, v, w) {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
function postorder(g) {
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
let result = {};
|
|
74
|
+
let lim = 0;
|
|
75
75
|
|
|
76
76
|
function dfs(v) {
|
|
77
|
-
|
|
77
|
+
let low = lim;
|
|
78
78
|
g.children(v).forEach(dfs);
|
|
79
79
|
result[v] = { low: low, lim: lim++ };
|
|
80
80
|
}
|