graphwise 1.3.2 → 1.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.
Files changed (123) hide show
  1. package/README.md +72 -1
  2. package/dist/__test__/fixtures/graphs/city-suburban-village.d.ts +3 -0
  3. package/dist/__test__/fixtures/graphs/city-suburban-village.d.ts.map +1 -0
  4. package/dist/__test__/fixtures/graphs/city-village.d.ts +3 -0
  5. package/dist/__test__/fixtures/graphs/city-village.d.ts.map +1 -0
  6. package/dist/__test__/fixtures/graphs/index.d.ts +13 -0
  7. package/dist/__test__/fixtures/graphs/index.d.ts.map +1 -0
  8. package/dist/__test__/fixtures/graphs/quality-vs-popularity.d.ts +3 -0
  9. package/dist/__test__/fixtures/graphs/quality-vs-popularity.d.ts.map +1 -0
  10. package/dist/__test__/fixtures/graphs/social-hub.d.ts +3 -0
  11. package/dist/__test__/fixtures/graphs/social-hub.d.ts.map +1 -0
  12. package/dist/__test__/fixtures/graphs/three-community.d.ts +3 -0
  13. package/dist/__test__/fixtures/graphs/three-community.d.ts.map +1 -0
  14. package/dist/__test__/fixtures/graphs/two-department.d.ts +3 -0
  15. package/dist/__test__/fixtures/graphs/two-department.d.ts.map +1 -0
  16. package/dist/__test__/fixtures/graphs/typed-entity.d.ts +3 -0
  17. package/dist/__test__/fixtures/graphs/typed-entity.d.ts.map +1 -0
  18. package/dist/__test__/fixtures/helpers.d.ts +66 -0
  19. package/dist/__test__/fixtures/helpers.d.ts.map +1 -0
  20. package/dist/__test__/fixtures/helpers.unit.test.d.ts +7 -0
  21. package/dist/__test__/fixtures/helpers.unit.test.d.ts.map +1 -0
  22. package/dist/__test__/fixtures/index.d.ts +10 -0
  23. package/dist/__test__/fixtures/index.d.ts.map +1 -0
  24. package/dist/__test__/fixtures/types.d.ts +35 -0
  25. package/dist/__test__/fixtures/types.d.ts.map +1 -0
  26. package/dist/expansion/dome.d.ts.map +1 -1
  27. package/dist/expansion/dome.integration.test.d.ts +18 -0
  28. package/dist/expansion/dome.integration.test.d.ts.map +1 -0
  29. package/dist/expansion/edge.d.ts +3 -3
  30. package/dist/expansion/edge.d.ts.map +1 -1
  31. package/dist/expansion/edge.integration.test.d.ts +11 -0
  32. package/dist/expansion/edge.integration.test.d.ts.map +1 -0
  33. package/dist/expansion/flux.d.ts +25 -0
  34. package/dist/expansion/flux.d.ts.map +1 -0
  35. package/dist/expansion/flux.integration.test.d.ts +14 -0
  36. package/dist/expansion/flux.integration.test.d.ts.map +1 -0
  37. package/dist/expansion/flux.unit.test.d.ts +2 -0
  38. package/dist/expansion/flux.unit.test.d.ts.map +1 -0
  39. package/dist/expansion/fuse.d.ts +28 -0
  40. package/dist/expansion/fuse.d.ts.map +1 -0
  41. package/dist/expansion/fuse.integration.test.d.ts +15 -0
  42. package/dist/expansion/fuse.integration.test.d.ts.map +1 -0
  43. package/dist/expansion/fuse.unit.test.d.ts +2 -0
  44. package/dist/expansion/fuse.unit.test.d.ts.map +1 -0
  45. package/dist/expansion/hae.d.ts +7 -7
  46. package/dist/expansion/hae.d.ts.map +1 -1
  47. package/dist/expansion/hae.integration.test.d.ts +11 -0
  48. package/dist/expansion/hae.integration.test.d.ts.map +1 -0
  49. package/dist/expansion/index.d.ts +6 -0
  50. package/dist/expansion/index.d.ts.map +1 -1
  51. package/dist/expansion/lace.d.ts +22 -0
  52. package/dist/expansion/lace.d.ts.map +1 -0
  53. package/dist/expansion/lace.integration.test.d.ts +14 -0
  54. package/dist/expansion/lace.integration.test.d.ts.map +1 -0
  55. package/dist/expansion/lace.unit.test.d.ts +2 -0
  56. package/dist/expansion/lace.unit.test.d.ts.map +1 -0
  57. package/dist/expansion/maze.d.ts +3 -13
  58. package/dist/expansion/maze.d.ts.map +1 -1
  59. package/dist/expansion/maze.integration.test.d.ts +11 -0
  60. package/dist/expansion/maze.integration.test.d.ts.map +1 -0
  61. package/dist/expansion/pipe.d.ts +3 -3
  62. package/dist/expansion/pipe.d.ts.map +1 -1
  63. package/dist/expansion/pipe.integration.test.d.ts +12 -0
  64. package/dist/expansion/pipe.integration.test.d.ts.map +1 -0
  65. package/dist/expansion/reach.d.ts +4 -14
  66. package/dist/expansion/reach.d.ts.map +1 -1
  67. package/dist/expansion/reach.integration.test.d.ts +9 -0
  68. package/dist/expansion/reach.integration.test.d.ts.map +1 -0
  69. package/dist/expansion/sage.d.ts +5 -13
  70. package/dist/expansion/sage.d.ts.map +1 -1
  71. package/dist/expansion/sage.integration.test.d.ts +9 -0
  72. package/dist/expansion/sage.integration.test.d.ts.map +1 -0
  73. package/dist/expansion/sift.d.ts +26 -0
  74. package/dist/expansion/sift.d.ts.map +1 -0
  75. package/dist/expansion/sift.integration.test.d.ts +13 -0
  76. package/dist/expansion/sift.integration.test.d.ts.map +1 -0
  77. package/dist/expansion/sift.unit.test.d.ts +2 -0
  78. package/dist/expansion/sift.unit.test.d.ts.map +1 -0
  79. package/dist/expansion/tide.d.ts +15 -0
  80. package/dist/expansion/tide.d.ts.map +1 -0
  81. package/dist/expansion/tide.integration.test.d.ts +14 -0
  82. package/dist/expansion/tide.integration.test.d.ts.map +1 -0
  83. package/dist/expansion/tide.unit.test.d.ts +2 -0
  84. package/dist/expansion/tide.unit.test.d.ts.map +1 -0
  85. package/dist/expansion/warp.d.ts +15 -0
  86. package/dist/expansion/warp.d.ts.map +1 -0
  87. package/dist/expansion/warp.integration.test.d.ts +13 -0
  88. package/dist/expansion/warp.integration.test.d.ts.map +1 -0
  89. package/dist/expansion/warp.unit.test.d.ts +2 -0
  90. package/dist/expansion/warp.unit.test.d.ts.map +1 -0
  91. package/dist/graph/adjacency-map.d.ts.map +1 -1
  92. package/dist/graph/index.cjs +7 -0
  93. package/dist/graph/index.cjs.map +1 -1
  94. package/dist/graph/index.js +7 -0
  95. package/dist/graph/index.js.map +1 -1
  96. package/dist/index/index.cjs +287 -42
  97. package/dist/index/index.cjs.map +1 -1
  98. package/dist/index/index.js +282 -43
  99. package/dist/index/index.js.map +1 -1
  100. package/dist/ranking/mi/etch.integration.test.d.ts +2 -0
  101. package/dist/ranking/mi/etch.integration.test.d.ts.map +1 -0
  102. package/dist/ranking/mi/notch.integration.test.d.ts +2 -0
  103. package/dist/ranking/mi/notch.integration.test.d.ts.map +1 -0
  104. package/dist/ranking/mi/scale.d.ts.map +1 -1
  105. package/dist/ranking/mi/scale.integration.test.d.ts +2 -0
  106. package/dist/ranking/mi/scale.integration.test.d.ts.map +1 -0
  107. package/dist/ranking/mi/skew.integration.test.d.ts +2 -0
  108. package/dist/ranking/mi/skew.integration.test.d.ts.map +1 -0
  109. package/dist/ranking/mi/span.integration.test.d.ts +2 -0
  110. package/dist/ranking/mi/span.integration.test.d.ts.map +1 -0
  111. package/dist/ranking/parse.integration.test.d.ts +10 -0
  112. package/dist/ranking/parse.integration.test.d.ts.map +1 -0
  113. package/dist/structures/index.cjs +12 -2
  114. package/dist/structures/index.cjs.map +1 -1
  115. package/dist/structures/index.js +12 -2
  116. package/dist/structures/index.js.map +1 -1
  117. package/dist/structures/priority-queue.d.ts +4 -2
  118. package/dist/structures/priority-queue.d.ts.map +1 -1
  119. package/dist/utils/index.cjs +76 -77
  120. package/dist/utils/index.cjs.map +1 -1
  121. package/dist/utils/index.js +76 -77
  122. package/dist/utils/index.js.map +1 -1
  123. package/package.json +1 -1
@@ -235,7 +235,7 @@ function emptyResult(algorithm, startTime) {
235
235
  */
236
236
  function dome(graph, seeds, config) {
237
237
  const domePriority = (nodeId, context) => {
238
- return graph.degree(nodeId);
238
+ return context.degree;
239
239
  };
240
240
  return base(graph, seeds, {
241
241
  ...config,
@@ -247,7 +247,7 @@ function dome(graph, seeds, config) {
247
247
  */
248
248
  function domeHighDegree(graph, seeds, config) {
249
249
  const domePriority = (nodeId, context) => {
250
- return -graph.degree(nodeId);
250
+ return -context.degree;
251
251
  };
252
252
  return base(graph, seeds, {
253
253
  ...config,
@@ -256,23 +256,26 @@ function domeHighDegree(graph, seeds, config) {
256
256
  }
257
257
  //#endregion
258
258
  //#region src/expansion/edge.ts
259
+ var EPSILON$1 = 1e-10;
259
260
  /**
260
- * EDGE priority function.
261
- *
262
- * Priority = degree(source) + degree(target)
263
- * Lower values = higher priority (explored first)
261
+ * Priority function using local type entropy.
262
+ * Lower values = higher priority (expanded first).
264
263
  */
265
264
  function edgePriority(nodeId, context) {
266
265
  const graph = context.graph;
267
- let totalDegree = context.degree;
268
- for (const neighbour of graph.neighbours(nodeId)) totalDegree += graph.degree(neighbour);
269
- return totalDegree;
266
+ const neighbours = graph.neighbours(nodeId);
267
+ const neighbourTypes = [];
268
+ for (const neighbour of neighbours) {
269
+ const node = graph.getNode(neighbour);
270
+ neighbourTypes.push(node?.type ?? "default");
271
+ }
272
+ return 1 / (localTypeEntropy(neighbourTypes) + EPSILON$1) * Math.log(context.degree + 1);
270
273
  }
271
274
  /**
272
- * Run EDGE expansion algorithm.
275
+ * Run EDGE expansion (Entropy-Driven Graph Expansion).
273
276
  *
274
- * Expands from seeds prioritising low-degree edges first.
275
- * Useful for avoiding hubs and exploring sparse regions.
277
+ * Discovers paths by prioritising nodes with diverse neighbour types,
278
+ * deferring nodes with homogeneous neighbourhoods.
276
279
  *
277
280
  * @param graph - Source graph
278
281
  * @param seeds - Seed nodes for expansion
@@ -286,6 +289,123 @@ function edge(graph, seeds, config) {
286
289
  });
287
290
  }
288
291
  //#endregion
292
+ //#region src/expansion/hae.ts
293
+ var EPSILON = 1e-10;
294
+ /**
295
+ * Default type mapper - uses node.type property.
296
+ */
297
+ function defaultTypeMapper(node) {
298
+ return node.type ?? "default";
299
+ }
300
+ /**
301
+ * Create a priority function using the given type mapper.
302
+ */
303
+ function createHAEPriority(typeMapper) {
304
+ return function haePriority(nodeId, context) {
305
+ const graph = context.graph;
306
+ const neighbours = graph.neighbours(nodeId);
307
+ const neighbourTypes = [];
308
+ for (const neighbour of neighbours) {
309
+ const node = graph.getNode(neighbour);
310
+ if (node !== void 0) neighbourTypes.push(typeMapper(node));
311
+ }
312
+ return 1 / (localTypeEntropy(neighbourTypes) + EPSILON) * Math.log(context.degree + 1);
313
+ };
314
+ }
315
+ /**
316
+ * Run HAE expansion (Heterogeneity-Aware Expansion).
317
+ *
318
+ * Discovers paths by prioritising nodes with diverse neighbour types,
319
+ * using a custom type mapper for flexible type extraction.
320
+ *
321
+ * @param graph - Source graph
322
+ * @param seeds - Seed nodes for expansion
323
+ * @param config - HAE configuration with optional typeMapper
324
+ * @returns Expansion result with discovered paths
325
+ */
326
+ function hae(graph, seeds, config) {
327
+ const typeMapper = config?.typeMapper ?? defaultTypeMapper;
328
+ return base(graph, seeds, {
329
+ ...config,
330
+ priority: createHAEPriority(typeMapper)
331
+ });
332
+ }
333
+ //#endregion
334
+ //#region src/expansion/pipe.ts
335
+ /**
336
+ * Priority function using path potential.
337
+ * Lower values = higher priority (expanded first).
338
+ *
339
+ * Path potential measures how many of a node's neighbours have been
340
+ * visited by OTHER frontiers (not the current frontier).
341
+ */
342
+ function pipePriority(nodeId, context) {
343
+ const graph = context.graph;
344
+ const neighbours = new Set(graph.neighbours(nodeId));
345
+ let pathPotential = 0;
346
+ for (const [visitedId, frontierIdx] of context.visitedByFrontier) if (frontierIdx !== context.frontierIndex && neighbours.has(visitedId)) pathPotential++;
347
+ return context.degree / (1 + pathPotential);
348
+ }
349
+ /**
350
+ * Run PIPE expansion (Path-Potential Informed Priority Expansion).
351
+ *
352
+ * Discovers paths by prioritising nodes that bridge multiple frontiers,
353
+ * identifying connecting points between seed regions.
354
+ *
355
+ * @param graph - Source graph
356
+ * @param seeds - Seed nodes for expansion
357
+ * @param config - Expansion configuration
358
+ * @returns Expansion result with discovered paths
359
+ */
360
+ function pipe(graph, seeds, config) {
361
+ return base(graph, seeds, {
362
+ ...config,
363
+ priority: pipePriority
364
+ });
365
+ }
366
+ //#endregion
367
+ //#region src/expansion/sage.ts
368
+ /**
369
+ * Run SAGE expansion algorithm.
370
+ *
371
+ * Salience-aware multi-frontier expansion with two phases:
372
+ * - Phase 1: Degree-based priority (early exploration)
373
+ * - Phase 2: Salience feedback (path-aware frontier steering)
374
+ *
375
+ * @param graph - Source graph
376
+ * @param seeds - Seed nodes for expansion
377
+ * @param config - Expansion configuration
378
+ * @returns Expansion result with discovered paths
379
+ */
380
+ function sage(graph, seeds, config) {
381
+ const salienceCounts = /* @__PURE__ */ new Map();
382
+ let inPhase2 = false;
383
+ let lastPathCount = 0;
384
+ /**
385
+ * SAGE priority function with phase transition logic.
386
+ */
387
+ function sagePriority(nodeId, context) {
388
+ const pathCount = context.discoveredPaths.length;
389
+ if (pathCount > 0 && !inPhase2) {
390
+ inPhase2 = true;
391
+ for (const path of context.discoveredPaths) for (const node of path.nodes) salienceCounts.set(node, (salienceCounts.get(node) ?? 0) + 1);
392
+ }
393
+ if (pathCount > lastPathCount) {
394
+ for (let i = lastPathCount; i < pathCount; i++) {
395
+ const path = context.discoveredPaths[i];
396
+ if (path !== void 0) for (const node of path.nodes) salienceCounts.set(node, (salienceCounts.get(node) ?? 0) + 1);
397
+ }
398
+ lastPathCount = pathCount;
399
+ }
400
+ if (!inPhase2) return Math.log(context.degree + 1);
401
+ return -((salienceCounts.get(nodeId) ?? 0) * 1e3 - context.degree);
402
+ }
403
+ return base(graph, seeds, {
404
+ ...config,
405
+ priority: sagePriority
406
+ });
407
+ }
408
+ //#endregion
289
409
  //#region src/ranking/mi/jaccard.ts
290
410
  /**
291
411
  * Compute Jaccard similarity between neighbourhoods of two nodes.
@@ -304,14 +424,133 @@ function jaccard(graph, source, target, config) {
304
424
  return Math.max(epsilon, score);
305
425
  }
306
426
  //#endregion
307
- //#region src/expansion/hae.ts
427
+ //#region src/expansion/reach.ts
308
428
  /**
309
- * HAE priority function.
429
+ * Run REACH expansion algorithm.
430
+ *
431
+ * Mutual information-aware multi-frontier expansion with two phases:
432
+ * - Phase 1: Degree-based priority (early exploration)
433
+ * - Phase 2: Structural similarity feedback (MI-guided frontier steering)
434
+ *
435
+ * @param graph - Source graph
436
+ * @param seeds - Seed nodes for expansion
437
+ * @param config - Expansion configuration
438
+ * @returns Expansion result with discovered paths
439
+ */
440
+ function reach(graph, seeds, config) {
441
+ let inPhase2 = false;
442
+ /**
443
+ * REACH priority function with MI estimation.
444
+ */
445
+ function reachPriority(nodeId, context) {
446
+ if (context.discoveredPaths.length > 0 && !inPhase2) inPhase2 = true;
447
+ if (!inPhase2) return Math.log(context.degree + 1);
448
+ let totalMI = 0;
449
+ let endpointCount = 0;
450
+ for (const path of context.discoveredPaths) {
451
+ const fromNodeId = path.fromSeed.id;
452
+ const toNodeId = path.toSeed.id;
453
+ totalMI += jaccard(graph, nodeId, fromNodeId);
454
+ totalMI += jaccard(graph, nodeId, toNodeId);
455
+ endpointCount += 2;
456
+ }
457
+ const miHat = endpointCount > 0 ? totalMI / endpointCount : 0;
458
+ return Math.log(context.degree + 1) * (1 - miHat);
459
+ }
460
+ return base(graph, seeds, {
461
+ ...config,
462
+ priority: reachPriority
463
+ });
464
+ }
465
+ //#endregion
466
+ //#region src/expansion/maze.ts
467
+ /** Default threshold for switching to phase 2 (after M paths) */
468
+ var DEFAULT_PHASE2_THRESHOLD = 1;
469
+ /** Salience weighting factor */
470
+ var SALIENCE_WEIGHT = 1e3;
471
+ /**
472
+ * Run MAZE expansion algorithm.
473
+ *
474
+ * Multi-phase expansion combining path potential and salience with
475
+ * adaptive frontier steering.
476
+ *
477
+ * @param graph - Source graph
478
+ * @param seeds - Seed nodes for expansion
479
+ * @param config - Expansion configuration
480
+ * @returns Expansion result with discovered paths
481
+ */
482
+ function maze(graph, seeds, config) {
483
+ const salienceCounts = /* @__PURE__ */ new Map();
484
+ let inPhase2 = false;
485
+ let lastPathCount = 0;
486
+ /**
487
+ * MAZE priority function with path potential and salience feedback.
488
+ */
489
+ function mazePriority(nodeId, context) {
490
+ const pathCount = context.discoveredPaths.length;
491
+ if (pathCount >= DEFAULT_PHASE2_THRESHOLD && !inPhase2) {
492
+ inPhase2 = true;
493
+ for (const path of context.discoveredPaths) for (const node of path.nodes) salienceCounts.set(node, (salienceCounts.get(node) ?? 0) + 1);
494
+ }
495
+ if (inPhase2 && pathCount > lastPathCount) {
496
+ for (let i = lastPathCount; i < pathCount; i++) {
497
+ const path = context.discoveredPaths[i];
498
+ if (path !== void 0) for (const node of path.nodes) salienceCounts.set(node, (salienceCounts.get(node) ?? 0) + 1);
499
+ }
500
+ lastPathCount = pathCount;
501
+ }
502
+ const nodeNeighbours = new Set(graph.neighbours(nodeId));
503
+ let pathPotential = 0;
504
+ for (const [visitedId, frontierIdx] of context.visitedByFrontier) if (frontierIdx !== context.frontierIndex && nodeNeighbours.has(visitedId)) pathPotential++;
505
+ if (!inPhase2) return context.degree / (1 + pathPotential);
506
+ const salience = salienceCounts.get(nodeId) ?? 0;
507
+ return context.degree / (1 + pathPotential) * (1 / (1 + SALIENCE_WEIGHT * salience));
508
+ }
509
+ return base(graph, seeds, {
510
+ ...config,
511
+ priority: mazePriority
512
+ });
513
+ }
514
+ //#endregion
515
+ //#region src/expansion/tide.ts
516
+ /**
517
+ * TIDE priority function.
518
+ *
519
+ * Priority = degree(source) + degree(target)
520
+ * Lower values = higher priority (explored first)
521
+ */
522
+ function tidePriority(nodeId, context) {
523
+ const graph = context.graph;
524
+ let totalDegree = context.degree;
525
+ for (const neighbour of graph.neighbours(nodeId)) totalDegree += graph.degree(neighbour);
526
+ return totalDegree;
527
+ }
528
+ /**
529
+ * Run TIDE expansion algorithm.
530
+ *
531
+ * Expands from seeds prioritising low-degree edges first.
532
+ * Useful for avoiding hubs and exploring sparse regions.
533
+ *
534
+ * @param graph - Source graph
535
+ * @param seeds - Seed nodes for expansion
536
+ * @param config - Expansion configuration
537
+ * @returns Expansion result with discovered paths
538
+ */
539
+ function tide(graph, seeds, config) {
540
+ return base(graph, seeds, {
541
+ ...config,
542
+ priority: tidePriority
543
+ });
544
+ }
545
+ //#endregion
546
+ //#region src/expansion/lace.ts
547
+ /**
548
+ * LACE priority function.
310
549
  *
311
550
  * Priority = 1 - MI(source, neighbour)
312
551
  * Higher MI = lower priority value = explored first
313
552
  */
314
- function haePriority(nodeId, context, mi) {
553
+ function lacePriority(nodeId, context, mi) {
315
554
  const graph = context.graph;
316
555
  const frontierIndex = context.frontierIndex;
317
556
  let maxMi = 0;
@@ -326,7 +565,7 @@ function haePriority(nodeId, context, mi) {
326
565
  return 1 - (count > 0 ? totalMi / count : 0);
327
566
  }
328
567
  /**
329
- * Run HAE expansion algorithm.
568
+ * Run LACE expansion algorithm.
330
569
  *
331
570
  * Expands from seeds prioritising high-MI edges.
332
571
  * Useful for finding paths with strong semantic associations.
@@ -336,16 +575,16 @@ function haePriority(nodeId, context, mi) {
336
575
  * @param config - Expansion configuration with MI function
337
576
  * @returns Expansion result with discovered paths
338
577
  */
339
- function hae(graph, seeds, config) {
578
+ function lace(graph, seeds, config) {
340
579
  const { mi = jaccard, ...restConfig } = config ?? {};
341
- const priority = (nodeId, context) => haePriority(nodeId, context, mi);
580
+ const priority = (nodeId, context) => lacePriority(nodeId, context, mi);
342
581
  return base(graph, seeds, {
343
582
  ...restConfig,
344
583
  priority
345
584
  });
346
585
  }
347
586
  //#endregion
348
- //#region src/expansion/pipe.ts
587
+ //#region src/expansion/warp.ts
349
588
  /**
350
589
  * PIPE priority function.
351
590
  *
@@ -353,7 +592,7 @@ function hae(graph, seeds, config) {
353
592
  * Bridge score = neighbourhood overlap with other frontiers
354
593
  * Higher bridge score = more likely to be on paths = explored first
355
594
  */
356
- function pipePriority(nodeId, context) {
595
+ function warpPriority(nodeId, context) {
357
596
  const graph = context.graph;
358
597
  const currentFrontier = context.frontierIndex;
359
598
  const nodeNeighbours = new Set(graph.neighbours(nodeId));
@@ -363,7 +602,7 @@ function pipePriority(nodeId, context) {
363
602
  return 1 / (1 + bridgeScore);
364
603
  }
365
604
  /**
366
- * Run PIPE expansion algorithm.
605
+ * Run WARP expansion algorithm.
367
606
  *
368
607
  * Expands from seeds prioritising bridge nodes.
369
608
  * Useful for finding paths through structurally important nodes.
@@ -373,14 +612,14 @@ function pipePriority(nodeId, context) {
373
612
  * @param config - Expansion configuration
374
613
  * @returns Expansion result with discovered paths
375
614
  */
376
- function pipe(graph, seeds, config) {
615
+ function warp(graph, seeds, config) {
377
616
  return base(graph, seeds, {
378
617
  ...config,
379
- priority: pipePriority
618
+ priority: warpPriority
380
619
  });
381
620
  }
382
621
  //#endregion
383
- //#region src/expansion/sage.ts
622
+ //#region src/expansion/fuse.ts
384
623
  /**
385
624
  * SAGE priority function.
386
625
  *
@@ -388,7 +627,7 @@ function pipe(graph, seeds, config) {
388
627
  * Priority = (1 - w) * degree + w * (1 - avg_salience)
389
628
  * Lower values = higher priority
390
629
  */
391
- function sagePriority(nodeId, context, mi, salienceWeight) {
630
+ function fusePriority(nodeId, context, mi, salienceWeight) {
392
631
  const graph = context.graph;
393
632
  const degree = context.degree;
394
633
  const frontierIndex = context.frontierIndex;
@@ -402,7 +641,7 @@ function sagePriority(nodeId, context, mi, salienceWeight) {
402
641
  return (1 - salienceWeight) * degree + salienceWeight * (1 - avgSalience);
403
642
  }
404
643
  /**
405
- * Run SAGE expansion algorithm.
644
+ * Run FUSE expansion algorithm.
406
645
  *
407
646
  * Combines structural exploration with semantic salience.
408
647
  * Useful for finding paths that are both short and semantically meaningful.
@@ -412,22 +651,22 @@ function sagePriority(nodeId, context, mi, salienceWeight) {
412
651
  * @param config - Expansion configuration with MI function
413
652
  * @returns Expansion result with discovered paths
414
653
  */
415
- function sage(graph, seeds, config) {
654
+ function fuse(graph, seeds, config) {
416
655
  const { mi = jaccard, salienceWeight = .5, ...restConfig } = config ?? {};
417
- const priority = (nodeId, context) => sagePriority(nodeId, context, mi, salienceWeight);
656
+ const priority = (nodeId, context) => fusePriority(nodeId, context, mi, salienceWeight);
418
657
  return base(graph, seeds, {
419
658
  ...restConfig,
420
659
  priority
421
660
  });
422
661
  }
423
662
  //#endregion
424
- //#region src/expansion/reach.ts
663
+ //#region src/expansion/sift.ts
425
664
  /**
426
665
  * REACH priority function (phase 2).
427
666
  *
428
667
  * Uses learned MI threshold to prioritise high-MI edges.
429
668
  */
430
- function reachPriority(nodeId, context, mi, miThreshold) {
669
+ function siftPriority(nodeId, context, mi, miThreshold) {
431
670
  const graph = context.graph;
432
671
  const frontierIndex = context.frontierIndex;
433
672
  let totalMi = 0;
@@ -441,7 +680,7 @@ function reachPriority(nodeId, context, mi, miThreshold) {
441
680
  else return context.degree + 100;
442
681
  }
443
682
  /**
444
- * Run REACH expansion algorithm.
683
+ * Run SIFT expansion algorithm.
445
684
  *
446
685
  * Two-phase adaptive expansion that learns MI thresholds
447
686
  * from initial sampling, then uses them for guided expansion.
@@ -451,16 +690,16 @@ function reachPriority(nodeId, context, mi, miThreshold) {
451
690
  * @param config - Expansion configuration
452
691
  * @returns Expansion result with discovered paths
453
692
  */
454
- function reach(graph, seeds, config) {
693
+ function sift(graph, seeds, config) {
455
694
  const { mi = jaccard, miThreshold = .25, ...restConfig } = config ?? {};
456
- const priority = (nodeId, context) => reachPriority(nodeId, context, mi, miThreshold);
695
+ const priority = (nodeId, context) => siftPriority(nodeId, context, mi, miThreshold);
457
696
  return base(graph, seeds, {
458
697
  ...restConfig,
459
698
  priority
460
699
  });
461
700
  }
462
701
  //#endregion
463
- //#region src/expansion/maze.ts
702
+ //#region src/expansion/flux.ts
464
703
  /**
465
704
  * Compute local density around a node.
466
705
  */
@@ -495,7 +734,7 @@ function bridgeScore(nodeId, context) {
495
734
  * - Low density + low bridge: DOME mode
496
735
  * - High bridge score: PIPE mode
497
736
  */
498
- function mazePriority(nodeId, context, densityThreshold, bridgeThreshold) {
737
+ function fluxPriority(nodeId, context, densityThreshold, bridgeThreshold) {
499
738
  const graph = context.graph;
500
739
  const degree = context.degree;
501
740
  const density = localDensity(graph, nodeId);
@@ -506,7 +745,7 @@ function mazePriority(nodeId, context, densityThreshold, bridgeThreshold) {
506
745
  else return degree;
507
746
  }
508
747
  /**
509
- * Run MAZE expansion algorithm.
748
+ * Run FLUX expansion algorithm.
510
749
  *
511
750
  * Adaptively switches between expansion strategies based on
512
751
  * local graph structure. Useful for heterogeneous graphs
@@ -517,9 +756,9 @@ function mazePriority(nodeId, context, densityThreshold, bridgeThreshold) {
517
756
  * @param config - Expansion configuration
518
757
  * @returns Expansion result with discovered paths
519
758
  */
520
- function maze(graph, seeds, config) {
759
+ function flux(graph, seeds, config) {
521
760
  const { densityThreshold = .5, bridgeThreshold = .3, ...restConfig } = config ?? {};
522
- const priority = (nodeId, context) => mazePriority(nodeId, context, densityThreshold, bridgeThreshold);
761
+ const priority = (nodeId, context) => fluxPriority(nodeId, context, densityThreshold, bridgeThreshold);
523
762
  return base(graph, seeds, {
524
763
  ...restConfig,
525
764
  priority
@@ -703,8 +942,8 @@ function scale(graph, source, target, config) {
703
942
  const jaccard = union > 0 ? intersection / union : 0;
704
943
  const n = graph.nodeCount;
705
944
  const m = graph.edgeCount;
706
- const densityNormaliser = graph.directed ? n * (n - 1) : 2 * n * (n - 1);
707
- const density = densityNormaliser > 0 ? m / densityNormaliser : 0;
945
+ const possibleEdges = n * (n - 1);
946
+ const density = possibleEdges > 0 ? (graph.directed ? m : 2 * m) / possibleEdges : 0;
708
947
  if (density === 0) return epsilon;
709
948
  const score = jaccard / density;
710
949
  return Math.max(epsilon, score);
@@ -875,7 +1114,7 @@ function degreeSum(graph, paths, config) {
875
1114
  return {
876
1115
  paths: scored.map(({ path, score }) => ({
877
1116
  ...path,
878
- score: includeScores ? score / maxScore : score / maxScore
1117
+ score: includeScores ? score / maxScore : score
879
1118
  })).sort((a, b) => b.score - a.score),
880
1119
  method: "degree-sum"
881
1120
  };
@@ -977,7 +1216,7 @@ function jaccardArithmetic(graph, paths, config) {
977
1216
  return {
978
1217
  paths: scored.map(({ path, score }) => ({
979
1218
  ...path,
980
- score: includeScores ? score / maxScore : score / maxScore
1219
+ score: includeScores ? score / maxScore : score
981
1220
  })).sort((a, b) => b.score - a.score),
982
1221
  method: "jaccard-arithmetic"
983
1222
  };
@@ -2164,6 +2403,6 @@ function filterSubgraph(graph, options) {
2164
2403
  return result;
2165
2404
  }
2166
2405
  //#endregion
2167
- export { AdjacencyMapGraph, GPUContext, GPUNotAvailableError, PriorityQueue, _computeMean, adamicAdar, adaptive, approximateClusteringCoefficient, assertWebGPUAvailable, base, batchClusteringCoefficients, betweenness, bfs, bfsWithPath, communicability, computeTrussNumbers, countEdgesOfType, countNodesOfType, createGPUContext, createResultBuffer, csrToGPUBuffers, degreeSum, detectWebGPU, dfs, dfsWithPath, dome, domeHighDegree, edge, entropyFromCounts, enumerateMotifs, enumerateMotifsWithInstances, etch, extractEgoNetwork, extractInducedSubgraph, extractKCore, extractKTruss, filterSubgraph, frontierBalanced, getGPUContext, getMotifName, graphToCSR, grasp, hae, isWebGPUAvailable, jaccard, jaccardArithmetic, katz, localClusteringCoefficient, localTypeEntropy, maze, miniBatchKMeans, neighbourIntersection, neighbourOverlap, neighbourSet, normaliseFeatures, normaliseFeatures as zScoreNormalise, normalisedEntropy, notch, pagerank, parse, pipe, randomPriority, randomRanking, reach, readBufferToCPU, resistanceDistance, sage, scale, shannonEntropy, shortest, skew, span, standardBfs, stratified, widestPath };
2406
+ export { AdjacencyMapGraph, GPUContext, GPUNotAvailableError, PriorityQueue, _computeMean, adamicAdar, adaptive, approximateClusteringCoefficient, assertWebGPUAvailable, base, batchClusteringCoefficients, betweenness, bfs, bfsWithPath, communicability, computeTrussNumbers, countEdgesOfType, countNodesOfType, createGPUContext, createResultBuffer, csrToGPUBuffers, degreeSum, detectWebGPU, dfs, dfsWithPath, dome, domeHighDegree, edge, entropyFromCounts, enumerateMotifs, enumerateMotifsWithInstances, etch, extractEgoNetwork, extractInducedSubgraph, extractKCore, extractKTruss, filterSubgraph, flux, frontierBalanced, fuse, getGPUContext, getMotifName, graphToCSR, grasp, hae, isWebGPUAvailable, jaccard, jaccardArithmetic, katz, lace, localClusteringCoefficient, localTypeEntropy, maze, miniBatchKMeans, neighbourIntersection, neighbourOverlap, neighbourSet, normaliseFeatures, normaliseFeatures as zScoreNormalise, normalisedEntropy, notch, pagerank, parse, pipe, randomPriority, randomRanking, reach, readBufferToCPU, resistanceDistance, sage, scale, shannonEntropy, shortest, sift, skew, span, standardBfs, stratified, tide, warp, widestPath };
2168
2407
 
2169
2408
  //# sourceMappingURL=index.js.map