@statewalker/fsm-charts 0.0.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/CHANGELOG.md +1 -0
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/dist/StateChart-DNGQd1XG.d.ts +53 -0
- package/dist/chunk-3GGM3ZWL.js +2685 -0
- package/dist/chunk-NXWOFQMO.js +10 -0
- package/dist/chunk-TPNWHU7Y.js +437 -0
- package/dist/index-layout.d.ts +96 -0
- package/dist/index-layout.js +2 -0
- package/dist/index-svg.d.ts +25 -0
- package/dist/index-svg.js +2 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/package.json +60 -0
- package/src/FsmStateConfig.ts +5 -0
- package/src/dagre/acyclic.d.ts +2 -0
- package/src/dagre/acyclic.js +60 -0
- package/src/dagre/add-border-segments.d.ts +1 -0
- package/src/dagre/add-border-segments.js +36 -0
- package/src/dagre/coordinate-system.d.ts +2 -0
- package/src/dagre/coordinate-system.js +75 -0
- package/src/dagre/data/list.d.ts +12 -0
- package/src/dagre/data/list.js +55 -0
- package/src/dagre/debug.d.ts +2 -0
- package/src/dagre/debug.js +32 -0
- package/src/dagre/greedy-fas.d.ts +1 -0
- package/src/dagre/greedy-fas.js +126 -0
- package/src/dagre/index.d.ts +5 -0
- package/src/dagre/index.js +6 -0
- package/src/dagre/layout.d.ts +1 -0
- package/src/dagre/layout.js +466 -0
- package/src/dagre/nesting-graph.d.ts +2 -0
- package/src/dagre/nesting-graph.js +137 -0
- package/src/dagre/normalize.d.ts +2 -0
- package/src/dagre/normalize.js +91 -0
- package/src/dagre/order/add-subgraph-constraints.d.ts +1 -0
- package/src/dagre/order/add-subgraph-constraints.js +53 -0
- package/src/dagre/order/barycenter.d.ts +15 -0
- package/src/dagre/order/barycenter.js +31 -0
- package/src/dagre/order/build-layer-graph.d.ts +2 -0
- package/src/dagre/order/build-layer-graph.js +76 -0
- package/src/dagre/order/cross-count.d.ts +1 -0
- package/src/dagre/order/cross-count.js +82 -0
- package/src/dagre/order/index.d.ts +1 -0
- package/src/dagre/order/index.js +77 -0
- package/src/dagre/order/init-order.d.ts +1 -0
- package/src/dagre/order/init-order.js +44 -0
- package/src/dagre/order/resolve-conflicts.d.ts +1 -0
- package/src/dagre/order/resolve-conflicts.js +128 -0
- package/src/dagre/order/sort-subgraph.d.ts +8 -0
- package/src/dagre/order/sort-subgraph.js +78 -0
- package/src/dagre/order/sort.d.ts +6 -0
- package/src/dagre/order/sort.js +59 -0
- package/src/dagre/parent-dummy-chains.d.ts +1 -0
- package/src/dagre/parent-dummy-chains.js +86 -0
- package/src/dagre/position/bk.d.ts +31 -0
- package/src/dagre/position/bk.js +423 -0
- package/src/dagre/position/index.d.ts +1 -0
- package/src/dagre/position/index.js +31 -0
- package/src/dagre/rank/feasible-tree.d.ts +2 -0
- package/src/dagre/rank/feasible-tree.js +87 -0
- package/src/dagre/rank/index.d.ts +1 -0
- package/src/dagre/rank/index.js +52 -0
- package/src/dagre/rank/network-simplex.d.ts +16 -0
- package/src/dagre/rank/network-simplex.js +236 -0
- package/src/dagre/rank/util.d.ts +2 -0
- package/src/dagre/rank/util.js +63 -0
- package/src/dagre/util.d.ts +27 -0
- package/src/dagre/util.js +250 -0
- package/src/graphlib/alg/components.d.ts +1 -0
- package/src/graphlib/alg/components.js +27 -0
- package/src/graphlib/alg/dfs.d.ts +1 -0
- package/src/graphlib/alg/dfs.js +46 -0
- package/src/graphlib/alg/dijkstra-all.d.ts +1 -0
- package/src/graphlib/alg/dijkstra-all.js +14 -0
- package/src/graphlib/alg/dijkstra.d.ts +1 -0
- package/src/graphlib/alg/dijkstra.js +65 -0
- package/src/graphlib/alg/find-cycles.d.ts +1 -0
- package/src/graphlib/alg/find-cycles.js +10 -0
- package/src/graphlib/alg/floyd-warshall.d.ts +1 -0
- package/src/graphlib/alg/floyd-warshall.js +55 -0
- package/src/graphlib/alg/index.d.ts +24 -0
- package/src/graphlib/alg/index.js +25 -0
- package/src/graphlib/alg/is-acyclic.d.ts +1 -0
- package/src/graphlib/alg/is-acyclic.js +15 -0
- package/src/graphlib/alg/postorder.d.ts +1 -0
- package/src/graphlib/alg/postorder.js +7 -0
- package/src/graphlib/alg/preorder.d.ts +1 -0
- package/src/graphlib/alg/preorder.js +7 -0
- package/src/graphlib/alg/prim.d.ts +2 -0
- package/src/graphlib/alg/prim.js +52 -0
- package/src/graphlib/alg/tarjan.d.ts +1 -0
- package/src/graphlib/alg/tarjan.js +47 -0
- package/src/graphlib/alg/topsort.d.ts +5 -0
- package/src/graphlib/alg/topsort.js +36 -0
- package/src/graphlib/data/priority-queue.d.ts +59 -0
- package/src/graphlib/data/priority-queue.js +152 -0
- package/src/graphlib/graph.d.ts +55 -0
- package/src/graphlib/graph.js +510 -0
- package/src/graphlib/index.d.ts +3 -0
- package/src/graphlib/index.js +7 -0
- package/src/graphlib/json.d.ts +16 -0
- package/src/graphlib/json.js +63 -0
- package/src/index-layout.ts +1 -0
- package/src/index-svg.ts +1 -0
- package/src/index.ts +2 -0
- package/src/layout/Dimensions.ts +8 -0
- package/src/layout/GraphParamsProvider.ts +17 -0
- package/src/layout/Padding.ts +10 -0
- package/src/layout/Position.ts +4 -0
- package/src/layout/StateChart.ts +8 -0
- package/src/layout/StateGraphEdge.ts +14 -0
- package/src/layout/StateGraphNode.ts +12 -0
- package/src/layout/Transition.ts +5 -0
- package/src/layout/TransitionsGraph.ts +13 -0
- package/src/layout/buildCharts.ts +74 -0
- package/src/layout/buildFlatCharts.ts +142 -0
- package/src/layout/getGraphParamsProvider.ts +63 -0
- package/src/layout/getLabelDimensions.ts +59 -0
- package/src/layout/index.ts +15 -0
- package/src/lodash-es/_deleteme.js +291 -0
- package/src/lodash-es/index.ts +9 -0
- package/src/lodash-es/types.ts +35 -0
- package/src/svg/buildStatechartCss.ts +120 -0
- package/src/svg/buildStatechartSvg.ts +256 -0
- package/src/svg/buildStatechartsPanel.ts +38 -0
- package/src/svg/index.ts +3 -0
- package/src/utils/BasisCurve.ts +89 -0
- package/src/utils/getPadding.ts +13 -0
- package/src/utils/serializeAttrs.ts +28 -0
- package/src/utils/serializeStyle.ts +11 -0
- package/src/utils/toKebabCase.ts +18 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { _ } from '../../lodash-es/index.ts';
|
|
2
|
+
|
|
3
|
+
export { dfs };
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* A helper that preforms a pre- or post-order traversal on the input graph
|
|
7
|
+
* and returns the nodes in the order they were visited. If the graph is
|
|
8
|
+
* undirected then this algorithm will navigate using neighbors. If the graph
|
|
9
|
+
* is directed then this algorithm will navigate using successors.
|
|
10
|
+
*
|
|
11
|
+
* Order must be one of "pre" or "post".
|
|
12
|
+
*/
|
|
13
|
+
function dfs(g, vs, order) {
|
|
14
|
+
if (!_.isArray(vs)) {
|
|
15
|
+
vs = [vs];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
var navigation = (g.isDirected() ? g.successors : g.neighbors).bind(g);
|
|
19
|
+
|
|
20
|
+
var acc = [];
|
|
21
|
+
var visited = {};
|
|
22
|
+
_.each(vs, function (v) {
|
|
23
|
+
if (!g.hasNode(v)) {
|
|
24
|
+
throw new Error('Graph does not have node: ' + v);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
doDfs(g, v, order === 'post', visited, navigation, acc);
|
|
28
|
+
});
|
|
29
|
+
return acc;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function doDfs(g, v, postorder, visited, navigation, acc) {
|
|
33
|
+
if (!_.has(visited, v)) {
|
|
34
|
+
visited[v] = true;
|
|
35
|
+
|
|
36
|
+
if (!postorder) {
|
|
37
|
+
acc.push(v);
|
|
38
|
+
}
|
|
39
|
+
_.each(navigation(v), function (w) {
|
|
40
|
+
doDfs(g, w, postorder, visited, navigation, acc);
|
|
41
|
+
});
|
|
42
|
+
if (postorder) {
|
|
43
|
+
acc.push(v);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function dijkstraAll(g: any, weightFunc: any, edgeFunc: any): {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { _ } from '../../lodash-es/index.ts';
|
|
2
|
+
import { dijkstra } from './dijkstra.js';
|
|
3
|
+
|
|
4
|
+
export { dijkstraAll };
|
|
5
|
+
|
|
6
|
+
function dijkstraAll(g, weightFunc, edgeFunc) {
|
|
7
|
+
return _.transform(
|
|
8
|
+
g.nodes(),
|
|
9
|
+
function (acc, v) {
|
|
10
|
+
acc[v] = dijkstra(g, v, weightFunc, edgeFunc);
|
|
11
|
+
},
|
|
12
|
+
{}
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function dijkstra(g: any, source: any, weightFn: any, edgeFn: any): {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { _ } from '../../lodash-es/index.ts';
|
|
2
|
+
import { PriorityQueue } from '../data/priority-queue.js';
|
|
3
|
+
|
|
4
|
+
export { dijkstra };
|
|
5
|
+
|
|
6
|
+
var DEFAULT_WEIGHT_FUNC = _.constant(1);
|
|
7
|
+
|
|
8
|
+
function dijkstra(g, source, weightFn, edgeFn) {
|
|
9
|
+
return runDijkstra(
|
|
10
|
+
g,
|
|
11
|
+
String(source),
|
|
12
|
+
weightFn || DEFAULT_WEIGHT_FUNC,
|
|
13
|
+
edgeFn ||
|
|
14
|
+
function (v) {
|
|
15
|
+
return g.outEdges(v);
|
|
16
|
+
}
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function runDijkstra(g, source, weightFn, edgeFn) {
|
|
21
|
+
var results = {};
|
|
22
|
+
var pq = new PriorityQueue();
|
|
23
|
+
var v, vEntry;
|
|
24
|
+
|
|
25
|
+
var updateNeighbors = function (edge) {
|
|
26
|
+
var w = edge.v !== v ? edge.v : edge.w;
|
|
27
|
+
var wEntry = results[w];
|
|
28
|
+
var weight = weightFn(edge);
|
|
29
|
+
var distance = vEntry.distance + weight;
|
|
30
|
+
|
|
31
|
+
if (weight < 0) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
'dijkstra does not allow negative edge weights. ' +
|
|
34
|
+
'Bad edge: ' +
|
|
35
|
+
edge +
|
|
36
|
+
' Weight: ' +
|
|
37
|
+
weight
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (distance < wEntry.distance) {
|
|
42
|
+
wEntry.distance = distance;
|
|
43
|
+
wEntry.predecessor = v;
|
|
44
|
+
pq.decrease(w, distance);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
g.nodes().forEach(function (v) {
|
|
49
|
+
var distance = v === source ? 0 : Number.POSITIVE_INFINITY;
|
|
50
|
+
results[v] = { distance: distance };
|
|
51
|
+
pq.add(v, distance);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
while (pq.size() > 0) {
|
|
55
|
+
v = pq.removeMin();
|
|
56
|
+
vEntry = results[v];
|
|
57
|
+
if (vEntry.distance === Number.POSITIVE_INFINITY) {
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
edgeFn(v).forEach(updateNeighbors);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return results;
|
|
65
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function findCycles(g: any): any[];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { _ } from '../../lodash-es/index.ts';
|
|
2
|
+
import { tarjan } from './tarjan.js';
|
|
3
|
+
|
|
4
|
+
export { findCycles };
|
|
5
|
+
|
|
6
|
+
function findCycles(g) {
|
|
7
|
+
return _.filter(tarjan(g), function (cmpt) {
|
|
8
|
+
return cmpt.length > 1 || (cmpt.length === 1 && g.hasEdge(cmpt[0], cmpt[0]));
|
|
9
|
+
});
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function floydWarshall(g: any, weightFn: any, edgeFn: any): {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { _ } from '../../lodash-es/index.ts';
|
|
2
|
+
|
|
3
|
+
export { floydWarshall };
|
|
4
|
+
|
|
5
|
+
var DEFAULT_WEIGHT_FUNC = _.constant(1);
|
|
6
|
+
|
|
7
|
+
function floydWarshall(g, weightFn, edgeFn) {
|
|
8
|
+
return runFloydWarshall(
|
|
9
|
+
g,
|
|
10
|
+
weightFn || DEFAULT_WEIGHT_FUNC,
|
|
11
|
+
edgeFn ||
|
|
12
|
+
function (v) {
|
|
13
|
+
return g.outEdges(v);
|
|
14
|
+
}
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function runFloydWarshall(g, weightFn, edgeFn) {
|
|
19
|
+
var results = {};
|
|
20
|
+
var nodes = g.nodes();
|
|
21
|
+
|
|
22
|
+
nodes.forEach(function (v) {
|
|
23
|
+
results[v] = {};
|
|
24
|
+
results[v][v] = { distance: 0 };
|
|
25
|
+
nodes.forEach(function (w) {
|
|
26
|
+
if (v !== w) {
|
|
27
|
+
results[v][w] = { distance: Number.POSITIVE_INFINITY };
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
edgeFn(v).forEach(function (edge) {
|
|
31
|
+
var w = edge.v === v ? edge.w : edge.v;
|
|
32
|
+
var d = weightFn(edge);
|
|
33
|
+
results[v][w] = { distance: d, predecessor: v };
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
nodes.forEach(function (k) {
|
|
38
|
+
var rowK = results[k];
|
|
39
|
+
nodes.forEach(function (i) {
|
|
40
|
+
var rowI = results[i];
|
|
41
|
+
nodes.forEach(function (j) {
|
|
42
|
+
var ik = rowI[k];
|
|
43
|
+
var kj = rowK[j];
|
|
44
|
+
var ij = rowI[j];
|
|
45
|
+
var altDistance = ik.distance + kj.distance;
|
|
46
|
+
if (altDistance < ij.distance) {
|
|
47
|
+
ij.distance = altDistance;
|
|
48
|
+
ij.predecessor = kj.predecessor;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return results;
|
|
55
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { components } from './components.js';
|
|
2
|
+
import { dijkstra } from './dijkstra.js';
|
|
3
|
+
import { dijkstraAll } from './dijkstra-all.js';
|
|
4
|
+
import { findCycles } from './find-cycles.js';
|
|
5
|
+
import { floydWarshall } from './floyd-warshall.js';
|
|
6
|
+
import { isAcyclic } from './is-acyclic.js';
|
|
7
|
+
import { postorder } from './postorder.js';
|
|
8
|
+
import { preorder } from './preorder.js';
|
|
9
|
+
import { prim } from './prim.js';
|
|
10
|
+
import { tarjan } from './tarjan.js';
|
|
11
|
+
import { topsort } from './topsort.js';
|
|
12
|
+
export {
|
|
13
|
+
components,
|
|
14
|
+
dijkstra,
|
|
15
|
+
dijkstraAll,
|
|
16
|
+
findCycles,
|
|
17
|
+
floydWarshall,
|
|
18
|
+
isAcyclic,
|
|
19
|
+
postorder,
|
|
20
|
+
preorder,
|
|
21
|
+
prim,
|
|
22
|
+
tarjan,
|
|
23
|
+
topsort,
|
|
24
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { components } from './components.js';
|
|
2
|
+
import { dijkstra } from './dijkstra.js';
|
|
3
|
+
import { dijkstraAll } from './dijkstra-all.js';
|
|
4
|
+
import { findCycles } from './find-cycles.js';
|
|
5
|
+
import { floydWarshall } from './floyd-warshall.js';
|
|
6
|
+
import { isAcyclic } from './is-acyclic.js';
|
|
7
|
+
import { postorder } from './postorder.js';
|
|
8
|
+
import { preorder } from './preorder.js';
|
|
9
|
+
import { prim } from './prim.js';
|
|
10
|
+
import { tarjan } from './tarjan.js';
|
|
11
|
+
import { topsort } from './topsort.js';
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
components,
|
|
15
|
+
dijkstra,
|
|
16
|
+
dijkstraAll,
|
|
17
|
+
findCycles,
|
|
18
|
+
floydWarshall,
|
|
19
|
+
isAcyclic,
|
|
20
|
+
postorder,
|
|
21
|
+
preorder,
|
|
22
|
+
prim,
|
|
23
|
+
tarjan,
|
|
24
|
+
topsort,
|
|
25
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function isAcyclic(g: any): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function postorder(g: any, vs: any): any[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function preorder(g: any, vs: any): any[];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { _ } from '../../lodash-es/index.ts';
|
|
2
|
+
import { PriorityQueue } from '../data/priority-queue.js';
|
|
3
|
+
import { Graph } from '../graph.js';
|
|
4
|
+
|
|
5
|
+
export { prim };
|
|
6
|
+
|
|
7
|
+
function prim(g, weightFunc) {
|
|
8
|
+
var result = new Graph();
|
|
9
|
+
var parents = {};
|
|
10
|
+
var pq = new PriorityQueue();
|
|
11
|
+
var v;
|
|
12
|
+
|
|
13
|
+
function updateNeighbors(edge) {
|
|
14
|
+
var w = edge.v === v ? edge.w : edge.v;
|
|
15
|
+
var pri = pq.priority(w);
|
|
16
|
+
if (pri !== undefined) {
|
|
17
|
+
var edgeWeight = weightFunc(edge);
|
|
18
|
+
if (edgeWeight < pri) {
|
|
19
|
+
parents[w] = v;
|
|
20
|
+
pq.decrease(w, edgeWeight);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (g.nodeCount() === 0) {
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_.each(g.nodes(), function (v) {
|
|
30
|
+
pq.add(v, Number.POSITIVE_INFINITY);
|
|
31
|
+
result.setNode(v);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Start from an arbitrary node
|
|
35
|
+
pq.decrease(g.nodes()[0], 0);
|
|
36
|
+
|
|
37
|
+
var init = false;
|
|
38
|
+
while (pq.size() > 0) {
|
|
39
|
+
v = pq.removeMin();
|
|
40
|
+
if (_.has(parents, v)) {
|
|
41
|
+
result.setEdge(v, parents[v]);
|
|
42
|
+
} else if (init) {
|
|
43
|
+
throw new Error('Input graph is not connected: ' + g);
|
|
44
|
+
} else {
|
|
45
|
+
init = true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
g.nodeEdges(v).forEach(updateNeighbors);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function tarjan(g: any): any[];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { _ } from '../../lodash-es/index.ts';
|
|
2
|
+
|
|
3
|
+
export { tarjan };
|
|
4
|
+
|
|
5
|
+
function tarjan(g) {
|
|
6
|
+
var index = 0;
|
|
7
|
+
var stack = [];
|
|
8
|
+
var visited = {}; // node id -> { onStack, lowlink, index }
|
|
9
|
+
var results = [];
|
|
10
|
+
|
|
11
|
+
function dfs(v) {
|
|
12
|
+
var entry = (visited[v] = {
|
|
13
|
+
onStack: true,
|
|
14
|
+
lowlink: index,
|
|
15
|
+
index: index++,
|
|
16
|
+
});
|
|
17
|
+
stack.push(v);
|
|
18
|
+
|
|
19
|
+
g.successors(v).forEach(function (w) {
|
|
20
|
+
if (!_.has(visited, w)) {
|
|
21
|
+
dfs(w);
|
|
22
|
+
entry.lowlink = Math.min(entry.lowlink, visited[w].lowlink);
|
|
23
|
+
} else if (visited[w].onStack) {
|
|
24
|
+
entry.lowlink = Math.min(entry.lowlink, visited[w].index);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (entry.lowlink === entry.index) {
|
|
29
|
+
var cmpt = [];
|
|
30
|
+
var w;
|
|
31
|
+
do {
|
|
32
|
+
w = stack.pop();
|
|
33
|
+
visited[w].onStack = false;
|
|
34
|
+
cmpt.push(w);
|
|
35
|
+
} while (v !== w);
|
|
36
|
+
results.push(cmpt);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
g.nodes().forEach(function (v) {
|
|
41
|
+
if (!_.has(visited, v)) {
|
|
42
|
+
dfs(v);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return results;
|
|
47
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { _ } from '../../lodash-es/index.ts';
|
|
2
|
+
|
|
3
|
+
export { topsort, CycleException };
|
|
4
|
+
|
|
5
|
+
topsort.CycleException = CycleException;
|
|
6
|
+
|
|
7
|
+
function topsort(g) {
|
|
8
|
+
var visited = {};
|
|
9
|
+
var stack = {};
|
|
10
|
+
var results = [];
|
|
11
|
+
|
|
12
|
+
function visit(node) {
|
|
13
|
+
if (_.has(stack, node)) {
|
|
14
|
+
throw new CycleException();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!_.has(visited, node)) {
|
|
18
|
+
stack[node] = true;
|
|
19
|
+
visited[node] = true;
|
|
20
|
+
_.each(g.predecessors(node), visit);
|
|
21
|
+
delete stack[node];
|
|
22
|
+
results.push(node);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
_.each(g.sinks(), visit);
|
|
27
|
+
|
|
28
|
+
if (_.size(visited) !== g.nodeCount()) {
|
|
29
|
+
throw new CycleException();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return results;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function CycleException() {}
|
|
36
|
+
CycleException.prototype = new Error(); // must be an instance of Error to pass testing
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A min-priority queue data structure. This algorithm is derived from Cormen,
|
|
3
|
+
* et al., "Introduction to Algorithms". The basic idea of a min-priority
|
|
4
|
+
* queue is that you can efficiently (in O(1) time) get the smallest key in
|
|
5
|
+
* the queue. Adding and removing elements takes O(log n) time. A key can
|
|
6
|
+
* have its priority decreased in O(log n) time.
|
|
7
|
+
*/
|
|
8
|
+
export class PriorityQueue {
|
|
9
|
+
_arr: any[];
|
|
10
|
+
_keyIndices: {};
|
|
11
|
+
/**
|
|
12
|
+
* Returns the number of elements in the queue. Takes `O(1)` time.
|
|
13
|
+
*/
|
|
14
|
+
size(): number;
|
|
15
|
+
/**
|
|
16
|
+
* Returns the keys that are in the queue. Takes `O(n)` time.
|
|
17
|
+
*/
|
|
18
|
+
keys(): any[];
|
|
19
|
+
/**
|
|
20
|
+
* Returns `true` if **key** is in the queue and `false` if not.
|
|
21
|
+
*/
|
|
22
|
+
has(key: any): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Returns the priority for **key**. If **key** is not present in the queue
|
|
25
|
+
* then this function returns `undefined`. Takes `O(1)` time.
|
|
26
|
+
*
|
|
27
|
+
* @param {Object} key
|
|
28
|
+
*/
|
|
29
|
+
priority(key: any): any;
|
|
30
|
+
/**
|
|
31
|
+
* Returns the key for the minimum element in this queue. If the queue is
|
|
32
|
+
* empty this function throws an Error. Takes `O(1)` time.
|
|
33
|
+
*/
|
|
34
|
+
min(): any;
|
|
35
|
+
/**
|
|
36
|
+
* Inserts a new key into the priority queue. If the key already exists in
|
|
37
|
+
* the queue this function returns `false`; otherwise it will return `true`.
|
|
38
|
+
* Takes `O(n)` time.
|
|
39
|
+
*
|
|
40
|
+
* @param {Object} key the key to add
|
|
41
|
+
* @param {Number} priority the initial priority for the key
|
|
42
|
+
*/
|
|
43
|
+
add(key: any, priority: number): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Removes and returns the smallest key in the queue. Takes `O(log n)` time.
|
|
46
|
+
*/
|
|
47
|
+
removeMin(): any;
|
|
48
|
+
/**
|
|
49
|
+
* Decreases the priority for **key** to **priority**. If the new priority is
|
|
50
|
+
* greater than the previous priority, this function will throw an Error.
|
|
51
|
+
*
|
|
52
|
+
* @param {Object} key the key for which to raise priority
|
|
53
|
+
* @param {Number} priority the new priority for the key
|
|
54
|
+
*/
|
|
55
|
+
decrease(key: any, priority: number): void;
|
|
56
|
+
_heapify(i: any): void;
|
|
57
|
+
_decrease(index: any): void;
|
|
58
|
+
_swap(i: any, j: any): void;
|
|
59
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { _ } from '../../lodash-es/index.ts';
|
|
2
|
+
|
|
3
|
+
export { PriorityQueue };
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A min-priority queue data structure. This algorithm is derived from Cormen,
|
|
7
|
+
* et al., "Introduction to Algorithms". The basic idea of a min-priority
|
|
8
|
+
* queue is that you can efficiently (in O(1) time) get the smallest key in
|
|
9
|
+
* the queue. Adding and removing elements takes O(log n) time. A key can
|
|
10
|
+
* have its priority decreased in O(log n) time.
|
|
11
|
+
*/
|
|
12
|
+
class PriorityQueue {
|
|
13
|
+
constructor() {
|
|
14
|
+
this._arr = [];
|
|
15
|
+
this._keyIndices = {};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Returns the number of elements in the queue. Takes `O(1)` time.
|
|
19
|
+
*/
|
|
20
|
+
size() {
|
|
21
|
+
return this._arr.length;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Returns the keys that are in the queue. Takes `O(n)` time.
|
|
25
|
+
*/
|
|
26
|
+
keys() {
|
|
27
|
+
return this._arr.map(function (x) {
|
|
28
|
+
return x.key;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Returns `true` if **key** is in the queue and `false` if not.
|
|
33
|
+
*/
|
|
34
|
+
has(key) {
|
|
35
|
+
return _.has(this._keyIndices, key);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Returns the priority for **key**. If **key** is not present in the queue
|
|
39
|
+
* then this function returns `undefined`. Takes `O(1)` time.
|
|
40
|
+
*
|
|
41
|
+
* @param {Object} key
|
|
42
|
+
*/
|
|
43
|
+
priority(key) {
|
|
44
|
+
var index = this._keyIndices[key];
|
|
45
|
+
if (index !== undefined) {
|
|
46
|
+
return this._arr[index].priority;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Returns the key for the minimum element in this queue. If the queue is
|
|
51
|
+
* empty this function throws an Error. Takes `O(1)` time.
|
|
52
|
+
*/
|
|
53
|
+
min() {
|
|
54
|
+
if (this.size() === 0) {
|
|
55
|
+
throw new Error('Queue underflow');
|
|
56
|
+
}
|
|
57
|
+
return this._arr[0].key;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Inserts a new key into the priority queue. If the key already exists in
|
|
61
|
+
* the queue this function returns `false`; otherwise it will return `true`.
|
|
62
|
+
* Takes `O(n)` time.
|
|
63
|
+
*
|
|
64
|
+
* @param {Object} key the key to add
|
|
65
|
+
* @param {Number} priority the initial priority for the key
|
|
66
|
+
*/
|
|
67
|
+
add(key, priority) {
|
|
68
|
+
var keyIndices = this._keyIndices;
|
|
69
|
+
key = String(key);
|
|
70
|
+
if (!_.has(keyIndices, key)) {
|
|
71
|
+
var arr = this._arr;
|
|
72
|
+
var index = arr.length;
|
|
73
|
+
keyIndices[key] = index;
|
|
74
|
+
arr.push({ key: key, priority: priority });
|
|
75
|
+
this._decrease(index);
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Removes and returns the smallest key in the queue. Takes `O(log n)` time.
|
|
82
|
+
*/
|
|
83
|
+
removeMin() {
|
|
84
|
+
this._swap(0, this._arr.length - 1);
|
|
85
|
+
var min = this._arr.pop();
|
|
86
|
+
delete this._keyIndices[min.key];
|
|
87
|
+
this._heapify(0);
|
|
88
|
+
return min.key;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Decreases the priority for **key** to **priority**. If the new priority is
|
|
92
|
+
* greater than the previous priority, this function will throw an Error.
|
|
93
|
+
*
|
|
94
|
+
* @param {Object} key the key for which to raise priority
|
|
95
|
+
* @param {Number} priority the new priority for the key
|
|
96
|
+
*/
|
|
97
|
+
decrease(key, priority) {
|
|
98
|
+
var index = this._keyIndices[key];
|
|
99
|
+
if (priority > this._arr[index].priority) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
'New priority is greater than current priority. ' +
|
|
102
|
+
'Key: ' +
|
|
103
|
+
key +
|
|
104
|
+
' Old: ' +
|
|
105
|
+
this._arr[index].priority +
|
|
106
|
+
' New: ' +
|
|
107
|
+
priority
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
this._arr[index].priority = priority;
|
|
111
|
+
this._decrease(index);
|
|
112
|
+
}
|
|
113
|
+
_heapify(i) {
|
|
114
|
+
var arr = this._arr;
|
|
115
|
+
var l = 2 * i;
|
|
116
|
+
var r = l + 1;
|
|
117
|
+
var largest = i;
|
|
118
|
+
if (l < arr.length) {
|
|
119
|
+
largest = arr[l].priority < arr[largest].priority ? l : largest;
|
|
120
|
+
if (r < arr.length) {
|
|
121
|
+
largest = arr[r].priority < arr[largest].priority ? r : largest;
|
|
122
|
+
}
|
|
123
|
+
if (largest !== i) {
|
|
124
|
+
this._swap(i, largest);
|
|
125
|
+
this._heapify(largest);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
_decrease(index) {
|
|
130
|
+
var arr = this._arr;
|
|
131
|
+
var priority = arr[index].priority;
|
|
132
|
+
var parent;
|
|
133
|
+
while (index !== 0) {
|
|
134
|
+
parent = index >> 1;
|
|
135
|
+
if (arr[parent].priority < priority) {
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
this._swap(index, parent);
|
|
139
|
+
index = parent;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
_swap(i, j) {
|
|
143
|
+
var arr = this._arr;
|
|
144
|
+
var keyIndices = this._keyIndices;
|
|
145
|
+
var origArrI = arr[i];
|
|
146
|
+
var origArrJ = arr[j];
|
|
147
|
+
arr[i] = origArrJ;
|
|
148
|
+
arr[j] = origArrI;
|
|
149
|
+
keyIndices[origArrJ.key] = i;
|
|
150
|
+
keyIndices[origArrI.key] = j;
|
|
151
|
+
}
|
|
152
|
+
}
|