jsnetworkx
Version:
A graph processing and visualization library for JavaScript (port of NetworkX for Python).
1,687 lines (1,483 loc) • 59.7 kB
JavaScript
'use strict';
var _get = require('babel-runtime/helpers/get')['default'];
var _inherits = require('babel-runtime/helpers/inherits')['default'];
var _createClass = require('babel-runtime/helpers/create-class')['default'];
var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default'];
var _slicedToArray = require('babel-runtime/helpers/sliced-to-array')['default'];
var _Object$assign = require('babel-runtime/core-js/object/assign')['default'];
var _Array$from = require('babel-runtime/core-js/array/from')['default'];
var _regeneratorRuntime = require('babel-runtime/regenerator')['default'];
var _getIterator = require('babel-runtime/core-js/get-iterator')['default'];
var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];
var _interopRequireWildcard = require('babel-runtime/helpers/interop-require-wildcard')['default'];
Object.defineProperty(exports, '__esModule', {
value: true
});
var _Graph2 = require('./Graph');
var _Graph3 = _interopRequireDefault(_Graph2);
var _internalsMap = require('../_internals/Map');
var _internalsMap2 = _interopRequireDefault(_internalsMap);
var _exceptionsJSNetworkXError = require('../exceptions/JSNetworkXError');
var _exceptionsJSNetworkXError2 = _interopRequireDefault(_exceptionsJSNetworkXError);
var _convert = require('../convert');
var convert = _interopRequireWildcard(_convert);
var _internals = require('../_internals');
/**
* Base class for directed graphs.
*
* A DiGraph stores nodes and edges with optional data, or attributes.
*
* DiGraphs hold directed edges. Self loops are allowed but multiple
* (parallel) edges are not.
*
* Nodes can be strings, numbers or any object with a custom `toString` method.
*
* Edges are represented as links between nodes with optional
* key/value attributes.
*
* ### Examples
*
* Create an empty graph (a "null graph") with no nodes and no edges.
*
* ```
* var G = new jsnx.DiGraph();
* ```
*
* G can be grown in several ways.
*
* #### Nodes
*
* Add one node at a time:
*
* ```
* G.addNode(1);
* ```
*
* Add the nodes from any iterable:
*
* ```
* G.addNodesFrom([2, 3]);
* G.addNodesFrom(new Set('foo', 'bar'));
* var H = jsnx.completeGraph(10);
* G.addNodesFrom(H);
* ```
*
* In addition to strings, numbers and arrays, any object that implements a
* custom `toString` method can be used as node.
*
* #### Edges
*
* `G` can also be grown by adding edges.
*
* Add one edge,
*
* ```
* G.addEdge(1, 2);
* ```
*
* a list of edges,
*
* ```
* G.addEdgesFrom([[1,2], [1,3]]);
* ```
*
* or a collection of edges,
*
* ```
* G.addEdgesFrom(H.edges);
* ```
*
* If some edges connect nodes not yet in the graph, the nodes are added
* automatically. There are no errors when adding nodes or edges that already
* exist.
*
* #### Attributes
*
* Each graph, node and edge can hold key/value attribute pairs in an associated
* attribute object (keys must be strings or numbers).
* By default these are empty, but can added or changed using `addEdge`,
* `addNode`.
*
* ```
* var G = new jsnx.DiGraph(null, {day: 'Friday'});
* G.graph
* // {day: 'Friday'}
* ```
*
* Add node attributes using `addNode()` or `addNodesFrom()`:
*
* ```
* G.addNode(1, {time: '5pm'});
* G.addNodesFrom([2, [3, {time: '3pm'}]], {time: '2pm'});
* G.nodes(true);
* // [[1, {time: '5pm'}], [2, {time: '2pm'}], [3, {time: '3pm'}]]
* ```
*
* Add edge attributes using `addEdge()`, or `addEdgesFrom()`:
*
* ```
* G.addEdge(1, w, {weight: 4.7});
* G.addEdgesFrom([[3,4], [4,5]], {color: 'red'});
* ```
*
* @see Graph
* @see MultiGraph
* @see MultiDiGraph
*/
var DiGraph = (function (_Graph) {
_inherits(DiGraph, _Graph);
/**
* @param {Iterable} optData
* Data to initialize graph. If data=None (default) an empty
* graph is created. The data can be an edge list, or any
* JSNetworkX graph object.
*
* @param {Object=} optAttr
* Attributes to add to graph as key=value pairs.
*/
function DiGraph(optData, optAttr) {
_classCallCheck(this, DiGraph);
_get(Object.getPrototypeOf(DiGraph.prototype), 'constructor', this).call(this);
this.graph = {}; // dictionary for graph attributes
this.node = new _internalsMap2['default'](); // dictionary for node attributes
// We store two adjacency lists:
// the predecessors of node n are stored in the dict self.pred
// the successors of node n are stored in the dict self.succ=self.adj
this.adj = new _internalsMap2['default'](); // empty adjacency dictionary
this.pred = new _internalsMap2['default'](); // predecessor
this.succ = this.adj; // successor
//attempt to load graph with data
if (optData != null) {
convert.toNetworkxGraph(optData, this);
}
// load graph attributes (must be afte convert)
_Object$assign(this.graph, optAttr || {});
this.edge = this.adj;
}
_createClass(DiGraph, [{
key: 'addNode',
/**
* Add a single node n and update node attributes.
*
* ### Examples
*
* ```
* var G = new jsnx.Graph() // or DiGraph, MultiGraph, MultiDiGraph, etc
* G.addNode(1);
* G.addNode('Hello');
* G.numberOfNodes();
* 2
* ```
*
* @see #addNodesFrom
*
* @param {Node} n Node
* @param {Object=} opt_attr_dict Dictionary of node attributes.
* Key/value pairs will update existing data associated with the node.
*/
value: function addNode(n) {
var optAttrDict = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
if (!(0, _internals.isPlainObject)(optAttrDict)) {
throw new _exceptionsJSNetworkXError2['default']('The opt_attr_dict argument must be an object.');
}
if (!this.succ.has(n)) {
this.succ.set(n, new _internalsMap2['default']());
this.pred.set(n, new _internalsMap2['default']());
this.node.set(n, optAttrDict);
} else {
// update attr even if node already exists
_Object$assign(this.node.get(n), optAttrDict);
}
}
}, {
key: 'addNodesFrom',
/**
* Add multiple nodes.
*
* ### Examples
*
* ```
* var G = new jsnx.Graph(); // or DiGraph, MultiGraph, MultiDiGraph
* G.addNodesFrom([1,2,3]);
* G.nodes();
* // [1,2,3]
* ```
*
* Use the second argument to update specific node attributes for every node.
*
* ```
* G.addNodesFrom([1,2], {size: 10});
* G.addNodesFrom([2,3], {weight: 0.4});
* ```
*
* Use `(node, object)` tuples to update attributes for specific nodes.
*
* ```
* G.addNodesFrom([[1, {size: 11}], [2, {color: 'blue'}]]);
* G.node.get(1).size
* // 11
* var H = new jsnx.Graph();
* H.addNodesFrom(G.nodes(true));
* H.node.get(1).size
* // 11
* ```
*
* @see #addNode
*
* @param {Iterable} nodes
* An iterable of nodes
* OR
* An iterable of (node, object) tuples.
*
* @param {Object=} optAttr Update attributes for all nodes in nodes.
* Node attributes specified in nodes as a tuple
* take precedence over attributes specified generally.
*/
value: function addNodesFrom(nodes) {
var optAttr = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
// if an object, only iterate over the keys
(0, _internals.forEach)(nodes, function (n) {
var newnode = !this.succ.has(n);
// test whether n is a (node, attr) tuple
if (Array.isArray(n) && n.length === 2 && (0, _internals.isPlainObject)(n[1])) {
var nn = n[0];
var ndict = n[1];
if (!this.succ.has(nn)) {
this.succ.set(nn, new _internalsMap2['default']());
this.pred.set(nn, new _internalsMap2['default']());
var newdict = (0, _internals.clone)(optAttr);
_Object$assign(newdict, ndict);
this.node.set(nn, newdict);
} else {
var olddict = this.node.get(nn);
_Object$assign(olddict, optAttr, ndict);
}
} else if (newnode) {
this.succ.set(n, new _internalsMap2['default']());
this.pred.set(n, new _internalsMap2['default']());
this.node.set(n, (0, _internals.clone)(optAttr));
} else {
_Object$assign(this.node.get(n), optAttr);
}
}, this);
}
}, {
key: 'removeNode',
/**
* Remove node n.
*
* Removes the node n and all adjacent edges.
* Attempting to remove a non-existent node will raise an exception.
*
* ### Example
*
* ```
* var G = new jsnx.Graph() // or DiGraph, MultiGraph, MultiDiGraph, etc
* G.addPath([0,1,2]);
* G.edges();
* // [[0,1], [1,2]]
* G.removeNode(1);
* G.edges();
* // []
* ```
*
* @see #removeNodesFrom
*
* @param {Node} n A node in the graph
*/
value: function removeNode(n) {
if (this.node['delete'](n)) {
var nbrs = this.succ.get(n);
nbrs.forEach(function (_, u) {
this.pred.get(u)['delete'](n); // remove all edges n-u in digraph
}, this);
this.succ['delete'](n); // remove node from succ
this.pred.get(n).forEach(function (_, u) {
this.succ.get(u)['delete'](n); // remove all edges n-u in digraph
}, this);
this.pred['delete'](n); // remove node from pred
} else {
throw new _exceptionsJSNetworkXError2['default']((0, _internals.sprintf)('The node "%j" is not in the graph', n));
}
}
}, {
key: 'removeNodesFrom',
/**
* Remove multiple nodes.
*
* ### Examples
*
* ```
* var G = new jsnx.Graph() // or DiGraph, MultiGraph, MultiDiGraph, etc
* G.addPath([0,1,2]);
* var e = G.nodes(); // [0,1,2]
* G.removeNodesFrom(e);
* G.nodes();
* // []
* ```
*
* @see #removeNode
*
* @param {Iterable} nodes A container of nodes.
* If a node in the container is not in the graph it is silently ignored.
*/
value: function removeNodesFrom(nodes) {
(0, _internals.forEach)(nodes, function (n) {
if (this.succ.has(n)) {
var succs = this.succ.get(n);
this.node['delete'](n);
succs.forEach(function (_, u) {
// remove all edges n-u in digraph
this.pred.get(u)['delete'](n);
}, this);
this.succ['delete'](n); // remove node from succ
this.pred.get(n).forEach(function (_, u) {
// remove all edges n-u in digraph
this.succ.get(u)['delete'](n);
}, this);
this.pred['delete'](n); // remove node from pred
}
}, this);
}
}, {
key: 'addEdge',
/**
* Add an edge between u and v.
*
* The nodes u and v will be automatically added if they are
* not already in the graph.
*
* Edge attributes can be specified with keywords or by providing
* a object with key/value pairs as third argument.
*
*
* ### Examples
*
* The following all add the edge `(1,2)` to graph `G`:
*
* ```
* var G = new jsnx.Graph() // or DiGraph, MultiGraph, MultiDiGraph, etc
* G.addEdge(1,2);
* G.addEdgesFrom([[1,2]]);
* ```
*
* Associate data to edges using an object:
*
* ```
* G.addEdge(1, 2, {weight: 3});
* G.addEdge(1, 3, {weight: 7, capacity: 15, length: 342.7});
* ```
*
* ### Notes
*
* Adding an edge that already exists updates the edge data.
*
* Many algorithms designed for weighted graphs use as the edge weight a
* numerical value assigned to an attribute which by default is 'weight'.
*
* @see #addEdgesFrom
*
* @param {Node} u Node
* @param {Node} v Node
* @param {Object=} optAttrDict Object of edge attributes.
* Key/value pairs will update existing data associated with the edge.
*/
value: function addEdge(u, v) {
var optAttrDict = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
if (!(0, _internals.isPlainObject)(optAttrDict)) {
throw new _exceptionsJSNetworkXError2['default']('The optAttrDict argument must be a plain object.');
}
// add nodes
if (!this.succ.has(u)) {
this.succ.set(u, new _internalsMap2['default']());
this.pred.set(u, new _internalsMap2['default']());
this.node.set(u, {});
}
if (!this.succ.has(v)) {
this.succ.set(v, new _internalsMap2['default']());
this.pred.set(v, new _internalsMap2['default']());
this.node.set(v, {});
}
// add the edge
var datadict = this.adj.get(u).get(v) || {};
_Object$assign(datadict, optAttrDict);
this.succ.get(u).set(v, datadict);
this.pred.get(v).set(u, datadict);
}
}, {
key: 'addEdgesFrom',
/**
* Add all the edges in `ebunch`.
*
* ### Examples
*
* ```
* var G = new jsnx.Graph() // or DiGraph, MultiGraph, MultiDiGraph, etc
* G.addEdgesFrom([[0,1], [1,2]]); // using a list of edges
* ```
*
* Associate data to edges
*
* ```
* G.addEdgesFrom([[1,2], [2,3]], {weight: 3});
* G.addEdgesFrom([[3,4], [1,4]], {label: 'WN2898'});
* ```
*
* ### Notes
*
* Adding the same edge twice has no effect but any edge data
* will be updated when each duplicate edge is added.
*
* @see #add_edge
* @see #addWeightedEdgesFrom
*
* @param {Iterable} ebunch container of edges
* Each edge given in the container will be added to the
* graph. The edges must be given as as 2-tuples (u,v) or
* 3-tuples (u,v,d) where d is a dictionary containing edge data.
*
* @param {Object=} optAttrDict Object of edge attributes.
* Dictionary of edge attributes. Key/value pairs will
* update existing data associated with each edge.
*/
value: function addEdgesFrom(ebunch) {
var optAttrDict = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
if (!(0, _internals.isPlainObject)(optAttrDict)) {
throw new _exceptionsJSNetworkXError2['default']('The opt_attr_dict argument must be an object.');
}
// process ebunch
(0, _internals.forEach)(ebunch, function (edge) {
var length = (0, _internals.size)(edge);
var u, v, edgeData;
if (length === 3) {
u = edge[0];
v = edge[1];
edgeData = edge[2];
} else if (length === 2) {
u = edge[0];
v = edge[1];
edgeData = {};
} else {
throw new _exceptionsJSNetworkXError2['default']((0, _internals.sprintf)('Edge tuple "%j" must be a 2-tuple or 3-tuple.', edge));
}
if (!this.succ.has(u)) {
this.succ.set(u, new _internalsMap2['default']());
this.pred.set(u, new _internalsMap2['default']());
this.node.set(u, {});
}
if (!this.succ.has(v)) {
this.succ.set(v, new _internalsMap2['default']());
this.pred.set(v, new _internalsMap2['default']());
this.node.set(v, {});
}
var datadict = this.adj.get(u).get(v) || {};
_Object$assign(datadict, optAttrDict, edgeData);
this.succ.get(u).set(v, datadict);
this.pred.get(v).set(u, datadict);
}, this);
}
}, {
key: 'removeEdge',
/**
* Remove the edge between u and v.
*
* ### Examples
*
* ```
* var G = new jsnx.Graph() // or DiGraph, MultiGraph, MultiDiGraph, etc
* G.addPath([0,1,2,3]);
* G.removeEdge(0,1);
* ```
*
* @see #removeEdgesFrom
*
* @param {Node} u Node
* @param {Node} v Node
*/
value: function removeEdge(u, v) {
var edge = this.succ.get(u);
if (edge !== undefined && edge['delete'](v)) {
this.pred.get(v)['delete'](u);
} else {
throw new _exceptionsJSNetworkXError2['default']((0, _internals.sprintf)('The edge "%j-%j" is not in the graph', u, v));
}
}
}, {
key: 'removeEdgesFrom',
/**
* Remove all edges specified in `ebunch`.
*
* ### Examples
*
* ```
* var G = new jsnx.Graph() // or DiGraph, MultiGraph, MultiDiGraph, etc
* G.addPath([0,1,2,3]);
* var ebunch = [[1,2], [2,3]];
* G.removeEdgesFrom(ebunch);
* ```
*
* ### Notes
*
* Will fail silently if an edge in `ebunch` is not in the graph.
*
* @param {Iterable} ebunch Iterable of edge tuples
* Each edge given in the list or container will be removed
* from the graph. The edges can be:
* - 2-tuples (u,v) edge between u and v.
* - 3-tuples (u,v,k) where k is ignored.
*/
value: function removeEdgesFrom(ebunch) {
(0, _internals.forEach)(ebunch, function (edge) {
var u = edge[0]; // ignore edge data if present
var v = edge[1];
try {
this.succ.get(u)['delete'](v);
this.pred.get(v)['delete'](u);
} catch (ex) {}
}, this);
}
}, {
key: 'hasSuccessor',
/**
* Return True if node u has successor v.
*
* This is true if graph has the edge u->v.
*
* @param {Node} u Node
* @param {Node} v Node
* @return {boolean} True if node u has successor v
*/
value: function hasSuccessor(u, v) {
return this.succ.has(u) && this.succ.get(u).has(v);
}
}, {
key: 'hasPredecessor',
/**
* Return True if node u has predecessor v.
*
* This is true if graph has the edge u<-v.
*
* @param {Node} u Node
* @param {Node} v Node
* @return {boolean} True if node u has predecessor v
*/
value: function hasPredecessor(u, v) {
return this.pred.has(u) && this.pred.get(u).has(v);
}
}, {
key: 'successorsIter',
/**
* Return an iterator over successor nodes of n.
*
* `neighborsIter()` and `successorsIter()` are the same.
*
* @param {Node} n Node
* @return {!Iterator} Iterator over successor nodes of n
*/
value: function successorsIter(n) {
var nbrs = this.succ.get(n);
if (nbrs !== undefined) {
return nbrs.keys();
}
throw new _exceptionsJSNetworkXError2['default']((0, _internals.sprintf)('The node "%j" is not in the digraph.', n));
}
}, {
key: 'predecessorsIter',
/**
* Return an iterator over predecessor nodes of n.
*
* @param {Node} n Node
* @return {!Iterator} Iterator over predecessor nodes of n
*/
value: function predecessorsIter(n) {
var nbrs = this.pred.get(n);
if (nbrs !== undefined) {
return nbrs.keys();
}
throw new _exceptionsJSNetworkXError2['default']((0, _internals.sprintf)('The node "%j" is not in the digraph.', n));
}
}, {
key: 'successors',
/**
* Return a list of successor nodes of n.
*
* `neighbors()` and `successors()` are the same.
*
* @param {Node} n Node
* @return {!Array} List of successor nodes of n
*/
value: function successors(n) {
return _Array$from(this.successorsIter(n));
}
}, {
key: 'predecessors',
/**
* Return list of predecessor nodes of n.
*
* @param {Node} n Node
* @return {!Array} List of predecessor nodes of n
*/
value: function predecessors(n) {
return _Array$from(this.predecessorsIter(n));
}
}, {
key: 'neighbors',
// digraph definitions
/**
* @alias successors
*/
value: function neighbors(n) {
return this.successors(n);
}
}, {
key: 'neighborsIter',
/**
* @alias successorsIter
*/
value: function neighborsIter(n) {
return this.successorsIter(n);
}
}, {
key: 'edgesIter',
/**
* Return an iterator over the edges.
*
* Edges are returned as tuples with optional data in the order
* `(node, neighbor, data)`.
*
* ### Examples
*
* ```
* var G = new jsnx.DiGraph() // or MultiDiGraph, etc
* G.addPath([0,1,2]);;
* G.addEdge(2, 3, {weight: 5});
* Array.from(G.edgesIter());
* // [[0,1], [1,2], [2,3]]
* Array.from(G.edgeIter(true)); // default data is {}
* // [[0,1,{}], [1,2,{}], [2,3,{weight: 5}]]
* Array.from(G.edgesIter([0,2]));
* // [[0,1], [2,3]]
* Array.from(G.edgesIter(0));
* // [[0,1]]
* ```
*
*
* ### Notes
*
* Nodes in `nbunch` that are not in the graph will be (quietly) ignored.
*
* @see #edges
*
* @param {?boolean=} optNbunch A container of nodes.
* The container will be iterated through once.
* @param {?boolean=} optData
* If True, return edge attribute dict in 3-tuple (u,v,data).
* @return {!Iterator} An iterator of (u,v) or (u,v,d) tuples of edges.
*/
value: _regeneratorRuntime.mark(function edgesIter(optNbunch) {
var optData = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
var nodesNbrs, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, nodeNbrs, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, nbrData, result;
return _regeneratorRuntime.wrap(function edgesIter$(context$2$0) {
// istanbul ignore next
var _this = this;
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
// handle calls with opt_data being the only argument
if ((0, _internals.isBoolean)(optNbunch)) {
optData = optNbunch;
optNbunch = undefined;
}
if (optNbunch === undefined) {
nodesNbrs = this.adj;
} else {
nodesNbrs = (0, _internals.mapIterator)(this.nbunchIter(optNbunch), function (n) {
return (0, _internals.tuple2)(n, _this.adj.get(n));
});
}
_iteratorNormalCompletion = true;
_didIteratorError = false;
_iteratorError = undefined;
context$2$0.prev = 5;
_iterator = _getIterator(nodesNbrs);
case 7:
if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
context$2$0.next = 40;
break;
}
nodeNbrs = _step.value;
_iteratorNormalCompletion2 = true;
_didIteratorError2 = false;
_iteratorError2 = undefined;
context$2$0.prev = 12;
_iterator2 = _getIterator(nodeNbrs[1]);
case 14:
if (_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done) {
context$2$0.next = 23;
break;
}
nbrData = _step2.value;
result = [nodeNbrs[0], nbrData[0]];
if (optData) {
result[2] = nbrData[1];
}
context$2$0.next = 20;
return result;
case 20:
_iteratorNormalCompletion2 = true;
context$2$0.next = 14;
break;
case 23:
context$2$0.next = 29;
break;
case 25:
context$2$0.prev = 25;
context$2$0.t0 = context$2$0['catch'](12);
_didIteratorError2 = true;
_iteratorError2 = context$2$0.t0;
case 29:
context$2$0.prev = 29;
context$2$0.prev = 30;
if (!_iteratorNormalCompletion2 && _iterator2['return']) {
_iterator2['return']();
}
case 32:
context$2$0.prev = 32;
if (!_didIteratorError2) {
context$2$0.next = 35;
break;
}
throw _iteratorError2;
case 35:
return context$2$0.finish(32);
case 36:
return context$2$0.finish(29);
case 37:
_iteratorNormalCompletion = true;
context$2$0.next = 7;
break;
case 40:
context$2$0.next = 46;
break;
case 42:
context$2$0.prev = 42;
context$2$0.t1 = context$2$0['catch'](5);
_didIteratorError = true;
_iteratorError = context$2$0.t1;
case 46:
context$2$0.prev = 46;
context$2$0.prev = 47;
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
case 49:
context$2$0.prev = 49;
if (!_didIteratorError) {
context$2$0.next = 52;
break;
}
throw _iteratorError;
case 52:
return context$2$0.finish(49);
case 53:
return context$2$0.finish(46);
case 54:
case 'end':
return context$2$0.stop();
}
}, edgesIter, this, [[5, 42, 46, 54], [12, 25, 29, 37], [30,, 32, 36], [47,, 49, 53]]);
})
}, {
key: 'outEdgesIter',
// alias out_edges to edges
/**
* @alias edgesIter
*/
value: function outEdgesIter(optNbunch, optData) {
return this.edgesIter(optNbunch, optData);
}
}, {
key: 'outEdges',
/**
* @alias edges
*/
value: function outEdges(optNbunch, optData) {
return this.edges(optNbunch, optData);
}
}, {
key: 'inEdgesIter',
/**
* Return an iterator over the incoming edges.
*
* @see edgesIter
*
* @param {?boolean=} optNbunch A container of nodes.
* The container will be iterated through once.
* @param {?boolean=} optData
* If True, return edge attribute dict in 3-tuple (u,v,data).
* @return {!Iterator} An iterator of (u,v) or (u,v,d) tuples of
* incoming edges.
*/
value: _regeneratorRuntime.mark(function inEdgesIter(optNbunch) {
var optData = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
var nodesNbrs, _iteratorNormalCompletion3, _didIteratorError3, _iteratorError3, _iterator3, _step3, nodeNbrs, _iteratorNormalCompletion4, _didIteratorError4, _iteratorError4, _iterator4, _step4, nbrData, result;
return _regeneratorRuntime.wrap(function inEdgesIter$(context$2$0) {
// istanbul ignore next
var _this2 = this;
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
// handle calls with opt_data being the only argument
if ((0, _internals.isBoolean)(optNbunch)) {
optData = optNbunch;
optNbunch = undefined;
}
if (optNbunch === undefined) {
nodesNbrs = this.pred;
} else {
nodesNbrs = (0, _internals.mapIterator)(this.nbunchIter(optNbunch), function (n) {
return (0, _internals.tuple2)(n, _this2.pred.get(n));
});
}
_iteratorNormalCompletion3 = true;
_didIteratorError3 = false;
_iteratorError3 = undefined;
context$2$0.prev = 5;
_iterator3 = _getIterator(nodesNbrs);
case 7:
if (_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done) {
context$2$0.next = 40;
break;
}
nodeNbrs = _step3.value;
_iteratorNormalCompletion4 = true;
_didIteratorError4 = false;
_iteratorError4 = undefined;
context$2$0.prev = 12;
_iterator4 = _getIterator(nodeNbrs[1]);
case 14:
if (_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done) {
context$2$0.next = 23;
break;
}
nbrData = _step4.value;
result = [nbrData[0], nodeNbrs[0]];
if (optData) {
result[2] = nbrData[1];
}
context$2$0.next = 20;
return result;
case 20:
_iteratorNormalCompletion4 = true;
context$2$0.next = 14;
break;
case 23:
context$2$0.next = 29;
break;
case 25:
context$2$0.prev = 25;
context$2$0.t0 = context$2$0['catch'](12);
_didIteratorError4 = true;
_iteratorError4 = context$2$0.t0;
case 29:
context$2$0.prev = 29;
context$2$0.prev = 30;
if (!_iteratorNormalCompletion4 && _iterator4['return']) {
_iterator4['return']();
}
case 32:
context$2$0.prev = 32;
if (!_didIteratorError4) {
context$2$0.next = 35;
break;
}
throw _iteratorError4;
case 35:
return context$2$0.finish(32);
case 36:
return context$2$0.finish(29);
case 37:
_iteratorNormalCompletion3 = true;
context$2$0.next = 7;
break;
case 40:
context$2$0.next = 46;
break;
case 42:
context$2$0.prev = 42;
context$2$0.t1 = context$2$0['catch'](5);
_didIteratorError3 = true;
_iteratorError3 = context$2$0.t1;
case 46:
context$2$0.prev = 46;
context$2$0.prev = 47;
if (!_iteratorNormalCompletion3 && _iterator3['return']) {
_iterator3['return']();
}
case 49:
context$2$0.prev = 49;
if (!_didIteratorError3) {
context$2$0.next = 52;
break;
}
throw _iteratorError3;
case 52:
return context$2$0.finish(49);
case 53:
return context$2$0.finish(46);
case 54:
case 'end':
return context$2$0.stop();
}
}, inEdgesIter, this, [[5, 42, 46, 54], [12, 25, 29, 37], [30,, 32, 36], [47,, 49, 53]]);
})
}, {
key: 'inEdges',
/**
* Return a list of the incoming edges.
*
* @see #edges
*
* @param {?Iterable=} optNbunch A container of nodes.
* The container will be iterated through once.
* @param {?boolean=} opt_data
* If True, return edge attribute dict in 3-tuple (u,v,data).
* @return {!Array} A list of incoming edges
*/
value: function inEdges(optNbunch) {
var optData = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
return _Array$from(this.inEdgesIter(optNbunch, optData));
}
}, {
key: 'degreeIter',
/**
* Return an iterator for (node, degree).
*
* The node degree is the number of edges adjacent to the node.
*
* ### Examples
*
* ```
* var G = new jsnx.DiGraph() // or MultiDiGraph, etc
* G.addPath([0,1,2,3]);
* Array.from(G.degreeIter(0));
* // [[0, 1]]
* Array.from(G.degreeIter([0,1]));
* // [[0, 1], [1, 2]]
* ```
*
* @see #degree
* @see #inDegree
* @see #outDegree
* @see #inDegreeIter
* @see #outDegreeIter
*
* @param {(Node|Iterable)=} optNbunch A container of nodes.
* The container will be iterated through once.
* @param {string=} optWeight
* The edge attribute that holds the numerical value used
* as a weight. If None, then each edge has weight 1.
* The degree is the sum of the edge weights adjacent to the node.
* @return {!Iterator} The iterator returns two-tuples of (node, degree).
*/
value: function degreeIter(optNbunch, optWeight) {
// istanbul ignore next
var _this3 = this;
var nodesNbrs;
if (optNbunch == null) {
nodesNbrs = (0, _internals.zipIterator)(this.succ.entries(), this.pred.entries());
} else {
var tuple2Succ = (0, _internals.createTupleFactory)(2);
var tuple2Pred = (0, _internals.createTupleFactory)(2);
nodesNbrs = (0, _internals.zipIterator)((0, _internals.mapIterator)(this.nbunchIter(optNbunch), function (n) {
return tuple2Succ(n, _this3.succ.get(n));
}), (0, _internals.mapIterator)(this.nbunchIter(optNbunch), function (n) {
return tuple2Pred(n, _this3.pred.get(n));
}));
}
if (optWeight == null) {
/*eslint no-unused-vars:0*/
return (0, _internals.mapIterator)(nodesNbrs, function (_ref) {
var _ref2 = _slicedToArray(_ref, 2);
var _ref2$0 = _slicedToArray(_ref2[0], 2);
var node = _ref2$0[0];
var succ = _ref2$0[1];
var _ref2$1 = _slicedToArray(_ref2[1], 2);
var u = _ref2$1[0];
var pred = _ref2$1[1];
return [node, pred.size + succ.size];
});
} else {
// edge weighted graph - degree is sum of edge weights
return (0, _internals.mapIterator)(nodesNbrs, function (_ref3) {
var _ref32 = _slicedToArray(_ref3, 2);
var _ref32$0 = _slicedToArray(_ref32[0], 2);
var node = _ref32$0[0];
var succ = _ref32$0[1];
var _ref32$1 = _slicedToArray(_ref32[1], 2);
var _ = _ref32$1[0];
var pred = _ref32$1[1];
var sum = 0;
function sumData(data) {
var weight = data[optWeight];
sum += weight != null ? +weight : 1;
}
succ.forEach(sumData);
pred.forEach(sumData);
return [node, sum];
});
}
}
}, {
key: 'inDegreeIter',
/**
* Return an iterator for (node, in-degree).
*
* The node in-degree is the number of edges pointing in to the node.
*
* ### Examples
*
* ```
* var G = new jsnx.DiGraph();
* G.addPath([0,1,2,3]);
* Array.from(G.inDegreeIter(0));
* // [[0, 0]]
* Array.from(G.inDegreeIter([0,1]));
* // [[0, 0], [1, ]]
* ```
*
* @see #degree
* @see #inDegree
* @see #outDegree
* @see #outDegreeIter
*
* @param {(Node|Iterable)=} optNbunch A container of nodes.
* The container will be iterated through once.
*
* @param {string=} optWeight
* The edge attribute that holds the numerical value used
* as a weight. If null or undefined, then each edge has weight 1.
* The degree is the sum of the edge weights adjacent to the node.
* @return {Iterator} The iterator returns two-tuples of (node, in-degree).
*/
value: function inDegreeIter(optNbunch, optWeight) {
// istanbul ignore next
var _this4 = this;
var nodesNbrs;
if (optNbunch == null) {
nodesNbrs = this.pred;
} else {
nodesNbrs = (0, _internals.mapIterator)(this.nbunchIter(optNbunch), function (n) {
return (0, _internals.tuple2)(n, _this4.pred.get(n));
});
}
if (optWeight == null) {
return (0, _internals.mapIterator)(nodesNbrs, function (_ref4) {
var _ref42 = _slicedToArray(_ref4, 2);
var node = _ref42[0];
var pred = _ref42[1];
return [node, pred.size];
});
} else {
return (0, _internals.mapIterator)(nodesNbrs, function (_ref5) {
var _ref52 = _slicedToArray(_ref5, 2);
var node = _ref52[0];
var pred = _ref52[1];
var sum = 0;
pred.forEach(function (data) {
var weight = data[optWeight];
sum += weight != null ? +weight : 1;
});
return [node, sum];
});
}
}
}, {
key: 'outDegreeIter',
/**
* Return an iterator for (node, out-degree).
*
* The node out-degree is the number of edges pointing in to the node.
*
* ### Examples
*
* ```
* var G = new jsnx.DiGraph();
* G.addPath([0,1,2,3]);
* Array.from(G.outDegreeIter(0));
* // [[0, 1]]
* Array.from(G.outDegreeIter([0,1]));
* // [[0, 1], [1, ]]
*
*
* @see #degree
* @see #inDegree
* @see #outDegree
* @see #inDegreeIter
*
* @param {(Node|Iterable)=} opt_nbunch A container of nodes.
* The container will be iterated through once.
* @param {string=} optWeight
* The edge attribute that holds the numerical value used
* as a weight. If None, then each edge has weight 1.
* The degree is the sum of the edge weights adjacent to the node.
* @return {Iterator} The iterator returns two-tuples of (node, out-degree).
*/
value: function outDegreeIter(optNbunch, optWeight) {
// istanbul ignore next
var _this5 = this;
var nodesNbrs;
if (optNbunch == null) {
nodesNbrs = this.succ;
} else {
nodesNbrs = (0, _internals.mapIterator)(this.nbunchIter(optNbunch), function (n) {
return (0, _internals.tuple2)(n, _this5.succ.get(n));
});
}
if (optWeight == null) {
return (0, _internals.mapIterator)(nodesNbrs, function (_ref6) {
var _ref62 = _slicedToArray(_ref6, 2);
var node = _ref62[0];
var succ = _ref62[1];
return [node, succ.size];
});
} else {
return (0, _internals.mapIterator)(nodesNbrs, function (_ref7) {
var _ref72 = _slicedToArray(_ref7, 2);
var node = _ref72[0];
var succ = _ref72[1];
var sum = 0;
succ.forEach(function (data) {
var weight = data[optWeight];
sum += weight != null ? +weight : 1;
});
return [node, sum];
});
}
}
}, {
key: 'inDegree',
/**
* Return the in-degree of a node or nodes.
*
* The node in-degree is the number of edges pointing in to the node.
*
* ### Examples
*
* ```
* var G = new jsnx.DiGraph(); // or MultiDiGraph
* G.addPath([0,1,2,3]);
* G.inDegree(0);
* // 0
* G.inDegree([0,1]);
* // Map {0: 0, 1: 1}
* Array.from(G.inDegree([0,1]).values());
* // [0, 1]
* ```
*
* @see #degree
* @see #outDegree
* @see #inDegreeIter
*
*
* @param {(Node|Iterable)=} optNbunch A container of nodes.
* The container will be iterated through once.
* @param {string=} opt_weight
* The edge attribute that holds the numerical value used
* as a weight. If None, then each edge has weight 1.
* The degree is the sum of the edge weights adjacent to the node.
* @return {(number|Map)}
* A dictionary with nodes as keys and in-degree as values or
* a number if a single node is specified.
*/
value: function inDegree(optNbunch, optWeight) {
if (optNbunch != null && this.hasNode(optNbunch)) {
// return a single node
return (0, _internals.next)(this.inDegreeIter(optNbunch, optWeight))[1];
} else {
return new _internalsMap2['default'](this.inDegreeIter(optNbunch, optWeight));
}
}
}, {
key: 'outDegree',
/**
* Return the out-degree of a node or nodes.
*
* The node out-degree is the number of edges pointing out of the node.
*
* ### Examples
*
* ```
* var G = new jsnx.DiGraph(); // or MultiDiGraph
* G.addPath([0,1,2,3]);
* G.outDegree(0);
* // 1
* G.outDegree([0,1]);
* // Map {0: 1, 1: 1}
* Array.from(G.inDegree([0,1]).values());
* // [1, 1]
* ```
*
* @see #degree
* @see #out_degree
* @see #in_degree_iter
*
* @param {(Node|Iterable)=} optNbunch A container of nodes.
* The container will be iterated through once.
* @param {string=} optWeight
* The edge attribute that holds the numerical value used
* as a weight. If None, then each edge has weight 1.
* The degree is the sum of the edge weights adjacent to the node.
* @return {(number|Map)}
* A dictionary with nodes as keys and in-degree as values or
* a number if a single node is specified.
*/
value: function outDegree(optNbunch, optWeight) {
if (optNbunch != null && this.hasNode(optNbunch)) {
// return a single node
return (0, _internals.next)(this.outDegreeIter(optNbunch, optWeight))[1];
} else {
return new _internalsMap2['default'](this.outDegreeIter(optNbunch, optWeight));
}
}
}, {
key: 'clear',
/**
* Remove all nodes and edges from the graph.
*
* This also removes the name, and all graph, node, and edge attributes.
*
* ### Examples
*
* ```
* var G = new jsnx.Graph() // or DiGraph, MultiGraph, MultiDiGraph, etc
* G.addPath([0,1,2,3]);
* G.clear();
* G.nodes();
* // []
* G.edges();
* // []
* ```
*/
value: function clear() {
this.succ.clear();
this.pred.clear();
this.node.clear();
(0, _internals.clear)(this.graph);
}
}, {
key: 'isMultigraph',
/**
* Return True if graph is a multigraph, False otherwise.
*
* @return {boolean} True if graph is a multigraph, False otherwise.
*/
value: function isMultigraph() {
return false;
}
}, {
key: 'isDirected',
/**
* Return True if graph is directed, False otherwise.
*
* @return {boolean} True if graph is directed, False otherwise.
*/
value: function isDirected() {
return true;
}
}, {
key: 'toDirected',
/**
* Return a directed copy of the graph.
*
* ### Examples
*
* ```
* var G = new jsnx.Graph(); // or MultiGraph, etc
* G.addPath([0,1]);
* var H = G.toDirected();
* H.edges();
* // [[0,1], [1,0]]
* ```
*
* If already directed, return a (deep) copy
*
* ```
* var G = new jsnx.DiGraph(); // or MultiDiGraph, etc
* G.addPath([0,1]);
* var H = G.toDirected();
* H.edges();
* // [[0,1]]
* ```
*
* ### Notes
*
* This returns a "deepcopy" of the edge, node, and
* graph attributes which attempts to completely copy
* all of the data and references.
*
* This is in contrast to the similar `var H = new jsnx.DiGraph(G)` which
* returns a shallow copy of the data.
*
* @return {!DiGraph} A deepcopy of the graph
*/
value: function toDirected() {
return (0, _internals.deepcopy)(this);
}
}, {
key: 'toUndirected',
/**
* Return an undirected representation of the digraph.
*
* ### Notes
*
* If edges in both directions (u,v) and (v,u) exist in the
* graph, attributes for the new undirected edge will be a combination of
* the attributes of the directed edges. The edge data is updated
* in the (arbitrary) order that the edges are encountered. For
* more customized control of the edge attributes use `addEdge()`.
*
* This returns a "deepcopy" of the edge, node, and graph attributes which
* attempts to completely copy all of the data and references.
*
* This is in contrast to the similar `var H = new jsnx.Graph(G)`
* which returns a shallow copy of the data.
*
* @param {boolean=} optReciprocal
* If True only keep edges that appear in both directions
* in the original digraph.
* @return {!Graph}
* An undirected graph with the same name and nodes and
* with edge (u,v,data) if either (u,v,data) or (v,u,data)
* is in the digraph. If both edges exist in digraph and
* their edge data is different, only one edge is created
* with an arbitrary choice of which edge data to use.
* You must check and correct for this manually if desired.
*/
value: function toUndirected(optReciprocal) {
var H = new _Graph3['default']();
H.name = this.name;
H.addNodesFrom(this);
var thisPred = this.pred;
if (optReciprocal) {
H.addEdgesFrom(_regeneratorRuntime.mark(function callee$2$0() {
var _iteratorNormalCompletion5, _didIteratorError5, _iteratorError5, _iterator5, _step5, nodeData, node, predecessors, _iteratorNormalCompletion6, _didIteratorError6, _iteratorError6, _iterator6, _step6, nbrData;
return _regeneratorRuntime.wrap(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
_iteratorNormalCompletion5 = true;
_didIteratorError5 = false;
_iteratorError5 = undefined;
context$3$0.prev = 3;
_iterator5 = _getIterator(this.adjacencyIter());
case 5:
if (_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done) {
context$3$0.next = 39;
break;
}
nodeData = _step5.value;
node = nodeData[0];
predecessors = thisPred.get(node);
_iteratorNormalCompletion6 = true;
_didIteratorError6 = false;
_iteratorError6 = undefined;
context$3$0.prev = 12;
_iterator6 = _getIterator(nodeData[1]);
case 14:
if (_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done) {
context$3$0.next = 22;
break;
}
nbrData = _step6.value;
if (!predecessors.has(nbrData[0])) {
context$3$0.next = 19;
break;
}
context$3$0.next = 19;
return (0, _internals.tuple3)(node, nbrData[0], (0, _internals.deepcopy)(nbrData[1]));
case 19:
_iteratorNormalCompletion6 = true;
context$3$0.next = 14;
break;
case 22:
context$3$0.next = 28;
break;
case 24:
context$3$0.prev = 24;
context$3$0.t0 = context$3$0['catch'](12);
_didIteratorError6 = true;
_iteratorError6 = context$3$0.t0;
case 28:
context$3$0.prev = 28;
context$3$0.prev = 29;
if (!_iteratorNormalCompletion6 && _iterator6['return']) {
_iterator6['return']();
}
case 31:
context$3$0.prev = 31;
if (!_didIteratorError6) {
context$3$0.next = 34;
break;
}
throw _iteratorError6;
case 34:
return context$3$0.finish(31);
case 35:
return context$3$0.finish(28);
case 36:
_iteratorNormalCompletion5 = true;
context$3$0.next = 5;
break;
case 39:
context$3$0.next = 45;
break;
case 41:
context$3$0.prev = 41;
context$3$0.t1 = context$3$0['catch'](3);
_didIteratorError5 = true;
_iteratorError5 = context$3$0.t1;
case 45:
context$3$0.prev = 45;
context$3$0.prev = 46;
if (!_iteratorNormalCompletion5 && _iterator5['return']) {
_iterator5['return']();
}
case 48:
context$3$0.prev = 48;
if (!_didIteratorError5) {
context$3$0.next = 51;
break;
}
throw _iteratorError5;
case 51:
return context$3$0.finish(48);
case 52:
return context$3$0.finish(45);
case 53:
case 'end':
return context$3$0.stop();
}
}, callee$2$0, this, [[3, 41, 45, 53], [12, 24, 28, 36], [29,, 31, 35], [46,, 48, 52]]);
}).call(this));
} else {
H.addEdgesFrom(_regeneratorRuntime.mark(function callee$2$0() {
var _iteratorNormalCompletion7, _didIteratorError7, _iteratorError7, _iterator7, _step7, nodeData, _iteratorNormalCompletion8, _didIteratorError8, _iteratorError8, _iterator8, _step8, nbrData;
return _regeneratorRuntime.wrap(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
_iteratorNormalCompletion7 = true;
_didIteratorError7 = false;
_iteratorError7 = undefined;
context$3$0.prev = 3;
_iterator7 = _getIterator(this.adjacencyIter());
case 5:
if (_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done) {
context$3$0.next = 36;
break;
}
nodeData = _step7.value;
_iteratorNormalCompletion8 = true;
_didIteratorError8 = false;
_iteratorError8 = undefined;
context$3$0.prev = 10;
_iterator8 = _getIterator(nodeData[1]);
case 12:
if (_iterator