@thi.ng/adjacency
Version: 
Sparse & bitwise adjacency matrices, lists and selected traversal algorithms for directed & undirected graphs
84 lines (83 loc) • 2.14 kB
JavaScript
import { outOfBounds } from "@thi.ng/errors/out-of-bounds";
class FloydWarshall {
  dist;
  next;
  numV;
  /**
   * Instantiates and pre-computes all shortest paths in given `graph`. See
   * class comments for details.
   *
   * @param graph
   * @param cost
   */
  constructor(graph, cost = () => 1) {
    const numV = this.numV = graph.numVertices();
    const dist = this.dist = new Float32Array(numV * numV).fill(Infinity);
    const next = this.next = new Int32Array(numV * numV).fill(-1);
    for (let [u, v] of graph.edges()) {
      const idx = u * numV + v;
      dist[idx] = cost(u, v);
      next[idx] = v;
    }
    for (let v = 0; v < numV; v++) {
      const idx = v * numV + v;
      dist[idx] = 0;
      next[idx] = v;
    }
    for (let k = 0; k < numV; k++) {
      for (let i = 0; i < numV; i++) {
        const idxIK = i * numV + k;
        for (let j = 0; j < numV; j++) {
          const idxIJ = i * numV + j;
          const idxKJ = k * numV + j;
          const minD = dist[idxIK] + dist[idxKJ];
          if (dist[idxIJ] > minD) {
            dist[idxIJ] = minD;
            next[idxIJ] = next[idxIK];
          }
        }
      }
    }
  }
  /**
   * Returns shortest distance between vertices `a` and `b`, or `undefined` if
   * no connecting path exists. Throws an error if either `a` or `b` are out
   * of bounds.
   *
   * @param a
   * @param b
   */
  distance(a, b) {
    this.ensurePair(a, b);
    return this.dist[a * this.numV + b];
  }
  /**
   * Returns iterator of vertex IDs of path between `a` and `b` (if any).
   * Throws an error if either `a` or `b` are out of bounds.
   *
   * @param a
   * @param b
   */
  *path(a, b) {
    this.ensurePair(a, b);
    const { next, numV } = this;
    if (next[a * numV + b] === -1) return;
    yield a;
    while (a !== b) {
      a = next[a * numV + b];
      yield a;
    }
  }
  ensureIndex(id) {
    !(id >= 0 && id < this.numV) && outOfBounds(id);
  }
  ensurePair(a, b) {
    this.ensureIndex(a);
    this.ensureIndex(b);
  }
}
const floydWarshall = (graph, cost) => new FloydWarshall(graph, cost);
export {
  FloydWarshall,
  floydWarshall
};