Skip to content

Commit d5c290e

Browse files
authored
Merge pull request #110 from JesusTheHun/fix/shortest-path-next-weight
fix: compute next weight from source to destination
2 parents 32039a5 + af7d6c2 commit d5c290e

File tree

3 files changed

+47
-53
lines changed

3 files changed

+47
-53
lines changed

src/algorithms/shortestPath/getPath.ts

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { TraversingTracks } from './types.js';
33
import type { NextWeightFnParams } from '../../types.js';
44

55
import { Graph } from '../../Graph.js';
6+
import { invariant } from '../../invariant.js';
67

78
/**
89
* Computes edge weight as the sum of all the edges in the path.
@@ -23,34 +24,22 @@ export function getPath<Node, LinkProps>(
2324
tracks: TraversingTracks<NoInfer<Node>>,
2425
source: NoInfer<Node>,
2526
destination: NoInfer<Node>,
26-
nextWeightFn: (params: NextWeightFnParams) => number = addWeightFunction,
27+
nextWeightFn: (
28+
params: NextWeightFnParams<Node, LinkProps>,
29+
) => number = addWeightFunction,
2730
): {
2831
nodes: [Node, Node, ...Node[]];
2932
weight: number | undefined;
3033
} {
3134
const { p } = tracks;
32-
const nodeList: Node[] & { weight?: EdgeWeight } = [];
35+
const nodeList: Node[] = [];
3336

34-
let totalWeight: EdgeWeight | undefined = undefined;
3537
let node = destination;
3638

37-
let hop = 1;
3839
while (p.has(node)) {
3940
const currentNode = p.get(node)!;
40-
4141
nodeList.push(node);
42-
const edgeWeight = graph.getEdgeWeight(currentNode, node);
43-
totalWeight = nextWeightFn({
44-
edgeWeight,
45-
currentPathWeight: totalWeight,
46-
hop: hop,
47-
graph: graph,
48-
path: tracks,
49-
previousNode: node,
50-
currentNode: currentNode,
51-
});
5242
node = currentNode;
53-
hop++;
5443
}
5544

5645
if (node !== source) {
@@ -60,6 +49,30 @@ export function getPath<Node, LinkProps>(
6049
nodeList.push(node);
6150
nodeList.reverse();
6251

52+
invariant(nodeList.length >= 2, 'The path should have a least two nodes');
53+
54+
let totalWeight: EdgeWeight | undefined = undefined;
55+
56+
// We start as index=1 to work on the first edge between node 0 and 1
57+
for (let i = 1; i < nodeList.length; i++) {
58+
const previousNode = nodeList[i - 1]!;
59+
const currentNode = nodeList[i]!;
60+
61+
const edgeWeight = graph.getEdgeWeight(previousNode, currentNode);
62+
const edgeProps = graph.getEdgeProperties(previousNode, currentNode)!;
63+
64+
totalWeight = nextWeightFn({
65+
edgeWeight,
66+
currentPathWeight: totalWeight,
67+
hop: i,
68+
graph,
69+
path: nodeList as [Node, Node, ...Node[]],
70+
previousNode,
71+
currentNode,
72+
props: edgeProps,
73+
});
74+
}
75+
6376
return {
6477
nodes: nodeList as [Node, Node, ...Node[]],
6578
weight: totalWeight,

src/algorithms/shortestPath/shortestPath.spec.ts

Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,6 @@ describe("Dijkstra's Shortest Path Algorithm", function () {
7979
.addEdge('e', 'f')
8080
.addEdge('f', 'c');
8181

82-
const serializedGraph = serializeGraph(graph);
83-
8482
expect(shortestPaths(graph, 'a', 'c')).toEqual([
8583
{ nodes: ['a', 'b', 'c'], weight: 2 },
8684
{ nodes: ['a', 'd', 'c'], weight: 2 },
@@ -115,9 +113,10 @@ describe('addWeightFunction', () => {
115113
currentPathWeight: undefined,
116114
hop: 1,
117115
graph: graph,
118-
path: { d: new Map(), p: new Map(), q: new Set() },
116+
path: ['a', 'b'] as const,
119117
previousNode: 'a',
120118
currentNode: 'b',
119+
props: undefined,
121120
};
122121
expect(addWeightFunction(params)).toBe(5);
123122
});
@@ -129,9 +128,10 @@ describe('addWeightFunction', () => {
129128
currentPathWeight: 10,
130129
hop: 1,
131130
graph: graph,
132-
path: { d: new Map(), p: new Map(), q: new Set() },
131+
path: ['a', 'b'] as const,
133132
previousNode: 'a',
134133
currentNode: 'b',
134+
props: undefined,
135135
};
136136
expect(addWeightFunction(params)).toBe(15);
137137
});
@@ -161,7 +161,7 @@ describe('shortestPath with custom weight functions', () => {
161161
const graph = new Graph().addEdge('a', 'b', 2).addEdge('b', 'c', 3);
162162
expect(shortestPath(graph, 'a', 'c', customWeightFn)).toEqual({
163163
nodes: ['a', 'b', 'c'],
164-
weight: 7,
164+
weight: 11,
165165
});
166166
});
167167

@@ -179,44 +179,25 @@ describe('shortestPath with custom weight functions', () => {
179179
shortestPath(graph, 'a', 'c', customWeightFn);
180180

181181
expect(customWeightFn).toHaveBeenCalledWith({
182-
edgeWeight: 2,
182+
edgeWeight: 1,
183183
currentPathWeight: undefined,
184184
hop: 1,
185185
graph: graph,
186+
previousNode: 'a',
186187
currentNode: 'b',
187-
previousNode: 'c',
188-
path: {
189-
d: new Map([
190-
['a', 0],
191-
['b', 1],
192-
['c', 3],
193-
]),
194-
p: new Map([
195-
['b', 'a'],
196-
['c', 'b'],
197-
]),
198-
q: new Set(),
199-
},
188+
path: ['a', 'b', 'c'],
189+
props: undefined,
200190
});
191+
201192
expect(customWeightFn).toHaveBeenCalledWith({
202-
edgeWeight: 1,
203-
currentPathWeight: 2,
193+
edgeWeight: 2,
194+
currentPathWeight: 1,
204195
hop: 2,
205196
graph: graph,
206-
currentNode: 'a',
207197
previousNode: 'b',
208-
path: {
209-
d: new Map([
210-
['a', 0],
211-
['b', 1],
212-
['c', 3],
213-
]),
214-
p: new Map([
215-
['b', 'a'],
216-
['c', 'b'],
217-
]),
218-
q: new Set(),
219-
},
198+
currentNode: 'c',
199+
path: ['a', 'b', 'c'],
200+
props: undefined,
220201
});
221202
});
222203

src/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { TraversingTracks } from './algorithms/shortestPath/types.js';
21
import { Graph } from './Graph.js';
32

43
export type EdgeWeight = number;
@@ -27,7 +26,8 @@ export type NextWeightFnParams<Node = unknown, LinkProps = unknown> = {
2726
currentPathWeight: EdgeWeight | undefined;
2827
hop: number;
2928
graph: Graph<Node, LinkProps>;
30-
path: TraversingTracks<NoInfer<Node>>;
31-
previousNode: NoInfer<Node>;
29+
path: readonly [NoInfer<Node>, NoInfer<Node>, ...NoInfer<Node>[]];
30+
previousNode: NoInfer<Node> | undefined;
3231
currentNode: NoInfer<Node>;
32+
props: LinkProps;
3333
};

0 commit comments

Comments
 (0)