ngraph.leiden
Version:
Leiden/Louvain community detection for ngraph.graph (JS)
663 lines (662 loc) • 24.2 kB
JavaScript
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
};