@hpcc-js/util 3.4.5 → 3.4.8

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/src/graph2.ts CHANGED
@@ -1,675 +1,675 @@
1
- import { compare2 } from "./array.ts";
2
-
3
- type ID = string | number;
4
-
5
- class GraphItem<T = any> {
6
- protected _graph: Graph2;
7
- _: T;
8
- id(): ID {
9
- return this._graph.id(this._);
10
- }
11
-
12
- constructor(g: Graph2, _: T) {
13
- this._graph = g;
14
- this._ = _;
15
- }
16
- }
17
-
18
- class ChildGraphItem<S = any> extends GraphItem<S> {
19
-
20
- private _parent: Subgraph | undefined;
21
-
22
- constructor(g: Graph2, _: S) {
23
- super(g, _);
24
- }
25
-
26
- clearParent(): this {
27
- if (this._parent) {
28
- this._parent.removeChild(this);
29
- delete this._parent;
30
- }
31
- return this;
32
- }
33
-
34
- parent(): Subgraph | undefined;
35
- parent(_: Subgraph | undefined): this;
36
- parent(_?: Subgraph): Subgraph | undefined | this {
37
- if (arguments.length === 0) return this._parent;
38
- if (this._parent !== _) {
39
- if (this._parent) {
40
- this._parent.removeChild(this);
41
- }
42
- this._parent = _;
43
- if (this._parent) {
44
- this._parent.addChild(this);
45
- }
46
- }
47
- return this;
48
- }
49
- }
50
-
51
- class Subgraph<S = any> extends ChildGraphItem<S> {
52
-
53
- private _children: ChildGraphItem[] = [];
54
-
55
- constructor(g: Graph2, _: S) {
56
- super(g, _);
57
- }
58
-
59
- children(): ChildGraphItem[] {
60
- return this._children;
61
- }
62
-
63
- addChild(_: ChildGraphItem) {
64
- this._children.push(_);
65
- }
66
-
67
- removeChild(_: ChildGraphItem) {
68
- this._children = this._children.filter(row => row.id !== _.id);
69
- }
70
- }
71
-
72
- class Vertex<V = any> extends ChildGraphItem<V> {
73
-
74
- private _inEdges: Edge[] = [];
75
- private _outEdges: Edge[] = [];
76
-
77
- constructor(g: Graph2, _: V) {
78
- super(g, _);
79
- }
80
-
81
- edges() {
82
- return [...this._inEdges, ...this._outEdges];
83
- }
84
-
85
- edgeCount() {
86
- return this._outEdges.length + this._inEdges.length;
87
- }
88
-
89
- inEdges() {
90
- return this._inEdges;
91
- }
92
-
93
- addInEdge(e: Edge) {
94
- this._inEdges.push(e);
95
- }
96
-
97
- removeInEdge(id: ID) {
98
- this._inEdges = this._inEdges.filter(e => e._.id !== id);
99
- }
100
-
101
- outEdges() {
102
- return this._outEdges;
103
- }
104
-
105
- addOutEdge(e: Edge) {
106
- this._outEdges.push(e);
107
- }
108
-
109
- removeOutEdge(id: ID) {
110
- this._outEdges = this._outEdges.filter(e => e._.id !== id);
111
- }
112
- }
113
-
114
- class Edge<E = any> extends ChildGraphItem<E> {
115
-
116
- _source: Vertex;
117
- _target: Vertex;
118
-
119
- constructor(g: Graph2, _: E, source: Vertex, target: Vertex) {
120
- super(g, _);
121
- this._source = source;
122
- this._target = target;
123
- }
124
- }
125
-
126
- type SubgraphMap<T> = { [id: string]: Subgraph<T> };
127
- type VertexMap<T> = { [id: string]: Vertex<T> };
128
- type EdgeMap<T> = { [id: string]: Edge<T> };
129
-
130
- export type HierarchyFormatter<V, S> = (type: "subgraph" | "vertex", item: V | S, children?: object[]) => object;
131
-
132
- export class Graph2<V = any, E = any, S = any> {
133
-
134
- private _directed: boolean;
135
- private _subgraphMap: SubgraphMap<S> = {};
136
- private _vertexMap: VertexMap<V> = {};
137
- private _edgeMap: EdgeMap<E> = {};
138
-
139
- constructor(directed = true) {
140
- this._directed = directed;
141
- }
142
-
143
- clear(): this {
144
- this._subgraphMap = {};
145
- this._vertexMap = {};
146
- this._edgeMap = {};
147
- return this;
148
- }
149
-
150
- clearParents(): this {
151
- for (const key in this._subgraphMap) {
152
- this._subgraphMap[key].clearParent();
153
- }
154
- for (const key in this._vertexMap) {
155
- this._vertexMap[key].clearParent();
156
- }
157
- return this;
158
- }
159
-
160
- isDirected(): boolean {
161
- return this._directed;
162
- }
163
-
164
- _idFunc = (_: any): ID => typeof _.id === "function" ? _.id() : _.id;
165
- idFunc(_: (_: S | V | E) => ID): this {
166
- this._idFunc = _;
167
- return this;
168
- }
169
-
170
- _sourceFunc = (_: any): ID => typeof _.source === "function" ? _.source() : _.source;
171
- sourceFunc(_: (_: E) => ID): this {
172
- this._sourceFunc = _;
173
- return this;
174
- }
175
-
176
- _targetFunc = (_: any): ID => typeof _.target === "function" ? _.target() : _.target;
177
- targetFunc(_: (_: E) => ID): this {
178
- this._targetFunc = _;
179
- return this;
180
- }
181
-
182
- _updateFunc = (before: S | V | E, after: S | V | E): S | V | E => after;
183
- updateFunc(_: (before: S | V | E, after: S | V | E) => S | V | E): this {
184
- this._updateFunc = _;
185
- return this;
186
- }
187
-
188
- id(_: S | V | E): ID {
189
- return this._idFunc(_);
190
- }
191
-
192
- type(id: ID): "S" | "V" | "E" | "" {
193
- if (this.subgraphExists(id)) return "S";
194
- if (this.vertexExists(id)) return "V";
195
- if (this.edgeExists(id)) return "E";
196
- return "";
197
- }
198
-
199
- isSubgraph(_: S | V | E): _ is S {
200
- return this.subgraphExists(this.id(_));
201
- }
202
-
203
- isVertex(_: S | V | E): _ is V {
204
- return this.vertexExists(this.id(_));
205
- }
206
-
207
- isEdge(_: S | V | E): _ is E {
208
- return this.edgeExists(this.id(_));
209
- }
210
-
211
- allItems(): Array<S | V | E> {
212
- return [...this.allSubgraphs(), ...this.allVertices(), ...this.allEdges()];
213
- }
214
-
215
- item(id: ID): S | V | E | undefined {
216
- if (this.subgraphExists(id)) return this.subgraph(id);
217
- if (this.vertexExists(id)) return this.vertex(id);
218
- if (this.edgeExists(id)) return this.edge(id);
219
- return undefined;
220
- }
221
-
222
- itemExists(id: ID): boolean {
223
- return this.edgeExists(id) || this.vertexExists(id) || this.subgraphExists(id);
224
- }
225
-
226
- // Subgraphs ---
227
- allSubgraphs(): S[] {
228
- const retVal: S[] = [];
229
- for (const key in this._subgraphMap) {
230
- retVal.push(this._subgraphMap[key]._);
231
- }
232
- return retVal;
233
- }
234
-
235
- subgraphs(): S[] {
236
- const retVal: S[] = [];
237
- for (const key in this._subgraphMap) {
238
- if (this._subgraphMap[key].parent() === undefined) {
239
- retVal.push(this._subgraphMap[key]._);
240
- }
241
- }
242
- return retVal;
243
- }
244
-
245
- subgraphExists(id: ID): boolean {
246
- return !!this._subgraphMap[id];
247
- }
248
-
249
- subgraph(id: ID): S {
250
- return this._subgraphMap[id]._;
251
- }
252
-
253
- subgraphSubgraphs(id: ID): S[] {
254
- return this._subgraphMap[id].children().filter(child => this.isSubgraph(child._)).map(child => child._);
255
- }
256
-
257
- subgraphVertices(id: ID): V[] {
258
- return this._subgraphMap[id].children().filter(child => this.isVertex(child._)).map(child => child._);
259
- }
260
-
261
- subgraphEdges(id: ID): E[] {
262
- return this._subgraphMap[id].children().filter(child => this.isEdge(child._)).map(child => child._);
263
- }
264
-
265
- addSubgraph(s: S, parent?: S): this {
266
- const s_id = this._idFunc(s);
267
- if (this._subgraphMap[s_id]) throw new Error(`Subgraph '${s_id}' already exists.`);
268
- const subgraph = new Subgraph(this, s);
269
- if (parent) {
270
- const p_id = this._idFunc(parent);
271
- if (!this._subgraphMap[p_id]) throw new Error(`Subgraph '${p_id}' does not exist.`);
272
- subgraph.parent(this._subgraphMap[p_id]);
273
- }
274
- this._subgraphMap[s_id] = subgraph;
275
- return this;
276
- }
277
-
278
- mergeSubgraphs(_subgraphs: S[] = []): this {
279
- const sgDiff = compare2<S>(this.allSubgraphs(), _subgraphs, sg => this._idFunc(sg), this._updateFunc as any);
280
- sgDiff.exit.forEach(sg => this.removeSubgraph(this._idFunc(sg)));
281
- sgDiff.enter.forEach(sg => this.addSubgraph(sg));
282
- sgDiff.update.forEach(sg => this.updateSubgraph(sg));
283
- return this;
284
- }
285
-
286
- updateSubgraph(sg: S): this {
287
- const sg_id = this._idFunc(sg);
288
- const subgraph = this._subgraphMap[sg_id];
289
- if (!subgraph) throw new Error(`Subgraph '${sg_id}' does not exist.`);
290
- subgraph._ = sg;
291
- return this;
292
- }
293
-
294
- removeSubgraph(id: ID, promoteChildren = true): this {
295
- const sg = this._subgraphMap[id];
296
- if (!sg) throw new Error(`Subgraph '${id}' does not exist.`);
297
- sg.children().forEach(child => {
298
- if (promoteChildren) {
299
- child.parent(sg.parent());
300
- } else {
301
- if (child instanceof Subgraph) {
302
- this.removeSubgraph(child.id());
303
- } else {
304
- this.removeVertex(child.id());
305
- }
306
- }
307
- });
308
- delete this._subgraphMap[id];
309
- return this;
310
- }
311
-
312
- subgraphParent(id: ID): S | undefined;
313
- subgraphParent(id: ID, parentID: ID): this;
314
- subgraphParent(id: ID, parentID?: ID): S | undefined | this {
315
- const item = this._subgraphMap[id];
316
- if (!item) throw new Error(`Subgraph '${id}' does not exist.`);
317
- if (parentID === void 0) {
318
- const parent = item.parent();
319
- return parent ? parent._ as S : undefined;
320
- }
321
- const parent = this._subgraphMap[parentID];
322
- if (!parent) throw new Error(`Vertex parent '${parent}' does not exist.`);
323
- item.parent(parent);
324
- return this;
325
- }
326
-
327
- // Vertices ---
328
- allVertices(): V[] {
329
- const retVal: V[] = [];
330
- for (const key in this._vertexMap) {
331
- retVal.push(this._vertexMap[key]._);
332
- }
333
- return retVal;
334
- }
335
-
336
- vertices(): V[] {
337
- const retVal: V[] = [];
338
- for (const key in this._vertexMap) {
339
- if (this._vertexMap[key].parent() === undefined) {
340
- retVal.push(this._vertexMap[key]._);
341
- }
342
- }
343
- return retVal;
344
- }
345
-
346
- vertexExists(id: ID): boolean {
347
- return !!this._vertexMap[id];
348
- }
349
-
350
- vertex(id: ID): V {
351
- return this._vertexMap[id]._;
352
- }
353
-
354
- allEdges(): E[] {
355
- const retVal: E[] = [];
356
- for (const key in this._edgeMap) {
357
- retVal.push(this._edgeMap[key]._);
358
- }
359
- return retVal;
360
- }
361
-
362
- edges(): E[] {
363
- const retVal: E[] = [];
364
- for (const key in this._edgeMap) {
365
- if (this._edgeMap[key].parent() === undefined) {
366
- retVal.push(this._edgeMap[key]._);
367
- }
368
- }
369
- return retVal;
370
- }
371
-
372
- vertexEdges(vertexID: ID): E[] {
373
- return this._vertexMap[vertexID].edges().map(e => e._);
374
- }
375
-
376
- inEdges(vertexID: ID): E[] {
377
- return this._vertexMap[vertexID].inEdges().map(e => e._);
378
- }
379
-
380
- outEdges(vertexID: ID): E[] {
381
- return this._vertexMap[vertexID].outEdges().map(e => e._);
382
- }
383
-
384
- private _neighbors(id: ID): Vertex[] {
385
- return [...this._vertexMap[id].outEdges().map(e => e._target), ...this._vertexMap[id].inEdges().map(e => e._source)];
386
- }
387
-
388
- neighbors(id: ID): V[] {
389
- return this._neighbors(id).map(n => n._);
390
- }
391
-
392
- singleNeighbors(id: ID): V[] {
393
- return this._neighbors(id).filter(n => n.edgeCount() === 1).map(n => n._);
394
- }
395
-
396
- addVertex(v: V, parent?: S): this {
397
- const v_id = this._idFunc(v);
398
- if (this._vertexMap[v_id]) throw new Error(`Vertex '${v_id}' already exists.`);
399
- const vertex = new Vertex(this, v);
400
- if (parent) {
401
- const p_id = this._idFunc(parent);
402
- if (!this.subgraphExists(p_id)) throw new Error(`Subgraph '${p_id}' does not exist.`);
403
- vertex.parent(this._subgraphMap[p_id]);
404
- }
405
- this._vertexMap[v_id] = vertex;
406
- return this;
407
- }
408
-
409
- mergeVertices(_vertices: V[]): this {
410
- const vDiff = compare2(this.allVertices(), _vertices, v => this._idFunc(v), this._updateFunc as any);
411
- vDiff.exit.forEach(v => this.removeVertex(this._idFunc(v)));
412
- vDiff.enter.forEach(v => this.addVertex(v));
413
- vDiff.update.forEach(v => this.updateVertex(v));
414
- return this;
415
- }
416
-
417
- updateVertex(v: V): this {
418
- const v_id = this._idFunc(v);
419
- const vertex = this._vertexMap[v_id];
420
- if (!vertex) throw new Error(`Vertex '${v_id}' does not exist.`);
421
- vertex._ = v;
422
- return this;
423
- }
424
-
425
- removeVertex(id: ID): this {
426
- const v = this._vertexMap[id];
427
- if (!v) throw new Error(`Vertex '${id}' does not exist.`);
428
- v.edges().forEach(e => {
429
- this.removeEdge(e.id());
430
- });
431
- delete this._vertexMap[id];
432
- return this;
433
- }
434
-
435
- vertexParent(id: ID): S | undefined;
436
- vertexParent(id: ID, parentID: ID): this;
437
- vertexParent(id: ID, parentID?: ID): S | undefined | this {
438
- const item = this._vertexMap[id];
439
- if (!item) throw new Error(`Vertex '${id}' does not exist.`);
440
- if (parentID === void 0) {
441
- const parent = item.parent();
442
- return parent ? parent._ as S : undefined;
443
- }
444
- const parent = this._subgraphMap[parentID];
445
- if (!parent) throw new Error(`Vertex parent '${parent}' does not exist.`);
446
- item.parent(parent);
447
- return this;
448
- }
449
-
450
- // Edges ---
451
- edgeExists(id: ID): boolean {
452
- return !!this._edgeMap[id];
453
- }
454
-
455
- edge(id: ID): E {
456
- return this._edgeMap[id]._;
457
- }
458
-
459
- addEdge(e: E, parent?: S): this {
460
- const e_id = this._idFunc(e);
461
- const e_source = this._sourceFunc(e);
462
- const e_target = this._targetFunc(e);
463
- if (this._edgeMap[e_id]) throw new Error(`Edge '${e_id}' already exists.`);
464
- if (!this.vertexExists(e_source)) throw new Error(`Edge Source '${e_source}' does not exist.`);
465
- if (!this.vertexExists(e_target)) throw new Error(`Edge Target '${e_target}' does not exist.`);
466
- const edge = new Edge(this, e, this._vertexMap[e_source], this._vertexMap[e_target]);
467
- if (parent) {
468
- const p_id = this._idFunc(parent);
469
- if (!this.subgraphExists(p_id)) throw new Error(`Subgraph '${p_id}' does not exist.`);
470
- edge.parent(this._subgraphMap[p_id]);
471
- }
472
- this._edgeMap[e_id] = edge;
473
- this._vertexMap[e_source].addOutEdge(edge);
474
- this._vertexMap[e_target].addInEdge(edge);
475
- return this;
476
- }
477
-
478
- mergeEdges(_edges: E[]): this {
479
- const eDiff = compare2(this.allEdges(), _edges, e => this._idFunc(e), this._updateFunc as any);
480
- eDiff.exit.forEach(e => this.removeEdge(this._idFunc(e)));
481
- eDiff.enter.forEach(e => this.addEdge(e));
482
- eDiff.update.forEach(e => this.updateEdge(e));
483
- return this;
484
- }
485
-
486
- updateEdge(e: E): this {
487
- const e_id = this._idFunc(e);
488
- const edge = this._edgeMap[e_id];
489
- if (!edge) throw new Error(`Edge '${e_id}' does not exist.`);
490
- const old_source = edge._source.id();
491
- const new_source = this._sourceFunc(e);
492
- if (old_source !== new_source) {
493
- this._vertexMap[old_source]?.removeOutEdge(e_id);
494
- this._vertexMap[new_source]?.addOutEdge(edge);
495
- }
496
- const old_target = edge._target.id();
497
- const new_target = this._targetFunc(e);
498
- if (old_target !== new_target) {
499
- this._vertexMap[old_target]?.removeInEdge(e_id);
500
- this._vertexMap[new_target]?.addInEdge(edge);
501
- }
502
- edge._ = e;
503
- edge._source = this._vertexMap[new_source];
504
- edge._target = this._vertexMap[new_target];
505
- return this;
506
- }
507
-
508
- removeEdge(id: ID): this {
509
- const e: Edge<E> = this._edgeMap[id];
510
- if (!e) throw new Error(`Edge '${id}' does not exist.`);
511
-
512
- const e_sourceID = this._idFunc(e._source._);
513
- if (!this.vertexExists(e_sourceID)) throw new Error(`Edge Source'${e_sourceID}' does not exist.`);
514
- this._vertexMap[e_sourceID].removeOutEdge(id);
515
-
516
- const e_targetID = this._idFunc(e._target._);
517
- if (!this.vertexExists(e_targetID)) throw new Error(`Edge Target'${e_targetID}' does not exist.`);
518
- this._vertexMap[e_targetID].removeInEdge(id);
519
-
520
- delete this._edgeMap[id];
521
- return this;
522
- }
523
-
524
- protected _hwalk(item: Subgraph<S> | Vertex<V>, formatter: HierarchyFormatter<V, S>): object {
525
- if (item instanceof Subgraph) {
526
- return formatter("subgraph", item._, item.children().map(child => this._hwalk(child as Subgraph<S> | Vertex<V>, formatter)));
527
- } else {
528
- return formatter("vertex", item._);
529
- }
530
- }
531
-
532
- hierarchy(formatter: HierarchyFormatter<V, S>): object[] {
533
- const retVal: object[] = [];
534
- for (const id in this._subgraphMap) {
535
- const sg = this._subgraphMap[id];
536
- if (sg.parent() === undefined) {
537
- retVal.push(this._hwalk(sg, formatter));
538
- }
539
- }
540
- for (const id in this._vertexMap) {
541
- const v = this._vertexMap[id];
542
- if (v.parent() === undefined) {
543
- retVal.push(this._hwalk(v, formatter));
544
- }
545
- }
546
- return retVal;
547
- }
548
-
549
- dijkstra(source: ID, target: ID): { ids: ID[], len: number } {
550
- const edges = this.allEdges();
551
- const Q = new Set<string | number>();
552
- const prev: { [key: string]: string } = {};
553
- const dist: { [key: string]: number } = {};
554
- const adj: { [key: string]: { [key: string]: number } } = {};
555
-
556
- function vertex_with_min_dist(Q: Set<string | number>, dist: { [key: string]: number }) {
557
- let min_distance = Infinity;
558
- let u: string | number | null = null;
559
-
560
- Q.forEach(v => {
561
- if (dist[v] < min_distance) {
562
- min_distance = dist[v];
563
- u = v;
564
- }
565
- });
566
- return u;
567
- }
568
-
569
- for (let i = 0; i < edges.length; i++) {
570
- const v1 = this._sourceFunc(edges[i]);
571
- const v2 = this._targetFunc(edges[i]);
572
- const len = 1;
573
-
574
- Q.add(v1);
575
- Q.add(v2);
576
-
577
- dist[v1] = Infinity;
578
- dist[v2] = Infinity;
579
-
580
- if (adj[v1] === undefined) adj[v1] = {};
581
- if (adj[v2] === undefined) adj[v2] = {};
582
-
583
- adj[v1][v2] = len;
584
- adj[v2][v1] = len;
585
- }
586
-
587
- dist[source] = 0;
588
-
589
- while (Q.size) {
590
- const u = vertex_with_min_dist(Q, dist);
591
- if (u === null) break;
592
- const neighbors = Object.keys(adj[u]).filter(v => Q.has(v)); // Neighbor still in Q
593
-
594
- Q.delete(u);
595
-
596
- if (u === target) break; // Break when the target has been found
597
-
598
- for (const v of neighbors) {
599
- const alt = dist[u] + adj[u][v];
600
- if (alt < dist[v]) {
601
- dist[v] = alt;
602
- prev[v] = u;
603
- }
604
- }
605
- }
606
-
607
- let u = target;
608
- const ids = [u];
609
- let len = 0;
610
-
611
- while (prev[u] !== undefined) {
612
- ids.unshift(prev[u]);
613
- len += adj[u][prev[u]];
614
- u = prev[u];
615
- }
616
- return { ids, len };
617
- }
618
-
619
- sort(v_id?: string): V[] {
620
- const retVal: V[] = [];
621
- const visited: { [id: string]: boolean } = {};
622
-
623
- const visit = (vertex: Vertex<V>, ancestors: Vertex<V>[] = []) => {
624
- const v_id = vertex.id();
625
- if (visited[v_id]) return;
626
- visited[v_id] = true;
627
- ancestors.push(vertex);
628
- vertex.outEdges().forEach(e => {
629
- if (ancestors.indexOf(e._target) < 0) {
630
- visit(e._target, [...ancestors]);
631
- }
632
- });
633
- retVal.unshift(vertex._);
634
- };
635
-
636
- if (v_id) {
637
- visit(this._vertexMap[v_id]);
638
- } else {
639
- for (const key in this._vertexMap) {
640
- visit(this._vertexMap[key]);
641
- }
642
- }
643
-
644
- return retVal;
645
- }
646
- }
647
-
648
- class Set<T> {
649
-
650
- private _content: T[] = [];
651
- get size(): number {
652
- return this._content.length;
653
- }
654
-
655
- has(_: T) {
656
- return this._content.indexOf(_) >= 0;
657
- }
658
-
659
- add(_: T) {
660
- if (!this.has(_)) {
661
- this._content.push(_);
662
- }
663
- }
664
-
665
- delete(_: T) {
666
- const idx = this._content.indexOf(_);
667
- if (idx >= 0) {
668
- this._content.splice(idx, 1);
669
- }
670
- }
671
-
672
- forEach(_: (value: T, index: number, array: T[]) => void) {
673
- this._content.forEach(_);
674
- }
675
- }
1
+ import { compare2 } from "./array.ts";
2
+
3
+ type ID = string | number;
4
+
5
+ class GraphItem<T = any> {
6
+ protected _graph: Graph2;
7
+ _: T;
8
+ id(): ID {
9
+ return this._graph.id(this._);
10
+ }
11
+
12
+ constructor(g: Graph2, _: T) {
13
+ this._graph = g;
14
+ this._ = _;
15
+ }
16
+ }
17
+
18
+ class ChildGraphItem<S = any> extends GraphItem<S> {
19
+
20
+ private _parent: Subgraph | undefined;
21
+
22
+ constructor(g: Graph2, _: S) {
23
+ super(g, _);
24
+ }
25
+
26
+ clearParent(): this {
27
+ if (this._parent) {
28
+ this._parent.removeChild(this);
29
+ delete this._parent;
30
+ }
31
+ return this;
32
+ }
33
+
34
+ parent(): Subgraph | undefined;
35
+ parent(_: Subgraph | undefined): this;
36
+ parent(_?: Subgraph): Subgraph | undefined | this {
37
+ if (arguments.length === 0) return this._parent;
38
+ if (this._parent !== _) {
39
+ if (this._parent) {
40
+ this._parent.removeChild(this);
41
+ }
42
+ this._parent = _;
43
+ if (this._parent) {
44
+ this._parent.addChild(this);
45
+ }
46
+ }
47
+ return this;
48
+ }
49
+ }
50
+
51
+ class Subgraph<S = any> extends ChildGraphItem<S> {
52
+
53
+ private _children: ChildGraphItem[] = [];
54
+
55
+ constructor(g: Graph2, _: S) {
56
+ super(g, _);
57
+ }
58
+
59
+ children(): ChildGraphItem[] {
60
+ return this._children;
61
+ }
62
+
63
+ addChild(_: ChildGraphItem) {
64
+ this._children.push(_);
65
+ }
66
+
67
+ removeChild(_: ChildGraphItem) {
68
+ this._children = this._children.filter(row => row.id !== _.id);
69
+ }
70
+ }
71
+
72
+ class Vertex<V = any> extends ChildGraphItem<V> {
73
+
74
+ private _inEdges: Edge[] = [];
75
+ private _outEdges: Edge[] = [];
76
+
77
+ constructor(g: Graph2, _: V) {
78
+ super(g, _);
79
+ }
80
+
81
+ edges() {
82
+ return [...this._inEdges, ...this._outEdges];
83
+ }
84
+
85
+ edgeCount() {
86
+ return this._outEdges.length + this._inEdges.length;
87
+ }
88
+
89
+ inEdges() {
90
+ return this._inEdges;
91
+ }
92
+
93
+ addInEdge(e: Edge) {
94
+ this._inEdges.push(e);
95
+ }
96
+
97
+ removeInEdge(id: ID) {
98
+ this._inEdges = this._inEdges.filter(e => e._.id !== id);
99
+ }
100
+
101
+ outEdges() {
102
+ return this._outEdges;
103
+ }
104
+
105
+ addOutEdge(e: Edge) {
106
+ this._outEdges.push(e);
107
+ }
108
+
109
+ removeOutEdge(id: ID) {
110
+ this._outEdges = this._outEdges.filter(e => e._.id !== id);
111
+ }
112
+ }
113
+
114
+ class Edge<E = any> extends ChildGraphItem<E> {
115
+
116
+ _source: Vertex;
117
+ _target: Vertex;
118
+
119
+ constructor(g: Graph2, _: E, source: Vertex, target: Vertex) {
120
+ super(g, _);
121
+ this._source = source;
122
+ this._target = target;
123
+ }
124
+ }
125
+
126
+ type SubgraphMap<T> = { [id: string]: Subgraph<T> };
127
+ type VertexMap<T> = { [id: string]: Vertex<T> };
128
+ type EdgeMap<T> = { [id: string]: Edge<T> };
129
+
130
+ export type HierarchyFormatter<V, S> = (type: "subgraph" | "vertex", item: V | S, children?: object[]) => object;
131
+
132
+ export class Graph2<V = any, E = any, S = any> {
133
+
134
+ private _directed: boolean;
135
+ private _subgraphMap: SubgraphMap<S> = {};
136
+ private _vertexMap: VertexMap<V> = {};
137
+ private _edgeMap: EdgeMap<E> = {};
138
+
139
+ constructor(directed = true) {
140
+ this._directed = directed;
141
+ }
142
+
143
+ clear(): this {
144
+ this._subgraphMap = {};
145
+ this._vertexMap = {};
146
+ this._edgeMap = {};
147
+ return this;
148
+ }
149
+
150
+ clearParents(): this {
151
+ for (const key in this._subgraphMap) {
152
+ this._subgraphMap[key].clearParent();
153
+ }
154
+ for (const key in this._vertexMap) {
155
+ this._vertexMap[key].clearParent();
156
+ }
157
+ return this;
158
+ }
159
+
160
+ isDirected(): boolean {
161
+ return this._directed;
162
+ }
163
+
164
+ _idFunc = (_: any): ID => typeof _.id === "function" ? _.id() : _.id;
165
+ idFunc(_: (_: S | V | E) => ID): this {
166
+ this._idFunc = _;
167
+ return this;
168
+ }
169
+
170
+ _sourceFunc = (_: any): ID => typeof _.source === "function" ? _.source() : _.source;
171
+ sourceFunc(_: (_: E) => ID): this {
172
+ this._sourceFunc = _;
173
+ return this;
174
+ }
175
+
176
+ _targetFunc = (_: any): ID => typeof _.target === "function" ? _.target() : _.target;
177
+ targetFunc(_: (_: E) => ID): this {
178
+ this._targetFunc = _;
179
+ return this;
180
+ }
181
+
182
+ _updateFunc = (before: S | V | E, after: S | V | E): S | V | E => after;
183
+ updateFunc(_: (before: S | V | E, after: S | V | E) => S | V | E): this {
184
+ this._updateFunc = _;
185
+ return this;
186
+ }
187
+
188
+ id(_: S | V | E): ID {
189
+ return this._idFunc(_);
190
+ }
191
+
192
+ type(id: ID): "S" | "V" | "E" | "" {
193
+ if (this.subgraphExists(id)) return "S";
194
+ if (this.vertexExists(id)) return "V";
195
+ if (this.edgeExists(id)) return "E";
196
+ return "";
197
+ }
198
+
199
+ isSubgraph(_: S | V | E): _ is S {
200
+ return this.subgraphExists(this.id(_));
201
+ }
202
+
203
+ isVertex(_: S | V | E): _ is V {
204
+ return this.vertexExists(this.id(_));
205
+ }
206
+
207
+ isEdge(_: S | V | E): _ is E {
208
+ return this.edgeExists(this.id(_));
209
+ }
210
+
211
+ allItems(): Array<S | V | E> {
212
+ return [...this.allSubgraphs(), ...this.allVertices(), ...this.allEdges()];
213
+ }
214
+
215
+ item(id: ID): S | V | E | undefined {
216
+ if (this.subgraphExists(id)) return this.subgraph(id);
217
+ if (this.vertexExists(id)) return this.vertex(id);
218
+ if (this.edgeExists(id)) return this.edge(id);
219
+ return undefined;
220
+ }
221
+
222
+ itemExists(id: ID): boolean {
223
+ return this.edgeExists(id) || this.vertexExists(id) || this.subgraphExists(id);
224
+ }
225
+
226
+ // Subgraphs ---
227
+ allSubgraphs(): S[] {
228
+ const retVal: S[] = [];
229
+ for (const key in this._subgraphMap) {
230
+ retVal.push(this._subgraphMap[key]._);
231
+ }
232
+ return retVal;
233
+ }
234
+
235
+ subgraphs(): S[] {
236
+ const retVal: S[] = [];
237
+ for (const key in this._subgraphMap) {
238
+ if (this._subgraphMap[key].parent() === undefined) {
239
+ retVal.push(this._subgraphMap[key]._);
240
+ }
241
+ }
242
+ return retVal;
243
+ }
244
+
245
+ subgraphExists(id: ID): boolean {
246
+ return !!this._subgraphMap[id];
247
+ }
248
+
249
+ subgraph(id: ID): S {
250
+ return this._subgraphMap[id]._;
251
+ }
252
+
253
+ subgraphSubgraphs(id: ID): S[] {
254
+ return this._subgraphMap[id].children().filter(child => this.isSubgraph(child._)).map(child => child._);
255
+ }
256
+
257
+ subgraphVertices(id: ID): V[] {
258
+ return this._subgraphMap[id].children().filter(child => this.isVertex(child._)).map(child => child._);
259
+ }
260
+
261
+ subgraphEdges(id: ID): E[] {
262
+ return this._subgraphMap[id].children().filter(child => this.isEdge(child._)).map(child => child._);
263
+ }
264
+
265
+ addSubgraph(s: S, parent?: S): this {
266
+ const s_id = this._idFunc(s);
267
+ if (this._subgraphMap[s_id]) throw new Error(`Subgraph '${s_id}' already exists.`);
268
+ const subgraph = new Subgraph(this, s);
269
+ if (parent) {
270
+ const p_id = this._idFunc(parent);
271
+ if (!this._subgraphMap[p_id]) throw new Error(`Subgraph '${p_id}' does not exist.`);
272
+ subgraph.parent(this._subgraphMap[p_id]);
273
+ }
274
+ this._subgraphMap[s_id] = subgraph;
275
+ return this;
276
+ }
277
+
278
+ mergeSubgraphs(_subgraphs: S[] = []): this {
279
+ const sgDiff = compare2<S>(this.allSubgraphs(), _subgraphs, sg => this._idFunc(sg), this._updateFunc as any);
280
+ sgDiff.exit.forEach(sg => this.removeSubgraph(this._idFunc(sg)));
281
+ sgDiff.enter.forEach(sg => this.addSubgraph(sg));
282
+ sgDiff.update.forEach(sg => this.updateSubgraph(sg));
283
+ return this;
284
+ }
285
+
286
+ updateSubgraph(sg: S): this {
287
+ const sg_id = this._idFunc(sg);
288
+ const subgraph = this._subgraphMap[sg_id];
289
+ if (!subgraph) throw new Error(`Subgraph '${sg_id}' does not exist.`);
290
+ subgraph._ = sg;
291
+ return this;
292
+ }
293
+
294
+ removeSubgraph(id: ID, promoteChildren = true): this {
295
+ const sg = this._subgraphMap[id];
296
+ if (!sg) throw new Error(`Subgraph '${id}' does not exist.`);
297
+ sg.children().forEach(child => {
298
+ if (promoteChildren) {
299
+ child.parent(sg.parent());
300
+ } else {
301
+ if (child instanceof Subgraph) {
302
+ this.removeSubgraph(child.id());
303
+ } else {
304
+ this.removeVertex(child.id());
305
+ }
306
+ }
307
+ });
308
+ delete this._subgraphMap[id];
309
+ return this;
310
+ }
311
+
312
+ subgraphParent(id: ID): S | undefined;
313
+ subgraphParent(id: ID, parentID: ID): this;
314
+ subgraphParent(id: ID, parentID?: ID): S | undefined | this {
315
+ const item = this._subgraphMap[id];
316
+ if (!item) throw new Error(`Subgraph '${id}' does not exist.`);
317
+ if (parentID === void 0) {
318
+ const parent = item.parent();
319
+ return parent ? parent._ as S : undefined;
320
+ }
321
+ const parent = this._subgraphMap[parentID];
322
+ if (!parent) throw new Error(`Vertex parent '${parent}' does not exist.`);
323
+ item.parent(parent);
324
+ return this;
325
+ }
326
+
327
+ // Vertices ---
328
+ allVertices(): V[] {
329
+ const retVal: V[] = [];
330
+ for (const key in this._vertexMap) {
331
+ retVal.push(this._vertexMap[key]._);
332
+ }
333
+ return retVal;
334
+ }
335
+
336
+ vertices(): V[] {
337
+ const retVal: V[] = [];
338
+ for (const key in this._vertexMap) {
339
+ if (this._vertexMap[key].parent() === undefined) {
340
+ retVal.push(this._vertexMap[key]._);
341
+ }
342
+ }
343
+ return retVal;
344
+ }
345
+
346
+ vertexExists(id: ID): boolean {
347
+ return !!this._vertexMap[id];
348
+ }
349
+
350
+ vertex(id: ID): V {
351
+ return this._vertexMap[id]._;
352
+ }
353
+
354
+ allEdges(): E[] {
355
+ const retVal: E[] = [];
356
+ for (const key in this._edgeMap) {
357
+ retVal.push(this._edgeMap[key]._);
358
+ }
359
+ return retVal;
360
+ }
361
+
362
+ edges(): E[] {
363
+ const retVal: E[] = [];
364
+ for (const key in this._edgeMap) {
365
+ if (this._edgeMap[key].parent() === undefined) {
366
+ retVal.push(this._edgeMap[key]._);
367
+ }
368
+ }
369
+ return retVal;
370
+ }
371
+
372
+ vertexEdges(vertexID: ID): E[] {
373
+ return this._vertexMap[vertexID].edges().map(e => e._);
374
+ }
375
+
376
+ inEdges(vertexID: ID): E[] {
377
+ return this._vertexMap[vertexID].inEdges().map(e => e._);
378
+ }
379
+
380
+ outEdges(vertexID: ID): E[] {
381
+ return this._vertexMap[vertexID].outEdges().map(e => e._);
382
+ }
383
+
384
+ private _neighbors(id: ID): Vertex[] {
385
+ return [...this._vertexMap[id].outEdges().map(e => e._target), ...this._vertexMap[id].inEdges().map(e => e._source)];
386
+ }
387
+
388
+ neighbors(id: ID): V[] {
389
+ return this._neighbors(id).map(n => n._);
390
+ }
391
+
392
+ singleNeighbors(id: ID): V[] {
393
+ return this._neighbors(id).filter(n => n.edgeCount() === 1).map(n => n._);
394
+ }
395
+
396
+ addVertex(v: V, parent?: S): this {
397
+ const v_id = this._idFunc(v);
398
+ if (this._vertexMap[v_id]) throw new Error(`Vertex '${v_id}' already exists.`);
399
+ const vertex = new Vertex(this, v);
400
+ if (parent) {
401
+ const p_id = this._idFunc(parent);
402
+ if (!this.subgraphExists(p_id)) throw new Error(`Subgraph '${p_id}' does not exist.`);
403
+ vertex.parent(this._subgraphMap[p_id]);
404
+ }
405
+ this._vertexMap[v_id] = vertex;
406
+ return this;
407
+ }
408
+
409
+ mergeVertices(_vertices: V[]): this {
410
+ const vDiff = compare2(this.allVertices(), _vertices, v => this._idFunc(v), this._updateFunc as any);
411
+ vDiff.exit.forEach(v => this.removeVertex(this._idFunc(v)));
412
+ vDiff.enter.forEach(v => this.addVertex(v));
413
+ vDiff.update.forEach(v => this.updateVertex(v));
414
+ return this;
415
+ }
416
+
417
+ updateVertex(v: V): this {
418
+ const v_id = this._idFunc(v);
419
+ const vertex = this._vertexMap[v_id];
420
+ if (!vertex) throw new Error(`Vertex '${v_id}' does not exist.`);
421
+ vertex._ = v;
422
+ return this;
423
+ }
424
+
425
+ removeVertex(id: ID): this {
426
+ const v = this._vertexMap[id];
427
+ if (!v) throw new Error(`Vertex '${id}' does not exist.`);
428
+ v.edges().forEach(e => {
429
+ this.removeEdge(e.id());
430
+ });
431
+ delete this._vertexMap[id];
432
+ return this;
433
+ }
434
+
435
+ vertexParent(id: ID): S | undefined;
436
+ vertexParent(id: ID, parentID: ID): this;
437
+ vertexParent(id: ID, parentID?: ID): S | undefined | this {
438
+ const item = this._vertexMap[id];
439
+ if (!item) throw new Error(`Vertex '${id}' does not exist.`);
440
+ if (parentID === void 0) {
441
+ const parent = item.parent();
442
+ return parent ? parent._ as S : undefined;
443
+ }
444
+ const parent = this._subgraphMap[parentID];
445
+ if (!parent) throw new Error(`Vertex parent '${parent}' does not exist.`);
446
+ item.parent(parent);
447
+ return this;
448
+ }
449
+
450
+ // Edges ---
451
+ edgeExists(id: ID): boolean {
452
+ return !!this._edgeMap[id];
453
+ }
454
+
455
+ edge(id: ID): E {
456
+ return this._edgeMap[id]._;
457
+ }
458
+
459
+ addEdge(e: E, parent?: S): this {
460
+ const e_id = this._idFunc(e);
461
+ const e_source = this._sourceFunc(e);
462
+ const e_target = this._targetFunc(e);
463
+ if (this._edgeMap[e_id]) throw new Error(`Edge '${e_id}' already exists.`);
464
+ if (!this.vertexExists(e_source)) throw new Error(`Edge Source '${e_source}' does not exist.`);
465
+ if (!this.vertexExists(e_target)) throw new Error(`Edge Target '${e_target}' does not exist.`);
466
+ const edge = new Edge(this, e, this._vertexMap[e_source], this._vertexMap[e_target]);
467
+ if (parent) {
468
+ const p_id = this._idFunc(parent);
469
+ if (!this.subgraphExists(p_id)) throw new Error(`Subgraph '${p_id}' does not exist.`);
470
+ edge.parent(this._subgraphMap[p_id]);
471
+ }
472
+ this._edgeMap[e_id] = edge;
473
+ this._vertexMap[e_source].addOutEdge(edge);
474
+ this._vertexMap[e_target].addInEdge(edge);
475
+ return this;
476
+ }
477
+
478
+ mergeEdges(_edges: E[]): this {
479
+ const eDiff = compare2(this.allEdges(), _edges, e => this._idFunc(e), this._updateFunc as any);
480
+ eDiff.exit.forEach(e => this.removeEdge(this._idFunc(e)));
481
+ eDiff.enter.forEach(e => this.addEdge(e));
482
+ eDiff.update.forEach(e => this.updateEdge(e));
483
+ return this;
484
+ }
485
+
486
+ updateEdge(e: E): this {
487
+ const e_id = this._idFunc(e);
488
+ const edge = this._edgeMap[e_id];
489
+ if (!edge) throw new Error(`Edge '${e_id}' does not exist.`);
490
+ const old_source = edge._source.id();
491
+ const new_source = this._sourceFunc(e);
492
+ if (old_source !== new_source) {
493
+ this._vertexMap[old_source]?.removeOutEdge(e_id);
494
+ this._vertexMap[new_source]?.addOutEdge(edge);
495
+ }
496
+ const old_target = edge._target.id();
497
+ const new_target = this._targetFunc(e);
498
+ if (old_target !== new_target) {
499
+ this._vertexMap[old_target]?.removeInEdge(e_id);
500
+ this._vertexMap[new_target]?.addInEdge(edge);
501
+ }
502
+ edge._ = e;
503
+ edge._source = this._vertexMap[new_source];
504
+ edge._target = this._vertexMap[new_target];
505
+ return this;
506
+ }
507
+
508
+ removeEdge(id: ID): this {
509
+ const e: Edge<E> = this._edgeMap[id];
510
+ if (!e) throw new Error(`Edge '${id}' does not exist.`);
511
+
512
+ const e_sourceID = this._idFunc(e._source._);
513
+ if (!this.vertexExists(e_sourceID)) throw new Error(`Edge Source'${e_sourceID}' does not exist.`);
514
+ this._vertexMap[e_sourceID].removeOutEdge(id);
515
+
516
+ const e_targetID = this._idFunc(e._target._);
517
+ if (!this.vertexExists(e_targetID)) throw new Error(`Edge Target'${e_targetID}' does not exist.`);
518
+ this._vertexMap[e_targetID].removeInEdge(id);
519
+
520
+ delete this._edgeMap[id];
521
+ return this;
522
+ }
523
+
524
+ protected _hwalk(item: Subgraph<S> | Vertex<V>, formatter: HierarchyFormatter<V, S>): object {
525
+ if (item instanceof Subgraph) {
526
+ return formatter("subgraph", item._, item.children().map(child => this._hwalk(child as Subgraph<S> | Vertex<V>, formatter)));
527
+ } else {
528
+ return formatter("vertex", item._);
529
+ }
530
+ }
531
+
532
+ hierarchy(formatter: HierarchyFormatter<V, S>): object[] {
533
+ const retVal: object[] = [];
534
+ for (const id in this._subgraphMap) {
535
+ const sg = this._subgraphMap[id];
536
+ if (sg.parent() === undefined) {
537
+ retVal.push(this._hwalk(sg, formatter));
538
+ }
539
+ }
540
+ for (const id in this._vertexMap) {
541
+ const v = this._vertexMap[id];
542
+ if (v.parent() === undefined) {
543
+ retVal.push(this._hwalk(v, formatter));
544
+ }
545
+ }
546
+ return retVal;
547
+ }
548
+
549
+ dijkstra(source: ID, target: ID): { ids: ID[], len: number } {
550
+ const edges = this.allEdges();
551
+ const Q = new Set<string | number>();
552
+ const prev: { [key: string]: string } = {};
553
+ const dist: { [key: string]: number } = {};
554
+ const adj: { [key: string]: { [key: string]: number } } = {};
555
+
556
+ function vertex_with_min_dist(Q: Set<string | number>, dist: { [key: string]: number }) {
557
+ let min_distance = Infinity;
558
+ let u: string | number | null = null;
559
+
560
+ Q.forEach(v => {
561
+ if (dist[v] < min_distance) {
562
+ min_distance = dist[v];
563
+ u = v;
564
+ }
565
+ });
566
+ return u;
567
+ }
568
+
569
+ for (let i = 0; i < edges.length; i++) {
570
+ const v1 = this._sourceFunc(edges[i]);
571
+ const v2 = this._targetFunc(edges[i]);
572
+ const len = 1;
573
+
574
+ Q.add(v1);
575
+ Q.add(v2);
576
+
577
+ dist[v1] = Infinity;
578
+ dist[v2] = Infinity;
579
+
580
+ if (adj[v1] === undefined) adj[v1] = {};
581
+ if (adj[v2] === undefined) adj[v2] = {};
582
+
583
+ adj[v1][v2] = len;
584
+ adj[v2][v1] = len;
585
+ }
586
+
587
+ dist[source] = 0;
588
+
589
+ while (Q.size) {
590
+ const u = vertex_with_min_dist(Q, dist);
591
+ if (u === null) break;
592
+ const neighbors = Object.keys(adj[u]).filter(v => Q.has(v)); // Neighbor still in Q
593
+
594
+ Q.delete(u);
595
+
596
+ if (u === target) break; // Break when the target has been found
597
+
598
+ for (const v of neighbors) {
599
+ const alt = dist[u] + adj[u][v];
600
+ if (alt < dist[v]) {
601
+ dist[v] = alt;
602
+ prev[v] = u;
603
+ }
604
+ }
605
+ }
606
+
607
+ let u = target;
608
+ const ids = [u];
609
+ let len = 0;
610
+
611
+ while (prev[u] !== undefined) {
612
+ ids.unshift(prev[u]);
613
+ len += adj[u][prev[u]];
614
+ u = prev[u];
615
+ }
616
+ return { ids, len };
617
+ }
618
+
619
+ sort(v_id?: string): V[] {
620
+ const retVal: V[] = [];
621
+ const visited: { [id: string]: boolean } = {};
622
+
623
+ const visit = (vertex: Vertex<V>, ancestors: Vertex<V>[] = []) => {
624
+ const v_id = vertex.id();
625
+ if (visited[v_id]) return;
626
+ visited[v_id] = true;
627
+ ancestors.push(vertex);
628
+ vertex.outEdges().forEach(e => {
629
+ if (ancestors.indexOf(e._target) < 0) {
630
+ visit(e._target, [...ancestors]);
631
+ }
632
+ });
633
+ retVal.unshift(vertex._);
634
+ };
635
+
636
+ if (v_id) {
637
+ visit(this._vertexMap[v_id]);
638
+ } else {
639
+ for (const key in this._vertexMap) {
640
+ visit(this._vertexMap[key]);
641
+ }
642
+ }
643
+
644
+ return retVal;
645
+ }
646
+ }
647
+
648
+ class Set<T> {
649
+
650
+ private _content: T[] = [];
651
+ get size(): number {
652
+ return this._content.length;
653
+ }
654
+
655
+ has(_: T) {
656
+ return this._content.indexOf(_) >= 0;
657
+ }
658
+
659
+ add(_: T) {
660
+ if (!this.has(_)) {
661
+ this._content.push(_);
662
+ }
663
+ }
664
+
665
+ delete(_: T) {
666
+ const idx = this._content.indexOf(_);
667
+ if (idx >= 0) {
668
+ this._content.splice(idx, 1);
669
+ }
670
+ }
671
+
672
+ forEach(_: (value: T, index: number, array: T[]) => void) {
673
+ this._content.forEach(_);
674
+ }
675
+ }