ttpg-darrell 1.1.7 → 1.1.10
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/build/cjs/lib/adjacency/adjacency.d.ts +23 -48
- package/build/cjs/lib/adjacency/adjacency.js +81 -174
- package/build/cjs/lib/adjacency/adjacency.js.map +1 -1
- package/build/esm/lib/adjacency/adjacency.d.ts +23 -48
- package/build/esm/lib/adjacency/adjacency.js +81 -174
- package/build/esm/lib/adjacency/adjacency.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,57 +1,32 @@
|
|
|
1
|
-
export type AdjacencyResult = {
|
|
2
|
-
node: string;
|
|
3
|
-
distance: number;
|
|
4
|
-
path: Array<string>;
|
|
5
|
-
};
|
|
6
1
|
/**
|
|
7
|
-
*
|
|
8
|
-
* Tansit nodes are on a path, but do not add to distance ("hyperlane").
|
|
9
|
-
* Transit nodes are not "reachable" and will not appear as destinations,
|
|
10
|
-
* but they can appear in paths to reach other nodes.
|
|
11
|
-
*
|
|
12
|
-
* If two nodes share a tag they are NOT connected UNLESS there is a link
|
|
13
|
-
* from tag back to itself.
|
|
14
|
-
*
|
|
15
|
-
* A link may connect to multiple nodes that share the tag.
|
|
2
|
+
* Opaque node id. Could be a hex coordinate, a wormhole class, etc.
|
|
16
3
|
*/
|
|
4
|
+
export type AdjacencyNodeType = string;
|
|
5
|
+
/**
|
|
6
|
+
* Directed link between two nodes.
|
|
7
|
+
* Paths cannot end with a transit node; they must connect two non-transit nodes.
|
|
8
|
+
*/
|
|
9
|
+
export type AdjacencyLinkType = {
|
|
10
|
+
src: AdjacencyNodeType;
|
|
11
|
+
dst: AdjacencyNodeType;
|
|
12
|
+
distance: number;
|
|
13
|
+
isTransit: boolean;
|
|
14
|
+
};
|
|
15
|
+
export type AdjacencyPathType = {
|
|
16
|
+
node: AdjacencyNodeType;
|
|
17
|
+
distance: number;
|
|
18
|
+
path: ReadonlyArray<AdjacencyLinkType>;
|
|
19
|
+
};
|
|
17
20
|
export declare class Adjacency {
|
|
18
|
-
private readonly
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
private readonly _transitNodes;
|
|
22
|
-
/**
|
|
23
|
-
* Add a node tag. Node tags may name the node, a specific edge, or a
|
|
24
|
-
* possibly-many-neighbors "hub tag" such as a wormhole.
|
|
25
|
-
*
|
|
26
|
-
* @param node
|
|
27
|
-
* @param tags
|
|
28
|
-
* @returns
|
|
29
|
-
*/
|
|
30
|
-
addNodeTags(node: string, tags: Array<string>): this;
|
|
31
|
-
removeNodeTags(node: string, tags: Array<string>): this;
|
|
32
|
-
hasNodeTag(node: string, tag: string): boolean;
|
|
33
|
-
_hasTagNode(tag: string, node: string): boolean;
|
|
21
|
+
private readonly _srcNodeOutgoingLinks;
|
|
22
|
+
addLink(link: AdjacencyLinkType): this;
|
|
23
|
+
hasLink(link: AdjacencyLinkType): boolean;
|
|
34
24
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* @param tag1
|
|
38
|
-
* @param tag2
|
|
39
|
-
* @returns
|
|
40
|
-
*/
|
|
41
|
-
addLink(tag1: string, tag2: string): this;
|
|
42
|
-
removeLink(tag1: string, tag2: string): this;
|
|
43
|
-
hasLink(tag1: string, tag2: string): boolean;
|
|
44
|
-
/**
|
|
45
|
-
* Transit nodes can appear along a path but do not add to distance
|
|
46
|
-
* (e.g. hyperlanes).
|
|
25
|
+
* Remove all links starting OR ENDING from the given node.
|
|
47
26
|
*
|
|
48
27
|
* @param node
|
|
49
|
-
* @returns
|
|
50
28
|
*/
|
|
51
|
-
|
|
52
|
-
removeTransitNode(node: string): this;
|
|
53
|
-
hasTransitNode(node: string): boolean;
|
|
54
|
-
_getAdjacentNodeSet(node: string): Set<string>;
|
|
29
|
+
removeNode(node: AdjacencyNodeType): this;
|
|
55
30
|
/**
|
|
56
31
|
* Compute shortest paths to all nodes within maxDistance.
|
|
57
32
|
*
|
|
@@ -59,5 +34,5 @@ export declare class Adjacency {
|
|
|
59
34
|
* @param maxDistance
|
|
60
35
|
* @returns
|
|
61
36
|
*/
|
|
62
|
-
get(origin:
|
|
37
|
+
get(origin: AdjacencyNodeType, maxDistance: number): ReadonlyArray<AdjacencyPathType>;
|
|
63
38
|
}
|
|
@@ -2,161 +2,55 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Adjacency = void 0;
|
|
4
4
|
const heap_1 = require("../heap/heap");
|
|
5
|
-
/**
|
|
6
|
-
* Nodes have tags, links connect tags.
|
|
7
|
-
* Tansit nodes are on a path, but do not add to distance ("hyperlane").
|
|
8
|
-
* Transit nodes are not "reachable" and will not appear as destinations,
|
|
9
|
-
* but they can appear in paths to reach other nodes.
|
|
10
|
-
*
|
|
11
|
-
* If two nodes share a tag they are NOT connected UNLESS there is a link
|
|
12
|
-
* from tag back to itself.
|
|
13
|
-
*
|
|
14
|
-
* A link may connect to multiple nodes that share the tag.
|
|
15
|
-
*/
|
|
16
5
|
class Adjacency {
|
|
17
6
|
constructor() {
|
|
18
|
-
this.
|
|
19
|
-
this._tagToNodeSet = {};
|
|
20
|
-
this._tagToLinkedTagSet = {};
|
|
21
|
-
this._transitNodes = new Set();
|
|
7
|
+
this._srcNodeOutgoingLinks = new Map();
|
|
22
8
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
* @returns
|
|
30
|
-
*/
|
|
31
|
-
addNodeTags(node, tags) {
|
|
32
|
-
let tagSet;
|
|
33
|
-
let nodeSet;
|
|
34
|
-
tagSet = this._nodeToTagSet[node];
|
|
35
|
-
if (!tagSet) {
|
|
36
|
-
tagSet = new Set();
|
|
37
|
-
this._nodeToTagSet[node] = tagSet;
|
|
38
|
-
}
|
|
39
|
-
for (const tag of tags) {
|
|
40
|
-
tagSet.add(tag);
|
|
41
|
-
nodeSet = this._tagToNodeSet[tag];
|
|
42
|
-
if (!nodeSet) {
|
|
43
|
-
nodeSet = new Set();
|
|
44
|
-
this._tagToNodeSet[tag] = nodeSet;
|
|
45
|
-
}
|
|
46
|
-
nodeSet.add(node);
|
|
9
|
+
addLink(link) {
|
|
10
|
+
// Create the src->link set if missing.
|
|
11
|
+
let outgoingLinks = this._srcNodeOutgoingLinks.get(link.src);
|
|
12
|
+
if (!outgoingLinks) {
|
|
13
|
+
outgoingLinks = new Set();
|
|
14
|
+
this._srcNodeOutgoingLinks.set(link.src, outgoingLinks);
|
|
47
15
|
}
|
|
16
|
+
// Add immutable link.
|
|
17
|
+
link = Object.freeze(link); // make immutable
|
|
18
|
+
outgoingLinks.add(link);
|
|
48
19
|
return this;
|
|
49
20
|
}
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
21
|
+
hasLink(link) {
|
|
22
|
+
const outgoingLinks = this._srcNodeOutgoingLinks.get(link.src);
|
|
23
|
+
if (outgoingLinks) {
|
|
24
|
+
for (const outgoingLink of outgoingLinks) {
|
|
25
|
+
if (outgoingLink.src === link.src &&
|
|
26
|
+
outgoingLink.dst === link.dst &&
|
|
27
|
+
outgoingLink.distance === link.distance &&
|
|
28
|
+
outgoingLink.isTransit === link.isTransit) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
59
31
|
}
|
|
60
32
|
}
|
|
61
|
-
return
|
|
62
|
-
}
|
|
63
|
-
hasNodeTag(node, tag) {
|
|
64
|
-
var _a;
|
|
65
|
-
const tagSet = this._nodeToTagSet[node];
|
|
66
|
-
return (_a = tagSet === null || tagSet === void 0 ? void 0 : tagSet.has(tag)) !== null && _a !== void 0 ? _a : false;
|
|
67
|
-
}
|
|
68
|
-
_hasTagNode(tag, node) {
|
|
69
|
-
var _a;
|
|
70
|
-
const nodeSet = this._tagToNodeSet[tag];
|
|
71
|
-
return (_a = nodeSet === null || nodeSet === void 0 ? void 0 : nodeSet.has(node)) !== null && _a !== void 0 ? _a : false;
|
|
33
|
+
return false;
|
|
72
34
|
}
|
|
73
35
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* @param tag1
|
|
77
|
-
* @param tag2
|
|
78
|
-
* @returns
|
|
79
|
-
*/
|
|
80
|
-
addLink(tag1, tag2) {
|
|
81
|
-
let linkedTagSet;
|
|
82
|
-
// 1 -> 1, 1 -> 2.
|
|
83
|
-
linkedTagSet = this._tagToLinkedTagSet[tag1];
|
|
84
|
-
if (!linkedTagSet) {
|
|
85
|
-
linkedTagSet = new Set();
|
|
86
|
-
this._tagToLinkedTagSet[tag1] = linkedTagSet;
|
|
87
|
-
}
|
|
88
|
-
linkedTagSet.add(tag1);
|
|
89
|
-
linkedTagSet.add(tag2);
|
|
90
|
-
// 2 -> 1, 2 -> 2.
|
|
91
|
-
linkedTagSet = this._tagToLinkedTagSet[tag2];
|
|
92
|
-
if (!linkedTagSet) {
|
|
93
|
-
linkedTagSet = new Set();
|
|
94
|
-
this._tagToLinkedTagSet[tag2] = linkedTagSet;
|
|
95
|
-
}
|
|
96
|
-
linkedTagSet.add(tag1);
|
|
97
|
-
linkedTagSet.add(tag2);
|
|
98
|
-
return this;
|
|
99
|
-
}
|
|
100
|
-
removeLink(tag1, tag2) {
|
|
101
|
-
let linkedTagSet;
|
|
102
|
-
// 1 -> 1, 1 -> 2.
|
|
103
|
-
linkedTagSet = this._tagToLinkedTagSet[tag1];
|
|
104
|
-
if (linkedTagSet) {
|
|
105
|
-
linkedTagSet.delete(tag1);
|
|
106
|
-
linkedTagSet.delete(tag2);
|
|
107
|
-
}
|
|
108
|
-
// 2 -> 1, 2 -> 2.
|
|
109
|
-
linkedTagSet = this._tagToLinkedTagSet[tag2];
|
|
110
|
-
if (linkedTagSet) {
|
|
111
|
-
linkedTagSet.delete(tag1);
|
|
112
|
-
linkedTagSet.delete(tag2);
|
|
113
|
-
}
|
|
114
|
-
return this;
|
|
115
|
-
}
|
|
116
|
-
hasLink(tag1, tag2) {
|
|
117
|
-
var _a;
|
|
118
|
-
const linkedTagSet = this._tagToLinkedTagSet[tag1];
|
|
119
|
-
return (_a = linkedTagSet === null || linkedTagSet === void 0 ? void 0 : linkedTagSet.has(tag2)) !== null && _a !== void 0 ? _a : false;
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Transit nodes can appear along a path but do not add to distance
|
|
123
|
-
* (e.g. hyperlanes).
|
|
36
|
+
* Remove all links starting OR ENDING from the given node.
|
|
124
37
|
*
|
|
125
38
|
* @param node
|
|
126
|
-
* @returns
|
|
127
39
|
*/
|
|
128
|
-
|
|
129
|
-
this.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
hasTransitNode(node) {
|
|
137
|
-
return this._transitNodes.has(node);
|
|
138
|
-
}
|
|
139
|
-
_getAdjacentNodeSet(node) {
|
|
140
|
-
const tagSet = this._nodeToTagSet[node];
|
|
141
|
-
const adjNodeSet = new Set();
|
|
142
|
-
if (tagSet) {
|
|
143
|
-
for (const tag of tagSet) {
|
|
144
|
-
const linkedTagSet = this._tagToLinkedTagSet[tag];
|
|
145
|
-
if (linkedTagSet) {
|
|
146
|
-
for (const linkedTag of linkedTagSet) {
|
|
147
|
-
const nodeSet = this._tagToNodeSet[linkedTag];
|
|
148
|
-
if (nodeSet) {
|
|
149
|
-
for (const linkedNode of nodeSet) {
|
|
150
|
-
if (linkedNode !== node) {
|
|
151
|
-
adjNodeSet.add(linkedNode);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
40
|
+
removeNode(node) {
|
|
41
|
+
this._srcNodeOutgoingLinks.delete(node);
|
|
42
|
+
for (const outgoingLinks of this._srcNodeOutgoingLinks.values()) {
|
|
43
|
+
const dele = new Set();
|
|
44
|
+
for (const link of outgoingLinks) {
|
|
45
|
+
if (link.dst === node) {
|
|
46
|
+
dele.add(link);
|
|
156
47
|
}
|
|
157
48
|
}
|
|
49
|
+
for (const link of dele) {
|
|
50
|
+
outgoingLinks.delete(link);
|
|
51
|
+
}
|
|
158
52
|
}
|
|
159
|
-
return
|
|
53
|
+
return this;
|
|
160
54
|
}
|
|
161
55
|
/**
|
|
162
56
|
* Compute shortest paths to all nodes within maxDistance.
|
|
@@ -166,52 +60,65 @@ class Adjacency {
|
|
|
166
60
|
* @returns
|
|
167
61
|
*/
|
|
168
62
|
get(origin, maxDistance) {
|
|
169
|
-
const
|
|
63
|
+
const nodeToAdjacencyPath = new Map();
|
|
64
|
+
const toExplore = new Set();
|
|
65
|
+
const explored = new Set();
|
|
66
|
+
// Start with the origin.
|
|
67
|
+
toExplore.add(origin); // start from the origin
|
|
68
|
+
const heap = new heap_1.Heap().add(origin, 0);
|
|
69
|
+
nodeToAdjacencyPath.set(origin, {
|
|
170
70
|
node: origin,
|
|
171
71
|
distance: 0,
|
|
172
|
-
path: [
|
|
173
|
-
};
|
|
174
|
-
const nodeToAdjacencyResult = {
|
|
175
|
-
[origin]: originAdjacencyResult,
|
|
176
|
-
};
|
|
177
|
-
const toVisit = new Set([
|
|
178
|
-
originAdjacencyResult,
|
|
179
|
-
]);
|
|
180
|
-
const visited = new Set();
|
|
181
|
-
const heap = new heap_1.Heap().add(origin, 0);
|
|
72
|
+
path: [],
|
|
73
|
+
});
|
|
182
74
|
let closestNode;
|
|
183
|
-
while (
|
|
75
|
+
while (toExplore.size > 0 && (closestNode = heap.removeMin())) {
|
|
184
76
|
// Find the closest of the to-visit nodes.
|
|
185
|
-
const closest =
|
|
77
|
+
const closest = nodeToAdjacencyPath.get(closestNode);
|
|
186
78
|
if (closest) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
79
|
+
// Mark as explored.
|
|
80
|
+
toExplore.delete(closest.node);
|
|
81
|
+
explored.add(closest.node);
|
|
82
|
+
// Walk the outgoing link destinations.
|
|
83
|
+
const outgoingLinks = this._srcNodeOutgoingLinks.get(closest.node);
|
|
84
|
+
if (outgoingLinks) {
|
|
85
|
+
for (const outgoingLink of outgoingLinks) {
|
|
86
|
+
const dst = outgoingLink.dst;
|
|
87
|
+
if (!explored.has(dst)) {
|
|
88
|
+
const distance = closest.distance + outgoingLink.distance;
|
|
89
|
+
const path = [
|
|
90
|
+
...closest.path,
|
|
91
|
+
outgoingLink,
|
|
92
|
+
];
|
|
93
|
+
if (distance <= maxDistance) {
|
|
94
|
+
// This dst is new and within range, add it to to-explore list.
|
|
95
|
+
toExplore.add(dst);
|
|
96
|
+
heap.add(dst, distance);
|
|
97
|
+
// Also add to the adjacency paths, even if ends with a transit.
|
|
98
|
+
nodeToAdjacencyPath.set(dst, {
|
|
99
|
+
node: dst,
|
|
100
|
+
distance,
|
|
101
|
+
path,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
205
104
|
}
|
|
206
105
|
}
|
|
207
106
|
}
|
|
208
107
|
}
|
|
209
108
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
109
|
+
// Get paths not ending with a transit node and make immutable.
|
|
110
|
+
const result = [
|
|
111
|
+
...nodeToAdjacencyPath.values(),
|
|
112
|
+
]
|
|
113
|
+
.filter((adjacencyPathType) => {
|
|
114
|
+
const lastLink = adjacencyPathType.path[adjacencyPathType.path.length - 1];
|
|
115
|
+
return lastLink !== undefined && !lastLink.isTransit;
|
|
116
|
+
})
|
|
117
|
+
.map((adjacencyPathType) => {
|
|
118
|
+
return Object.freeze(adjacencyPathType);
|
|
119
|
+
});
|
|
213
120
|
// Sort by distance.
|
|
214
|
-
result
|
|
121
|
+
result.sort((a, b) => {
|
|
215
122
|
if (a.distance < b.distance) {
|
|
216
123
|
return -1;
|
|
217
124
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adjacency.js","sourceRoot":"","sources":["../../../../src/lib/adjacency/adjacency.ts"],"names":[],"mappings":";;;AAAA,uCAAoC;
|
|
1
|
+
{"version":3,"file":"adjacency.js","sourceRoot":"","sources":["../../../../src/lib/adjacency/adjacency.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,57 +1,32 @@
|
|
|
1
|
-
export type AdjacencyResult = {
|
|
2
|
-
node: string;
|
|
3
|
-
distance: number;
|
|
4
|
-
path: Array<string>;
|
|
5
|
-
};
|
|
6
1
|
/**
|
|
7
|
-
*
|
|
8
|
-
* Tansit nodes are on a path, but do not add to distance ("hyperlane").
|
|
9
|
-
* Transit nodes are not "reachable" and will not appear as destinations,
|
|
10
|
-
* but they can appear in paths to reach other nodes.
|
|
11
|
-
*
|
|
12
|
-
* If two nodes share a tag they are NOT connected UNLESS there is a link
|
|
13
|
-
* from tag back to itself.
|
|
14
|
-
*
|
|
15
|
-
* A link may connect to multiple nodes that share the tag.
|
|
2
|
+
* Opaque node id. Could be a hex coordinate, a wormhole class, etc.
|
|
16
3
|
*/
|
|
4
|
+
export type AdjacencyNodeType = string;
|
|
5
|
+
/**
|
|
6
|
+
* Directed link between two nodes.
|
|
7
|
+
* Paths cannot end with a transit node; they must connect two non-transit nodes.
|
|
8
|
+
*/
|
|
9
|
+
export type AdjacencyLinkType = {
|
|
10
|
+
src: AdjacencyNodeType;
|
|
11
|
+
dst: AdjacencyNodeType;
|
|
12
|
+
distance: number;
|
|
13
|
+
isTransit: boolean;
|
|
14
|
+
};
|
|
15
|
+
export type AdjacencyPathType = {
|
|
16
|
+
node: AdjacencyNodeType;
|
|
17
|
+
distance: number;
|
|
18
|
+
path: ReadonlyArray<AdjacencyLinkType>;
|
|
19
|
+
};
|
|
17
20
|
export declare class Adjacency {
|
|
18
|
-
private readonly
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
private readonly _transitNodes;
|
|
22
|
-
/**
|
|
23
|
-
* Add a node tag. Node tags may name the node, a specific edge, or a
|
|
24
|
-
* possibly-many-neighbors "hub tag" such as a wormhole.
|
|
25
|
-
*
|
|
26
|
-
* @param node
|
|
27
|
-
* @param tags
|
|
28
|
-
* @returns
|
|
29
|
-
*/
|
|
30
|
-
addNodeTags(node: string, tags: Array<string>): this;
|
|
31
|
-
removeNodeTags(node: string, tags: Array<string>): this;
|
|
32
|
-
hasNodeTag(node: string, tag: string): boolean;
|
|
33
|
-
_hasTagNode(tag: string, node: string): boolean;
|
|
21
|
+
private readonly _srcNodeOutgoingLinks;
|
|
22
|
+
addLink(link: AdjacencyLinkType): this;
|
|
23
|
+
hasLink(link: AdjacencyLinkType): boolean;
|
|
34
24
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* @param tag1
|
|
38
|
-
* @param tag2
|
|
39
|
-
* @returns
|
|
40
|
-
*/
|
|
41
|
-
addLink(tag1: string, tag2: string): this;
|
|
42
|
-
removeLink(tag1: string, tag2: string): this;
|
|
43
|
-
hasLink(tag1: string, tag2: string): boolean;
|
|
44
|
-
/**
|
|
45
|
-
* Transit nodes can appear along a path but do not add to distance
|
|
46
|
-
* (e.g. hyperlanes).
|
|
25
|
+
* Remove all links starting OR ENDING from the given node.
|
|
47
26
|
*
|
|
48
27
|
* @param node
|
|
49
|
-
* @returns
|
|
50
28
|
*/
|
|
51
|
-
|
|
52
|
-
removeTransitNode(node: string): this;
|
|
53
|
-
hasTransitNode(node: string): boolean;
|
|
54
|
-
_getAdjacentNodeSet(node: string): Set<string>;
|
|
29
|
+
removeNode(node: AdjacencyNodeType): this;
|
|
55
30
|
/**
|
|
56
31
|
* Compute shortest paths to all nodes within maxDistance.
|
|
57
32
|
*
|
|
@@ -59,5 +34,5 @@ export declare class Adjacency {
|
|
|
59
34
|
* @param maxDistance
|
|
60
35
|
* @returns
|
|
61
36
|
*/
|
|
62
|
-
get(origin:
|
|
37
|
+
get(origin: AdjacencyNodeType, maxDistance: number): ReadonlyArray<AdjacencyPathType>;
|
|
63
38
|
}
|
|
@@ -1,159 +1,53 @@
|
|
|
1
1
|
import { Heap } from "../heap/heap";
|
|
2
|
-
/**
|
|
3
|
-
* Nodes have tags, links connect tags.
|
|
4
|
-
* Tansit nodes are on a path, but do not add to distance ("hyperlane").
|
|
5
|
-
* Transit nodes are not "reachable" and will not appear as destinations,
|
|
6
|
-
* but they can appear in paths to reach other nodes.
|
|
7
|
-
*
|
|
8
|
-
* If two nodes share a tag they are NOT connected UNLESS there is a link
|
|
9
|
-
* from tag back to itself.
|
|
10
|
-
*
|
|
11
|
-
* A link may connect to multiple nodes that share the tag.
|
|
12
|
-
*/
|
|
13
2
|
export class Adjacency {
|
|
14
3
|
constructor() {
|
|
15
|
-
this.
|
|
16
|
-
this._tagToNodeSet = {};
|
|
17
|
-
this._tagToLinkedTagSet = {};
|
|
18
|
-
this._transitNodes = new Set();
|
|
4
|
+
this._srcNodeOutgoingLinks = new Map();
|
|
19
5
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
* @returns
|
|
27
|
-
*/
|
|
28
|
-
addNodeTags(node, tags) {
|
|
29
|
-
let tagSet;
|
|
30
|
-
let nodeSet;
|
|
31
|
-
tagSet = this._nodeToTagSet[node];
|
|
32
|
-
if (!tagSet) {
|
|
33
|
-
tagSet = new Set();
|
|
34
|
-
this._nodeToTagSet[node] = tagSet;
|
|
35
|
-
}
|
|
36
|
-
for (const tag of tags) {
|
|
37
|
-
tagSet.add(tag);
|
|
38
|
-
nodeSet = this._tagToNodeSet[tag];
|
|
39
|
-
if (!nodeSet) {
|
|
40
|
-
nodeSet = new Set();
|
|
41
|
-
this._tagToNodeSet[tag] = nodeSet;
|
|
42
|
-
}
|
|
43
|
-
nodeSet.add(node);
|
|
6
|
+
addLink(link) {
|
|
7
|
+
// Create the src->link set if missing.
|
|
8
|
+
let outgoingLinks = this._srcNodeOutgoingLinks.get(link.src);
|
|
9
|
+
if (!outgoingLinks) {
|
|
10
|
+
outgoingLinks = new Set();
|
|
11
|
+
this._srcNodeOutgoingLinks.set(link.src, outgoingLinks);
|
|
44
12
|
}
|
|
13
|
+
// Add immutable link.
|
|
14
|
+
link = Object.freeze(link); // make immutable
|
|
15
|
+
outgoingLinks.add(link);
|
|
45
16
|
return this;
|
|
46
17
|
}
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
18
|
+
hasLink(link) {
|
|
19
|
+
const outgoingLinks = this._srcNodeOutgoingLinks.get(link.src);
|
|
20
|
+
if (outgoingLinks) {
|
|
21
|
+
for (const outgoingLink of outgoingLinks) {
|
|
22
|
+
if (outgoingLink.src === link.src &&
|
|
23
|
+
outgoingLink.dst === link.dst &&
|
|
24
|
+
outgoingLink.distance === link.distance &&
|
|
25
|
+
outgoingLink.isTransit === link.isTransit) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
56
28
|
}
|
|
57
29
|
}
|
|
58
|
-
return
|
|
59
|
-
}
|
|
60
|
-
hasNodeTag(node, tag) {
|
|
61
|
-
var _a;
|
|
62
|
-
const tagSet = this._nodeToTagSet[node];
|
|
63
|
-
return (_a = tagSet === null || tagSet === void 0 ? void 0 : tagSet.has(tag)) !== null && _a !== void 0 ? _a : false;
|
|
64
|
-
}
|
|
65
|
-
_hasTagNode(tag, node) {
|
|
66
|
-
var _a;
|
|
67
|
-
const nodeSet = this._tagToNodeSet[tag];
|
|
68
|
-
return (_a = nodeSet === null || nodeSet === void 0 ? void 0 : nodeSet.has(node)) !== null && _a !== void 0 ? _a : false;
|
|
30
|
+
return false;
|
|
69
31
|
}
|
|
70
32
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* @param tag1
|
|
74
|
-
* @param tag2
|
|
75
|
-
* @returns
|
|
76
|
-
*/
|
|
77
|
-
addLink(tag1, tag2) {
|
|
78
|
-
let linkedTagSet;
|
|
79
|
-
// 1 -> 1, 1 -> 2.
|
|
80
|
-
linkedTagSet = this._tagToLinkedTagSet[tag1];
|
|
81
|
-
if (!linkedTagSet) {
|
|
82
|
-
linkedTagSet = new Set();
|
|
83
|
-
this._tagToLinkedTagSet[tag1] = linkedTagSet;
|
|
84
|
-
}
|
|
85
|
-
linkedTagSet.add(tag1);
|
|
86
|
-
linkedTagSet.add(tag2);
|
|
87
|
-
// 2 -> 1, 2 -> 2.
|
|
88
|
-
linkedTagSet = this._tagToLinkedTagSet[tag2];
|
|
89
|
-
if (!linkedTagSet) {
|
|
90
|
-
linkedTagSet = new Set();
|
|
91
|
-
this._tagToLinkedTagSet[tag2] = linkedTagSet;
|
|
92
|
-
}
|
|
93
|
-
linkedTagSet.add(tag1);
|
|
94
|
-
linkedTagSet.add(tag2);
|
|
95
|
-
return this;
|
|
96
|
-
}
|
|
97
|
-
removeLink(tag1, tag2) {
|
|
98
|
-
let linkedTagSet;
|
|
99
|
-
// 1 -> 1, 1 -> 2.
|
|
100
|
-
linkedTagSet = this._tagToLinkedTagSet[tag1];
|
|
101
|
-
if (linkedTagSet) {
|
|
102
|
-
linkedTagSet.delete(tag1);
|
|
103
|
-
linkedTagSet.delete(tag2);
|
|
104
|
-
}
|
|
105
|
-
// 2 -> 1, 2 -> 2.
|
|
106
|
-
linkedTagSet = this._tagToLinkedTagSet[tag2];
|
|
107
|
-
if (linkedTagSet) {
|
|
108
|
-
linkedTagSet.delete(tag1);
|
|
109
|
-
linkedTagSet.delete(tag2);
|
|
110
|
-
}
|
|
111
|
-
return this;
|
|
112
|
-
}
|
|
113
|
-
hasLink(tag1, tag2) {
|
|
114
|
-
var _a;
|
|
115
|
-
const linkedTagSet = this._tagToLinkedTagSet[tag1];
|
|
116
|
-
return (_a = linkedTagSet === null || linkedTagSet === void 0 ? void 0 : linkedTagSet.has(tag2)) !== null && _a !== void 0 ? _a : false;
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Transit nodes can appear along a path but do not add to distance
|
|
120
|
-
* (e.g. hyperlanes).
|
|
33
|
+
* Remove all links starting OR ENDING from the given node.
|
|
121
34
|
*
|
|
122
35
|
* @param node
|
|
123
|
-
* @returns
|
|
124
36
|
*/
|
|
125
|
-
|
|
126
|
-
this.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
hasTransitNode(node) {
|
|
134
|
-
return this._transitNodes.has(node);
|
|
135
|
-
}
|
|
136
|
-
_getAdjacentNodeSet(node) {
|
|
137
|
-
const tagSet = this._nodeToTagSet[node];
|
|
138
|
-
const adjNodeSet = new Set();
|
|
139
|
-
if (tagSet) {
|
|
140
|
-
for (const tag of tagSet) {
|
|
141
|
-
const linkedTagSet = this._tagToLinkedTagSet[tag];
|
|
142
|
-
if (linkedTagSet) {
|
|
143
|
-
for (const linkedTag of linkedTagSet) {
|
|
144
|
-
const nodeSet = this._tagToNodeSet[linkedTag];
|
|
145
|
-
if (nodeSet) {
|
|
146
|
-
for (const linkedNode of nodeSet) {
|
|
147
|
-
if (linkedNode !== node) {
|
|
148
|
-
adjNodeSet.add(linkedNode);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
37
|
+
removeNode(node) {
|
|
38
|
+
this._srcNodeOutgoingLinks.delete(node);
|
|
39
|
+
for (const outgoingLinks of this._srcNodeOutgoingLinks.values()) {
|
|
40
|
+
const dele = new Set();
|
|
41
|
+
for (const link of outgoingLinks) {
|
|
42
|
+
if (link.dst === node) {
|
|
43
|
+
dele.add(link);
|
|
153
44
|
}
|
|
154
45
|
}
|
|
46
|
+
for (const link of dele) {
|
|
47
|
+
outgoingLinks.delete(link);
|
|
48
|
+
}
|
|
155
49
|
}
|
|
156
|
-
return
|
|
50
|
+
return this;
|
|
157
51
|
}
|
|
158
52
|
/**
|
|
159
53
|
* Compute shortest paths to all nodes within maxDistance.
|
|
@@ -163,52 +57,65 @@ export class Adjacency {
|
|
|
163
57
|
* @returns
|
|
164
58
|
*/
|
|
165
59
|
get(origin, maxDistance) {
|
|
166
|
-
const
|
|
60
|
+
const nodeToAdjacencyPath = new Map();
|
|
61
|
+
const toExplore = new Set();
|
|
62
|
+
const explored = new Set();
|
|
63
|
+
// Start with the origin.
|
|
64
|
+
toExplore.add(origin); // start from the origin
|
|
65
|
+
const heap = new Heap().add(origin, 0);
|
|
66
|
+
nodeToAdjacencyPath.set(origin, {
|
|
167
67
|
node: origin,
|
|
168
68
|
distance: 0,
|
|
169
|
-
path: [
|
|
170
|
-
};
|
|
171
|
-
const nodeToAdjacencyResult = {
|
|
172
|
-
[origin]: originAdjacencyResult,
|
|
173
|
-
};
|
|
174
|
-
const toVisit = new Set([
|
|
175
|
-
originAdjacencyResult,
|
|
176
|
-
]);
|
|
177
|
-
const visited = new Set();
|
|
178
|
-
const heap = new Heap().add(origin, 0);
|
|
69
|
+
path: [],
|
|
70
|
+
});
|
|
179
71
|
let closestNode;
|
|
180
|
-
while (
|
|
72
|
+
while (toExplore.size > 0 && (closestNode = heap.removeMin())) {
|
|
181
73
|
// Find the closest of the to-visit nodes.
|
|
182
|
-
const closest =
|
|
74
|
+
const closest = nodeToAdjacencyPath.get(closestNode);
|
|
183
75
|
if (closest) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
76
|
+
// Mark as explored.
|
|
77
|
+
toExplore.delete(closest.node);
|
|
78
|
+
explored.add(closest.node);
|
|
79
|
+
// Walk the outgoing link destinations.
|
|
80
|
+
const outgoingLinks = this._srcNodeOutgoingLinks.get(closest.node);
|
|
81
|
+
if (outgoingLinks) {
|
|
82
|
+
for (const outgoingLink of outgoingLinks) {
|
|
83
|
+
const dst = outgoingLink.dst;
|
|
84
|
+
if (!explored.has(dst)) {
|
|
85
|
+
const distance = closest.distance + outgoingLink.distance;
|
|
86
|
+
const path = [
|
|
87
|
+
...closest.path,
|
|
88
|
+
outgoingLink,
|
|
89
|
+
];
|
|
90
|
+
if (distance <= maxDistance) {
|
|
91
|
+
// This dst is new and within range, add it to to-explore list.
|
|
92
|
+
toExplore.add(dst);
|
|
93
|
+
heap.add(dst, distance);
|
|
94
|
+
// Also add to the adjacency paths, even if ends with a transit.
|
|
95
|
+
nodeToAdjacencyPath.set(dst, {
|
|
96
|
+
node: dst,
|
|
97
|
+
distance,
|
|
98
|
+
path,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
202
101
|
}
|
|
203
102
|
}
|
|
204
103
|
}
|
|
205
104
|
}
|
|
206
105
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
106
|
+
// Get paths not ending with a transit node and make immutable.
|
|
107
|
+
const result = [
|
|
108
|
+
...nodeToAdjacencyPath.values(),
|
|
109
|
+
]
|
|
110
|
+
.filter((adjacencyPathType) => {
|
|
111
|
+
const lastLink = adjacencyPathType.path[adjacencyPathType.path.length - 1];
|
|
112
|
+
return lastLink !== undefined && !lastLink.isTransit;
|
|
113
|
+
})
|
|
114
|
+
.map((adjacencyPathType) => {
|
|
115
|
+
return Object.freeze(adjacencyPathType);
|
|
116
|
+
});
|
|
210
117
|
// Sort by distance.
|
|
211
|
-
result
|
|
118
|
+
result.sort((a, b) => {
|
|
212
119
|
if (a.distance < b.distance) {
|
|
213
120
|
return -1;
|
|
214
121
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adjacency.js","sourceRoot":"","sources":["../../../../src/lib/adjacency/adjacency.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"adjacency.js","sourceRoot":"","sources":["../../../../src/lib/adjacency/adjacency.ts"],"names":[],"mappings":"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"}
|