blob: f36c9a7d8c88201da426586c5719bb1ddecbedde [file] [log] [blame]
library graphlib.alg.dijkstra;
import "../graph.dart";
import "../data/priority_queue.dart";
import "common.dart";
Map<dynamic, Path> dijkstra(Graph g, source, [weightFunc weightFn, edgeFunc edgeFn]) {
return _runDijkstra(g, source.toString(),
weightFn == null ? DEFAULT_WEIGHT_FUNC : weightFn,
edgeFn == null ? (v) => g.outEdges(v) : edgeFn);
}
Map<dynamic, Path> _runDijkstra(Graph g, source, weightFunc weightFn, edgeFunc edgeFn) {
Map<dynamic, Path> results = {};
final pq = new PriorityQueue();
var v, vEntry;
updateNeighbors(Edge edge) {
final w = edge.v != v ? edge.v : edge.w,
wEntry = results[w],
weight = weightFn(edge);
final distance = (vEntry.distance != null ? vEntry.distance : 0.0) +
(weight != null ? weight : 0.0);
if (weight < 0) {
throw new AlgorithmException("dijkstra does not allow negative edge weights. "
"Bad edge: $edge Weight: $weight");
}
if (wEntry.distance != null && distance < wEntry.distance) {
wEntry.distance = distance;
wEntry.predecessor = v;
pq.decrease(w, distance);
}
};
g.nodes.forEach((v) {
var distance = v == source ? 0 : double.INFINITY;
results[v] = new Path(distance: distance);
pq.add(v, distance);
});
while (pq.length > 0) {
v = pq.removeMin();
vEntry = results[v];
if (vEntry.distance == double.INFINITY) {
break;
}
List<Edge> edges = edgeFn(v);
edges.forEach(updateNeighbors);
}
return results;
}
Map<dynamic, Map<dynamic, Path>> dijkstraAll(Graph g, [weightFunc weightFn, edgeFunc edgeFn]) {
var results = {};
g.nodes.forEach((v) {
results[v] = dijkstra(g, v, weightFn, edgeFn);
});
return results;
}