UNPKG

@pipepack/graph

Version:

A graph data structure with pipepack related algorithm.

163 lines (127 loc) 4.08 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; // interface class Graph { // nodes mean key, edges mean value // Computes a string encoding of an edge, // for use as a key in an object. static encodeEdge(u, v) { return `${u}|${v}`; } constructor(serialized) { this.edges = new Map(); this.edgeWeights = new Map(); // If a serialized graph was passed into the constructor, deserialize it. if (serialized) { this.deserialize(serialized); } } // gets the adjacent node list for the given node as access layer adjacent(nid) { return this.edges.get(nid) || new Set(); } // maybe better when implment standard iterator nodes() { const deduplication = new Set(); this.edges.forEach((adjacents, nid) => { // node self deduplication.add(nid); // node adjacents adjacents.forEach(aid => { deduplication.add(aid); }); }); return Array.from(deduplication); } // adds a node to the graph. // If node was already added, this function does nothing. // If node was not already added, this function sets up an empty adjacency list. addNode(nid) { this.edges.set(nid, this.adjacent(nid)); return this; } // removes a node from the graph, also removes incoming and outgoing edges. removeNode(nid) { // delete node self this.edges.delete(nid); // delete adjacent link this.edges.forEach(adjacents => { adjacents.delete(nid); }); return this; } // directional edige addEdge(u, v, weight) { this.addNode(u); this.addNode(v); // node 'u' already within internal storage, without worrying about lost state this.adjacent(u).add(v); this.setEdgeWeight(u, v, weight); return this; } // Removes the edge from node u to node v. // Does not remove the nodes. // Does nothing if the edge does not exist. removeEdge(u, v) { // remove adjacent node when source node exist, nothing when not exist this.adjacent(u).delete(u); // remove edge weight if any this.edgeWeights.delete(Graph.encodeEdge(u, v)); return this; } // gets the weight of the given edge, returns 1 if no weight was previously set. // use number as weights just now getEdgeWeight(u, v) { return this.edgeWeights.get(Graph.encodeEdge(u, v)); } // sets the weight of the given edge. setEdgeWeight(u, v, weight) { if (weight) { this.edgeWeights.set(Graph.encodeEdge(u, v), weight); } return this; } // omit weight property when undefined, simplify serialize wrapEdgeWeight(u, v) { const weight = this.getEdgeWeight(u, v); const required = { source: u, target: v }; const optional = weight ? {} : { weight }; return { ...required, ...optional }; } serialize() { const ids = this.nodes(); const nodes = ids.map(id => ({ id })); const edges = ids.reduce((acc, id) => { // use mangle prefix for better semantic link // eslint-disable-next-line @typescript-eslint/naming-convention, no-underscore-dangle const _edges = []; this.adjacent(id).forEach(aid => { _edges.push(this.wrapEdgeWeight(id, aid)); }); return [...acc, ..._edges]; }, []); return { nodes, edges }; } // Deserializes the given serialized graph deserialize(serialized) { serialized.nodes.forEach(node => { this.addNode(node.id); }); serialized.edges.forEach(edge => { this.addEdge(edge.source, edge.target, edge.weight); }); return this; } // computes the indegree for the given node. // not very efficient, costs O(E) where E = number of edges. indegree(nid) { return Array.from(this.edges.values()).reduce((acc, curr) => { return curr.has(nid) ? acc + 1 : acc; }, 0); } // computes the outdegree for the given node. outdegree(nid) { return this.adjacent(nid).size; } } var _default = Graph; exports.default = _default; //# sourceMappingURL=Graph.js.map