occam-directed-graphs 3.0.36 → 3.0.41
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 +34 -49
- package/lib/cycle.js +31 -14
- package/lib/directedGraph.js +215 -201
- package/lib/index.js +9 -1
- package/lib/utilities/index.js +40 -0
- package/lib/utilities/search.js +91 -0
- package/lib/utilities/vertex.js +11 -50
- package/lib/vertex.js +88 -251
- package/package.json +7 -8
- package/src/cycle.js +8 -28
- package/src/directedGraph.js +277 -198
- package/src/index.js +2 -0
- package/src/utilities/index.js +25 -0
- package/src/utilities/search.js +69 -0
- package/src/utilities/vertex.js +6 -61
- package/src/vertex.js +92 -261
- package/test/cirectedGraph.js +589 -0
- package/bin/main.js +0 -15
- package/lib/directedAcyclicGraph.js +0 -364
- package/lib/example.js +0 -21
- package/lib/partialCycle.js +0 -102
- package/lib/utilities/edge.js +0 -65
- package/src/directedAcyclicGraph.js +0 -422
- package/src/example.js +0 -22
- package/src/partialCycle.js +0 -69
- package/src/utilities/edge.js +0 -58
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Occam Directed Graphs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[Occam](https://github.com/djalbat/occam)'s directed graphs.
|
|
4
4
|
|
|
5
5
|
### Contents
|
|
6
6
|
|
|
@@ -8,12 +8,13 @@ Directed graphs comprised of directed acyclic graphs together with cycles for [O
|
|
|
8
8
|
- [Installation](#installation)
|
|
9
9
|
- [Usage](#usage)
|
|
10
10
|
- [Building](#building)
|
|
11
|
+
- [Running the tests](#running-the-tests)
|
|
11
12
|
- [References](#references)
|
|
12
13
|
- [Contact](#contact)
|
|
13
14
|
|
|
14
15
|
## Introduction
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
This implementation extends an incremental algorithm for directed graphs, one that returns a topological ordering for the graph. If one or more cyclic edges are added then the extended algorithm handles it gracefully rather than throwing an error. In these cases a cycle can be returned rather than a topological ordering. If all cyclic edges are removed thereafter then the algorithm recovers and a topological ordering can be returned again.
|
|
17
18
|
|
|
18
19
|
## Installation
|
|
19
20
|
|
|
@@ -31,53 +32,47 @@ You can also clone the repository with [Git](https://git-scm.com/)...
|
|
|
31
32
|
|
|
32
33
|
## Usage
|
|
33
34
|
|
|
34
|
-
An empty directed graph can be created by calling the `fromNothing()` factory method
|
|
35
|
+
An empty directed graph can be created by calling the `fromNothing()` factory method:
|
|
35
36
|
|
|
36
37
|
```
|
|
37
38
|
import { DirectedGraph } from "occam-directed-graphs";
|
|
38
39
|
|
|
39
|
-
const directedGraph = DirectedGraph.fromNothing()
|
|
40
|
-
|
|
41
|
-
sourceVertexName = "j",
|
|
42
|
-
targetVertexName = "k";
|
|
40
|
+
const directedGraph = DirectedGraph.fromNothing();
|
|
41
|
+
```
|
|
43
42
|
|
|
44
|
-
|
|
43
|
+
After instantiation, vertices and edges can be added incrementally:
|
|
45
44
|
|
|
46
|
-
directedGraph.addEdgeByVertexNames(sourceVertexName, targetVertexName);
|
|
47
45
|
```
|
|
46
|
+
import { Edge } from "occam-directed-graphs";
|
|
48
47
|
|
|
49
|
-
|
|
48
|
+
const vertexName = "i";
|
|
50
49
|
|
|
51
|
-
|
|
50
|
+
directedGraph.addVertexByVertexName(vertexName);
|
|
51
|
+
|
|
52
|
+
const sourceVertexName = "j",
|
|
53
|
+
targetVertexName = "k",
|
|
54
|
+
edge = Edge.fromSourceVertexNameAndTargetVertexName(sourceVertexName, targetVertexName);
|
|
52
55
|
|
|
56
|
+
directedGraph.addEdge(edge);
|
|
53
57
|
```
|
|
54
|
-
import { DirectedGraph } from "occam-directed-graphs";
|
|
55
58
|
|
|
56
|
-
|
|
59
|
+
Note that there is no need to add vertices explicitly, they will be added whenever necessary when edges that reference them are added.
|
|
57
60
|
|
|
58
|
-
|
|
59
|
-
["b", ["c"]],
|
|
60
|
-
["d", ["c"]],
|
|
61
|
-
["e", []],
|
|
62
|
-
["f", ["g"]],
|
|
63
|
-
["h", ["g"]]
|
|
61
|
+
You can also remove vertices and edges. Removing a vertex could result in removing edges. When you remove an edge, you can additionally specify that the any stranded vertices that result are also removed:
|
|
64
62
|
|
|
65
|
-
]);
|
|
66
63
|
```
|
|
64
|
+
import { Edge } from "occam-directed-graphs";
|
|
67
65
|
|
|
68
|
-
|
|
66
|
+
const vertexName = "i";
|
|
69
67
|
|
|
70
|
-
|
|
68
|
+
directedGraph.removeVertexByName(vertexName);
|
|
71
69
|
|
|
72
|
-
|
|
73
|
-
const vertexName = "i",
|
|
74
|
-
sourceVertexName = "j",
|
|
70
|
+
const sourceVertexName = "j",
|
|
75
71
|
targetVertexName = "k",
|
|
76
|
-
removeStrandedVertices = true
|
|
77
|
-
|
|
78
|
-
directedGraph.removeVertexByName(vertexName);
|
|
72
|
+
removeStrandedVertices = true,
|
|
73
|
+
edge = Edge.fromSourceVertexNameAndTargetVertexName(sourceVertexName, targetVertexName);
|
|
79
74
|
|
|
80
|
-
directedGraph.
|
|
75
|
+
directedGraph.removeEdge(edge, removeStrandedVertices);
|
|
81
76
|
```
|
|
82
77
|
|
|
83
78
|
The default is to leave stranded vertices in place.
|
|
@@ -85,33 +80,17 @@ The default is to leave stranded vertices in place.
|
|
|
85
80
|
You can detect and recover cycles thus:
|
|
86
81
|
|
|
87
82
|
```
|
|
88
|
-
const
|
|
89
|
-
cyclePresent = directedGraph.isCyclePresentByVertexName(vertexName);
|
|
83
|
+
const cyclePresent = directedGraph.isCyclePresent();
|
|
90
84
|
|
|
91
85
|
if (cyclePresent) {
|
|
92
|
-
const
|
|
93
|
-
|
|
86
|
+
const firstCycle = directedGraph.getFirstCycle(),
|
|
87
|
+
firstCycleVertexNames = firstCycle.getVertexNames();
|
|
94
88
|
|
|
95
89
|
...
|
|
96
90
|
}
|
|
97
91
|
```
|
|
98
|
-
As already pointed out in the introduction, if a vertex is part of more than one cycle, any of of them can be given.
|
|
99
|
-
|
|
100
92
|
You can get a topologically ordered list of vertices at any time.
|
|
101
|
-
Bear in mind that this
|
|
102
|
-
A method is also provided to ascertain whether cycles are generally present and it is left up to you to decide whether the topologically ordered list of vertices is useful in the event that they are:
|
|
103
|
-
|
|
104
|
-
```
|
|
105
|
-
const cyclesPresent = directedGraph.areCyclesPresent();
|
|
106
|
-
|
|
107
|
-
if (cyclesPresent) {
|
|
108
|
-
///
|
|
109
|
-
} else {
|
|
110
|
-
const orderedVertexNames = directedGraph.getOrderedVertexNames();
|
|
111
|
-
|
|
112
|
-
...
|
|
113
|
-
}
|
|
114
|
-
```
|
|
93
|
+
Bear in mind that this is useless information when cycles are present.
|
|
115
94
|
|
|
116
95
|
## Building
|
|
117
96
|
|
|
@@ -120,6 +99,12 @@ Automation is done with [npm scripts](https://docs.npmjs.com/misc/scripts), have
|
|
|
120
99
|
npm run build-debug
|
|
121
100
|
npm run watch-debug
|
|
122
101
|
|
|
102
|
+
## Running the tests
|
|
103
|
+
|
|
104
|
+
Assuming that the packages are installed:
|
|
105
|
+
|
|
106
|
+
npm test
|
|
107
|
+
|
|
123
108
|
## References
|
|
124
109
|
|
|
125
110
|
This implementation is based on the Pearce-Kelly algorithm:
|
package/lib/cycle.js
CHANGED
|
@@ -8,8 +8,15 @@ Object.defineProperty(exports, "default", {
|
|
|
8
8
|
return Cycle;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
-
var _necessary = require("necessary");
|
|
12
11
|
var _vertex = require("./utilities/vertex");
|
|
12
|
+
function _array_like_to_array(arr, len) {
|
|
13
|
+
if (len == null || len > arr.length) len = arr.length;
|
|
14
|
+
for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
|
|
15
|
+
return arr2;
|
|
16
|
+
}
|
|
17
|
+
function _array_without_holes(arr) {
|
|
18
|
+
if (Array.isArray(arr)) return _array_like_to_array(arr);
|
|
19
|
+
}
|
|
13
20
|
function _class_call_check(instance, Constructor) {
|
|
14
21
|
if (!(instance instanceof Constructor)) {
|
|
15
22
|
throw new TypeError("Cannot call a class as a function");
|
|
@@ -29,7 +36,23 @@ function _create_class(Constructor, protoProps, staticProps) {
|
|
|
29
36
|
if (staticProps) _defineProperties(Constructor, staticProps);
|
|
30
37
|
return Constructor;
|
|
31
38
|
}
|
|
32
|
-
|
|
39
|
+
function _iterable_to_array(iter) {
|
|
40
|
+
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
|
|
41
|
+
}
|
|
42
|
+
function _non_iterable_spread() {
|
|
43
|
+
throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
44
|
+
}
|
|
45
|
+
function _to_consumable_array(arr) {
|
|
46
|
+
return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
|
|
47
|
+
}
|
|
48
|
+
function _unsupported_iterable_to_array(o, minLen) {
|
|
49
|
+
if (!o) return;
|
|
50
|
+
if (typeof o === "string") return _array_like_to_array(o, minLen);
|
|
51
|
+
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
52
|
+
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
53
|
+
if (n === "Map" || n === "Set") return Array.from(n);
|
|
54
|
+
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
55
|
+
}
|
|
33
56
|
var Cycle = /*#__PURE__*/ function() {
|
|
34
57
|
function Cycle(vertexNames) {
|
|
35
58
|
_class_call_check(this, Cycle);
|
|
@@ -44,17 +67,11 @@ var Cycle = /*#__PURE__*/ function() {
|
|
|
44
67
|
}
|
|
45
68
|
], [
|
|
46
69
|
{
|
|
47
|
-
key: "
|
|
48
|
-
value: function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
var firstSuccessorVertex = first(successorVertices), firstSuccessorVertexName = firstSuccessorVertex.getName(), cyclicEdgeTargetVertexName = partialCycle.getTargetVertexName();
|
|
53
|
-
if (firstSuccessorVertexName === cyclicEdgeTargetVertexName) {
|
|
54
|
-
successorVertices.shift();
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
var cyclicEdgeSourceVertexName = partialCycle.getCyclicEdgeSourceVertexName(), cyclicEdgeTargetVertexName1 = partialCycle.getCyclicEdgeTargetVertexName(), predecessorVertexNames = partialCycle.getPredecessorVertexNames(), successorVertexNames = (0, _vertex.vertexNamesFromVertices)(successorVertices), vertexNames = vertexName === cyclicEdgeTargetVertexName1 ? [].concat(cyclicEdgeTargetVertexName1).concat(predecessorVertexNames).concat(cyclicEdgeSourceVertexName) : [].concat(predecessorVertexNames).concat(cyclicEdgeSourceVertexName).concat(cyclicEdgeTargetVertexName1).concat(successorVertexNames), cycle = new Cycle(vertexNames);
|
|
70
|
+
key: "fromSourceVertexAndPredecessorVertexes",
|
|
71
|
+
value: function fromSourceVertexAndPredecessorVertexes(sourceVertex, predecessorVertexes) {
|
|
72
|
+
var vertexes = _to_consumable_array(predecessorVertexes).concat([
|
|
73
|
+
sourceVertex
|
|
74
|
+
]), vertexNames = (0, _vertex.vertexNamesFromVertexes)(vertexes), cycle = new Cycle(vertexNames);
|
|
58
75
|
return cycle;
|
|
59
76
|
}
|
|
60
77
|
}
|
|
@@ -62,4 +79,4 @@ var Cycle = /*#__PURE__*/ function() {
|
|
|
62
79
|
return Cycle;
|
|
63
80
|
}();
|
|
64
81
|
|
|
65
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9jeWNsZS5qcyIsIjw8anN4LWNvbmZpZy1wcmFnbWEuanM+
|
|
82
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9jeWNsZS5qcyIsIjw8anN4LWNvbmZpZy1wcmFnbWEuanM+PiJdLCJzb3VyY2VzQ29udGVudCI6WyJcInVzZSBzdHJpY3RcIjtcblxuaW1wb3J0IHsgdmVydGV4TmFtZXNGcm9tVmVydGV4ZXMgfSBmcm9tIFwiLi91dGlsaXRpZXMvdmVydGV4XCI7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEN5Y2xlIHtcbiAgY29uc3RydWN0b3IodmVydGV4TmFtZXMpIHtcbiAgICB0aGlzLnZlcnRleE5hbWVzID0gdmVydGV4TmFtZXM7XG4gIH1cblxuICBnZXRWZXJ0ZXhOYW1lcygpIHtcbiAgICByZXR1cm4gdGhpcy52ZXJ0ZXhOYW1lcztcbiAgfVxuXG4gIHN0YXRpYyBmcm9tU291cmNlVmVydGV4QW5kUHJlZGVjZXNzb3JWZXJ0ZXhlcyhzb3VyY2VWZXJ0ZXgsIHByZWRlY2Vzc29yVmVydGV4ZXMpIHtcbiAgICBjb25zdCB2ZXJ0ZXhlcyA9IFtcbiAgICAgICAgICAgIC4uLnByZWRlY2Vzc29yVmVydGV4ZXMsXG4gICAgICAgICAgICBzb3VyY2VWZXJ0ZXhcbiAgICAgICAgICBdLFxuICAgICAgICAgIHZlcnRleE5hbWVzID0gdmVydGV4TmFtZXNGcm9tVmVydGV4ZXModmVydGV4ZXMpLFxuICAgICAgICAgIGN5Y2xlID0gbmV3IEN5Y2xlKHZlcnRleE5hbWVzKTtcblxuICAgIHJldHVybiBjeWNsZTtcbiAgfVxufVxuIiwiUmVhY3QuY3JlYXRlRWxlbWVudCJdLCJuYW1lcyI6WyJDeWNsZSIsInZlcnRleE5hbWVzIiwiZ2V0VmVydGV4TmFtZXMiLCJmcm9tU291cmNlVmVydGV4QW5kUHJlZGVjZXNzb3JWZXJ0ZXhlcyIsInNvdXJjZVZlcnRleCIsInByZWRlY2Vzc29yVmVydGV4ZXMiLCJ2ZXJ0ZXhlcyIsInZlcnRleE5hbWVzRnJvbVZlcnRleGVzIiwiY3ljbGUiXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7O2VBSXFCQTs7O3NCQUZtQjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRXpCLElBQUEsQUFBTUEsc0JBQU47YUFBTUEsTUFDUEMsV0FBVztnQ0FESkQ7UUFFakIsSUFBSSxDQUFDQyxjQUFjQTs7a0JBRkZEOztZQUtuQkUsS0FBQUE7bUJBQUFBLFNBQUFBO2dCQUNFLE9BQU8sSUFBSSxDQUFDRDtZQUNkOzs7O1lBRU9FLEtBQUFBO21CQUFQLFNBQU9BLHVDQUF1Q0MsWUFBWSxFQUFFQyxtQkFBbUI7Z0JBQzdFLElBQU1DLFdBQVcsQUFDVCxxQkFBR0QsNEJBRE07b0JBRVREO2lCQUNELEdBQ0RILGNBQWNNLElBQUFBLGlDQUF3QkQsV0FDdENFLFFBQVEsSUFmR1IsTUFlT0M7Z0JBRXhCLE9BQU9PO1lBQ1Q7OztXQWxCbUJSIn0=
|