bmssp 0.12.0 → 0.14.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/index.mjs +1 -0
- package/package.json +5 -5
- package/src/bmssp.mjs +38 -0
- package/src/dijkstra.mjs +80 -0
package/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bmssp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Javascript package implementation of the bmssp algorithm.",
|
|
5
5
|
"main": "index.mjs",
|
|
6
6
|
"keywords": [
|
|
@@ -42,13 +42,13 @@
|
|
|
42
42
|
"prettier:fix": "prettier --write \"./**/{*.js,*.mjs}\""
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@eslint/js": "^
|
|
45
|
+
"@eslint/js": "^10.0.1",
|
|
46
46
|
"@eslint/markdown": "^7.2.0",
|
|
47
|
-
"eslint": "^
|
|
47
|
+
"eslint": "^10.0.0",
|
|
48
48
|
"eslint-config-prettier": "^10.1.8",
|
|
49
49
|
"eslint-plugin-prettier": "^5.5.4",
|
|
50
|
-
"globals": "^
|
|
50
|
+
"globals": "^17.0.0",
|
|
51
51
|
"jest": "^30.1.1",
|
|
52
|
-
"prettier": "3.
|
|
52
|
+
"prettier": "3.8.1"
|
|
53
53
|
}
|
|
54
54
|
}
|
package/src/bmssp.mjs
CHANGED
|
@@ -1,10 +1,48 @@
|
|
|
1
|
+
import { dijkstra } from "./dijkstra.mjs";
|
|
2
|
+
|
|
1
3
|
class BMSSP {
|
|
2
4
|
constructor(inputGraph) {
|
|
5
|
+
// Main graph represented as an array of edges
|
|
3
6
|
this.graph = [];
|
|
7
|
+
// Set to store unique node IDs
|
|
8
|
+
this.nodeIDs = new Set();
|
|
9
|
+
// Map to store shortest paths
|
|
10
|
+
this.shortestPaths = new Map();
|
|
11
|
+
|
|
4
12
|
for (let edge of inputGraph) {
|
|
5
13
|
// Create a deep copy of each edge array
|
|
6
14
|
this.graph.push([...edge]);
|
|
15
|
+
|
|
16
|
+
// Add node IDs to the set
|
|
17
|
+
this.nodeIDs.add(edge[0]);
|
|
18
|
+
this.nodeIDs.add(edge[1]);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Initialize shortest paths map
|
|
22
|
+
this.initializeShortestPaths();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Method to initialize the shortest paths map
|
|
26
|
+
initializeShortestPaths() {
|
|
27
|
+
for (let nodeId of this.nodeIDs) {
|
|
28
|
+
this.shortestPaths.set(nodeId, Infinity);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Method to calculate shortest paths from startNode using Dijkstra
|
|
33
|
+
calculateShortestPaths(startNode) {
|
|
34
|
+
// To clean the state before calculation
|
|
35
|
+
this.initializeShortestPaths();
|
|
36
|
+
|
|
37
|
+
// validate startNode
|
|
38
|
+
if (!this.nodeIDs.has(startNode)) {
|
|
39
|
+
throw new Error("Start node not found in the graph");
|
|
7
40
|
}
|
|
41
|
+
|
|
42
|
+
const result = dijkstra(this.graph, this.nodeIDs, startNode);
|
|
43
|
+
result.forEach((distance, nodeId) => {
|
|
44
|
+
this.shortestPaths.set(nodeId, distance);
|
|
45
|
+
});
|
|
8
46
|
}
|
|
9
47
|
}
|
|
10
48
|
|
package/src/dijkstra.mjs
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple Dijkstra single-source shortest path.
|
|
3
|
+
* Requires all edge weights to be non-negative; with negative weights it may return incorrect paths.
|
|
4
|
+
* @param {Array<[number, number, number]>} graph - Array of edges [from, to, weight] with non-negative weight
|
|
5
|
+
* @param {Set<number>} nodeIDs - Set of all node IDs (distances for these will be in the result)
|
|
6
|
+
* @param {number} source - Source node ID (must be present in nodeIDs)
|
|
7
|
+
* @throws {Error} If source is not in nodeIDs
|
|
8
|
+
* @returns {Map<number, number>} Map from node ID to shortest distance from source (Infinity if unreachable)
|
|
9
|
+
*/
|
|
10
|
+
function dijkstra(graph, nodeIDs, source) {
|
|
11
|
+
if (!nodeIDs.has(source)) {
|
|
12
|
+
throw new Error("Source node not found in nodeIDs");
|
|
13
|
+
}
|
|
14
|
+
const dist = new Map();
|
|
15
|
+
for (const id of nodeIDs) {
|
|
16
|
+
dist.set(id, Infinity);
|
|
17
|
+
}
|
|
18
|
+
dist.set(source, 0);
|
|
19
|
+
|
|
20
|
+
// Build adjacency list: from -> [{ to, weight }, ...]
|
|
21
|
+
const adj = new Map();
|
|
22
|
+
for (const [from, to, weight] of graph) {
|
|
23
|
+
if (!adj.has(from)) adj.set(from, []);
|
|
24
|
+
adj.get(from).push({ to, weight });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Min-heap of [distance, node]; compare by distance
|
|
28
|
+
const heap = [[0, source]];
|
|
29
|
+
|
|
30
|
+
function heapPush(d, v) {
|
|
31
|
+
heap.push([d, v]);
|
|
32
|
+
let i = heap.length - 1;
|
|
33
|
+
while (i > 0) {
|
|
34
|
+
const p = (i - 1) >> 1;
|
|
35
|
+
if (heap[p][0] <= heap[i][0]) break;
|
|
36
|
+
[heap[p], heap[i]] = [heap[i], heap[p]];
|
|
37
|
+
i = p;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function heapPop() {
|
|
42
|
+
if (heap.length === 0) return null;
|
|
43
|
+
const top = heap[0];
|
|
44
|
+
const last = heap.pop();
|
|
45
|
+
if (heap.length === 0) return top;
|
|
46
|
+
heap[0] = last;
|
|
47
|
+
let i = 0;
|
|
48
|
+
const n = heap.length;
|
|
49
|
+
while (true) {
|
|
50
|
+
let smallest = i;
|
|
51
|
+
const left = 2 * i + 1;
|
|
52
|
+
const right = 2 * i + 2;
|
|
53
|
+
if (left < n && heap[left][0] < heap[smallest][0]) smallest = left;
|
|
54
|
+
if (right < n && heap[right][0] < heap[smallest][0]) smallest = right;
|
|
55
|
+
if (smallest === i) break;
|
|
56
|
+
[heap[i], heap[smallest]] = [heap[smallest], heap[i]];
|
|
57
|
+
i = smallest;
|
|
58
|
+
}
|
|
59
|
+
return top;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
while (heap.length > 0) {
|
|
63
|
+
const [d, u] = heapPop();
|
|
64
|
+
if (d > dist.get(u)) continue;
|
|
65
|
+
const neighbors = adj.get(u);
|
|
66
|
+
if (!neighbors) continue;
|
|
67
|
+
for (const { to, weight } of neighbors) {
|
|
68
|
+
if (!dist.has(to)) continue;
|
|
69
|
+
const alt = d + weight;
|
|
70
|
+
if (alt < dist.get(to)) {
|
|
71
|
+
dist.set(to, alt);
|
|
72
|
+
heapPush(alt, to);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return dist;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export { dijkstra };
|