graphwise 1.1.0 → 1.2.0
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/dist/expansion/frontier-balanced.d.ts +12 -0
- package/dist/expansion/frontier-balanced.d.ts.map +1 -0
- package/dist/expansion/frontier-balanced.unit.test.d.ts +2 -0
- package/dist/expansion/frontier-balanced.unit.test.d.ts.map +1 -0
- package/dist/expansion/index.d.ts +12 -13
- package/dist/expansion/index.d.ts.map +1 -1
- package/dist/expansion/random-priority.d.ts +20 -0
- package/dist/expansion/random-priority.d.ts.map +1 -0
- package/dist/expansion/random-priority.unit.test.d.ts +2 -0
- package/dist/expansion/random-priority.unit.test.d.ts.map +1 -0
- package/dist/expansion/standard-bfs.d.ts +12 -0
- package/dist/expansion/standard-bfs.d.ts.map +1 -0
- package/dist/expansion/standard-bfs.unit.test.d.ts +2 -0
- package/dist/expansion/standard-bfs.unit.test.d.ts.map +1 -0
- package/dist/extraction/index.d.ts +6 -6
- package/dist/extraction/index.d.ts.map +1 -1
- package/dist/extraction/motif.d.ts.map +1 -1
- package/dist/gpu/context.d.ts.map +1 -1
- package/dist/gpu/csr.d.ts.map +1 -1
- package/dist/gpu/index.cjs +410 -5
- package/dist/gpu/index.cjs.map +1 -0
- package/dist/gpu/index.d.ts +4 -5
- package/dist/gpu/index.d.ts.map +1 -1
- package/dist/gpu/index.js +400 -2
- package/dist/gpu/index.js.map +1 -0
- package/dist/graph/index.cjs +222 -2
- package/dist/graph/index.cjs.map +1 -0
- package/dist/graph/index.d.ts +3 -3
- package/dist/graph/index.d.ts.map +1 -1
- package/dist/graph/index.js +221 -1
- package/dist/graph/index.js.map +1 -0
- package/dist/index/index.cjs +902 -10
- package/dist/index/index.cjs.map +1 -1
- package/dist/index/index.js +880 -10
- package/dist/index/index.js.map +1 -1
- package/dist/{kmeans-B0HEOU6k.cjs → kmeans-87ExSUNZ.js} +27 -13
- package/dist/{kmeans-DgbsOznU.js.map → kmeans-87ExSUNZ.js.map} +1 -1
- package/dist/{kmeans-DgbsOznU.js → kmeans-BIgSyGKu.cjs} +44 -2
- package/dist/{kmeans-B0HEOU6k.cjs.map → kmeans-BIgSyGKu.cjs.map} +1 -1
- package/dist/ranking/baselines/betweenness.d.ts +13 -0
- package/dist/ranking/baselines/betweenness.d.ts.map +1 -0
- package/dist/ranking/baselines/betweenness.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/betweenness.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/communicability.d.ts +13 -0
- package/dist/ranking/baselines/communicability.d.ts.map +1 -0
- package/dist/ranking/baselines/communicability.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/communicability.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/degree-sum.d.ts +13 -0
- package/dist/ranking/baselines/degree-sum.d.ts.map +1 -0
- package/dist/ranking/baselines/degree-sum.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/degree-sum.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/index.d.ts +20 -0
- package/dist/ranking/baselines/index.d.ts.map +1 -0
- package/dist/ranking/baselines/jaccard-arithmetic.d.ts +13 -0
- package/dist/ranking/baselines/jaccard-arithmetic.d.ts.map +1 -0
- package/dist/ranking/baselines/jaccard-arithmetic.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/jaccard-arithmetic.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/katz.d.ts +13 -0
- package/dist/ranking/baselines/katz.d.ts.map +1 -0
- package/dist/ranking/baselines/katz.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/katz.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/pagerank.d.ts +13 -0
- package/dist/ranking/baselines/pagerank.d.ts.map +1 -0
- package/dist/ranking/baselines/pagerank.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/pagerank.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/random-ranking.d.ts +21 -0
- package/dist/ranking/baselines/random-ranking.d.ts.map +1 -0
- package/dist/ranking/baselines/random-ranking.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/random-ranking.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/resistance-distance.d.ts +13 -0
- package/dist/ranking/baselines/resistance-distance.d.ts.map +1 -0
- package/dist/ranking/baselines/resistance-distance.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/resistance-distance.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/widest-path.d.ts +13 -0
- package/dist/ranking/baselines/widest-path.d.ts.map +1 -0
- package/dist/ranking/baselines/widest-path.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/widest-path.unit.test.d.ts.map +1 -0
- package/dist/ranking/index.d.ts +3 -6
- package/dist/ranking/index.d.ts.map +1 -1
- package/dist/ranking/mi/index.d.ts +9 -9
- package/dist/ranking/mi/index.d.ts.map +1 -1
- package/dist/schemas/index.d.ts +2 -2
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/seeds/index.cjs +398 -3
- package/dist/seeds/index.cjs.map +1 -0
- package/dist/seeds/index.d.ts +2 -4
- package/dist/seeds/index.d.ts.map +1 -1
- package/dist/seeds/index.js +396 -1
- package/dist/seeds/index.js.map +1 -0
- package/dist/seeds/stratified.d.ts.map +1 -1
- package/dist/structures/index.cjs +133 -2
- package/dist/structures/index.cjs.map +1 -0
- package/dist/structures/index.d.ts +1 -2
- package/dist/structures/index.d.ts.map +1 -1
- package/dist/structures/index.js +132 -1
- package/dist/structures/index.js.map +1 -0
- package/dist/traversal/index.cjs +152 -5
- package/dist/traversal/index.cjs.map +1 -0
- package/dist/traversal/index.d.ts +2 -2
- package/dist/traversal/index.d.ts.map +1 -1
- package/dist/traversal/index.js +148 -1
- package/dist/traversal/index.js.map +1 -0
- package/dist/utils/index.cjs +172 -9
- package/dist/utils/index.cjs.map +1 -0
- package/dist/utils/index.d.ts +3 -3
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +165 -3
- package/dist/utils/index.js.map +1 -0
- package/package.json +1 -1
- package/dist/gpu-BJRVYBjx.cjs +0 -338
- package/dist/gpu-BJRVYBjx.cjs.map +0 -1
- package/dist/gpu-BveuXugy.js +0 -315
- package/dist/gpu-BveuXugy.js.map +0 -1
- package/dist/graph-DLWiziLB.js +0 -222
- package/dist/graph-DLWiziLB.js.map +0 -1
- package/dist/graph-az06J1YV.cjs +0 -227
- package/dist/graph-az06J1YV.cjs.map +0 -1
- package/dist/seeds-B6J9oJfU.cjs +0 -404
- package/dist/seeds-B6J9oJfU.cjs.map +0 -1
- package/dist/seeds-UNZxqm_U.js +0 -393
- package/dist/seeds-UNZxqm_U.js.map +0 -1
- package/dist/structures-BPfhfqNP.js +0 -133
- package/dist/structures-BPfhfqNP.js.map +0 -1
- package/dist/structures-CJ_S_7fs.cjs +0 -138
- package/dist/structures-CJ_S_7fs.cjs.map +0 -1
- package/dist/traversal-CQCjUwUJ.js +0 -149
- package/dist/traversal-CQCjUwUJ.js.map +0 -1
- package/dist/traversal-QeHaNUWn.cjs +0 -172
- package/dist/traversal-QeHaNUWn.cjs.map +0 -1
- package/dist/utils-Q_akvlMn.js +0 -164
- package/dist/utils-Q_akvlMn.js.map +0 -1
- package/dist/utils-spZa1ZvS.cjs +0 -205
- package/dist/utils-spZa1ZvS.cjs.map +0 -1
package/dist/structures/index.js
CHANGED
|
@@ -1,2 +1,133 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/structures/priority-queue.ts
|
|
2
|
+
/**
|
|
3
|
+
* Min-heap priority queue implementation using an array-based binary heap.
|
|
4
|
+
* Lower priority values have higher precedence (extracted first).
|
|
5
|
+
*/
|
|
6
|
+
var PriorityQueue = class {
|
|
7
|
+
heap = [];
|
|
8
|
+
/**
|
|
9
|
+
* Returns the number of items in the queue.
|
|
10
|
+
*/
|
|
11
|
+
size() {
|
|
12
|
+
return this.heap.length;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Returns true if the queue is empty.
|
|
16
|
+
*/
|
|
17
|
+
isEmpty() {
|
|
18
|
+
return this.heap.length === 0;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Adds an item with the given priority to the queue.
|
|
22
|
+
*/
|
|
23
|
+
push(item, priority) {
|
|
24
|
+
const entry = {
|
|
25
|
+
item,
|
|
26
|
+
priority
|
|
27
|
+
};
|
|
28
|
+
this.heap.push(entry);
|
|
29
|
+
this.heapifyUp(this.heap.length - 1);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Removes and returns the highest precedence item (lowest priority value).
|
|
33
|
+
* Returns undefined if the queue is empty.
|
|
34
|
+
*/
|
|
35
|
+
pop() {
|
|
36
|
+
if (this.heap.length === 0) return;
|
|
37
|
+
const root = this.heap[0];
|
|
38
|
+
if (root === void 0) return;
|
|
39
|
+
const last = this.heap.pop();
|
|
40
|
+
if (last === void 0) return root;
|
|
41
|
+
if (this.heap.length > 0) {
|
|
42
|
+
this.heap[0] = last;
|
|
43
|
+
this.heapifyDown(0);
|
|
44
|
+
}
|
|
45
|
+
return root;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Returns the highest precedence item without removing it.
|
|
49
|
+
* Returns undefined if the queue is empty.
|
|
50
|
+
*/
|
|
51
|
+
peek() {
|
|
52
|
+
return this.heap[0];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Rebuilds the heap from the current array state.
|
|
56
|
+
* Useful when priorities have been modified externally (e.g., phase transitions).
|
|
57
|
+
*/
|
|
58
|
+
rebuild() {
|
|
59
|
+
const start = Math.floor(this.heap.length / 2) - 1;
|
|
60
|
+
for (let i = start; i >= 0; i--) this.heapifyDown(i);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Decreases the priority of an existing item in the queue.
|
|
64
|
+
* Returns true if the item was found and updated, false otherwise.
|
|
65
|
+
*
|
|
66
|
+
* @param item - The item to find
|
|
67
|
+
* @param newPriority - The new (lower) priority value
|
|
68
|
+
* @param equals - Function to compare items for equality
|
|
69
|
+
*/
|
|
70
|
+
decreaseKey(item, newPriority, equals) {
|
|
71
|
+
let foundIndex = -1;
|
|
72
|
+
for (let i = 0; i < this.heap.length; i++) {
|
|
73
|
+
const entry = this.heap[i];
|
|
74
|
+
if (entry !== void 0 && equals(entry.item, item)) {
|
|
75
|
+
foundIndex = i;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (foundIndex === -1) return false;
|
|
80
|
+
const entry = this.heap[foundIndex];
|
|
81
|
+
if (entry === void 0) return false;
|
|
82
|
+
if (newPriority >= entry.priority) return false;
|
|
83
|
+
entry.priority = newPriority;
|
|
84
|
+
this.heapifyUp(foundIndex);
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Restores heap property by moving element up from given index.
|
|
89
|
+
*/
|
|
90
|
+
heapifyUp(index) {
|
|
91
|
+
let current = index;
|
|
92
|
+
while (current > 0) {
|
|
93
|
+
const parent = Math.floor((current - 1) / 2);
|
|
94
|
+
const currentEntry = this.heap[current];
|
|
95
|
+
const parentEntry = this.heap[parent];
|
|
96
|
+
if (currentEntry === void 0 || parentEntry === void 0) return;
|
|
97
|
+
if (currentEntry.priority >= parentEntry.priority) return;
|
|
98
|
+
this.heap[current] = parentEntry;
|
|
99
|
+
this.heap[parent] = currentEntry;
|
|
100
|
+
current = parent;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Restores heap property by moving element down from given index.
|
|
105
|
+
*/
|
|
106
|
+
heapifyDown(index) {
|
|
107
|
+
let current = index;
|
|
108
|
+
const length = this.heap.length;
|
|
109
|
+
while (current < length) {
|
|
110
|
+
const left = 2 * current + 1;
|
|
111
|
+
const right = 2 * current + 2;
|
|
112
|
+
let smallest = current;
|
|
113
|
+
const currentEntry = this.heap[current];
|
|
114
|
+
if (currentEntry === void 0) return;
|
|
115
|
+
const leftEntry = this.heap[left];
|
|
116
|
+
if (left < length && leftEntry !== void 0 && leftEntry.priority < currentEntry.priority) smallest = left;
|
|
117
|
+
const rightEntry = this.heap[right];
|
|
118
|
+
const currentSmallestEntry = this.heap[smallest];
|
|
119
|
+
if (right < length && rightEntry !== void 0 && currentSmallestEntry !== void 0 && rightEntry.priority < currentSmallestEntry.priority) smallest = right;
|
|
120
|
+
if (smallest === current) return;
|
|
121
|
+
const finalSmallestEntry = this.heap[smallest];
|
|
122
|
+
if (finalSmallestEntry !== void 0) {
|
|
123
|
+
this.heap[current] = finalSmallestEntry;
|
|
124
|
+
this.heap[smallest] = currentEntry;
|
|
125
|
+
current = smallest;
|
|
126
|
+
} else return;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
//#endregion
|
|
2
131
|
export { PriorityQueue };
|
|
132
|
+
|
|
133
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/structures/priority-queue.ts"],"sourcesContent":["/**\n * Priority queue entry containing an item and its priority.\n */\nexport interface PriorityEntry<T> {\n\titem: T;\n\tpriority: number;\n}\n\n/**\n * Min-heap priority queue implementation using an array-based binary heap.\n * Lower priority values have higher precedence (extracted first).\n */\nexport class PriorityQueue<T> {\n\tprivate heap: PriorityEntry<T>[] = [];\n\n\t/**\n\t * Returns the number of items in the queue.\n\t */\n\tpublic size(): number {\n\t\treturn this.heap.length;\n\t}\n\n\t/**\n\t * Returns true if the queue is empty.\n\t */\n\tpublic isEmpty(): boolean {\n\t\treturn this.heap.length === 0;\n\t}\n\n\t/**\n\t * Adds an item with the given priority to the queue.\n\t */\n\tpublic push(item: T, priority: number): void {\n\t\tconst entry: PriorityEntry<T> = { item, priority };\n\t\tthis.heap.push(entry);\n\t\tthis.heapifyUp(this.heap.length - 1);\n\t}\n\n\t/**\n\t * Removes and returns the highest precedence item (lowest priority value).\n\t * Returns undefined if the queue is empty.\n\t */\n\tpublic pop(): PriorityEntry<T> | undefined {\n\t\tif (this.heap.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst root = this.heap[0];\n\t\tif (root === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst last = this.heap.pop();\n\t\tif (last === undefined) {\n\t\t\treturn root;\n\t\t}\n\n\t\tif (this.heap.length > 0) {\n\t\t\tthis.heap[0] = last;\n\t\t\tthis.heapifyDown(0);\n\t\t}\n\n\t\treturn root;\n\t}\n\n\t/**\n\t * Returns the highest precedence item without removing it.\n\t * Returns undefined if the queue is empty.\n\t */\n\tpublic peek(): PriorityEntry<T> | undefined {\n\t\treturn this.heap[0];\n\t}\n\n\t/**\n\t * Rebuilds the heap from the current array state.\n\t * Useful when priorities have been modified externally (e.g., phase transitions).\n\t */\n\tpublic rebuild(): void {\n\t\t// Floyd's algorithm: heapify down from last non-leaf to root\n\t\tconst start = Math.floor(this.heap.length / 2) - 1;\n\t\tfor (let i = start; i >= 0; i--) {\n\t\t\tthis.heapifyDown(i);\n\t\t}\n\t}\n\n\t/**\n\t * Decreases the priority of an existing item in the queue.\n\t * Returns true if the item was found and updated, false otherwise.\n\t *\n\t * @param item - The item to find\n\t * @param newPriority - The new (lower) priority value\n\t * @param equals - Function to compare items for equality\n\t */\n\tpublic decreaseKey(\n\t\titem: T,\n\t\tnewPriority: number,\n\t\tequals: (a: T, b: T) => boolean,\n\t): boolean {\n\t\tlet foundIndex = -1;\n\n\t\tfor (let i = 0; i < this.heap.length; i++) {\n\t\t\tconst entry = this.heap[i];\n\t\t\tif (entry !== undefined && equals(entry.item, item)) {\n\t\t\t\tfoundIndex = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (foundIndex === -1) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst entry = this.heap[foundIndex];\n\t\tif (entry === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Only update if new priority is lower (higher precedence)\n\t\tif (newPriority >= entry.priority) {\n\t\t\treturn false;\n\t\t}\n\n\t\tentry.priority = newPriority;\n\t\tthis.heapifyUp(foundIndex);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Restores heap property by moving element up from given index.\n\t */\n\tprivate heapifyUp(index: number): void {\n\t\tlet current = index;\n\n\t\twhile (current > 0) {\n\t\t\tconst parent = Math.floor((current - 1) / 2);\n\t\t\tconst currentEntry = this.heap[current];\n\t\t\tconst parentEntry = this.heap[parent];\n\n\t\t\tif (currentEntry === undefined || parentEntry === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (currentEntry.priority >= parentEntry.priority) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Swap current and parent\n\t\t\tthis.heap[current] = parentEntry;\n\t\t\tthis.heap[parent] = currentEntry;\n\t\t\tcurrent = parent;\n\t\t}\n\t}\n\n\t/**\n\t * Restores heap property by moving element down from given index.\n\t */\n\tprivate heapifyDown(index: number): void {\n\t\tlet current = index;\n\t\tconst length = this.heap.length;\n\n\t\twhile (current < length) {\n\t\t\tconst left = 2 * current + 1;\n\t\t\tconst right = 2 * current + 2;\n\t\t\tlet smallest = current;\n\n\t\t\tconst currentEntry = this.heap[current];\n\t\t\tif (currentEntry === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Compare with left child\n\t\t\tconst leftEntry = this.heap[left];\n\t\t\tif (\n\t\t\t\tleft < length &&\n\t\t\t\tleftEntry !== undefined &&\n\t\t\t\tleftEntry.priority < currentEntry.priority\n\t\t\t) {\n\t\t\t\tsmallest = left;\n\t\t\t}\n\n\t\t\t// Compare with right child (need to re-fetch smallest after potential update)\n\t\t\tconst rightEntry = this.heap[right];\n\t\t\tconst currentSmallestEntry = this.heap[smallest];\n\t\t\tif (\n\t\t\t\tright < length &&\n\t\t\t\trightEntry !== undefined &&\n\t\t\t\tcurrentSmallestEntry !== undefined &&\n\t\t\t\trightEntry.priority < currentSmallestEntry.priority\n\t\t\t) {\n\t\t\t\tsmallest = right;\n\t\t\t}\n\n\t\t\tif (smallest === current) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Get the final smallest entry (after determining final smallest index)\n\t\t\tconst finalSmallestEntry = this.heap[smallest];\n\t\t\tif (finalSmallestEntry !== undefined) {\n\t\t\t\tthis.heap[current] = finalSmallestEntry;\n\t\t\t\tthis.heap[smallest] = currentEntry;\n\t\t\t\tcurrent = smallest;\n\t\t\t} else {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n"],"mappings":";;;;;AAYA,IAAa,gBAAb,MAA8B;CAC7B,OAAmC,EAAE;;;;CAKrC,OAAsB;AACrB,SAAO,KAAK,KAAK;;;;;CAMlB,UAA0B;AACzB,SAAO,KAAK,KAAK,WAAW;;;;;CAM7B,KAAY,MAAS,UAAwB;EAC5C,MAAM,QAA0B;GAAE;GAAM;GAAU;AAClD,OAAK,KAAK,KAAK,MAAM;AACrB,OAAK,UAAU,KAAK,KAAK,SAAS,EAAE;;;;;;CAOrC,MAA2C;AAC1C,MAAI,KAAK,KAAK,WAAW,EACxB;EAGD,MAAM,OAAO,KAAK,KAAK;AACvB,MAAI,SAAS,KAAA,EACZ;EAGD,MAAM,OAAO,KAAK,KAAK,KAAK;AAC5B,MAAI,SAAS,KAAA,EACZ,QAAO;AAGR,MAAI,KAAK,KAAK,SAAS,GAAG;AACzB,QAAK,KAAK,KAAK;AACf,QAAK,YAAY,EAAE;;AAGpB,SAAO;;;;;;CAOR,OAA4C;AAC3C,SAAO,KAAK,KAAK;;;;;;CAOlB,UAAuB;EAEtB,MAAM,QAAQ,KAAK,MAAM,KAAK,KAAK,SAAS,EAAE,GAAG;AACjD,OAAK,IAAI,IAAI,OAAO,KAAK,GAAG,IAC3B,MAAK,YAAY,EAAE;;;;;;;;;;CAYrB,YACC,MACA,aACA,QACU;EACV,IAAI,aAAa;AAEjB,OAAK,IAAI,IAAI,GAAG,IAAI,KAAK,KAAK,QAAQ,KAAK;GAC1C,MAAM,QAAQ,KAAK,KAAK;AACxB,OAAI,UAAU,KAAA,KAAa,OAAO,MAAM,MAAM,KAAK,EAAE;AACpD,iBAAa;AACb;;;AAIF,MAAI,eAAe,GAClB,QAAO;EAGR,MAAM,QAAQ,KAAK,KAAK;AACxB,MAAI,UAAU,KAAA,EACb,QAAO;AAIR,MAAI,eAAe,MAAM,SACxB,QAAO;AAGR,QAAM,WAAW;AACjB,OAAK,UAAU,WAAW;AAC1B,SAAO;;;;;CAMR,UAAkB,OAAqB;EACtC,IAAI,UAAU;AAEd,SAAO,UAAU,GAAG;GACnB,MAAM,SAAS,KAAK,OAAO,UAAU,KAAK,EAAE;GAC5C,MAAM,eAAe,KAAK,KAAK;GAC/B,MAAM,cAAc,KAAK,KAAK;AAE9B,OAAI,iBAAiB,KAAA,KAAa,gBAAgB,KAAA,EACjD;AAGD,OAAI,aAAa,YAAY,YAAY,SACxC;AAID,QAAK,KAAK,WAAW;AACrB,QAAK,KAAK,UAAU;AACpB,aAAU;;;;;;CAOZ,YAAoB,OAAqB;EACxC,IAAI,UAAU;EACd,MAAM,SAAS,KAAK,KAAK;AAEzB,SAAO,UAAU,QAAQ;GACxB,MAAM,OAAO,IAAI,UAAU;GAC3B,MAAM,QAAQ,IAAI,UAAU;GAC5B,IAAI,WAAW;GAEf,MAAM,eAAe,KAAK,KAAK;AAC/B,OAAI,iBAAiB,KAAA,EACpB;GAID,MAAM,YAAY,KAAK,KAAK;AAC5B,OACC,OAAO,UACP,cAAc,KAAA,KACd,UAAU,WAAW,aAAa,SAElC,YAAW;GAIZ,MAAM,aAAa,KAAK,KAAK;GAC7B,MAAM,uBAAuB,KAAK,KAAK;AACvC,OACC,QAAQ,UACR,eAAe,KAAA,KACf,yBAAyB,KAAA,KACzB,WAAW,WAAW,qBAAqB,SAE3C,YAAW;AAGZ,OAAI,aAAa,QAChB;GAID,MAAM,qBAAqB,KAAK,KAAK;AACrC,OAAI,uBAAuB,KAAA,GAAW;AACrC,SAAK,KAAK,WAAW;AACrB,SAAK,KAAK,YAAY;AACtB,cAAU;SAEV"}
|
package/dist/traversal/index.cjs
CHANGED
|
@@ -1,6 +1,153 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
//#region src/traversal/bfs.ts
|
|
3
|
+
/**
|
|
4
|
+
* Perform a breadth-first search traversal from a start node.
|
|
5
|
+
*
|
|
6
|
+
* This generator yields node IDs in BFS order. It uses lazy evaluation
|
|
7
|
+
* via a generator, making it memory-efficient for large graphs.
|
|
8
|
+
*
|
|
9
|
+
* @param graph - The graph to traverse
|
|
10
|
+
* @param start - The starting node ID
|
|
11
|
+
* @yields Node IDs in BFS order
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* for (const nodeId of bfs(graph, "A")) {
|
|
16
|
+
* console.log(nodeId);
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
function* bfs(graph, start) {
|
|
21
|
+
if (!graph.hasNode(start)) return;
|
|
22
|
+
const visited = new Set([start]);
|
|
23
|
+
const queue = [start];
|
|
24
|
+
while (queue.length > 0) {
|
|
25
|
+
const current = queue.shift();
|
|
26
|
+
if (current === void 0) break;
|
|
27
|
+
yield current;
|
|
28
|
+
for (const neighbour of graph.neighbours(current)) if (!visited.has(neighbour)) {
|
|
29
|
+
visited.add(neighbour);
|
|
30
|
+
queue.push(neighbour);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Perform a breadth-first search traversal with path information.
|
|
36
|
+
*
|
|
37
|
+
* This generator yields detailed information about each visited node,
|
|
38
|
+
* including its depth from the start and parent in the BFS tree.
|
|
39
|
+
* Useful for reconstructing shortest paths.
|
|
40
|
+
*
|
|
41
|
+
* @param graph - The graph to traverse
|
|
42
|
+
* @param start - The starting node ID
|
|
43
|
+
* @yields Objects containing node ID, depth, and parent
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* for (const entry of bfsWithPath(graph, "A")) {
|
|
48
|
+
* console.log(`${entry.node} at depth ${entry.depth}`);
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
function* bfsWithPath(graph, start) {
|
|
53
|
+
if (!graph.hasNode(start)) return;
|
|
54
|
+
const visited = new Set([start]);
|
|
55
|
+
const queue = [{
|
|
56
|
+
node: start,
|
|
57
|
+
depth: 0,
|
|
58
|
+
parent: void 0
|
|
59
|
+
}];
|
|
60
|
+
while (queue.length > 0) {
|
|
61
|
+
const current = queue.shift();
|
|
62
|
+
if (current === void 0) break;
|
|
63
|
+
yield current;
|
|
64
|
+
for (const neighbour of graph.neighbours(current.node)) if (!visited.has(neighbour)) {
|
|
65
|
+
visited.add(neighbour);
|
|
66
|
+
queue.push({
|
|
67
|
+
node: neighbour,
|
|
68
|
+
depth: current.depth + 1,
|
|
69
|
+
parent: current.node
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/traversal/dfs.ts
|
|
76
|
+
/**
|
|
77
|
+
* Perform a depth-first search traversal from a start node.
|
|
78
|
+
*
|
|
79
|
+
* This generator yields node IDs in DFS order (pre-order traversal).
|
|
80
|
+
* It uses lazy evaluation via a generator, making it memory-efficient
|
|
81
|
+
* for large graphs.
|
|
82
|
+
*
|
|
83
|
+
* @param graph - The graph to traverse
|
|
84
|
+
* @param start - The starting node ID
|
|
85
|
+
* @yields Node IDs in DFS order
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* for (const nodeId of dfs(graph, "A")) {
|
|
90
|
+
* console.log(nodeId);
|
|
91
|
+
* }
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
function* dfs(graph, start) {
|
|
95
|
+
if (!graph.hasNode(start)) return;
|
|
96
|
+
const visited = /* @__PURE__ */ new Set();
|
|
97
|
+
const stack = [start];
|
|
98
|
+
while (stack.length > 0) {
|
|
99
|
+
const current = stack.pop();
|
|
100
|
+
if (current === void 0) break;
|
|
101
|
+
if (visited.has(current)) continue;
|
|
102
|
+
visited.add(current);
|
|
103
|
+
yield current;
|
|
104
|
+
const neighbours = [...graph.neighbours(current)].reverse();
|
|
105
|
+
for (const neighbour of neighbours) if (!visited.has(neighbour)) stack.push(neighbour);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Perform a depth-first search traversal with path information.
|
|
110
|
+
*
|
|
111
|
+
* This generator yields detailed information about each visited node,
|
|
112
|
+
* including its depth from the start and parent in the DFS tree.
|
|
113
|
+
*
|
|
114
|
+
* @param graph - The graph to traverse
|
|
115
|
+
* @param start - The starting node ID
|
|
116
|
+
* @yields Objects containing node ID, depth, and parent
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* for (const entry of dfsWithPath(graph, "A")) {
|
|
121
|
+
* console.log(`${entry.node} at depth ${entry.depth}`);
|
|
122
|
+
* }
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
function* dfsWithPath(graph, start) {
|
|
126
|
+
if (!graph.hasNode(start)) return;
|
|
127
|
+
const visited = /* @__PURE__ */ new Set();
|
|
128
|
+
const stack = [{
|
|
129
|
+
node: start,
|
|
130
|
+
depth: 0,
|
|
131
|
+
parent: void 0
|
|
132
|
+
}];
|
|
133
|
+
while (stack.length > 0) {
|
|
134
|
+
const current = stack.pop();
|
|
135
|
+
if (current === void 0) break;
|
|
136
|
+
if (visited.has(current.node)) continue;
|
|
137
|
+
visited.add(current.node);
|
|
138
|
+
yield current;
|
|
139
|
+
const neighbours = [...graph.neighbours(current.node)].reverse();
|
|
140
|
+
for (const neighbour of neighbours) if (!visited.has(neighbour)) stack.push({
|
|
141
|
+
node: neighbour,
|
|
142
|
+
depth: current.depth + 1,
|
|
143
|
+
parent: current.node
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
148
|
+
exports.bfs = bfs;
|
|
149
|
+
exports.bfsWithPath = bfsWithPath;
|
|
150
|
+
exports.dfs = dfs;
|
|
151
|
+
exports.dfsWithPath = dfsWithPath;
|
|
152
|
+
|
|
153
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../../src/traversal/bfs.ts","../../src/traversal/dfs.ts"],"sourcesContent":["/**\n * Breadth-first search traversal algorithms.\n *\n * BFS explores nodes level by level, visiting all neighbours at the current\n * depth before moving to nodes at the next depth level. This guarantees\n * shortest path discovery in unweighted graphs.\n */\n\nimport type { ReadableGraph, NodeId } from \"../graph\";\n\n/**\n * Node visit information during BFS traversal.\n */\nexport interface BfsPathEntry {\n\t/** The visited node identifier */\n\tnode: NodeId;\n\t/** Distance from the start node (0 for start node) */\n\tdepth: number;\n\t/** Parent node in the BFS tree (undefined for start node) */\n\tparent: NodeId | undefined;\n}\n\n/**\n * Perform a breadth-first search traversal from a start node.\n *\n * This generator yields node IDs in BFS order. It uses lazy evaluation\n * via a generator, making it memory-efficient for large graphs.\n *\n * @param graph - The graph to traverse\n * @param start - The starting node ID\n * @yields Node IDs in BFS order\n *\n * @example\n * ```typescript\n * for (const nodeId of bfs(graph, \"A\")) {\n * console.log(nodeId);\n * }\n * ```\n */\nexport function* bfs(graph: ReadableGraph, start: NodeId): Iterable<NodeId> {\n\tif (!graph.hasNode(start)) {\n\t\treturn;\n\t}\n\n\tconst visited = new Set<NodeId>([start]);\n\tconst queue: NodeId[] = [start];\n\n\twhile (queue.length > 0) {\n\t\tconst current = queue.shift();\n\t\tif (current === undefined) break;\n\t\tyield current;\n\n\t\tfor (const neighbour of graph.neighbours(current)) {\n\t\t\tif (!visited.has(neighbour)) {\n\t\t\t\tvisited.add(neighbour);\n\t\t\t\tqueue.push(neighbour);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Perform a breadth-first search traversal with path information.\n *\n * This generator yields detailed information about each visited node,\n * including its depth from the start and parent in the BFS tree.\n * Useful for reconstructing shortest paths.\n *\n * @param graph - The graph to traverse\n * @param start - The starting node ID\n * @yields Objects containing node ID, depth, and parent\n *\n * @example\n * ```typescript\n * for (const entry of bfsWithPath(graph, \"A\")) {\n * console.log(`${entry.node} at depth ${entry.depth}`);\n * }\n * ```\n */\nexport function* bfsWithPath(\n\tgraph: ReadableGraph,\n\tstart: NodeId,\n): Iterable<BfsPathEntry> {\n\tif (!graph.hasNode(start)) {\n\t\treturn;\n\t}\n\n\tconst visited = new Set<NodeId>([start]);\n\tconst queue: { node: NodeId; depth: number; parent: NodeId | undefined }[] = [\n\t\t{ node: start, depth: 0, parent: undefined },\n\t];\n\n\twhile (queue.length > 0) {\n\t\tconst current = queue.shift();\n\t\tif (current === undefined) break;\n\t\tyield current;\n\n\t\tfor (const neighbour of graph.neighbours(current.node)) {\n\t\t\tif (!visited.has(neighbour)) {\n\t\t\t\tvisited.add(neighbour);\n\t\t\t\tqueue.push({\n\t\t\t\t\tnode: neighbour,\n\t\t\t\t\tdepth: current.depth + 1,\n\t\t\t\t\tparent: current.node,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * Depth-first search traversal algorithms.\n *\n * DFS explores as far as possible along each branch before backtracking.\n * This makes it useful for cycle detection, topological sorting, and\n * finding connected components.\n */\n\nimport type { ReadableGraph, NodeId } from \"../graph\";\n\n/**\n * Node visit information during DFS traversal.\n */\nexport interface DfsPathEntry {\n\t/** The visited node identifier */\n\tnode: NodeId;\n\t/** Distance from the start node (0 for start node) */\n\tdepth: number;\n\t/** Parent node in the DFS tree (undefined for start node) */\n\tparent: NodeId | undefined;\n}\n\n/**\n * Perform a depth-first search traversal from a start node.\n *\n * This generator yields node IDs in DFS order (pre-order traversal).\n * It uses lazy evaluation via a generator, making it memory-efficient\n * for large graphs.\n *\n * @param graph - The graph to traverse\n * @param start - The starting node ID\n * @yields Node IDs in DFS order\n *\n * @example\n * ```typescript\n * for (const nodeId of dfs(graph, \"A\")) {\n * console.log(nodeId);\n * }\n * ```\n */\nexport function* dfs(graph: ReadableGraph, start: NodeId): Iterable<NodeId> {\n\tif (!graph.hasNode(start)) {\n\t\treturn;\n\t}\n\n\tconst visited = new Set<NodeId>();\n\tconst stack: NodeId[] = [start];\n\n\twhile (stack.length > 0) {\n\t\tconst current = stack.pop();\n\t\tif (current === undefined) break;\n\n\t\tif (visited.has(current)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tvisited.add(current);\n\t\tyield current;\n\n\t\t// Add neighbours in reverse order to maintain left-to-right traversal\n\t\t// when popping from the stack\n\t\tconst neighbours = [...graph.neighbours(current)].reverse();\n\t\tfor (const neighbour of neighbours) {\n\t\t\tif (!visited.has(neighbour)) {\n\t\t\t\tstack.push(neighbour);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Perform a depth-first search traversal with path information.\n *\n * This generator yields detailed information about each visited node,\n * including its depth from the start and parent in the DFS tree.\n *\n * @param graph - The graph to traverse\n * @param start - The starting node ID\n * @yields Objects containing node ID, depth, and parent\n *\n * @example\n * ```typescript\n * for (const entry of dfsWithPath(graph, \"A\")) {\n * console.log(`${entry.node} at depth ${entry.depth}`);\n * }\n * ```\n */\nexport function* dfsWithPath(\n\tgraph: ReadableGraph,\n\tstart: NodeId,\n): Iterable<DfsPathEntry> {\n\tif (!graph.hasNode(start)) {\n\t\treturn;\n\t}\n\n\tconst visited = new Set<NodeId>();\n\tconst stack: { node: NodeId; depth: number; parent: NodeId | undefined }[] = [\n\t\t{ node: start, depth: 0, parent: undefined },\n\t];\n\n\twhile (stack.length > 0) {\n\t\tconst current = stack.pop();\n\t\tif (current === undefined) break;\n\n\t\tif (visited.has(current.node)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tvisited.add(current.node);\n\t\tyield current;\n\n\t\t// Add neighbours in reverse order to maintain left-to-right traversal\n\t\t// when popping from the stack\n\t\tconst neighbours = [...graph.neighbours(current.node)].reverse();\n\t\tfor (const neighbour of neighbours) {\n\t\t\tif (!visited.has(neighbour)) {\n\t\t\t\tstack.push({\n\t\t\t\t\tnode: neighbour,\n\t\t\t\t\tdepth: current.depth + 1,\n\t\t\t\t\tparent: current.node,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAuCA,UAAiB,IAAI,OAAsB,OAAiC;AAC3E,KAAI,CAAC,MAAM,QAAQ,MAAM,CACxB;CAGD,MAAM,UAAU,IAAI,IAAY,CAAC,MAAM,CAAC;CACxC,MAAM,QAAkB,CAAC,MAAM;AAE/B,QAAO,MAAM,SAAS,GAAG;EACxB,MAAM,UAAU,MAAM,OAAO;AAC7B,MAAI,YAAY,KAAA,EAAW;AAC3B,QAAM;AAEN,OAAK,MAAM,aAAa,MAAM,WAAW,QAAQ,CAChD,KAAI,CAAC,QAAQ,IAAI,UAAU,EAAE;AAC5B,WAAQ,IAAI,UAAU;AACtB,SAAM,KAAK,UAAU;;;;;;;;;;;;;;;;;;;;;;AAwBzB,UAAiB,YAChB,OACA,OACyB;AACzB,KAAI,CAAC,MAAM,QAAQ,MAAM,CACxB;CAGD,MAAM,UAAU,IAAI,IAAY,CAAC,MAAM,CAAC;CACxC,MAAM,QAAuE,CAC5E;EAAE,MAAM;EAAO,OAAO;EAAG,QAAQ,KAAA;EAAW,CAC5C;AAED,QAAO,MAAM,SAAS,GAAG;EACxB,MAAM,UAAU,MAAM,OAAO;AAC7B,MAAI,YAAY,KAAA,EAAW;AAC3B,QAAM;AAEN,OAAK,MAAM,aAAa,MAAM,WAAW,QAAQ,KAAK,CACrD,KAAI,CAAC,QAAQ,IAAI,UAAU,EAAE;AAC5B,WAAQ,IAAI,UAAU;AACtB,SAAM,KAAK;IACV,MAAM;IACN,OAAO,QAAQ,QAAQ;IACvB,QAAQ,QAAQ;IAChB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;AChEN,UAAiB,IAAI,OAAsB,OAAiC;AAC3E,KAAI,CAAC,MAAM,QAAQ,MAAM,CACxB;CAGD,MAAM,0BAAU,IAAI,KAAa;CACjC,MAAM,QAAkB,CAAC,MAAM;AAE/B,QAAO,MAAM,SAAS,GAAG;EACxB,MAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,YAAY,KAAA,EAAW;AAE3B,MAAI,QAAQ,IAAI,QAAQ,CACvB;AAGD,UAAQ,IAAI,QAAQ;AACpB,QAAM;EAIN,MAAM,aAAa,CAAC,GAAG,MAAM,WAAW,QAAQ,CAAC,CAAC,SAAS;AAC3D,OAAK,MAAM,aAAa,WACvB,KAAI,CAAC,QAAQ,IAAI,UAAU,CAC1B,OAAM,KAAK,UAAU;;;;;;;;;;;;;;;;;;;;AAuBzB,UAAiB,YAChB,OACA,OACyB;AACzB,KAAI,CAAC,MAAM,QAAQ,MAAM,CACxB;CAGD,MAAM,0BAAU,IAAI,KAAa;CACjC,MAAM,QAAuE,CAC5E;EAAE,MAAM;EAAO,OAAO;EAAG,QAAQ,KAAA;EAAW,CAC5C;AAED,QAAO,MAAM,SAAS,GAAG;EACxB,MAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,YAAY,KAAA,EAAW;AAE3B,MAAI,QAAQ,IAAI,QAAQ,KAAK,CAC5B;AAGD,UAAQ,IAAI,QAAQ,KAAK;AACzB,QAAM;EAIN,MAAM,aAAa,CAAC,GAAG,MAAM,WAAW,QAAQ,KAAK,CAAC,CAAC,SAAS;AAChE,OAAK,MAAM,aAAa,WACvB,KAAI,CAAC,QAAQ,IAAI,UAAU,CAC1B,OAAM,KAAK;GACV,MAAM;GACN,OAAO,QAAQ,QAAQ;GACvB,QAAQ,QAAQ;GAChB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/traversal/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/traversal/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,OAAO,CAAC;AACtB,cAAc,OAAO,CAAC"}
|
package/dist/traversal/index.js
CHANGED
|
@@ -1,2 +1,149 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/traversal/bfs.ts
|
|
2
|
+
/**
|
|
3
|
+
* Perform a breadth-first search traversal from a start node.
|
|
4
|
+
*
|
|
5
|
+
* This generator yields node IDs in BFS order. It uses lazy evaluation
|
|
6
|
+
* via a generator, making it memory-efficient for large graphs.
|
|
7
|
+
*
|
|
8
|
+
* @param graph - The graph to traverse
|
|
9
|
+
* @param start - The starting node ID
|
|
10
|
+
* @yields Node IDs in BFS order
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* for (const nodeId of bfs(graph, "A")) {
|
|
15
|
+
* console.log(nodeId);
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
function* bfs(graph, start) {
|
|
20
|
+
if (!graph.hasNode(start)) return;
|
|
21
|
+
const visited = new Set([start]);
|
|
22
|
+
const queue = [start];
|
|
23
|
+
while (queue.length > 0) {
|
|
24
|
+
const current = queue.shift();
|
|
25
|
+
if (current === void 0) break;
|
|
26
|
+
yield current;
|
|
27
|
+
for (const neighbour of graph.neighbours(current)) if (!visited.has(neighbour)) {
|
|
28
|
+
visited.add(neighbour);
|
|
29
|
+
queue.push(neighbour);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Perform a breadth-first search traversal with path information.
|
|
35
|
+
*
|
|
36
|
+
* This generator yields detailed information about each visited node,
|
|
37
|
+
* including its depth from the start and parent in the BFS tree.
|
|
38
|
+
* Useful for reconstructing shortest paths.
|
|
39
|
+
*
|
|
40
|
+
* @param graph - The graph to traverse
|
|
41
|
+
* @param start - The starting node ID
|
|
42
|
+
* @yields Objects containing node ID, depth, and parent
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* for (const entry of bfsWithPath(graph, "A")) {
|
|
47
|
+
* console.log(`${entry.node} at depth ${entry.depth}`);
|
|
48
|
+
* }
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
function* bfsWithPath(graph, start) {
|
|
52
|
+
if (!graph.hasNode(start)) return;
|
|
53
|
+
const visited = new Set([start]);
|
|
54
|
+
const queue = [{
|
|
55
|
+
node: start,
|
|
56
|
+
depth: 0,
|
|
57
|
+
parent: void 0
|
|
58
|
+
}];
|
|
59
|
+
while (queue.length > 0) {
|
|
60
|
+
const current = queue.shift();
|
|
61
|
+
if (current === void 0) break;
|
|
62
|
+
yield current;
|
|
63
|
+
for (const neighbour of graph.neighbours(current.node)) if (!visited.has(neighbour)) {
|
|
64
|
+
visited.add(neighbour);
|
|
65
|
+
queue.push({
|
|
66
|
+
node: neighbour,
|
|
67
|
+
depth: current.depth + 1,
|
|
68
|
+
parent: current.node
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/traversal/dfs.ts
|
|
75
|
+
/**
|
|
76
|
+
* Perform a depth-first search traversal from a start node.
|
|
77
|
+
*
|
|
78
|
+
* This generator yields node IDs in DFS order (pre-order traversal).
|
|
79
|
+
* It uses lazy evaluation via a generator, making it memory-efficient
|
|
80
|
+
* for large graphs.
|
|
81
|
+
*
|
|
82
|
+
* @param graph - The graph to traverse
|
|
83
|
+
* @param start - The starting node ID
|
|
84
|
+
* @yields Node IDs in DFS order
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* for (const nodeId of dfs(graph, "A")) {
|
|
89
|
+
* console.log(nodeId);
|
|
90
|
+
* }
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
function* dfs(graph, start) {
|
|
94
|
+
if (!graph.hasNode(start)) return;
|
|
95
|
+
const visited = /* @__PURE__ */ new Set();
|
|
96
|
+
const stack = [start];
|
|
97
|
+
while (stack.length > 0) {
|
|
98
|
+
const current = stack.pop();
|
|
99
|
+
if (current === void 0) break;
|
|
100
|
+
if (visited.has(current)) continue;
|
|
101
|
+
visited.add(current);
|
|
102
|
+
yield current;
|
|
103
|
+
const neighbours = [...graph.neighbours(current)].reverse();
|
|
104
|
+
for (const neighbour of neighbours) if (!visited.has(neighbour)) stack.push(neighbour);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Perform a depth-first search traversal with path information.
|
|
109
|
+
*
|
|
110
|
+
* This generator yields detailed information about each visited node,
|
|
111
|
+
* including its depth from the start and parent in the DFS tree.
|
|
112
|
+
*
|
|
113
|
+
* @param graph - The graph to traverse
|
|
114
|
+
* @param start - The starting node ID
|
|
115
|
+
* @yields Objects containing node ID, depth, and parent
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* for (const entry of dfsWithPath(graph, "A")) {
|
|
120
|
+
* console.log(`${entry.node} at depth ${entry.depth}`);
|
|
121
|
+
* }
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
function* dfsWithPath(graph, start) {
|
|
125
|
+
if (!graph.hasNode(start)) return;
|
|
126
|
+
const visited = /* @__PURE__ */ new Set();
|
|
127
|
+
const stack = [{
|
|
128
|
+
node: start,
|
|
129
|
+
depth: 0,
|
|
130
|
+
parent: void 0
|
|
131
|
+
}];
|
|
132
|
+
while (stack.length > 0) {
|
|
133
|
+
const current = stack.pop();
|
|
134
|
+
if (current === void 0) break;
|
|
135
|
+
if (visited.has(current.node)) continue;
|
|
136
|
+
visited.add(current.node);
|
|
137
|
+
yield current;
|
|
138
|
+
const neighbours = [...graph.neighbours(current.node)].reverse();
|
|
139
|
+
for (const neighbour of neighbours) if (!visited.has(neighbour)) stack.push({
|
|
140
|
+
node: neighbour,
|
|
141
|
+
depth: current.depth + 1,
|
|
142
|
+
parent: current.node
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
2
147
|
export { bfs, bfsWithPath, dfs, dfsWithPath };
|
|
148
|
+
|
|
149
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/traversal/bfs.ts","../../src/traversal/dfs.ts"],"sourcesContent":["/**\n * Breadth-first search traversal algorithms.\n *\n * BFS explores nodes level by level, visiting all neighbours at the current\n * depth before moving to nodes at the next depth level. This guarantees\n * shortest path discovery in unweighted graphs.\n */\n\nimport type { ReadableGraph, NodeId } from \"../graph\";\n\n/**\n * Node visit information during BFS traversal.\n */\nexport interface BfsPathEntry {\n\t/** The visited node identifier */\n\tnode: NodeId;\n\t/** Distance from the start node (0 for start node) */\n\tdepth: number;\n\t/** Parent node in the BFS tree (undefined for start node) */\n\tparent: NodeId | undefined;\n}\n\n/**\n * Perform a breadth-first search traversal from a start node.\n *\n * This generator yields node IDs in BFS order. It uses lazy evaluation\n * via a generator, making it memory-efficient for large graphs.\n *\n * @param graph - The graph to traverse\n * @param start - The starting node ID\n * @yields Node IDs in BFS order\n *\n * @example\n * ```typescript\n * for (const nodeId of bfs(graph, \"A\")) {\n * console.log(nodeId);\n * }\n * ```\n */\nexport function* bfs(graph: ReadableGraph, start: NodeId): Iterable<NodeId> {\n\tif (!graph.hasNode(start)) {\n\t\treturn;\n\t}\n\n\tconst visited = new Set<NodeId>([start]);\n\tconst queue: NodeId[] = [start];\n\n\twhile (queue.length > 0) {\n\t\tconst current = queue.shift();\n\t\tif (current === undefined) break;\n\t\tyield current;\n\n\t\tfor (const neighbour of graph.neighbours(current)) {\n\t\t\tif (!visited.has(neighbour)) {\n\t\t\t\tvisited.add(neighbour);\n\t\t\t\tqueue.push(neighbour);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Perform a breadth-first search traversal with path information.\n *\n * This generator yields detailed information about each visited node,\n * including its depth from the start and parent in the BFS tree.\n * Useful for reconstructing shortest paths.\n *\n * @param graph - The graph to traverse\n * @param start - The starting node ID\n * @yields Objects containing node ID, depth, and parent\n *\n * @example\n * ```typescript\n * for (const entry of bfsWithPath(graph, \"A\")) {\n * console.log(`${entry.node} at depth ${entry.depth}`);\n * }\n * ```\n */\nexport function* bfsWithPath(\n\tgraph: ReadableGraph,\n\tstart: NodeId,\n): Iterable<BfsPathEntry> {\n\tif (!graph.hasNode(start)) {\n\t\treturn;\n\t}\n\n\tconst visited = new Set<NodeId>([start]);\n\tconst queue: { node: NodeId; depth: number; parent: NodeId | undefined }[] = [\n\t\t{ node: start, depth: 0, parent: undefined },\n\t];\n\n\twhile (queue.length > 0) {\n\t\tconst current = queue.shift();\n\t\tif (current === undefined) break;\n\t\tyield current;\n\n\t\tfor (const neighbour of graph.neighbours(current.node)) {\n\t\t\tif (!visited.has(neighbour)) {\n\t\t\t\tvisited.add(neighbour);\n\t\t\t\tqueue.push({\n\t\t\t\t\tnode: neighbour,\n\t\t\t\t\tdepth: current.depth + 1,\n\t\t\t\t\tparent: current.node,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * Depth-first search traversal algorithms.\n *\n * DFS explores as far as possible along each branch before backtracking.\n * This makes it useful for cycle detection, topological sorting, and\n * finding connected components.\n */\n\nimport type { ReadableGraph, NodeId } from \"../graph\";\n\n/**\n * Node visit information during DFS traversal.\n */\nexport interface DfsPathEntry {\n\t/** The visited node identifier */\n\tnode: NodeId;\n\t/** Distance from the start node (0 for start node) */\n\tdepth: number;\n\t/** Parent node in the DFS tree (undefined for start node) */\n\tparent: NodeId | undefined;\n}\n\n/**\n * Perform a depth-first search traversal from a start node.\n *\n * This generator yields node IDs in DFS order (pre-order traversal).\n * It uses lazy evaluation via a generator, making it memory-efficient\n * for large graphs.\n *\n * @param graph - The graph to traverse\n * @param start - The starting node ID\n * @yields Node IDs in DFS order\n *\n * @example\n * ```typescript\n * for (const nodeId of dfs(graph, \"A\")) {\n * console.log(nodeId);\n * }\n * ```\n */\nexport function* dfs(graph: ReadableGraph, start: NodeId): Iterable<NodeId> {\n\tif (!graph.hasNode(start)) {\n\t\treturn;\n\t}\n\n\tconst visited = new Set<NodeId>();\n\tconst stack: NodeId[] = [start];\n\n\twhile (stack.length > 0) {\n\t\tconst current = stack.pop();\n\t\tif (current === undefined) break;\n\n\t\tif (visited.has(current)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tvisited.add(current);\n\t\tyield current;\n\n\t\t// Add neighbours in reverse order to maintain left-to-right traversal\n\t\t// when popping from the stack\n\t\tconst neighbours = [...graph.neighbours(current)].reverse();\n\t\tfor (const neighbour of neighbours) {\n\t\t\tif (!visited.has(neighbour)) {\n\t\t\t\tstack.push(neighbour);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Perform a depth-first search traversal with path information.\n *\n * This generator yields detailed information about each visited node,\n * including its depth from the start and parent in the DFS tree.\n *\n * @param graph - The graph to traverse\n * @param start - The starting node ID\n * @yields Objects containing node ID, depth, and parent\n *\n * @example\n * ```typescript\n * for (const entry of dfsWithPath(graph, \"A\")) {\n * console.log(`${entry.node} at depth ${entry.depth}`);\n * }\n * ```\n */\nexport function* dfsWithPath(\n\tgraph: ReadableGraph,\n\tstart: NodeId,\n): Iterable<DfsPathEntry> {\n\tif (!graph.hasNode(start)) {\n\t\treturn;\n\t}\n\n\tconst visited = new Set<NodeId>();\n\tconst stack: { node: NodeId; depth: number; parent: NodeId | undefined }[] = [\n\t\t{ node: start, depth: 0, parent: undefined },\n\t];\n\n\twhile (stack.length > 0) {\n\t\tconst current = stack.pop();\n\t\tif (current === undefined) break;\n\n\t\tif (visited.has(current.node)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tvisited.add(current.node);\n\t\tyield current;\n\n\t\t// Add neighbours in reverse order to maintain left-to-right traversal\n\t\t// when popping from the stack\n\t\tconst neighbours = [...graph.neighbours(current.node)].reverse();\n\t\tfor (const neighbour of neighbours) {\n\t\t\tif (!visited.has(neighbour)) {\n\t\t\t\tstack.push({\n\t\t\t\t\tnode: neighbour,\n\t\t\t\t\tdepth: current.depth + 1,\n\t\t\t\t\tparent: current.node,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAuCA,UAAiB,IAAI,OAAsB,OAAiC;AAC3E,KAAI,CAAC,MAAM,QAAQ,MAAM,CACxB;CAGD,MAAM,UAAU,IAAI,IAAY,CAAC,MAAM,CAAC;CACxC,MAAM,QAAkB,CAAC,MAAM;AAE/B,QAAO,MAAM,SAAS,GAAG;EACxB,MAAM,UAAU,MAAM,OAAO;AAC7B,MAAI,YAAY,KAAA,EAAW;AAC3B,QAAM;AAEN,OAAK,MAAM,aAAa,MAAM,WAAW,QAAQ,CAChD,KAAI,CAAC,QAAQ,IAAI,UAAU,EAAE;AAC5B,WAAQ,IAAI,UAAU;AACtB,SAAM,KAAK,UAAU;;;;;;;;;;;;;;;;;;;;;;AAwBzB,UAAiB,YAChB,OACA,OACyB;AACzB,KAAI,CAAC,MAAM,QAAQ,MAAM,CACxB;CAGD,MAAM,UAAU,IAAI,IAAY,CAAC,MAAM,CAAC;CACxC,MAAM,QAAuE,CAC5E;EAAE,MAAM;EAAO,OAAO;EAAG,QAAQ,KAAA;EAAW,CAC5C;AAED,QAAO,MAAM,SAAS,GAAG;EACxB,MAAM,UAAU,MAAM,OAAO;AAC7B,MAAI,YAAY,KAAA,EAAW;AAC3B,QAAM;AAEN,OAAK,MAAM,aAAa,MAAM,WAAW,QAAQ,KAAK,CACrD,KAAI,CAAC,QAAQ,IAAI,UAAU,EAAE;AAC5B,WAAQ,IAAI,UAAU;AACtB,SAAM,KAAK;IACV,MAAM;IACN,OAAO,QAAQ,QAAQ;IACvB,QAAQ,QAAQ;IAChB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;AChEN,UAAiB,IAAI,OAAsB,OAAiC;AAC3E,KAAI,CAAC,MAAM,QAAQ,MAAM,CACxB;CAGD,MAAM,0BAAU,IAAI,KAAa;CACjC,MAAM,QAAkB,CAAC,MAAM;AAE/B,QAAO,MAAM,SAAS,GAAG;EACxB,MAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,YAAY,KAAA,EAAW;AAE3B,MAAI,QAAQ,IAAI,QAAQ,CACvB;AAGD,UAAQ,IAAI,QAAQ;AACpB,QAAM;EAIN,MAAM,aAAa,CAAC,GAAG,MAAM,WAAW,QAAQ,CAAC,CAAC,SAAS;AAC3D,OAAK,MAAM,aAAa,WACvB,KAAI,CAAC,QAAQ,IAAI,UAAU,CAC1B,OAAM,KAAK,UAAU;;;;;;;;;;;;;;;;;;;;AAuBzB,UAAiB,YAChB,OACA,OACyB;AACzB,KAAI,CAAC,MAAM,QAAQ,MAAM,CACxB;CAGD,MAAM,0BAAU,IAAI,KAAa;CACjC,MAAM,QAAuE,CAC5E;EAAE,MAAM;EAAO,OAAO;EAAG,QAAQ,KAAA;EAAW,CAC5C;AAED,QAAO,MAAM,SAAS,GAAG;EACxB,MAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,YAAY,KAAA,EAAW;AAE3B,MAAI,QAAQ,IAAI,QAAQ,KAAK,CAC5B;AAGD,UAAQ,IAAI,QAAQ,KAAK;AACzB,QAAM;EAIN,MAAM,aAAa,CAAC,GAAG,MAAM,WAAW,QAAQ,KAAK,CAAC,CAAC,SAAS;AAChE,OAAK,MAAM,aAAa,WACvB,KAAI,CAAC,QAAQ,IAAI,UAAU,CAC1B,OAAM,KAAK;GACV,MAAM;GACN,OAAO,QAAQ,QAAQ;GACvB,QAAQ,QAAQ;GAChB,CAAC"}
|