dagre-d3-es
Version:
<p align="center"> <a href="https://tbo47.github.io/" ><img src="https://img.shields.io/badge/created_by-tbo47-blue.svg" alt="Created by tbo47"></a> <a href="https://www.npmjs.com/dagre-d3-es"><img src="https://img.shields.io/npm/v/dagre-d3-es.svg?log
119 lines (110 loc) • 3.6 kB
JavaScript
import * as _ from 'lodash-es';
/**
* @import { Graph, EdgeObj, NodeID } from '../graph.js';
* @import { PathEntry } from './dijkstra.js';
*/
export { floydWarshall };
var DEFAULT_WEIGHT_FUNC = _.constant(1);
/**
* This function is an implementation of the [Floyd-Warshall algorithm][],
* which finds the shortest path from each node to every other reachable node
* in the graph. It is similar to {@link dijkstraAll}, but
* it handles negative edge weights and is more efficient for some types of
* graphs.
*
* [Floyd-Warshall algorithm]: https://en.wikipedia.org/wiki/Floyd-Warshall_algorithm
*
* @remarks This algorithm takes `O(|V|^3)` time.
*
* @example
*
* 
*
* ```js
* function weight(e) { return g.edge(e); }
*
* graphlib.alg.floydWarshall(g, function(e) { return g.edge(e); });
*
* // => { A:
* // { A: { distance: 0 },
* // B: { distance: 6, predecessor: 'C' },
* // C: { distance: 4, predecessor: 'A' },
* // D: { distance: 2, predecessor: 'A' },
* // E: { distance: 8, predecessor: 'F' },
* // F: { distance: 4, predecessor: 'D' } },
* // B:
* // { A: { distance: Infinity },
* // B: { distance: 0 },
* // C: { distance: Infinity },
* // D: { distance: Infinity },
* // E: { distance: 6, predecessor: 'B' },
* // F: { distance: Infinity } },
* // C: { ... },
* // D: { ... },
* // E: { ... },
* // F: { ... } }
* ```
*
* @param {Graph} g - The graph to analyze.
* @param {(e: EdgeObj) => number} [weightFn] - Optional function that returns
* the weight for edge `e`. If no `weightFn` is supplied then each edge is
* assumed to have a weight of 1.
* @param {(v: NodeID) => EdgeObj[]} [edgeFn] - Optional function that returns
* the ids of all edges incident to the node `v` for the purposes of shortest
* path traversal.
* By default this function uses the {@link Graph.outEdges} function on the
* supplied graph.
* @returns {Record<NodeID, Record<NodeID, PathEntry>>} a map of
* `source -> { target -> { distance, predecessor }`.
*/
function floydWarshall(g, weightFn, edgeFn) {
return runFloydWarshall(
g,
weightFn || DEFAULT_WEIGHT_FUNC,
edgeFn ||
function (v) {
return g.outEdges(v);
},
);
}
/**
* @param {Graph} g - Input graph.
* @param {(e: EdgeObj) => number} weightFn - Required weight function.
* @param {(v: NodeID) => EdgeObj[]} edgeFn - Required edge function.
*/
function runFloydWarshall(g, weightFn, edgeFn) {
/** @type {Record<NodeID, Record<NodeID, PathEntry>>} */
var results = {};
var nodes = g.nodes();
nodes.forEach(function (v) {
results[v] = {};
results[v][v] = { distance: 0 };
nodes.forEach(function (w) {
if (v !== w) {
results[v][w] = { distance: Number.POSITIVE_INFINITY };
}
});
edgeFn(v).forEach(function (edge) {
var w = edge.v === v ? edge.w : edge.v;
var d = weightFn(edge);
results[v][w] = { distance: d, predecessor: v };
});
});
nodes.forEach(function (k) {
var rowK = results[k];
nodes.forEach(function (i) {
var rowI = results[i];
nodes.forEach(function (j) {
var ik = rowI[k];
var kj = rowK[j];
var ij = rowI[j];
var altDistance = ik.distance + kj.distance;
if (altDistance < ij.distance) {
ij.distance = altDistance;
ij.predecessor = kj.predecessor;
}
});
});
});
return results;
}