@odla-ai/kg 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,376 @@
1
+ // src/temporal/prng.ts
2
+ function hash32(s) {
3
+ let h = 2166136261;
4
+ for (let i = 0; i < s.length; i++) {
5
+ h ^= s.charCodeAt(i);
6
+ h = Math.imul(h, 16777619);
7
+ }
8
+ return h >>> 0;
9
+ }
10
+ function mulberry32(seed) {
11
+ let a = seed >>> 0;
12
+ return () => {
13
+ a = a + 1831565813 >>> 0;
14
+ let t = a;
15
+ t = Math.imul(t ^ t >>> 15, t | 1);
16
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
17
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
18
+ };
19
+ }
20
+ function shuffle(items, rand) {
21
+ const out = items.slice();
22
+ for (let i = out.length - 1; i > 0; i--) {
23
+ const j = Math.floor(rand() * (i + 1));
24
+ const tmp = out[i];
25
+ out[i] = out[j];
26
+ out[j] = tmp;
27
+ }
28
+ return out;
29
+ }
30
+
31
+ // src/temporal/time.ts
32
+ var DAY = 864e5;
33
+ var DATE_ONLY = /^(\d{4})-(\d{2})-(\d{2})$/;
34
+ function parseDateMs(v) {
35
+ if (typeof v === "number") return Number.isFinite(v) ? v : null;
36
+ if (typeof v !== "string") return null;
37
+ const m = DATE_ONLY.exec(v.trim());
38
+ if (m) {
39
+ const t2 = Date.UTC(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
40
+ return new Date(t2).toISOString().slice(0, 10) === m[0].trim() ? t2 : null;
41
+ }
42
+ const t = Date.parse(v);
43
+ return Number.isNaN(t) ? null : t;
44
+ }
45
+ function isoWeek(t) {
46
+ const d = new Date(t);
47
+ const midnight = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
48
+ const dow = new Date(midnight).getUTCDay() || 7;
49
+ const thursday = midnight + (4 - dow) * DAY;
50
+ const year = new Date(thursday).getUTCFullYear();
51
+ const week = Math.floor((thursday - Date.UTC(year, 0, 1)) / DAY / 7) + 1;
52
+ return { year, week };
53
+ }
54
+ function isoWeekStart(year, week) {
55
+ const jan4 = Date.UTC(year, 0, 4);
56
+ const dow = new Date(jan4).getUTCDay() || 7;
57
+ return jan4 - (dow - 1) * DAY + (week - 1) * 7 * DAY;
58
+ }
59
+ var pad2 = (n) => String(n).padStart(2, "0");
60
+ function bucketKey(t, grain) {
61
+ const d = new Date(t);
62
+ if (grain === "month") return `${d.getUTCFullYear()}-${pad2(d.getUTCMonth() + 1)}`;
63
+ if (grain === "quarter") return `${d.getUTCFullYear()}-Q${Math.floor(d.getUTCMonth() / 3) + 1}`;
64
+ const { year, week } = isoWeek(t);
65
+ return `${year}-W${pad2(week)}`;
66
+ }
67
+ function bucketFor(key) {
68
+ let m = /^(\d{4})-(\d{2})$/.exec(key);
69
+ if (m) {
70
+ const [y, mo] = [Number(m[1]), Number(m[2])];
71
+ return { key, start: Date.UTC(y, mo - 1, 1), end: Date.UTC(y, mo, 1) };
72
+ }
73
+ m = /^(\d{4})-Q([1-4])$/.exec(key);
74
+ if (m) {
75
+ const [y, q] = [Number(m[1]), Number(m[2])];
76
+ return { key, start: Date.UTC(y, (q - 1) * 3, 1), end: Date.UTC(y, q * 3, 1) };
77
+ }
78
+ m = /^(\d{4})-W(\d{2})$/.exec(key);
79
+ if (m) {
80
+ const start = isoWeekStart(Number(m[1]), Number(m[2]));
81
+ return { key, start, end: start + 7 * DAY };
82
+ }
83
+ throw new Error(`not a bucket key: ${key}`);
84
+ }
85
+ function bucketRange(from, to, grain) {
86
+ const out = [];
87
+ if (from > to) return out;
88
+ let cur = bucketFor(bucketKey(from, grain));
89
+ const last = bucketKey(to, grain);
90
+ for (; ; ) {
91
+ out.push(cur);
92
+ if (cur.key === last) return out;
93
+ cur = bucketFor(bucketKey(cur.end, grain));
94
+ }
95
+ }
96
+
97
+ // src/temporal/adjacency.ts
98
+ function nodeId(ref) {
99
+ return `${ref.type}:${ref.key}`;
100
+ }
101
+ function byNodeId(a, b) {
102
+ const ia = nodeId(a);
103
+ const ib = nodeId(b);
104
+ return ia < ib ? -1 : ia > ib ? 1 : 0;
105
+ }
106
+ function indexGraph(fragment) {
107
+ const nodes = /* @__PURE__ */ new Map();
108
+ const byType = /* @__PURE__ */ new Map();
109
+ for (const n of fragment.nodes) {
110
+ nodes.set(nodeId(n), n);
111
+ const list = byType.get(n.type);
112
+ list ? list.push(n) : byType.set(n.type, [n]);
113
+ }
114
+ const adj = /* @__PURE__ */ new Map();
115
+ for (const e of fragment.edges) {
116
+ const k = `${nodeId(e.from)}|${e.label}`;
117
+ const list = adj.get(k);
118
+ list ? list.push(e.to) : adj.set(k, [e.to]);
119
+ }
120
+ return {
121
+ node: (id) => nodes.get(id),
122
+ out: (id, label) => adj.get(`${id}|${label}`) ?? [],
123
+ nodesOf: (type) => byType.get(type) ?? []
124
+ };
125
+ }
126
+ function resolvePath(g, start, labels) {
127
+ let frontier = [start];
128
+ for (const label of labels) {
129
+ const seen = /* @__PURE__ */ new Set();
130
+ const next = [];
131
+ for (const ref of frontier) {
132
+ for (const target of g.out(nodeId(ref), label)) {
133
+ const id = nodeId(target);
134
+ if (!seen.has(id)) {
135
+ seen.add(id);
136
+ next.push(target);
137
+ }
138
+ }
139
+ }
140
+ frontier = next;
141
+ }
142
+ return frontier.slice().sort(byNodeId);
143
+ }
144
+
145
+ // src/temporal/communities.ts
146
+ function labelPropagation(nodes, edges, opts = {}) {
147
+ const { seed = 1, maxRounds = 20 } = opts;
148
+ const sorted = [...nodes].sort();
149
+ const labels = new Map(sorted.map((id) => [id, id]));
150
+ const neighbors = /* @__PURE__ */ new Map();
151
+ for (const e of edges) {
152
+ if (!labels.has(e.a) || !labels.has(e.b) || e.a === e.b) continue;
153
+ const w = e.weight ?? 1;
154
+ let listA = neighbors.get(e.a);
155
+ if (!listA) neighbors.set(e.a, listA = []);
156
+ listA.push({ id: e.b, weight: w });
157
+ let listB = neighbors.get(e.b);
158
+ if (!listB) neighbors.set(e.b, listB = []);
159
+ listB.push({ id: e.a, weight: w });
160
+ }
161
+ const rand = mulberry32(seed);
162
+ for (let round = 0; round < maxRounds; round++) {
163
+ const order = shuffle(sorted, rand);
164
+ let changed = false;
165
+ for (const id of order) {
166
+ const incident = neighbors.get(id);
167
+ if (!incident || incident.length === 0) continue;
168
+ const votes = /* @__PURE__ */ new Map();
169
+ for (const n of incident) {
170
+ const label = labels.get(n.id);
171
+ votes.set(label, (votes.get(label) ?? 0) + n.weight);
172
+ }
173
+ let best = [];
174
+ let bestWeight = -Infinity;
175
+ for (const [label, weight] of votes) {
176
+ if (weight > bestWeight) {
177
+ bestWeight = weight;
178
+ best = [label];
179
+ } else if (weight === bestWeight) {
180
+ best.push(label);
181
+ }
182
+ }
183
+ const current = labels.get(id);
184
+ if (best.includes(current)) continue;
185
+ best.sort();
186
+ const pick = best.length === 1 ? best[0] : best[Math.floor(rand() * best.length)];
187
+ labels.set(id, pick);
188
+ changed = true;
189
+ }
190
+ if (!changed) break;
191
+ }
192
+ const members = /* @__PURE__ */ new Map();
193
+ for (const [id, label] of labels) {
194
+ const list = members.get(label);
195
+ list ? list.push(id) : members.set(label, [id]);
196
+ }
197
+ const canonical = /* @__PURE__ */ new Map();
198
+ for (const [label, ids] of members) canonical.set(label, ids[0]);
199
+ return new Map(sorted.map((id) => [id, canonical.get(labels.get(id))]));
200
+ }
201
+
202
+ // src/temporal/lenses.ts
203
+ function reifiedBridgeTargets(fragment, opts) {
204
+ const bridgesOf = /* @__PURE__ */ new Map();
205
+ const targetsOf = /* @__PURE__ */ new Map();
206
+ for (const e of fragment.edges) {
207
+ if (e.from.type !== opts.reified) continue;
208
+ const to = `${e.to.type}:${e.to.key}`;
209
+ if (e.label === opts.bridgeLabel) (bridgesOf.get(e.from.key) ?? bridgesOf.set(e.from.key, []).get(e.from.key)).push(to);
210
+ if (e.label === opts.targetLabel) (targetsOf.get(e.from.key) ?? targetsOf.set(e.from.key, []).get(e.from.key)).push(to);
211
+ }
212
+ const out = /* @__PURE__ */ new Map();
213
+ for (const [reifiedKey, bridges] of bridgesOf) {
214
+ for (const bridge of bridges) {
215
+ for (const target of targetsOf.get(reifiedKey) ?? []) {
216
+ (out.get(bridge) ?? out.set(bridge, /* @__PURE__ */ new Set()).get(bridge)).add(target);
217
+ }
218
+ }
219
+ }
220
+ return out;
221
+ }
222
+ function directTargets(fragment, label) {
223
+ const out = /* @__PURE__ */ new Map();
224
+ for (const e of fragment.edges) {
225
+ if (e.label !== label) continue;
226
+ const from = `${e.from.type}:${e.from.key}`;
227
+ (out.get(from) ?? out.set(from, /* @__PURE__ */ new Set()).get(from)).add(`${e.to.type}:${e.to.key}`);
228
+ }
229
+ return out;
230
+ }
231
+ function composeTargets(ab, bc) {
232
+ const out = /* @__PURE__ */ new Map();
233
+ for (const [a, bs] of ab) {
234
+ for (const b of bs) {
235
+ for (const c of bc.get(b) ?? []) {
236
+ (out.get(a) ?? out.set(a, /* @__PURE__ */ new Set()).get(a)).add(c);
237
+ }
238
+ }
239
+ }
240
+ return out;
241
+ }
242
+ function projectBridges(bridges, opts = {}) {
243
+ const { maxPerBridge = 12, viaCap = 4 } = opts;
244
+ const acc = /* @__PURE__ */ new Map();
245
+ for (const [bridge, targetSet] of [...bridges.entries()].sort((x, y) => x[0] < y[0] ? -1 : 1)) {
246
+ const targets = [...targetSet].sort();
247
+ if (targets.length < 2 || targets.length > maxPerBridge) continue;
248
+ for (let i = 0; i < targets.length; i++) {
249
+ for (let j = i + 1; j < targets.length; j++) {
250
+ const key = `${targets[i]}|${targets[j]}`;
251
+ const hit = acc.get(key) ?? { a: targets[i], b: targets[j], w: 0, via: [] };
252
+ hit.w += 1;
253
+ if (hit.via.length < viaCap) hit.via.push(bridge);
254
+ acc.set(key, hit);
255
+ }
256
+ }
257
+ }
258
+ return [...acc.keys()].sort().map((k) => acc.get(k));
259
+ }
260
+ function timePairs(arrivals, opts = {}) {
261
+ const { k = 4, halfLifeDays = 30 } = opts;
262
+ const halfLife = halfLifeDays * 864e5;
263
+ const rows = [...arrivals.entries()].filter(([, t]) => Number.isFinite(t)).sort((x, y) => x[1] - y[1] || (x[0] < y[0] ? -1 : 1));
264
+ const acc = /* @__PURE__ */ new Map();
265
+ for (let i = 0; i < rows.length; i++) {
266
+ for (let j = i + 1; j < Math.min(rows.length, i + 1 + k); j++) {
267
+ const [idA, tA] = rows[i];
268
+ const [idB, tB] = rows[j];
269
+ const w = Math.pow(0.5, Math.abs(tB - tA) / halfLife);
270
+ if (w < 0.01) break;
271
+ const [a, b] = idA < idB ? [idA, idB] : [idB, idA];
272
+ acc.set(`${a}|${b}`, { a, b, w, via: [] });
273
+ }
274
+ }
275
+ return [...acc.keys()].sort().map((key) => acc.get(key));
276
+ }
277
+ function geoPairs(positions, opts = {}) {
278
+ const { k = 4, halfDist = 0.04 } = opts;
279
+ const rows = [...positions.entries()].sort((x, y) => x[0] < y[0] ? -1 : 1);
280
+ const acc = /* @__PURE__ */ new Map();
281
+ for (let i = 0; i < rows.length; i++) {
282
+ const dists = [];
283
+ for (let j = 0; j < rows.length; j++) {
284
+ if (i === j) continue;
285
+ const dx = rows[i][1].x - rows[j][1].x;
286
+ const dy = rows[i][1].y - rows[j][1].y;
287
+ dists.push({ j, d: Math.hypot(dx, dy) });
288
+ }
289
+ dists.sort((x, y) => x.d - y.d || x.j - y.j);
290
+ for (const { j, d } of dists.slice(0, k)) {
291
+ const w = Math.pow(0.5, d / halfDist);
292
+ if (w < 0.01) continue;
293
+ const [a, b] = rows[i][0] < rows[j][0] ? [rows[i][0], rows[j][0]] : [rows[j][0], rows[i][0]];
294
+ const key = `${a}|${b}`;
295
+ const prev = acc.get(key);
296
+ if (!prev || prev.w < w) acc.set(key, { a, b, w, via: [] });
297
+ }
298
+ }
299
+ return [...acc.keys()].sort().map((key) => acc.get(key));
300
+ }
301
+ function blendPairs(sets) {
302
+ const acc = /* @__PURE__ */ new Map();
303
+ for (const { pairs, weight } of sets) {
304
+ if (weight <= 0 || pairs.length === 0) continue;
305
+ const max = Math.max(...pairs.map((p) => p.w));
306
+ for (const p of pairs) {
307
+ const key = `${p.a}|${p.b}`;
308
+ const hit = acc.get(key) ?? { a: p.a, b: p.b, w: 0, via: [] };
309
+ hit.w += p.w / max * weight;
310
+ for (const v of p.via) if (hit.via.length < 6 && !hit.via.includes(v)) hit.via.push(v);
311
+ acc.set(key, hit);
312
+ }
313
+ }
314
+ return [...acc.keys()].sort().map((key) => acc.get(key));
315
+ }
316
+
317
+ // src/temporal/bridges.ts
318
+ function bridgingScores(edges, labels) {
319
+ const cross = /* @__PURE__ */ new Map();
320
+ const foreign = /* @__PURE__ */ new Map();
321
+ const touch = (id, otherLabel, w) => {
322
+ cross.set(id, (cross.get(id) ?? 0) + w);
323
+ (foreign.get(id) ?? foreign.set(id, /* @__PURE__ */ new Set()).get(id)).add(otherLabel);
324
+ };
325
+ for (const e of edges) {
326
+ const la = labels.get(e.a);
327
+ const lb = labels.get(e.b);
328
+ if (la === void 0 || lb === void 0 || la === lb) continue;
329
+ const w = e.weight ?? 1;
330
+ touch(e.a, lb, w);
331
+ touch(e.b, la, w);
332
+ }
333
+ let max = 0;
334
+ const raw = /* @__PURE__ */ new Map();
335
+ for (const [id, w] of cross) {
336
+ const r = w * foreign.get(id).size;
337
+ raw.set(id, r);
338
+ if (r > max) max = r;
339
+ }
340
+ const out = /* @__PURE__ */ new Map();
341
+ for (const [id] of labels) {
342
+ const r = raw.get(id) ?? 0;
343
+ const own = labels.get(id);
344
+ const groups = r > 0 ? [own, ...[...foreign.get(id)].sort()] : [own];
345
+ out.set(id, { score: max > 0 ? r / max : 0, groups });
346
+ }
347
+ return out;
348
+ }
349
+ function topBridges(bridging, n = 5) {
350
+ return [...bridging.entries()].filter(([, b]) => b.score > 0).sort((x, y) => y[1].score - x[1].score || (x[0] < y[0] ? -1 : 1)).slice(0, n).map(([id, b]) => ({ id, score: Math.round(b.score * 100) / 100, groups: b.groups }));
351
+ }
352
+
353
+ export {
354
+ parseDateMs,
355
+ bucketKey,
356
+ bucketFor,
357
+ bucketRange,
358
+ hash32,
359
+ mulberry32,
360
+ shuffle,
361
+ nodeId,
362
+ byNodeId,
363
+ indexGraph,
364
+ resolvePath,
365
+ labelPropagation,
366
+ reifiedBridgeTargets,
367
+ directTargets,
368
+ composeTargets,
369
+ projectBridges,
370
+ timePairs,
371
+ geoPairs,
372
+ blendPairs,
373
+ bridgingScores,
374
+ topBridges
375
+ };
376
+ //# sourceMappingURL=chunk-T6SYIVST.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/temporal/prng.ts","../src/temporal/time.ts","../src/temporal/adjacency.ts","../src/temporal/communities.ts","../src/temporal/lenses.ts","../src/temporal/bridges.ts"],"sourcesContent":["// Deterministic randomness for temporal analytics. Communities and layout\n// derive ALL randomness from node identity + an explicit seed, so results are\n// pure functions of their inputs — never of Map iteration or insertion order.\n\n/**\n * FNV-1a 32-bit hash of a string. Used to derive a per-identity PRNG seed\n * (`mulberry32(hash32(id) ^ seed)`), which makes node placement independent\n * of the order nodes arrive in.\n */\nexport function hash32(s: string): number {\n let h = 0x811c9dc5;\n for (let i = 0; i < s.length; i++) {\n h ^= s.charCodeAt(i);\n h = Math.imul(h, 0x01000193);\n }\n return h >>> 0;\n}\n\n/**\n * mulberry32: a tiny, fast, seedable PRNG returning floats in [0, 1).\n * The same seed always yields the same sequence — replayable layouts and\n * community assignments depend on this.\n */\nexport function mulberry32(seed: number): () => number {\n let a = seed >>> 0;\n return () => {\n a = (a + 0x6d2b79f5) >>> 0;\n let t = a;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\n/**\n * Fisher–Yates shuffle into a NEW array, driven by the supplied random source\n * (pass a seeded `mulberry32` for a deterministic permutation).\n */\nexport function shuffle<T>(items: readonly T[], rand: () => number): T[] {\n const out = items.slice();\n for (let i = out.length - 1; i > 0; i--) {\n const j = Math.floor(rand() * (i + 1));\n const tmp = out[i] as T; // i, j always in bounds\n out[i] = out[j] as T;\n out[j] = tmp;\n }\n return out;\n}\n","// UTC-only time bucketing. Date-only strings are read as UTC midnight and all\n// bucket math uses Date.UTC accessors — results never depend on the host zone.\n\n/** Supported bucketing granularities. */\nexport type TimeGrain = \"week\" | \"month\" | \"quarter\";\n\n/** One half-open time bucket: `start` inclusive, `end` exclusive (epoch ms). */\nexport interface TimeBucket {\n key: string;\n start: number;\n end: number;\n}\n\nconst DAY = 86_400_000;\nconst DATE_ONLY = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\n/**\n * Parse a date-ish value to epoch ms, or null if unparseable. Accepts\n * `\"YYYY-MM-DD\"` (UTC midnight, with real calendar validation — `2026-02-31`\n * is null), full ISO strings, and finite numbers (already epoch ms).\n */\nexport function parseDateMs(v: unknown): number | null {\n if (typeof v === \"number\") return Number.isFinite(v) ? v : null;\n if (typeof v !== \"string\") return null;\n const m = DATE_ONLY.exec(v.trim());\n if (m) {\n const t = Date.UTC(Number(m[1]), Number(m[2]) - 1, Number(m[3]));\n // JS rolls invalid components (\"2026-02-31\" → Mar 3); a real date\n // round-trips to the same YYYY-MM-DD.\n return new Date(t).toISOString().slice(0, 10) === m[0].trim() ? t : null;\n }\n const t = Date.parse(v);\n return Number.isNaN(t) ? null : t;\n}\n\n// ISO-8601 week: week 1 contains the year's first Thursday; weeks run Mon–Sun.\nfunction isoWeek(t: number): { year: number; week: number } {\n const d = new Date(t);\n const midnight = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());\n const dow = new Date(midnight).getUTCDay() || 7; // Mon=1 … Sun=7\n const thursday = midnight + (4 - dow) * DAY;\n const year = new Date(thursday).getUTCFullYear();\n const week = Math.floor((thursday - Date.UTC(year, 0, 1)) / DAY / 7) + 1;\n return { year, week };\n}\n\n// Monday (UTC midnight) of ISO week `week` of ISO year `year`: Jan 4 is\n// always inside week 1.\nfunction isoWeekStart(year: number, week: number): number {\n const jan4 = Date.UTC(year, 0, 4);\n const dow = new Date(jan4).getUTCDay() || 7;\n return jan4 - (dow - 1) * DAY + (week - 1) * 7 * DAY;\n}\n\nconst pad2 = (n: number) => String(n).padStart(2, \"0\");\n\n/** The bucket key containing epoch-ms `t`: `\"2026-07\"`, `\"2026-Q3\"`, or `\"2026-W29\"`. */\nexport function bucketKey(t: number, grain: TimeGrain): string {\n const d = new Date(t);\n if (grain === \"month\") return `${d.getUTCFullYear()}-${pad2(d.getUTCMonth() + 1)}`;\n if (grain === \"quarter\") return `${d.getUTCFullYear()}-Q${Math.floor(d.getUTCMonth() / 3) + 1}`;\n const { year, week } = isoWeek(t);\n return `${year}-W${pad2(week)}`;\n}\n\n/**\n * Expand a bucket key back to its half-open [start, end) range. Throws on a\n * key that matches no known grain format.\n */\nexport function bucketFor(key: string): TimeBucket {\n let m = /^(\\d{4})-(\\d{2})$/.exec(key);\n if (m) {\n const [y, mo] = [Number(m[1]), Number(m[2])];\n return { key, start: Date.UTC(y, mo - 1, 1), end: Date.UTC(y, mo, 1) };\n }\n m = /^(\\d{4})-Q([1-4])$/.exec(key);\n if (m) {\n const [y, q] = [Number(m[1]), Number(m[2])];\n return { key, start: Date.UTC(y, (q - 1) * 3, 1), end: Date.UTC(y, q * 3, 1) };\n }\n m = /^(\\d{4})-W(\\d{2})$/.exec(key);\n if (m) {\n const start = isoWeekStart(Number(m[1]), Number(m[2]));\n return { key, start, end: start + 7 * DAY };\n }\n throw new Error(`not a bucket key: ${key}`);\n}\n\n/**\n * Every bucket from the one containing `from` through the one containing `to`,\n * in order. Returns [] when from > to.\n */\nexport function bucketRange(from: number, to: number, grain: TimeGrain): TimeBucket[] {\n const out: TimeBucket[] = [];\n if (from > to) return out;\n let cur = bucketFor(bucketKey(from, grain));\n const last = bucketKey(to, grain);\n for (;;) {\n out.push(cur);\n if (cur.key === last) return out;\n cur = bucketFor(bucketKey(cur.end, grain));\n }\n}\n","// Indexed, read-only view of a GraphFragment for path walking. Everything the\n// temporal toolkit does starts from this — it never touches odla-db.\nimport type { GraphFragment, GraphNode } from \"../types\";\n\n/** A node reference: the `{type, key}` pair used by fragment edges. */\nexport interface NodeRef {\n type: string;\n key: string;\n}\n\n/** Canonical string id for a node reference: `\"type:key\"`. */\nexport type NodeId = string;\n\n/** Make the canonical `\"type:key\"` id for a node reference. */\nexport function nodeId(ref: NodeRef): NodeId {\n return `${ref.type}:${ref.key}`;\n}\n\n/** Compare two refs by canonical id (stable orderings everywhere). */\nexport function byNodeId(a: NodeRef, b: NodeRef): number {\n const ia = nodeId(a);\n const ib = nodeId(b);\n return ia < ib ? -1 : ia > ib ? 1 : 0;\n}\n\n/** Indexed view of one GraphFragment. */\nexport interface GraphIndex {\n /** The node for an id, if present in the fragment. */\n node(id: NodeId): GraphNode | undefined;\n /** Forward-label adjacency: targets of `label` edges out of `id`. */\n out(id: NodeId, label: string): NodeRef[];\n /** Every node of one entity type. */\n nodesOf(type: string): GraphNode[];\n}\n\n/** Build the index (one pass over nodes + edges). */\nexport function indexGraph(fragment: GraphFragment): GraphIndex {\n const nodes = new Map<NodeId, GraphNode>();\n const byType = new Map<string, GraphNode[]>();\n for (const n of fragment.nodes) {\n nodes.set(nodeId(n), n);\n const list = byType.get(n.type);\n list ? list.push(n) : byType.set(n.type, [n]);\n }\n const adj = new Map<string, NodeRef[]>();\n for (const e of fragment.edges) {\n const k = `${nodeId(e.from)}|${e.label}`;\n const list = adj.get(k);\n list ? list.push(e.to) : adj.set(k, [e.to]);\n }\n return {\n node: (id) => nodes.get(id),\n out: (id, label) => adj.get(`${id}|${label}`) ?? [],\n nodesOf: (type) => byType.get(type) ?? [],\n };\n}\n\n/**\n * Walk a sequence of forward edge labels from `start`, breadth-first, and\n * return the deduplicated frontier after the last hop, sorted by id.\n * An empty label list returns just `start`.\n */\nexport function resolvePath(g: GraphIndex, start: NodeRef, labels: readonly string[]): NodeRef[] {\n let frontier: NodeRef[] = [start];\n for (const label of labels) {\n const seen = new Set<NodeId>();\n const next: NodeRef[] = [];\n for (const ref of frontier) {\n for (const target of g.out(nodeId(ref), label)) {\n const id = nodeId(target);\n if (!seen.has(id)) {\n seen.add(id);\n next.push(target);\n }\n }\n }\n frontier = next;\n }\n return frontier.slice().sort(byNodeId);\n}\n","// Deterministic label propagation. Classic LPA needs random visit order to\n// break symmetry; here that randomness comes from one seeded shuffle stream,\n// so the same (nodes, edges, seed) always yields the same communities.\nimport { mulberry32, shuffle } from \"./prng\";\nimport type { NodeId } from \"./adjacency\";\n\n/**\n * Asynchronous label propagation with deterministic (seeded) tie-breaking:\n * - labels start as each node's own id;\n * - each round visits nodes in a seeded-shuffled order (one PRNG stream\n * reused across rounds) and adopts the label with the greatest total\n * incident edge weight; if the node's CURRENT label ties for the max it is\n * kept, otherwise a tied max is picked via the same seeded stream (a\n * lexicographic tie-break would systematically bleed communities toward\n * alphabetically small ids — verified on the two-triangles fixture);\n * - stops on a round with no change, or after `maxRounds`;\n * - finally each community's label is canonicalized to its smallest member\n * id, so the output is independent of propagation history.\n * Isolated nodes keep their own label (singleton communities).\n */\nexport function labelPropagation(\n nodes: readonly NodeId[],\n edges: ReadonlyArray<{ a: NodeId; b: NodeId; weight?: number }>,\n opts: { seed?: number; maxRounds?: number } = {},\n): Map<NodeId, string> {\n const { seed = 1, maxRounds = 20 } = opts;\n const sorted = [...nodes].sort();\n const labels = new Map<NodeId, string>(sorted.map((id) => [id, id]));\n\n const neighbors = new Map<NodeId, Array<{ id: NodeId; weight: number }>>();\n for (const e of edges) {\n if (!labels.has(e.a) || !labels.has(e.b) || e.a === e.b) continue;\n const w = e.weight ?? 1;\n let listA = neighbors.get(e.a);\n if (!listA) neighbors.set(e.a, (listA = []));\n listA.push({ id: e.b, weight: w });\n let listB = neighbors.get(e.b);\n if (!listB) neighbors.set(e.b, (listB = []));\n listB.push({ id: e.a, weight: w });\n }\n\n const rand = mulberry32(seed);\n for (let round = 0; round < maxRounds; round++) {\n const order = shuffle(sorted, rand);\n let changed = false;\n for (const id of order) {\n const incident = neighbors.get(id);\n if (!incident || incident.length === 0) continue;\n const votes = new Map<string, number>();\n for (const n of incident) {\n const label = labels.get(n.id)!;\n votes.set(label, (votes.get(label) ?? 0) + n.weight);\n }\n let best: string[] = [];\n let bestWeight = -Infinity;\n for (const [label, weight] of votes) {\n if (weight > bestWeight) {\n bestWeight = weight;\n best = [label];\n } else if (weight === bestWeight) {\n best.push(label);\n }\n }\n const current = labels.get(id)!;\n if (best.includes(current)) continue; // keep on tie — stability first\n best.sort();\n const pick = best.length === 1 ? best[0]! : best[Math.floor(rand() * best.length)]!;\n labels.set(id, pick);\n changed = true;\n }\n if (!changed) break;\n }\n\n // Canonicalize: community label = smallest member id.\n const members = new Map<string, NodeId[]>();\n for (const [id, label] of labels) {\n const list = members.get(label);\n list ? list.push(id) : members.set(label, [id]);\n }\n const canonical = new Map<string, string>();\n // Members collect in `sorted` iteration order, so ids[0] is the minimum.\n for (const [label, ids] of members) canonical.set(label, ids[0]!);\n return new Map(sorted.map((id) => [id, canonical.get(labels.get(id)!)!]));\n}\n","// Connection lenses: project a heterogeneous graph onto ONE node universe\n// (companies, people, places…) under a chosen relatedness — shared bridges\n// (people, investors), spatial proximity, temporal cohort — and blend several\n// lenses into the weighted edge set a layout/community pass consumes. Pure\n// and deterministic; the viewer re-runs these live as sliders move.\nimport type { GraphFragment } from \"../types\";\n\n/** A 2-D point in a normalized layout/map space (for the geo proximity lens). */\nexport interface XY {\n x: number;\n y: number;\n}\n\n/** One undirected weighted pair, with (capped) bridging node ids as evidence. */\nexport interface WeightedPair {\n a: string;\n b: string;\n w: number;\n via: string[];\n}\n\n/**\n * Bridge → target sets through a REIFIED relationship node (affiliation,\n * funding_round, record): every reified node with a `bridgeLabel` edge to the\n * bridge and a `targetLabel` edge to a target contributes that target to the\n * bridge's set. Ids are `type:key`.\n */\nexport function reifiedBridgeTargets(\n fragment: GraphFragment,\n opts: { reified: string; bridgeLabel: string; targetLabel: string },\n): Map<string, Set<string>> {\n const bridgesOf = new Map<string, string[]>(); // a round can have several investors\n const targetsOf = new Map<string, string[]>();\n for (const e of fragment.edges) {\n if (e.from.type !== opts.reified) continue;\n const to = `${e.to.type}:${e.to.key}`;\n if (e.label === opts.bridgeLabel) (bridgesOf.get(e.from.key) ?? bridgesOf.set(e.from.key, []).get(e.from.key))!.push(to);\n if (e.label === opts.targetLabel) (targetsOf.get(e.from.key) ?? targetsOf.set(e.from.key, []).get(e.from.key))!.push(to);\n }\n const out = new Map<string, Set<string>>();\n for (const [reifiedKey, bridges] of bridgesOf) {\n for (const bridge of bridges) {\n for (const target of targetsOf.get(reifiedKey) ?? []) {\n (out.get(bridge) ?? out.set(bridge, new Set()).get(bridge))!.add(target);\n }\n }\n }\n return out;\n}\n\n/** Direct-edge targets: `from` node id → set of `to` node ids for one label. */\nexport function directTargets(fragment: GraphFragment, label: string): Map<string, Set<string>> {\n const out = new Map<string, Set<string>>();\n for (const e of fragment.edges) {\n if (e.label !== label) continue;\n const from = `${e.from.type}:${e.from.key}`;\n (out.get(from) ?? out.set(from, new Set()).get(from))!.add(`${e.to.type}:${e.to.key}`);\n }\n return out;\n}\n\n/** Compose A→B with B→C into A→C (e.g. person→companies ∘ company→counties). */\nexport function composeTargets(\n ab: Map<string, Set<string>>,\n bc: Map<string, Set<string>>,\n): Map<string, Set<string>> {\n const out = new Map<string, Set<string>>();\n for (const [a, bs] of ab) {\n for (const b of bs) {\n for (const c of bc.get(b) ?? []) {\n (out.get(a) ?? out.set(a, new Set()).get(a))!.add(c);\n }\n }\n }\n return out;\n}\n\n/**\n * The bipartite projection: targets sharing a bridge become pairs, weight =\n * number of distinct shared bridges. `maxPerBridge` skips promiscuous hubs\n * (a bridge touching 40 targets says little about any pair). Deterministic\n * pair order (a < b, then sorted).\n */\nexport function projectBridges(\n bridges: Map<string, Set<string>>,\n opts: { maxPerBridge?: number; viaCap?: number } = {},\n): WeightedPair[] {\n const { maxPerBridge = 12, viaCap = 4 } = opts;\n const acc = new Map<string, { a: string; b: string; w: number; via: string[] }>();\n for (const [bridge, targetSet] of [...bridges.entries()].sort((x, y) => (x[0] < y[0] ? -1 : 1))) {\n const targets = [...targetSet].sort();\n if (targets.length < 2 || targets.length > maxPerBridge) continue;\n for (let i = 0; i < targets.length; i++) {\n for (let j = i + 1; j < targets.length; j++) {\n const key = `${targets[i]}|${targets[j]}`;\n const hit = acc.get(key) ?? { a: targets[i]!, b: targets[j]!, w: 0, via: [] };\n hit.w += 1;\n if (hit.via.length < viaCap) hit.via.push(bridge);\n acc.set(key, hit);\n }\n }\n }\n return [...acc.keys()].sort().map((k) => acc.get(k)!);\n}\n\n/**\n * Temporal cohort pairs: each node links to its k nearest neighbors in\n * arrival time, weight decaying with the gap (0.5 per halfLife). Nodes\n * without a date contribute nothing.\n */\nexport function timePairs(\n arrivals: Map<string, number>,\n opts: { k?: number; halfLifeDays?: number } = {},\n): WeightedPair[] {\n const { k = 4, halfLifeDays = 30 } = opts;\n const halfLife = halfLifeDays * 86_400_000;\n const rows = [...arrivals.entries()].filter(([, t]) => Number.isFinite(t)).sort((x, y) => x[1] - y[1] || (x[0] < y[0] ? -1 : 1));\n const acc = new Map<string, WeightedPair>();\n for (let i = 0; i < rows.length; i++) {\n for (let j = i + 1; j < Math.min(rows.length, i + 1 + k); j++) {\n const [idA, tA] = rows[i]!;\n const [idB, tB] = rows[j]!;\n const w = Math.pow(0.5, Math.abs(tB - tA) / halfLife);\n if (w < 0.01) break; // sorted by time — later neighbors are only farther\n const [a, b] = idA < idB ? [idA, idB] : [idB, idA];\n acc.set(`${a}|${b}`, { a, b, w, via: [] }); // i<j scan visits each pair once\n }\n }\n return [...acc.keys()].sort().map((key) => acc.get(key)!);\n}\n\n/**\n * Spatial proximity pairs: k nearest neighbors in normalized map space,\n * weight decaying with distance (0.5 per halfDist). Nodes without a\n * position contribute nothing. O(n²) — fine for the ≤1k-node universes\n * lenses operate on.\n */\nexport function geoPairs(\n positions: Map<string, XY>,\n opts: { k?: number; halfDist?: number } = {},\n): WeightedPair[] {\n const { k = 4, halfDist = 0.04 } = opts;\n const rows = [...positions.entries()].sort((x, y) => (x[0] < y[0] ? -1 : 1));\n const acc = new Map<string, WeightedPair>();\n for (let i = 0; i < rows.length; i++) {\n const dists: Array<{ j: number; d: number }> = [];\n for (let j = 0; j < rows.length; j++) {\n if (i === j) continue;\n const dx = rows[i]![1].x - rows[j]![1].x;\n const dy = rows[i]![1].y - rows[j]![1].y;\n dists.push({ j, d: Math.hypot(dx, dy) });\n }\n dists.sort((x, y) => x.d - y.d || x.j - y.j);\n for (const { j, d } of dists.slice(0, k)) {\n const w = Math.pow(0.5, d / halfDist);\n if (w < 0.01) continue;\n const [a, b] = rows[i]![0] < rows[j]![0] ? [rows[i]![0], rows[j]![0]] : [rows[j]![0], rows[i]![0]];\n const key = `${a}|${b}`;\n const prev = acc.get(key);\n if (!prev || prev.w < w) acc.set(key, { a, b, w, via: [] });\n }\n }\n return [...acc.keys()].sort().map((key) => acc.get(key)!);\n}\n\n/**\n * Blend lens edge sets: each set is normalized to a max weight of 1 (a lens\n * with big raw counts must not drown the others), scaled by its slider\n * weight, and summed per pair. Zero-weight lenses drop out entirely.\n */\nexport function blendPairs(sets: Array<{ pairs: WeightedPair[]; weight: number }>): WeightedPair[] {\n const acc = new Map<string, WeightedPair>();\n for (const { pairs, weight } of sets) {\n if (weight <= 0 || pairs.length === 0) continue;\n const max = Math.max(...pairs.map((p) => p.w));\n for (const p of pairs) {\n const key = `${p.a}|${p.b}`;\n const hit = acc.get(key) ?? { a: p.a, b: p.b, w: 0, via: [] };\n hit.w += (p.w / max) * weight;\n for (const v of p.via) if (hit.via.length < 6 && !hit.via.includes(v)) hit.via.push(v);\n acc.set(key, hit);\n }\n }\n return [...acc.keys()].sort().map((key) => acc.get(key)!);\n}\n","// Brokerage: which nodes connect otherwise-distinct groups? Scored against\n// the community partition (labelPropagation) already computed per frame:\n// a node's bridging weight is its edge weight INTO foreign communities,\n// amplified by how many distinct groups it touches. Pure and cheap (O(E))\n// — cheap enough to recompute every frame of a replay.\nimport type { NodeId } from \"./adjacency\";\n\n/** One node's brokerage: normalized score + the communities it connects. */\nexport interface Bridging {\n /** 0..1, 1 = the frame's strongest connector. */\n score: number;\n /** Communities this node touches through its edges (own community first). */\n groups: string[];\n}\n\n/**\n * Score every node's brokerage against a community partition. Edges inside a\n * community contribute nothing; an edge to a foreign community contributes\n * its weight, and the total is multiplied by the number of DISTINCT foreign\n * communities — a node wiring three groups together outranks one with the\n * same raw weight into a single neighbor group. Scores are normalized to\n * the frame's max (empty/one-community frames → all zeros).\n */\nexport function bridgingScores(\n edges: ReadonlyArray<{ a: NodeId; b: NodeId; weight?: number }>,\n labels: Map<NodeId, string>,\n): Map<NodeId, Bridging> {\n const cross = new Map<NodeId, number>();\n const foreign = new Map<NodeId, Set<string>>();\n const touch = (id: NodeId, otherLabel: string, w: number) => {\n cross.set(id, (cross.get(id) ?? 0) + w);\n (foreign.get(id) ?? foreign.set(id, new Set()).get(id))!.add(otherLabel);\n };\n for (const e of edges) {\n const la = labels.get(e.a);\n const lb = labels.get(e.b);\n if (la === undefined || lb === undefined || la === lb) continue;\n const w = e.weight ?? 1;\n touch(e.a, lb, w);\n touch(e.b, la, w);\n }\n let max = 0;\n const raw = new Map<NodeId, number>();\n for (const [id, w] of cross) {\n const r = w * foreign.get(id)!.size;\n raw.set(id, r);\n if (r > max) max = r;\n }\n const out = new Map<NodeId, Bridging>();\n for (const [id] of labels) {\n const r = raw.get(id) ?? 0;\n const own = labels.get(id)!;\n const groups = r > 0 ? [own, ...[...foreign.get(id)!].sort()] : [own];\n out.set(id, { score: max > 0 ? r / max : 0, groups });\n }\n return out;\n}\n\n/** The frame's strongest connectors, ranked (ties: id order). */\nexport function topBridges(\n bridging: Map<NodeId, Bridging>,\n n = 5,\n): Array<{ id: NodeId; score: number; groups: string[] }> {\n return [...bridging.entries()]\n .filter(([, b]) => b.score > 0)\n .sort((x, y) => y[1].score - x[1].score || (x[0] < y[0] ? -1 : 1))\n .slice(0, n)\n .map(([id, b]) => ({ id, score: Math.round(b.score * 100) / 100, groups: b.groups }));\n}\n"],"mappings":"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","names":["t"]}