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.
- package/README.md +72 -1
- package/dist/__test__/fixtures/graphs/city-suburban-village.d.ts +3 -0
- package/dist/__test__/fixtures/graphs/city-suburban-village.d.ts.map +1 -0
- package/dist/__test__/fixtures/graphs/city-village.d.ts +3 -0
- package/dist/__test__/fixtures/graphs/city-village.d.ts.map +1 -0
- package/dist/__test__/fixtures/graphs/index.d.ts +13 -0
- package/dist/__test__/fixtures/graphs/index.d.ts.map +1 -0
- package/dist/__test__/fixtures/graphs/quality-vs-popularity.d.ts +3 -0
- package/dist/__test__/fixtures/graphs/quality-vs-popularity.d.ts.map +1 -0
- package/dist/__test__/fixtures/graphs/social-hub.d.ts +3 -0
- package/dist/__test__/fixtures/graphs/social-hub.d.ts.map +1 -0
- package/dist/__test__/fixtures/graphs/three-community.d.ts +3 -0
- package/dist/__test__/fixtures/graphs/three-community.d.ts.map +1 -0
- package/dist/__test__/fixtures/graphs/two-department.d.ts +3 -0
- package/dist/__test__/fixtures/graphs/two-department.d.ts.map +1 -0
- package/dist/__test__/fixtures/graphs/typed-entity.d.ts +3 -0
- package/dist/__test__/fixtures/graphs/typed-entity.d.ts.map +1 -0
- package/dist/__test__/fixtures/helpers.d.ts +66 -0
- package/dist/__test__/fixtures/helpers.d.ts.map +1 -0
- package/dist/__test__/fixtures/helpers.unit.test.d.ts +7 -0
- package/dist/__test__/fixtures/helpers.unit.test.d.ts.map +1 -0
- package/dist/__test__/fixtures/index.d.ts +10 -0
- package/dist/__test__/fixtures/index.d.ts.map +1 -0
- package/dist/__test__/fixtures/types.d.ts +35 -0
- package/dist/__test__/fixtures/types.d.ts.map +1 -0
- package/dist/expansion/dome.d.ts.map +1 -1
- package/dist/expansion/dome.integration.test.d.ts +18 -0
- package/dist/expansion/dome.integration.test.d.ts.map +1 -0
- package/dist/expansion/edge.d.ts +3 -3
- package/dist/expansion/edge.d.ts.map +1 -1
- package/dist/expansion/edge.integration.test.d.ts +11 -0
- package/dist/expansion/edge.integration.test.d.ts.map +1 -0
- package/dist/expansion/flux.d.ts +25 -0
- package/dist/expansion/flux.d.ts.map +1 -0
- package/dist/expansion/flux.integration.test.d.ts +14 -0
- package/dist/expansion/flux.integration.test.d.ts.map +1 -0
- package/dist/expansion/flux.unit.test.d.ts +2 -0
- package/dist/expansion/flux.unit.test.d.ts.map +1 -0
- package/dist/expansion/fuse.d.ts +28 -0
- package/dist/expansion/fuse.d.ts.map +1 -0
- package/dist/expansion/fuse.integration.test.d.ts +15 -0
- package/dist/expansion/fuse.integration.test.d.ts.map +1 -0
- package/dist/expansion/fuse.unit.test.d.ts +2 -0
- package/dist/expansion/fuse.unit.test.d.ts.map +1 -0
- package/dist/expansion/hae.d.ts +7 -7
- package/dist/expansion/hae.d.ts.map +1 -1
- package/dist/expansion/hae.integration.test.d.ts +11 -0
- package/dist/expansion/hae.integration.test.d.ts.map +1 -0
- package/dist/expansion/index.d.ts +6 -0
- package/dist/expansion/index.d.ts.map +1 -1
- package/dist/expansion/lace.d.ts +22 -0
- package/dist/expansion/lace.d.ts.map +1 -0
- package/dist/expansion/lace.integration.test.d.ts +14 -0
- package/dist/expansion/lace.integration.test.d.ts.map +1 -0
- package/dist/expansion/lace.unit.test.d.ts +2 -0
- package/dist/expansion/lace.unit.test.d.ts.map +1 -0
- package/dist/expansion/maze.d.ts +3 -13
- package/dist/expansion/maze.d.ts.map +1 -1
- package/dist/expansion/maze.integration.test.d.ts +11 -0
- package/dist/expansion/maze.integration.test.d.ts.map +1 -0
- package/dist/expansion/pipe.d.ts +3 -3
- package/dist/expansion/pipe.d.ts.map +1 -1
- package/dist/expansion/pipe.integration.test.d.ts +12 -0
- package/dist/expansion/pipe.integration.test.d.ts.map +1 -0
- package/dist/expansion/reach.d.ts +4 -14
- package/dist/expansion/reach.d.ts.map +1 -1
- package/dist/expansion/reach.integration.test.d.ts +9 -0
- package/dist/expansion/reach.integration.test.d.ts.map +1 -0
- package/dist/expansion/sage.d.ts +5 -13
- package/dist/expansion/sage.d.ts.map +1 -1
- package/dist/expansion/sage.integration.test.d.ts +9 -0
- package/dist/expansion/sage.integration.test.d.ts.map +1 -0
- package/dist/expansion/sift.d.ts +26 -0
- package/dist/expansion/sift.d.ts.map +1 -0
- package/dist/expansion/sift.integration.test.d.ts +13 -0
- package/dist/expansion/sift.integration.test.d.ts.map +1 -0
- package/dist/expansion/sift.unit.test.d.ts +2 -0
- package/dist/expansion/sift.unit.test.d.ts.map +1 -0
- package/dist/expansion/tide.d.ts +15 -0
- package/dist/expansion/tide.d.ts.map +1 -0
- package/dist/expansion/tide.integration.test.d.ts +14 -0
- package/dist/expansion/tide.integration.test.d.ts.map +1 -0
- package/dist/expansion/tide.unit.test.d.ts +2 -0
- package/dist/expansion/tide.unit.test.d.ts.map +1 -0
- package/dist/expansion/warp.d.ts +15 -0
- package/dist/expansion/warp.d.ts.map +1 -0
- package/dist/expansion/warp.integration.test.d.ts +13 -0
- package/dist/expansion/warp.integration.test.d.ts.map +1 -0
- package/dist/expansion/warp.unit.test.d.ts +2 -0
- package/dist/expansion/warp.unit.test.d.ts.map +1 -0
- package/dist/graph/adjacency-map.d.ts.map +1 -1
- package/dist/graph/index.cjs +7 -0
- package/dist/graph/index.cjs.map +1 -1
- package/dist/graph/index.js +7 -0
- package/dist/graph/index.js.map +1 -1
- package/dist/index/index.cjs +287 -42
- package/dist/index/index.cjs.map +1 -1
- package/dist/index/index.js +282 -43
- package/dist/index/index.js.map +1 -1
- package/dist/ranking/mi/etch.integration.test.d.ts +2 -0
- package/dist/ranking/mi/etch.integration.test.d.ts.map +1 -0
- package/dist/ranking/mi/notch.integration.test.d.ts +2 -0
- package/dist/ranking/mi/notch.integration.test.d.ts.map +1 -0
- package/dist/ranking/mi/scale.d.ts.map +1 -1
- package/dist/ranking/mi/scale.integration.test.d.ts +2 -0
- package/dist/ranking/mi/scale.integration.test.d.ts.map +1 -0
- package/dist/ranking/mi/skew.integration.test.d.ts +2 -0
- package/dist/ranking/mi/skew.integration.test.d.ts.map +1 -0
- package/dist/ranking/mi/span.integration.test.d.ts +2 -0
- package/dist/ranking/mi/span.integration.test.d.ts.map +1 -0
- package/dist/ranking/parse.integration.test.d.ts +10 -0
- package/dist/ranking/parse.integration.test.d.ts.map +1 -0
- package/dist/structures/index.cjs +12 -2
- package/dist/structures/index.cjs.map +1 -1
- package/dist/structures/index.js +12 -2
- package/dist/structures/index.js.map +1 -1
- package/dist/structures/priority-queue.d.ts +4 -2
- package/dist/structures/priority-queue.d.ts.map +1 -1
- package/dist/utils/index.cjs +76 -77
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.js +76 -77
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index/index.cjs
CHANGED
|
@@ -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
|
|
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 -
|
|
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
|
-
*
|
|
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
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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
|
|
276
|
+
* Run EDGE expansion (Entropy-Driven Graph Expansion).
|
|
274
277
|
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
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/
|
|
428
|
+
//#region src/expansion/reach.ts
|
|
309
429
|
/**
|
|
310
|
-
*
|
|
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
|
|
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
|
|
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
|
|
579
|
+
function lace(graph, seeds, config) {
|
|
341
580
|
const { mi = jaccard, ...restConfig } = config ?? {};
|
|
342
|
-
const priority = (nodeId, context) =>
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
616
|
+
function warp(graph, seeds, config) {
|
|
378
617
|
return base(graph, seeds, {
|
|
379
618
|
...config,
|
|
380
|
-
priority:
|
|
619
|
+
priority: warpPriority
|
|
381
620
|
});
|
|
382
621
|
}
|
|
383
622
|
//#endregion
|
|
384
|
-
//#region src/expansion/
|
|
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
|
|
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
|
|
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
|
|
655
|
+
function fuse(graph, seeds, config) {
|
|
417
656
|
const { mi = jaccard, salienceWeight = .5, ...restConfig } = config ?? {};
|
|
418
|
-
const priority = (nodeId, context) =>
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
694
|
+
function sift(graph, seeds, config) {
|
|
456
695
|
const { mi = jaccard, miThreshold = .25, ...restConfig } = config ?? {};
|
|
457
|
-
const priority = (nodeId, context) =>
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
760
|
+
function flux(graph, seeds, config) {
|
|
522
761
|
const { densityThreshold = .5, bridgeThreshold = .3, ...restConfig } = config ?? {};
|
|
523
|
-
const priority = (nodeId, context) =>
|
|
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
|
|
708
|
-
const density =
|
|
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
|
|
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
|
|
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
|