graphwise 1.1.1 → 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
|
@@ -1,138 +0,0 @@
|
|
|
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
|
|
131
|
-
Object.defineProperty(exports, "PriorityQueue", {
|
|
132
|
-
enumerable: true,
|
|
133
|
-
get: function() {
|
|
134
|
-
return PriorityQueue;
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
//# sourceMappingURL=structures-CJ_S_7fs.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"structures-CJ_S_7fs.cjs","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"}
|
|
@@ -1,149 +0,0 @@
|
|
|
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
|
|
147
|
-
export { bfsWithPath as i, dfsWithPath as n, bfs as r, dfs as t };
|
|
148
|
-
|
|
149
|
-
//# sourceMappingURL=traversal-CQCjUwUJ.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"traversal-CQCjUwUJ.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"}
|
|
@@ -1,172 +0,0 @@
|
|
|
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
|
|
147
|
-
Object.defineProperty(exports, "bfs", {
|
|
148
|
-
enumerable: true,
|
|
149
|
-
get: function() {
|
|
150
|
-
return bfs;
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
Object.defineProperty(exports, "bfsWithPath", {
|
|
154
|
-
enumerable: true,
|
|
155
|
-
get: function() {
|
|
156
|
-
return bfsWithPath;
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
Object.defineProperty(exports, "dfs", {
|
|
160
|
-
enumerable: true,
|
|
161
|
-
get: function() {
|
|
162
|
-
return dfs;
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
Object.defineProperty(exports, "dfsWithPath", {
|
|
166
|
-
enumerable: true,
|
|
167
|
-
get: function() {
|
|
168
|
-
return dfsWithPath;
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
//# sourceMappingURL=traversal-QeHaNUWn.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"traversal-QeHaNUWn.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"}
|
package/dist/utils-Q_akvlMn.js
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
//#region src/utils/clustering-coefficient.ts
|
|
2
|
-
/**
|
|
3
|
-
* Compute the local clustering coefficient for a single node.
|
|
4
|
-
*
|
|
5
|
-
* The clustering coefficient is defined as:
|
|
6
|
-
* CC(v) = (triangles through v) / (possible triangles)
|
|
7
|
-
* CC(v) = 2 * |{(u,w) : u,w in N(v), (u,w) in E}| / (deg(v) * (deg(v) - 1))
|
|
8
|
-
*
|
|
9
|
-
* For nodes with degree < 2, the clustering coefficient is 0.
|
|
10
|
-
*
|
|
11
|
-
* @param graph - The graph to compute on
|
|
12
|
-
* @param nodeId - The node to compute clustering coefficient for
|
|
13
|
-
* @returns The clustering coefficient in [0, 1], or 0 if undefined
|
|
14
|
-
*/
|
|
15
|
-
function localClusteringCoefficient(graph, nodeId) {
|
|
16
|
-
const neighbours = [...graph.neighbours(nodeId, "both")];
|
|
17
|
-
const degree = neighbours.length;
|
|
18
|
-
if (degree < 2) return 0;
|
|
19
|
-
let triangleCount = 0;
|
|
20
|
-
for (let i = 0; i < neighbours.length; i++) {
|
|
21
|
-
const u = neighbours[i];
|
|
22
|
-
if (u === void 0) continue;
|
|
23
|
-
for (let j = i + 1; j < neighbours.length; j++) {
|
|
24
|
-
const w = neighbours[j];
|
|
25
|
-
if (w === void 0) continue;
|
|
26
|
-
if (graph.getEdge(u, w) !== void 0 || graph.getEdge(w, u) !== void 0) triangleCount++;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
const possibleTriangles = degree * (degree - 1) / 2;
|
|
30
|
-
return triangleCount / possibleTriangles;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Compute approximate local clustering coefficient using sampling.
|
|
34
|
-
*
|
|
35
|
-
* For nodes with many neighbours, this samples neighbour pairs rather than
|
|
36
|
-
* checking all pairs. Useful for large graphs where exact computation is expensive.
|
|
37
|
-
*
|
|
38
|
-
* @param graph - The graph to compute on
|
|
39
|
-
* @param nodeId - The node to compute clustering coefficient for
|
|
40
|
-
* @param sampleSize - Maximum number of neighbour pairs to check (default: 100)
|
|
41
|
-
* @returns The approximate clustering coefficient in [0, 1]
|
|
42
|
-
*/
|
|
43
|
-
function approximateClusteringCoefficient(graph, nodeId, sampleSize = 100) {
|
|
44
|
-
const neighbours = [...graph.neighbours(nodeId, "both")];
|
|
45
|
-
const degree = neighbours.length;
|
|
46
|
-
if (degree < 2) return 0;
|
|
47
|
-
const possibleTriangles = degree * (degree - 1) / 2;
|
|
48
|
-
if (possibleTriangles <= sampleSize) return localClusteringCoefficient(graph, nodeId);
|
|
49
|
-
let triangleCount = 0;
|
|
50
|
-
let sampled = 0;
|
|
51
|
-
for (let i = 0; i < neighbours.length && sampled < sampleSize; i++) {
|
|
52
|
-
const u = neighbours[i];
|
|
53
|
-
if (u === void 0) continue;
|
|
54
|
-
for (let j = i + 1; j < neighbours.length && sampled < sampleSize; j++) {
|
|
55
|
-
const w = neighbours[j];
|
|
56
|
-
if (w === void 0) continue;
|
|
57
|
-
sampled++;
|
|
58
|
-
if (graph.getEdge(u, w) !== void 0 || graph.getEdge(w, u) !== void 0) triangleCount++;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return triangleCount / sampled * (possibleTriangles / possibleTriangles);
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Compute clustering coefficients for multiple nodes efficiently.
|
|
65
|
-
*
|
|
66
|
-
* Reuses neighbour sets to avoid repeated iteration.
|
|
67
|
-
*
|
|
68
|
-
* @param graph - The graph to compute on
|
|
69
|
-
* @param nodeIds - The nodes to compute clustering coefficients for
|
|
70
|
-
* @returns Map from nodeId to clustering coefficient
|
|
71
|
-
*/
|
|
72
|
-
function batchClusteringCoefficients(graph, nodeIds) {
|
|
73
|
-
const results = /* @__PURE__ */ new Map();
|
|
74
|
-
for (const nodeId of nodeIds) results.set(nodeId, localClusteringCoefficient(graph, nodeId));
|
|
75
|
-
return results;
|
|
76
|
-
}
|
|
77
|
-
//#endregion
|
|
78
|
-
//#region src/utils/entropy.ts
|
|
79
|
-
/**
|
|
80
|
-
* Entropy computation utilities for graph analysis.
|
|
81
|
-
*
|
|
82
|
-
* Shannon entropy measures uncertainty or randomness in a distribution.
|
|
83
|
-
* Used in EDGE and HAE algorithms for heterogeneity-aware expansion.
|
|
84
|
-
*
|
|
85
|
-
* @packageDocumentation
|
|
86
|
-
*/
|
|
87
|
-
/**
|
|
88
|
-
* Compute Shannon entropy of a probability distribution.
|
|
89
|
-
*
|
|
90
|
-
* Shannon entropy is defined as:
|
|
91
|
-
* H(X) = -Σ p(x) × log₂(p(x))
|
|
92
|
-
*
|
|
93
|
-
* A uniform distribution has maximum entropy.
|
|
94
|
-
* A deterministic distribution (all probability on one value) has zero entropy.
|
|
95
|
-
*
|
|
96
|
-
* @param probabilities - Array of probabilities (should sum to 1)
|
|
97
|
-
* @returns Entropy in bits (log base 2), or 0 if probabilities are invalid
|
|
98
|
-
*/
|
|
99
|
-
function shannonEntropy(probabilities) {
|
|
100
|
-
if (probabilities.length === 0) return 0;
|
|
101
|
-
let entropy = 0;
|
|
102
|
-
for (const p of probabilities) if (p > 0) entropy -= p * Math.log2(p);
|
|
103
|
-
return entropy;
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Compute normalised entropy (entropy divided by maximum possible entropy).
|
|
107
|
-
*
|
|
108
|
-
* Normalised entropy is in [0, 1], where:
|
|
109
|
-
* - 0 means the distribution is deterministic (all mass on one value)
|
|
110
|
-
* - 1 means the distribution is uniform (maximum uncertainty)
|
|
111
|
-
*
|
|
112
|
-
* This is useful for comparing entropy across distributions with different
|
|
113
|
-
* numbers of possible values.
|
|
114
|
-
*
|
|
115
|
-
* @param probabilities - Array of probabilities (should sum to 1)
|
|
116
|
-
* @returns Normalised entropy in [0, 1], or 0 if only one category
|
|
117
|
-
*/
|
|
118
|
-
function normalisedEntropy(probabilities) {
|
|
119
|
-
if (probabilities.length <= 1) return 0;
|
|
120
|
-
const H = shannonEntropy(probabilities);
|
|
121
|
-
const Hmax = Math.log2(probabilities.length);
|
|
122
|
-
if (Hmax === 0) return 0;
|
|
123
|
-
return H / Hmax;
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Compute entropy from a frequency count.
|
|
127
|
-
*
|
|
128
|
-
* Converts counts to probabilities and then computes entropy.
|
|
129
|
-
* This is a convenience function when you have raw counts rather than
|
|
130
|
-
* normalised probabilities.
|
|
131
|
-
*
|
|
132
|
-
* @param counts - Array of frequency counts
|
|
133
|
-
* @returns Entropy in bits
|
|
134
|
-
*/
|
|
135
|
-
function entropyFromCounts(counts) {
|
|
136
|
-
if (counts.length === 0) return 0;
|
|
137
|
-
const total = counts.reduce((sum, c) => sum + c, 0);
|
|
138
|
-
if (total === 0) return 0;
|
|
139
|
-
return shannonEntropy(counts.map((c) => c / total));
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Compute local type entropy for a node's neighbours.
|
|
143
|
-
*
|
|
144
|
-
* This measures the diversity of types among a node's neighbours.
|
|
145
|
-
* High entropy = heterogeneous neighbourhood (diverse types).
|
|
146
|
-
* Low entropy = homogeneous neighbourhood (similar types).
|
|
147
|
-
*
|
|
148
|
-
* @param neighbourTypes - Array of type labels for neighbours
|
|
149
|
-
* @returns Normalised entropy in [0, 1]
|
|
150
|
-
*/
|
|
151
|
-
function localTypeEntropy(neighbourTypes) {
|
|
152
|
-
if (neighbourTypes.length <= 1) return 0;
|
|
153
|
-
const typeCounts = /* @__PURE__ */ new Map();
|
|
154
|
-
for (const t of neighbourTypes) typeCounts.set(t, (typeCounts.get(t) ?? 0) + 1);
|
|
155
|
-
if (typeCounts.size === 1) return 0;
|
|
156
|
-
const probabilities = [];
|
|
157
|
-
const total = neighbourTypes.length;
|
|
158
|
-
for (const count of typeCounts.values()) probabilities.push(count / total);
|
|
159
|
-
return normalisedEntropy(probabilities);
|
|
160
|
-
}
|
|
161
|
-
//#endregion
|
|
162
|
-
export { approximateClusteringCoefficient as a, shannonEntropy as i, localTypeEntropy as n, batchClusteringCoefficients as o, normalisedEntropy as r, localClusteringCoefficient as s, entropyFromCounts as t };
|
|
163
|
-
|
|
164
|
-
//# sourceMappingURL=utils-Q_akvlMn.js.map
|