diff --git a/src/index.ts b/src/index.ts index d5c6e4e..941fb17 100644 --- a/src/index.ts +++ b/src/index.ts @@ -178,7 +178,7 @@ export function Graph(serialized?: Serialized) { function depthFirstSearch( sourceNodes?: NodeId[], includeSourceNodes: boolean = true, - errorOnCycle: boolean = false + errorOnCycle: boolean = false, ) { if (!sourceNodes) { sourceNodes = nodes(); @@ -284,7 +284,7 @@ export function Graph(serialized?: Serialized) { // Cormen et al. "Introduction to Algorithms" 3rd Ed. p. 613 function topologicalSort( sourceNodes?: NodeId[], - includeSourceNodes: boolean = true + includeSourceNodes: boolean = true, ) { return depthFirstSearch(sourceNodes, includeSourceNodes, true).reverse(); } @@ -394,12 +394,22 @@ export function Graph(serialized?: Serialized) { function shortestPaths(source: NodeId, destination: NodeId) { let path = shortestPath(source, destination); const paths = [path], - removedEdges = [], + removedEdges: { u: NodeId; v: NodeId; weight: EdgeWeight }[] = [], weight = path.weight; while (weight) { - removeEdge(path[0], path[1]); - removeEdge(path[1], path[0]); - removedEdges.push([path[0], path[1]]); + const u = path[0]; + const v = path[1]; + + if (hasEdge(u, v)) { + removedEdges.push({ u, v, weight: getEdgeWeight(u, v) }); + removeEdge(u, v); + } + + if (hasEdge(v, u)) { + removedEdges.push({ u: v, v: u, weight: getEdgeWeight(v, u) }); + removeEdge(v, u); + } + try { path = shortestPath(source, destination); if (!path.weight || weight < path.weight) break; @@ -408,10 +418,7 @@ export function Graph(serialized?: Serialized) { break; } } - for (const [u, v] of removedEdges) { - addEdge(u, v); - addEdge(v, u); - } + for (const { u, v, weight } of removedEdges) addEdge(u, v, weight); return paths; } diff --git a/test.js b/test.js index 922e3f4..60210ea 100644 --- a/test.js +++ b/test.js @@ -378,7 +378,7 @@ describe("Graph", function () { var graph = Graph().addEdge("a", "b").addEdge("b", "c"); assert.deepEqual( graph.shortestPath("a", "c"), - withWeight(["a", "b", "c"], 2) + withWeight(["a", "b", "c"], 2), ); }); @@ -396,11 +396,11 @@ describe("Graph", function () { assert.deepEqual( graph.shortestPath("s", "z"), - withWeight(["s", "y", "z"], 5 + 2) + withWeight(["s", "y", "z"], 5 + 2), ); assert.deepEqual( graph.shortestPath("s", "x"), - withWeight(["s", "y", "t", "x"], 5 + 3 + 1) + withWeight(["s", "y", "t", "x"], 5 + 3 + 1), ); }); @@ -423,11 +423,11 @@ describe("Graph", function () { var graph = Graph().addEdge("a", "b").addEdge("b", "c").addEdge("d", "e"); assert.deepEqual( graph.shortestPath("a", "c"), - withWeight(["a", "b", "c"], 2) + withWeight(["a", "b", "c"], 2), ); }); - it("Should compute shortest paths on six edges.", function () { + it("Should compute shortest paths.", function () { var graph = Graph() .addEdge("a", "b") .addEdge("b", "c") @@ -436,14 +436,21 @@ describe("Graph", function () { .addEdge("a", "e") .addEdge("e", "f") .addEdge("f", "c"); + const serializedGraph = graph.serialize(); assert.deepEqual(graph.shortestPaths("a", "c"), [ withWeight(["a", "b", "c"], 2), withWeight(["a", "d", "c"], 2), ]); - // need to check nodes are still present because we remove them to get all shortest paths - const nodes = ["a", "b", "c", "d", "e", "f"]; - assert.equal(graph.nodes().length, nodes.length); - nodes.forEach((node) => assert(contains(graph.nodes(), node))); + // check graph has not changed + const postSerializedGraph = graph.serialize(); + assert.equal( + postSerializedGraph.links.length, + serializedGraph.links.length, + ); + assert.equal( + postSerializedGraph.nodes.length, + serializedGraph.nodes.length, + ); }); }); @@ -458,11 +465,7 @@ describe("Graph", function () { }); function contains(arr, item) { - return ( - arr.filter(function (d) { - return d === item; - }).length > 0 - ); + return arr.includes(item); } function comesBefore(arr, a, b) {