/** * Gets all nodes of the graph. Note, the in case of compound graph subnodes are * not included in list. * Complexity: O(1). */nodes(){return Object.keys(this._nodes)} /** * Gets list of nodes without in-edges. * Complexity: O(|V|). */sources(){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|). */sinks(){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|). */setNodes(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). */setNode(v,value){if(Object.hasOwn(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} /** * Gets the label of node with specified name. * Complexity: O(|V|). */node(v){return this._nodes[v]} /** * Detects whether graph has a node with specified name or not. */hasNode(v){return Object.hasOwn(this._nodes,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). */removeNode(v){var self=this;if(Object.hasOwn(this._nodes,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). */setParent(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;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}_removeFromParentsChildList(v){delete this._children[this._parent[v]][v]} /** * Gets parent node for node v. * Complexity: O(1). */parent(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). */children(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|). */predecessors(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|). */successors(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|). */neighbors(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())}}isLeaf(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|). */filterNodes(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). */setDefaultEdgeLabel(newDefault){this._defaultEdgeLabelFn=newDefault;if(typeof newDefault!=="function"){this._defaultEdgeLabelFn=()=>newDefault}return this} /** * Gets the number of edges in the graph. * Complexity: O(1). */edgeCount(){return this._edgeCount} /** * Gets edges of the graph. In case of compound graph subgraphs are not considered. * Complexity: O(|E|). */edges(){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|). */setPath(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. */setEdge(){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(Object.hasOwn(this._edgeLabels,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. // First ensure the nodes exist. this.setNode(v);this.setNode(w);this._edgeLabels[e]=valueSpecified?value:this._defaultEdgeLabelFn(v,w,name);var edgeObj=edgeArgsToObj(this._isDirected,v,w,name); // 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} /** * Gets the label for the specified edge. * Complexity: O(1). */edge(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name);return this._edgeLabels[e]} /** * Gets the label for the specified edge and converts it to an object. * Complexity: O(1) */edgeAsObj(){const edge=this.edge(...arguments);if(typeof edge!=="object"){return{label:edge}}return edge} /** * Detects whether the graph contains specified edge or not. No subgraphs are considered. * Complexity: O(1). */hasEdge(v,w,name){var e=arguments.length===1?edgeObjToId(this._isDirected,arguments[0]):edgeArgsToId(this._isDirected,v,w,name);return Object.hasOwn(this._edgeLabels,e)} /** * Removes the specified edge from the graph. No subgraphs are considered. * Complexity: O(1). */removeEdge(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|). */inEdges(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|). */outEdges(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|). */nodeEdges(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)}module.exports=Graph},{}],17:[function(require,module,exports){ // Includes only the "core" of graphlib 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.2.4"},{}]},{},[1])(1)});