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.js
CHANGED
|
@@ -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
|
|
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 -
|
|
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
|
-
*
|
|
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
|
-
|
|
268
|
-
|
|
269
|
-
|
|
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
|
|
275
|
+
* Run EDGE expansion (Entropy-Driven Graph Expansion).
|
|
273
276
|
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
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/
|
|
427
|
+
//#region src/expansion/reach.ts
|
|
308
428
|
/**
|
|
309
|
-
*
|
|
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
|
|
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
|
|
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
|
|
578
|
+
function lace(graph, seeds, config) {
|
|
340
579
|
const { mi = jaccard, ...restConfig } = config ?? {};
|
|
341
|
-
const priority = (nodeId, context) =>
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
615
|
+
function warp(graph, seeds, config) {
|
|
377
616
|
return base(graph, seeds, {
|
|
378
617
|
...config,
|
|
379
|
-
priority:
|
|
618
|
+
priority: warpPriority
|
|
380
619
|
});
|
|
381
620
|
}
|
|
382
621
|
//#endregion
|
|
383
|
-
//#region src/expansion/
|
|
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
|
|
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
|
|
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
|
|
654
|
+
function fuse(graph, seeds, config) {
|
|
416
655
|
const { mi = jaccard, salienceWeight = .5, ...restConfig } = config ?? {};
|
|
417
|
-
const priority = (nodeId, context) =>
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
693
|
+
function sift(graph, seeds, config) {
|
|
455
694
|
const { mi = jaccard, miThreshold = .25, ...restConfig } = config ?? {};
|
|
456
|
-
const priority = (nodeId, context) =>
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
759
|
+
function flux(graph, seeds, config) {
|
|
521
760
|
const { densityThreshold = .5, bridgeThreshold = .3, ...restConfig } = config ?? {};
|
|
522
|
-
const priority = (nodeId, context) =>
|
|
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
|
|
707
|
-
const density =
|
|
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
|
|
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
|
|
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
|