@dagrejs/dagre 1.0.1 → 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 +139 -0
- 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 +3 -1
package/index.d.ts
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// Type definitions for dagre 1.0.1
|
|
2
|
+
// Project: https://github.com/dagrejs/dagre
|
|
3
|
+
// Definitions by: Qinfeng Chen <https://github.com/qinfchen>
|
|
4
|
+
// Pete Vilter <https://github.com/vilterp>
|
|
5
|
+
// David Newell <https://github.com/rustedgrail>
|
|
6
|
+
// Graham Lea <https://github.com/GrahamLea>
|
|
7
|
+
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
|
8
|
+
|
|
9
|
+
declare module '@dagrejs/dagre' {
|
|
10
|
+
export namespace graphlib {
|
|
11
|
+
class Graph<T = {}> {
|
|
12
|
+
constructor(opt?: { directed?: boolean | undefined; multigraph?: boolean | undefined; compound?: boolean | undefined });
|
|
13
|
+
|
|
14
|
+
graph(): GraphLabel;
|
|
15
|
+
isDirected(): boolean;
|
|
16
|
+
isMultigraph(): boolean;
|
|
17
|
+
setGraph(label: GraphLabel): Graph<T>;
|
|
18
|
+
|
|
19
|
+
edge(edgeObj: Edge): GraphEdge;
|
|
20
|
+
edge(outNodeName: string, inNodeName: string, name?: string): GraphEdge;
|
|
21
|
+
edgeCount(): number;
|
|
22
|
+
edges(): Edge[];
|
|
23
|
+
hasEdge(edgeObj: Edge): boolean;
|
|
24
|
+
hasEdge(outNodeName: string, inNodeName: string, name?: string): boolean;
|
|
25
|
+
inEdges(inNodeName: string, outNodeName?: string): Edge[] | undefined;
|
|
26
|
+
outEdges(outNodeName: string, inNodeName?: string): Edge[] | undefined;
|
|
27
|
+
removeEdge(outNodeName: string, inNodeName: string, name?: string): Graph<T>;
|
|
28
|
+
setDefaultEdgeLabel(callback: string | ((v: string, w: string, name?: string) => string | Label)): Graph<T>;
|
|
29
|
+
setEdge(params: Edge, value?: string | { [key: string]: any }): Graph<T>;
|
|
30
|
+
setEdge(sourceId: string, targetId: string, value?: string | Label, name?: string): Graph<T>;
|
|
31
|
+
|
|
32
|
+
children(parentName: string): string | undefined;
|
|
33
|
+
hasNode(name: string): boolean;
|
|
34
|
+
neighbors(name: string): Array<Node<T>> | undefined;
|
|
35
|
+
node(id: string | Label): Node<T>;
|
|
36
|
+
nodeCount(): number;
|
|
37
|
+
nodes(): string[];
|
|
38
|
+
parent(childName: string): string | undefined;
|
|
39
|
+
predecessors(name: string): Array<Node<T>> | undefined;
|
|
40
|
+
removeNode(name: string): Graph<T>;
|
|
41
|
+
filterNodes(callback: (nodeId: string) => boolean): Graph<T>;
|
|
42
|
+
setDefaultNodeLabel(callback: string | ((nodeId: string) => string | Label)): Graph<T>;
|
|
43
|
+
setNode(name: string, label: string | Label): Graph<T>;
|
|
44
|
+
setParent(childName: string, parentName: string): void;
|
|
45
|
+
sinks(): Array<Node<T>>;
|
|
46
|
+
sources(): Array<Node<T>>;
|
|
47
|
+
successors(name: string): Array<Node<T>> | undefined;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
namespace json {
|
|
51
|
+
function read(graph: any): Graph;
|
|
52
|
+
function write(graph: Graph): any;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
namespace alg {
|
|
56
|
+
function components(graph: Graph): string[][];
|
|
57
|
+
function dijkstra(graph: Graph, source: string, weightFn?: WeightFn, edgeFn?: EdgeFn): any;
|
|
58
|
+
function dijkstraAll(graph: Graph, weightFn?: WeightFn, edgeFn?: EdgeFn): any;
|
|
59
|
+
function findCycles(graph: Graph): string[][];
|
|
60
|
+
function floydWarchall(graph: Graph, weightFn?: WeightFn, edgeFn?: EdgeFn): any;
|
|
61
|
+
function isAcyclic(graph: Graph): boolean;
|
|
62
|
+
function postorder(graph: Graph, nodeNames: string | string[]): string[];
|
|
63
|
+
function preorder(graph: Graph, nodeNames: string | string[]): string[];
|
|
64
|
+
function prim<T>(graph: Graph<T>, weightFn?: WeightFn): Graph<T>;
|
|
65
|
+
function tarjam(graph: Graph): string[][];
|
|
66
|
+
function topsort(graph: Graph): string[];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface Label {
|
|
71
|
+
label?: string;
|
|
72
|
+
width?: number;
|
|
73
|
+
height?: number;
|
|
74
|
+
minRank?: number;
|
|
75
|
+
maxRank?: number;
|
|
76
|
+
borderLeft?: string[];
|
|
77
|
+
borderRight?: string[];
|
|
78
|
+
[key: string]: any;
|
|
79
|
+
}
|
|
80
|
+
export type WeightFn = (edge: Edge) => number;
|
|
81
|
+
export type EdgeFn = (outNodeName: string) => GraphEdge[];
|
|
82
|
+
|
|
83
|
+
export interface GraphLabel {
|
|
84
|
+
width?: number | undefined;
|
|
85
|
+
height?: number | undefined;
|
|
86
|
+
compound?: boolean | undefined;
|
|
87
|
+
rankdir?: string | undefined;
|
|
88
|
+
align?: string | undefined;
|
|
89
|
+
nodesep?: number | undefined;
|
|
90
|
+
edgesep?: number | undefined;
|
|
91
|
+
ranksep?: number | undefined;
|
|
92
|
+
marginx?: number | undefined;
|
|
93
|
+
marginy?: number | undefined;
|
|
94
|
+
acyclicer?: string | undefined;
|
|
95
|
+
ranker?: string | undefined;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface NodeConfig {
|
|
99
|
+
width?: number | undefined;
|
|
100
|
+
height?: number | undefined;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface EdgeConfig {
|
|
104
|
+
minlen?: number | undefined;
|
|
105
|
+
weight?: number | undefined;
|
|
106
|
+
width?: number | undefined;
|
|
107
|
+
height?: number | undefined;
|
|
108
|
+
lablepos?: 'l' | 'c' | 'r' | undefined;
|
|
109
|
+
labeloffest?: number | undefined;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function layout(graph: graphlib.Graph, layout?: GraphLabel & NodeConfig & EdgeConfig): void;
|
|
113
|
+
|
|
114
|
+
export interface Edge {
|
|
115
|
+
v: string;
|
|
116
|
+
w: string;
|
|
117
|
+
name?: string | undefined;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface GraphEdge {
|
|
121
|
+
points: Array<{ x: number; y: number }>;
|
|
122
|
+
[key: string]: any;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export type Node<T = {}> = T & {
|
|
126
|
+
x: number;
|
|
127
|
+
y: number;
|
|
128
|
+
width: number;
|
|
129
|
+
height: number;
|
|
130
|
+
class?: string | undefined;
|
|
131
|
+
label?: string | undefined;
|
|
132
|
+
padding?: number | undefined;
|
|
133
|
+
paddingX?: number | undefined;
|
|
134
|
+
paddingY?: number | undefined;
|
|
135
|
+
rx?: number | undefined;
|
|
136
|
+
ry?: number | undefined;
|
|
137
|
+
shape?: string | undefined;
|
|
138
|
+
};
|
|
139
|
+
}
|
package/lib/acyclic.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
let greedyFAS = require("./greedy-fas");
|
|
4
|
+
let uniqueId = require("./util").uniqueId;
|
|
5
5
|
|
|
6
6
|
module.exports = {
|
|
7
7
|
run: run,
|
|
@@ -9,11 +9,11 @@ module.exports = {
|
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
function run(g) {
|
|
12
|
-
|
|
12
|
+
let fas = (g.graph().acyclicer === "greedy"
|
|
13
13
|
? greedyFAS(g, weightFn(g))
|
|
14
14
|
: dfsFAS(g));
|
|
15
|
-
fas.forEach(
|
|
16
|
-
|
|
15
|
+
fas.forEach(e => {
|
|
16
|
+
let label = g.edge(e);
|
|
17
17
|
g.removeEdge(e);
|
|
18
18
|
label.forwardName = e.name;
|
|
19
19
|
label.reversed = true;
|
|
@@ -21,16 +21,16 @@ function run(g) {
|
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
function weightFn(g) {
|
|
24
|
-
return
|
|
24
|
+
return e => {
|
|
25
25
|
return g.edge(e).weight;
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
function dfsFAS(g) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
let fas = [];
|
|
32
|
+
let stack = {};
|
|
33
|
+
let visited = {};
|
|
34
34
|
|
|
35
35
|
function dfs(v) {
|
|
36
36
|
if (visited.hasOwnProperty(v)) {
|
|
@@ -38,7 +38,7 @@ function dfsFAS(g) {
|
|
|
38
38
|
}
|
|
39
39
|
visited[v] = true;
|
|
40
40
|
stack[v] = true;
|
|
41
|
-
g.outEdges(v).forEach(
|
|
41
|
+
g.outEdges(v).forEach(e => {
|
|
42
42
|
if (stack.hasOwnProperty(e.w)) {
|
|
43
43
|
fas.push(e);
|
|
44
44
|
} else {
|
|
@@ -53,12 +53,12 @@ function dfsFAS(g) {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
function undo(g) {
|
|
56
|
-
g.edges().forEach(
|
|
57
|
-
|
|
56
|
+
g.edges().forEach(e => {
|
|
57
|
+
let label = g.edge(e);
|
|
58
58
|
if (label.reversed) {
|
|
59
59
|
g.removeEdge(e);
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
let forwardName = label.forwardName;
|
|
62
62
|
delete label.reversed;
|
|
63
63
|
delete label.forwardName;
|
|
64
64
|
g.setEdge(e.w, e.v, label, forwardName);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
let util = require("./util");
|
|
2
2
|
|
|
3
3
|
module.exports = addBorderSegments;
|
|
4
4
|
|
|
5
5
|
function addBorderSegments(g) {
|
|
6
6
|
function dfs(v) {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
let children = g.children(v);
|
|
8
|
+
let node = g.node(v);
|
|
9
9
|
if (children.length) {
|
|
10
10
|
children.forEach(dfs);
|
|
11
11
|
}
|
|
@@ -13,7 +13,7 @@ function addBorderSegments(g) {
|
|
|
13
13
|
if (node.hasOwnProperty("minRank")) {
|
|
14
14
|
node.borderLeft = [];
|
|
15
15
|
node.borderRight = [];
|
|
16
|
-
for (
|
|
16
|
+
for (let rank = node.minRank, maxRank = node.maxRank + 1;
|
|
17
17
|
rank < maxRank;
|
|
18
18
|
++rank) {
|
|
19
19
|
addBorderNode(g, "borderLeft", "_bl", v, node, rank);
|
|
@@ -26,9 +26,9 @@ function addBorderSegments(g) {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
function addBorderNode(g, prop, prefix, sg, sgNode, rank) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
let label = { width: 0, height: 0, rank: rank, borderType: prop };
|
|
30
|
+
let prev = sgNode[prop][rank - 1];
|
|
31
|
+
let curr = util.addDummyNode(g, "border", label, prefix);
|
|
32
32
|
sgNode[prop][rank] = curr;
|
|
33
33
|
g.setParent(curr, sg);
|
|
34
34
|
if (prev) {
|
package/lib/coordinate-system.js
CHANGED
|
@@ -6,14 +6,14 @@ module.exports = {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
function adjust(g) {
|
|
9
|
-
|
|
9
|
+
let rankDir = g.graph().rankdir.toLowerCase();
|
|
10
10
|
if (rankDir === "lr" || rankDir === "rl") {
|
|
11
11
|
swapWidthHeight(g);
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
function undo(g) {
|
|
16
|
-
|
|
16
|
+
let rankDir = g.graph().rankdir.toLowerCase();
|
|
17
17
|
if (rankDir === "bt" || rankDir === "rl") {
|
|
18
18
|
reverseY(g);
|
|
19
19
|
}
|
|
@@ -30,7 +30,7 @@ function swapWidthHeight(g) {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
function swapWidthHeightOne(attrs) {
|
|
33
|
-
|
|
33
|
+
let w = attrs.width;
|
|
34
34
|
attrs.width = attrs.height;
|
|
35
35
|
attrs.height = w;
|
|
36
36
|
}
|
|
@@ -38,8 +38,8 @@ function swapWidthHeightOne(attrs) {
|
|
|
38
38
|
function reverseY(g) {
|
|
39
39
|
g.nodes().forEach(v => reverseYOne(g.node(v)));
|
|
40
40
|
|
|
41
|
-
g.edges().forEach(
|
|
42
|
-
|
|
41
|
+
g.edges().forEach(e => {
|
|
42
|
+
let edge = g.edge(e);
|
|
43
43
|
edge.points.forEach(reverseYOne);
|
|
44
44
|
if (edge.hasOwnProperty("y")) {
|
|
45
45
|
reverseYOne(edge);
|
|
@@ -54,8 +54,8 @@ function reverseYOne(attrs) {
|
|
|
54
54
|
function swapXY(g) {
|
|
55
55
|
g.nodes().forEach(v => swapXYOne(g.node(v)));
|
|
56
56
|
|
|
57
|
-
g.edges().forEach(
|
|
58
|
-
|
|
57
|
+
g.edges().forEach(e => {
|
|
58
|
+
let edge = g.edge(e);
|
|
59
59
|
edge.points.forEach(swapXYOne);
|
|
60
60
|
if (edge.hasOwnProperty("x")) {
|
|
61
61
|
swapXYOne(edge);
|
|
@@ -64,7 +64,7 @@ function swapXY(g) {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
function swapXYOne(attrs) {
|
|
67
|
-
|
|
67
|
+
let x = attrs.x;
|
|
68
68
|
attrs.x = attrs.y;
|
|
69
69
|
attrs.y = x;
|
|
70
70
|
}
|
package/lib/data/list.js
CHANGED
|
@@ -3,44 +3,44 @@
|
|
|
3
3
|
* "Introduction to Algorithms".
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
6
|
+
class List {
|
|
7
|
+
constructor() {
|
|
8
|
+
let sentinel = {};
|
|
9
|
+
sentinel._next = sentinel._prev = sentinel;
|
|
10
|
+
this._sentinel = sentinel;
|
|
11
|
+
}
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
dequeue() {
|
|
14
|
+
let sentinel = this._sentinel;
|
|
15
|
+
let entry = sentinel._prev;
|
|
16
|
+
if (entry !== sentinel) {
|
|
17
|
+
unlink(entry);
|
|
18
|
+
return entry;
|
|
19
|
+
}
|
|
20
20
|
}
|
|
21
|
-
};
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
enqueue(entry) {
|
|
23
|
+
let sentinel = this._sentinel;
|
|
24
|
+
if (entry._prev && entry._next) {
|
|
25
|
+
unlink(entry);
|
|
26
|
+
}
|
|
27
|
+
entry._next = sentinel._next;
|
|
28
|
+
sentinel._next._prev = entry;
|
|
29
|
+
sentinel._next = entry;
|
|
30
|
+
entry._prev = sentinel;
|
|
27
31
|
}
|
|
28
|
-
entry._next = sentinel._next;
|
|
29
|
-
sentinel._next._prev = entry;
|
|
30
|
-
sentinel._next = entry;
|
|
31
|
-
entry._prev = sentinel;
|
|
32
|
-
};
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
toString() {
|
|
34
|
+
let strs = [];
|
|
35
|
+
let sentinel = this._sentinel;
|
|
36
|
+
let curr = sentinel._prev;
|
|
37
|
+
while (curr !== sentinel) {
|
|
38
|
+
strs.push(JSON.stringify(curr, filterOutLinks));
|
|
39
|
+
curr = curr._prev;
|
|
40
|
+
}
|
|
41
|
+
return "[" + strs.join(", ") + "]";
|
|
41
42
|
}
|
|
42
|
-
|
|
43
|
-
};
|
|
43
|
+
}
|
|
44
44
|
|
|
45
45
|
function unlink(entry) {
|
|
46
46
|
entry._prev._next = entry._next;
|
|
@@ -54,3 +54,5 @@ function filterOutLinks(k, v) {
|
|
|
54
54
|
return v;
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
+
|
|
58
|
+
module.exports = List;
|
package/lib/debug.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
let util = require("./util");
|
|
2
|
+
let Graph = require("@dagrejs/graphlib").Graph;
|
|
3
3
|
|
|
4
4
|
module.exports = {
|
|
5
5
|
debugOrdering: debugOrdering
|
|
@@ -7,23 +7,21 @@ module.exports = {
|
|
|
7
7
|
|
|
8
8
|
/* istanbul ignore next */
|
|
9
9
|
function debugOrdering(g) {
|
|
10
|
-
|
|
10
|
+
let layerMatrix = util.buildLayerMatrix(g);
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
let h = new Graph({ compound: true, multigraph: true }).setGraph({});
|
|
13
13
|
|
|
14
|
-
g.nodes().forEach(
|
|
14
|
+
g.nodes().forEach(v => {
|
|
15
15
|
h.setNode(v, { label: v });
|
|
16
16
|
h.setParent(v, "layer" + g.node(v).rank);
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
g.edges().forEach(
|
|
20
|
-
h.setEdge(e.v, e.w, {}, e.name);
|
|
21
|
-
});
|
|
19
|
+
g.edges().forEach(e => h.setEdge(e.v, e.w, {}, e.name));
|
|
22
20
|
|
|
23
|
-
layerMatrix.forEach(
|
|
24
|
-
|
|
21
|
+
layerMatrix.forEach((layer, i) => {
|
|
22
|
+
let layerV = "layer" + i;
|
|
25
23
|
h.setNode(layerV, { rank: "same" });
|
|
26
|
-
layer.reduce(
|
|
24
|
+
layer.reduce((u, v) => {
|
|
27
25
|
h.setEdge(u, v, { style: "invis" });
|
|
28
26
|
return v;
|
|
29
27
|
});
|
package/lib/greedy-fas.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
let Graph = require("@dagrejs/graphlib").Graph;
|
|
2
|
+
let List = require("./data/list");
|
|
3
3
|
|
|
4
4
|
/*
|
|
5
5
|
* A greedy heuristic for finding a feedback arc set for a graph. A feedback
|
|
@@ -10,30 +10,30 @@ var List = require("./data/list");
|
|
|
10
10
|
*/
|
|
11
11
|
module.exports = greedyFAS;
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
let DEFAULT_WEIGHT_FN = () => 1;
|
|
14
14
|
|
|
15
15
|
function greedyFAS(g, weightFn) {
|
|
16
16
|
if (g.nodeCount() <= 1) {
|
|
17
17
|
return [];
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
let state = buildState(g, weightFn || DEFAULT_WEIGHT_FN);
|
|
20
|
+
let results = doGreedyFAS(state.graph, state.buckets, state.zeroIdx);
|
|
21
21
|
|
|
22
22
|
// Expand multi-edges
|
|
23
23
|
return results.flatMap(e => g.outEdges(e.v, e.w));
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
function doGreedyFAS(g, buckets, zeroIdx) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
let results = [];
|
|
28
|
+
let sources = buckets[buckets.length - 1];
|
|
29
|
+
let sinks = buckets[0];
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
let entry;
|
|
32
32
|
while (g.nodeCount()) {
|
|
33
33
|
while ((entry = sinks.dequeue())) { removeNode(g, buckets, zeroIdx, entry); }
|
|
34
34
|
while ((entry = sources.dequeue())) { removeNode(g, buckets, zeroIdx, entry); }
|
|
35
35
|
if (g.nodeCount()) {
|
|
36
|
-
for (
|
|
36
|
+
for (let i = buckets.length - 2; i > 0; --i) {
|
|
37
37
|
entry = buckets[i].dequeue();
|
|
38
38
|
if (entry) {
|
|
39
39
|
results = results.concat(removeNode(g, buckets, zeroIdx, entry, true));
|
|
@@ -47,11 +47,11 @@ function doGreedyFAS(g, buckets, zeroIdx) {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
|
|
50
|
-
|
|
50
|
+
let results = collectPredecessors ? [] : undefined;
|
|
51
51
|
|
|
52
|
-
g.inEdges(entry.v).forEach(
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
g.inEdges(entry.v).forEach(edge => {
|
|
53
|
+
let weight = g.edge(edge);
|
|
54
|
+
let uEntry = g.node(edge.v);
|
|
55
55
|
|
|
56
56
|
if (collectPredecessors) {
|
|
57
57
|
results.push({ v: edge.v, w: edge.w });
|
|
@@ -61,10 +61,10 @@ function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
|
|
|
61
61
|
assignBucket(buckets, zeroIdx, uEntry);
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
g.outEdges(entry.v).forEach(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
g.outEdges(entry.v).forEach(edge => {
|
|
65
|
+
let weight = g.edge(edge);
|
|
66
|
+
let w = edge.w;
|
|
67
|
+
let wEntry = g.node(w);
|
|
68
68
|
wEntry["in"] -= weight;
|
|
69
69
|
assignBucket(buckets, zeroIdx, wEntry);
|
|
70
70
|
});
|
|
@@ -75,29 +75,29 @@ function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
function buildState(g, weightFn) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
let fasGraph = new Graph();
|
|
79
|
+
let maxIn = 0;
|
|
80
|
+
let maxOut = 0;
|
|
81
81
|
|
|
82
|
-
g.nodes().forEach(
|
|
82
|
+
g.nodes().forEach(v => {
|
|
83
83
|
fasGraph.setNode(v, { v: v, "in": 0, out: 0 });
|
|
84
84
|
});
|
|
85
85
|
|
|
86
86
|
// Aggregate weights on nodes, but also sum the weights across multi-edges
|
|
87
87
|
// into a single edge for the fasGraph.
|
|
88
|
-
g.edges().forEach(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
g.edges().forEach(e => {
|
|
89
|
+
let prevWeight = fasGraph.edge(e.v, e.w) || 0;
|
|
90
|
+
let weight = weightFn(e);
|
|
91
|
+
let edgeWeight = prevWeight + weight;
|
|
92
92
|
fasGraph.setEdge(e.v, e.w, edgeWeight);
|
|
93
93
|
maxOut = Math.max(maxOut, fasGraph.node(e.v).out += weight);
|
|
94
94
|
maxIn = Math.max(maxIn, fasGraph.node(e.w)["in"] += weight);
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
let buckets = range(maxOut + maxIn + 3).map(() => new List());
|
|
98
|
+
let zeroIdx = maxIn + 1;
|
|
99
99
|
|
|
100
|
-
fasGraph.nodes().forEach(
|
|
100
|
+
fasGraph.nodes().forEach(v => {
|
|
101
101
|
assignBucket(buckets, zeroIdx, fasGraph.node(v));
|
|
102
102
|
});
|
|
103
103
|
|