@dagrejs/graphlib
Advanced tools
Comparing version 2.1.4 to 2.1.10
@@ -1,2 +0,2 @@ | ||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.graphlib = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.graphlib = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ | ||
/** | ||
@@ -42,20 +42,18 @@ * Copyright (c) 2014, Chris Pettitt | ||
},{"./lib":17,"./lib/alg":8,"./lib/json":18}],2:[function(require,module,exports){ | ||
var _ = require("../lodash"); | ||
module.exports = components; | ||
function components(g) { | ||
var visited = {}, | ||
cmpts = [], | ||
cmpt; | ||
var visited = {}; | ||
var cmpts = []; | ||
var cmpt; | ||
function dfs(v) { | ||
if (_.has(visited, v)) return; | ||
if (visited.hasOwnProperty(v)) return; | ||
visited[v] = true; | ||
cmpt.push(v); | ||
_.each(g.successors(v), dfs); | ||
_.each(g.predecessors(v), dfs); | ||
g.successors(v).forEach(dfs); | ||
g.predecessors(v).forEach(dfs); | ||
} | ||
_.each(g.nodes(), function(v) { | ||
g.nodes().forEach(function(v) { | ||
cmpt = []; | ||
@@ -71,5 +69,3 @@ dfs(v); | ||
},{"../lodash":19}],3:[function(require,module,exports){ | ||
var _ = require("../lodash"); | ||
},{}],3:[function(require,module,exports){ | ||
module.exports = dfs; | ||
@@ -86,3 +82,3 @@ | ||
function dfs(g, vs, order) { | ||
if (!_.isArray(vs)) { | ||
if (!Array.isArray(vs)) { | ||
vs = [vs]; | ||
@@ -93,5 +89,5 @@ } | ||
var acc = [], | ||
visited = {}; | ||
_.each(vs, function(v) { | ||
var acc = []; | ||
var visited = {}; | ||
vs.forEach(function(v) { | ||
if (!g.hasNode(v)) { | ||
@@ -107,7 +103,7 @@ throw new Error("Graph does not have node: " + v); | ||
function doDfs(g, v, postorder, visited, navigation, acc) { | ||
if (!_.has(visited, v)) { | ||
if (!visited.hasOwnProperty(v)) { | ||
visited[v] = true; | ||
if (!postorder) { acc.push(v); } | ||
_.each(navigation(v), function(w) { | ||
navigation(v).forEach(function(w) { | ||
doDfs(g, w, postorder, visited, navigation, acc); | ||
@@ -119,5 +115,4 @@ }); | ||
},{"../lodash":19}],4:[function(require,module,exports){ | ||
var dijkstra = require("./dijkstra"), | ||
_ = require("../lodash"); | ||
},{}],4:[function(require,module,exports){ | ||
var dijkstra = require("./dijkstra"); | ||
@@ -127,31 +122,31 @@ module.exports = dijkstraAll; | ||
function dijkstraAll(g, weightFunc, edgeFunc) { | ||
return _.transform(g.nodes(), function(acc, v) { | ||
return g.nodes().reduce(function(acc, v) { | ||
acc[v] = dijkstra(g, v, weightFunc, edgeFunc); | ||
return acc; | ||
}, {}); | ||
} | ||
},{"../lodash":19,"./dijkstra":5}],5:[function(require,module,exports){ | ||
var _ = require("../lodash"), | ||
PriorityQueue = require("../data/priority-queue"); | ||
},{"./dijkstra":5}],5:[function(require,module,exports){ | ||
var PriorityQueue = require("../data/priority-queue"); | ||
module.exports = dijkstra; | ||
var DEFAULT_WEIGHT_FUNC = _.constant(1); | ||
var DEFAULT_WEIGHT_FUNC = () => 1; | ||
function dijkstra(g, source, weightFn, edgeFn) { | ||
return runDijkstra(g, String(source), | ||
weightFn || DEFAULT_WEIGHT_FUNC, | ||
edgeFn || function(v) { return g.outEdges(v); }); | ||
weightFn || DEFAULT_WEIGHT_FUNC, | ||
edgeFn || function(v) { return g.outEdges(v); }); | ||
} | ||
function runDijkstra(g, source, weightFn, edgeFn) { | ||
var results = {}, | ||
pq = new PriorityQueue(), | ||
v, vEntry; | ||
var results = {}; | ||
var pq = new PriorityQueue(); | ||
var v, vEntry; | ||
var updateNeighbors = function(edge) { | ||
var w = edge.v !== v ? edge.v : edge.w, | ||
wEntry = results[w], | ||
weight = weightFn(edge), | ||
distance = vEntry.distance + weight; | ||
var w = edge.v !== v ? edge.v : edge.w; | ||
var wEntry = results[w]; | ||
var weight = weightFn(edge); | ||
var distance = vEntry.distance + weight; | ||
@@ -189,5 +184,4 @@ if (weight < 0) { | ||
},{"../data/priority-queue":15,"../lodash":19}],6:[function(require,module,exports){ | ||
var _ = require("../lodash"), | ||
tarjan = require("./tarjan"); | ||
},{"../data/priority-queue":15}],6:[function(require,module,exports){ | ||
var tarjan = require("./tarjan"); | ||
@@ -197,3 +191,3 @@ module.exports = findCycles; | ||
function findCycles(g) { | ||
return _.filter(tarjan(g), function(cmpt) { | ||
return tarjan(g).filter(function(cmpt) { | ||
return cmpt.length > 1 || (cmpt.length === 1 && g.hasEdge(cmpt[0], cmpt[0])); | ||
@@ -203,18 +197,16 @@ }); | ||
},{"../lodash":19,"./tarjan":13}],7:[function(require,module,exports){ | ||
var _ = require("../lodash"); | ||
},{"./tarjan":13}],7:[function(require,module,exports){ | ||
module.exports = floydWarshall; | ||
var DEFAULT_WEIGHT_FUNC = _.constant(1); | ||
var DEFAULT_WEIGHT_FUNC = () => 1; | ||
function floydWarshall(g, weightFn, edgeFn) { | ||
return runFloydWarshall(g, | ||
weightFn || DEFAULT_WEIGHT_FUNC, | ||
edgeFn || function(v) { return g.outEdges(v); }); | ||
weightFn || DEFAULT_WEIGHT_FUNC, | ||
edgeFn || function(v) { return g.outEdges(v); }); | ||
} | ||
function runFloydWarshall(g, weightFn, edgeFn) { | ||
var results = {}, | ||
nodes = g.nodes(); | ||
var results = {}; | ||
var nodes = g.nodes(); | ||
@@ -230,4 +222,4 @@ nodes.forEach(function(v) { | ||
edgeFn(v).forEach(function(edge) { | ||
var w = edge.v === v ? edge.w : edge.v, | ||
d = weightFn(edge); | ||
var w = edge.v === v ? edge.w : edge.v; | ||
var d = weightFn(edge); | ||
results[v][w] = { distance: d, predecessor: v }; | ||
@@ -257,3 +249,3 @@ }); | ||
},{"../lodash":19}],8:[function(require,module,exports){ | ||
},{}],8:[function(require,module,exports){ | ||
module.exports = { | ||
@@ -309,5 +301,4 @@ components: require("./components"), | ||
},{"./dfs":3}],12:[function(require,module,exports){ | ||
var _ = require("../lodash"), | ||
Graph = require("../graph"), | ||
PriorityQueue = require("../data/priority-queue"); | ||
var Graph = require("../graph"); | ||
var PriorityQueue = require("../data/priority-queue"); | ||
@@ -317,10 +308,10 @@ module.exports = prim; | ||
function prim(g, weightFunc) { | ||
var result = new Graph(), | ||
parents = {}, | ||
pq = new PriorityQueue(), | ||
v; | ||
var result = new Graph(); | ||
var parents = {}; | ||
var pq = new PriorityQueue(); | ||
var v; | ||
function updateNeighbors(edge) { | ||
var w = edge.v === v ? edge.w : edge.v, | ||
pri = pq.priority(w); | ||
var w = edge.v === v ? edge.w : edge.v; | ||
var pri = pq.priority(w); | ||
if (pri !== undefined) { | ||
@@ -339,3 +330,3 @@ var edgeWeight = weightFunc(edge); | ||
_.each(g.nodes(), function(v) { | ||
g.nodes().forEach(function(v) { | ||
pq.add(v, Number.POSITIVE_INFINITY); | ||
@@ -351,3 +342,3 @@ result.setNode(v); | ||
v = pq.removeMin(); | ||
if (_.has(parents, v)) { | ||
if (parents.hasOwnProperty(v)) { | ||
result.setEdge(v, parents[v]); | ||
@@ -366,12 +357,10 @@ } else if (init) { | ||
},{"../data/priority-queue":15,"../graph":16,"../lodash":19}],13:[function(require,module,exports){ | ||
var _ = require("../lodash"); | ||
},{"../data/priority-queue":15,"../graph":16}],13:[function(require,module,exports){ | ||
module.exports = tarjan; | ||
function tarjan(g) { | ||
var index = 0, | ||
stack = [], | ||
visited = {}, // node id -> { onStack, lowlink, index } | ||
results = []; | ||
var index = 0; | ||
var stack = []; | ||
var visited = {}; // node id -> { onStack, lowlink, index } | ||
var results = []; | ||
@@ -387,3 +376,3 @@ function dfs(v) { | ||
g.successors(v).forEach(function(w) { | ||
if (!_.has(visited, w)) { | ||
if (!visited.hasOwnProperty(w)) { | ||
dfs(w); | ||
@@ -397,4 +386,4 @@ entry.lowlink = Math.min(entry.lowlink, visited[w].lowlink); | ||
if (entry.lowlink === entry.index) { | ||
var cmpt = [], | ||
w; | ||
var cmpt = []; | ||
var w; | ||
do { | ||
@@ -410,3 +399,3 @@ w = stack.pop(); | ||
g.nodes().forEach(function(v) { | ||
if (!_.has(visited, v)) { | ||
if (!visited.hasOwnProperty(v)) { | ||
dfs(v); | ||
@@ -419,5 +408,3 @@ } | ||
},{"../lodash":19}],14:[function(require,module,exports){ | ||
var _ = require("../lodash"); | ||
},{}],14:[function(require,module,exports){ | ||
module.exports = topsort; | ||
@@ -427,15 +414,15 @@ topsort.CycleException = CycleException; | ||
function topsort(g) { | ||
var visited = {}, | ||
stack = {}, | ||
results = []; | ||
var visited = {}; | ||
var stack = {}; | ||
var results = []; | ||
function visit(node) { | ||
if (_.has(stack, node)) { | ||
if (stack.hasOwnProperty(node)) { | ||
throw new CycleException(); | ||
} | ||
if (!_.has(visited, node)) { | ||
if (!visited.hasOwnProperty(node)) { | ||
stack[node] = true; | ||
visited[node] = true; | ||
_.each(g.predecessors(node), visit); | ||
g.predecessors(node).forEach(visit); | ||
delete stack[node]; | ||
@@ -446,5 +433,5 @@ results.push(node); | ||
_.each(g.sinks(), visit); | ||
g.sinks().forEach(visit); | ||
if (_.size(visited) !== g.nodeCount()) { | ||
if (Object.keys(visited).length !== g.nodeCount()) { | ||
throw new CycleException(); | ||
@@ -457,6 +444,5 @@ } | ||
function CycleException() {} | ||
CycleException.prototype = new Error(); // must be an instance of Error to pass testing | ||
},{"../lodash":19}],15:[function(require,module,exports){ | ||
var _ = require("../lodash"); | ||
},{}],15:[function(require,module,exports){ | ||
module.exports = PriorityQueue; | ||
@@ -494,3 +480,3 @@ | ||
PriorityQueue.prototype.has = function(key) { | ||
return _.has(this._keyIndices, key); | ||
return this._keyIndices.hasOwnProperty(key); | ||
}; | ||
@@ -533,3 +519,3 @@ | ||
key = String(key); | ||
if (!_.has(keyIndices, key)) { | ||
if (!keyIndices.hasOwnProperty(key)) { | ||
var arr = this._arr; | ||
@@ -575,5 +561,5 @@ var index = arr.length; | ||
var arr = this._arr; | ||
var l = 2 * i, | ||
r = l + 1, | ||
largest = i; | ||
var l = 2 * i; | ||
var r = l + 1; | ||
var largest = i; | ||
if (l < arr.length) { | ||
@@ -616,12 +602,10 @@ largest = arr[l].priority < arr[largest].priority ? l : largest; | ||
},{"../lodash":19}],16:[function(require,module,exports){ | ||
},{}],16:[function(require,module,exports){ | ||
"use strict"; | ||
var _ = require("./lodash"); | ||
module.exports = Graph; | ||
var DEFAULT_EDGE_NAME = "\x00", | ||
GRAPH_NODE = "\x00", | ||
EDGE_KEY_DELIM = "\x01"; | ||
var DEFAULT_EDGE_NAME = "\x00"; | ||
var GRAPH_NODE = "\x00"; | ||
var EDGE_KEY_DELIM = "\x01"; | ||
@@ -639,6 +623,12 @@ // Implementation notes: | ||
function Graph(opts) { | ||
this._isDirected = _.has(opts, "directed") ? opts.directed : true; | ||
this._isMultigraph = _.has(opts, "multigraph") ? opts.multigraph : false; | ||
this._isCompound = _.has(opts, "compound") ? opts.compound : false; | ||
this._isDirected = true; | ||
this._isMultigraph = false; | ||
this._isCompound = false; | ||
if (opts) { | ||
this._isDirected = opts.hasOwnProperty("directed") ? opts.directed : true; | ||
this._isMultigraph = opts.hasOwnProperty("multigraph") ? opts.multigraph : false; | ||
this._isCompound = opts.hasOwnProperty("compound") ? opts.compound : false; | ||
} | ||
// Label for the graph itself | ||
@@ -648,6 +638,6 @@ this._label = undefined; | ||
// Defaults to be set when creating a new node | ||
this._defaultNodeLabelFn = _.constant(undefined); | ||
this._defaultNodeLabelFn = () => undefined; | ||
// Defaults to be set when creating a new edge | ||
this._defaultEdgeLabelFn = _.constant(undefined); | ||
this._defaultEdgeLabelFn = () => undefined; | ||
@@ -694,2 +684,5 @@ // v -> label | ||
/** | ||
* Whether graph was created with 'directed' flag set to true or not. | ||
*/ | ||
Graph.prototype.isDirected = function() { | ||
@@ -699,2 +692,5 @@ return this._isDirected; | ||
/** | ||
* Whether graph was created with 'multigraph' flag set to true or not. | ||
*/ | ||
Graph.prototype.isMultigraph = function() { | ||
@@ -704,2 +700,5 @@ return this._isMultigraph; | ||
/** | ||
* Whether graph was created with 'compound' flag set to true or not. | ||
*/ | ||
Graph.prototype.isCompound = function() { | ||
@@ -709,2 +708,5 @@ return this._isCompound; | ||
/** | ||
* Sets the label of the graph. | ||
*/ | ||
Graph.prototype.setGraph = function(label) { | ||
@@ -715,2 +717,5 @@ this._label = label; | ||
/** | ||
* Gets the graph label. | ||
*/ | ||
Graph.prototype.graph = function() { | ||
@@ -723,10 +728,22 @@ return this._label; | ||
/** | ||
* Sets the default node label. If newDefault is a function, it will be | ||
* invoked ach time when setting a label for a node. Otherwise, this label | ||
* will be assigned as default label in case if no label was specified while | ||
* setting a node. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.setDefaultNodeLabel = function(newDefault) { | ||
if (!_.isFunction(newDefault)) { | ||
newDefault = _.constant(newDefault); | ||
this._defaultNodeLabelFn = newDefault; | ||
if (typeof newDefault !== 'function') { | ||
this._defaultNodeLabelFn = () => newDefault; | ||
} | ||
this._defaultNodeLabelFn = newDefault; | ||
return this; | ||
}; | ||
/** | ||
* Gets the number of nodes in the graph. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.nodeCount = function() { | ||
@@ -736,32 +753,54 @@ return this._nodeCount; | ||
/** | ||
* Gets all nodes of the graph. Note, the in case of compound graph subnodes are | ||
* not included in list. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.nodes = function() { | ||
return _.keys(this._nodes); | ||
return Object.keys(this._nodes); | ||
}; | ||
/** | ||
* Gets list of nodes without in-edges. | ||
* Complexity: O(|V|). | ||
*/ | ||
Graph.prototype.sources = function() { | ||
return _.filter(this.nodes(), _.bind(function(v) { | ||
return _.isEmpty(this._in[v]); | ||
}, this)); | ||
var self = this; | ||
return this.nodes().filter(v => Object.keys(self._in[v]).length === 0); | ||
}; | ||
/** | ||
* Gets list of nodes without out-edges. | ||
* Complexity: O(|V|). | ||
*/ | ||
Graph.prototype.sinks = function() { | ||
return _.filter(this.nodes(), _.bind(function(v) { | ||
return _.isEmpty(this._out[v]); | ||
}, this)); | ||
var self = this; | ||
return this.nodes().filter(v => Object.keys(self._out[v]).length === 0); | ||
}; | ||
/** | ||
* Invokes setNode method for each node in names list. | ||
* Complexity: O(|names|). | ||
*/ | ||
Graph.prototype.setNodes = function(vs, value) { | ||
var args = arguments; | ||
_.each(vs, _.bind(function(v) { | ||
var self = this; | ||
vs.forEach(function(v) { | ||
if (args.length > 1) { | ||
this.setNode(v, value); | ||
self.setNode(v, value); | ||
} else { | ||
this.setNode(v); | ||
self.setNode(v); | ||
} | ||
}, this)); | ||
}); | ||
return this; | ||
}; | ||
/** | ||
* Creates or updates the value for the node v in the graph. If label is supplied | ||
* it is set as the value for the node. If label is not supplied and the node was | ||
* created by this call then the default node label will be assigned. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.setNode = function(v, value) { | ||
if (_.has(this._nodes, v)) { | ||
if (this._nodes.hasOwnProperty(v)) { | ||
if (arguments.length > 1) { | ||
@@ -787,2 +826,6 @@ this._nodes[v] = value; | ||
/** | ||
* Gets the label of node with specified name. | ||
* Complexity: O(|V|). | ||
*/ | ||
Graph.prototype.node = function(v) { | ||
@@ -792,10 +835,19 @@ return this._nodes[v]; | ||
/** | ||
* Detects whether graph has a node with specified name or not. | ||
*/ | ||
Graph.prototype.hasNode = function(v) { | ||
return _.has(this._nodes, v); | ||
return this._nodes.hasOwnProperty(v); | ||
}; | ||
/** | ||
* Remove the node with the name from the graph or do nothing if the node is not in | ||
* the graph. If the node was removed this function also removes any incident | ||
* edges. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.removeNode = function(v) { | ||
var self = this; | ||
if (_.has(this._nodes, v)) { | ||
var removeEdge = function(e) { self.removeEdge(self._edgeObjs[e]); }; | ||
if (this._nodes.hasOwnProperty(v)) { | ||
var removeEdge = e => self.removeEdge(self._edgeObjs[e]); | ||
delete this._nodes[v]; | ||
@@ -805,11 +857,11 @@ if (this._isCompound) { | ||
delete this._parent[v]; | ||
_.each(this.children(v), _.bind(function(child) { | ||
this.setParent(child); | ||
}, this)); | ||
this.children(v).forEach(function(child) { | ||
self.setParent(child); | ||
}); | ||
delete this._children[v]; | ||
} | ||
_.each(_.keys(this._in[v]), removeEdge); | ||
Object.keys(this._in[v]).forEach(removeEdge); | ||
delete this._in[v]; | ||
delete this._preds[v]; | ||
_.each(_.keys(this._out[v]), removeEdge); | ||
Object.keys(this._out[v]).forEach(removeEdge); | ||
delete this._out[v]; | ||
@@ -822,2 +874,8 @@ delete this._sucs[v]; | ||
/** | ||
* Sets node p as a parent for node v if it is defined, or removes the | ||
* parent for v if p is undefined. Method throws an exception in case of | ||
* invoking it in context of noncompound graph. | ||
* Average-case complexity: O(1). | ||
*/ | ||
Graph.prototype.setParent = function(v, parent) { | ||
@@ -828,3 +886,3 @@ if (!this._isCompound) { | ||
if (_.isUndefined(parent)) { | ||
if (parent === undefined) { | ||
parent = GRAPH_NODE; | ||
@@ -835,7 +893,7 @@ } else { | ||
for (var ancestor = parent; | ||
!_.isUndefined(ancestor); | ||
ancestor = this.parent(ancestor)) { | ||
ancestor !== undefined; | ||
ancestor = this.parent(ancestor)) { | ||
if (ancestor === v) { | ||
throw new Error("Setting " + parent+ " as parent of " + v + | ||
" would create create a cycle"); | ||
" would create a cycle"); | ||
} | ||
@@ -858,2 +916,6 @@ } | ||
/** | ||
* Gets parent node for node v. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.parent = function(v) { | ||
@@ -868,11 +930,11 @@ if (this._isCompound) { | ||
Graph.prototype.children = function(v) { | ||
if (_.isUndefined(v)) { | ||
v = GRAPH_NODE; | ||
} | ||
/** | ||
* Gets list of direct children of node v. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.children = function(v = GRAPH_NODE) { | ||
if (this._isCompound) { | ||
var children = this._children[v]; | ||
if (children) { | ||
return _.keys(children); | ||
return Object.keys(children); | ||
} | ||
@@ -886,20 +948,40 @@ } else if (v === GRAPH_NODE) { | ||
/** | ||
* Return all nodes that are predecessors of the specified node or undefined if node v is not in | ||
* the graph. Behavior is undefined for undirected graphs - use neighbors instead. | ||
* Complexity: O(|V|). | ||
*/ | ||
Graph.prototype.predecessors = function(v) { | ||
var predsV = this._preds[v]; | ||
if (predsV) { | ||
return _.keys(predsV); | ||
return Object.keys(predsV); | ||
} | ||
}; | ||
/** | ||
* Return all nodes that are successors of the specified node or undefined if node v is not in | ||
* the graph. Behavior is undefined for undirected graphs - use neighbors instead. | ||
* Complexity: O(|V|). | ||
*/ | ||
Graph.prototype.successors = function(v) { | ||
var sucsV = this._sucs[v]; | ||
if (sucsV) { | ||
return _.keys(sucsV); | ||
return Object.keys(sucsV); | ||
} | ||
}; | ||
/** | ||
* Return all nodes that are predecessors or successors of the specified node or undefined if | ||
* node v is not in the graph. | ||
* Complexity: O(|V|). | ||
*/ | ||
Graph.prototype.neighbors = function(v) { | ||
var preds = this.predecessors(v); | ||
if (preds) { | ||
return _.union(preds, this.successors(v)); | ||
const union = new Set(preds); | ||
for (var succ of this.successors(v)) { | ||
union.add(succ); | ||
} | ||
return Array.from(union.values()); | ||
} | ||
@@ -918,2 +1000,8 @@ }; | ||
/** | ||
* Creates new graph with nodes filtered via filter. Edges incident to rejected node | ||
* are also removed. In case of compound graph, if parent is rejected by filter, | ||
* than all its children are rejected too. | ||
* Average-case complexity: O(|E|+|V|). | ||
*/ | ||
Graph.prototype.filterNodes = function(filter) { | ||
@@ -928,15 +1016,15 @@ var copy = new this.constructor({ | ||
_.each(this._nodes, _.bind(function(value, v) { | ||
var self = this; | ||
Object.entries(this._nodes).forEach(function([v, value]) { | ||
if (filter(v)) { | ||
copy.setNode(v, value); | ||
} | ||
}, this)); | ||
}); | ||
_.each(this._edgeObjs, _.bind(function(e) { | ||
Object.values(this._edgeObjs).forEach(function(e) { | ||
if (copy.hasNode(e.v) && copy.hasNode(e.w)) { | ||
copy.setEdge(e, this.edge(e)); | ||
copy.setEdge(e, self.edge(e)); | ||
} | ||
}, this)); | ||
}); | ||
var self = this; | ||
var parents = {}; | ||
@@ -956,5 +1044,3 @@ function findParent(v) { | ||
if (this._isCompound) { | ||
_.each(copy.nodes(), function(v) { | ||
copy.setParent(v, findParent(v)); | ||
}); | ||
copy.nodes().forEach(v => copy.setParent(v, findParent(v))); | ||
} | ||
@@ -967,10 +1053,22 @@ | ||
/** | ||
* Sets the default edge label or factory function. This label will be | ||
* assigned as default label in case if no label was specified while setting | ||
* an edge or this function will be invoked each time when setting an edge | ||
* with no label specified and returned value * will be used as a label for edge. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.setDefaultEdgeLabel = function(newDefault) { | ||
if (!_.isFunction(newDefault)) { | ||
newDefault = _.constant(newDefault); | ||
this._defaultEdgeLabelFn = newDefault; | ||
if (typeof newDefault !== 'function') { | ||
this._defaultEdgeLabelFn = () => newDefault; | ||
} | ||
this._defaultEdgeLabelFn = newDefault; | ||
return this; | ||
}; | ||
/** | ||
* Gets the number of edges in the graph. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.edgeCount = function() { | ||
@@ -980,10 +1078,20 @@ return this._edgeCount; | ||
/** | ||
* Gets edges of the graph. In case of compound graph subgraphs are not considered. | ||
* Complexity: O(|E|). | ||
*/ | ||
Graph.prototype.edges = function() { | ||
return _.values(this._edgeObjs); | ||
return Object.values(this._edgeObjs); | ||
}; | ||
/** | ||
* Establish an edges path over the nodes in nodes list. If some edge is already | ||
* exists, it will update its label, otherwise it will create an edge between pair | ||
* of nodes with label provided or default label if no label provided. | ||
* Complexity: O(|nodes|). | ||
*/ | ||
Graph.prototype.setPath = function(vs, value) { | ||
var self = this, | ||
args = arguments; | ||
_.reduce(vs, function(v, w) { | ||
var self = this; | ||
var args = arguments; | ||
vs.reduce(function(v, w) { | ||
if (args.length > 1) { | ||
@@ -999,10 +1107,12 @@ self.setEdge(v, w, value); | ||
/* | ||
* setEdge(v, w, [value, [name]]) | ||
* setEdge({ v, w, [name] }, [value]) | ||
/** | ||
* Creates or updates the label for the edge (v, w) with the optionally supplied | ||
* name. If label is supplied it is set as the value for the edge. If label is not | ||
* supplied and the edge was created by this call then the default edge label will | ||
* be assigned. The name parameter is only useful with multigraphs. | ||
*/ | ||
Graph.prototype.setEdge = function() { | ||
var v, w, name, value, | ||
valueSpecified = false, | ||
arg0 = arguments[0]; | ||
var v, w, name, value; | ||
var valueSpecified = false; | ||
var arg0 = arguments[0]; | ||
@@ -1029,3 +1139,3 @@ if (typeof arg0 === "object" && arg0 !== null && "v" in arg0) { | ||
w = "" + w; | ||
if (!_.isUndefined(name)) { | ||
if (name !== undefined) { | ||
name = "" + name; | ||
@@ -1035,3 +1145,3 @@ } | ||
var e = edgeArgsToId(this._isDirected, v, w, name); | ||
if (_.has(this._edgeLabels, e)) { | ||
if (this._edgeLabels.hasOwnProperty(e)) { | ||
if (valueSpecified) { | ||
@@ -1043,3 +1153,3 @@ this._edgeLabels[e] = value; | ||
if (!_.isUndefined(name) && !this._isMultigraph) { | ||
if (name !== undefined && !this._isMultigraph) { | ||
throw new Error("Cannot set a named edge when isMultigraph = false"); | ||
@@ -1070,21 +1180,33 @@ } | ||
/** | ||
* Gets the label for the specified edge. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.edge = function(v, w, name) { | ||
var e = (arguments.length === 1 | ||
? edgeObjToId(this._isDirected, arguments[0]) | ||
: edgeArgsToId(this._isDirected, v, w, name)); | ||
? edgeObjToId(this._isDirected, arguments[0]) | ||
: edgeArgsToId(this._isDirected, v, w, name)); | ||
return this._edgeLabels[e]; | ||
}; | ||
/** | ||
* Detects whether the graph contains specified edge or not. No subgraphs are considered. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.hasEdge = function(v, w, name) { | ||
var e = (arguments.length === 1 | ||
? edgeObjToId(this._isDirected, arguments[0]) | ||
: edgeArgsToId(this._isDirected, v, w, name)); | ||
return _.has(this._edgeLabels, e); | ||
? edgeObjToId(this._isDirected, arguments[0]) | ||
: edgeArgsToId(this._isDirected, v, w, name)); | ||
return this._edgeLabels.hasOwnProperty(e); | ||
}; | ||
/** | ||
* Removes the specified edge from the graph. No subgraphs are considered. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.removeEdge = function(v, w, name) { | ||
var e = (arguments.length === 1 | ||
? edgeObjToId(this._isDirected, arguments[0]) | ||
: edgeArgsToId(this._isDirected, v, w, name)), | ||
edge = this._edgeObjs[e]; | ||
? edgeObjToId(this._isDirected, arguments[0]) | ||
: edgeArgsToId(this._isDirected, v, w, name)); | ||
var edge = this._edgeObjs[e]; | ||
if (edge) { | ||
@@ -1104,24 +1226,39 @@ v = edge.v; | ||
/** | ||
* Return all edges that point to the node v. Optionally filters those edges down to just those | ||
* coming from node u. Behavior is undefined for undirected graphs - use nodeEdges instead. | ||
* Complexity: O(|E|). | ||
*/ | ||
Graph.prototype.inEdges = function(v, u) { | ||
var inV = this._in[v]; | ||
if (inV) { | ||
var edges = _.values(inV); | ||
var edges = Object.values(inV); | ||
if (!u) { | ||
return edges; | ||
} | ||
return _.filter(edges, function(edge) { return edge.v === u; }); | ||
return edges.filter(edge => edge.v === u); | ||
} | ||
}; | ||
/** | ||
* Return all edges that are pointed at by node v. Optionally filters those edges down to just | ||
* those point to w. Behavior is undefined for undirected graphs - use nodeEdges instead. | ||
* Complexity: O(|E|). | ||
*/ | ||
Graph.prototype.outEdges = function(v, w) { | ||
var outV = this._out[v]; | ||
if (outV) { | ||
var edges = _.values(outV); | ||
var edges = Object.values(outV); | ||
if (!w) { | ||
return edges; | ||
} | ||
return _.filter(edges, function(edge) { return edge.w === w; }); | ||
return edges.filter(edge => edge.w === w); | ||
} | ||
}; | ||
/** | ||
* Returns all edges to or from node v regardless of direction. Optionally filters those edges | ||
* down to just those between nodes v and w regardless of direction. | ||
* Complexity: O(|E|). | ||
*/ | ||
Graph.prototype.nodeEdges = function(v, w) { | ||
@@ -1155,3 +1292,3 @@ var inEdges = this.inEdges(v, w); | ||
return v + EDGE_KEY_DELIM + w + EDGE_KEY_DELIM + | ||
(_.isUndefined(name) ? DEFAULT_EDGE_NAME : name); | ||
(name === undefined ? DEFAULT_EDGE_NAME : name); | ||
} | ||
@@ -1178,3 +1315,3 @@ | ||
},{"./lodash":19}],17:[function(require,module,exports){ | ||
},{}],17:[function(require,module,exports){ | ||
// Includes only the "core" of graphlib | ||
@@ -1186,5 +1323,4 @@ module.exports = { | ||
},{"./graph":16,"./version":20}],18:[function(require,module,exports){ | ||
var _ = require("./lodash"), | ||
Graph = require("./graph"); | ||
},{"./graph":16,"./version":19}],18:[function(require,module,exports){ | ||
var Graph = require("./graph"); | ||
@@ -1196,2 +1332,6 @@ module.exports = { | ||
/** | ||
* Creates a JSON representation of the graph that can be serialized to a string with | ||
* JSON.stringify. The graph can later be restored using json.read. | ||
*/ | ||
function write(g) { | ||
@@ -1207,4 +1347,5 @@ var json = { | ||
}; | ||
if (!_.isUndefined(g.graph())) { | ||
json.value = _.clone(g.graph()); | ||
if (g.graph() !== undefined) { | ||
json.value = structuredClone(g.graph()); | ||
} | ||
@@ -1215,10 +1356,10 @@ return json; | ||
function writeNodes(g) { | ||
return _.map(g.nodes(), function(v) { | ||
var nodeValue = g.node(v), | ||
parent = g.parent(v), | ||
node = { v: v }; | ||
if (!_.isUndefined(nodeValue)) { | ||
return g.nodes().map(function(v) { | ||
var nodeValue = g.node(v); | ||
var parent = g.parent(v); | ||
var node = { v: v }; | ||
if (nodeValue !== undefined) { | ||
node.value = nodeValue; | ||
} | ||
if (!_.isUndefined(parent)) { | ||
if (parent !== undefined) { | ||
node.parent = parent; | ||
@@ -1231,9 +1372,9 @@ } | ||
function writeEdges(g) { | ||
return _.map(g.edges(), function(e) { | ||
var edgeValue = g.edge(e), | ||
edge = { v: e.v, w: e.w }; | ||
if (!_.isUndefined(e.name)) { | ||
return g.edges().map(function(e) { | ||
var edgeValue = g.edge(e); | ||
var edge = { v: e.v, w: e.w }; | ||
if (e.name !== undefined) { | ||
edge.name = e.name; | ||
} | ||
if (!_.isUndefined(edgeValue)) { | ||
if (edgeValue !== undefined) { | ||
edge.value = edgeValue; | ||
@@ -1245,5 +1386,15 @@ } | ||
/** | ||
* Takes JSON as input and returns the graph representation. | ||
* | ||
* @example | ||
* var g2 = graphlib.json.read(JSON.parse(str)); | ||
* g2.nodes(); | ||
* // ['a', 'b'] | ||
* g2.edges() | ||
* // [ { v: 'a', w: 'b' } ] | ||
*/ | ||
function read(json) { | ||
var g = new Graph(json.options).setGraph(json.value); | ||
_.each(json.nodes, function(entry) { | ||
json.nodes.forEach(function(entry) { | ||
g.setNode(entry.v, entry.value); | ||
@@ -1254,3 +1405,3 @@ if (entry.parent) { | ||
}); | ||
_.each(json.edges, function(entry) { | ||
json.edges.forEach(function(entry) { | ||
g.setEdge({ v: entry.v, w: entry.w, name: entry.name }, entry.value); | ||
@@ -1261,23 +1412,6 @@ }); | ||
},{"./graph":16,"./lodash":19}],19:[function(require,module,exports){ | ||
/* global window */ | ||
},{"./graph":16}],19:[function(require,module,exports){ | ||
module.exports = '2.1.9'; | ||
var lodash; | ||
if (typeof require === "function") { | ||
try { | ||
lodash = require("lodash"); | ||
} catch (e) {} | ||
} | ||
if (!lodash) { | ||
lodash = window._; | ||
} | ||
module.exports = lodash; | ||
},{"lodash":undefined}],20:[function(require,module,exports){ | ||
module.exports = '2.1.4'; | ||
},{}]},{},[1])(1) | ||
}); | ||
}); |
@@ -1,2 +0,3 @@ | ||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.graphlib=f()}})(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}({1:[function(require,module,exports){/** | ||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.graphlib=f()}})(function(){var define,module,exports;return function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r}()({1:[function(require,module,exports){ | ||
/** | ||
* Copyright (c) 2014, Chris Pettitt | ||
@@ -30,3 +31,4 @@ * All rights reserved. | ||
*/ | ||
var lib=require("./lib");module.exports={Graph:lib.Graph,json:require("./lib/json"),alg:require("./lib/alg"),version:lib.version}},{"./lib":17,"./lib/alg":8,"./lib/json":18}],2:[function(require,module,exports){var _=require("../lodash");module.exports=components;function components(g){var visited={},cmpts=[],cmpt;function dfs(v){if(_.has(visited,v))return;visited[v]=true;cmpt.push(v);_.each(g.successors(v),dfs);_.each(g.predecessors(v),dfs)}_.each(g.nodes(),function(v){cmpt=[];dfs(v);if(cmpt.length){cmpts.push(cmpt)}});return cmpts}},{"../lodash":19}],3:[function(require,module,exports){var _=require("../lodash");module.exports=dfs;/* | ||
var lib=require("./lib");module.exports={Graph:lib.Graph,json:require("./lib/json"),alg:require("./lib/alg"),version:lib.version}},{"./lib":17,"./lib/alg":8,"./lib/json":18}],2:[function(require,module,exports){module.exports=components;function components(g){var visited={};var cmpts=[];var cmpt;function dfs(v){if(visited.hasOwnProperty(v))return;visited[v]=true;cmpt.push(v);g.successors(v).forEach(dfs);g.predecessors(v).forEach(dfs)}g.nodes().forEach(function(v){cmpt=[];dfs(v);if(cmpt.length){cmpts.push(cmpt)}});return cmpts}},{}],3:[function(require,module,exports){module.exports=dfs; | ||
/* | ||
* A helper that preforms a pre- or post-order traversal on the input graph | ||
@@ -38,7 +40,8 @@ * and returns the nodes in the order they were visited. If the graph is | ||
* Order must be one of "pre" or "post". | ||
*/ | ||
function dfs(g,vs,order){if(!_.isArray(vs)){vs=[vs]}var navigation=(g.isDirected()?g.successors:g.neighbors).bind(g);var acc=[],visited={};_.each(vs,function(v){if(!g.hasNode(v)){throw new Error("Graph does not have node: "+v)}doDfs(g,v,order==="post",visited,navigation,acc)});return acc}function doDfs(g,v,postorder,visited,navigation,acc){if(!_.has(visited,v)){visited[v]=true;if(!postorder){acc.push(v)}_.each(navigation(v),function(w){doDfs(g,w,postorder,visited,navigation,acc)});if(postorder){acc.push(v)}}}},{"../lodash":19}],4:[function(require,module,exports){var dijkstra=require("./dijkstra"),_=require("../lodash");module.exports=dijkstraAll;function dijkstraAll(g,weightFunc,edgeFunc){return _.transform(g.nodes(),function(acc,v){acc[v]=dijkstra(g,v,weightFunc,edgeFunc)},{})}},{"../lodash":19,"./dijkstra":5}],5:[function(require,module,exports){var _=require("../lodash"),PriorityQueue=require("../data/priority-queue");module.exports=dijkstra;var DEFAULT_WEIGHT_FUNC=_.constant(1);function dijkstra(g,source,weightFn,edgeFn){return runDijkstra(g,String(source),weightFn||DEFAULT_WEIGHT_FUNC,edgeFn||function(v){return g.outEdges(v)})}function runDijkstra(g,source,weightFn,edgeFn){var results={},pq=new PriorityQueue,v,vEntry;var updateNeighbors=function(edge){var w=edge.v!==v?edge.v:edge.w,wEntry=results[w],weight=weightFn(edge),distance=vEntry.distance+weight;if(weight<0){throw new Error("dijkstra does not allow negative edge weights. "+"Bad edge: "+edge+" Weight: "+weight)}if(distance<wEntry.distance){wEntry.distance=distance;wEntry.predecessor=v;pq.decrease(w,distance)}};g.nodes().forEach(function(v){var distance=v===source?0:Number.POSITIVE_INFINITY;results[v]={distance:distance};pq.add(v,distance)});while(pq.size()>0){v=pq.removeMin();vEntry=results[v];if(vEntry.distance===Number.POSITIVE_INFINITY){break}edgeFn(v).forEach(updateNeighbors)}return results}},{"../data/priority-queue":15,"../lodash":19}],6:[function(require,module,exports){var _=require("../lodash"),tarjan=require("./tarjan");module.exports=findCycles;function findCycles(g){return _.filter(tarjan(g),function(cmpt){return cmpt.length>1||cmpt.length===1&&g.hasEdge(cmpt[0],cmpt[0])})}},{"../lodash":19,"./tarjan":13}],7:[function(require,module,exports){var _=require("../lodash");module.exports=floydWarshall;var DEFAULT_WEIGHT_FUNC=_.constant(1);function floydWarshall(g,weightFn,edgeFn){return runFloydWarshall(g,weightFn||DEFAULT_WEIGHT_FUNC,edgeFn||function(v){return g.outEdges(v)})}function runFloydWarshall(g,weightFn,edgeFn){var results={},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,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}},{"../lodash":19}],8:[function(require,module,exports){module.exports={components:require("./components"),dijkstra:require("./dijkstra"),dijkstraAll:require("./dijkstra-all"),findCycles:require("./find-cycles"),floydWarshall:require("./floyd-warshall"),isAcyclic:require("./is-acyclic"),postorder:require("./postorder"),preorder:require("./preorder"),prim:require("./prim"),tarjan:require("./tarjan"),topsort:require("./topsort")}},{"./components":2,"./dijkstra":5,"./dijkstra-all":4,"./find-cycles":6,"./floyd-warshall":7,"./is-acyclic":9,"./postorder":10,"./preorder":11,"./prim":12,"./tarjan":13,"./topsort":14}],9:[function(require,module,exports){var topsort=require("./topsort");module.exports=isAcyclic;function isAcyclic(g){try{topsort(g)}catch(e){if(e instanceof topsort.CycleException){return false}throw e}return true}},{"./topsort":14}],10:[function(require,module,exports){var dfs=require("./dfs");module.exports=postorder;function postorder(g,vs){return dfs(g,vs,"post")}},{"./dfs":3}],11:[function(require,module,exports){var dfs=require("./dfs");module.exports=preorder;function preorder(g,vs){return dfs(g,vs,"pre")}},{"./dfs":3}],12:[function(require,module,exports){var _=require("../lodash"),Graph=require("../graph"),PriorityQueue=require("../data/priority-queue");module.exports=prim;function prim(g,weightFunc){var result=new Graph,parents={},pq=new PriorityQueue,v;function updateNeighbors(edge){var w=edge.v===v?edge.w:edge.v,pri=pq.priority(w);if(pri!==undefined){var edgeWeight=weightFunc(edge);if(edgeWeight<pri){parents[w]=v;pq.decrease(w,edgeWeight)}}}if(g.nodeCount()===0){return result}_.each(g.nodes(),function(v){pq.add(v,Number.POSITIVE_INFINITY);result.setNode(v)}); | ||
*/function dfs(g,vs,order){if(!Array.isArray(vs)){vs=[vs]}var navigation=(g.isDirected()?g.successors:g.neighbors).bind(g);var acc=[];var visited={};vs.forEach(function(v){if(!g.hasNode(v)){throw new Error("Graph does not have node: "+v)}doDfs(g,v,order==="post",visited,navigation,acc)});return acc}function doDfs(g,v,postorder,visited,navigation,acc){if(!visited.hasOwnProperty(v)){visited[v]=true;if(!postorder){acc.push(v)}navigation(v).forEach(function(w){doDfs(g,w,postorder,visited,navigation,acc)});if(postorder){acc.push(v)}}}},{}],4:[function(require,module,exports){var dijkstra=require("./dijkstra");module.exports=dijkstraAll;function dijkstraAll(g,weightFunc,edgeFunc){return g.nodes().reduce(function(acc,v){acc[v]=dijkstra(g,v,weightFunc,edgeFunc);return acc},{})}},{"./dijkstra":5}],5:[function(require,module,exports){var PriorityQueue=require("../data/priority-queue");module.exports=dijkstra;var DEFAULT_WEIGHT_FUNC=()=>1;function dijkstra(g,source,weightFn,edgeFn){return runDijkstra(g,String(source),weightFn||DEFAULT_WEIGHT_FUNC,edgeFn||function(v){return g.outEdges(v)})}function runDijkstra(g,source,weightFn,edgeFn){var results={};var pq=new PriorityQueue;var v,vEntry;var updateNeighbors=function(edge){var w=edge.v!==v?edge.v:edge.w;var wEntry=results[w];var weight=weightFn(edge);var distance=vEntry.distance+weight;if(weight<0){throw new Error("dijkstra does not allow negative edge weights. "+"Bad edge: "+edge+" Weight: "+weight)}if(distance<wEntry.distance){wEntry.distance=distance;wEntry.predecessor=v;pq.decrease(w,distance)}};g.nodes().forEach(function(v){var distance=v===source?0:Number.POSITIVE_INFINITY;results[v]={distance:distance};pq.add(v,distance)});while(pq.size()>0){v=pq.removeMin();vEntry=results[v];if(vEntry.distance===Number.POSITIVE_INFINITY){break}edgeFn(v).forEach(updateNeighbors)}return results}},{"../data/priority-queue":15}],6:[function(require,module,exports){var tarjan=require("./tarjan");module.exports=findCycles;function findCycles(g){return tarjan(g).filter(function(cmpt){return cmpt.length>1||cmpt.length===1&&g.hasEdge(cmpt[0],cmpt[0])})}},{"./tarjan":13}],7:[function(require,module,exports){module.exports=floydWarshall;var DEFAULT_WEIGHT_FUNC=()=>1;function floydWarshall(g,weightFn,edgeFn){return runFloydWarshall(g,weightFn||DEFAULT_WEIGHT_FUNC,edgeFn||function(v){return g.outEdges(v)})}function runFloydWarshall(g,weightFn,edgeFn){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}},{}],8:[function(require,module,exports){module.exports={components:require("./components"),dijkstra:require("./dijkstra"),dijkstraAll:require("./dijkstra-all"),findCycles:require("./find-cycles"),floydWarshall:require("./floyd-warshall"),isAcyclic:require("./is-acyclic"),postorder:require("./postorder"),preorder:require("./preorder"),prim:require("./prim"),tarjan:require("./tarjan"),topsort:require("./topsort")}},{"./components":2,"./dijkstra":5,"./dijkstra-all":4,"./find-cycles":6,"./floyd-warshall":7,"./is-acyclic":9,"./postorder":10,"./preorder":11,"./prim":12,"./tarjan":13,"./topsort":14}],9:[function(require,module,exports){var topsort=require("./topsort");module.exports=isAcyclic;function isAcyclic(g){try{topsort(g)}catch(e){if(e instanceof topsort.CycleException){return false}throw e}return true}},{"./topsort":14}],10:[function(require,module,exports){var dfs=require("./dfs");module.exports=postorder;function postorder(g,vs){return dfs(g,vs,"post")}},{"./dfs":3}],11:[function(require,module,exports){var dfs=require("./dfs");module.exports=preorder;function preorder(g,vs){return dfs(g,vs,"pre")}},{"./dfs":3}],12:[function(require,module,exports){var Graph=require("../graph");var PriorityQueue=require("../data/priority-queue");module.exports=prim;function prim(g,weightFunc){var result=new Graph;var parents={};var pq=new PriorityQueue;var v;function updateNeighbors(edge){var w=edge.v===v?edge.w:edge.v;var pri=pq.priority(w);if(pri!==undefined){var edgeWeight=weightFunc(edge);if(edgeWeight<pri){parents[w]=v;pq.decrease(w,edgeWeight)}}}if(g.nodeCount()===0){return result}g.nodes().forEach(function(v){pq.add(v,Number.POSITIVE_INFINITY);result.setNode(v)}); | ||
// Start from an arbitrary node | ||
pq.decrease(g.nodes()[0],0);var init=false;while(pq.size()>0){v=pq.removeMin();if(_.has(parents,v)){result.setEdge(v,parents[v])}else if(init){throw new Error("Input graph is not connected: "+g)}else{init=true}g.nodeEdges(v).forEach(updateNeighbors)}return result}},{"../data/priority-queue":15,"../graph":16,"../lodash":19}],13:[function(require,module,exports){var _=require("../lodash");module.exports=tarjan;function tarjan(g){var index=0,stack=[],visited={},// node id -> { onStack, lowlink, index } | ||
results=[];function dfs(v){var entry=visited[v]={onStack:true,lowlink:index,index:index++};stack.push(v);g.successors(v).forEach(function(w){if(!_.has(visited,w)){dfs(w);entry.lowlink=Math.min(entry.lowlink,visited[w].lowlink)}else if(visited[w].onStack){entry.lowlink=Math.min(entry.lowlink,visited[w].index)}});if(entry.lowlink===entry.index){var cmpt=[],w;do{w=stack.pop();visited[w].onStack=false;cmpt.push(w)}while(v!==w);results.push(cmpt)}}g.nodes().forEach(function(v){if(!_.has(visited,v)){dfs(v)}});return results}},{"../lodash":19}],14:[function(require,module,exports){var _=require("../lodash");module.exports=topsort;topsort.CycleException=CycleException;function topsort(g){var visited={},stack={},results=[];function visit(node){if(_.has(stack,node)){throw new CycleException}if(!_.has(visited,node)){stack[node]=true;visited[node]=true;_.each(g.predecessors(node),visit);delete stack[node];results.push(node)}}_.each(g.sinks(),visit);if(_.size(visited)!==g.nodeCount()){throw new CycleException}return results}function CycleException(){}},{"../lodash":19}],15:[function(require,module,exports){var _=require("../lodash");module.exports=PriorityQueue;/** | ||
pq.decrease(g.nodes()[0],0);var init=false;while(pq.size()>0){v=pq.removeMin();if(parents.hasOwnProperty(v)){result.setEdge(v,parents[v])}else if(init){throw new Error("Input graph is not connected: "+g)}else{init=true}g.nodeEdges(v).forEach(updateNeighbors)}return result}},{"../data/priority-queue":15,"../graph":16}],13:[function(require,module,exports){module.exports=tarjan;function tarjan(g){var index=0;var stack=[];var visited={};// node id -> { onStack, lowlink, index } | ||
var results=[];function dfs(v){var entry=visited[v]={onStack:true,lowlink:index,index:index++};stack.push(v);g.successors(v).forEach(function(w){if(!visited.hasOwnProperty(w)){dfs(w);entry.lowlink=Math.min(entry.lowlink,visited[w].lowlink)}else if(visited[w].onStack){entry.lowlink=Math.min(entry.lowlink,visited[w].index)}});if(entry.lowlink===entry.index){var cmpt=[];var w;do{w=stack.pop();visited[w].onStack=false;cmpt.push(w)}while(v!==w);results.push(cmpt)}}g.nodes().forEach(function(v){if(!visited.hasOwnProperty(v)){dfs(v)}});return results}},{}],14:[function(require,module,exports){module.exports=topsort;topsort.CycleException=CycleException;function topsort(g){var visited={};var stack={};var results=[];function visit(node){if(stack.hasOwnProperty(node)){throw new CycleException}if(!visited.hasOwnProperty(node)){stack[node]=true;visited[node]=true;g.predecessors(node).forEach(visit);delete stack[node];results.push(node)}}g.sinks().forEach(visit);if(Object.keys(visited).length!==g.nodeCount()){throw new CycleException}return results}function CycleException(){}CycleException.prototype=new Error;// must be an instance of Error to pass testing | ||
},{}],15:[function(require,module,exports){module.exports=PriorityQueue; | ||
/** | ||
* A min-priority queue data structure. This algorithm is derived from Cormen, | ||
@@ -49,13 +52,13 @@ * et al., "Introduction to Algorithms". The basic idea of a min-priority | ||
* have its priority decreased in O(log n) time. | ||
*/ | ||
function PriorityQueue(){this._arr=[];this._keyIndices={}}/** | ||
*/function PriorityQueue(){this._arr=[];this._keyIndices={}} | ||
/** | ||
* Returns the number of elements in the queue. Takes `O(1)` time. | ||
*/ | ||
PriorityQueue.prototype.size=function(){return this._arr.length};/** | ||
*/PriorityQueue.prototype.size=function(){return this._arr.length}; | ||
/** | ||
* Returns the keys that are in the queue. Takes `O(n)` time. | ||
*/ | ||
PriorityQueue.prototype.keys=function(){return this._arr.map(function(x){return x.key})};/** | ||
*/PriorityQueue.prototype.keys=function(){return this._arr.map(function(x){return x.key})}; | ||
/** | ||
* Returns `true` if **key** is in the queue and `false` if not. | ||
*/ | ||
PriorityQueue.prototype.has=function(key){return _.has(this._keyIndices,key)};/** | ||
*/PriorityQueue.prototype.has=function(key){return this._keyIndices.hasOwnProperty(key)}; | ||
/** | ||
* Returns the priority for **key**. If **key** is not present in the queue | ||
@@ -65,8 +68,8 @@ * then this function returns `undefined`. Takes `O(1)` time. | ||
* @param {Object} key | ||
*/ | ||
PriorityQueue.prototype.priority=function(key){var index=this._keyIndices[key];if(index!==undefined){return this._arr[index].priority}};/** | ||
*/PriorityQueue.prototype.priority=function(key){var index=this._keyIndices[key];if(index!==undefined){return this._arr[index].priority}}; | ||
/** | ||
* Returns the key for the minimum element in this queue. If the queue is | ||
* empty this function throws an Error. Takes `O(1)` time. | ||
*/ | ||
PriorityQueue.prototype.min=function(){if(this.size()===0){throw new Error("Queue underflow")}return this._arr[0].key};/** | ||
*/PriorityQueue.prototype.min=function(){if(this.size()===0){throw new Error("Queue underflow")}return this._arr[0].key}; | ||
/** | ||
* Inserts a new key into the priority queue. If the key already exists in | ||
@@ -78,7 +81,7 @@ * the queue this function returns `false`; otherwise it will return `true`. | ||
* @param {Number} priority the initial priority for the key | ||
*/ | ||
PriorityQueue.prototype.add=function(key,priority){var keyIndices=this._keyIndices;key=String(key);if(!_.has(keyIndices,key)){var arr=this._arr;var index=arr.length;keyIndices[key]=index;arr.push({key:key,priority:priority});this._decrease(index);return true}return false};/** | ||
*/PriorityQueue.prototype.add=function(key,priority){var keyIndices=this._keyIndices;key=String(key);if(!keyIndices.hasOwnProperty(key)){var arr=this._arr;var index=arr.length;keyIndices[key]=index;arr.push({key:key,priority:priority});this._decrease(index);return true}return false}; | ||
/** | ||
* Removes and returns the smallest key in the queue. Takes `O(log n)` time. | ||
*/ | ||
PriorityQueue.prototype.removeMin=function(){this._swap(0,this._arr.length-1);var min=this._arr.pop();delete this._keyIndices[min.key];this._heapify(0);return min.key};/** | ||
*/PriorityQueue.prototype.removeMin=function(){this._swap(0,this._arr.length-1);var min=this._arr.pop();delete this._keyIndices[min.key];this._heapify(0);return min.key}; | ||
/** | ||
* Decreases the priority for **key** to **priority**. If the new priority is | ||
@@ -89,4 +92,3 @@ * greater than the previous priority, this function will throw an Error. | ||
* @param {Number} priority the new priority for the key | ||
*/ | ||
PriorityQueue.prototype.decrease=function(key,priority){var index=this._keyIndices[key];if(priority>this._arr[index].priority){throw new Error("New priority is greater than current priority. "+"Key: "+key+" Old: "+this._arr[index].priority+" New: "+priority)}this._arr[index].priority=priority;this._decrease(index)};PriorityQueue.prototype._heapify=function(i){var arr=this._arr;var l=2*i,r=l+1,largest=i;if(l<arr.length){largest=arr[l].priority<arr[largest].priority?l:largest;if(r<arr.length){largest=arr[r].priority<arr[largest].priority?r:largest}if(largest!==i){this._swap(i,largest);this._heapify(largest)}}};PriorityQueue.prototype._decrease=function(index){var arr=this._arr;var priority=arr[index].priority;var parent;while(index!==0){parent=index>>1;if(arr[parent].priority<priority){break}this._swap(index,parent);index=parent}};PriorityQueue.prototype._swap=function(i,j){var arr=this._arr;var keyIndices=this._keyIndices;var origArrI=arr[i];var origArrJ=arr[j];arr[i]=origArrJ;arr[j]=origArrI;keyIndices[origArrJ.key]=i;keyIndices[origArrI.key]=j}},{"../lodash":19}],16:[function(require,module,exports){"use strict";var _=require("./lodash");module.exports=Graph;var DEFAULT_EDGE_NAME="\0",GRAPH_NODE="\0",EDGE_KEY_DELIM=""; | ||
*/PriorityQueue.prototype.decrease=function(key,priority){var index=this._keyIndices[key];if(priority>this._arr[index].priority){throw new Error("New priority is greater than current priority. "+"Key: "+key+" Old: "+this._arr[index].priority+" New: "+priority)}this._arr[index].priority=priority;this._decrease(index)};PriorityQueue.prototype._heapify=function(i){var arr=this._arr;var l=2*i;var r=l+1;var largest=i;if(l<arr.length){largest=arr[l].priority<arr[largest].priority?l:largest;if(r<arr.length){largest=arr[r].priority<arr[largest].priority?r:largest}if(largest!==i){this._swap(i,largest);this._heapify(largest)}}};PriorityQueue.prototype._decrease=function(index){var arr=this._arr;var priority=arr[index].priority;var parent;while(index!==0){parent=index>>1;if(arr[parent].priority<priority){break}this._swap(index,parent);index=parent}};PriorityQueue.prototype._swap=function(i,j){var arr=this._arr;var keyIndices=this._keyIndices;var origArrI=arr[i];var origArrJ=arr[j];arr[i]=origArrJ;arr[j]=origArrI;keyIndices[origArrJ.key]=i;keyIndices[origArrI.key]=j}},{}],16:[function(require,module,exports){"use strict";module.exports=Graph;var DEFAULT_EDGE_NAME="\0";var GRAPH_NODE="\0";var EDGE_KEY_DELIM=""; | ||
// Implementation notes: | ||
@@ -101,9 +103,9 @@ // | ||
// we're going to get to a performant hashtable in JavaScript. | ||
function Graph(opts){this._isDirected=_.has(opts,"directed")?opts.directed:true;this._isMultigraph=_.has(opts,"multigraph")?opts.multigraph:false;this._isCompound=_.has(opts,"compound")?opts.compound:false; | ||
function Graph(opts){this._isDirected=true;this._isMultigraph=false;this._isCompound=false;if(opts){this._isDirected=opts.hasOwnProperty("directed")?opts.directed:true;this._isMultigraph=opts.hasOwnProperty("multigraph")?opts.multigraph:false;this._isCompound=opts.hasOwnProperty("compound")?opts.compound:false} | ||
// Label for the graph itself | ||
this._label=undefined; | ||
// Defaults to be set when creating a new node | ||
this._defaultNodeLabelFn=_.constant(undefined); | ||
this._defaultNodeLabelFn=()=>undefined; | ||
// Defaults to be set when creating a new edge | ||
this._defaultEdgeLabelFn=_.constant(undefined); | ||
this._defaultEdgeLabelFn=()=>undefined; | ||
// v -> label | ||
@@ -126,14 +128,134 @@ this._nodes={};if(this._isCompound){ | ||
// e -> label | ||
this._edgeLabels={}}/* Number of nodes in the graph. Should only be changed by the implementation. */ | ||
Graph.prototype._nodeCount=0;/* Number of edges in the graph. Should only be changed by the implementation. */ | ||
Graph.prototype._edgeCount=0;/* === Graph functions ========= */ | ||
Graph.prototype.isDirected=function(){return this._isDirected};Graph.prototype.isMultigraph=function(){return this._isMultigraph};Graph.prototype.isCompound=function(){return this._isCompound};Graph.prototype.setGraph=function(label){this._label=label;return this};Graph.prototype.graph=function(){return this._label};/* === Node functions ========== */ | ||
Graph.prototype.setDefaultNodeLabel=function(newDefault){if(!_.isFunction(newDefault)){newDefault=_.constant(newDefault)}this._defaultNodeLabelFn=newDefault;return this};Graph.prototype.nodeCount=function(){return this._nodeCount};Graph.prototype.nodes=function(){return _.keys(this._nodes)};Graph.prototype.sources=function(){return _.filter(this.nodes(),_.bind(function(v){return _.isEmpty(this._in[v])},this))};Graph.prototype.sinks=function(){return _.filter(this.nodes(),_.bind(function(v){return _.isEmpty(this._out[v])},this))};Graph.prototype.setNodes=function(vs,value){var args=arguments;_.each(vs,_.bind(function(v){if(args.length>1){this.setNode(v,value)}else{this.setNode(v)}},this));return this};Graph.prototype.setNode=function(v,value){if(_.has(this._nodes,v)){if(arguments.length>1){this._nodes[v]=value}return this}this._nodes[v]=arguments.length>1?value:this._defaultNodeLabelFn(v);if(this._isCompound){this._parent[v]=GRAPH_NODE;this._children[v]={};this._children[GRAPH_NODE][v]=true}this._in[v]={};this._preds[v]={};this._out[v]={};this._sucs[v]={};++this._nodeCount;return this};Graph.prototype.node=function(v){return this._nodes[v]};Graph.prototype.hasNode=function(v){return _.has(this._nodes,v)};Graph.prototype.removeNode=function(v){var self=this;if(_.has(this._nodes,v)){var removeEdge=function(e){self.removeEdge(self._edgeObjs[e])};delete this._nodes[v];if(this._isCompound){this._removeFromParentsChildList(v);delete this._parent[v];_.each(this.children(v),_.bind(function(child){this.setParent(child)},this));delete this._children[v]}_.each(_.keys(this._in[v]),removeEdge);delete this._in[v];delete this._preds[v];_.each(_.keys(this._out[v]),removeEdge);delete this._out[v];delete this._sucs[v];--this._nodeCount}return this};Graph.prototype.setParent=function(v,parent){if(!this._isCompound){throw new Error("Cannot set parent in a non-compound graph")}if(_.isUndefined(parent)){parent=GRAPH_NODE}else{ | ||
this._edgeLabels={}} | ||
/* Number of nodes in the graph. Should only be changed by the implementation. */Graph.prototype._nodeCount=0; | ||
/* Number of edges in the graph. Should only be changed by the implementation. */Graph.prototype._edgeCount=0; | ||
/* === Graph functions ========= */ | ||
/** | ||
* Whether graph was created with 'directed' flag set to true or not. | ||
*/Graph.prototype.isDirected=function(){return this._isDirected}; | ||
/** | ||
* Whether graph was created with 'multigraph' flag set to true or not. | ||
*/Graph.prototype.isMultigraph=function(){return this._isMultigraph}; | ||
/** | ||
* Whether graph was created with 'compound' flag set to true or not. | ||
*/Graph.prototype.isCompound=function(){return this._isCompound}; | ||
/** | ||
* Sets the label of the graph. | ||
*/Graph.prototype.setGraph=function(label){this._label=label;return this}; | ||
/** | ||
* Gets the graph label. | ||
*/Graph.prototype.graph=function(){return this._label}; | ||
/* === Node functions ========== */ | ||
/** | ||
* Sets the default node label. If newDefault is a function, it will be | ||
* invoked ach time when setting a label for a node. Otherwise, this label | ||
* will be assigned as default label in case if no label was specified while | ||
* setting a node. | ||
* Complexity: O(1). | ||
*/Graph.prototype.setDefaultNodeLabel=function(newDefault){this._defaultNodeLabelFn=newDefault;if(typeof newDefault!=="function"){this._defaultNodeLabelFn=()=>newDefault}return this}; | ||
/** | ||
* Gets the number of nodes in the graph. | ||
* Complexity: O(1). | ||
*/Graph.prototype.nodeCount=function(){return this._nodeCount}; | ||
/** | ||
* Gets all nodes of the graph. Note, the in case of compound graph subnodes are | ||
* not included in list. | ||
* Complexity: O(1). | ||
*/Graph.prototype.nodes=function(){return Object.keys(this._nodes)}; | ||
/** | ||
* Gets list of nodes without in-edges. | ||
* Complexity: O(|V|). | ||
*/Graph.prototype.sources=function(){var self=this;return this.nodes().filter(v=>Object.keys(self._in[v]).length===0)}; | ||
/** | ||
* Gets list of nodes without out-edges. | ||
* Complexity: O(|V|). | ||
*/Graph.prototype.sinks=function(){var self=this;return this.nodes().filter(v=>Object.keys(self._out[v]).length===0)}; | ||
/** | ||
* Invokes setNode method for each node in names list. | ||
* Complexity: O(|names|). | ||
*/Graph.prototype.setNodes=function(vs,value){var args=arguments;var self=this;vs.forEach(function(v){if(args.length>1){self.setNode(v,value)}else{self.setNode(v)}});return this}; | ||
/** | ||
* Creates or updates the value for the node v in the graph. If label is supplied | ||
* it is set as the value for the node. If label is not supplied and the node was | ||
* created by this call then the default node label will be assigned. | ||
* Complexity: O(1). | ||
*/Graph.prototype.setNode=function(v,value){if(this._nodes.hasOwnProperty(v)){if(arguments.length>1){this._nodes[v]=value}return this}this._nodes[v]=arguments.length>1?value:this._defaultNodeLabelFn(v);if(this._isCompound){this._parent[v]=GRAPH_NODE;this._children[v]={};this._children[GRAPH_NODE][v]=true}this._in[v]={};this._preds[v]={};this._out[v]={};this._sucs[v]={};++this._nodeCount;return this}; | ||
/** | ||
* Gets the label of node with specified name. | ||
* Complexity: O(|V|). | ||
*/Graph.prototype.node=function(v){return this._nodes[v]}; | ||
/** | ||
* Detects whether graph has a node with specified name or not. | ||
*/Graph.prototype.hasNode=function(v){return this._nodes.hasOwnProperty(v)}; | ||
/** | ||
* Remove the node with the name from the graph or do nothing if the node is not in | ||
* the graph. If the node was removed this function also removes any incident | ||
* edges. | ||
* Complexity: O(1). | ||
*/Graph.prototype.removeNode=function(v){var self=this;if(this._nodes.hasOwnProperty(v)){var removeEdge=e=>self.removeEdge(self._edgeObjs[e]);delete this._nodes[v];if(this._isCompound){this._removeFromParentsChildList(v);delete this._parent[v];this.children(v).forEach(function(child){self.setParent(child)});delete this._children[v]}Object.keys(this._in[v]).forEach(removeEdge);delete this._in[v];delete this._preds[v];Object.keys(this._out[v]).forEach(removeEdge);delete this._out[v];delete this._sucs[v];--this._nodeCount}return this}; | ||
/** | ||
* Sets node p as a parent for node v if it is defined, or removes the | ||
* parent for v if p is undefined. Method throws an exception in case of | ||
* invoking it in context of noncompound graph. | ||
* Average-case complexity: O(1). | ||
*/Graph.prototype.setParent=function(v,parent){if(!this._isCompound){throw new Error("Cannot set parent in a non-compound graph")}if(parent===undefined){parent=GRAPH_NODE}else{ | ||
// Coerce parent to string | ||
parent+="";for(var ancestor=parent;!_.isUndefined(ancestor);ancestor=this.parent(ancestor)){if(ancestor===v){throw new Error("Setting "+parent+" as parent of "+v+" would create create a cycle")}}this.setNode(parent)}this.setNode(v);this._removeFromParentsChildList(v);this._parent[v]=parent;this._children[parent][v]=true;return this};Graph.prototype._removeFromParentsChildList=function(v){delete this._children[this._parent[v]][v]};Graph.prototype.parent=function(v){if(this._isCompound){var parent=this._parent[v];if(parent!==GRAPH_NODE){return parent}}};Graph.prototype.children=function(v){if(_.isUndefined(v)){v=GRAPH_NODE}if(this._isCompound){var children=this._children[v];if(children){return _.keys(children)}}else if(v===GRAPH_NODE){return this.nodes()}else if(this.hasNode(v)){return[]}};Graph.prototype.predecessors=function(v){var predsV=this._preds[v];if(predsV){return _.keys(predsV)}};Graph.prototype.successors=function(v){var sucsV=this._sucs[v];if(sucsV){return _.keys(sucsV)}};Graph.prototype.neighbors=function(v){var preds=this.predecessors(v);if(preds){return _.union(preds,this.successors(v))}};Graph.prototype.isLeaf=function(v){var neighbors;if(this.isDirected()){neighbors=this.successors(v)}else{neighbors=this.neighbors(v)}return neighbors.length===0};Graph.prototype.filterNodes=function(filter){var copy=new this.constructor({directed:this._isDirected,multigraph:this._isMultigraph,compound:this._isCompound});copy.setGraph(this.graph());_.each(this._nodes,_.bind(function(value,v){if(filter(v)){copy.setNode(v,value)}},this));_.each(this._edgeObjs,_.bind(function(e){if(copy.hasNode(e.v)&©.hasNode(e.w)){copy.setEdge(e,this.edge(e))}},this));var self=this;var parents={};function findParent(v){var parent=self.parent(v);if(parent===undefined||copy.hasNode(parent)){parents[v]=parent;return parent}else if(parent in parents){return parents[parent]}else{return findParent(parent)}}if(this._isCompound){_.each(copy.nodes(),function(v){copy.setParent(v,findParent(v))})}return copy};/* === Edge functions ========== */ | ||
Graph.prototype.setDefaultEdgeLabel=function(newDefault){if(!_.isFunction(newDefault)){newDefault=_.constant(newDefault)}this._defaultEdgeLabelFn=newDefault;return this};Graph.prototype.edgeCount=function(){return this._edgeCount};Graph.prototype.edges=function(){return _.values(this._edgeObjs)};Graph.prototype.setPath=function(vs,value){var self=this,args=arguments;_.reduce(vs,function(v,w){if(args.length>1){self.setEdge(v,w,value)}else{self.setEdge(v,w)}return w});return this};/* | ||
* setEdge(v, w, [value, [name]]) | ||
* setEdge({ v, w, [name] }, [value]) | ||
*/ | ||
Graph.prototype.setEdge=function(){var v,w,name,value,valueSpecified=false,arg0=arguments[0];if(typeof arg0==="object"&&arg0!==null&&"v"in arg0){v=arg0.v;w=arg0.w;name=arg0.name;if(arguments.length===2){value=arguments[1];valueSpecified=true}}else{v=arg0;w=arguments[1];name=arguments[3];if(arguments.length>2){value=arguments[2];valueSpecified=true}}v=""+v;w=""+w;if(!_.isUndefined(name)){name=""+name}var e=edgeArgsToId(this._isDirected,v,w,name);if(_.has(this._edgeLabels,e)){if(valueSpecified){this._edgeLabels[e]=value}return this}if(!_.isUndefined(name)&&!this._isMultigraph){throw new Error("Cannot set a named edge when isMultigraph = false")} | ||
parent+="";for(var ancestor=parent;ancestor!==undefined;ancestor=this.parent(ancestor)){if(ancestor===v){throw new Error("Setting "+parent+" as parent of "+v+" would create a cycle")}}this.setNode(parent)}this.setNode(v);this._removeFromParentsChildList(v);this._parent[v]=parent;this._children[parent][v]=true;return this};Graph.prototype._removeFromParentsChildList=function(v){delete this._children[this._parent[v]][v]}; | ||
/** | ||
* Gets parent node for node v. | ||
* Complexity: O(1). | ||
*/Graph.prototype.parent=function(v){if(this._isCompound){var parent=this._parent[v];if(parent!==GRAPH_NODE){return parent}}}; | ||
/** | ||
* Gets list of direct children of node v. | ||
* Complexity: O(1). | ||
*/Graph.prototype.children=function(v=GRAPH_NODE){if(this._isCompound){var children=this._children[v];if(children){return Object.keys(children)}}else if(v===GRAPH_NODE){return this.nodes()}else if(this.hasNode(v)){return[]}}; | ||
/** | ||
* Return all nodes that are predecessors of the specified node or undefined if node v is not in | ||
* the graph. Behavior is undefined for undirected graphs - use neighbors instead. | ||
* Complexity: O(|V|). | ||
*/Graph.prototype.predecessors=function(v){var predsV=this._preds[v];if(predsV){return Object.keys(predsV)}}; | ||
/** | ||
* Return all nodes that are successors of the specified node or undefined if node v is not in | ||
* the graph. Behavior is undefined for undirected graphs - use neighbors instead. | ||
* Complexity: O(|V|). | ||
*/Graph.prototype.successors=function(v){var sucsV=this._sucs[v];if(sucsV){return Object.keys(sucsV)}}; | ||
/** | ||
* Return all nodes that are predecessors or successors of the specified node or undefined if | ||
* node v is not in the graph. | ||
* Complexity: O(|V|). | ||
*/Graph.prototype.neighbors=function(v){var preds=this.predecessors(v);if(preds){const union=new Set(preds);for(var succ of this.successors(v)){union.add(succ)}return Array.from(union.values())}};Graph.prototype.isLeaf=function(v){var neighbors;if(this.isDirected()){neighbors=this.successors(v)}else{neighbors=this.neighbors(v)}return neighbors.length===0}; | ||
/** | ||
* Creates new graph with nodes filtered via filter. Edges incident to rejected node | ||
* are also removed. In case of compound graph, if parent is rejected by filter, | ||
* than all its children are rejected too. | ||
* Average-case complexity: O(|E|+|V|). | ||
*/Graph.prototype.filterNodes=function(filter){var copy=new this.constructor({directed:this._isDirected,multigraph:this._isMultigraph,compound:this._isCompound});copy.setGraph(this.graph());var self=this;Object.entries(this._nodes).forEach(function([v,value]){if(filter(v)){copy.setNode(v,value)}});Object.values(this._edgeObjs).forEach(function(e){if(copy.hasNode(e.v)&©.hasNode(e.w)){copy.setEdge(e,self.edge(e))}});var parents={};function findParent(v){var parent=self.parent(v);if(parent===undefined||copy.hasNode(parent)){parents[v]=parent;return parent}else if(parent in parents){return parents[parent]}else{return findParent(parent)}}if(this._isCompound){copy.nodes().forEach(v=>copy.setParent(v,findParent(v)))}return copy}; | ||
/* === Edge functions ========== */ | ||
/** | ||
* Sets the default edge label or factory function. This label will be | ||
* assigned as default label in case if no label was specified while setting | ||
* an edge or this function will be invoked each time when setting an edge | ||
* with no label specified and returned value * will be used as a label for edge. | ||
* Complexity: O(1). | ||
*/Graph.prototype.setDefaultEdgeLabel=function(newDefault){this._defaultEdgeLabelFn=newDefault;if(typeof newDefault!=="function"){this._defaultEdgeLabelFn=()=>newDefault}return this}; | ||
/** | ||
* Gets the number of edges in the graph. | ||
* Complexity: O(1). | ||
*/Graph.prototype.edgeCount=function(){return this._edgeCount}; | ||
/** | ||
* Gets edges of the graph. In case of compound graph subgraphs are not considered. | ||
* Complexity: O(|E|). | ||
*/Graph.prototype.edges=function(){return Object.values(this._edgeObjs)}; | ||
/** | ||
* Establish an edges path over the nodes in nodes list. If some edge is already | ||
* exists, it will update its label, otherwise it will create an edge between pair | ||
* of nodes with label provided or default label if no label provided. | ||
* Complexity: O(|nodes|). | ||
*/Graph.prototype.setPath=function(vs,value){var self=this;var args=arguments;vs.reduce(function(v,w){if(args.length>1){self.setEdge(v,w,value)}else{self.setEdge(v,w)}return w});return this}; | ||
/** | ||
* Creates or updates the label for the edge (v, w) with the optionally supplied | ||
* name. If label is supplied it is set as the value for the edge. If label is not | ||
* supplied and the edge was created by this call then the default edge label will | ||
* be assigned. The name parameter is only useful with multigraphs. | ||
*/Graph.prototype.setEdge=function(){var v,w,name,value;var valueSpecified=false;var arg0=arguments[0];if(typeof arg0==="object"&&arg0!==null&&"v"in arg0){v=arg0.v;w=arg0.w;name=arg0.name;if(arguments.length===2){value=arguments[1];valueSpecified=true}}else{v=arg0;w=arguments[1];name=arguments[3];if(arguments.length>2){value=arguments[2];valueSpecified=true}}v=""+v;w=""+w;if(name!==undefined){name=""+name}var e=edgeArgsToId(this._isDirected,v,w,name);if(this._edgeLabels.hasOwnProperty(e)){if(valueSpecified){this._edgeLabels[e]=value}return this}if(name!==undefined&&!this._isMultigraph){throw new Error("Cannot set a named edge when isMultigraph = false")} | ||
// It didn't exist, so we need to create it. | ||
@@ -143,5 +265,45 @@ // First ensure the nodes exist. | ||
// Ensure we add undirected edges in a consistent way. | ||
v=edgeObj.v;w=edgeObj.w;Object.freeze(edgeObj);this._edgeObjs[e]=edgeObj;incrementOrInitEntry(this._preds[w],v);incrementOrInitEntry(this._sucs[v],w);this._in[w][e]=edgeObj;this._out[v][e]=edgeObj;this._edgeCount++;return this};Graph.prototype.edge=function(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name);return this._edgeLabels[e]};Graph.prototype.hasEdge=function(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name);return _.has(this._edgeLabels,e)};Graph.prototype.removeEdge=function(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name),edge=this._edgeObjs[e];if(edge){v=edge.v;w=edge.w;delete this._edgeLabels[e];delete this._edgeObjs[e];decrementOrRemoveEntry(this._preds[w],v);decrementOrRemoveEntry(this._sucs[v],w);delete this._in[w][e];delete this._out[v][e];this._edgeCount--}return this};Graph.prototype.inEdges=function(v,u){var inV=this._in[v];if(inV){var edges=_.values(inV);if(!u){return edges}return _.filter(edges,function(edge){return edge.v===u})}};Graph.prototype.outEdges=function(v,w){var outV=this._out[v];if(outV){var edges=_.values(outV);if(!w){return edges}return _.filter(edges,function(edge){return edge.w===w})}};Graph.prototype.nodeEdges=function(v,w){var inEdges=this.inEdges(v,w);if(inEdges){return inEdges.concat(this.outEdges(v,w))}};function incrementOrInitEntry(map,k){if(map[k]){map[k]++}else{map[k]=1}}function decrementOrRemoveEntry(map,k){if(!--map[k]){delete map[k]}}function edgeArgsToId(isDirected,v_,w_,name){var v=""+v_;var w=""+w_;if(!isDirected&&v>w){var tmp=v;v=w;w=tmp}return v+EDGE_KEY_DELIM+w+EDGE_KEY_DELIM+(_.isUndefined(name)?DEFAULT_EDGE_NAME:name)}function edgeArgsToObj(isDirected,v_,w_,name){var v=""+v_;var w=""+w_;if(!isDirected&&v>w){var tmp=v;v=w;w=tmp}var edgeObj={v:v,w:w};if(name){edgeObj.name=name}return edgeObj}function edgeObjToId(isDirected,edgeObj){return edgeArgsToId(isDirected,edgeObj.v,edgeObj.w,edgeObj.name)}},{"./lodash":19}],17:[function(require,module,exports){ | ||
v=edgeObj.v;w=edgeObj.w;Object.freeze(edgeObj);this._edgeObjs[e]=edgeObj;incrementOrInitEntry(this._preds[w],v);incrementOrInitEntry(this._sucs[v],w);this._in[w][e]=edgeObj;this._out[v][e]=edgeObj;this._edgeCount++;return this}; | ||
/** | ||
* Gets the label for the specified edge. | ||
* Complexity: O(1). | ||
*/Graph.prototype.edge=function(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name);return this._edgeLabels[e]}; | ||
/** | ||
* Detects whether the graph contains specified edge or not. No subgraphs are considered. | ||
* Complexity: O(1). | ||
*/Graph.prototype.hasEdge=function(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name);return this._edgeLabels.hasOwnProperty(e)}; | ||
/** | ||
* Removes the specified edge from the graph. No subgraphs are considered. | ||
* Complexity: O(1). | ||
*/Graph.prototype.removeEdge=function(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name);var edge=this._edgeObjs[e];if(edge){v=edge.v;w=edge.w;delete this._edgeLabels[e];delete this._edgeObjs[e];decrementOrRemoveEntry(this._preds[w],v);decrementOrRemoveEntry(this._sucs[v],w);delete this._in[w][e];delete this._out[v][e];this._edgeCount--}return this}; | ||
/** | ||
* Return all edges that point to the node v. Optionally filters those edges down to just those | ||
* coming from node u. Behavior is undefined for undirected graphs - use nodeEdges instead. | ||
* Complexity: O(|E|). | ||
*/Graph.prototype.inEdges=function(v,u){var inV=this._in[v];if(inV){var edges=Object.values(inV);if(!u){return edges}return edges.filter(edge=>edge.v===u)}}; | ||
/** | ||
* Return all edges that are pointed at by node v. Optionally filters those edges down to just | ||
* those point to w. Behavior is undefined for undirected graphs - use nodeEdges instead. | ||
* Complexity: O(|E|). | ||
*/Graph.prototype.outEdges=function(v,w){var outV=this._out[v];if(outV){var edges=Object.values(outV);if(!w){return edges}return edges.filter(edge=>edge.w===w)}}; | ||
/** | ||
* Returns all edges to or from node v regardless of direction. Optionally filters those edges | ||
* down to just those between nodes v and w regardless of direction. | ||
* Complexity: O(|E|). | ||
*/Graph.prototype.nodeEdges=function(v,w){var inEdges=this.inEdges(v,w);if(inEdges){return inEdges.concat(this.outEdges(v,w))}};function incrementOrInitEntry(map,k){if(map[k]){map[k]++}else{map[k]=1}}function decrementOrRemoveEntry(map,k){if(!--map[k]){delete map[k]}}function edgeArgsToId(isDirected,v_,w_,name){var v=""+v_;var w=""+w_;if(!isDirected&&v>w){var tmp=v;v=w;w=tmp}return v+EDGE_KEY_DELIM+w+EDGE_KEY_DELIM+(name===undefined?DEFAULT_EDGE_NAME:name)}function edgeArgsToObj(isDirected,v_,w_,name){var v=""+v_;var w=""+w_;if(!isDirected&&v>w){var tmp=v;v=w;w=tmp}var edgeObj={v:v,w:w};if(name){edgeObj.name=name}return edgeObj}function edgeObjToId(isDirected,edgeObj){return edgeArgsToId(isDirected,edgeObj.v,edgeObj.w,edgeObj.name)}},{}],17:[function(require,module,exports){ | ||
// Includes only the "core" of graphlib | ||
module.exports={Graph:require("./graph"),version:require("./version")}},{"./graph":16,"./version":20}],18:[function(require,module,exports){var _=require("./lodash"),Graph=require("./graph");module.exports={write:write,read:read};function write(g){var json={options:{directed:g.isDirected(),multigraph:g.isMultigraph(),compound:g.isCompound()},nodes:writeNodes(g),edges:writeEdges(g)};if(!_.isUndefined(g.graph())){json.value=_.clone(g.graph())}return json}function writeNodes(g){return _.map(g.nodes(),function(v){var nodeValue=g.node(v),parent=g.parent(v),node={v:v};if(!_.isUndefined(nodeValue)){node.value=nodeValue}if(!_.isUndefined(parent)){node.parent=parent}return node})}function writeEdges(g){return _.map(g.edges(),function(e){var edgeValue=g.edge(e),edge={v:e.v,w:e.w};if(!_.isUndefined(e.name)){edge.name=e.name}if(!_.isUndefined(edgeValue)){edge.value=edgeValue}return edge})}function read(json){var g=new Graph(json.options).setGraph(json.value);_.each(json.nodes,function(entry){g.setNode(entry.v,entry.value);if(entry.parent){g.setParent(entry.v,entry.parent)}});_.each(json.edges,function(entry){g.setEdge({v:entry.v,w:entry.w,name:entry.name},entry.value)});return g}},{"./graph":16,"./lodash":19}],19:[function(require,module,exports){/* global window */ | ||
var lodash;if(typeof require==="function"){try{lodash=require("lodash")}catch(e){}}if(!lodash){lodash=window._}module.exports=lodash},{lodash:undefined}],20:[function(require,module,exports){module.exports="2.1.4"},{}]},{},[1])(1)}); | ||
module.exports={Graph:require("./graph"),version:require("./version")}},{"./graph":16,"./version":19}],18:[function(require,module,exports){var Graph=require("./graph");module.exports={write:write,read:read}; | ||
/** | ||
* Creates a JSON representation of the graph that can be serialized to a string with | ||
* JSON.stringify. The graph can later be restored using json.read. | ||
*/function write(g){var json={options:{directed:g.isDirected(),multigraph:g.isMultigraph(),compound:g.isCompound()},nodes:writeNodes(g),edges:writeEdges(g)};if(g.graph()!==undefined){json.value=structuredClone(g.graph())}return json}function writeNodes(g){return g.nodes().map(function(v){var nodeValue=g.node(v);var parent=g.parent(v);var node={v:v};if(nodeValue!==undefined){node.value=nodeValue}if(parent!==undefined){node.parent=parent}return node})}function writeEdges(g){return g.edges().map(function(e){var edgeValue=g.edge(e);var edge={v:e.v,w:e.w};if(e.name!==undefined){edge.name=e.name}if(edgeValue!==undefined){edge.value=edgeValue}return edge})} | ||
/** | ||
* Takes JSON as input and returns the graph representation. | ||
* | ||
* @example | ||
* var g2 = graphlib.json.read(JSON.parse(str)); | ||
* g2.nodes(); | ||
* // ['a', 'b'] | ||
* g2.edges() | ||
* // [ { v: 'a', w: 'b' } ] | ||
*/function read(json){var g=new Graph(json.options).setGraph(json.value);json.nodes.forEach(function(entry){g.setNode(entry.v,entry.value);if(entry.parent){g.setParent(entry.v,entry.parent)}});json.edges.forEach(function(entry){g.setEdge({v:entry.v,w:entry.w,name:entry.name},entry.value)});return g}},{"./graph":16}],19:[function(require,module,exports){module.exports="2.1.9"},{}]},{},[1])(1)}); |
@@ -1,19 +0,17 @@ | ||
var _ = require("../lodash"); | ||
module.exports = components; | ||
function components(g) { | ||
var visited = {}, | ||
cmpts = [], | ||
cmpt; | ||
var visited = {}; | ||
var cmpts = []; | ||
var cmpt; | ||
function dfs(v) { | ||
if (_.has(visited, v)) return; | ||
if (visited.hasOwnProperty(v)) return; | ||
visited[v] = true; | ||
cmpt.push(v); | ||
_.each(g.successors(v), dfs); | ||
_.each(g.predecessors(v), dfs); | ||
g.successors(v).forEach(dfs); | ||
g.predecessors(v).forEach(dfs); | ||
} | ||
_.each(g.nodes(), function(v) { | ||
g.nodes().forEach(function(v) { | ||
cmpt = []; | ||
@@ -20,0 +18,0 @@ dfs(v); |
@@ -1,3 +0,1 @@ | ||
var _ = require("../lodash"); | ||
module.exports = dfs; | ||
@@ -14,3 +12,3 @@ | ||
function dfs(g, vs, order) { | ||
if (!_.isArray(vs)) { | ||
if (!Array.isArray(vs)) { | ||
vs = [vs]; | ||
@@ -21,5 +19,5 @@ } | ||
var acc = [], | ||
visited = {}; | ||
_.each(vs, function(v) { | ||
var acc = []; | ||
var visited = {}; | ||
vs.forEach(function(v) { | ||
if (!g.hasNode(v)) { | ||
@@ -35,7 +33,7 @@ throw new Error("Graph does not have node: " + v); | ||
function doDfs(g, v, postorder, visited, navigation, acc) { | ||
if (!_.has(visited, v)) { | ||
if (!visited.hasOwnProperty(v)) { | ||
visited[v] = true; | ||
if (!postorder) { acc.push(v); } | ||
_.each(navigation(v), function(w) { | ||
navigation(v).forEach(function(w) { | ||
doDfs(g, w, postorder, visited, navigation, acc); | ||
@@ -42,0 +40,0 @@ }); |
@@ -1,3 +0,2 @@ | ||
var dijkstra = require("./dijkstra"), | ||
_ = require("../lodash"); | ||
var dijkstra = require("./dijkstra"); | ||
@@ -7,5 +6,6 @@ module.exports = dijkstraAll; | ||
function dijkstraAll(g, weightFunc, edgeFunc) { | ||
return _.transform(g.nodes(), function(acc, v) { | ||
return g.nodes().reduce(function(acc, v) { | ||
acc[v] = dijkstra(g, v, weightFunc, edgeFunc); | ||
return acc; | ||
}, {}); | ||
} |
@@ -1,24 +0,23 @@ | ||
var _ = require("../lodash"), | ||
PriorityQueue = require("../data/priority-queue"); | ||
var PriorityQueue = require("../data/priority-queue"); | ||
module.exports = dijkstra; | ||
var DEFAULT_WEIGHT_FUNC = _.constant(1); | ||
var DEFAULT_WEIGHT_FUNC = () => 1; | ||
function dijkstra(g, source, weightFn, edgeFn) { | ||
return runDijkstra(g, String(source), | ||
weightFn || DEFAULT_WEIGHT_FUNC, | ||
edgeFn || function(v) { return g.outEdges(v); }); | ||
weightFn || DEFAULT_WEIGHT_FUNC, | ||
edgeFn || function(v) { return g.outEdges(v); }); | ||
} | ||
function runDijkstra(g, source, weightFn, edgeFn) { | ||
var results = {}, | ||
pq = new PriorityQueue(), | ||
v, vEntry; | ||
var results = {}; | ||
var pq = new PriorityQueue(); | ||
var v, vEntry; | ||
var updateNeighbors = function(edge) { | ||
var w = edge.v !== v ? edge.v : edge.w, | ||
wEntry = results[w], | ||
weight = weightFn(edge), | ||
distance = vEntry.distance + weight; | ||
var w = edge.v !== v ? edge.v : edge.w; | ||
var wEntry = results[w]; | ||
var weight = weightFn(edge); | ||
var distance = vEntry.distance + weight; | ||
@@ -25,0 +24,0 @@ if (weight < 0) { |
@@ -1,3 +0,2 @@ | ||
var _ = require("../lodash"), | ||
tarjan = require("./tarjan"); | ||
var tarjan = require("./tarjan"); | ||
@@ -7,5 +6,5 @@ module.exports = findCycles; | ||
function findCycles(g) { | ||
return _.filter(tarjan(g), function(cmpt) { | ||
return tarjan(g).filter(function(cmpt) { | ||
return cmpt.length > 1 || (cmpt.length === 1 && g.hasEdge(cmpt[0], cmpt[0])); | ||
}); | ||
} |
@@ -1,16 +0,14 @@ | ||
var _ = require("../lodash"); | ||
module.exports = floydWarshall; | ||
var DEFAULT_WEIGHT_FUNC = _.constant(1); | ||
var DEFAULT_WEIGHT_FUNC = () => 1; | ||
function floydWarshall(g, weightFn, edgeFn) { | ||
return runFloydWarshall(g, | ||
weightFn || DEFAULT_WEIGHT_FUNC, | ||
edgeFn || function(v) { return g.outEdges(v); }); | ||
weightFn || DEFAULT_WEIGHT_FUNC, | ||
edgeFn || function(v) { return g.outEdges(v); }); | ||
} | ||
function runFloydWarshall(g, weightFn, edgeFn) { | ||
var results = {}, | ||
nodes = g.nodes(); | ||
var results = {}; | ||
var nodes = g.nodes(); | ||
@@ -26,4 +24,4 @@ nodes.forEach(function(v) { | ||
edgeFn(v).forEach(function(edge) { | ||
var w = edge.v === v ? edge.w : edge.v, | ||
d = weightFn(edge); | ||
var w = edge.v === v ? edge.w : edge.v; | ||
var d = weightFn(edge); | ||
results[v][w] = { distance: d, predecessor: v }; | ||
@@ -30,0 +28,0 @@ }); |
@@ -1,4 +0,3 @@ | ||
var _ = require("../lodash"), | ||
Graph = require("../graph"), | ||
PriorityQueue = require("../data/priority-queue"); | ||
var Graph = require("../graph"); | ||
var PriorityQueue = require("../data/priority-queue"); | ||
@@ -8,10 +7,10 @@ module.exports = prim; | ||
function prim(g, weightFunc) { | ||
var result = new Graph(), | ||
parents = {}, | ||
pq = new PriorityQueue(), | ||
v; | ||
var result = new Graph(); | ||
var parents = {}; | ||
var pq = new PriorityQueue(); | ||
var v; | ||
function updateNeighbors(edge) { | ||
var w = edge.v === v ? edge.w : edge.v, | ||
pri = pq.priority(w); | ||
var w = edge.v === v ? edge.w : edge.v; | ||
var pri = pq.priority(w); | ||
if (pri !== undefined) { | ||
@@ -30,3 +29,3 @@ var edgeWeight = weightFunc(edge); | ||
_.each(g.nodes(), function(v) { | ||
g.nodes().forEach(function(v) { | ||
pq.add(v, Number.POSITIVE_INFINITY); | ||
@@ -42,3 +41,3 @@ result.setNode(v); | ||
v = pq.removeMin(); | ||
if (_.has(parents, v)) { | ||
if (parents.hasOwnProperty(v)) { | ||
result.setEdge(v, parents[v]); | ||
@@ -45,0 +44,0 @@ } else if (init) { |
@@ -1,10 +0,8 @@ | ||
var _ = require("../lodash"); | ||
module.exports = tarjan; | ||
function tarjan(g) { | ||
var index = 0, | ||
stack = [], | ||
visited = {}, // node id -> { onStack, lowlink, index } | ||
results = []; | ||
var index = 0; | ||
var stack = []; | ||
var visited = {}; // node id -> { onStack, lowlink, index } | ||
var results = []; | ||
@@ -20,3 +18,3 @@ function dfs(v) { | ||
g.successors(v).forEach(function(w) { | ||
if (!_.has(visited, w)) { | ||
if (!visited.hasOwnProperty(w)) { | ||
dfs(w); | ||
@@ -30,4 +28,4 @@ entry.lowlink = Math.min(entry.lowlink, visited[w].lowlink); | ||
if (entry.lowlink === entry.index) { | ||
var cmpt = [], | ||
w; | ||
var cmpt = []; | ||
var w; | ||
do { | ||
@@ -43,3 +41,3 @@ w = stack.pop(); | ||
g.nodes().forEach(function(v) { | ||
if (!_.has(visited, v)) { | ||
if (!visited.hasOwnProperty(v)) { | ||
dfs(v); | ||
@@ -46,0 +44,0 @@ } |
@@ -1,3 +0,1 @@ | ||
var _ = require("../lodash"); | ||
module.exports = topsort; | ||
@@ -7,15 +5,15 @@ topsort.CycleException = CycleException; | ||
function topsort(g) { | ||
var visited = {}, | ||
stack = {}, | ||
results = []; | ||
var visited = {}; | ||
var stack = {}; | ||
var results = []; | ||
function visit(node) { | ||
if (_.has(stack, node)) { | ||
if (stack.hasOwnProperty(node)) { | ||
throw new CycleException(); | ||
} | ||
if (!_.has(visited, node)) { | ||
if (!visited.hasOwnProperty(node)) { | ||
stack[node] = true; | ||
visited[node] = true; | ||
_.each(g.predecessors(node), visit); | ||
g.predecessors(node).forEach(visit); | ||
delete stack[node]; | ||
@@ -26,5 +24,5 @@ results.push(node); | ||
_.each(g.sinks(), visit); | ||
g.sinks().forEach(visit); | ||
if (_.size(visited) !== g.nodeCount()) { | ||
if (Object.keys(visited).length !== g.nodeCount()) { | ||
throw new CycleException(); | ||
@@ -37,1 +35,2 @@ } | ||
function CycleException() {} | ||
CycleException.prototype = new Error(); // must be an instance of Error to pass testing |
@@ -1,3 +0,1 @@ | ||
var _ = require("../lodash"); | ||
module.exports = PriorityQueue; | ||
@@ -35,3 +33,3 @@ | ||
PriorityQueue.prototype.has = function(key) { | ||
return _.has(this._keyIndices, key); | ||
return this._keyIndices.hasOwnProperty(key); | ||
}; | ||
@@ -74,3 +72,3 @@ | ||
key = String(key); | ||
if (!_.has(keyIndices, key)) { | ||
if (!keyIndices.hasOwnProperty(key)) { | ||
var arr = this._arr; | ||
@@ -116,5 +114,5 @@ var index = arr.length; | ||
var arr = this._arr; | ||
var l = 2 * i, | ||
r = l + 1, | ||
largest = i; | ||
var l = 2 * i; | ||
var r = l + 1; | ||
var largest = i; | ||
if (l < arr.length) { | ||
@@ -121,0 +119,0 @@ largest = arr[l].priority < arr[largest].priority ? l : largest; |
319
lib/graph.js
"use strict"; | ||
var _ = require("./lodash"); | ||
module.exports = Graph; | ||
var DEFAULT_EDGE_NAME = "\x00", | ||
GRAPH_NODE = "\x00", | ||
EDGE_KEY_DELIM = "\x01"; | ||
var DEFAULT_EDGE_NAME = "\x00"; | ||
var GRAPH_NODE = "\x00"; | ||
var EDGE_KEY_DELIM = "\x01"; | ||
@@ -22,6 +20,12 @@ // Implementation notes: | ||
function Graph(opts) { | ||
this._isDirected = _.has(opts, "directed") ? opts.directed : true; | ||
this._isMultigraph = _.has(opts, "multigraph") ? opts.multigraph : false; | ||
this._isCompound = _.has(opts, "compound") ? opts.compound : false; | ||
this._isDirected = true; | ||
this._isMultigraph = false; | ||
this._isCompound = false; | ||
if (opts) { | ||
this._isDirected = opts.hasOwnProperty("directed") ? opts.directed : true; | ||
this._isMultigraph = opts.hasOwnProperty("multigraph") ? opts.multigraph : false; | ||
this._isCompound = opts.hasOwnProperty("compound") ? opts.compound : false; | ||
} | ||
// Label for the graph itself | ||
@@ -31,6 +35,6 @@ this._label = undefined; | ||
// Defaults to be set when creating a new node | ||
this._defaultNodeLabelFn = _.constant(undefined); | ||
this._defaultNodeLabelFn = () => undefined; | ||
// Defaults to be set when creating a new edge | ||
this._defaultEdgeLabelFn = _.constant(undefined); | ||
this._defaultEdgeLabelFn = () => undefined; | ||
@@ -77,2 +81,5 @@ // v -> label | ||
/** | ||
* Whether graph was created with 'directed' flag set to true or not. | ||
*/ | ||
Graph.prototype.isDirected = function() { | ||
@@ -82,2 +89,5 @@ return this._isDirected; | ||
/** | ||
* Whether graph was created with 'multigraph' flag set to true or not. | ||
*/ | ||
Graph.prototype.isMultigraph = function() { | ||
@@ -87,2 +97,5 @@ return this._isMultigraph; | ||
/** | ||
* Whether graph was created with 'compound' flag set to true or not. | ||
*/ | ||
Graph.prototype.isCompound = function() { | ||
@@ -92,2 +105,5 @@ return this._isCompound; | ||
/** | ||
* Sets the label of the graph. | ||
*/ | ||
Graph.prototype.setGraph = function(label) { | ||
@@ -98,2 +114,5 @@ this._label = label; | ||
/** | ||
* Gets the graph label. | ||
*/ | ||
Graph.prototype.graph = function() { | ||
@@ -106,10 +125,22 @@ return this._label; | ||
/** | ||
* Sets the default node label. If newDefault is a function, it will be | ||
* invoked ach time when setting a label for a node. Otherwise, this label | ||
* will be assigned as default label in case if no label was specified while | ||
* setting a node. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.setDefaultNodeLabel = function(newDefault) { | ||
if (!_.isFunction(newDefault)) { | ||
newDefault = _.constant(newDefault); | ||
this._defaultNodeLabelFn = newDefault; | ||
if (typeof newDefault !== 'function') { | ||
this._defaultNodeLabelFn = () => newDefault; | ||
} | ||
this._defaultNodeLabelFn = newDefault; | ||
return this; | ||
}; | ||
/** | ||
* Gets the number of nodes in the graph. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.nodeCount = function() { | ||
@@ -119,32 +150,54 @@ return this._nodeCount; | ||
/** | ||
* Gets all nodes of the graph. Note, the in case of compound graph subnodes are | ||
* not included in list. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.nodes = function() { | ||
return _.keys(this._nodes); | ||
return Object.keys(this._nodes); | ||
}; | ||
/** | ||
* Gets list of nodes without in-edges. | ||
* Complexity: O(|V|). | ||
*/ | ||
Graph.prototype.sources = function() { | ||
return _.filter(this.nodes(), _.bind(function(v) { | ||
return _.isEmpty(this._in[v]); | ||
}, this)); | ||
var self = this; | ||
return this.nodes().filter(v => Object.keys(self._in[v]).length === 0); | ||
}; | ||
/** | ||
* Gets list of nodes without out-edges. | ||
* Complexity: O(|V|). | ||
*/ | ||
Graph.prototype.sinks = function() { | ||
return _.filter(this.nodes(), _.bind(function(v) { | ||
return _.isEmpty(this._out[v]); | ||
}, this)); | ||
var self = this; | ||
return this.nodes().filter(v => Object.keys(self._out[v]).length === 0); | ||
}; | ||
/** | ||
* Invokes setNode method for each node in names list. | ||
* Complexity: O(|names|). | ||
*/ | ||
Graph.prototype.setNodes = function(vs, value) { | ||
var args = arguments; | ||
_.each(vs, _.bind(function(v) { | ||
var self = this; | ||
vs.forEach(function(v) { | ||
if (args.length > 1) { | ||
this.setNode(v, value); | ||
self.setNode(v, value); | ||
} else { | ||
this.setNode(v); | ||
self.setNode(v); | ||
} | ||
}, this)); | ||
}); | ||
return this; | ||
}; | ||
/** | ||
* Creates or updates the value for the node v in the graph. If label is supplied | ||
* it is set as the value for the node. If label is not supplied and the node was | ||
* created by this call then the default node label will be assigned. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.setNode = function(v, value) { | ||
if (_.has(this._nodes, v)) { | ||
if (this._nodes.hasOwnProperty(v)) { | ||
if (arguments.length > 1) { | ||
@@ -170,2 +223,6 @@ this._nodes[v] = value; | ||
/** | ||
* Gets the label of node with specified name. | ||
* Complexity: O(|V|). | ||
*/ | ||
Graph.prototype.node = function(v) { | ||
@@ -175,10 +232,19 @@ return this._nodes[v]; | ||
/** | ||
* Detects whether graph has a node with specified name or not. | ||
*/ | ||
Graph.prototype.hasNode = function(v) { | ||
return _.has(this._nodes, v); | ||
return this._nodes.hasOwnProperty(v); | ||
}; | ||
/** | ||
* Remove the node with the name from the graph or do nothing if the node is not in | ||
* the graph. If the node was removed this function also removes any incident | ||
* edges. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.removeNode = function(v) { | ||
var self = this; | ||
if (_.has(this._nodes, v)) { | ||
var removeEdge = function(e) { self.removeEdge(self._edgeObjs[e]); }; | ||
if (this._nodes.hasOwnProperty(v)) { | ||
var removeEdge = e => self.removeEdge(self._edgeObjs[e]); | ||
delete this._nodes[v]; | ||
@@ -188,11 +254,11 @@ if (this._isCompound) { | ||
delete this._parent[v]; | ||
_.each(this.children(v), _.bind(function(child) { | ||
this.setParent(child); | ||
}, this)); | ||
this.children(v).forEach(function(child) { | ||
self.setParent(child); | ||
}); | ||
delete this._children[v]; | ||
} | ||
_.each(_.keys(this._in[v]), removeEdge); | ||
Object.keys(this._in[v]).forEach(removeEdge); | ||
delete this._in[v]; | ||
delete this._preds[v]; | ||
_.each(_.keys(this._out[v]), removeEdge); | ||
Object.keys(this._out[v]).forEach(removeEdge); | ||
delete this._out[v]; | ||
@@ -205,2 +271,8 @@ delete this._sucs[v]; | ||
/** | ||
* Sets node p as a parent for node v if it is defined, or removes the | ||
* parent for v if p is undefined. Method throws an exception in case of | ||
* invoking it in context of noncompound graph. | ||
* Average-case complexity: O(1). | ||
*/ | ||
Graph.prototype.setParent = function(v, parent) { | ||
@@ -211,3 +283,3 @@ if (!this._isCompound) { | ||
if (_.isUndefined(parent)) { | ||
if (parent === undefined) { | ||
parent = GRAPH_NODE; | ||
@@ -218,7 +290,7 @@ } else { | ||
for (var ancestor = parent; | ||
!_.isUndefined(ancestor); | ||
ancestor = this.parent(ancestor)) { | ||
ancestor !== undefined; | ||
ancestor = this.parent(ancestor)) { | ||
if (ancestor === v) { | ||
throw new Error("Setting " + parent+ " as parent of " + v + | ||
" would create create a cycle"); | ||
" would create a cycle"); | ||
} | ||
@@ -241,2 +313,6 @@ } | ||
/** | ||
* Gets parent node for node v. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.parent = function(v) { | ||
@@ -251,11 +327,11 @@ if (this._isCompound) { | ||
Graph.prototype.children = function(v) { | ||
if (_.isUndefined(v)) { | ||
v = GRAPH_NODE; | ||
} | ||
/** | ||
* Gets list of direct children of node v. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.children = function(v = GRAPH_NODE) { | ||
if (this._isCompound) { | ||
var children = this._children[v]; | ||
if (children) { | ||
return _.keys(children); | ||
return Object.keys(children); | ||
} | ||
@@ -269,20 +345,40 @@ } else if (v === GRAPH_NODE) { | ||
/** | ||
* Return all nodes that are predecessors of the specified node or undefined if node v is not in | ||
* the graph. Behavior is undefined for undirected graphs - use neighbors instead. | ||
* Complexity: O(|V|). | ||
*/ | ||
Graph.prototype.predecessors = function(v) { | ||
var predsV = this._preds[v]; | ||
if (predsV) { | ||
return _.keys(predsV); | ||
return Object.keys(predsV); | ||
} | ||
}; | ||
/** | ||
* Return all nodes that are successors of the specified node or undefined if node v is not in | ||
* the graph. Behavior is undefined for undirected graphs - use neighbors instead. | ||
* Complexity: O(|V|). | ||
*/ | ||
Graph.prototype.successors = function(v) { | ||
var sucsV = this._sucs[v]; | ||
if (sucsV) { | ||
return _.keys(sucsV); | ||
return Object.keys(sucsV); | ||
} | ||
}; | ||
/** | ||
* Return all nodes that are predecessors or successors of the specified node or undefined if | ||
* node v is not in the graph. | ||
* Complexity: O(|V|). | ||
*/ | ||
Graph.prototype.neighbors = function(v) { | ||
var preds = this.predecessors(v); | ||
if (preds) { | ||
return _.union(preds, this.successors(v)); | ||
const union = new Set(preds); | ||
for (var succ of this.successors(v)) { | ||
union.add(succ); | ||
} | ||
return Array.from(union.values()); | ||
} | ||
@@ -301,2 +397,8 @@ }; | ||
/** | ||
* Creates new graph with nodes filtered via filter. Edges incident to rejected node | ||
* are also removed. In case of compound graph, if parent is rejected by filter, | ||
* than all its children are rejected too. | ||
* Average-case complexity: O(|E|+|V|). | ||
*/ | ||
Graph.prototype.filterNodes = function(filter) { | ||
@@ -311,15 +413,15 @@ var copy = new this.constructor({ | ||
_.each(this._nodes, _.bind(function(value, v) { | ||
var self = this; | ||
Object.entries(this._nodes).forEach(function([v, value]) { | ||
if (filter(v)) { | ||
copy.setNode(v, value); | ||
} | ||
}, this)); | ||
}); | ||
_.each(this._edgeObjs, _.bind(function(e) { | ||
Object.values(this._edgeObjs).forEach(function(e) { | ||
if (copy.hasNode(e.v) && copy.hasNode(e.w)) { | ||
copy.setEdge(e, this.edge(e)); | ||
copy.setEdge(e, self.edge(e)); | ||
} | ||
}, this)); | ||
}); | ||
var self = this; | ||
var parents = {}; | ||
@@ -339,5 +441,3 @@ function findParent(v) { | ||
if (this._isCompound) { | ||
_.each(copy.nodes(), function(v) { | ||
copy.setParent(v, findParent(v)); | ||
}); | ||
copy.nodes().forEach(v => copy.setParent(v, findParent(v))); | ||
} | ||
@@ -350,10 +450,22 @@ | ||
/** | ||
* Sets the default edge label or factory function. This label will be | ||
* assigned as default label in case if no label was specified while setting | ||
* an edge or this function will be invoked each time when setting an edge | ||
* with no label specified and returned value * will be used as a label for edge. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.setDefaultEdgeLabel = function(newDefault) { | ||
if (!_.isFunction(newDefault)) { | ||
newDefault = _.constant(newDefault); | ||
this._defaultEdgeLabelFn = newDefault; | ||
if (typeof newDefault !== 'function') { | ||
this._defaultEdgeLabelFn = () => newDefault; | ||
} | ||
this._defaultEdgeLabelFn = newDefault; | ||
return this; | ||
}; | ||
/** | ||
* Gets the number of edges in the graph. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.edgeCount = function() { | ||
@@ -363,10 +475,20 @@ return this._edgeCount; | ||
/** | ||
* Gets edges of the graph. In case of compound graph subgraphs are not considered. | ||
* Complexity: O(|E|). | ||
*/ | ||
Graph.prototype.edges = function() { | ||
return _.values(this._edgeObjs); | ||
return Object.values(this._edgeObjs); | ||
}; | ||
/** | ||
* Establish an edges path over the nodes in nodes list. If some edge is already | ||
* exists, it will update its label, otherwise it will create an edge between pair | ||
* of nodes with label provided or default label if no label provided. | ||
* Complexity: O(|nodes|). | ||
*/ | ||
Graph.prototype.setPath = function(vs, value) { | ||
var self = this, | ||
args = arguments; | ||
_.reduce(vs, function(v, w) { | ||
var self = this; | ||
var args = arguments; | ||
vs.reduce(function(v, w) { | ||
if (args.length > 1) { | ||
@@ -382,10 +504,12 @@ self.setEdge(v, w, value); | ||
/* | ||
* setEdge(v, w, [value, [name]]) | ||
* setEdge({ v, w, [name] }, [value]) | ||
/** | ||
* Creates or updates the label for the edge (v, w) with the optionally supplied | ||
* name. If label is supplied it is set as the value for the edge. If label is not | ||
* supplied and the edge was created by this call then the default edge label will | ||
* be assigned. The name parameter is only useful with multigraphs. | ||
*/ | ||
Graph.prototype.setEdge = function() { | ||
var v, w, name, value, | ||
valueSpecified = false, | ||
arg0 = arguments[0]; | ||
var v, w, name, value; | ||
var valueSpecified = false; | ||
var arg0 = arguments[0]; | ||
@@ -412,3 +536,3 @@ if (typeof arg0 === "object" && arg0 !== null && "v" in arg0) { | ||
w = "" + w; | ||
if (!_.isUndefined(name)) { | ||
if (name !== undefined) { | ||
name = "" + name; | ||
@@ -418,3 +542,3 @@ } | ||
var e = edgeArgsToId(this._isDirected, v, w, name); | ||
if (_.has(this._edgeLabels, e)) { | ||
if (this._edgeLabels.hasOwnProperty(e)) { | ||
if (valueSpecified) { | ||
@@ -426,3 +550,3 @@ this._edgeLabels[e] = value; | ||
if (!_.isUndefined(name) && !this._isMultigraph) { | ||
if (name !== undefined && !this._isMultigraph) { | ||
throw new Error("Cannot set a named edge when isMultigraph = false"); | ||
@@ -453,21 +577,33 @@ } | ||
/** | ||
* Gets the label for the specified edge. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.edge = function(v, w, name) { | ||
var e = (arguments.length === 1 | ||
? edgeObjToId(this._isDirected, arguments[0]) | ||
: edgeArgsToId(this._isDirected, v, w, name)); | ||
? edgeObjToId(this._isDirected, arguments[0]) | ||
: edgeArgsToId(this._isDirected, v, w, name)); | ||
return this._edgeLabels[e]; | ||
}; | ||
/** | ||
* Detects whether the graph contains specified edge or not. No subgraphs are considered. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.hasEdge = function(v, w, name) { | ||
var e = (arguments.length === 1 | ||
? edgeObjToId(this._isDirected, arguments[0]) | ||
: edgeArgsToId(this._isDirected, v, w, name)); | ||
return _.has(this._edgeLabels, e); | ||
? edgeObjToId(this._isDirected, arguments[0]) | ||
: edgeArgsToId(this._isDirected, v, w, name)); | ||
return this._edgeLabels.hasOwnProperty(e); | ||
}; | ||
/** | ||
* Removes the specified edge from the graph. No subgraphs are considered. | ||
* Complexity: O(1). | ||
*/ | ||
Graph.prototype.removeEdge = function(v, w, name) { | ||
var e = (arguments.length === 1 | ||
? edgeObjToId(this._isDirected, arguments[0]) | ||
: edgeArgsToId(this._isDirected, v, w, name)), | ||
edge = this._edgeObjs[e]; | ||
? edgeObjToId(this._isDirected, arguments[0]) | ||
: edgeArgsToId(this._isDirected, v, w, name)); | ||
var edge = this._edgeObjs[e]; | ||
if (edge) { | ||
@@ -487,24 +623,39 @@ v = edge.v; | ||
/** | ||
* Return all edges that point to the node v. Optionally filters those edges down to just those | ||
* coming from node u. Behavior is undefined for undirected graphs - use nodeEdges instead. | ||
* Complexity: O(|E|). | ||
*/ | ||
Graph.prototype.inEdges = function(v, u) { | ||
var inV = this._in[v]; | ||
if (inV) { | ||
var edges = _.values(inV); | ||
var edges = Object.values(inV); | ||
if (!u) { | ||
return edges; | ||
} | ||
return _.filter(edges, function(edge) { return edge.v === u; }); | ||
return edges.filter(edge => edge.v === u); | ||
} | ||
}; | ||
/** | ||
* Return all edges that are pointed at by node v. Optionally filters those edges down to just | ||
* those point to w. Behavior is undefined for undirected graphs - use nodeEdges instead. | ||
* Complexity: O(|E|). | ||
*/ | ||
Graph.prototype.outEdges = function(v, w) { | ||
var outV = this._out[v]; | ||
if (outV) { | ||
var edges = _.values(outV); | ||
var edges = Object.values(outV); | ||
if (!w) { | ||
return edges; | ||
} | ||
return _.filter(edges, function(edge) { return edge.w === w; }); | ||
return edges.filter(edge => edge.w === w); | ||
} | ||
}; | ||
/** | ||
* Returns all edges to or from node v regardless of direction. Optionally filters those edges | ||
* down to just those between nodes v and w regardless of direction. | ||
* Complexity: O(|E|). | ||
*/ | ||
Graph.prototype.nodeEdges = function(v, w) { | ||
@@ -538,3 +689,3 @@ var inEdges = this.inEdges(v, w); | ||
return v + EDGE_KEY_DELIM + w + EDGE_KEY_DELIM + | ||
(_.isUndefined(name) ? DEFAULT_EDGE_NAME : name); | ||
(name === undefined ? DEFAULT_EDGE_NAME : name); | ||
} | ||
@@ -541,0 +692,0 @@ |
@@ -1,3 +0,2 @@ | ||
var _ = require("./lodash"), | ||
Graph = require("./graph"); | ||
var Graph = require("./graph"); | ||
@@ -9,2 +8,6 @@ module.exports = { | ||
/** | ||
* Creates a JSON representation of the graph that can be serialized to a string with | ||
* JSON.stringify. The graph can later be restored using json.read. | ||
*/ | ||
function write(g) { | ||
@@ -20,4 +23,5 @@ var json = { | ||
}; | ||
if (!_.isUndefined(g.graph())) { | ||
json.value = _.clone(g.graph()); | ||
if (g.graph() !== undefined) { | ||
json.value = structuredClone(g.graph()); | ||
} | ||
@@ -28,10 +32,10 @@ return json; | ||
function writeNodes(g) { | ||
return _.map(g.nodes(), function(v) { | ||
var nodeValue = g.node(v), | ||
parent = g.parent(v), | ||
node = { v: v }; | ||
if (!_.isUndefined(nodeValue)) { | ||
return g.nodes().map(function(v) { | ||
var nodeValue = g.node(v); | ||
var parent = g.parent(v); | ||
var node = { v: v }; | ||
if (nodeValue !== undefined) { | ||
node.value = nodeValue; | ||
} | ||
if (!_.isUndefined(parent)) { | ||
if (parent !== undefined) { | ||
node.parent = parent; | ||
@@ -44,9 +48,9 @@ } | ||
function writeEdges(g) { | ||
return _.map(g.edges(), function(e) { | ||
var edgeValue = g.edge(e), | ||
edge = { v: e.v, w: e.w }; | ||
if (!_.isUndefined(e.name)) { | ||
return g.edges().map(function(e) { | ||
var edgeValue = g.edge(e); | ||
var edge = { v: e.v, w: e.w }; | ||
if (e.name !== undefined) { | ||
edge.name = e.name; | ||
} | ||
if (!_.isUndefined(edgeValue)) { | ||
if (edgeValue !== undefined) { | ||
edge.value = edgeValue; | ||
@@ -58,5 +62,15 @@ } | ||
/** | ||
* Takes JSON as input and returns the graph representation. | ||
* | ||
* @example | ||
* var g2 = graphlib.json.read(JSON.parse(str)); | ||
* g2.nodes(); | ||
* // ['a', 'b'] | ||
* g2.edges() | ||
* // [ { v: 'a', w: 'b' } ] | ||
*/ | ||
function read(json) { | ||
var g = new Graph(json.options).setGraph(json.value); | ||
_.each(json.nodes, function(entry) { | ||
json.nodes.forEach(function(entry) { | ||
g.setNode(entry.v, entry.value); | ||
@@ -67,3 +81,3 @@ if (entry.parent) { | ||
}); | ||
_.each(json.edges, function(entry) { | ||
json.edges.forEach(function(entry) { | ||
g.setEdge({ v: entry.v, w: entry.w, name: entry.name }, entry.value); | ||
@@ -70,0 +84,0 @@ }); |
@@ -1,1 +0,1 @@ | ||
module.exports = '2.1.4'; | ||
module.exports = '2.1.9'; |
{ | ||
"name": "@dagrejs/graphlib", | ||
"version": "2.1.4", | ||
"version": "2.1.10", | ||
"description": "A directed and undirected multi-graph library", | ||
"author": "Chris Pettitt <cpettitt@gmail.com>", | ||
"license": "MIT", | ||
"main": "index.js", | ||
"scripts": { | ||
"lint": "make lint", | ||
"test": "make test" | ||
}, | ||
"files": [ | ||
"index.js", | ||
"dist/", | ||
"lib/" | ||
], | ||
"engines": { | ||
"node": ">17.0.0" | ||
}, | ||
"keywords": [ | ||
@@ -11,27 +24,23 @@ "graph", | ||
], | ||
"dependencies": { | ||
"lodash": "^4.11.1" | ||
}, | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"benchmark": "^1.0.0", | ||
"browserify": "^13.0.0", | ||
"chai": "^1.9.2", | ||
"istanbul": "^0.3.2", | ||
"jscs": "^1.7.3", | ||
"jshint": "^2.5.6", | ||
"jshint-stylish": "^1.0.0", | ||
"karma": "^0.13.22", | ||
"karma-chrome-launcher": "^0.2.0", | ||
"karma-firefox-launcher": "^0.1.6", | ||
"karma-mocha": "^0.2.0", | ||
"karma-phantomjs-launcher": "^1.0.0", | ||
"karma-requirejs": "^0.2.5", | ||
"karma-safari-launcher": "^0.1.1", | ||
"mocha": "^1.21.5", | ||
"phantomjs-prebuilt": "^2.1.7", | ||
"requirejs": "^2.1.22", | ||
"seedrandom": "^2.4.2", | ||
"semver": "^4.1.0", | ||
"sprintf": "^0.1.4", | ||
"uglify-js": "^2.4.15" | ||
"benchmark": "2.1.4", | ||
"browserify": "16.5.1", | ||
"chai": "^4.3.6", | ||
"eslint": "8.35.0", | ||
"istanbul": "^0.4.5", | ||
"jshint": "2.13.5", | ||
"jshint-stylish": "2.2.1", | ||
"karma": "6.4.1", | ||
"karma-chrome-launcher": "3.1.0", | ||
"karma-firefox-launcher": "1.3.0", | ||
"karma-mocha": "2.0.1", | ||
"karma-requirejs": "1.1.0", | ||
"karma-safari-launcher": "1.0.0", | ||
"mocha": "10.1.0", | ||
"requirejs": "2.3.6", | ||
"seedrandom": "3.0.5", | ||
"semver": "7.3.2", | ||
"sprintf": "0.1.5", | ||
"uglify-js": "3.17.4" | ||
}, | ||
@@ -41,4 +50,3 @@ "repository": { | ||
"url": "https://github.com/dagrejs/graphlib.git" | ||
}, | ||
"license": "MIT" | ||
} | ||
} |
@@ -6,3 +6,4 @@ # Graphlib | ||
[![Build Status](https://secure.travis-ci.org/dagrejs/graphlib.png)](http://travis-ci.org/dagrejs/graphlib) | ||
[![Build Status](https://github.com/dagrejs/graphlib/workflows/Build%20Status/badge.svg?branch=master)](https://github.com/dagrejs/graphlib/actions?query=workflow%3A%22Build+Status%22) | ||
[![npm](https://img.shields.io/npm/v/graphlib.svg)](https://www.npmjs.com/package/graphlib) | ||
@@ -9,0 +10,0 @@ To learn more [see our Wiki](https://github.com/cpettitt/graphlib/wiki). |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses eval() which is a dangerous function. This prevents the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
0
19
18
2
165271
26
4184
- Removedlodash@^4.11.1
- Removedlodash@4.17.21(transitive)