UNPKG

@haragei/dag

Version:

A Directed Acyclic Graph (DAG) library with online cycle detection and topological ordering.

3 lines (2 loc) 5.82 kB
var y=Object.defineProperty;var g=(c,e)=>y(c,"name",{value:e,configurable:!0});class a extends Error{static{g(this,"CycleError")}constructor(){super("Cycle detected"),this.name="CycleError"}}function w(c,e){return m(c.order,e.order)}g(w,"byOrder");function m(c,e){return c<e?-1:c==e?0:1}g(m,"byValue");class S{static{g(this,"PriorityQueue")}#e;#t;constructor(){this.#e=[],this.#t=[]}enqueue(e,t){const{length:s}=this.#e;if(this.#e.push(e),this.#t.push(t),s>0&&this.#t[s-1]>t){let r=0,o=s;for(;r<o;){const n=r+Math.trunc((o-r)/2);this.#t[n]<t?r=n+1:o=n}r<s&&(this.#e.copyWithin(r+1,r,s),this.#e[r]=e,this.#t.copyWithin(r+1,r,s),this.#t[r]=t)}}[Symbol.iterator](){return this.#e[Symbol.iterator]()}toArray(){return this.#e.slice(0)}}function O(c,e){if("union"in c)return c.union(e);const t=new Set(c);for(const s of e)t.add(s);return t}g(O,"union");class p{static{g(this,"DAG")}#e;#t;constructor(e){if(this.#e=new Map,this.#t=[],e)for(const t of e)this.#s(t)}get order(){return this.#t.slice(0)}get size(){return this.#e.size}[Symbol.iterator](){return this.#t[Symbol.iterator]()}keys(){return this.#t[Symbol.iterator]()}copy(){const e=new p;e.#t=this.#t.slice(0),e.#e=new Map;for(const[t,s]of this.#e)e.#e.set(t,{id:t,order:s.order,incoming:new Set(s.incoming),outgoing:new Set(s.outgoing)});return e}clear(){return this.#e.clear(),this.#t.splice(0,this.#t.length),this}add(e){return this.#s(e),this}has(e){return this.#e.has(e)}delete(e){const t=this.#e.get(e);if(t){const s=t.order,r=this.#t.length-1;for(let o=s;o<r;o++)this.#t[o]=this.#t[o+1],this.#e.get(this.#t[o]).order=o;this.#t.pop();for(const o of t.incoming)this.#e.get(o).outgoing.delete(e);for(const o of t.outgoing)this.#e.get(o).incoming.delete(e);this.#e.delete(e)}return this}addEdge(e,t){if(e==t)throw new a;return this.#h(e,t),this}tryAddEdge(e,t){try{return this.addEdge(e,t),!0}catch{return!1}}hasEdge(e,t){const s=this.#e.get(e);return s!==void 0&&s.outgoing.has(t)}deleteEdge(e,t){return this.hasEdge(e,t)&&(this.#e.get(e).outgoing.delete(t),this.#e.get(t).incoming.delete(e)),this}deleteOutgoingEdgesOf(e){return this.#o("outgoing",e)}deleteIncomingEdgesOf(e){return this.#o("incoming",e)}getNodeOrder(...e){return this.sortNodes(e)}sortNodes(e){return e.sort((t,s)=>{const r=this.#e.get(t);if(!r)return 1;const o=this.#e.get(s);return o?m(r.order,o.order):-1})}getImmediatePredecessorsOf(...e){return this.#n("incoming",...e)}getOrderedImmediatePredecessorsOf(...e){return this.#r(this.getImmediatePredecessorsOf(...e))}getPredecessorsOf(...e){return this.#i("incoming",...e)}getOrderedPredecessorsOf(...e){return this.#r(this.getPredecessorsOf(...e))}getImmediateSuccessorsOf(...e){return this.#n("outgoing",...e)}getOrderedImmediateSuccessorsOf(...e){return this.#r(this.getImmediateSuccessorsOf(...e))}getSuccessorsOf(...e){return this.#i("outgoing",...e)}getOrderedSuccessorsOf(...e){return this.#r(this.getSuccessorsOf(...e))}hasPath(e,t){if(e==t)return!1;const s=this.#e.get(e),r=this.#e.get(t);if(!s||!r||s.order>r.order)return!1;if(s.outgoing.has(t))return!0;const o=[e],n=new Set(o);for(;o.length>0;)for(const i of this.#e.get(o.shift()).outgoing){if(i==t)return!0;n.has(i)||(n.add(i),o.push(i))}return!1}mergeNodes(e,t){if(e==t)return this;const s=this.#e.get(e),r=this.#e.get(t);if(s&&r){if(this.hasPath(e,t)||this.hasPath(t,e))throw new a;for(const o of r.incoming)this.addEdge(o,e);for(const o of r.outgoing)this.addEdge(e,o);this.delete(t)}return this}tryMergeNodes(e,t){try{return this.mergeNodes(e,t),!0}catch{return!1}}subGraphs(){const e=[];if(this.#t.length==0)return e;const t=new Set;for(const s of this.#t){if(t.has(s))continue;const r=new S,o=[s];for(;o.length>0;){const n=o.pop();if(t.has(n))continue;const i=this.#e.get(n);t.add(n),r.enqueue(n,i.order);for(const h of i.outgoing)t.has(h)||o.push(h)}e.push(r.toArray())}return e}parallelize(){const e=new Set;for(const t of this.subGraphs())e.add(this.#c(t));return e}#c(e){if(e.length==1)return e[0];const t=new Map,s=[];for(const r of e){const o=this.#e.get(r);if(!o)continue;const n=Math.max(0,...Array.from(o.incoming,i=>(t.get(i)||0)+1));t.set(r,n),s.length<=n&&s.push(new Set),s[n].add(r)}return s.map(r=>r.size==1?Array.from(r)[0]:r)}#s(e){let t=this.#e.get(e);return t||(t={id:e,order:this.#t.length,incoming:new Set,outgoing:new Set},this.#e.set(e,t),this.#t.push(e),t)}#h(e,t){if(this.hasEdge(e,t))return;const s=this.#s(t),r=this.#s(e);if(s.order<r.order){const o=this.#d(s,r.order),n=this.#u(r,s.order);o.sort(w),n.sort(w);const i=n.length,h=i+o.length,f=new Array(h);let d=0;for(const{order:u}of o)f[d++]=u;for(const{order:u}of n)f[d++]=u;for(f.sort(m),d=0;d<i;d++){const u=f[d],l=n[d];this.#t[u]=l.id,l.order=u}for(d=i;d<h;d++){const u=f[d],l=o[d-i];this.#t[u]=l.id,l.order=u}}s.incoming.add(e),r.outgoing.add(t)}#o(e,t){const s=this.#e.get(t);if(s){const r=e=="incoming"?"outgoing":"incoming";for(const o of s[e])this.#e.get(o)[r].delete(t);s[e].clear()}return this}#d(e,t){const s=[],r=new Set,o=[e];for(;o.length>0;){const n=o.pop();if(!r.has(n.id)){r.add(n.id),s.push(n);for(const i of n.outgoing){const h=this.#e.get(i);if(h.order==t)throw new a;!r.has(i)&&h.order<t&&o.push(h)}}}return s}#u(e,t){const s=[],r=new Set,o=[e];for(;o.length>0;){const n=o.pop();if(!r.has(n.id)){r.add(n.id),s.push(n);for(const i of n.incoming){const h=this.#e.get(i);!r.has(i)&&h.order>=t&&o.push(h)}}}return s}#n(e,...t){let s=new Set;for(const r of t){const o=this.#e.get(r);o&&(s=O(s,o[e]))}for(const r of t)s.delete(r);return s}#i(e,...t){const s=new Set(t),r=t.slice(0);for(;r.length>0;){const o=this.#e.get(r.shift());if(o)for(const n of o[e])s.has(n)||(s.add(n),r.push(n))}for(const o of t)s.delete(o);return s}#r(e){const t=new S;for(const s of e)t.enqueue(s,this.#e.get(s).order);return t}}export{a as CycleError,p as DAG}; //# sourceMappingURL=index.mjs.map