UNPKG

graph-curry

Version:

a Map based implementation of canonical graph data algorithms

61 lines (50 loc) 2.24 kB
import { addBinSet, asSet, get, hasK, lastK, mapDiff, popFirst, spread, spreadK, } from 'fenugreek-collections'; import { initPath, nextPath, } from './path'; import { components, } from './components'; // **dfs** `:: Map<edge> -> node -> Map<pathEntry>` // depth first traversal export const dfs = edges => (src) => { // >**dfs.trav** `:: Map<pathEntry> -> [node, w] -> Map<pathEntry>` // >depth first traversal const trav = (path = initPath(src), [ n, w ] = [ lastK(path), 0 ]) => spread(mapDiff(edges.get(n))(path)).reduce(trav, nextPath(path, [ n, w ])); return trav(initPath(src)); }; // **bfs** `:: Map<edge> -> node -> Map<pathEntry>` // breadth first traversal export const bfs = edges => (iNode) => { const bVisit = bPath => (bQueue) => { const pred = popFirst(bQueue); const nextNabes = mapDiff(edges.get(pred))(bPath); spread(nextNabes).reduce(nextPath, bPath); spreadK(nextNabes).reduce(addBinSet, bQueue); return bQueue.size > 0 ? bVisit(bPath)(bQueue) : bPath; }; return bVisit(initPath(iNode))(asSet([ iNode ])); }; // **dijkstra** `:: Map<edge> -> node -> Map<pathEntry>` // finds shortest paths from a source node to all node reachable from that node export const dijkstra = edges => (iNode) => { const reachables = bfs(edges)(iNode); const inspectQueue = asSet([ iNode ]); const solutionSet = initPath(iNode); while (inspectQueue.size > 0) { const pred = popFirst(inspectQueue); const nextNabes = edges.get(pred); const { length: dCount, weight: dWeight } = solutionSet.get(pred); for (const [ nabe, nWeight ] of nextNabes) { const prevMap = reachables.get(nabe) || { length: 1, weight: 0 }; const { length: rCount, weight: rWeight } = prevMap; const dMap = { pred, length: dCount + 1, weight: dWeight + nWeight, }; const sMap = ((dWeight + nWeight) < rWeight) ? dMap : prevMap; if (!solutionSet.has(nabe)) { inspectQueue.add(nabe); solutionSet.set(nabe, sMap); } } } return solutionSet; }; // **pathBetween** `:: Map<edge> -> node -> node -> Boolean` // checks for a path between two nodes export const pathBetween = e => n0 => n1 => hasK(get(components(e))(n0))(n1);