UNPKG

ngraph.leiden

Version:

Leiden/Louvain community detection for ngraph.graph (JS)

663 lines (662 loc) 24.2 kB
import tt from "ngraph.graph"; function K(t, o = {}) { const n = o.linkWeight || ((w) => w.data && typeof w.data.weight == "number" ? w.data.weight : 1), s = o.nodeSize || ((w) => w.data && typeof w.data.size == "number" ? w.data.size : 1), i = !!o.directed, l = o.baseNodeIds, d = [], g = /* @__PURE__ */ new Map(); if (Array.isArray(l) && l.length > 0) for (let w = 0; w < l.length; w++) { const S = l[w]; if (!(t.getNode ? t.getNode(S) : null)) throw new Error("Multilayer graphs must share identical node ids. Missing: " + S); g.set(S, w), d.push(S); } else t.forEachNode((w) => { g.set(w.id, d.length), d.push(w.id); }); const e = d.length, u = new Float64Array(e), m = new Float64Array(e), f = new Float64Array(e), y = new Float64Array(e), h = new Array(e), a = new Array(e); for (let w = 0; w < e; w++) h[w] = [], a[w] = []; if (i) t.forEachLink((w) => { const S = g.get(w.fromId), I = g.get(w.toId); if (S == null || I == null) return; const z = +n(w) || 0; S === I && (m[S] += z), h[S].push({ to: I, w: z }), a[I].push({ from: S, w: z }), f[S] += z, y[I] += z; }); else { const w = /* @__PURE__ */ new Map(); t.forEachLink((S) => { const I = g.get(S.fromId), z = g.get(S.toId); if (I == null || z == null) return; const b = +n(S) || 0; if (I === z) { m[I] += b; return; } const E = I < z ? I : z, P = I < z ? z : I, q = E + ":" + P; let N = w.get(q); N || (N = { sum: 0, seenAB: 0, seenBA: 0 }, w.set(q, N)), N.sum += b, I === E ? N.seenAB = 1 : N.seenBA = 1; }); for (const [S, I] of w.entries()) { const [z, b] = S.split(":"), E = +z, P = +b, q = (I.seenAB ? 1 : 0) + (I.seenBA ? 1 : 0), N = q > 0 ? I.sum / q : 0; N !== 0 && (h[E].push({ to: P, w: N }), h[P].push({ to: E, w: N }), a[E].push({ from: P, w: N }), a[P].push({ from: E, w: N }), f[E] += N, f[P] += N, y[E] += N, y[P] += N); } for (let S = 0; S < e; S++) { const I = m[S]; I !== 0 && (h[S].push({ to: S, w: I }), a[S].push({ from: S, w: I }), f[S] += I, y[S] += I); } } t.forEachNode((w) => { const S = g.get(w.id); u[S] = +s(w) || 0; }); const T = f.reduce((w, S) => w + S, 0); function F(w, S) { const I = h[w]; for (let z = 0; z < I.length; z++) S(I[z].to, I[z].w); } return { n: e, nodeIds: d, idToIndex: g, size: u, selfLoop: m, strengthOut: f, strengthIn: y, outEdges: h, inEdges: a, directed: i, totalWeight: T, forEachNeighbor: F }; } function Y(t) { const o = t.n, n = new Int32Array(o); for (let r = 0; r < o; r++) n[r] = r; let s = o, i = new Float64Array(s), l = new Int32Array(s), d = new Float64Array(s), g = new Float64Array(s), e = new Float64Array(s), u = new Float64Array(s), m = new Int32Array(o), f = 0, y = new Float64Array(o), h = new Float64Array(o), a = new Float64Array(o), T = new Uint8Array(o); function F(r) { if (r <= i.length) return; const c = Math.max(r, Math.ceil(i.length * 1.5)); i = H(i, c), l = ut(l, c), d = H(d, c), g = H(g, c), e = H(e, c), u = H(u, c); } function w() { i.fill(0), l.fill(0), d.fill(0), g.fill(0), e.fill(0), u.fill(0); for (let r = 0; r < o; r++) { const c = n[r]; i[c] += t.size[r], l[c] += 1, t.directed ? (e[c] += t.strengthOut[r], u[c] += t.strengthIn[r]) : g[c] += t.strengthOut[r], t.selfLoop[r] !== 0 && (d[c] += t.selfLoop[r]); } if (t.directed) for (let r = 0; r < o; r++) { const c = n[r], x = t.outEdges[r]; for (let A = 0; A < x.length; A++) { const { to: M, w: _ } = x[A]; c === n[M] && (d[c] += _); } } else for (let r = 0; r < o; r++) { const c = n[r], x = t.outEdges[r]; for (let A = 0; A < x.length; A++) { const { to: M, w: _ } = x[A]; M <= r || c === n[M] && (d[c] += _); } } } function S() { for (let r = 0; r < f; r++) { const c = m[r]; T[c] = 0, y[c] = 0, h[c] = 0, a[c] = 0; } f = 0; } function I(r) { T[r] || (T[r] = 1, m[f++] = r); } function z(r) { S(); const c = n[r]; if (I(c), t.directed) { const x = t.outEdges[r]; for (let M = 0; M < x.length; M++) { const _ = x[M].to, W = x[M].w, k = n[_]; I(k), h[k] += W; } const A = t.inEdges[r]; for (let M = 0; M < A.length; M++) { const _ = A[M].from, W = A[M].w, k = n[_]; I(k), a[k] += W; } } else { const x = t.outEdges[r]; for (let A = 0; A < x.length; A++) { const M = x[A].to, _ = x[A].w, W = n[M]; I(W), y[W] += _; } } return f; } const b = t.totalWeight; function E(r, c) { const x = n[r]; if (c === x) return 0; const A = t.strengthOut[r], M = c < y.length && y[c] || 0, _ = y[x] || 0, W = c < g.length ? g[c] : 0, k = g[x], G = -(_ / b - A * k / (b * b)), V = M / b - A * W / (b * b); return G + V; } function P(r, c) { const x = n[r]; if (c === x) return 0; const A = t.totalWeight, M = t.strengthOut[r], _ = t.strengthIn[r], W = c < a.length && a[c] || 0, k = c < h.length && h[c] || 0, G = a[x] || 0, V = h[x] || 0, C = c < u.length ? u[c] : 0, O = c < e.length ? e[c] : 0, D = u[x], p = e[x], B = (W + k - G - V) / A, X = (M * (C - D) + _ * (O - p)) / (A * A); return B - X; } function q(r, c, x = 1) { const A = n[r]; if (c === A) return 0; const M = y[A] || 0, _ = c < y.length && y[c] || 0, W = t.size[r] || 1, k = i[A] || 0, G = c < i.length ? i[c] : 0; return _ - M - x * W * (G - k + W); } function N(r, c) { const x = n[r]; if (x === c) return !1; c >= s && (F(c + 1), s = c + 1); const A = t.strengthOut[r], M = t.strengthIn[r], _ = t.selfLoop[r], W = t.size[r]; if (l[x] -= 1, l[c] += 1, i[x] -= W, i[c] += W, t.directed ? (e[x] -= A, e[c] += A, u[x] -= M, u[c] += M) : (g[x] -= A, g[c] += A), t.directed) { const k = h[x] || 0, G = a[x] || 0, V = c < h.length && h[c] || 0, C = c < a.length && a[c] || 0; d[x] -= k + G + _, d[c] += V + C + _; } else { const k = y[x] || 0, G = y[c] || 0; d[x] -= 2 * k + _, d[c] += 2 * G + _; } return n[r] = c, !0; } function R(r = {}) { const c = []; for (let C = 0; C < s; C++) l[C] > 0 && c.push(C); r.keepOldOrder ? c.sort((C, O) => C - O) : r.preserveMap instanceof Map ? c.sort((C, O) => { const D = r.preserveMap.get(C), p = r.preserveMap.get(O); return D != null && p != null && D !== p ? D - p : D != null && p == null ? -1 : p != null && D == null ? 1 : i[O] - i[C] || l[O] - l[C] || C - O; }) : c.sort((C, O) => i[O] - i[C] || l[O] - l[C] || C - O); const x = new Int32Array(s).fill(-1); c.forEach((C, O) => { x[C] = O; }); for (let C = 0; C < n.length; C++) n[C] = x[n[C]]; const A = c.length, M = new Float64Array(A), _ = new Int32Array(A), W = new Float64Array(A), k = new Float64Array(A), G = new Float64Array(A), V = new Float64Array(A); for (let C = 0; C < o; C++) { const O = n[C]; M[O] += t.size[C], _[O] += 1, t.directed ? (G[O] += t.strengthOut[C], V[O] += t.strengthIn[C]) : k[O] += t.strengthOut[C]; } if (t.directed) for (let C = 0; C < o; C++) { const O = n[C], D = t.outEdges[C]; for (let p = 0; p < D.length; p++) { const { to: B, w: X } = D[p]; O === n[B] && (W[O] += X); } } else for (let C = 0; C < o; C++) { const O = n[C], D = t.outEdges[C]; for (let p = 0; p < D.length; p++) { const { to: B, w: X } = D[p]; B <= C || O === n[B] && (W[O] += X); } } s = A, i = M, l = _, d = W, g = k, e = G, u = V; } function L() { const r = new Array(s); for (let c = 0; c < s; c++) r[c] = []; for (let c = 0; c < o; c++) r[n[c]].push(c); return r; } function v(r) { return r < i.length ? i[r] : 0; } function j(r) { return r < l.length ? l[r] : 0; } return { n: o, get communityCount() { return s; }, nodeCommunity: n, communityTotalSize: i, communityNodeCount: l, communityInternalEdgeWeight: d, communityTotalStrength: g, communityTotalOutStrength: e, communityTotalInStrength: u, initializeAggregates: w, accumulateNeighborCommunityEdgeWeights: z, getCandidateCommunityCount: () => f, getCandidateCommunityAt: (r) => m[r], getNeighborEdgeWeightToCommunity: (r) => y[r] || 0, getOutEdgeWeightToCommunity: (r) => h[r] || 0, getInEdgeWeightFromCommunity: (r) => a[r] || 0, deltaModularityUndirected: E, deltaModularityDirected: P, deltaCPM: q, moveNodeToCommunity: N, compactCommunityIds: R, getCommunityMembers: L, getCommunityTotalSize: v, getCommunityNodeCount: j }; } function H(t, o) { const n = new Float64Array(o); return n.set(t), n; } function ut(t, o) { const n = new Int32Array(o); return n.set(t), n; } function lt(t) { return t && t.__esModule && Object.prototype.hasOwnProperty.call(t, "default") ? t.default : t; } var J = { exports: {} }, Z; function at() { if (Z) return J.exports; Z = 1, J.exports = t, J.exports.random = t, J.exports.randomIterator = g; function t(e) { var u = typeof e == "number" ? e : +/* @__PURE__ */ new Date(); return new o(u); } function o(e) { this.seed = e; } o.prototype.next = d, o.prototype.nextDouble = l, o.prototype.uniform = l, o.prototype.gaussian = n, o.prototype.random = l; function n() { var e, u, m; do u = this.nextDouble() * 2 - 1, m = this.nextDouble() * 2 - 1, e = u * u + m * m; while (e >= 1 || e === 0); return u * Math.sqrt(-2 * Math.log(e) / e); } o.prototype.levy = s; function s() { var e = 1.5, u = Math.pow( i(1 + e) * Math.sin(Math.PI * e / 2) / (i((1 + e) / 2) * e * Math.pow(2, (e - 1) / 2)), 1 / e ); return this.gaussian() * u / Math.pow(Math.abs(this.gaussian()), 1 / e); } function i(e) { return Math.sqrt(2 * Math.PI / e) * Math.pow(1 / Math.E * (e + 1 / (12 * e - 1 / (10 * e))), e); } function l() { var e = this.seed; return e = e + 2127912214 + (e << 12) & 4294967295, e = (e ^ 3345072700 ^ e >>> 19) & 4294967295, e = e + 374761393 + (e << 5) & 4294967295, e = (e + 3550635116 ^ e << 9) & 4294967295, e = e + 4251993797 + (e << 3) & 4294967295, e = (e ^ 3042594569 ^ e >>> 16) & 4294967295, this.seed = e, (e & 268435455) / 268435456; } function d(e) { return Math.floor(this.nextDouble() * e); } function g(e, u) { var m = u || t(); if (typeof m.next != "function") throw new Error("customRandom does not match expected API: next() function is missing"); return { /** * Visits every single element of a collection once, in a random order. * Note: collection is modified in place. */ forEach: y, /** * Shuffles array randomly, in place. */ shuffle: f }; function f() { var h, a, T; for (h = e.length - 1; h > 0; --h) a = m.next(h + 1), T = e[a], e[a] = e[h], e[h] = T; return e; } function y(h) { var a, T, F; for (a = e.length - 1; a > 0; --a) T = m.next(a + 1), F = e[T], e[T] = e[a], e[a] = F, h(F); e.length && h(e[0]); } } return J.exports; } var mt = at(); const dt = /* @__PURE__ */ lt(mt); function ft(t, o, n, s) { if (o.directed) return et(t, o, n, s); const i = t.nodeCommunity[n]; if (s === i) return 0; const l = o.strengthOut[n], d = o.totalWeight, g = t.getNeighborEdgeWeightToCommunity(s) || 0, e = t.getNeighborEdgeWeightToCommunity(i) || 0, u = s < t.communityTotalStrength.length ? t.communityTotalStrength[s] : 0, m = t.communityTotalStrength[i], f = -(e / d - l * m / (d * d)), y = g / d - l * u / (d * d); return f + y; } function et(t, o, n, s) { const i = t.nodeCommunity[n]; if (s === i) return 0; const l = o.totalWeight, d = o.strengthOut[n], g = o.strengthIn[n], e = s < o.n && t.getInEdgeWeightFromCommunity(s) || 0, u = s < o.n && t.getOutEdgeWeightToCommunity(s) || 0, m = t.getInEdgeWeightFromCommunity(i) || 0, f = t.getOutEdgeWeightToCommunity(i) || 0, y = s < t.communityTotalInStrength.length ? t.communityTotalInStrength[s] : 0, h = s < t.communityTotalOutStrength.length ? t.communityTotalOutStrength[s] : 0, a = t.communityTotalInStrength[i], T = t.communityTotalOutStrength[i], F = (e + u - m - f) / l, w = (d * (y - a) + g * (h - T)) / (l * l); return F - w; } function nt(t, o) { const n = o.totalWeight; let s = 0; if (o.directed) for (let i = 0; i < t.communityCount; i++) s += t.communityInternalEdgeWeight[i] / n - t.communityTotalOutStrength[i] * t.communityTotalInStrength[i] / (n * n); else for (let i = 0; i < t.communityCount; i++) { const l = t.communityInternalEdgeWeight[i], d = t.communityTotalStrength[i]; s += l / n - d * d / (n * n); } return s; } function gt(t, o, n, s, i = 1) { const l = t.nodeCommunity[n]; if (s === l) return 0; const d = t.getNeighborEdgeWeightToCommunity(l) || 0, g = s < o.n && t.getNeighborEdgeWeightToCommunity(s) || 0, e = o.size[n] || 1, u = t.communityTotalSize[l] || 0, m = s < t.communityTotalSize.length ? t.communityTotalSize[s] : 0; return g - d - i * e * (m - u + e); } function ot(t, o, n = 1) { let s = 0; for (let i = 0; i < t.communityCount; i++) s += t.communityInternalEdgeWeight[i] - n * (t.communityNodeCount[i] * (t.communityNodeCount[i] - 1)) / 2; return s; } function it(t, o, n = 1) { let s = 0; for (let i = 0; i < t.communityCount; i++) { const l = t.communityTotalSize[i] || 0; s += t.communityInternalEdgeWeight[i] - n * (l * (l - 1)) / 2; } return s; } const ht = 50, rt = 20, st = 1e-12, U = { Neighbors: 0, // neighbor communities only All: 1, // all communities RandomAny: 2, // random among all RandomNeighbor: 3 // random among neighbor communities }; function yt(t, o = {}) { const n = St(o); let s = t; const i = [], l = dt(n.randomSeed), d = () => l.nextDouble(), g = K(s, { directed: n.directed, ...o }), e = g.n, u = new Int32Array(e); for (let y = 0; y < e; y++) u[y] = y; let m = null; if (n.fixedNodes) { const y = new Uint8Array(e), h = n.fixedNodes instanceof Set ? n.fixedNodes : new Set(n.fixedNodes); for (const a of h) { const T = g.idToIndex.get(a); T != null && (y[T] = 1); } m = y; } for (let y = 0; y < n.maxLevels; y++) { const h = y === 0 ? g : K(s, { directed: n.directed, ...o }), a = Y(h); a.graph = h, a.initializeAggregates(); const T = new Int32Array(h.n); for (let b = 0; b < h.n; b++) T[b] = b; let F = !0, w = 0; const S = n.candidateStrategyCode; for (; F; ) { F = !1, w++, ct(T, d); for (let b = 0; b < T.length; b++) { const E = T[b]; if (y === 0 && m && m[E]) continue; const P = a.accumulateNeighborCommunityEdgeWeights(E); let q = a.nodeCommunity[E], N = 0; const R = n.maxCommunitySize; if (S === U.All) for (let L = 0; L < a.communityCount; L++) { if (L === a.nodeCommunity[E] || R < 1 / 0 && a.getCommunityTotalSize(L) + h.size[E] > R) continue; const v = Q(a, E, L, n); v > N && (N = v, q = L); } else if (S === U.RandomAny) { const L = Math.min(10, Math.max(1, a.communityCount)); for (let v = 0; v < L; v++) { const j = d() * a.communityCount | 0; if (j === a.nodeCommunity[E] || R < 1 / 0 && a.getCommunityTotalSize(j) + h.size[E] > R) continue; const r = Q(a, E, j, n); r > N && (N = r, q = j); } } else if (S === U.RandomNeighbor) { const L = Math.min(10, Math.max(1, P)); for (let v = 0; v < L; v++) { const j = a.getCandidateCommunityAt(d() * P | 0); if (j === a.nodeCommunity[E] || R < 1 / 0 && a.getCommunityTotalSize(j) + h.size[E] > R) continue; const r = Q(a, E, j, n); r > N && (N = r, q = j); } } else for (let L = 0; L < P; L++) { const v = a.getCandidateCommunityAt(L); if (R < 1 / 0 && a.getCommunityTotalSize(v) + h.size[E] > R) continue; const j = Q(a, E, v, n); j > N && (N = j, q = v); } if (n.allowNewCommunity) { const L = a.communityCount, v = Q(a, E, L, n); v > N && (N = v, q = L); } q !== a.nodeCommunity[E] && N > st && (a.moveNodeToCommunity(E, q), F = !0); } if (w > n.maxLocalPasses) break; } $(a, n.preserveLabels); let I = a; if (n.refine) { const b = Ct(h, a, d, n, y === 0 ? m : null); $(b, n.preserveLabels), I = b; } i.push({ graph: h, partition: I }); const z = I.nodeCommunity; for (let b = 0; b < u.length; b++) u[b] = z[u[b]]; if (a.communityCount === h.n) break; s = wt(h, I); } const f = i[i.length - 1]; return { graph: f.graph, partition: f.partition, levels: i, originalToCurrent: u, originalNodeIds: g.nodeIds }; } function wt(t, o) { const n = tt(); for (let i = 0; i < o.communityCount; i++) n.addNode(i, { size: o.communityTotalSize[i] }); const s = /* @__PURE__ */ new Map(); for (let i = 0; i < t.n; i++) { const l = o.nodeCommunity[i], d = t.outEdges[i]; for (let g = 0; g < d.length; g++) { const e = d[g].to, u = d[g].w, m = o.nodeCommunity[e], f = l + ":" + m; s.set(f, (s.get(f) || 0) + u); } } for (const [i, l] of s.entries()) { const [d, g] = i.split(":"), e = +d, u = +g; n.addLink(e, u, { weight: l }); } return n; } function Ct(t, o, n, s, i) { const l = Y(t); l.initializeAggregates(), l.graph = t; const d = o.nodeCommunity; let g = new Int32Array(l.communityCount); for (let f = 0; f < l.communityCount; f++) g[f] = d[f]; const e = new Int32Array(t.n); for (let f = 0; f < t.n; f++) e[f] = f; let u = !0, m = 0; for (; u; ) { u = !1, m++, ct(e, n); for (let f = 0; f < e.length; f++) { const y = e[f]; if (i && i[y]) continue; const h = d[y], a = l.accumulateNeighborCommunityEdgeWeights(y); let T = l.nodeCommunity[y], F = 0; const w = Number.isFinite(s.maxCommunitySize) ? s.maxCommunitySize : 1 / 0; for (let S = 0; S < a; S++) { const I = l.getCandidateCommunityAt(S); if (g[I] !== h || w < 1 / 0 && l.getCommunityTotalSize(I) + t.size[y] > w) continue; const z = Q(l, y, I, s); z > F && (F = z, T = I); } T !== l.nodeCommunity[y] && F > st && (l.moveNodeToCommunity(y, T), u = !0); } if (m > (s.maxLocalPasses || rt)) break; } return l; } function Q(t, o, n, s) { if ((s.quality || "modularity").toLowerCase() === "cpm") { const l = typeof s.resolution == "number" ? s.resolution : 1; return gt(t, t.graph || {}, o, n, l) || t.deltaCPM?.(o, n, l) || 0; } return s.directed ? et(t, t.graph || {}, o, n) || t.deltaModularityDirected?.(o, n) || 0 : ft(t, t.graph || {}, o, n) || t.deltaModularityUndirected?.(o, n) || 0; } function ct(t, o = Math.random) { for (let n = t.length - 1; n > 0; n--) { const s = Math.floor(o() * (n + 1)), i = t[n]; t[n] = t[s], t[s] = i; } return t; } function It(t) { const o = t.candidateStrategy; if (typeof o != "string") return U.Neighbors; switch (o) { case "neighbors": return U.Neighbors; case "all": return U.All; case "random": return U.RandomAny; case "random-neighbor": return U.RandomNeighbor; default: return U.Neighbors; } } function St(t = {}) { const o = !!t.directed, n = Number.isFinite(t.randomSeed) ? t.randomSeed : 42, s = Number.isFinite(t.maxLevels) ? t.maxLevels : ht, i = Number.isFinite(t.maxLocalPasses) ? t.maxLocalPasses : rt, l = !!t.allowNewCommunity, d = It(t), g = (t.quality || "modularity").toLowerCase(), e = typeof t.resolution == "number" ? t.resolution : 1, u = t.refine !== !1, m = t.preserveLabels, f = Number.isFinite(t.maxCommunitySize) ? t.maxCommunitySize : 1 / 0; return { directed: o, randomSeed: n, maxLevels: s, maxLocalPasses: i, allowNewCommunity: l, candidateStrategyCode: d, quality: g, resolution: e, refine: u, preserveLabels: m, maxCommunitySize: f, fixedNodes: t.fixedNodes }; } function $(t, o) { o && o instanceof Map ? t.compactCommunityIds({ preserveMap: o }) : o === !0 ? t.compactCommunityIds({ keepOldOrder: !0 }) : t.compactCommunityIds(); } function xt(t, o = {}) { if (!Array.isArray(t) || t.length === 0) throw new Error("layers must be a non-empty array"); o.directed; const n = t[0].graph, s = [], i = /* @__PURE__ */ new Set(); n.forEachNode((e) => { s.push(e.id), i.add(e.id); }); for (let e = 1; e < t.length; e++) t[e].graph.forEachNode((m) => { if (!i.has(m.id)) throw new Error("All layers must share identical node ids. Missing in base: " + m.id); }); const l = tt(), d = t[0].nodeSize || ((e) => e.data && typeof e.data.size == "number" ? e.data.size : 1); for (let e = 0; e < s.length; e++) { const u = s[e], m = n.getNode ? n.getNode(u) : null, f = m ? d(m) : 1; l.addNode(u, { size: f }); } const g = /* @__PURE__ */ new Map(); for (let e = 0; e < t.length; e++) { const { graph: u, weight: m = 1, linkWeight: f } = t[e], y = f || ((h) => h.data && typeof h.data.weight == "number" ? h.data.weight : 1); u.forEachLink((h) => { const a = h.fromId, T = h.toId; if (!i.has(a) || !i.has(T)) return; const F = m * y(h); if (F === 0) return; const w = a + "\0" + T; g.set(w, (g.get(w) || 0) + F); }); } for (const [e, u] of g.entries()) { const m = e.indexOf("\0"), f = e.substring(0, m), y = e.substring(m + 1); l.addLink(f, y, { weight: u }); } return l; } function bt(t, o = {}) { let n = t; Array.isArray(t) && (n = xt(t, { directed: !!o.directed })); const { graph: s, partition: i, levels: l, originalToCurrent: d, originalNodeIds: g } = yt(n, o), e = /* @__PURE__ */ new Map(); for (let u = 0; u < g.length; u++) { const m = d[u]; e.set(g[u], m); } return { getClass(u) { return e.get(u); }, getCommunities() { const u = /* @__PURE__ */ new Map(); for (const [m, f] of e) u.has(f) || u.set(f, []), u.get(f).push(m); return u; }, quality() { if ((o.quality || "modularity").toLowerCase() === "cpm") { const m = typeof o.resolution == "number" ? o.resolution : 1; return (o.cpmMode || "unit") === "size-aware" ? it(i, s, m) : ot(i, s, m); } else return nt(i, s); }, toJSON() { const u = {}; for (const [m, f] of e) u[m] = f; return { membership: u, meta: { levels: l.length, quality: this.quality(), options: o } }; } }; } function Et(t, o, n = {}) { const s = !!n.directed, i = K(t, { directed: s, ...n }), l = Y(i); l.graph = i; const d = i.idToIndex, g = (u) => o instanceof Map ? o.get(u) : o?.[u]; for (let u = 0; u < i.nodeIds.length; u++) { const m = i.nodeIds[u], f = g(m); if (f == null) { if (n.requireMembership) throw new Error("Missing membership for node: " + m); continue; } const y = At(f); l.nodeCommunity[d.get(m)] = y; } if (l.compactCommunityIds(), (n.quality || "modularity").toLowerCase() === "cpm") { const u = typeof n.resolution == "number" ? n.resolution : 1; return (n.cpmMode || "unit") === "size-aware" ? it(l, i, u) : ot(l, i, u); } return nt(l, i); } function At(t) { if (typeof t == "number") return t | 0; if (typeof t == "string") { const o = Number(t); return Number.isFinite(o) ? o | 0 : Nt(t); } return 0; } function Nt(t) { let o = 2166136261; for (let n = 0; n < t.length; n++) o ^= t.charCodeAt(n), o = Math.imul(o, 16777619); return o >>> 0; } export { bt as detectClusters, Et as evaluateQuality };