graph-by-ivan-tulaev
Version:
Graph library for traversing and processing any directional graphs.
186 lines (185 loc) • 5.98 kB
JavaScript
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
};