diff --git a/lib/alg/dijkstra.js b/lib/alg/dijkstra.js index 4bd4eed9..9a553b03 100644 --- a/lib/alg/dijkstra.js +++ b/lib/alg/dijkstra.js @@ -6,9 +6,13 @@ module.exports = dijkstra; var DEFAULT_WEIGHT_FUNC = _.constant(1); function dijkstra(g, source, weightFn, edgeFn) { + var defaultEdgeFn = function(v) { + return g.outEdges(v); + }; + return runDijkstra(g, String(source), weightFn || DEFAULT_WEIGHT_FUNC, - edgeFn || function(v) { return g.outEdges(v); }); + edgeFn || defaultEdgeFn); } function runDijkstra(g, source, weightFn, edgeFn) { diff --git a/lib/graph.js b/lib/graph.js index 0db664b8..b9505e57 100644 --- a/lib/graph.js +++ b/lib/graph.js @@ -411,8 +411,9 @@ Graph.prototype.setEdge = function() { this._edgeLabels[e] = valueSpecified ? value : this._defaultEdgeLabelFn(v, w, name); - var edgeObj = edgeArgsToObj(this._isDirected, v, w, name); // Ensure we add undirected edges in a consistent way. + var edgeObj = edgeArgsToObj(this._isDirected, v, w, name); + v = edgeObj.v; w = edgeObj.w; @@ -460,32 +461,37 @@ Graph.prototype.removeEdge = function(v, w, name) { }; Graph.prototype.inEdges = function(v, u) { - var inV = this._in[v]; - if (inV) { - var edges = _.values(inV); - if (!u) { - return edges; - } - return _.filter(edges, function(edge) { return edge.v === u; }); + if (this.isDirected()) { + return this._filterEdges(this._in[v], v, u); } + return this.nodeEdges(v, u); }; Graph.prototype.outEdges = function(v, w) { - var outV = this._out[v]; - if (outV) { - var edges = _.values(outV); - if (!w) { - return edges; - } - return _.filter(edges, function(edge) { return edge.w === w; }); + if (this.isDirected()) { + return this._filterEdges(this._out[v], v, w); } + return this.nodeEdges(v, w); }; Graph.prototype.nodeEdges = function(v, w) { - var inEdges = this.inEdges(v, w); - if (inEdges) { - return inEdges.concat(this.outEdges(v, w)); + if (v in this._nodes) { + return this._filterEdges(_.merge(this._in[v], this._out[v]), v, w); + } +}; + +Graph.prototype._filterEdges = function(setV, localEdge, remoteEdge) { + if (!setV) { + return; + } + var edges = _.values(setV); + if (!remoteEdge) { + return edges; } + return _.filter(edges, function(edge) { + return edge.v === localEdge && edge.w === remoteEdge + || edge.v === remoteEdge && edge.w === localEdge; + }); }; function incrementOrInitEntry(map, k) { diff --git a/test/alg/dijkstra-test.js b/test/alg/dijkstra-test.js index 29ce897b..bbd5fd09 100644 --- a/test/alg/dijkstra-test.js +++ b/test/alg/dijkstra-test.js @@ -44,6 +44,20 @@ describe("alg.dijkstra", function() { }); }); + it("works for undirected graphs when edges have a different natural order", + function() { + var g = new Graph({ directed: false }); + g.setPath(["a", "b", "c"]); + g.setEdge("b", "d"); + expect(dijkstra(g, "d")).to.eql({ + a: { distance: 2, predecessor: "b" }, + b: { distance: 1, predecessor: "d" }, + c: { distance: 2, predecessor: "b" }, + d: { distance: 0 } + }); + } + ); + it("uses an optionally supplied weight function", function() { var g = new Graph(); g.setEdge("a", "b", 1);