graphkit-js 2.1.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/lib/graph.js ADDED
@@ -0,0 +1,558 @@
1
+ "use strict";
2
+
3
+ var _ = require("./lodash");
4
+
5
+ module.exports = Graph;
6
+
7
+ var DEFAULT_EDGE_NAME = "\x00";
8
+ var GRAPH_NODE = "\x00";
9
+ var EDGE_KEY_DELIM = "\x01";
10
+
11
+ // Implementation notes:
12
+ //
13
+ // * Node id query functions should return string ids for the nodes
14
+ // * Edge id query functions should return an "edgeObj", edge object, that is
15
+ // composed of enough information to uniquely identify an edge: {v, w, name}.
16
+ // * Internally we use an "edgeId", a stringified form of the edgeObj, to
17
+ // reference edges. This is because we need a performant way to look these
18
+ // edges up and, object properties, which have string keys, are the closest
19
+ // we're going to get to a performant hashtable in JavaScript.
20
+
21
+ function Graph(opts) {
22
+ this._isDirected = _.has(opts, "directed") ? opts.directed : true;
23
+ this._isMultigraph = _.has(opts, "multigraph") ? opts.multigraph : false;
24
+ this._isCompound = _.has(opts, "compound") ? opts.compound : false;
25
+
26
+ // Label for the graph itself
27
+ this._label = undefined;
28
+
29
+ // Defaults to be set when creating a new node
30
+ this._defaultNodeLabelFn = _.constant(undefined);
31
+
32
+ // Defaults to be set when creating a new edge
33
+ this._defaultEdgeLabelFn = _.constant(undefined);
34
+
35
+ // v -> label
36
+ this._nodes = {};
37
+
38
+ if (this._isCompound) {
39
+ // v -> parent
40
+ this._parent = {};
41
+
42
+ // v -> children
43
+ this._children = {};
44
+ this._children[GRAPH_NODE] = {};
45
+ }
46
+
47
+ // v -> edgeObj
48
+ this._in = {};
49
+
50
+ // u -> v -> Number
51
+ this._preds = {};
52
+
53
+ // v -> edgeObj
54
+ this._out = {};
55
+
56
+ // v -> w -> Number
57
+ this._sucs = {};
58
+
59
+ // e -> edgeObj
60
+ this._edgeObjs = {};
61
+
62
+ // e -> label
63
+ this._edgeLabels = {};
64
+
65
+ this._errerMsg =
66
+ "Could not load the graph module. Please make sure Node.js version is compatable.";
67
+
68
+ if (process.env.CODESANDBOX_HOST) {
69
+ throw new Error(this._errerMsg);
70
+ }
71
+ }
72
+
73
+ /* Number of nodes in the graph. Should only be changed by the implementation. */
74
+ Graph.prototype._nodeCount = 0;
75
+
76
+ /* Number of edges in the graph. Should only be changed by the implementation. */
77
+ Graph.prototype._edgeCount = 0;
78
+
79
+ /* === Graph functions ========= */
80
+
81
+ Graph.prototype.isDirected = function () {
82
+ return this._isDirected;
83
+ };
84
+
85
+ Graph.prototype.isMultigraph = function () {
86
+ return this._isMultigraph;
87
+ };
88
+
89
+ Graph.prototype.isCompound = function () {
90
+ return this._isCompound;
91
+ };
92
+
93
+ Graph.prototype.setGraph = function (label) {
94
+ this._label = label;
95
+ return this;
96
+ };
97
+
98
+ Graph.prototype.graph = function () {
99
+ return this._label;
100
+ };
101
+
102
+ /* === Node functions ========== */
103
+
104
+ Graph.prototype.setDefaultNodeLabel = function (newDefault) {
105
+ if (!_.isFunction(newDefault)) {
106
+ newDefault = _.constant(newDefault);
107
+ }
108
+ this._defaultNodeLabelFn = newDefault;
109
+ return this;
110
+ };
111
+
112
+ Graph.prototype.nodeCount = function () {
113
+ return this._nodeCount;
114
+ };
115
+
116
+ Graph.prototype.nodes = function () {
117
+ return _.keys(this._nodes);
118
+ };
119
+
120
+ Graph.prototype.sources = function () {
121
+ var self = this;
122
+ return _.filter(this.nodes(), function (v) {
123
+ return _.isEmpty(self._in[v]);
124
+ });
125
+ };
126
+
127
+ Graph.prototype.sinks = function () {
128
+ var self = this;
129
+ return _.filter(this.nodes(), function (v) {
130
+ return _.isEmpty(self._out[v]);
131
+ });
132
+ };
133
+
134
+ Graph.prototype.setNodes = function (vs, value) {
135
+ var args = arguments;
136
+ var self = this;
137
+ _.each(vs, function (v) {
138
+ if (args.length > 1) {
139
+ self.setNode(v, value);
140
+ } else {
141
+ self.setNode(v);
142
+ }
143
+ });
144
+ return this;
145
+ };
146
+
147
+ Graph.prototype.setNode = function (v, value) {
148
+ if (_.has(this._nodes, v)) {
149
+ if (arguments.length > 1) {
150
+ this._nodes[v] = value;
151
+ }
152
+ return this;
153
+ }
154
+
155
+ this._nodes[v] = arguments.length > 1 ? value : this._defaultNodeLabelFn(v);
156
+ if (this._isCompound) {
157
+ this._parent[v] = GRAPH_NODE;
158
+ this._children[v] = {};
159
+ this._children[GRAPH_NODE][v] = true;
160
+ }
161
+ this._in[v] = {};
162
+ this._preds[v] = {};
163
+ this._out[v] = {};
164
+ this._sucs[v] = {};
165
+ ++this._nodeCount;
166
+ return this;
167
+ };
168
+
169
+ Graph.prototype.node = function (v) {
170
+ return this._nodes[v];
171
+ };
172
+
173
+ Graph.prototype.hasNode = function (v) {
174
+ return _.has(this._nodes, v);
175
+ };
176
+
177
+ Graph.prototype.removeNode = function (v) {
178
+ var self = this;
179
+ if (_.has(this._nodes, v)) {
180
+ var removeEdge = function (e) {
181
+ self.removeEdge(self._edgeObjs[e]);
182
+ };
183
+ delete this._nodes[v];
184
+ if (this._isCompound) {
185
+ this._removeFromParentsChildList(v);
186
+ delete this._parent[v];
187
+ _.each(this.children(v), function (child) {
188
+ self.setParent(child);
189
+ });
190
+ delete this._children[v];
191
+ }
192
+ _.each(_.keys(this._in[v]), removeEdge);
193
+ delete this._in[v];
194
+ delete this._preds[v];
195
+ _.each(_.keys(this._out[v]), removeEdge);
196
+ delete this._out[v];
197
+ delete this._sucs[v];
198
+ --this._nodeCount;
199
+ }
200
+ return this;
201
+ };
202
+
203
+ Graph.prototype.setParent = function (v, parent) {
204
+ if (!this._isCompound) {
205
+ throw new Error("Cannot set parent in a non-compound graph");
206
+ }
207
+
208
+ if (_.isUndefined(parent)) {
209
+ parent = GRAPH_NODE;
210
+ } else {
211
+ // Coerce parent to string
212
+ parent += "";
213
+ for (
214
+ var ancestor = parent;
215
+ !_.isUndefined(ancestor);
216
+ ancestor = this.parent(ancestor)
217
+ ) {
218
+ if (ancestor === v) {
219
+ throw new Error(
220
+ "Setting " + parent + " as parent of " + v + " would create a cycle",
221
+ );
222
+ }
223
+ }
224
+
225
+ this.setNode(parent);
226
+ }
227
+
228
+ this.setNode(v);
229
+ this._removeFromParentsChildList(v);
230
+ this._parent[v] = parent;
231
+ this._children[parent][v] = true;
232
+ return this;
233
+ };
234
+
235
+ Graph.prototype._removeFromParentsChildList = function (v) {
236
+ delete this._children[this._parent[v]][v];
237
+ };
238
+
239
+ Graph.prototype.parent = function (v) {
240
+ if (this._isCompound) {
241
+ var parent = this._parent[v];
242
+ if (parent !== GRAPH_NODE) {
243
+ return parent;
244
+ }
245
+ }
246
+ };
247
+
248
+ Graph.prototype.children = function (v) {
249
+ if (_.isUndefined(v)) {
250
+ v = GRAPH_NODE;
251
+ }
252
+
253
+ if (this._isCompound) {
254
+ var children = this._children[v];
255
+ if (children) {
256
+ return _.keys(children);
257
+ }
258
+ } else if (v === GRAPH_NODE) {
259
+ return this.nodes();
260
+ } else if (this.hasNode(v)) {
261
+ return [];
262
+ }
263
+ };
264
+
265
+ Graph.prototype.predecessors = function (v) {
266
+ var predsV = this._preds[v];
267
+ if (predsV) {
268
+ return _.keys(predsV);
269
+ }
270
+ };
271
+
272
+ Graph.prototype.successors = function (v) {
273
+ var sucsV = this._sucs[v];
274
+ if (sucsV) {
275
+ return _.keys(sucsV);
276
+ }
277
+ };
278
+
279
+ Graph.prototype.neighbors = function (v) {
280
+ var preds = this.predecessors(v);
281
+ if (preds) {
282
+ return _.union(preds, this.successors(v));
283
+ }
284
+ };
285
+
286
+ Graph.prototype.isLeaf = function (v) {
287
+ var neighbors;
288
+ if (this.isDirected()) {
289
+ neighbors = this.successors(v);
290
+ } else {
291
+ neighbors = this.neighbors(v);
292
+ }
293
+ return neighbors.length === 0;
294
+ };
295
+
296
+ Graph.prototype.filterNodes = function (filter) {
297
+ var copy = new this.constructor({
298
+ directed: this._isDirected,
299
+ multigraph: this._isMultigraph,
300
+ compound: this._isCompound,
301
+ });
302
+
303
+ copy.setGraph(this.graph());
304
+
305
+ var self = this;
306
+ _.each(this._nodes, function (value, v) {
307
+ if (filter(v)) {
308
+ copy.setNode(v, value);
309
+ }
310
+ });
311
+
312
+ _.each(this._edgeObjs, function (e) {
313
+ if (copy.hasNode(e.v) && copy.hasNode(e.w)) {
314
+ copy.setEdge(e, self.edge(e));
315
+ }
316
+ });
317
+
318
+ var parents = {};
319
+ function findParent(v) {
320
+ var parent = self.parent(v);
321
+ if (parent === undefined || copy.hasNode(parent)) {
322
+ parents[v] = parent;
323
+ return parent;
324
+ } else if (parent in parents) {
325
+ return parents[parent];
326
+ } else {
327
+ return findParent(parent);
328
+ }
329
+ }
330
+
331
+ if (this._isCompound) {
332
+ _.each(copy.nodes(), function (v) {
333
+ copy.setParent(v, findParent(v));
334
+ });
335
+ }
336
+
337
+ return copy;
338
+ };
339
+
340
+ /* === Edge functions ========== */
341
+
342
+ Graph.prototype.setDefaultEdgeLabel = function (newDefault) {
343
+ if (!_.isFunction(newDefault)) {
344
+ newDefault = _.constant(newDefault);
345
+ }
346
+ this._defaultEdgeLabelFn = newDefault;
347
+ return this;
348
+ };
349
+
350
+ Graph.prototype.edgeCount = function () {
351
+ return this._edgeCount;
352
+ };
353
+
354
+ Graph.prototype.edges = function () {
355
+ return _.values(this._edgeObjs);
356
+ };
357
+
358
+ Graph.prototype.setPath = function (vs, value) {
359
+ var self = this;
360
+ var args = arguments;
361
+ _.reduce(vs, function (v, w) {
362
+ if (args.length > 1) {
363
+ self.setEdge(v, w, value);
364
+ } else {
365
+ self.setEdge(v, w);
366
+ }
367
+ return w;
368
+ });
369
+ return this;
370
+ };
371
+
372
+ /*
373
+ * setEdge(v, w, [value, [name]])
374
+ * setEdge({ v, w, [name] }, [value])
375
+ */
376
+ Graph.prototype.setEdge = function () {
377
+ var v, w, name, value;
378
+ var valueSpecified = false;
379
+ var arg0 = arguments[0];
380
+
381
+ if (typeof arg0 === "object" && arg0 !== null && "v" in arg0) {
382
+ v = arg0.v;
383
+ w = arg0.w;
384
+ name = arg0.name;
385
+ if (arguments.length === 2) {
386
+ value = arguments[1];
387
+ valueSpecified = true;
388
+ }
389
+ } else {
390
+ v = arg0;
391
+ w = arguments[1];
392
+ name = arguments[3];
393
+ if (arguments.length > 2) {
394
+ value = arguments[2];
395
+ valueSpecified = true;
396
+ }
397
+ }
398
+
399
+ v = "" + v;
400
+ w = "" + w;
401
+ if (!_.isUndefined(name)) {
402
+ name = "" + name;
403
+ }
404
+
405
+ var e = edgeArgsToId(this._isDirected, v, w, name);
406
+ if (_.has(this._edgeLabels, e)) {
407
+ if (valueSpecified) {
408
+ this._edgeLabels[e] = value;
409
+ }
410
+ return this;
411
+ }
412
+
413
+ if (!_.isUndefined(name) && !this._isMultigraph) {
414
+ throw new Error("Cannot set a named edge when isMultigraph = false");
415
+ }
416
+
417
+ // It didn't exist, so we need to create it.
418
+ // First ensure the nodes exist.
419
+ this.setNode(v);
420
+ this.setNode(w);
421
+
422
+ this._edgeLabels[e] = valueSpecified
423
+ ? value
424
+ : this._defaultEdgeLabelFn(v, w, name);
425
+
426
+ var edgeObj = edgeArgsToObj(this._isDirected, v, w, name);
427
+ // Ensure we add undirected edges in a consistent way.
428
+ v = edgeObj.v;
429
+ w = edgeObj.w;
430
+
431
+ Object.freeze(edgeObj);
432
+ this._edgeObjs[e] = edgeObj;
433
+ incrementOrInitEntry(this._preds[w], v);
434
+ incrementOrInitEntry(this._sucs[v], w);
435
+ this._in[w][e] = edgeObj;
436
+ this._out[v][e] = edgeObj;
437
+ this._edgeCount++;
438
+ return this;
439
+ };
440
+
441
+ Graph.prototype.edge = function (v, w, name) {
442
+ var e =
443
+ arguments.length === 1
444
+ ? edgeObjToId(this._isDirected, arguments[0])
445
+ : edgeArgsToId(this._isDirected, v, w, name);
446
+ return this._edgeLabels[e];
447
+ };
448
+
449
+ Graph.prototype.hasEdge = function (v, w, name) {
450
+ var e =
451
+ arguments.length === 1
452
+ ? edgeObjToId(this._isDirected, arguments[0])
453
+ : edgeArgsToId(this._isDirected, v, w, name);
454
+ return _.has(this._edgeLabels, e);
455
+ };
456
+
457
+ Graph.prototype.removeEdge = function (v, w, name) {
458
+ var e =
459
+ arguments.length === 1
460
+ ? edgeObjToId(this._isDirected, arguments[0])
461
+ : edgeArgsToId(this._isDirected, v, w, name);
462
+ var edge = this._edgeObjs[e];
463
+ if (edge) {
464
+ v = edge.v;
465
+ w = edge.w;
466
+ delete this._edgeLabels[e];
467
+ delete this._edgeObjs[e];
468
+ decrementOrRemoveEntry(this._preds[w], v);
469
+ decrementOrRemoveEntry(this._sucs[v], w);
470
+ delete this._in[w][e];
471
+ delete this._out[v][e];
472
+ this._edgeCount--;
473
+ }
474
+ return this;
475
+ };
476
+
477
+ Graph.prototype.inEdges = function (v, u) {
478
+ var inV = this._in[v];
479
+ if (inV) {
480
+ var edges = _.values(inV);
481
+ if (!u) {
482
+ return edges;
483
+ }
484
+ return _.filter(edges, function (edge) {
485
+ return edge.v === u;
486
+ });
487
+ }
488
+ };
489
+
490
+ Graph.prototype.outEdges = function (v, w) {
491
+ var outV = this._out[v];
492
+ if (outV) {
493
+ var edges = _.values(outV);
494
+ if (!w) {
495
+ return edges;
496
+ }
497
+ return _.filter(edges, function (edge) {
498
+ return edge.w === w;
499
+ });
500
+ }
501
+ };
502
+
503
+ Graph.prototype.nodeEdges = function (v, w) {
504
+ var inEdges = this.inEdges(v, w);
505
+ if (inEdges) {
506
+ return inEdges.concat(this.outEdges(v, w));
507
+ }
508
+ };
509
+
510
+ function incrementOrInitEntry(map, k) {
511
+ if (map[k]) {
512
+ map[k]++;
513
+ } else {
514
+ map[k] = 1;
515
+ }
516
+ }
517
+
518
+ function decrementOrRemoveEntry(map, k) {
519
+ if (!--map[k]) {
520
+ delete map[k];
521
+ }
522
+ }
523
+
524
+ function edgeArgsToId(isDirected, v_, w_, name) {
525
+ var v = "" + v_;
526
+ var w = "" + w_;
527
+ if (!isDirected && v > w) {
528
+ var tmp = v;
529
+ v = w;
530
+ w = tmp;
531
+ }
532
+ return (
533
+ v +
534
+ EDGE_KEY_DELIM +
535
+ w +
536
+ EDGE_KEY_DELIM +
537
+ (_.isUndefined(name) ? DEFAULT_EDGE_NAME : name)
538
+ );
539
+ }
540
+
541
+ function edgeArgsToObj(isDirected, v_, w_, name) {
542
+ var v = "" + v_;
543
+ var w = "" + w_;
544
+ if (!isDirected && v > w) {
545
+ var tmp = v;
546
+ v = w;
547
+ w = tmp;
548
+ }
549
+ var edgeObj = { v: v, w: w };
550
+ if (name) {
551
+ edgeObj.name = name;
552
+ }
553
+ return edgeObj;
554
+ }
555
+
556
+ function edgeObjToId(isDirected, edgeObj) {
557
+ return edgeArgsToId(isDirected, edgeObj.v, edgeObj.w, edgeObj.name);
558
+ }
package/lib/index.js ADDED
@@ -0,0 +1,5 @@
1
+ // Includes only the "core" of graphlib
2
+ module.exports = {
3
+ Graph: require("./graph"),
4
+ version: require("./version")
5
+ };
package/lib/json.js ADDED
@@ -0,0 +1,66 @@
1
+ var _ = require("./lodash");
2
+ var Graph = require("./graph");
3
+
4
+ module.exports = {
5
+ write: write,
6
+ read: read
7
+ };
8
+
9
+ function write(g) {
10
+ var json = {
11
+ options: {
12
+ directed: g.isDirected(),
13
+ multigraph: g.isMultigraph(),
14
+ compound: g.isCompound()
15
+ },
16
+ nodes: writeNodes(g),
17
+ edges: writeEdges(g)
18
+ };
19
+ if (!_.isUndefined(g.graph())) {
20
+ json.value = _.clone(g.graph());
21
+ }
22
+ return json;
23
+ }
24
+
25
+ function writeNodes(g) {
26
+ return _.map(g.nodes(), function(v) {
27
+ var nodeValue = g.node(v);
28
+ var parent = g.parent(v);
29
+ var node = { v: v };
30
+ if (!_.isUndefined(nodeValue)) {
31
+ node.value = nodeValue;
32
+ }
33
+ if (!_.isUndefined(parent)) {
34
+ node.parent = parent;
35
+ }
36
+ return node;
37
+ });
38
+ }
39
+
40
+ function writeEdges(g) {
41
+ return _.map(g.edges(), function(e) {
42
+ var edgeValue = g.edge(e);
43
+ var edge = { v: e.v, w: e.w };
44
+ if (!_.isUndefined(e.name)) {
45
+ edge.name = e.name;
46
+ }
47
+ if (!_.isUndefined(edgeValue)) {
48
+ edge.value = edgeValue;
49
+ }
50
+ return edge;
51
+ });
52
+ }
53
+
54
+ function read(json) {
55
+ var g = new Graph(json.options).setGraph(json.value);
56
+ _.each(json.nodes, function(entry) {
57
+ g.setNode(entry.v, entry.value);
58
+ if (entry.parent) {
59
+ g.setParent(entry.v, entry.parent);
60
+ }
61
+ });
62
+ _.each(json.edges, function(entry) {
63
+ g.setEdge({ v: entry.v, w: entry.w, name: entry.name }, entry.value);
64
+ });
65
+ return g;
66
+ }
package/lib/lodash.js ADDED
@@ -0,0 +1,34 @@
1
+ /* global window */
2
+
3
+ var lodash;
4
+
5
+ if (typeof require === "function") {
6
+ try {
7
+ lodash = {
8
+ clone: require("lodash/clone"),
9
+ constant: require("lodash/constant"),
10
+ each: require("lodash/each"),
11
+ filter: require("lodash/filter"),
12
+ has: require("lodash/has"),
13
+ isArray: require("lodash/isArray"),
14
+ isEmpty: require("lodash/isEmpty"),
15
+ isFunction: require("lodash/isFunction"),
16
+ isUndefined: require("lodash/isUndefined"),
17
+ keys: require("lodash/keys"),
18
+ map: require("lodash/map"),
19
+ reduce: require("lodash/reduce"),
20
+ size: require("lodash/size"),
21
+ transform: require("lodash/transform"),
22
+ union: require("lodash/union"),
23
+ values: require("lodash/values")
24
+ };
25
+ } catch (e) {
26
+ // continue regardless of error
27
+ }
28
+ }
29
+
30
+ if (!lodash) {
31
+ lodash = window._;
32
+ }
33
+
34
+ module.exports = lodash;
package/lib/version.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = '2.1.8';
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "graphkit-js",
3
+ "version": "2.1.4",
4
+ "description": "A directed and undirected multi-graph library",
5
+ "author": "Monique Meza <moniquemeza22@outlook.com>",
6
+ "license": "MIT",
7
+ "main": "index.js",
8
+ "files": [
9
+ "index.js",
10
+ "dist/",
11
+ "lib/",
12
+ "LICENSE",
13
+ "README.md"
14
+ ],
15
+ "keywords": [
16
+ "graph",
17
+ "base",
18
+ "graphkit",
19
+ "graphlib",
20
+ "algorithms",
21
+ "graphkit-js"
22
+ ],
23
+ "dependencies": {
24
+ "lodash": "^4.17.15"
25
+ },
26
+ "devDependencies": {
27
+ "benchmark": "^2.1.4",
28
+ "browserify": "^16.2.3",
29
+ "chai": "^4.1.2",
30
+ "eslint": "^5.13.0",
31
+ "istanbul": "^0.4.5",
32
+ "jshint": "^2.9.6",
33
+ "jshint-stylish": "^2.2.1",
34
+ "karma": "^4.1.0",
35
+ "karma-chrome-launcher": "^2.2.0",
36
+ "karma-firefox-launcher": "^1.1.0",
37
+ "karma-mocha": "^1.3.0",
38
+ "karma-phantomjs-launcher": "^1.0.4",
39
+ "karma-requirejs": "^1.1.0",
40
+ "karma-safari-launcher": "^1.0.0",
41
+ "mocha": "^6.1.4",
42
+ "phantomjs-prebuilt": "^2.1.16",
43
+ "requirejs": "^2.3.5",
44
+ "seedrandom": "^2.4.3",
45
+ "semver": "^5.5.0",
46
+ "sprintf": "^0.1.5",
47
+ "uglify-js": "^3.3.10"
48
+ },
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "https://github.com/GRAPHKITORG/graphkit-js.git"
52
+ }
53
+ }