graphwise 1.4.0 → 1.4.1
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/dist/expansion/base.d.ts.map +1 -1
- package/dist/expansion/maze.d.ts.map +1 -1
- package/dist/expansion/reach.d.ts.map +1 -1
- package/dist/expansion/sage.d.ts.map +1 -1
- package/dist/index/index.cjs +47 -29
- package/dist/index/index.cjs.map +1 -1
- package/dist/index/index.js +47 -29
- package/dist/index/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/expansion/base.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAU,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE1E,OAAO,KAAK,EACX,IAAI,EACJ,eAAe,EAGf,eAAe,EAEf,MAAM,SAAS,CAAC;AAqBjB;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAC1D,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,MAAM,CAAC,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,GAC5B,eAAe,
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/expansion/base.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAU,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE1E,OAAO,KAAK,EACX,IAAI,EACJ,eAAe,EAGf,eAAe,EAEf,MAAM,SAAS,CAAC;AAqBjB;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAC1D,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,MAAM,CAAC,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,GAC5B,eAAe,CAwOjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"maze.d.ts","sourceRoot":"","sources":["../../src/expansion/maze.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAU,MAAM,UAAU,CAAC;AAC1E,OAAO,KAAK,EACX,IAAI,EACJ,eAAe,EACf,eAAe,EAEf,MAAM,SAAS,CAAC;AASjB;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAC1D,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,MAAM,CAAC,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,GAC5B,eAAe,
|
|
1
|
+
{"version":3,"file":"maze.d.ts","sourceRoot":"","sources":["../../src/expansion/maze.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAU,MAAM,UAAU,CAAC;AAC1E,OAAO,KAAK,EACX,IAAI,EACJ,eAAe,EACf,eAAe,EAEf,MAAM,SAAS,CAAC;AASjB;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAC1D,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,MAAM,CAAC,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,GAC5B,eAAe,CAsEjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reach.d.ts","sourceRoot":"","sources":["../../src/expansion/reach.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAU,MAAM,UAAU,CAAC;AAC1E,OAAO,KAAK,EACX,IAAI,EACJ,eAAe,EACf,eAAe,EAEf,MAAM,SAAS,CAAC;AAIjB;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAC3D,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,MAAM,CAAC,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,GAC5B,eAAe,
|
|
1
|
+
{"version":3,"file":"reach.d.ts","sourceRoot":"","sources":["../../src/expansion/reach.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAU,MAAM,UAAU,CAAC;AAC1E,OAAO,KAAK,EACX,IAAI,EACJ,eAAe,EACf,eAAe,EAEf,MAAM,SAAS,CAAC;AAIjB;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAC3D,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,MAAM,CAAC,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,GAC5B,eAAe,CA2EjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sage.d.ts","sourceRoot":"","sources":["../../src/expansion/sage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAU,MAAM,UAAU,CAAC;AAC1E,OAAO,KAAK,EACX,IAAI,EACJ,eAAe,EACf,eAAe,EAEf,MAAM,SAAS,CAAC;AAGjB;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAC1D,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,MAAM,CAAC,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,GAC5B,eAAe,
|
|
1
|
+
{"version":3,"file":"sage.d.ts","sourceRoot":"","sources":["../../src/expansion/sage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAU,MAAM,UAAU,CAAC;AAC1E,OAAO,KAAK,EACX,IAAI,EACJ,eAAe,EACf,eAAe,EAEf,MAAM,SAAS,CAAC;AAGjB;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAC1D,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,MAAM,CAAC,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,GAC5B,eAAe,CAiDjB"}
|
package/dist/index/index.cjs
CHANGED
|
@@ -26,6 +26,8 @@ function base(graph, seeds, config) {
|
|
|
26
26
|
const { maxNodes = 0, maxIterations = 0, maxPaths = 0, priority = degreePriority, debug = false } = config ?? {};
|
|
27
27
|
if (seeds.length === 0) return emptyResult("base", startTime);
|
|
28
28
|
const numFrontiers = seeds.length;
|
|
29
|
+
const allVisited = /* @__PURE__ */ new Set();
|
|
30
|
+
const combinedVisited = /* @__PURE__ */ new Map();
|
|
29
31
|
const visitedByFrontier = [];
|
|
30
32
|
const predecessors = [];
|
|
31
33
|
const queues = [];
|
|
@@ -37,15 +39,16 @@ function base(graph, seeds, config) {
|
|
|
37
39
|
if (seed === void 0) continue;
|
|
38
40
|
const seedNode = seed.id;
|
|
39
41
|
predecessors[i]?.set(seedNode, null);
|
|
40
|
-
|
|
42
|
+
combinedVisited.set(seedNode, i);
|
|
43
|
+
allVisited.add(seedNode);
|
|
44
|
+
const seedPriority = priority(seedNode, createPriorityContext(graph, seedNode, i, combinedVisited, allVisited, [], 0));
|
|
41
45
|
queues[i]?.push({
|
|
42
46
|
nodeId: seedNode,
|
|
43
47
|
frontierIndex: i,
|
|
44
48
|
predecessor: null
|
|
45
49
|
}, seedPriority);
|
|
46
50
|
}
|
|
47
|
-
const
|
|
48
|
-
const sampledEdges = /* @__PURE__ */ new Set();
|
|
51
|
+
const sampledEdgeMap = /* @__PURE__ */ new Map();
|
|
49
52
|
const discoveredPaths = [];
|
|
50
53
|
let iterations = 0;
|
|
51
54
|
let edgesTraversed = 0;
|
|
@@ -90,6 +93,7 @@ function base(graph, seeds, config) {
|
|
|
90
93
|
const frontierVisited = visitedByFrontier[activeFrontier];
|
|
91
94
|
if (frontierVisited === void 0 || frontierVisited.has(nodeId)) continue;
|
|
92
95
|
frontierVisited.set(nodeId, activeFrontier);
|
|
96
|
+
combinedVisited.set(nodeId, activeFrontier);
|
|
93
97
|
if (predecessor !== null) {
|
|
94
98
|
const predMap = predecessors[activeFrontier];
|
|
95
99
|
if (predMap !== void 0) predMap.set(nodeId, predecessor);
|
|
@@ -111,11 +115,16 @@ function base(graph, seeds, config) {
|
|
|
111
115
|
const neighbours = graph.neighbours(nodeId);
|
|
112
116
|
for (const neighbour of neighbours) {
|
|
113
117
|
edgesTraversed++;
|
|
114
|
-
const
|
|
115
|
-
|
|
118
|
+
const [s, t] = nodeId < neighbour ? [nodeId, neighbour] : [neighbour, nodeId];
|
|
119
|
+
let targets = sampledEdgeMap.get(s);
|
|
120
|
+
if (targets === void 0) {
|
|
121
|
+
targets = /* @__PURE__ */ new Set();
|
|
122
|
+
sampledEdgeMap.set(s, targets);
|
|
123
|
+
}
|
|
124
|
+
targets.add(t);
|
|
116
125
|
const frontierVisited = visitedByFrontier[activeFrontier];
|
|
117
126
|
if (frontierVisited === void 0 || frontierVisited.has(neighbour)) continue;
|
|
118
|
-
const neighbourPriority = priority(neighbour, createPriorityContext(graph, neighbour, activeFrontier,
|
|
127
|
+
const neighbourPriority = priority(neighbour, createPriorityContext(graph, neighbour, activeFrontier, combinedVisited, allVisited, discoveredPaths, iterations + 1));
|
|
119
128
|
queue.push({
|
|
120
129
|
nodeId: neighbour,
|
|
121
130
|
frontierIndex: activeFrontier,
|
|
@@ -127,14 +136,7 @@ function base(graph, seeds, config) {
|
|
|
127
136
|
const endTime = performance.now();
|
|
128
137
|
const visitedPerFrontier = visitedByFrontier.map((m) => new Set(m.keys()));
|
|
129
138
|
const edgeTuples = /* @__PURE__ */ new Set();
|
|
130
|
-
for (const
|
|
131
|
-
const parts = edgeKey.split("::");
|
|
132
|
-
if (parts.length === 2) {
|
|
133
|
-
const source = parts[0];
|
|
134
|
-
const target = parts[1];
|
|
135
|
-
if (source !== void 0 && target !== void 0) edgeTuples.add([source, target]);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
139
|
+
for (const [source, targets] of sampledEdgeMap) for (const target of targets) edgeTuples.add([source, target]);
|
|
138
140
|
return {
|
|
139
141
|
paths: discoveredPaths,
|
|
140
142
|
sampledNodes: allVisited,
|
|
@@ -154,10 +156,7 @@ function base(graph, seeds, config) {
|
|
|
154
156
|
/**
|
|
155
157
|
* Create priority context for a node.
|
|
156
158
|
*/
|
|
157
|
-
function createPriorityContext(graph, nodeId, frontierIndex,
|
|
158
|
-
const combinedVisited = /* @__PURE__ */ new Map();
|
|
159
|
-
for (const frontierMap of visitedByFrontier) for (const [id, idx] of frontierMap) combinedVisited.set(id, idx);
|
|
160
|
-
const allVisited = new Set(combinedVisited.keys());
|
|
159
|
+
function createPriorityContext(graph, nodeId, frontierIndex, combinedVisited, allVisited, discoveredPaths, iteration) {
|
|
161
160
|
return {
|
|
162
161
|
graph,
|
|
163
162
|
degree: graph.degree(nodeId),
|
|
@@ -341,10 +340,12 @@ function hae(graph, seeds, config) {
|
|
|
341
340
|
* visited by OTHER frontiers (not the current frontier).
|
|
342
341
|
*/
|
|
343
342
|
function pipePriority(nodeId, context) {
|
|
344
|
-
const
|
|
345
|
-
const neighbours = new Set(graph.neighbours(nodeId));
|
|
343
|
+
const neighbours = context.graph.neighbours(nodeId);
|
|
346
344
|
let pathPotential = 0;
|
|
347
|
-
for (const
|
|
345
|
+
for (const neighbour of neighbours) {
|
|
346
|
+
const visitedBy = context.visitedByFrontier.get(neighbour);
|
|
347
|
+
if (visitedBy !== void 0 && visitedBy !== context.frontierIndex) pathPotential++;
|
|
348
|
+
}
|
|
348
349
|
return context.degree / (1 + pathPotential);
|
|
349
350
|
}
|
|
350
351
|
/**
|
|
@@ -387,10 +388,7 @@ function sage(graph, seeds, config) {
|
|
|
387
388
|
*/
|
|
388
389
|
function sagePriority(nodeId, context) {
|
|
389
390
|
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
|
-
}
|
|
391
|
+
if (pathCount > 0 && !inPhase2) inPhase2 = true;
|
|
394
392
|
if (pathCount > lastPathCount) {
|
|
395
393
|
for (let i = lastPathCount; i < pathCount; i++) {
|
|
396
394
|
const path = context.discoveredPaths[i];
|
|
@@ -440,6 +438,23 @@ function jaccard(graph, source, target, config) {
|
|
|
440
438
|
*/
|
|
441
439
|
function reach(graph, seeds, config) {
|
|
442
440
|
let inPhase2 = false;
|
|
441
|
+
const jaccardCache = /* @__PURE__ */ new Map();
|
|
442
|
+
/**
|
|
443
|
+
* Compute Jaccard similarity with caching.
|
|
444
|
+
*
|
|
445
|
+
* Exploits symmetry of Jaccard (J(A,B) = J(B,A)) to reduce
|
|
446
|
+
* duplicate computations when the same pair appears in multiple
|
|
447
|
+
* discovered paths. Key format ensures consistent ordering.
|
|
448
|
+
*/
|
|
449
|
+
function cachedJaccard(source, target) {
|
|
450
|
+
const key = source < target ? `${source}::${target}` : `${target}::${source}`;
|
|
451
|
+
let score = jaccardCache.get(key);
|
|
452
|
+
if (score === void 0) {
|
|
453
|
+
score = jaccard(graph, source, target);
|
|
454
|
+
jaccardCache.set(key, score);
|
|
455
|
+
}
|
|
456
|
+
return score;
|
|
457
|
+
}
|
|
443
458
|
/**
|
|
444
459
|
* REACH priority function with MI estimation.
|
|
445
460
|
*/
|
|
@@ -451,8 +466,8 @@ function reach(graph, seeds, config) {
|
|
|
451
466
|
for (const path of context.discoveredPaths) {
|
|
452
467
|
const fromNodeId = path.fromSeed.id;
|
|
453
468
|
const toNodeId = path.toSeed.id;
|
|
454
|
-
totalMI +=
|
|
455
|
-
totalMI +=
|
|
469
|
+
totalMI += cachedJaccard(nodeId, fromNodeId);
|
|
470
|
+
totalMI += cachedJaccard(nodeId, toNodeId);
|
|
456
471
|
endpointCount += 2;
|
|
457
472
|
}
|
|
458
473
|
const miHat = endpointCount > 0 ? totalMI / endpointCount : 0;
|
|
@@ -500,9 +515,12 @@ function maze(graph, seeds, config) {
|
|
|
500
515
|
}
|
|
501
516
|
lastPathCount = pathCount;
|
|
502
517
|
}
|
|
503
|
-
const nodeNeighbours =
|
|
518
|
+
const nodeNeighbours = graph.neighbours(nodeId);
|
|
504
519
|
let pathPotential = 0;
|
|
505
|
-
for (const
|
|
520
|
+
for (const neighbour of nodeNeighbours) {
|
|
521
|
+
const visitedBy = context.visitedByFrontier.get(neighbour);
|
|
522
|
+
if (visitedBy !== void 0 && visitedBy !== context.frontierIndex) pathPotential++;
|
|
523
|
+
}
|
|
506
524
|
if (!inPhase2) return context.degree / (1 + pathPotential);
|
|
507
525
|
const salience = salienceCounts.get(nodeId) ?? 0;
|
|
508
526
|
return context.degree / (1 + pathPotential) * (1 / (1 + SALIENCE_WEIGHT * salience));
|