-
Notifications
You must be signed in to change notification settings - Fork 606
/
index.js
81 lines (68 loc) · 2.22 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
"use strict";
let initOrder = require("./init-order");
let crossCount = require("./cross-count");
let sortSubgraph = require("./sort-subgraph");
let buildLayerGraph = require("./build-layer-graph");
let addSubgraphConstraints = require("./add-subgraph-constraints");
let Graph = require("@dagrejs/graphlib").Graph;
let util = require("../util");
module.exports = order;
/*
* Applies heuristics to minimize edge crossings in the graph and sets the best
* order solution as an order attribute on each node.
*
* Pre-conditions:
*
* 1. Graph must be DAG
* 2. Graph nodes must be objects with a "rank" attribute
* 3. Graph edges must have the "weight" attribute
*
* Post-conditions:
*
* 1. Graph nodes will have an "order" attribute based on the results of the
* algorithm.
*/
function order(g, opts) {
if (opts && typeof opts.customOrder === 'function') {
opts.customOrder(g, order);
return;
}
let maxRank = util.maxRank(g),
downLayerGraphs = buildLayerGraphs(g, util.range(1, maxRank + 1), "inEdges"),
upLayerGraphs = buildLayerGraphs(g, util.range(maxRank - 1, -1, -1), "outEdges");
let layering = initOrder(g);
assignOrder(g, layering);
if (opts && opts.disableOptimalOrderHeuristic) {
return;
}
let bestCC = Number.POSITIVE_INFINITY,
best;
for (let i = 0, lastBest = 0; lastBest < 4; ++i, ++lastBest) {
sweepLayerGraphs(i % 2 ? downLayerGraphs : upLayerGraphs, i % 4 >= 2);
layering = util.buildLayerMatrix(g);
let cc = crossCount(g, layering);
if (cc < bestCC) {
lastBest = 0;
best = Object.assign({}, layering);
bestCC = cc;
}
}
assignOrder(g, best);
}
function buildLayerGraphs(g, ranks, relationship) {
return ranks.map(function(rank) {
return buildLayerGraph(g, rank, relationship);
});
}
function sweepLayerGraphs(layerGraphs, biasRight) {
let cg = new Graph();
layerGraphs.forEach(function(lg) {
let root = lg.graph().root;
let sorted = sortSubgraph(lg, root, cg, biasRight);
sorted.vs.forEach((v, i) => lg.node(v).order = i);
addSubgraphConstraints(lg, cg, sorted.vs);
});
}
function assignOrder(g, layering) {
Object.values(layering).forEach(layer => layer.forEach((v, i) => g.node(v).order = i));
}