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
@@ -236,7 +236,7 @@ function emptyResult(algorithm, startTime) {
236
236
  */
237
237
  function dome(graph, seeds, config) {
238
238
  const domePriority = (nodeId, context) => {
239
- return graph.degree(nodeId);
239
+ return context.degree;
240
240
  };
241
241
  return base(graph, seeds, {
242
242
  ...config,
@@ -248,7 +248,7 @@ function dome(graph, seeds, config) {
248
248
  */
249
249
  function domeHighDegree(graph, seeds, config) {
250
250
  const domePriority = (nodeId, context) => {
251
- return -graph.degree(nodeId);
251
+ return -context.degree;
252
252
  };
253
253
  return base(graph, seeds, {
254
254
  ...config,
@@ -257,23 +257,26 @@ function domeHighDegree(graph, seeds, config) {
257
257
  }
258
258
  //#endregion
259
259
  //#region src/expansion/edge.ts
260
+ var EPSILON$1 = 1e-10;
260
261
  /**
261
- * EDGE priority function.
262
- *
263
- * Priority = degree(source) + degree(target)
264
- * Lower values = higher priority (explored first)
262
+ * Priority function using local type entropy.
263
+ * Lower values = higher priority (expanded first).
265
264
  */
266
265
  function edgePriority(nodeId, context) {
267
266
  const graph = context.graph;
268
- let totalDegree = context.degree;
269
- for (const neighbour of graph.neighbours(nodeId)) totalDegree += graph.degree(neighbour);
270
- return totalDegree;
267
+ const neighbours = graph.neighbours(nodeId);
268
+ const neighbourTypes = [];
269
+ for (const neighbour of neighbours) {
270
+ const node = graph.getNode(neighbour);
271
+ neighbourTypes.push(node?.type ?? "default");
272
+ }
273
+ return 1 / (require_utils.localTypeEntropy(neighbourTypes) + EPSILON$1) * Math.log(context.degree + 1);
271
274
  }
272
275
  /**
273
- * Run EDGE expansion algorithm.
276
+ * Run EDGE expansion (Entropy-Driven Graph Expansion).
274
277
  *
275
- * Expands from seeds prioritising low-degree edges first.
276
- * Useful for avoiding hubs and exploring sparse regions.
278
+ * Discovers paths by prioritising nodes with diverse neighbour types,
279
+ * deferring nodes with homogeneous neighbourhoods.
277
280
  *
278
281
  * @param graph - Source graph
279
282
  * @param seeds - Seed nodes for expansion
@@ -287,6 +290,123 @@ function edge(graph, seeds, config) {
287
290
  });
288
291
  }
289
292
  //#endregion
293
+ //#region src/expansion/hae.ts
294
+ var EPSILON = 1e-10;
295
+ /**
296
+ * Default type mapper - uses node.type property.
297
+ */
298
+ function defaultTypeMapper(node) {
299
+ return node.type ?? "default";
300
+ }
301
+ /**
302
+ * Create a priority function using the given type mapper.
303
+ */
304
+ function createHAEPriority(typeMapper) {
305
+ return function haePriority(nodeId, context) {
306
+ const graph = context.graph;
307
+ const neighbours = graph.neighbours(nodeId);
308
+ const neighbourTypes = [];
309
+ for (const neighbour of neighbours) {
310
+ const node = graph.getNode(neighbour);
311
+ if (node !== void 0) neighbourTypes.push(typeMapper(node));
312
+ }
313
+ return 1 / (require_utils.localTypeEntropy(neighbourTypes) + EPSILON) * Math.log(context.degree + 1);
314
+ };
315
+ }
316
+ /**
317
+ * Run HAE expansion (Heterogeneity-Aware Expansion).
318
+ *
319
+ * Discovers paths by prioritising nodes with diverse neighbour types,
320
+ * using a custom type mapper for flexible type extraction.
321
+ *
322
+ * @param graph - Source graph
323
+ * @param seeds - Seed nodes for expansion
324
+ * @param config - HAE configuration with optional typeMapper
325
+ * @returns Expansion result with discovered paths
326
+ */
327
+ function hae(graph, seeds, config) {
328
+ const typeMapper = config?.typeMapper ?? defaultTypeMapper;
329
+ return base(graph, seeds, {
330
+ ...config,
331
+ priority: createHAEPriority(typeMapper)
332
+ });
333
+ }
334
+ //#endregion
335
+ //#region src/expansion/pipe.ts
336
+ /**
337
+ * Priority function using path potential.
338
+ * Lower values = higher priority (expanded first).
339
+ *
340
+ * Path potential measures how many of a node's neighbours have been
341
+ * visited by OTHER frontiers (not the current frontier).
342
+ */
343
+ function pipePriority(nodeId, context) {
344
+ const graph = context.graph;
345
+ const neighbours = new Set(graph.neighbours(nodeId));
346
+ let pathPotential = 0;
347
+ for (const [visitedId, frontierIdx] of context.visitedByFrontier) if (frontierIdx !== context.frontierIndex && neighbours.has(visitedId)) pathPotential++;
348
+ return context.degree / (1 + pathPotential);
349
+ }
350
+ /**
351
+ * Run PIPE expansion (Path-Potential Informed Priority Expansion).
352
+ *
353
+ * Discovers paths by prioritising nodes that bridge multiple frontiers,
354
+ * identifying connecting points between seed regions.
355
+ *
356
+ * @param graph - Source graph
357
+ * @param seeds - Seed nodes for expansion
358
+ * @param config - Expansion configuration
359
+ * @returns Expansion result with discovered paths
360
+ */
361
+ function pipe(graph, seeds, config) {
362
+ return base(graph, seeds, {
363
+ ...config,
364
+ priority: pipePriority
365
+ });
366
+ }
367
+ //#endregion
368
+ //#region src/expansion/sage.ts
369
+ /**
370
+ * Run SAGE expansion algorithm.
371
+ *
372
+ * Salience-aware multi-frontier expansion with two phases:
373
+ * - Phase 1: Degree-based priority (early exploration)
374
+ * - Phase 2: Salience feedback (path-aware frontier steering)
375
+ *
376
+ * @param graph - Source graph
377
+ * @param seeds - Seed nodes for expansion
378
+ * @param config - Expansion configuration
379
+ * @returns Expansion result with discovered paths
380
+ */
381
+ function sage(graph, seeds, config) {
382
+ const salienceCounts = /* @__PURE__ */ new Map();
383
+ let inPhase2 = false;
384
+ let lastPathCount = 0;
385
+ /**
386
+ * SAGE priority function with phase transition logic.
387
+ */
388
+ function sagePriority(nodeId, context) {
389
+ const pathCount = context.discoveredPaths.length;
390
+ if (pathCount > 0 && !inPhase2) {
391
+ inPhase2 = true;
392
+ for (const path of context.discoveredPaths) for (const node of path.nodes) salienceCounts.set(node, (salienceCounts.get(node) ?? 0) + 1);
393
+ }
394
+ if (pathCount > lastPathCount) {
395
+ for (let i = lastPathCount; i < pathCount; i++) {
396
+ const path = context.discoveredPaths[i];
397
+ if (path !== void 0) for (const node of path.nodes) salienceCounts.set(node, (salienceCounts.get(node) ?? 0) + 1);
398
+ }
399
+ lastPathCount = pathCount;
400
+ }
401
+ if (!inPhase2) return Math.log(context.degree + 1);
402
+ return -((salienceCounts.get(nodeId) ?? 0) * 1e3 - context.degree);
403
+ }
404
+ return base(graph, seeds, {
405
+ ...config,
406
+ priority: sagePriority
407
+ });
408
+ }
409
+ //#endregion
290
410
  //#region src/ranking/mi/jaccard.ts
291
411
  /**
292
412
  * Compute Jaccard similarity between neighbourhoods of two nodes.
@@ -305,14 +425,133 @@ function jaccard(graph, source, target, config) {
305
425
  return Math.max(epsilon, score);
306
426
  }
307
427
  //#endregion
308
- //#region src/expansion/hae.ts
428
+ //#region src/expansion/reach.ts
309
429
  /**
310
- * HAE priority function.
430
+ * Run REACH expansion algorithm.
431
+ *
432
+ * Mutual information-aware multi-frontier expansion with two phases:
433
+ * - Phase 1: Degree-based priority (early exploration)
434
+ * - Phase 2: Structural similarity feedback (MI-guided frontier steering)
435
+ *
436
+ * @param graph - Source graph
437
+ * @param seeds - Seed nodes for expansion
438
+ * @param config - Expansion configuration
439
+ * @returns Expansion result with discovered paths
440
+ */
441
+ function reach(graph, seeds, config) {
442
+ let inPhase2 = false;
443
+ /**
444
+ * REACH priority function with MI estimation.
445
+ */
446
+ function reachPriority(nodeId, context) {
447
+ if (context.discoveredPaths.length > 0 && !inPhase2) inPhase2 = true;
448
+ if (!inPhase2) return Math.log(context.degree + 1);
449
+ let totalMI = 0;
450
+ let endpointCount = 0;
451
+ for (const path of context.discoveredPaths) {
452
+ const fromNodeId = path.fromSeed.id;
453
+ const toNodeId = path.toSeed.id;
454
+ totalMI += jaccard(graph, nodeId, fromNodeId);
455
+ totalMI += jaccard(graph, nodeId, toNodeId);
456
+ endpointCount += 2;
457
+ }
458
+ const miHat = endpointCount > 0 ? totalMI / endpointCount : 0;
459
+ return Math.log(context.degree + 1) * (1 - miHat);
460
+ }
461
+ return base(graph, seeds, {
462
+ ...config,
463
+ priority: reachPriority
464
+ });
465
+ }
466
+ //#endregion
467
+ //#region src/expansion/maze.ts
468
+ /** Default threshold for switching to phase 2 (after M paths) */
469
+ var DEFAULT_PHASE2_THRESHOLD = 1;
470
+ /** Salience weighting factor */
471
+ var SALIENCE_WEIGHT = 1e3;
472
+ /**
473
+ * Run MAZE expansion algorithm.
474
+ *
475
+ * Multi-phase expansion combining path potential and salience with
476
+ * adaptive frontier steering.
477
+ *
478
+ * @param graph - Source graph
479
+ * @param seeds - Seed nodes for expansion
480
+ * @param config - Expansion configuration
481
+ * @returns Expansion result with discovered paths
482
+ */
483
+ function maze(graph, seeds, config) {
484
+ const salienceCounts = /* @__PURE__ */ new Map();
485
+ let inPhase2 = false;
486
+ let lastPathCount = 0;
487
+ /**
488
+ * MAZE priority function with path potential and salience feedback.
489
+ */
490
+ function mazePriority(nodeId, context) {
491
+ const pathCount = context.discoveredPaths.length;
492
+ if (pathCount >= DEFAULT_PHASE2_THRESHOLD && !inPhase2) {
493
+ inPhase2 = true;
494
+ for (const path of context.discoveredPaths) for (const node of path.nodes) salienceCounts.set(node, (salienceCounts.get(node) ?? 0) + 1);
495
+ }
496
+ if (inPhase2 && pathCount > lastPathCount) {
497
+ for (let i = lastPathCount; i < pathCount; i++) {
498
+ const path = context.discoveredPaths[i];
499
+ if (path !== void 0) for (const node of path.nodes) salienceCounts.set(node, (salienceCounts.get(node) ?? 0) + 1);
500
+ }
501
+ lastPathCount = pathCount;
502
+ }
503
+ const nodeNeighbours = new Set(graph.neighbours(nodeId));
504
+ let pathPotential = 0;
505
+ for (const [visitedId, frontierIdx] of context.visitedByFrontier) if (frontierIdx !== context.frontierIndex && nodeNeighbours.has(visitedId)) pathPotential++;
506
+ if (!inPhase2) return context.degree / (1 + pathPotential);
507
+ const salience = salienceCounts.get(nodeId) ?? 0;
508
+ return context.degree / (1 + pathPotential) * (1 / (1 + SALIENCE_WEIGHT * salience));
509
+ }
510
+ return base(graph, seeds, {
511
+ ...config,
512
+ priority: mazePriority
513
+ });
514
+ }
515
+ //#endregion
516
+ //#region src/expansion/tide.ts
517
+ /**
518
+ * TIDE priority function.
519
+ *
520
+ * Priority = degree(source) + degree(target)
521
+ * Lower values = higher priority (explored first)
522
+ */
523
+ function tidePriority(nodeId, context) {
524
+ const graph = context.graph;
525
+ let totalDegree = context.degree;
526
+ for (const neighbour of graph.neighbours(nodeId)) totalDegree += graph.degree(neighbour);
527
+ return totalDegree;
528
+ }
529
+ /**
530
+ * Run TIDE expansion algorithm.
531
+ *
532
+ * Expands from seeds prioritising low-degree edges first.
533
+ * Useful for avoiding hubs and exploring sparse regions.
534
+ *
535
+ * @param graph - Source graph
536
+ * @param seeds - Seed nodes for expansion
537
+ * @param config - Expansion configuration
538
+ * @returns Expansion result with discovered paths
539
+ */
540
+ function tide(graph, seeds, config) {
541
+ return base(graph, seeds, {
542
+ ...config,
543
+ priority: tidePriority
544
+ });
545
+ }
546
+ //#endregion
547
+ //#region src/expansion/lace.ts
548
+ /**
549
+ * LACE priority function.
311
550
  *
312
551
  * Priority = 1 - MI(source, neighbour)
313
552
  * Higher MI = lower priority value = explored first
314
553
  */
315
- function haePriority(nodeId, context, mi) {
554
+ function lacePriority(nodeId, context, mi) {
316
555
  const graph = context.graph;
317
556
  const frontierIndex = context.frontierIndex;
318
557
  let maxMi = 0;
@@ -327,7 +566,7 @@ function haePriority(nodeId, context, mi) {
327
566
  return 1 - (count > 0 ? totalMi / count : 0);
328
567
  }
329
568
  /**
330
- * Run HAE expansion algorithm.
569
+ * Run LACE expansion algorithm.
331
570
  *
332
571
  * Expands from seeds prioritising high-MI edges.
333
572
  * Useful for finding paths with strong semantic associations.
@@ -337,16 +576,16 @@ function haePriority(nodeId, context, mi) {
337
576
  * @param config - Expansion configuration with MI function
338
577
  * @returns Expansion result with discovered paths
339
578
  */
340
- function hae(graph, seeds, config) {
579
+ function lace(graph, seeds, config) {
341
580
  const { mi = jaccard, ...restConfig } = config ?? {};
342
- const priority = (nodeId, context) => haePriority(nodeId, context, mi);
581
+ const priority = (nodeId, context) => lacePriority(nodeId, context, mi);
343
582
  return base(graph, seeds, {
344
583
  ...restConfig,
345
584
  priority
346
585
  });
347
586
  }
348
587
  //#endregion
349
- //#region src/expansion/pipe.ts
588
+ //#region src/expansion/warp.ts
350
589
  /**
351
590
  * PIPE priority function.
352
591
  *
@@ -354,7 +593,7 @@ function hae(graph, seeds, config) {
354
593
  * Bridge score = neighbourhood overlap with other frontiers
355
594
  * Higher bridge score = more likely to be on paths = explored first
356
595
  */
357
- function pipePriority(nodeId, context) {
596
+ function warpPriority(nodeId, context) {
358
597
  const graph = context.graph;
359
598
  const currentFrontier = context.frontierIndex;
360
599
  const nodeNeighbours = new Set(graph.neighbours(nodeId));
@@ -364,7 +603,7 @@ function pipePriority(nodeId, context) {
364
603
  return 1 / (1 + bridgeScore);
365
604
  }
366
605
  /**
367
- * Run PIPE expansion algorithm.
606
+ * Run WARP expansion algorithm.
368
607
  *
369
608
  * Expands from seeds prioritising bridge nodes.
370
609
  * Useful for finding paths through structurally important nodes.
@@ -374,14 +613,14 @@ function pipePriority(nodeId, context) {
374
613
  * @param config - Expansion configuration
375
614
  * @returns Expansion result with discovered paths
376
615
  */
377
- function pipe(graph, seeds, config) {
616
+ function warp(graph, seeds, config) {
378
617
  return base(graph, seeds, {
379
618
  ...config,
380
- priority: pipePriority
619
+ priority: warpPriority
381
620
  });
382
621
  }
383
622
  //#endregion
384
- //#region src/expansion/sage.ts
623
+ //#region src/expansion/fuse.ts
385
624
  /**
386
625
  * SAGE priority function.
387
626
  *
@@ -389,7 +628,7 @@ function pipe(graph, seeds, config) {
389
628
  * Priority = (1 - w) * degree + w * (1 - avg_salience)
390
629
  * Lower values = higher priority
391
630
  */
392
- function sagePriority(nodeId, context, mi, salienceWeight) {
631
+ function fusePriority(nodeId, context, mi, salienceWeight) {
393
632
  const graph = context.graph;
394
633
  const degree = context.degree;
395
634
  const frontierIndex = context.frontierIndex;
@@ -403,7 +642,7 @@ function sagePriority(nodeId, context, mi, salienceWeight) {
403
642
  return (1 - salienceWeight) * degree + salienceWeight * (1 - avgSalience);
404
643
  }
405
644
  /**
406
- * Run SAGE expansion algorithm.
645
+ * Run FUSE expansion algorithm.
407
646
  *
408
647
  * Combines structural exploration with semantic salience.
409
648
  * Useful for finding paths that are both short and semantically meaningful.
@@ -413,22 +652,22 @@ function sagePriority(nodeId, context, mi, salienceWeight) {
413
652
  * @param config - Expansion configuration with MI function
414
653
  * @returns Expansion result with discovered paths
415
654
  */
416
- function sage(graph, seeds, config) {
655
+ function fuse(graph, seeds, config) {
417
656
  const { mi = jaccard, salienceWeight = .5, ...restConfig } = config ?? {};
418
- const priority = (nodeId, context) => sagePriority(nodeId, context, mi, salienceWeight);
657
+ const priority = (nodeId, context) => fusePriority(nodeId, context, mi, salienceWeight);
419
658
  return base(graph, seeds, {
420
659
  ...restConfig,
421
660
  priority
422
661
  });
423
662
  }
424
663
  //#endregion
425
- //#region src/expansion/reach.ts
664
+ //#region src/expansion/sift.ts
426
665
  /**
427
666
  * REACH priority function (phase 2).
428
667
  *
429
668
  * Uses learned MI threshold to prioritise high-MI edges.
430
669
  */
431
- function reachPriority(nodeId, context, mi, miThreshold) {
670
+ function siftPriority(nodeId, context, mi, miThreshold) {
432
671
  const graph = context.graph;
433
672
  const frontierIndex = context.frontierIndex;
434
673
  let totalMi = 0;
@@ -442,7 +681,7 @@ function reachPriority(nodeId, context, mi, miThreshold) {
442
681
  else return context.degree + 100;
443
682
  }
444
683
  /**
445
- * Run REACH expansion algorithm.
684
+ * Run SIFT expansion algorithm.
446
685
  *
447
686
  * Two-phase adaptive expansion that learns MI thresholds
448
687
  * from initial sampling, then uses them for guided expansion.
@@ -452,16 +691,16 @@ function reachPriority(nodeId, context, mi, miThreshold) {
452
691
  * @param config - Expansion configuration
453
692
  * @returns Expansion result with discovered paths
454
693
  */
455
- function reach(graph, seeds, config) {
694
+ function sift(graph, seeds, config) {
456
695
  const { mi = jaccard, miThreshold = .25, ...restConfig } = config ?? {};
457
- const priority = (nodeId, context) => reachPriority(nodeId, context, mi, miThreshold);
696
+ const priority = (nodeId, context) => siftPriority(nodeId, context, mi, miThreshold);
458
697
  return base(graph, seeds, {
459
698
  ...restConfig,
460
699
  priority
461
700
  });
462
701
  }
463
702
  //#endregion
464
- //#region src/expansion/maze.ts
703
+ //#region src/expansion/flux.ts
465
704
  /**
466
705
  * Compute local density around a node.
467
706
  */
@@ -496,7 +735,7 @@ function bridgeScore(nodeId, context) {
496
735
  * - Low density + low bridge: DOME mode
497
736
  * - High bridge score: PIPE mode
498
737
  */
499
- function mazePriority(nodeId, context, densityThreshold, bridgeThreshold) {
738
+ function fluxPriority(nodeId, context, densityThreshold, bridgeThreshold) {
500
739
  const graph = context.graph;
501
740
  const degree = context.degree;
502
741
  const density = localDensity(graph, nodeId);
@@ -507,7 +746,7 @@ function mazePriority(nodeId, context, densityThreshold, bridgeThreshold) {
507
746
  else return degree;
508
747
  }
509
748
  /**
510
- * Run MAZE expansion algorithm.
749
+ * Run FLUX expansion algorithm.
511
750
  *
512
751
  * Adaptively switches between expansion strategies based on
513
752
  * local graph structure. Useful for heterogeneous graphs
@@ -518,9 +757,9 @@ function mazePriority(nodeId, context, densityThreshold, bridgeThreshold) {
518
757
  * @param config - Expansion configuration
519
758
  * @returns Expansion result with discovered paths
520
759
  */
521
- function maze(graph, seeds, config) {
760
+ function flux(graph, seeds, config) {
522
761
  const { densityThreshold = .5, bridgeThreshold = .3, ...restConfig } = config ?? {};
523
- const priority = (nodeId, context) => mazePriority(nodeId, context, densityThreshold, bridgeThreshold);
762
+ const priority = (nodeId, context) => fluxPriority(nodeId, context, densityThreshold, bridgeThreshold);
524
763
  return base(graph, seeds, {
525
764
  ...restConfig,
526
765
  priority
@@ -704,8 +943,8 @@ function scale(graph, source, target, config) {
704
943
  const jaccard = union > 0 ? intersection / union : 0;
705
944
  const n = graph.nodeCount;
706
945
  const m = graph.edgeCount;
707
- const densityNormaliser = graph.directed ? n * (n - 1) : 2 * n * (n - 1);
708
- const density = densityNormaliser > 0 ? m / densityNormaliser : 0;
946
+ const possibleEdges = n * (n - 1);
947
+ const density = possibleEdges > 0 ? (graph.directed ? m : 2 * m) / possibleEdges : 0;
709
948
  if (density === 0) return epsilon;
710
949
  const score = jaccard / density;
711
950
  return Math.max(epsilon, score);
@@ -876,7 +1115,7 @@ function degreeSum(graph, paths, config) {
876
1115
  return {
877
1116
  paths: scored.map(({ path, score }) => ({
878
1117
  ...path,
879
- score: includeScores ? score / maxScore : score / maxScore
1118
+ score: includeScores ? score / maxScore : score
880
1119
  })).sort((a, b) => b.score - a.score),
881
1120
  method: "degree-sum"
882
1121
  };
@@ -978,7 +1217,7 @@ function jaccardArithmetic(graph, paths, config) {
978
1217
  return {
979
1218
  paths: scored.map(({ path, score }) => ({
980
1219
  ...path,
981
- score: includeScores ? score / maxScore : score / maxScore
1220
+ score: includeScores ? score / maxScore : score
982
1221
  })).sort((a, b) => b.score - a.score),
983
1222
  method: "jaccard-arithmetic"
984
1223
  };
@@ -2202,7 +2441,9 @@ exports.extractInducedSubgraph = extractInducedSubgraph;
2202
2441
  exports.extractKCore = extractKCore;
2203
2442
  exports.extractKTruss = extractKTruss;
2204
2443
  exports.filterSubgraph = filterSubgraph;
2444
+ exports.flux = flux;
2205
2445
  exports.frontierBalanced = frontierBalanced;
2446
+ exports.fuse = fuse;
2206
2447
  exports.getGPUContext = require_gpu.getGPUContext;
2207
2448
  exports.getMotifName = getMotifName;
2208
2449
  exports.graphToCSR = require_gpu.graphToCSR;
@@ -2212,6 +2453,7 @@ exports.isWebGPUAvailable = require_gpu.isWebGPUAvailable;
2212
2453
  exports.jaccard = jaccard;
2213
2454
  exports.jaccardArithmetic = jaccardArithmetic;
2214
2455
  exports.katz = katz;
2456
+ exports.lace = lace;
2215
2457
  exports.localClusteringCoefficient = require_utils.localClusteringCoefficient;
2216
2458
  exports.localTypeEntropy = require_utils.localTypeEntropy;
2217
2459
  exports.maze = maze;
@@ -2235,10 +2477,13 @@ exports.sage = sage;
2235
2477
  exports.scale = scale;
2236
2478
  exports.shannonEntropy = require_utils.shannonEntropy;
2237
2479
  exports.shortest = shortest;
2480
+ exports.sift = sift;
2238
2481
  exports.skew = skew;
2239
2482
  exports.span = span;
2240
2483
  exports.standardBfs = standardBfs;
2241
2484
  exports.stratified = require_seeds.stratified;
2485
+ exports.tide = tide;
2486
+ exports.warp = warp;
2242
2487
  exports.widestPath = widestPath;
2243
2488
 
2244
2489
  //# sourceMappingURL=index.cjs.map