@dagrejs/dagre 1.1.0 → 1.1.1
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/dist/dagre.js +16 -5
- package/dist/dagre.min.js +4 -4
- package/lib/acyclic.js +18 -10
- package/lib/add-border-segments.js +11 -19
- package/lib/coordinate-system.js +15 -5
- package/lib/data/list.js +7 -8
- package/lib/debug.js +14 -25
- package/lib/greedy-fas.js +30 -35
- package/lib/layout.js +102 -105
- package/lib/nesting-graph.js +21 -18
- package/lib/normalize.js +18 -22
- package/lib/order/add-subgraph-constraints.js +2 -6
- package/lib/order/barycenter.js +6 -14
- package/lib/order/build-layer-graph.js +13 -19
- package/lib/order/cross-count.js +10 -13
- package/lib/order/index.js +23 -23
- package/lib/order/init-order.js +7 -8
- package/lib/order/resolve-conflicts.js +19 -9
- package/lib/order/sort-subgraph.js +22 -16
- package/lib/order/sort.js +12 -13
- package/lib/parent-dummy-chains.js +19 -17
- package/lib/position/bk.js +84 -40
- package/lib/position/index.js +9 -10
- package/lib/rank/feasible-tree.js +17 -14
- package/lib/rank/index.js +15 -25
- package/lib/rank/network-simplex.js +39 -18
- package/lib/rank/util.js +12 -6
- package/lib/util.js +57 -42
- package/lib/version.js +1 -8
- package/package.json +3 -15
- package/lib/index.js +0 -38
- package/mjs-lib/acyclic.js +0 -62
- package/mjs-lib/add-border-segments.js +0 -35
- package/mjs-lib/coordinate-system.js +0 -65
- package/mjs-lib/data/list.js +0 -56
- package/mjs-lib/debug.js +0 -30
- package/mjs-lib/greedy-fas.js +0 -125
- package/mjs-lib/index.js +0 -9
- package/mjs-lib/layout.js +0 -405
- package/mjs-lib/nesting-graph.js +0 -120
- package/mjs-lib/normalize.js +0 -84
- package/mjs-lib/order/add-subgraph-constraints.js +0 -49
- package/mjs-lib/order/barycenter.js +0 -24
- package/mjs-lib/order/build-layer-graph.js +0 -71
- package/mjs-lib/order/cross-count.js +0 -64
- package/mjs-lib/order/index.js +0 -70
- package/mjs-lib/order/init-order.js +0 -34
- package/mjs-lib/order/resolve-conflicts.js +0 -116
- package/mjs-lib/order/sort-subgraph.js +0 -71
- package/mjs-lib/order/sort.js +0 -54
- package/mjs-lib/parent-dummy-chains.js +0 -82
- package/mjs-lib/position/bk.js +0 -409
- package/mjs-lib/position/index.js +0 -30
- package/mjs-lib/rank/feasible-tree.js +0 -93
- package/mjs-lib/rank/index.js +0 -46
- package/mjs-lib/rank/network-simplex.js +0 -233
- package/mjs-lib/rank/util.js +0 -58
- package/mjs-lib/util.js +0 -305
- package/mjs-lib/version.js +0 -1
package/dist/dagre.js
CHANGED
|
@@ -1309,7 +1309,12 @@ module.exports = order;
|
|
|
1309
1309
|
* 1. Graph nodes will have an "order" attribute based on the results of the
|
|
1310
1310
|
* algorithm.
|
|
1311
1311
|
*/
|
|
1312
|
-
function order(g) {
|
|
1312
|
+
function order(g, opts) {
|
|
1313
|
+
if (opts && typeof opts.customOrder === 'function') {
|
|
1314
|
+
opts.customOrder(g, order);
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1313
1318
|
let maxRank = util.maxRank(g),
|
|
1314
1319
|
downLayerGraphs = buildLayerGraphs(g, util.range(1, maxRank + 1), "inEdges"),
|
|
1315
1320
|
upLayerGraphs = buildLayerGraphs(g, util.range(maxRank - 1, -1, -1), "outEdges");
|
|
@@ -1317,6 +1322,10 @@ function order(g) {
|
|
|
1317
1322
|
let layering = initOrder(g);
|
|
1318
1323
|
assignOrder(g, layering);
|
|
1319
1324
|
|
|
1325
|
+
if (opts && opts.disableOptimalOrderHeuristic) {
|
|
1326
|
+
return;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1320
1329
|
let bestCC = Number.POSITIVE_INFINITY,
|
|
1321
1330
|
best;
|
|
1322
1331
|
|
|
@@ -1810,7 +1819,8 @@ function findType1Conflicts(g, layering) {
|
|
|
1810
1819
|
return layer;
|
|
1811
1820
|
}
|
|
1812
1821
|
|
|
1813
|
-
layering.reduce(visitLayer);
|
|
1822
|
+
layering.length && layering.reduce(visitLayer);
|
|
1823
|
+
|
|
1814
1824
|
return conflicts;
|
|
1815
1825
|
}
|
|
1816
1826
|
|
|
@@ -1855,7 +1865,8 @@ function findType2Conflicts(g, layering) {
|
|
|
1855
1865
|
return south;
|
|
1856
1866
|
}
|
|
1857
1867
|
|
|
1858
|
-
layering.reduce(visitLayer);
|
|
1868
|
+
layering.length && layering.reduce(visitLayer);
|
|
1869
|
+
|
|
1859
1870
|
return conflicts;
|
|
1860
1871
|
}
|
|
1861
1872
|
|
|
@@ -2948,7 +2959,7 @@ function zipObject(props, values) {
|
|
|
2948
2959
|
}
|
|
2949
2960
|
|
|
2950
2961
|
},{"@dagrejs/graphlib":29}],28:[function(require,module,exports){
|
|
2951
|
-
module.exports = "1.
|
|
2962
|
+
module.exports = "1.1.1";
|
|
2952
2963
|
|
|
2953
2964
|
},{}],29:[function(require,module,exports){
|
|
2954
2965
|
/**
|
|
@@ -4342,7 +4353,7 @@ function read(json) {
|
|
|
4342
4353
|
}
|
|
4343
4354
|
|
|
4344
4355
|
},{"./graph":44}],47:[function(require,module,exports){
|
|
4345
|
-
module.exports = '2.1
|
|
4356
|
+
module.exports = '2.2.1';
|
|
4346
4357
|
|
|
4347
4358
|
},{}]},{},[1])(1)
|
|
4348
4359
|
});
|
package/dist/dagre.min.js
CHANGED
|
@@ -207,7 +207,7 @@ let cc=0;southEntries.forEach(entry=>{let index=entry.pos+firstIndex;tree[index]
|
|
|
207
207
|
*
|
|
208
208
|
* 1. Graph nodes will have an "order" attribute based on the results of the
|
|
209
209
|
* algorithm.
|
|
210
|
-
*/function order(g){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);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))}},{"../util":27,"./add-subgraph-constraints":11,"./build-layer-graph":13,"./cross-count":14,"./init-order":16,"./sort-subgraph":18,"@dagrejs/graphlib":29}],16:[function(require,module,exports){"use strict";let util=require("../util");module.exports=initOrder;
|
|
210
|
+
*/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))}},{"../util":27,"./add-subgraph-constraints":11,"./build-layer-graph":13,"./cross-count":14,"./init-order":16,"./sort-subgraph":18,"@dagrejs/graphlib":29}],16:[function(require,module,exports){"use strict";let util=require("../util");module.exports=initOrder;
|
|
211
211
|
/*
|
|
212
212
|
* Assigns an initial order value for each node by performing a DFS search
|
|
213
213
|
* starting from nodes in the first rank. Nodes are assigned an order in their
|
|
@@ -277,7 +277,7 @@ parent=w;while((parent=g.parent(parent))!==lca){wPath.push(parent)}return{path:v
|
|
|
277
277
|
k0=0,
|
|
278
278
|
// Tracks the last node in this layer scanned for crossings with a type-1
|
|
279
279
|
// segment.
|
|
280
|
-
scanPos=0,prevLayerLength=prevLayer.length,lastNode=layer[layer.length-1];layer.forEach((v,i)=>{let w=findOtherInnerSegmentNode(g,v),k1=w?g.node(w).order:prevLayerLength;if(w||v===lastNode){layer.slice(scanPos,i+1).forEach(scanNode=>{g.predecessors(scanNode).forEach(u=>{let uLabel=g.node(u),uPos=uLabel.order;if((uPos<k0||k1<uPos)&&!(uLabel.dummy&&g.node(scanNode).dummy)){addConflict(conflicts,u,scanNode)}})});scanPos=i+1;k0=k1}});return layer}layering.reduce(visitLayer);return conflicts}function findType2Conflicts(g,layering){let conflicts={};function scan(south,southPos,southEnd,prevNorthBorder,nextNorthBorder){let v;util.range(southPos,southEnd).forEach(i=>{v=south[i];if(g.node(v).dummy){g.predecessors(v).forEach(u=>{let uNode=g.node(u);if(uNode.dummy&&(uNode.order<prevNorthBorder||uNode.order>nextNorthBorder)){addConflict(conflicts,u,v)}})}})}function visitLayer(north,south){let prevNorthPos=-1,nextNorthPos,southPos=0;south.forEach((v,southLookahead)=>{if(g.node(v).dummy==="border"){let predecessors=g.predecessors(v);if(predecessors.length){nextNorthPos=g.node(predecessors[0]).order;scan(south,southPos,southLookahead,prevNorthPos,nextNorthPos);southPos=southLookahead;prevNorthPos=nextNorthPos}}scan(south,southPos,south.length,nextNorthPos,north.length)});return south}layering.reduce(visitLayer);return conflicts}function findOtherInnerSegmentNode(g,v){if(g.node(v).dummy){return g.predecessors(v).find(u=>g.node(u).dummy)}}function addConflict(conflicts,v,w){if(v>w){let tmp=v;v=w;w=tmp}let conflictsV=conflicts[v];if(!conflictsV){conflicts[v]=conflictsV={}}conflictsV[w]=true}function hasConflict(conflicts,v,w){if(v>w){let tmp=v;v=w;w=tmp}return!!conflicts[v]&&conflicts[v].hasOwnProperty(w)}
|
|
280
|
+
scanPos=0,prevLayerLength=prevLayer.length,lastNode=layer[layer.length-1];layer.forEach((v,i)=>{let w=findOtherInnerSegmentNode(g,v),k1=w?g.node(w).order:prevLayerLength;if(w||v===lastNode){layer.slice(scanPos,i+1).forEach(scanNode=>{g.predecessors(scanNode).forEach(u=>{let uLabel=g.node(u),uPos=uLabel.order;if((uPos<k0||k1<uPos)&&!(uLabel.dummy&&g.node(scanNode).dummy)){addConflict(conflicts,u,scanNode)}})});scanPos=i+1;k0=k1}});return layer}layering.length&&layering.reduce(visitLayer);return conflicts}function findType2Conflicts(g,layering){let conflicts={};function scan(south,southPos,southEnd,prevNorthBorder,nextNorthBorder){let v;util.range(southPos,southEnd).forEach(i=>{v=south[i];if(g.node(v).dummy){g.predecessors(v).forEach(u=>{let uNode=g.node(u);if(uNode.dummy&&(uNode.order<prevNorthBorder||uNode.order>nextNorthBorder)){addConflict(conflicts,u,v)}})}})}function visitLayer(north,south){let prevNorthPos=-1,nextNorthPos,southPos=0;south.forEach((v,southLookahead)=>{if(g.node(v).dummy==="border"){let predecessors=g.predecessors(v);if(predecessors.length){nextNorthPos=g.node(predecessors[0]).order;scan(south,southPos,southLookahead,prevNorthPos,nextNorthPos);southPos=southLookahead;prevNorthPos=nextNorthPos}}scan(south,southPos,south.length,nextNorthPos,north.length)});return south}layering.length&&layering.reduce(visitLayer);return conflicts}function findOtherInnerSegmentNode(g,v){if(g.node(v).dummy){return g.predecessors(v).find(u=>g.node(u).dummy)}}function addConflict(conflicts,v,w){if(v>w){let tmp=v;v=w;w=tmp}let conflictsV=conflicts[v];if(!conflictsV){conflicts[v]=conflictsV={}}conflictsV[w]=true}function hasConflict(conflicts,v,w){if(v>w){let tmp=v;v=w;w=tmp}return!!conflicts[v]&&conflicts[v].hasOwnProperty(w)}
|
|
281
281
|
/*
|
|
282
282
|
* Try to align nodes into vertical "blocks" where possible. This algorithm
|
|
283
283
|
* attempts to align a node with one of its median neighbors. If the edge
|
|
@@ -495,7 +495,7 @@ let offset=Math.min(...g.nodes().map(v=>g.node(v).rank));let layers=[];g.nodes()
|
|
|
495
495
|
/*
|
|
496
496
|
* Returns a new function that wraps `fn` with a timer. The wrapper logs the
|
|
497
497
|
* time it takes to execute the function.
|
|
498
|
-
*/function time(name,fn){let start=Date.now();try{return fn()}finally{console.log(name+" time: "+(Date.now()-start)+"ms")}}function notime(name,fn){return fn()}let idCounter=0;function uniqueId(prefix){var id=++idCounter;return toString(prefix)+id}function range(start,limit,step=1){if(limit==null){limit=start;start=0}let endCon=i=>i<limit;if(step<0){endCon=i=>limit<i}const range=[];for(let i=start;endCon(i);i+=step){range.push(i)}return range}function pick(source,keys){const dest={};for(const key of keys){if(source[key]!==undefined){dest[key]=source[key]}}return dest}function mapValues(obj,funcOrProp){let func=funcOrProp;if(typeof funcOrProp==="string"){func=val=>val[funcOrProp]}return Object.entries(obj).reduce((acc,[k,v])=>{acc[k]=func(v,k);return acc},{})}function zipObject(props,values){return props.reduce((acc,key,i)=>{acc[key]=values[i];return acc},{})}},{"@dagrejs/graphlib":29}],28:[function(require,module,exports){module.exports="1.
|
|
498
|
+
*/function time(name,fn){let start=Date.now();try{return fn()}finally{console.log(name+" time: "+(Date.now()-start)+"ms")}}function notime(name,fn){return fn()}let idCounter=0;function uniqueId(prefix){var id=++idCounter;return toString(prefix)+id}function range(start,limit,step=1){if(limit==null){limit=start;start=0}let endCon=i=>i<limit;if(step<0){endCon=i=>limit<i}const range=[];for(let i=start;endCon(i);i+=step){range.push(i)}return range}function pick(source,keys){const dest={};for(const key of keys){if(source[key]!==undefined){dest[key]=source[key]}}return dest}function mapValues(obj,funcOrProp){let func=funcOrProp;if(typeof funcOrProp==="string"){func=val=>val[funcOrProp]}return Object.entries(obj).reduce((acc,[k,v])=>{acc[k]=func(v,k);return acc},{})}function zipObject(props,values){return props.reduce((acc,key,i)=>{acc[key]=values[i];return acc},{})}},{"@dagrejs/graphlib":29}],28:[function(require,module,exports){module.exports="1.1.1"},{}],29:[function(require,module,exports){
|
|
499
499
|
/**
|
|
500
500
|
* Copyright (c) 2014, Chris Pettitt
|
|
501
501
|
* All rights reserved.
|
|
@@ -798,4 +798,4 @@ module.exports={Graph:require("./graph"),version:require("./version")}},{"./grap
|
|
|
798
798
|
* // ['a', 'b']
|
|
799
799
|
* g2.edges()
|
|
800
800
|
* // [ { v: 'a', w: 'b' } ]
|
|
801
|
-
*/function read(json){var g=new Graph(json.options).setGraph(json.value);json.nodes.forEach(function(entry){g.setNode(entry.v,entry.value);if(entry.parent){g.setParent(entry.v,entry.parent)}});json.edges.forEach(function(entry){g.setEdge({v:entry.v,w:entry.w,name:entry.name},entry.value)});return g}},{"./graph":44}],47:[function(require,module,exports){module.exports="2.1
|
|
801
|
+
*/function read(json){var g=new Graph(json.options).setGraph(json.value);json.nodes.forEach(function(entry){g.setNode(entry.v,entry.value);if(entry.parent){g.setParent(entry.v,entry.parent)}});json.edges.forEach(function(entry){g.setEdge({v:entry.v,w:entry.w,name:entry.name},entry.value)});return g}},{"./graph":44}],47:[function(require,module,exports){module.exports="2.2.1"},{}]},{},[1])(1)});
|
package/lib/acyclic.js
CHANGED
|
@@ -1,32 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
exports
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
let greedyFAS = require("./greedy-fas");
|
|
4
|
+
let uniqueId = require("./util").uniqueId;
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
run: run,
|
|
8
|
+
undo: undo
|
|
9
|
+
};
|
|
10
|
+
|
|
11
11
|
function run(g) {
|
|
12
|
-
let fas = g.graph().acyclicer === "greedy"
|
|
12
|
+
let fas = (g.graph().acyclicer === "greedy"
|
|
13
|
+
? greedyFAS(g, weightFn(g))
|
|
14
|
+
: dfsFAS(g));
|
|
13
15
|
fas.forEach(e => {
|
|
14
16
|
let label = g.edge(e);
|
|
15
17
|
g.removeEdge(e);
|
|
16
18
|
label.forwardName = e.name;
|
|
17
19
|
label.reversed = true;
|
|
18
|
-
g.setEdge(e.w, e.v, label,
|
|
20
|
+
g.setEdge(e.w, e.v, label, uniqueId("rev"));
|
|
19
21
|
});
|
|
22
|
+
|
|
20
23
|
function weightFn(g) {
|
|
21
24
|
return e => {
|
|
22
25
|
return g.edge(e).weight;
|
|
23
26
|
};
|
|
24
27
|
}
|
|
25
28
|
}
|
|
29
|
+
|
|
26
30
|
function dfsFAS(g) {
|
|
27
31
|
let fas = [];
|
|
28
32
|
let stack = {};
|
|
29
33
|
let visited = {};
|
|
34
|
+
|
|
30
35
|
function dfs(v) {
|
|
31
36
|
if (visited.hasOwnProperty(v)) {
|
|
32
37
|
return;
|
|
@@ -42,14 +47,17 @@ function dfsFAS(g) {
|
|
|
42
47
|
});
|
|
43
48
|
delete stack[v];
|
|
44
49
|
}
|
|
50
|
+
|
|
45
51
|
g.nodes().forEach(dfs);
|
|
46
52
|
return fas;
|
|
47
53
|
}
|
|
54
|
+
|
|
48
55
|
function undo(g) {
|
|
49
56
|
g.edges().forEach(e => {
|
|
50
57
|
let label = g.edge(e);
|
|
51
58
|
if (label.reversed) {
|
|
52
59
|
g.removeEdge(e);
|
|
60
|
+
|
|
53
61
|
let forwardName = label.forwardName;
|
|
54
62
|
delete label.reversed;
|
|
55
63
|
delete label.forwardName;
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
let util = require("./util");
|
|
2
|
+
|
|
3
|
+
module.exports = addBorderSegments;
|
|
2
4
|
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = addBorderSegments;
|
|
7
|
-
var util = _interopRequireWildcard(require("./util.js"));
|
|
8
|
-
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
9
|
-
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
10
5
|
function addBorderSegments(g) {
|
|
11
6
|
function dfs(v) {
|
|
12
7
|
let children = g.children(v);
|
|
@@ -14,32 +9,29 @@ function addBorderSegments(g) {
|
|
|
14
9
|
if (children.length) {
|
|
15
10
|
children.forEach(dfs);
|
|
16
11
|
}
|
|
12
|
+
|
|
17
13
|
if (node.hasOwnProperty("minRank")) {
|
|
18
14
|
node.borderLeft = [];
|
|
19
15
|
node.borderRight = [];
|
|
20
|
-
for (let rank = node.minRank, maxRank = node.maxRank + 1;
|
|
16
|
+
for (let rank = node.minRank, maxRank = node.maxRank + 1;
|
|
17
|
+
rank < maxRank;
|
|
18
|
+
++rank) {
|
|
21
19
|
addBorderNode(g, "borderLeft", "_bl", v, node, rank);
|
|
22
20
|
addBorderNode(g, "borderRight", "_br", v, node, rank);
|
|
23
21
|
}
|
|
24
22
|
}
|
|
25
23
|
}
|
|
24
|
+
|
|
26
25
|
g.children().forEach(dfs);
|
|
27
26
|
}
|
|
27
|
+
|
|
28
28
|
function addBorderNode(g, prop, prefix, sg, sgNode, rank) {
|
|
29
|
-
let label = {
|
|
30
|
-
width: 0,
|
|
31
|
-
height: 0,
|
|
32
|
-
rank: rank,
|
|
33
|
-
borderType: prop
|
|
34
|
-
};
|
|
29
|
+
let label = { width: 0, height: 0, rank: rank, borderType: prop };
|
|
35
30
|
let prev = sgNode[prop][rank - 1];
|
|
36
31
|
let curr = util.addDummyNode(g, "border", label, prefix);
|
|
37
32
|
sgNode[prop][rank] = curr;
|
|
38
33
|
g.setParent(curr, sg);
|
|
39
34
|
if (prev) {
|
|
40
|
-
g.setEdge(prev, curr, {
|
|
41
|
-
weight: 1
|
|
42
|
-
});
|
|
35
|
+
g.setEdge(prev, curr, { weight: 1 });
|
|
43
36
|
}
|
|
44
37
|
}
|
|
45
|
-
module.exports = exports.default;
|
package/lib/coordinate-system.js
CHANGED
|
@@ -1,37 +1,43 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
module.exports = {
|
|
4
|
+
adjust: adjust,
|
|
5
|
+
undo: undo
|
|
6
|
+
};
|
|
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
|
function undo(g) {
|
|
15
16
|
let rankDir = g.graph().rankdir.toLowerCase();
|
|
16
17
|
if (rankDir === "bt" || rankDir === "rl") {
|
|
17
18
|
reverseY(g);
|
|
18
19
|
}
|
|
20
|
+
|
|
19
21
|
if (rankDir === "lr" || rankDir === "rl") {
|
|
20
22
|
swapXY(g);
|
|
21
23
|
swapWidthHeight(g);
|
|
22
24
|
}
|
|
23
25
|
}
|
|
26
|
+
|
|
24
27
|
function swapWidthHeight(g) {
|
|
25
28
|
g.nodes().forEach(v => swapWidthHeightOne(g.node(v)));
|
|
26
29
|
g.edges().forEach(e => swapWidthHeightOne(g.edge(e)));
|
|
27
30
|
}
|
|
31
|
+
|
|
28
32
|
function swapWidthHeightOne(attrs) {
|
|
29
33
|
let w = attrs.width;
|
|
30
34
|
attrs.width = attrs.height;
|
|
31
35
|
attrs.height = w;
|
|
32
36
|
}
|
|
37
|
+
|
|
33
38
|
function reverseY(g) {
|
|
34
39
|
g.nodes().forEach(v => reverseYOne(g.node(v)));
|
|
40
|
+
|
|
35
41
|
g.edges().forEach(e => {
|
|
36
42
|
let edge = g.edge(e);
|
|
37
43
|
edge.points.forEach(reverseYOne);
|
|
@@ -40,11 +46,14 @@ function reverseY(g) {
|
|
|
40
46
|
}
|
|
41
47
|
});
|
|
42
48
|
}
|
|
49
|
+
|
|
43
50
|
function reverseYOne(attrs) {
|
|
44
51
|
attrs.y = -attrs.y;
|
|
45
52
|
}
|
|
53
|
+
|
|
46
54
|
function swapXY(g) {
|
|
47
55
|
g.nodes().forEach(v => swapXYOne(g.node(v)));
|
|
56
|
+
|
|
48
57
|
g.edges().forEach(e => {
|
|
49
58
|
let edge = g.edge(e);
|
|
50
59
|
edge.points.forEach(swapXYOne);
|
|
@@ -53,6 +62,7 @@ function swapXY(g) {
|
|
|
53
62
|
}
|
|
54
63
|
});
|
|
55
64
|
}
|
|
65
|
+
|
|
56
66
|
function swapXYOne(attrs) {
|
|
57
67
|
let x = attrs.x;
|
|
58
68
|
attrs.x = attrs.y;
|
package/lib/data/list.js
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
1
|
/*
|
|
8
2
|
* Simple doubly linked list implementation derived from Cormen, et al.,
|
|
9
3
|
* "Introduction to Algorithms".
|
|
@@ -15,6 +9,7 @@ class List {
|
|
|
15
9
|
sentinel._next = sentinel._prev = sentinel;
|
|
16
10
|
this._sentinel = sentinel;
|
|
17
11
|
}
|
|
12
|
+
|
|
18
13
|
dequeue() {
|
|
19
14
|
let sentinel = this._sentinel;
|
|
20
15
|
let entry = sentinel._prev;
|
|
@@ -23,6 +18,7 @@ class List {
|
|
|
23
18
|
return entry;
|
|
24
19
|
}
|
|
25
20
|
}
|
|
21
|
+
|
|
26
22
|
enqueue(entry) {
|
|
27
23
|
let sentinel = this._sentinel;
|
|
28
24
|
if (entry._prev && entry._next) {
|
|
@@ -33,6 +29,7 @@ class List {
|
|
|
33
29
|
sentinel._next = entry;
|
|
34
30
|
entry._prev = sentinel;
|
|
35
31
|
}
|
|
32
|
+
|
|
36
33
|
toString() {
|
|
37
34
|
let strs = [];
|
|
38
35
|
let sentinel = this._sentinel;
|
|
@@ -44,16 +41,18 @@ class List {
|
|
|
44
41
|
return "[" + strs.join(", ") + "]";
|
|
45
42
|
}
|
|
46
43
|
}
|
|
47
|
-
|
|
44
|
+
|
|
48
45
|
function unlink(entry) {
|
|
49
46
|
entry._prev._next = entry._next;
|
|
50
47
|
entry._next._prev = entry._prev;
|
|
51
48
|
delete entry._next;
|
|
52
49
|
delete entry._prev;
|
|
53
50
|
}
|
|
51
|
+
|
|
54
52
|
function filterOutLinks(k, v) {
|
|
55
53
|
if (k !== "_next" && k !== "_prev") {
|
|
56
54
|
return v;
|
|
57
55
|
}
|
|
58
56
|
}
|
|
59
|
-
|
|
57
|
+
|
|
58
|
+
module.exports = List;
|
package/lib/debug.js
CHANGED
|
@@ -1,42 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
let util = require("./util");
|
|
2
|
+
let Graph = require("@dagrejs/graphlib").Graph;
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
exports.default = debugOrdering;
|
|
7
|
-
var util = _interopRequireWildcard(require("./util.js"));
|
|
8
|
-
var _graphlib = require("@dagrejs/graphlib");
|
|
9
|
-
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
10
|
-
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
11
|
-
// web-devs write a <script type="importmap"> to map
|
|
12
|
-
// nodejs paths to actual http://paths
|
|
4
|
+
module.exports = {
|
|
5
|
+
debugOrdering: debugOrdering
|
|
6
|
+
};
|
|
13
7
|
|
|
14
8
|
/* istanbul ignore next */
|
|
15
9
|
function debugOrdering(g) {
|
|
16
10
|
let layerMatrix = util.buildLayerMatrix(g);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}).setGraph({});
|
|
11
|
+
|
|
12
|
+
let h = new Graph({ compound: true, multigraph: true }).setGraph({});
|
|
13
|
+
|
|
21
14
|
g.nodes().forEach(v => {
|
|
22
|
-
h.setNode(v, {
|
|
23
|
-
label: v
|
|
24
|
-
});
|
|
15
|
+
h.setNode(v, { label: v });
|
|
25
16
|
h.setParent(v, "layer" + g.node(v).rank);
|
|
26
17
|
});
|
|
18
|
+
|
|
27
19
|
g.edges().forEach(e => h.setEdge(e.v, e.w, {}, e.name));
|
|
20
|
+
|
|
28
21
|
layerMatrix.forEach((layer, i) => {
|
|
29
22
|
let layerV = "layer" + i;
|
|
30
|
-
h.setNode(layerV, {
|
|
31
|
-
rank: "same"
|
|
32
|
-
});
|
|
23
|
+
h.setNode(layerV, { rank: "same" });
|
|
33
24
|
layer.reduce((u, v) => {
|
|
34
|
-
h.setEdge(u, v, {
|
|
35
|
-
style: "invis"
|
|
36
|
-
});
|
|
25
|
+
h.setEdge(u, v, { style: "invis" });
|
|
37
26
|
return v;
|
|
38
27
|
});
|
|
39
28
|
});
|
|
29
|
+
|
|
40
30
|
return h;
|
|
41
31
|
}
|
|
42
|
-
module.exports = exports.default;
|
package/lib/greedy-fas.js
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = greedyFAS;
|
|
7
|
-
var _graphlib = require("@dagrejs/graphlib");
|
|
8
|
-
var _list = _interopRequireDefault(require("./data/list.js"));
|
|
9
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
10
|
-
// web-devs write a <script type="importmap"> to map
|
|
11
|
-
// nodejs paths to actual http://paths
|
|
1
|
+
let Graph = require("@dagrejs/graphlib").Graph;
|
|
2
|
+
let List = require("./data/list");
|
|
12
3
|
|
|
13
4
|
/*
|
|
14
5
|
* A greedy heuristic for finding a feedback arc set for a graph. A feedback
|
|
@@ -17,8 +8,10 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
17
8
|
* effective heuristic for the feedback arc set problem." This implementation
|
|
18
9
|
* adjusts that from the paper to allow for weighted edges.
|
|
19
10
|
*/
|
|
11
|
+
module.exports = greedyFAS;
|
|
20
12
|
|
|
21
13
|
let DEFAULT_WEIGHT_FN = () => 1;
|
|
14
|
+
|
|
22
15
|
function greedyFAS(g, weightFn) {
|
|
23
16
|
if (g.nodeCount() <= 1) {
|
|
24
17
|
return [];
|
|
@@ -29,18 +22,16 @@ function greedyFAS(g, weightFn) {
|
|
|
29
22
|
// Expand multi-edges
|
|
30
23
|
return results.flatMap(e => g.outEdges(e.v, e.w));
|
|
31
24
|
}
|
|
25
|
+
|
|
32
26
|
function doGreedyFAS(g, buckets, zeroIdx) {
|
|
33
27
|
let results = [];
|
|
34
28
|
let sources = buckets[buckets.length - 1];
|
|
35
29
|
let sinks = buckets[0];
|
|
30
|
+
|
|
36
31
|
let entry;
|
|
37
32
|
while (g.nodeCount()) {
|
|
38
|
-
while (entry = sinks.dequeue())
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
while (entry = sources.dequeue()) {
|
|
42
|
-
removeNode(g, buckets, zeroIdx, entry);
|
|
43
|
-
}
|
|
33
|
+
while ((entry = sinks.dequeue())) { removeNode(g, buckets, zeroIdx, entry); }
|
|
34
|
+
while ((entry = sources.dequeue())) { removeNode(g, buckets, zeroIdx, entry); }
|
|
44
35
|
if (g.nodeCount()) {
|
|
45
36
|
for (let i = buckets.length - 2; i > 0; --i) {
|
|
46
37
|
entry = buckets[i].dequeue();
|
|
@@ -51,22 +42,25 @@ function doGreedyFAS(g, buckets, zeroIdx) {
|
|
|
51
42
|
}
|
|
52
43
|
}
|
|
53
44
|
}
|
|
45
|
+
|
|
54
46
|
return results;
|
|
55
47
|
}
|
|
48
|
+
|
|
56
49
|
function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
|
|
57
50
|
let results = collectPredecessors ? [] : undefined;
|
|
51
|
+
|
|
58
52
|
g.inEdges(entry.v).forEach(edge => {
|
|
59
53
|
let weight = g.edge(edge);
|
|
60
54
|
let uEntry = g.node(edge.v);
|
|
55
|
+
|
|
61
56
|
if (collectPredecessors) {
|
|
62
|
-
results.push({
|
|
63
|
-
v: edge.v,
|
|
64
|
-
w: edge.w
|
|
65
|
-
});
|
|
57
|
+
results.push({ v: edge.v, w: edge.w });
|
|
66
58
|
}
|
|
59
|
+
|
|
67
60
|
uEntry.out -= weight;
|
|
68
61
|
assignBucket(buckets, zeroIdx, uEntry);
|
|
69
62
|
});
|
|
63
|
+
|
|
70
64
|
g.outEdges(entry.v).forEach(edge => {
|
|
71
65
|
let weight = g.edge(edge);
|
|
72
66
|
let w = edge.w;
|
|
@@ -74,19 +68,19 @@ function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
|
|
|
74
68
|
wEntry["in"] -= weight;
|
|
75
69
|
assignBucket(buckets, zeroIdx, wEntry);
|
|
76
70
|
});
|
|
71
|
+
|
|
77
72
|
g.removeNode(entry.v);
|
|
73
|
+
|
|
78
74
|
return results;
|
|
79
75
|
}
|
|
76
|
+
|
|
80
77
|
function buildState(g, weightFn) {
|
|
81
|
-
let fasGraph = new
|
|
78
|
+
let fasGraph = new Graph();
|
|
82
79
|
let maxIn = 0;
|
|
83
80
|
let maxOut = 0;
|
|
81
|
+
|
|
84
82
|
g.nodes().forEach(v => {
|
|
85
|
-
fasGraph.setNode(v, {
|
|
86
|
-
v: v,
|
|
87
|
-
"in": 0,
|
|
88
|
-
out: 0
|
|
89
|
-
});
|
|
83
|
+
fasGraph.setNode(v, { v: v, "in": 0, out: 0 });
|
|
90
84
|
});
|
|
91
85
|
|
|
92
86
|
// Aggregate weights on nodes, but also sum the weights across multi-edges
|
|
@@ -97,19 +91,19 @@ function buildState(g, weightFn) {
|
|
|
97
91
|
let edgeWeight = prevWeight + weight;
|
|
98
92
|
fasGraph.setEdge(e.v, e.w, edgeWeight);
|
|
99
93
|
maxOut = Math.max(maxOut, fasGraph.node(e.v).out += weight);
|
|
100
|
-
maxIn
|
|
94
|
+
maxIn = Math.max(maxIn, fasGraph.node(e.w)["in"] += weight);
|
|
101
95
|
});
|
|
102
|
-
|
|
96
|
+
|
|
97
|
+
let buckets = range(maxOut + maxIn + 3).map(() => new List());
|
|
103
98
|
let zeroIdx = maxIn + 1;
|
|
99
|
+
|
|
104
100
|
fasGraph.nodes().forEach(v => {
|
|
105
101
|
assignBucket(buckets, zeroIdx, fasGraph.node(v));
|
|
106
102
|
});
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
buckets: buckets,
|
|
110
|
-
zeroIdx: zeroIdx
|
|
111
|
-
};
|
|
103
|
+
|
|
104
|
+
return { graph: fasGraph, buckets: buckets, zeroIdx: zeroIdx };
|
|
112
105
|
}
|
|
106
|
+
|
|
113
107
|
function assignBucket(buckets, zeroIdx, entry) {
|
|
114
108
|
if (!entry.out) {
|
|
115
109
|
buckets[0].enqueue(entry);
|
|
@@ -119,11 +113,12 @@ function assignBucket(buckets, zeroIdx, entry) {
|
|
|
119
113
|
buckets[entry.out - entry["in"] + zeroIdx].enqueue(entry);
|
|
120
114
|
}
|
|
121
115
|
}
|
|
116
|
+
|
|
122
117
|
function range(limit) {
|
|
123
118
|
const range = [];
|
|
124
119
|
for (let i = 0; i < limit; i++) {
|
|
125
120
|
range.push(i);
|
|
126
121
|
}
|
|
122
|
+
|
|
127
123
|
return range;
|
|
128
124
|
}
|
|
129
|
-
module.exports = exports.default;
|