graph-data-structure
Version:
A graph data structure with topological sort.
3 lines (2 loc) • 6.3 kB
JavaScript
function e(e,t){if(!1===e||null==e)throw console.warn("Test invariant failed:",t),new Error(t)}class t{nodes=new Set;edges=new Map;edgeWeights=new Map;edgeProperties=new Map;addNode(e){return this.nodes.has(e)||this.nodes.add(e),this.edges.has(e)||this.edges.set(e,new Set),this}removeNode(e){this.edges.delete(e),this.nodes.delete(e);for(const t of this.edges.values())t.delete(e);return this}adjacent(e){return this.edges.get(e)}setEdgeWeight(t,r,o){this.edgeWeights.has(t)||this.edgeWeights.set(t,new Map);const s=this.edgeWeights.get(t);return e(s),s.set(r,o),this}getEdgeWeight(e,t){return this.edgeWeights.get(e)?.get(t)??1}setEdgeProperties(t,r,o){this.edgeProperties.has(t)||this.edgeProperties.set(t,new Map);const s=this.edgeProperties.get(t);return e(s),s.set(r,o),this}getEdgeProperties(e,t){return this.edgeProperties.get(e)?.get(t)}addEdge(t,r,...o){let s,n;const d=o[0];"number"==typeof d&&(s=d),"object"==typeof d&&(s=d.weight,d&&(n=Object.prototype.hasOwnProperty.call(d,"props")?d.props:void 0)),this.addNode(t),this.addNode(r);const i=this.adjacent(t);return e(i),i.add(r),void 0!==s&&this.setEdgeWeight(t,r,s),void 0!==n&&this.setEdgeProperties(t,r,n),this}removeEdge(e,t){return this.edges.get(e)?.delete(t),this.edgeProperties.get(e)?.delete(t),this}hasEdge(e,t){return this.edges.get(e)?.has(t)??!1}}class r extends Error{constructor(e){super(e),Object.setPrototypeOf(this,r.prototype)}}function o(e,t,s,n,d,i){const{errorOnCycle:h=!1,shouldFollow:g}=i;if(n.has(d)&&h)throw new r("Cycle found");s.has(d)||(s.add(d),n.add(d),e.adjacent(d)?.forEach((r=>{(void 0===g||g({source:d,target:r,graph:e,props:e.getEdgeProperties(d,r)}))&&o(e,t,s,n,r,i)})),n.delete(d),t.push(d))}function s(e,t={}){const{sourceNodes:r=Array.from(e.nodes),includeSourceNodes:s=!0}=t,n=new Set,d=new Set,i=[];if(s){for(let s=0;s<r.length;s++){const h=r[s];h&&o(e,i,n,d,h,t)}return i}for(let e=0;e<r.length;e++){const t=r[e];t&&n.add(t)}for(let s=0;s<r.length;s++){const h=r[s];h&&e.adjacent(h)?.forEach((r=>o(e,i,n,d,r,t)))}return i}function n(e){let t,r=1/0;const{d:o,q:s}=e;return s.forEach((e=>{const s=o.get(e)??1/0;s<r&&(r=s,t=e)})),void 0===t?(s.clear(),null):(s.delete(t),t)}function d(t,r,o,s){const{d:n,p:d}=r,i=t.getEdgeWeight(o,s),h=n.get(o),g=n.get(s);e(h,"Missing source distance"),e(g,"Missing target distance"),g>h+i&&(n.set(s,h+i),d.set(s,o))}function i(e,t,r,o){const s=e.nodes,{q:i}=t;for(!function(e,{d:t},r,o){if(e.forEach((e=>{t.set(e,1/0)})),t.get(r)!==1/0)throw new Error("Source node is not in the graph");if(t.get(o)!==1/0)throw new Error("Destination node is not in the graph");t.set(r,0)}(s,t,r,o),function(e,{q:t}){e.forEach((e=>{t.add(e)}))}(s,t);0!==i.size;){const r=n(t);if(null===r)return;e.adjacent(r)?.forEach((o=>{d(e,t,r,o)}))}}function h(e){return void 0===e.currentPathWeight?e.edgeWeight:e.edgeWeight+e.currentPathWeight}function g(t,r,o,s=h){const n={d:new Map,p:new Map,q:new Set};return i(t,n,r,o),function(t,r,o,s,n=h){const{p:d}=r,i=[];let g,c=s;for(;d.has(c);){const e=d.get(c);i.push(c),c=e}if(c!==o)throw new Error("No path found");i.push(c),i.reverse(),e(i.length>=2,"The path should have a least two nodes");for(let e=1;e<i.length;e++){const r=i[e-1],o=i[e],s=t.getEdgeWeight(r,o),d=t.getEdgeProperties(r,o);g=n({edgeWeight:s,currentPathWeight:g,hop:e,graph:t,path:i,previousNode:r,currentNode:o,props:d})}return{nodes:i,weight:g}}(t,n,r,o,s)}function c(e,t,r,o,s,n){return!!o.has(s)||(o.add(s),t.push(s),s==n?(r.push(s),!1):Array.from(e.adjacent(s)??[]).every((s=>c(e,t,r,o,s,n))))}function a(e,t,r,o,s){o.has(s)||(o.add(s),t.indexOf(s)>=0?r.push(s):0==r.length&&e.adjacent(s)?.forEach((s=>{a(e,t,r,o,s)})))}exports.CycleError=r,exports.Graph=t,exports.cloneGraph=function(e){const r=new t;for(let[t,o]of e.edges.entries())o.forEach((o=>{r.addEdge.apply(r,[t,o]);const s=e.edgeWeights.get(t)?.get(o);s&&r.setEdgeWeight(t,o,s);const n=e.getEdgeProperties(t,o);n&&r.setEdgeProperties(t,o,n)}));return r},exports.depthFirstSearch=s,exports.deserializeGraph=function(...e){const[r,o]=e,s=new t,n=new Map;return r.nodes.forEach((e=>{s.addNode(e),o&&n.set(o(e),e)})),r.links.forEach((e=>{if(!o)return void s.addEdge.apply(s,[e.source,e.target,e.weight,e.props]);const t=n.get(o(e.source))??e.source,r=n.get(o(e.target))??e.target;s.addEdge.apply(s,[t,r,e.weight,e.props])})),s},exports.findNodes=function(e,t){const r=[];return e.nodes.forEach((e=>{t(e)&&r.push(e)})),r},exports.getFirstNode=function(e,t){for(const r of e.nodes)if(t(r))return r;throw new Error("Node not found.")},exports.getNode=function(e,t){const r=[];for(const o of e.nodes)t(o)&&r.push(o);if(0===r.length)throw new Error("Node not found.");if(r.length>1)throw new Error("More than one node found.");return r[0]},exports.hasCycle=function(e,t){try{return s(e,{...t,includeSourceNodes:!0,errorOnCycle:!0}),!1}catch(e){if(e instanceof r)return!0;throw e}},exports.indegree=function(e,t){let r=0;for(const o of e.edges.values())for(let e of o)e===t&&r++;return r},exports.lowestCommonAncestors=function(e,t,r){const o=[],s=[];return c(e,o,s,new Set,t,r)&&a(e,o,s,new Set,r),s},exports.outdegree=function(e,t){return e.edges.get(t)?.size??0},exports.serializeGraph=function(e,...t){const r="function"==typeof t[0]?t[0]:void 0,o="function"==typeof t[0]?t[1]:t[0],{includeDefaultWeight:s=!1}=o??{},n={nodes:Array.from(e.nodes),links:[]},d=new Map;return n.nodes.forEach((t=>{const o=t;e.adjacent(o)?.forEach((t=>{const i=e.getEdgeWeight(o,t),h=e.getEdgeProperties(o,t);r&&!d.has(o)&&d.set(o,r(o)),r&&!d.has(t)&&d.set(t,r(t));const g={source:d.get(o)??o,target:d.get(t)??t};(1!=i||s)&&(g.weight=i),h&&(g.props=h),n.links.push(g)}))})),n},exports.shortestPath=g,exports.shortestPaths=function(e,t,r){let o=g(e,t,r);const s=[o],n=o.weight,d=[];for(;o.weight;){const i=o.nodes[0],h=o.nodes[1];e.hasEdge(i,h)&&(d.push({u:i,v:h,weight:e.getEdgeWeight(i,h),props:e.getEdgeProperties(i,h)}),e.removeEdge(i,h)),e.hasEdge(h,i)&&(d.push({u:h,v:i,weight:e.getEdgeWeight(h,i),props:e.getEdgeProperties(h,i)}),e.removeEdge(h,i));try{if(o=g(e,t,r),!o.weight||!n||n<o.weight)break;s.push(o)}catch(e){break}}for(const{u:t,v:r,weight:o,props:s}of d)e.addEdge(t,r,o,s);return s},exports.topologicalSort=function(e,t={}){return s(e,{...t,errorOnCycle:!0}).reverse()};
//# sourceMappingURL=index.cjs.map
;