UNPKG

theprogrammablemind

Version:

213 lines (189 loc) 4.44 kB
const _ = require('lodash') const toA = (edge) => { if (Array.isArray(edge)) { return edge } else { return [edge.child, edge.parent] } } class Digraph { // edges maybe either [child, parent] or { child, parent } constructor (edges = []) { // dont make a copy of edges. this is shared and that breaks stuff. TODO fix this this._edges = edges } // BFS path (from, to) { const frontier = { [from]: [[]] } const done = new Set() while (Object.keys(frontier).length > 0) { const n = Object.keys(frontier)[0] const ps = frontier[n] if (to == n) { return ps[0] } if (done.has(n)) { delete frontier[n] continue } done.add(n) for (const edge of this._edges) { if (edge.child == n) { if (!frontier[edge.parent]) { frontier[edge.parent] = [] } for (const path of ps) { if (edge.parent == to) { return [...path, edge] } frontier[edge.parent].push([...path, edge]) } } } } } get length () { return this._edges.length } addEdges (edges) { for (const edge of edges) { this.addEdge(edge) } } addEdge (edge) { edge = toA(edge) if (this._edges.find((existing) => _.isEqual(edge, existing))) { return false } this._edges.push(edge) return true } get edges () { return this._edges } set edges (edges) { this._edges = edges } /* set edges(edges) { this._edges = edges.map( toA ) } */ acdcs (s, from, to) { const todo = [s] const seen = new Set([s]) const acdcs = new Set([]) while (todo.length > 0) { const n = todo.pop() this._edges.forEach((e) => { e = toA(e) if (e[from] === n) { acdcs.add(e[to]) if (!seen.has(e[to])) { todo.push(e[to]) seen.add(e[to]) } } }) } return acdcs } isA (low, high) { if (low === high) { return true } return this.ancestors(low).has(high) } lessThan (low, high) { if (low === high) { return false } return this.ancestors(low).has(high) } descendants (s) { return this.acdcs(s, 1, 0) } ancestors (s, { includeSelf } = {}) { const ancestors = this.acdcs(s, 0, 1) if (includeSelf) { ancestors.add(s) } return ancestors } minima (nodes) { nodes = new Set(nodes) const nodeToDescendants = {} for (const node of nodes) { nodeToDescendants[node] = this.descendants(node) } const minima = new Set() for (const node of nodes) { let okay = true for (const key of nodeToDescendants[node]) { if (nodes.has(key)) { if (key in nodeToDescendants && nodeToDescendants[key].has(node)) { continue } okay = false break } } if (okay) { minima.add(node) } } return minima } lub (nodes) { if (nodes.length === 0) { return new Set([]) } nodes = Array.from(nodes) let common = this.ancestors(nodes[0], { includeSelf: true }) for (let i = 1; i < nodes.length; i++) { const ancestors = this.ancestors(nodes[i], { includeSelf: true }) common = new Set([...common].filter(x => ancestors.has(x))) if (common.size === 0) { break } } return this.minima(common) } /* maxima (nodes) { const maxima = new Set(nodes) const descendants = new Set([]) nodes.forEach((node) => { this.descendants(node).forEach((n) => descendants.add(n)) }) descendants.forEach((n) => maxima.delete(n)) return maxima } */ add (child, parent) { this._edges.push([child, parent]) } exists (child, parent) { return this._edges.find((edge) => edge[0] == child && edge[1] == parent) } addList (l) { for (let i = 1; i < l.length; ++i) { if (!this.exists(l[i - 1], l[i])) { this._edges.push([l[i - 1], l[i]]) } } } order (todo) { const ordered = [] while (todo.length > 0) { const nodes = this.minima(todo) todo = todo.filter((e) => !nodes.has(e)) for (const node of nodes) { ordered.push(node) } // ordered = ordered.concat([...nodes]) } return ordered } } module.exports = Digraph