@graphty/algorithms 1.2.0 → 1.3.1
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/README.md +490 -336
- package/dist/algorithms.d.ts +42 -2
- package/dist/algorithms.js +11099 -2
- package/dist/algorithms.js.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.d.ts +4 -0
- package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.js +124 -170
- package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
- package/dist/src/algorithms/centrality/closeness.d.ts +26 -1
- package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/closeness.js +56 -149
- package/dist/src/algorithms/centrality/closeness.js.map +1 -1
- package/dist/src/algorithms/centrality/degree.js +3 -3
- package/dist/src/algorithms/centrality/degree.js.map +1 -1
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts +39 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js +286 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank.d.ts +80 -0
- package/dist/src/algorithms/centrality/delta-pagerank.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank.js +294 -0
- package/dist/src/algorithms/centrality/delta-pagerank.js.map +1 -0
- package/dist/src/algorithms/centrality/index.d.ts +2 -0
- package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/index.js +1 -0
- package/dist/src/algorithms/centrality/index.js.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.d.ts +17 -0
- package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.js +45 -0
- package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.js +47 -54
- package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
- package/dist/src/algorithms/community/index.d.ts +2 -0
- package/dist/src/algorithms/community/index.d.ts.map +1 -1
- package/dist/src/algorithms/community/index.js.map +1 -1
- package/dist/src/algorithms/community/label-propagation.d.ts +13 -3
- package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
- package/dist/src/algorithms/community/label-propagation.js +50 -35
- package/dist/src/algorithms/community/label-propagation.js.map +1 -1
- package/dist/src/algorithms/community/leiden.d.ts +3 -2
- package/dist/src/algorithms/community/leiden.d.ts.map +1 -1
- package/dist/src/algorithms/community/leiden.js +34 -39
- package/dist/src/algorithms/community/leiden.js.map +1 -1
- package/dist/src/algorithms/community/louvain-optimized.d.ts +112 -0
- package/dist/src/algorithms/community/louvain-optimized.d.ts.map +1 -0
- package/dist/src/algorithms/community/louvain-optimized.js +303 -0
- package/dist/src/algorithms/community/louvain-optimized.js.map +1 -0
- package/dist/src/algorithms/community/louvain.d.ts.map +1 -1
- package/dist/src/algorithms/community/louvain.js +17 -76
- package/dist/src/algorithms/community/louvain.js.map +1 -1
- package/dist/src/algorithms/community/modularity-utils.d.ts +59 -0
- package/dist/src/algorithms/community/modularity-utils.d.ts.map +1 -0
- package/dist/src/algorithms/community/modularity-utils.js +112 -0
- package/dist/src/algorithms/community/modularity-utils.js.map +1 -0
- package/dist/src/algorithms/matching/bipartite.d.ts.map +1 -1
- package/dist/src/algorithms/matching/bipartite.js +8 -40
- package/dist/src/algorithms/matching/bipartite.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.js +1 -12
- package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts +37 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts.map +1 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js +193 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js.map +1 -0
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts +5 -2
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/dijkstra.js +15 -14
- package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs-unified.d.ts +29 -0
- package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/bfs-unified.js +333 -0
- package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -0
- package/dist/src/algorithms/traversal/bfs-variants.d.ts +54 -0
- package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/bfs-variants.js +368 -0
- package/dist/src/algorithms/traversal/bfs-variants.js.map +1 -0
- package/dist/src/algorithms/traversal/bfs.d.ts +4 -18
- package/dist/src/algorithms/traversal/bfs.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/bfs.js +5 -182
- package/dist/src/algorithms/traversal/bfs.js.map +1 -1
- package/dist/src/benchmark-all-algorithms.d.ts +23 -0
- package/dist/src/benchmark-all-algorithms.d.ts.map +1 -0
- package/dist/src/benchmark-all-algorithms.js +462 -0
- package/dist/src/benchmark-all-algorithms.js.map +1 -0
- package/dist/src/clustering/hierarchical.d.ts +16 -15
- package/dist/src/clustering/hierarchical.d.ts.map +1 -1
- package/dist/src/clustering/hierarchical.js +209 -223
- package/dist/src/clustering/hierarchical.js.map +1 -1
- package/dist/src/clustering/index.d.ts +4 -2
- package/dist/src/clustering/index.d.ts.map +1 -1
- package/dist/src/clustering/index.js +2 -2
- package/dist/src/clustering/index.js.map +1 -1
- package/dist/src/clustering/k-core.d.ts +16 -15
- package/dist/src/clustering/k-core.d.ts.map +1 -1
- package/dist/src/clustering/k-core.js +57 -21
- package/dist/src/clustering/k-core.js.map +1 -1
- package/dist/src/clustering/spectral.d.ts +8 -0
- package/dist/src/clustering/spectral.d.ts.map +1 -1
- package/dist/src/clustering/spectral.js +40 -21
- package/dist/src/clustering/spectral.js.map +1 -1
- package/dist/src/core/graph.js +4 -4
- package/dist/src/core/graph.js.map +1 -1
- package/dist/src/flow/ford-fulkerson.d.ts +17 -11
- package/dist/src/flow/ford-fulkerson.d.ts.map +1 -1
- package/dist/src/flow/ford-fulkerson.js +141 -217
- package/dist/src/flow/ford-fulkerson.js.map +1 -1
- package/dist/src/flow/min-cut.d.ts +6 -5
- package/dist/src/flow/min-cut.d.ts.map +1 -1
- package/dist/src/flow/min-cut.js +17 -8
- package/dist/src/flow/min-cut.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/link-prediction/adamic-adar.d.ts.map +1 -1
- package/dist/src/link-prediction/adamic-adar.js +17 -26
- package/dist/src/link-prediction/adamic-adar.js.map +1 -1
- package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -1
- package/dist/src/link-prediction/common-neighbors.js +7 -11
- package/dist/src/link-prediction/common-neighbors.js.map +1 -1
- package/dist/src/optimized/bit-packed.d.ts +143 -0
- package/dist/src/optimized/bit-packed.d.ts.map +1 -0
- package/dist/src/optimized/bit-packed.js +292 -0
- package/dist/src/optimized/bit-packed.js.map +1 -0
- package/dist/src/optimized/csr-graph.d.ts +86 -0
- package/dist/src/optimized/csr-graph.d.ts.map +1 -0
- package/dist/src/optimized/csr-graph.js +341 -0
- package/dist/src/optimized/csr-graph.js.map +1 -0
- package/dist/src/optimized/direction-optimized-bfs.d.ts +74 -0
- package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -0
- package/dist/src/optimized/direction-optimized-bfs.js +223 -0
- package/dist/src/optimized/direction-optimized-bfs.js.map +1 -0
- package/dist/src/optimized/graph-adapter.d.ts +62 -0
- package/dist/src/optimized/graph-adapter.d.ts.map +1 -0
- package/dist/src/optimized/graph-adapter.js +146 -0
- package/dist/src/optimized/graph-adapter.js.map +1 -0
- package/dist/src/optimized/index.d.ts +14 -0
- package/dist/src/optimized/index.d.ts.map +1 -0
- package/dist/src/optimized/index.js +28 -0
- package/dist/src/optimized/index.js.map +1 -0
- package/dist/src/research/grsbm.d.ts.map +1 -1
- package/dist/src/research/grsbm.js +6 -14
- package/dist/src/research/grsbm.js.map +1 -1
- package/dist/src/research/sync.d.ts.map +1 -1
- package/dist/src/research/sync.js +3 -29
- package/dist/src/research/sync.js.map +1 -1
- package/dist/src/research/terahac.d.ts +2 -0
- package/dist/src/research/terahac.d.ts.map +1 -1
- package/dist/src/research/terahac.js +7 -3
- package/dist/src/research/terahac.js.map +1 -1
- package/dist/src/types/index.d.ts +8 -0
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/utils/algorithm-utilities.d.ts +2 -0
- package/dist/src/utils/algorithm-utilities.d.ts.map +1 -0
- package/dist/src/utils/algorithm-utilities.js +2 -0
- package/dist/src/utils/algorithm-utilities.js.map +1 -0
- package/dist/src/utils/graph-converters.d.ts +79 -0
- package/dist/src/utils/graph-converters.d.ts.map +1 -0
- package/dist/src/utils/graph-converters.js +196 -0
- package/dist/src/utils/graph-converters.js.map +1 -0
- package/dist/src/utils/graph-utilities.d.ts +62 -0
- package/dist/src/utils/graph-utilities.d.ts.map +1 -0
- package/dist/src/utils/graph-utilities.js +148 -0
- package/dist/src/utils/graph-utilities.js.map +1 -0
- package/dist/src/utils/index.d.ts +5 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/index.js +5 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/math-utilities.d.ts +52 -0
- package/dist/src/utils/math-utilities.d.ts.map +1 -0
- package/dist/src/utils/math-utilities.js +123 -0
- package/dist/src/utils/math-utilities.js.map +1 -0
- package/dist/src/utils/matrix-utilities.d.ts +2 -0
- package/dist/src/utils/matrix-utilities.d.ts.map +1 -0
- package/dist/src/utils/matrix-utilities.js +2 -0
- package/dist/src/utils/matrix-utilities.js.map +1 -0
- package/dist/src/utils/optimization-helpers.d.ts +33 -0
- package/dist/src/utils/optimization-helpers.d.ts.map +1 -0
- package/dist/src/utils/optimization-helpers.js +47 -0
- package/dist/src/utils/optimization-helpers.js.map +1 -0
- package/package.json +18 -3
- package/src/algorithms/centrality/betweenness.ts +167 -199
- package/src/algorithms/centrality/closeness.ts +73 -191
- package/src/algorithms/centrality/degree.ts +3 -3
- package/src/algorithms/centrality/delta-pagerank-simple.ts +366 -0
- package/src/algorithms/centrality/delta-pagerank.ts +435 -0
- package/src/algorithms/centrality/index.ts +2 -0
- package/src/algorithms/centrality/pagerank.ts +66 -0
- package/src/algorithms/community/girvan-newman.ts +52 -59
- package/src/algorithms/community/index.ts +2 -0
- package/src/algorithms/community/label-propagation.ts +64 -35
- package/src/algorithms/community/leiden.ts +40 -41
- package/src/algorithms/community/louvain-optimized.ts +445 -0
- package/src/algorithms/community/louvain.ts +24 -104
- package/src/algorithms/community/modularity-utils.ts +146 -0
- package/src/algorithms/matching/bipartite.ts +8 -44
- package/src/algorithms/shortest-path/bellman-ford.ts +1 -14
- package/src/algorithms/shortest-path/bidirectional-dijkstra.ts +248 -0
- package/src/algorithms/shortest-path/dijkstra.ts +17 -15
- package/src/algorithms/traversal/bfs-unified.ts +433 -0
- package/src/algorithms/traversal/bfs-variants.ts +496 -0
- package/src/algorithms/traversal/bfs.ts +10 -228
- package/src/benchmark-all-algorithms.ts +548 -0
- package/src/clustering/hierarchical.ts +241 -251
- package/src/clustering/index.ts +4 -2
- package/src/clustering/k-core.ts +87 -39
- package/src/clustering/spectral.ts +44 -20
- package/src/core/graph.ts +4 -4
- package/src/flow/ford-fulkerson.ts +186 -254
- package/src/flow/min-cut.ts +21 -11
- package/src/index.ts +6 -0
- package/src/link-prediction/adamic-adar.ts +17 -30
- package/src/link-prediction/common-neighbors.ts +7 -16
- package/src/optimized/bit-packed.ts +340 -0
- package/src/optimized/csr-graph.ts +455 -0
- package/src/optimized/direction-optimized-bfs.ts +291 -0
- package/src/optimized/graph-adapter.ts +200 -0
- package/src/optimized/index.ts +36 -0
- package/src/research/grsbm.ts +7 -16
- package/src/research/sync.ts +3 -32
- package/src/research/terahac.ts +10 -2
- package/src/types/index.ts +8 -0
- package/src/utils/algorithm-utilities.ts +2 -0
- package/src/utils/graph-converters.ts +241 -0
- package/src/utils/graph-utilities.ts +199 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/math-utilities.ts +140 -0
- package/src/utils/matrix-utilities.ts +2 -0
- package/src/utils/optimization-helpers.ts +81 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type {Graph} from "../core/graph.js";
|
|
2
2
|
import type {NodeId} from "../types/index.js";
|
|
3
|
+
import {getCommonNeighbors, getIntermediateNodes} from "../utils/graph-utilities.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Common Neighbors link prediction implementation
|
|
@@ -39,23 +40,13 @@ export function commonNeighborsScore(
|
|
|
39
40
|
|
|
40
41
|
const {directed = false} = options;
|
|
41
42
|
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
directed ? Array.from(graph.inNeighbors(target)) : Array.from(graph.neighbors(target)),
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
// Count common neighbors
|
|
51
|
-
let commonCount = 0;
|
|
52
|
-
for (const neighbor of sourceNeighbors) {
|
|
53
|
-
if (targetNeighbors.has(neighbor)) {
|
|
54
|
-
commonCount++;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
43
|
+
// Use utility function to get common neighbors
|
|
44
|
+
// For directed graphs, we want intermediate nodes that form paths source->X->target
|
|
45
|
+
const commonNeighborsSet = directed ?
|
|
46
|
+
getIntermediateNodes(graph, source, target) :
|
|
47
|
+
getCommonNeighbors(graph, source, target, false);
|
|
57
48
|
|
|
58
|
-
return
|
|
49
|
+
return commonNeighborsSet.size;
|
|
59
50
|
}
|
|
60
51
|
|
|
61
52
|
/**
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import {TypedFastBitSet} from "typedfastbitset";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wrapper around TypedFastBitSet with graph-specific optimizations
|
|
5
|
+
*
|
|
6
|
+
* Provides efficient bit-packed set operations optimized for graph algorithms
|
|
7
|
+
* with 8x memory reduction compared to standard JavaScript Set for boolean values.
|
|
8
|
+
*/
|
|
9
|
+
export class GraphBitSet {
|
|
10
|
+
private bitset: TypedFastBitSet;
|
|
11
|
+
private _cardinality = 0;
|
|
12
|
+
|
|
13
|
+
constructor(capacity?: number) {
|
|
14
|
+
this.bitset = new TypedFastBitSet();
|
|
15
|
+
if (capacity) {
|
|
16
|
+
// Pre-allocate for known size
|
|
17
|
+
this.bitset.resize(capacity);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Add a single element
|
|
23
|
+
*/
|
|
24
|
+
add(index: number): void {
|
|
25
|
+
if (!this.bitset.has(index)) {
|
|
26
|
+
this.bitset.add(index);
|
|
27
|
+
this._cardinality++;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Remove a single element
|
|
33
|
+
*/
|
|
34
|
+
remove(index: number): void {
|
|
35
|
+
if (this.bitset.has(index)) {
|
|
36
|
+
this.bitset.remove(index);
|
|
37
|
+
this._cardinality--;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Check if element exists
|
|
43
|
+
*/
|
|
44
|
+
has(index: number): boolean {
|
|
45
|
+
return this.bitset.has(index);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Clear all elements
|
|
50
|
+
*/
|
|
51
|
+
clear(): void {
|
|
52
|
+
this.bitset.clear();
|
|
53
|
+
this._cardinality = 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Check if empty
|
|
58
|
+
*/
|
|
59
|
+
isEmpty(): boolean {
|
|
60
|
+
return this._cardinality === 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Optimized for graph algorithms - add range of indices
|
|
65
|
+
*/
|
|
66
|
+
addRange(start: number, end: number): void {
|
|
67
|
+
for (let i = start; i < end; i++) {
|
|
68
|
+
if (!this.bitset.has(i)) {
|
|
69
|
+
this.bitset.add(i);
|
|
70
|
+
this._cardinality++;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Fast cardinality tracking
|
|
77
|
+
*/
|
|
78
|
+
size(): number {
|
|
79
|
+
return this._cardinality;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Batch operations for frontier management - swap contents
|
|
84
|
+
*/
|
|
85
|
+
swap(other: GraphBitSet): void {
|
|
86
|
+
[this.bitset, other.bitset] = [other.bitset, this.bitset];
|
|
87
|
+
[this._cardinality, other._cardinality] = [other._cardinality, this._cardinality];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Efficient iteration
|
|
92
|
+
*/
|
|
93
|
+
*[Symbol.iterator](): Generator<number> {
|
|
94
|
+
// Use TypedFastBitSet's optimized iteration
|
|
95
|
+
yield* this.bitset;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Set operations with cardinality tracking
|
|
100
|
+
*/
|
|
101
|
+
union(other: GraphBitSet): void {
|
|
102
|
+
const result = this.bitset.union(other.bitset);
|
|
103
|
+
this.bitset = result;
|
|
104
|
+
|
|
105
|
+
const size = this.bitset.size();
|
|
106
|
+
this._cardinality = size;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
intersection(other: GraphBitSet): void {
|
|
110
|
+
const result = this.bitset.intersection(other.bitset);
|
|
111
|
+
this.bitset = result;
|
|
112
|
+
|
|
113
|
+
const size = this.bitset.size();
|
|
114
|
+
this._cardinality = size;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
difference(other: GraphBitSet): void {
|
|
118
|
+
const result = this.bitset.difference(other.bitset);
|
|
119
|
+
this.bitset = result;
|
|
120
|
+
|
|
121
|
+
const size = this.bitset.size();
|
|
122
|
+
this._cardinality = size;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Clone the bitset
|
|
127
|
+
*/
|
|
128
|
+
clone(): GraphBitSet {
|
|
129
|
+
const cloned = new GraphBitSet();
|
|
130
|
+
cloned.bitset = this.bitset.clone();
|
|
131
|
+
|
|
132
|
+
cloned._cardinality = this._cardinality;
|
|
133
|
+
return cloned;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Specialized bit array for visited tracking
|
|
139
|
+
*
|
|
140
|
+
* More memory efficient than GraphBitSet for simple boolean arrays
|
|
141
|
+
* that don't need set operations.
|
|
142
|
+
*/
|
|
143
|
+
export class VisitedBitArray {
|
|
144
|
+
private words: Uint32Array;
|
|
145
|
+
private wordCount: number;
|
|
146
|
+
private _size: number;
|
|
147
|
+
|
|
148
|
+
constructor(size: number) {
|
|
149
|
+
this._size = size;
|
|
150
|
+
this.wordCount = Math.ceil(size / 32);
|
|
151
|
+
this.words = new Uint32Array(this.wordCount);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Set bit at index
|
|
156
|
+
*/
|
|
157
|
+
set(index: number): void {
|
|
158
|
+
if (index < 0 || index >= this._size) {
|
|
159
|
+
throw new Error(`Index ${String(index)} out of bounds [0, ${String(this._size)})`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const wordIndex = index >>> 5; // divide by 32
|
|
163
|
+
const bitIndex = index & 31; // modulo 32
|
|
164
|
+
const word = this.words[wordIndex];
|
|
165
|
+
if (word !== undefined) {
|
|
166
|
+
this.words[wordIndex] = word | (1 << bitIndex);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Get bit at index
|
|
172
|
+
*/
|
|
173
|
+
get(index: number): boolean {
|
|
174
|
+
if (index < 0 || index >= this._size) {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const wordIndex = index >>> 5;
|
|
179
|
+
const bitIndex = index & 31;
|
|
180
|
+
const word = this.words[wordIndex];
|
|
181
|
+
return word !== undefined && (word & (1 << bitIndex)) !== 0;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Clear all bits
|
|
186
|
+
*/
|
|
187
|
+
clear(): void {
|
|
188
|
+
this.words.fill(0);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Toggle bit at index
|
|
193
|
+
*/
|
|
194
|
+
toggle(index: number): void {
|
|
195
|
+
if (index < 0 || index >= this._size) {
|
|
196
|
+
throw new Error(`Index ${String(index)} out of bounds [0, ${String(this._size)})`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const wordIndex = index >>> 5;
|
|
200
|
+
const bitIndex = index & 31;
|
|
201
|
+
const word = this.words[wordIndex];
|
|
202
|
+
if (word !== undefined) {
|
|
203
|
+
this.words[wordIndex] = word ^ (1 << bitIndex);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Population count for statistics
|
|
209
|
+
*/
|
|
210
|
+
popcount(): number {
|
|
211
|
+
let count = 0;
|
|
212
|
+
for (let i = 0; i < this.wordCount; i++) {
|
|
213
|
+
const word = this.words[i];
|
|
214
|
+
if (word !== undefined) {
|
|
215
|
+
count += this.popcountWord(word);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return count;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Efficient population count for a single word
|
|
223
|
+
* Uses bit manipulation tricks for fast counting
|
|
224
|
+
*/
|
|
225
|
+
private popcountWord(n: number): number {
|
|
226
|
+
let x = n;
|
|
227
|
+
x = x - ((x >>> 1) & 0x55555555);
|
|
228
|
+
x = (x & 0x33333333) + ((x >>> 2) & 0x33333333);
|
|
229
|
+
return (((x + (x >>> 4)) & 0xF0F0F0F) * 0x1010101) >>> 24;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Get size of the bit array
|
|
234
|
+
*/
|
|
235
|
+
size(): number {
|
|
236
|
+
return this._size;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Check if all bits are zero
|
|
241
|
+
*/
|
|
242
|
+
isEmpty(): boolean {
|
|
243
|
+
for (let i = 0; i < this.wordCount; i++) {
|
|
244
|
+
if (this.words[i] !== 0) {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Set multiple bits from array
|
|
253
|
+
*/
|
|
254
|
+
setMultiple(indices: number[]): void {
|
|
255
|
+
for (const index of indices) {
|
|
256
|
+
this.set(index);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Get indices of all set bits
|
|
262
|
+
*/
|
|
263
|
+
getSetIndices(): number[] {
|
|
264
|
+
const indices: number[] = [];
|
|
265
|
+
for (let wordIndex = 0; wordIndex < this.wordCount; wordIndex++) {
|
|
266
|
+
const word = this.words[wordIndex];
|
|
267
|
+
if (!word || word === 0) {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
for (let bitIndex = 0; bitIndex < 32; bitIndex++) {
|
|
272
|
+
if (word & (1 << bitIndex)) {
|
|
273
|
+
const index = (wordIndex << 5) + bitIndex;
|
|
274
|
+
if (index < this._size) {
|
|
275
|
+
indices.push(index);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return indices;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Bit-packed distance array for BFS
|
|
286
|
+
*
|
|
287
|
+
* Optimized for storing distances using 16-bit integers (up to 65,535 levels)
|
|
288
|
+
* Still provides 2x memory savings compared to standard 32-bit numbers
|
|
289
|
+
*/
|
|
290
|
+
export class CompactDistanceArray {
|
|
291
|
+
private data: Uint16Array;
|
|
292
|
+
private _size: number;
|
|
293
|
+
private static readonly INFINITY = 65535;
|
|
294
|
+
|
|
295
|
+
constructor(size: number) {
|
|
296
|
+
this._size = size;
|
|
297
|
+
this.data = new Uint16Array(size);
|
|
298
|
+
this.data.fill(CompactDistanceArray.INFINITY); // Initialize with max value (unvisited)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Set distance at index
|
|
303
|
+
*/
|
|
304
|
+
set(index: number, distance: number): void {
|
|
305
|
+
if (distance >= CompactDistanceArray.INFINITY) {
|
|
306
|
+
throw new Error(`Distance exceeds maximum value (${String(CompactDistanceArray.INFINITY - 1)})`);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
this.data[index] = distance;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Get distance at index
|
|
314
|
+
*/
|
|
315
|
+
get(index: number): number {
|
|
316
|
+
const value = this.data[index];
|
|
317
|
+
return value ?? CompactDistanceArray.INFINITY; // Default to unvisited
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Check if node has been visited
|
|
322
|
+
*/
|
|
323
|
+
isVisited(index: number): boolean {
|
|
324
|
+
return this.data[index] !== CompactDistanceArray.INFINITY;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Reset all distances
|
|
329
|
+
*/
|
|
330
|
+
clear(): void {
|
|
331
|
+
this.data.fill(CompactDistanceArray.INFINITY);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Get size
|
|
336
|
+
*/
|
|
337
|
+
size(): number {
|
|
338
|
+
return this._size;
|
|
339
|
+
}
|
|
340
|
+
}
|