Skip to content

Commit

Permalink
Merge pull request #71 from krm35/fix/shortestPaths
Browse files Browse the repository at this point in the history
Fix/shortest paths
  • Loading branch information
curran committed Dec 6, 2023
2 parents 8b5bcad + e3cc716 commit 4610bed
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 24 deletions.
27 changes: 17 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down
31 changes: 17 additions & 14 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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),
);
});

Expand All @@ -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),
);
});

Expand All @@ -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")
Expand All @@ -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,
);
});
});

Expand All @@ -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) {
Expand Down

0 comments on commit 4610bed

Please sign in to comment.