UNPKG

graph-by-ivan-tulaev

Version:

Graph library for traversing and processing any directional graphs.

186 lines (185 loc) 5.98 kB
var N = Object.defineProperty; var j = (c, e, t) => e in c ? N(c, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : c[e] = t; var m = (c, e, t) => j(c, typeof e != "symbol" ? e + "" : e, t); /*! * MIT License * * Copyright (c) 2025 Ivan Tulaev * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ function y(c, e) { return e.nodes.find((t) => !c.has(t)); } function w(c) { return c.pop(); } function T(c) { return c.shift(); } function E(c, e) { for (const t of c) e.push(t); } function G(c, e) { for (const t of c) e.unshift(t); } function L(c, e, t) { return [...e.getOutgoingEdgesFor(c)].map((n) => n.target).filter((n) => !t.has(n)); } function S(c, e, t) { return [...e.getIncomingEdgesFor(c)].map((n) => n.source).filter((n) => !t.has(n)); } class p { constructor(e = !1) { m(this, "notDirected"); m(this, "_adjacencyList"); this.notDirected = e, this._adjacencyList = /* @__PURE__ */ new Map(); } get nodes() { return [...this._adjacencyList.keys()]; } addNode(e) { this.nodes.includes(e) || this._adjacencyList.set(e, { incoming: /* @__PURE__ */ new Set(), outgoing: /* @__PURE__ */ new Set() }); } deleteNode(e) { this._adjacencyList.delete(e); for (const [, t] of this._adjacencyList) { const { incoming: n, outgoing: i } = t, s = /* @__PURE__ */ new Set([...n, ...i]); for (const r of s) r.source !== e && r.source !== e || (n.delete(r), i.delete(r)); } } get edges() { return new Set([...this._adjacencyList.values()].map((e) => [...e.incoming, ...e.outgoing]).flat()); } addEdge(e) { const { source: t, target: n } = e; if (!this._adjacencyList.has(t) || !this._adjacencyList.has(n)) throw new Error(`Cannot add adjacency: has no node ${t} or ${n}`); const i = this._adjacencyList.get(n); i && i.incoming.add(e); const s = this._adjacencyList.get(t); s && s.outgoing.add(e); } deleteEdge(e) { const { source: t, target: n } = e, i = this._adjacencyList.get(n); i && i.incoming.delete(e); const s = this._adjacencyList.get(t); s && s.outgoing.delete(e); } getIncomingEdgesFor(e) { var t; return ((t = this._adjacencyList.get(e)) == null ? void 0 : t.incoming) || /* @__PURE__ */ new Set(); } getOutgoingEdgesFor(e) { var t; return ((t = this._adjacencyList.get(e)) == null ? void 0 : t.outgoing) || /* @__PURE__ */ new Set(); } /** * @param getStartElement * @param getNextFromExecutionSequence * @param getNextNodes will be sorted * @param addNextNodesToExecutionSequence * @param executeCurrent */ genericTraversing(e, t, n, i, s) { const r = /* @__PURE__ */ new Set(); for (; r.size < this.nodes.length; ) { const d = e(r, this); if (!d) break; const a = [d]; for (; a.length > 0; ) { const o = t(a); if (!o) throw new Error(`Can't get current node from ${a}`); s && s(o), r.add(o); const g = n(o, this, r); if (!g) break; i(g, a); } } } // TODO: ADD OPTIMISATION getSeparatedGraphs() { const e = /* @__PURE__ */ new Set(), t = (s, r) => { const d = r.getOutgoingEdgesFor(s), a = [...d].map((f) => f.target), o = r.getIncomingEdgesFor(s), g = [...o].map((f) => f.source), u = /* @__PURE__ */ new Set([...d, ...o]), h = /* @__PURE__ */ new Set([...a, ...g]), l = new p(!1); l.addNode(s); for (const f of h) l.addNode(f); for (const f of u) l.addEdge(f); return l; }, n = (s, r) => { const d = /* @__PURE__ */ new Set(); for (const a of r.nodes) for (const o of s) if (o.nodes.includes(a)) { d.add(o); break; } return d; }, i = (s, r, d) => { const a = t(s, r), o = n(e, a); if (o.size > 0) { for (const u of o) e.delete(u); const g = p.mergeGraphs(o.add(a)); e.add(g); } else e.add(a); return [...a.nodes].filter((g) => !d.has(g)); }; return this.genericTraversing(y, w, i, E), [...e]; } // TODO: ADD OPTIMISATION for self loop isNodeTraced(e, t, n = !1) { let i = !1; const s = [t].flat(), r = (o) => o.has(e) ? void 0 : e, d = (o) => { e === o && s.includes(o) && (i = !0); }, a = (o, g, u) => { const h = n ? S(o, g, u) : L(o, g, u); if (h.some((l) => s.includes(l))) { i = !0; return; } return h; }; return this.genericTraversing(r, w, a, E, d), i; } static mergeGraphs(e) { const t = new p(!1); for (const n of e) { for (const i of n.nodes) t.addNode(i); for (const i of n.edges) t.addEdge(i); } return t; } } export { p as Graph, E as addToEnd, G as addToStart, T as getFirst, y as getFirstUnvisited, w as getLast, S as getNotVisitedIncomingNodes, L as getNotVisitedOutgoingNodes };