graphwise 1.1.1 → 1.3.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 +149 -2
- package/dist/expansion/frontier-balanced.d.ts +12 -0
- package/dist/expansion/frontier-balanced.d.ts.map +1 -0
- package/dist/expansion/frontier-balanced.unit.test.d.ts +2 -0
- package/dist/expansion/frontier-balanced.unit.test.d.ts.map +1 -0
- package/dist/expansion/index.d.ts +12 -13
- package/dist/expansion/index.d.ts.map +1 -1
- package/dist/expansion/random-priority.d.ts +20 -0
- package/dist/expansion/random-priority.d.ts.map +1 -0
- package/dist/expansion/random-priority.unit.test.d.ts +2 -0
- package/dist/expansion/random-priority.unit.test.d.ts.map +1 -0
- package/dist/expansion/standard-bfs.d.ts +12 -0
- package/dist/expansion/standard-bfs.d.ts.map +1 -0
- package/dist/expansion/standard-bfs.unit.test.d.ts +2 -0
- package/dist/expansion/standard-bfs.unit.test.d.ts.map +1 -0
- package/dist/extraction/index.d.ts +6 -6
- package/dist/extraction/index.d.ts.map +1 -1
- package/dist/extraction/motif.d.ts.map +1 -1
- package/dist/gpu/context.d.ts.map +1 -1
- package/dist/gpu/csr.d.ts.map +1 -1
- package/dist/gpu/index.cjs +410 -5
- package/dist/gpu/index.cjs.map +1 -0
- package/dist/gpu/index.d.ts +4 -5
- package/dist/gpu/index.d.ts.map +1 -1
- package/dist/gpu/index.js +400 -2
- package/dist/gpu/index.js.map +1 -0
- package/dist/graph/index.cjs +222 -2
- package/dist/graph/index.cjs.map +1 -0
- package/dist/graph/index.d.ts +3 -3
- package/dist/graph/index.d.ts.map +1 -1
- package/dist/graph/index.js +221 -1
- package/dist/graph/index.js.map +1 -0
- package/dist/index/index.cjs +966 -126
- package/dist/index/index.cjs.map +1 -1
- package/dist/index/index.js +939 -126
- package/dist/index/index.js.map +1 -1
- package/dist/{kmeans-B0HEOU6k.cjs → kmeans-87ExSUNZ.js} +27 -13
- package/dist/{kmeans-DgbsOznU.js.map → kmeans-87ExSUNZ.js.map} +1 -1
- package/dist/{kmeans-DgbsOznU.js → kmeans-BIgSyGKu.cjs} +44 -2
- package/dist/{kmeans-B0HEOU6k.cjs.map → kmeans-BIgSyGKu.cjs.map} +1 -1
- package/dist/ranking/baselines/betweenness.d.ts +13 -0
- package/dist/ranking/baselines/betweenness.d.ts.map +1 -0
- package/dist/ranking/baselines/betweenness.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/betweenness.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/communicability.d.ts +13 -0
- package/dist/ranking/baselines/communicability.d.ts.map +1 -0
- package/dist/ranking/baselines/communicability.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/communicability.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/degree-sum.d.ts +13 -0
- package/dist/ranking/baselines/degree-sum.d.ts.map +1 -0
- package/dist/ranking/baselines/degree-sum.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/degree-sum.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/index.d.ts +20 -0
- package/dist/ranking/baselines/index.d.ts.map +1 -0
- package/dist/ranking/baselines/jaccard-arithmetic.d.ts +13 -0
- package/dist/ranking/baselines/jaccard-arithmetic.d.ts.map +1 -0
- package/dist/ranking/baselines/jaccard-arithmetic.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/jaccard-arithmetic.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/katz.d.ts +13 -0
- package/dist/ranking/baselines/katz.d.ts.map +1 -0
- package/dist/ranking/baselines/katz.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/katz.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/pagerank.d.ts +13 -0
- package/dist/ranking/baselines/pagerank.d.ts.map +1 -0
- package/dist/ranking/baselines/pagerank.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/pagerank.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/random-ranking.d.ts +21 -0
- package/dist/ranking/baselines/random-ranking.d.ts.map +1 -0
- package/dist/ranking/baselines/random-ranking.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/random-ranking.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/resistance-distance.d.ts +13 -0
- package/dist/ranking/baselines/resistance-distance.d.ts.map +1 -0
- package/dist/ranking/baselines/resistance-distance.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/resistance-distance.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/widest-path.d.ts +13 -0
- package/dist/ranking/baselines/widest-path.d.ts.map +1 -0
- package/dist/ranking/baselines/widest-path.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/widest-path.unit.test.d.ts.map +1 -0
- package/dist/ranking/index.d.ts +3 -6
- package/dist/ranking/index.d.ts.map +1 -1
- package/dist/ranking/mi/adamic-adar.d.ts.map +1 -1
- package/dist/ranking/mi/adaptive.d.ts +1 -1
- package/dist/ranking/mi/adaptive.d.ts.map +1 -1
- package/dist/ranking/mi/etch.d.ts.map +1 -1
- package/dist/ranking/mi/index.d.ts +9 -9
- package/dist/ranking/mi/index.d.ts.map +1 -1
- package/dist/ranking/mi/jaccard.d.ts.map +1 -1
- package/dist/ranking/mi/notch.d.ts.map +1 -1
- package/dist/ranking/mi/scale.d.ts.map +1 -1
- package/dist/ranking/mi/skew.d.ts.map +1 -1
- package/dist/ranking/mi/span.d.ts.map +1 -1
- package/dist/schemas/index.d.ts +2 -2
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/seeds/index.cjs +398 -3
- package/dist/seeds/index.cjs.map +1 -0
- package/dist/seeds/index.d.ts +2 -4
- package/dist/seeds/index.d.ts.map +1 -1
- package/dist/seeds/index.js +396 -1
- package/dist/seeds/index.js.map +1 -0
- package/dist/seeds/stratified.d.ts.map +1 -1
- package/dist/structures/index.cjs +133 -2
- package/dist/structures/index.cjs.map +1 -0
- package/dist/structures/index.d.ts +1 -2
- package/dist/structures/index.d.ts.map +1 -1
- package/dist/structures/index.js +132 -1
- package/dist/structures/index.js.map +1 -0
- package/dist/traversal/index.cjs +152 -5
- package/dist/traversal/index.cjs.map +1 -0
- package/dist/traversal/index.d.ts +2 -2
- package/dist/traversal/index.d.ts.map +1 -1
- package/dist/traversal/index.js +148 -1
- package/dist/traversal/index.js.map +1 -0
- package/dist/utils/index.cjs +254 -9
- package/dist/utils/index.cjs.map +1 -0
- package/dist/utils/index.d.ts +4 -3
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +242 -3
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/neighbours.d.ts +54 -0
- package/dist/utils/neighbours.d.ts.map +1 -0
- package/dist/utils/neighbours.unit.test.d.ts +5 -0
- package/dist/utils/neighbours.unit.test.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/gpu-BJRVYBjx.cjs +0 -338
- package/dist/gpu-BJRVYBjx.cjs.map +0 -1
- package/dist/gpu-BveuXugy.js +0 -315
- package/dist/gpu-BveuXugy.js.map +0 -1
- package/dist/graph-DLWiziLB.js +0 -222
- package/dist/graph-DLWiziLB.js.map +0 -1
- package/dist/graph-az06J1YV.cjs +0 -227
- package/dist/graph-az06J1YV.cjs.map +0 -1
- package/dist/seeds-B6J9oJfU.cjs +0 -404
- package/dist/seeds-B6J9oJfU.cjs.map +0 -1
- package/dist/seeds-UNZxqm_U.js +0 -393
- package/dist/seeds-UNZxqm_U.js.map +0 -1
- package/dist/structures-BPfhfqNP.js +0 -133
- package/dist/structures-BPfhfqNP.js.map +0 -1
- package/dist/structures-CJ_S_7fs.cjs +0 -138
- package/dist/structures-CJ_S_7fs.cjs.map +0 -1
- package/dist/traversal-CQCjUwUJ.js +0 -149
- package/dist/traversal-CQCjUwUJ.js.map +0 -1
- package/dist/traversal-QeHaNUWn.cjs +0 -172
- package/dist/traversal-QeHaNUWn.cjs.map +0 -1
- package/dist/utils-Q_akvlMn.js +0 -164
- package/dist/utils-Q_akvlMn.js.map +0 -1
- package/dist/utils-spZa1ZvS.cjs +0 -205
- package/dist/utils-spZa1ZvS.cjs.map +0 -1
|
@@ -22,6 +22,31 @@ function euclideanDistance(a, b) {
|
|
|
22
22
|
const d3 = a.f3 - b.f3;
|
|
23
23
|
return Math.sqrt(d1 * d1 + d2 * d2 + d3 * d3);
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Compute the mean of a set of feature vectors.
|
|
27
|
+
* @internal - Used for testing
|
|
28
|
+
*/
|
|
29
|
+
function _computeMean(vectors) {
|
|
30
|
+
if (vectors.length === 0) return {
|
|
31
|
+
f1: 0,
|
|
32
|
+
f2: 0,
|
|
33
|
+
f3: 0
|
|
34
|
+
};
|
|
35
|
+
let sum1 = 0;
|
|
36
|
+
let sum2 = 0;
|
|
37
|
+
let sum3 = 0;
|
|
38
|
+
for (const v of vectors) {
|
|
39
|
+
sum1 += v.f1;
|
|
40
|
+
sum2 += v.f2;
|
|
41
|
+
sum3 += v.f3;
|
|
42
|
+
}
|
|
43
|
+
const n = vectors.length;
|
|
44
|
+
return {
|
|
45
|
+
f1: sum1 / n,
|
|
46
|
+
f2: sum2 / n,
|
|
47
|
+
f3: sum3 / n
|
|
48
|
+
};
|
|
49
|
+
}
|
|
25
50
|
function normaliseFeatures(features) {
|
|
26
51
|
if (features.length === 0) return [];
|
|
27
52
|
let sum1 = 0;
|
|
@@ -218,17 +243,6 @@ function initialiseCentroidsKMeansPP(features, k, rng) {
|
|
|
218
243
|
return centroids;
|
|
219
244
|
}
|
|
220
245
|
//#endregion
|
|
221
|
-
|
|
222
|
-
enumerable: true,
|
|
223
|
-
get: function() {
|
|
224
|
-
return miniBatchKMeans;
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
Object.defineProperty(exports, "normaliseFeatures", {
|
|
228
|
-
enumerable: true,
|
|
229
|
-
get: function() {
|
|
230
|
-
return normaliseFeatures;
|
|
231
|
-
}
|
|
232
|
-
});
|
|
246
|
+
export { miniBatchKMeans as n, normaliseFeatures as r, _computeMean as t };
|
|
233
247
|
|
|
234
|
-
//# sourceMappingURL=kmeans-
|
|
248
|
+
//# sourceMappingURL=kmeans-87ExSUNZ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kmeans-DgbsOznU.js","names":[],"sources":["../src/utils/kmeans.ts"],"sourcesContent":["/**\n * Minimal K-means clustering implementation for GRASP seed selection.\n *\n * This is a lightweight implementation specifically designed for 3D feature vectors\n * used in structural seed selection. For general-purpose clustering, consider\n * using a dedicated library.\n *\n * @packageDocumentation\n */\n\n/**\n * A 3D feature vector representing node structural properties.\n */\nexport interface FeatureVector3D {\n\t/** First dimension (e.g., log-degree) */\n\treadonly f1: number;\n\t/** Second dimension (e.g., clustering coefficient) */\n\treadonly f2: number;\n\t/** Third dimension (e.g., approximate PageRank) */\n\treadonly f3: number;\n}\n\n/**\n * A labelled feature vector with associated node ID.\n */\nexport interface LabelledFeature extends FeatureVector3D {\n\t/** Node identifier */\n\treadonly nodeId: string;\n}\n\n/**\n * Result of K-means clustering.\n */\nexport interface KMeansResult {\n\t/** Cluster centroids */\n\treadonly centroids: readonly FeatureVector3D[];\n\t/** Cluster assignments: nodeId -> cluster index */\n\treadonly assignments: ReadonlyMap<string, number>;\n\t/** Number of clusters */\n\treadonly k: number;\n}\n\n/**\n * Options for K-means clustering.\n */\nexport interface KMeansOptions {\n\t/** Number of clusters */\n\treadonly k: number;\n\t/** Maximum iterations (default: 100) */\n\treadonly maxIterations?: number;\n\t/** Convergence threshold (default: 1e-6) */\n\treadonly tolerance?: number;\n\t/** Random seed for reproducibility */\n\treadonly seed?: number;\n}\n\n/** Small epsilon to prevent division by zero */\nconst EPSILON = 1e-10;\n\n/**\n * Simple seeded pseudo-random number generator using mulberry32.\n */\nfunction createRNG(seed: number): () => number {\n\tlet state = seed >>> 0;\n\treturn (): number => {\n\t\tstate = (state + 0x6d2b79f5) >>> 0;\n\t\tlet t = Math.imul(state ^ (state >>> 15), state | 1);\n\t\tt = (t ^ (t >>> 7)) * (t | 0x61c88647);\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\n/**\n * Compute Euclidean distance between two 3D feature vectors.\n */\nfunction euclideanDistance(a: FeatureVector3D, b: FeatureVector3D): number {\n\tconst d1 = a.f1 - b.f1;\n\tconst d2 = a.f2 - b.f2;\n\tconst d3 = a.f3 - b.f3;\n\treturn Math.sqrt(d1 * d1 + d2 * d2 + d3 * d3);\n}\n\n/**\n * Compute the mean of a set of feature vectors.\n * @internal - Used for testing\n */\nexport function _computeMean(\n\tvectors: readonly FeatureVector3D[],\n): FeatureVector3D {\n\tif (vectors.length === 0) {\n\t\treturn { f1: 0, f2: 0, f3: 0 };\n\t}\n\tlet sum1 = 0;\n\tlet sum2 = 0;\n\tlet sum3 = 0;\n\tfor (const v of vectors) {\n\t\tsum1 += v.f1;\n\t\tsum2 += v.f2;\n\t\tsum3 += v.f3;\n\t}\n\tconst n = vectors.length;\n\treturn { f1: sum1 / n, f2: sum2 / n, f3: sum3 / n };\n}\n\n/**\n * Z-score normalise features (zero mean, unit variance).\n */\nexport { normaliseFeatures as zScoreNormalise };\n\nexport function normaliseFeatures(\n\tfeatures: readonly LabelledFeature[],\n): LabelledFeature[] {\n\tif (features.length === 0) {\n\t\treturn [];\n\t}\n\n\t// Compute means\n\tlet sum1 = 0;\n\tlet sum2 = 0;\n\tlet sum3 = 0;\n\tfor (const f of features) {\n\t\tsum1 += f.f1;\n\t\tsum2 += f.f2;\n\t\tsum3 += f.f3;\n\t}\n\tconst n = features.length;\n\tconst mean1 = sum1 / n;\n\tconst mean2 = sum2 / n;\n\tconst mean3 = sum3 / n;\n\n\t// Compute standard deviations\n\tlet var1 = 0;\n\tlet var2 = 0;\n\tlet var3 = 0;\n\tfor (const f of features) {\n\t\tvar1 += (f.f1 - mean1) ** 2;\n\t\tvar2 += (f.f2 - mean2) ** 2;\n\t\tvar3 += (f.f3 - mean3) ** 2;\n\t}\n\tconst std1 = Math.sqrt(var1 / n + EPSILON);\n\tconst std2 = Math.sqrt(var2 / n + EPSILON);\n\tconst std3 = Math.sqrt(var3 / n + EPSILON);\n\n\t// Normalise\n\treturn features.map(\n\t\t(f): LabelledFeature => ({\n\t\t\tnodeId: f.nodeId,\n\t\t\tf1: (f.f1 - mean1) / std1,\n\t\t\tf2: (f.f2 - mean2) / std2,\n\t\t\tf3: (f.f3 - mean3) / std3,\n\t\t}),\n\t);\n}\n\n/**\n * Mini-batch K-means clustering for 3D feature vectors.\n *\n * Uses Mini-batch K-means for efficiency with large datasets.\n * This is specifically designed for the GRASP seed selection algorithm.\n *\n * @param features - Array of labelled feature vectors\n * @param options - Clustering options\n * @returns Clustering result with centroids and assignments\n */\nexport function miniBatchKMeans(\n\tfeatures: readonly LabelledFeature[],\n\toptions: KMeansOptions,\n): KMeansResult {\n\tconst { k, maxIterations = 100, tolerance = 1e-6, seed = 42 } = options;\n\n\tif (features.length === 0) {\n\t\treturn {\n\t\t\tcentroids: [],\n\t\t\tassignments: new Map(),\n\t\t\tk,\n\t\t};\n\t}\n\n\tconst rng = createRNG(seed);\n\tconst n = features.length;\n\tconst effectiveK = Math.min(k, n);\n\n\t// Initialise centroids using k-means++ seeding\n\tconst centroids: FeatureVector3D[] = initialiseCentroidsKMeansPP(\n\t\tfeatures,\n\t\teffectiveK,\n\t\trng,\n\t);\n\n\t// Assignments map\n\tconst assignments = new Map<string, number>();\n\n\t// Mini-batch size (10% of data or at least 10)\n\tconst batchSize = Math.max(10, Math.floor(n / 10));\n\n\tfor (let iter = 0; iter < maxIterations; iter++) {\n\t\t// Sample mini-batch\n\t\tconst batchIndices = new Set<number>();\n\t\twhile (batchIndices.size < Math.min(batchSize, n)) {\n\t\t\tbatchIndices.add(Math.floor(rng() * n));\n\t\t}\n\n\t\t// Assign batch points to nearest centroid\n\t\tconst batchPoints: { feature: LabelledFeature; cluster: number }[] = [];\n\t\tfor (const idx of batchIndices) {\n\t\t\tconst feature = features[idx];\n\t\t\tif (feature === undefined) continue;\n\t\t\tlet minDist = Infinity;\n\t\t\tlet bestCluster = 0;\n\t\t\tfor (let c = 0; c < centroids.length; c++) {\n\t\t\t\tconst centroid = centroids[c];\n\t\t\t\tif (centroid === undefined) continue;\n\t\t\t\tconst dist = euclideanDistance(feature, centroid);\n\t\t\t\tif (dist < minDist) {\n\t\t\t\t\tminDist = dist;\n\t\t\t\t\tbestCluster = c;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbatchPoints.push({ feature, cluster: bestCluster });\n\t\t}\n\n\t\t// Update centroids based on batch\n\t\tconst oldCentroids = centroids.map((c) => ({ ...c }));\n\n\t\t// Compute per-cluster counts and sums from batch\n\t\tconst clusterCounts = Array.from({ length: centroids.length }, () => 0);\n\t\tconst clusterSums: [number, number, number][] = Array.from(\n\t\t\t{ length: centroids.length },\n\t\t\t(): [number, number, number] => [0, 0, 0],\n\t\t);\n\n\t\tfor (const { feature, cluster } of batchPoints) {\n\t\t\tconst currentCount = clusterCounts[cluster];\n\t\t\tif (currentCount !== undefined) {\n\t\t\t\tclusterCounts[cluster] = currentCount + 1;\n\t\t\t}\n\t\t\tconst sum = clusterSums[cluster];\n\t\t\tif (sum !== undefined) {\n\t\t\t\tsum[0] += feature.f1;\n\t\t\t\tsum[1] += feature.f2;\n\t\t\t\tsum[2] += feature.f3;\n\t\t\t}\n\t\t}\n\n\t\t// Update centroids\n\t\tfor (let c = 0; c < centroids.length; c++) {\n\t\t\tconst count = clusterCounts[c] ?? 0;\n\t\t\tif (count > 0) {\n\t\t\t\tconst sum = clusterSums[c];\n\t\t\t\tif (sum !== undefined) {\n\t\t\t\t\tcentroids[c] = {\n\t\t\t\t\t\tf1: sum[0] / count,\n\t\t\t\t\t\tf2: sum[1] / count,\n\t\t\t\t\t\tf3: sum[2] / count,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check convergence\n\t\tlet maxShift = 0;\n\t\tfor (let c = 0; c < centroids.length; c++) {\n\t\t\tconst newCentroid = centroids[c];\n\t\t\tconst oldCentroid = oldCentroids[c];\n\t\t\tif (newCentroid !== undefined && oldCentroid !== undefined) {\n\t\t\t\tconst shift = euclideanDistance(newCentroid, oldCentroid);\n\t\t\t\tmaxShift = Math.max(maxShift, shift);\n\t\t\t}\n\t\t}\n\n\t\tif (maxShift < tolerance) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Final assignment of all points\n\tfor (const feature of features) {\n\t\tlet minDist = Infinity;\n\t\tlet bestCluster = 0;\n\t\tfor (let c = 0; c < centroids.length; c++) {\n\t\t\tconst centroid = centroids[c];\n\t\t\tif (centroid === undefined) continue;\n\t\t\tconst dist = euclideanDistance(feature, centroid);\n\t\t\tif (dist < minDist) {\n\t\t\t\tminDist = dist;\n\t\t\t\tbestCluster = c;\n\t\t\t}\n\t\t}\n\t\tassignments.set(feature.nodeId, bestCluster);\n\t}\n\n\treturn {\n\t\tcentroids,\n\t\tassignments,\n\t\tk: effectiveK,\n\t};\n}\n\n/**\n * K-means++ initialisation for better centroid seeding.\n */\nfunction initialiseCentroidsKMeansPP(\n\tfeatures: readonly LabelledFeature[],\n\tk: number,\n\trng: () => number,\n): FeatureVector3D[] {\n\tconst centroids: FeatureVector3D[] = [];\n\tconst n = features.length;\n\n\t// Choose first centroid randomly\n\tconst firstIdx = Math.floor(rng() * n);\n\tconst firstFeature = features[firstIdx];\n\tif (firstFeature === undefined) {\n\t\treturn [{ f1: 0, f2: 0, f3: 0 }];\n\t}\n\tcentroids.push({\n\t\tf1: firstFeature.f1,\n\t\tf2: firstFeature.f2,\n\t\tf3: firstFeature.f3,\n\t});\n\n\t// Choose remaining centroids with probability proportional to squared distance\n\tconst distances = Array.from({ length: n }, () => Infinity);\n\n\tfor (let c = 1; c < k; c++) {\n\t\t// Update distances to nearest centroid\n\t\tlet totalDistSq = 0;\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tconst feature = features[i];\n\t\t\tif (feature === undefined) continue;\n\t\t\tconst lastCentroid = centroids[c - 1];\n\t\t\tif (lastCentroid === undefined) continue;\n\t\t\tconst dist = euclideanDistance(feature, lastCentroid);\n\t\t\tconst currentMin = distances[i];\n\t\t\tif (currentMin !== undefined && dist < currentMin) {\n\t\t\t\tdistances[i] = dist;\n\t\t\t}\n\t\t\tconst d = distances[i];\n\t\t\tif (d !== undefined) {\n\t\t\t\ttotalDistSq += d * d;\n\t\t\t}\n\t\t}\n\n\t\t// Choose next centroid with probability proportional to squared distance\n\t\tconst threshold = rng() * totalDistSq;\n\t\tlet cumulative = 0;\n\t\tlet nextIdx = 0;\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tconst d = distances[i];\n\t\t\tif (d !== undefined) {\n\t\t\t\tcumulative += d * d;\n\t\t\t\tif (cumulative >= threshold) {\n\t\t\t\t\tnextIdx = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst nextFeature = features[nextIdx];\n\t\tif (nextFeature !== undefined) {\n\t\t\tcentroids.push({\n\t\t\t\tf1: nextFeature.f1,\n\t\t\t\tf2: nextFeature.f2,\n\t\t\t\tf3: nextFeature.f3,\n\t\t\t});\n\t\t} else {\n\t\t\t// Fallback: use zero centroid\n\t\t\tcentroids.push({ f1: 0, f2: 0, f3: 0 });\n\t\t}\n\t}\n\n\treturn centroids;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"kmeans-87ExSUNZ.js","names":[],"sources":["../src/utils/kmeans.ts"],"sourcesContent":["/**\n * Minimal K-means clustering implementation for GRASP seed selection.\n *\n * This is a lightweight implementation specifically designed for 3D feature vectors\n * used in structural seed selection. For general-purpose clustering, consider\n * using a dedicated library.\n *\n * @packageDocumentation\n */\n\n/**\n * A 3D feature vector representing node structural properties.\n */\nexport interface FeatureVector3D {\n\t/** First dimension (e.g., log-degree) */\n\treadonly f1: number;\n\t/** Second dimension (e.g., clustering coefficient) */\n\treadonly f2: number;\n\t/** Third dimension (e.g., approximate PageRank) */\n\treadonly f3: number;\n}\n\n/**\n * A labelled feature vector with associated node ID.\n */\nexport interface LabelledFeature extends FeatureVector3D {\n\t/** Node identifier */\n\treadonly nodeId: string;\n}\n\n/**\n * Result of K-means clustering.\n */\nexport interface KMeansResult {\n\t/** Cluster centroids */\n\treadonly centroids: readonly FeatureVector3D[];\n\t/** Cluster assignments: nodeId -> cluster index */\n\treadonly assignments: ReadonlyMap<string, number>;\n\t/** Number of clusters */\n\treadonly k: number;\n}\n\n/**\n * Options for K-means clustering.\n */\nexport interface KMeansOptions {\n\t/** Number of clusters */\n\treadonly k: number;\n\t/** Maximum iterations (default: 100) */\n\treadonly maxIterations?: number;\n\t/** Convergence threshold (default: 1e-6) */\n\treadonly tolerance?: number;\n\t/** Random seed for reproducibility */\n\treadonly seed?: number;\n}\n\n/** Small epsilon to prevent division by zero */\nconst EPSILON = 1e-10;\n\n/**\n * Simple seeded pseudo-random number generator using mulberry32.\n */\nfunction createRNG(seed: number): () => number {\n\tlet state = seed >>> 0;\n\treturn (): number => {\n\t\tstate = (state + 0x6d2b79f5) >>> 0;\n\t\tlet t = Math.imul(state ^ (state >>> 15), state | 1);\n\t\tt = (t ^ (t >>> 7)) * (t | 0x61c88647);\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\n/**\n * Compute Euclidean distance between two 3D feature vectors.\n */\nfunction euclideanDistance(a: FeatureVector3D, b: FeatureVector3D): number {\n\tconst d1 = a.f1 - b.f1;\n\tconst d2 = a.f2 - b.f2;\n\tconst d3 = a.f3 - b.f3;\n\treturn Math.sqrt(d1 * d1 + d2 * d2 + d3 * d3);\n}\n\n/**\n * Compute the mean of a set of feature vectors.\n * @internal - Used for testing\n */\nexport function _computeMean(\n\tvectors: readonly FeatureVector3D[],\n): FeatureVector3D {\n\tif (vectors.length === 0) {\n\t\treturn { f1: 0, f2: 0, f3: 0 };\n\t}\n\tlet sum1 = 0;\n\tlet sum2 = 0;\n\tlet sum3 = 0;\n\tfor (const v of vectors) {\n\t\tsum1 += v.f1;\n\t\tsum2 += v.f2;\n\t\tsum3 += v.f3;\n\t}\n\tconst n = vectors.length;\n\treturn { f1: sum1 / n, f2: sum2 / n, f3: sum3 / n };\n}\n\n/**\n * Z-score normalise features (zero mean, unit variance).\n */\nexport { normaliseFeatures as zScoreNormalise };\n\nexport function normaliseFeatures(\n\tfeatures: readonly LabelledFeature[],\n): LabelledFeature[] {\n\tif (features.length === 0) {\n\t\treturn [];\n\t}\n\n\t// Compute means\n\tlet sum1 = 0;\n\tlet sum2 = 0;\n\tlet sum3 = 0;\n\tfor (const f of features) {\n\t\tsum1 += f.f1;\n\t\tsum2 += f.f2;\n\t\tsum3 += f.f3;\n\t}\n\tconst n = features.length;\n\tconst mean1 = sum1 / n;\n\tconst mean2 = sum2 / n;\n\tconst mean3 = sum3 / n;\n\n\t// Compute standard deviations\n\tlet var1 = 0;\n\tlet var2 = 0;\n\tlet var3 = 0;\n\tfor (const f of features) {\n\t\tvar1 += (f.f1 - mean1) ** 2;\n\t\tvar2 += (f.f2 - mean2) ** 2;\n\t\tvar3 += (f.f3 - mean3) ** 2;\n\t}\n\tconst std1 = Math.sqrt(var1 / n + EPSILON);\n\tconst std2 = Math.sqrt(var2 / n + EPSILON);\n\tconst std3 = Math.sqrt(var3 / n + EPSILON);\n\n\t// Normalise\n\treturn features.map(\n\t\t(f): LabelledFeature => ({\n\t\t\tnodeId: f.nodeId,\n\t\t\tf1: (f.f1 - mean1) / std1,\n\t\t\tf2: (f.f2 - mean2) / std2,\n\t\t\tf3: (f.f3 - mean3) / std3,\n\t\t}),\n\t);\n}\n\n/**\n * Mini-batch K-means clustering for 3D feature vectors.\n *\n * Uses Mini-batch K-means for efficiency with large datasets.\n * This is specifically designed for the GRASP seed selection algorithm.\n *\n * @param features - Array of labelled feature vectors\n * @param options - Clustering options\n * @returns Clustering result with centroids and assignments\n */\nexport function miniBatchKMeans(\n\tfeatures: readonly LabelledFeature[],\n\toptions: KMeansOptions,\n): KMeansResult {\n\tconst { k, maxIterations = 100, tolerance = 1e-6, seed = 42 } = options;\n\n\tif (features.length === 0) {\n\t\treturn {\n\t\t\tcentroids: [],\n\t\t\tassignments: new Map(),\n\t\t\tk,\n\t\t};\n\t}\n\n\tconst rng = createRNG(seed);\n\tconst n = features.length;\n\tconst effectiveK = Math.min(k, n);\n\n\t// Initialise centroids using k-means++ seeding\n\tconst centroids: FeatureVector3D[] = initialiseCentroidsKMeansPP(\n\t\tfeatures,\n\t\teffectiveK,\n\t\trng,\n\t);\n\n\t// Assignments map\n\tconst assignments = new Map<string, number>();\n\n\t// Mini-batch size (10% of data or at least 10)\n\tconst batchSize = Math.max(10, Math.floor(n / 10));\n\n\tfor (let iter = 0; iter < maxIterations; iter++) {\n\t\t// Sample mini-batch\n\t\tconst batchIndices = new Set<number>();\n\t\twhile (batchIndices.size < Math.min(batchSize, n)) {\n\t\t\tbatchIndices.add(Math.floor(rng() * n));\n\t\t}\n\n\t\t// Assign batch points to nearest centroid\n\t\tconst batchPoints: { feature: LabelledFeature; cluster: number }[] = [];\n\t\tfor (const idx of batchIndices) {\n\t\t\tconst feature = features[idx];\n\t\t\tif (feature === undefined) continue;\n\t\t\tlet minDist = Infinity;\n\t\t\tlet bestCluster = 0;\n\t\t\tfor (let c = 0; c < centroids.length; c++) {\n\t\t\t\tconst centroid = centroids[c];\n\t\t\t\tif (centroid === undefined) continue;\n\t\t\t\tconst dist = euclideanDistance(feature, centroid);\n\t\t\t\tif (dist < minDist) {\n\t\t\t\t\tminDist = dist;\n\t\t\t\t\tbestCluster = c;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbatchPoints.push({ feature, cluster: bestCluster });\n\t\t}\n\n\t\t// Update centroids based on batch\n\t\tconst oldCentroids = centroids.map((c) => ({ ...c }));\n\n\t\t// Compute per-cluster counts and sums from batch\n\t\tconst clusterCounts = Array.from({ length: centroids.length }, () => 0);\n\t\tconst clusterSums: [number, number, number][] = Array.from(\n\t\t\t{ length: centroids.length },\n\t\t\t(): [number, number, number] => [0, 0, 0],\n\t\t);\n\n\t\tfor (const { feature, cluster } of batchPoints) {\n\t\t\tconst currentCount = clusterCounts[cluster];\n\t\t\tif (currentCount !== undefined) {\n\t\t\t\tclusterCounts[cluster] = currentCount + 1;\n\t\t\t}\n\t\t\tconst sum = clusterSums[cluster];\n\t\t\tif (sum !== undefined) {\n\t\t\t\tsum[0] += feature.f1;\n\t\t\t\tsum[1] += feature.f2;\n\t\t\t\tsum[2] += feature.f3;\n\t\t\t}\n\t\t}\n\n\t\t// Update centroids\n\t\tfor (let c = 0; c < centroids.length; c++) {\n\t\t\tconst count = clusterCounts[c] ?? 0;\n\t\t\tif (count > 0) {\n\t\t\t\tconst sum = clusterSums[c];\n\t\t\t\tif (sum !== undefined) {\n\t\t\t\t\tcentroids[c] = {\n\t\t\t\t\t\tf1: sum[0] / count,\n\t\t\t\t\t\tf2: sum[1] / count,\n\t\t\t\t\t\tf3: sum[2] / count,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check convergence\n\t\tlet maxShift = 0;\n\t\tfor (let c = 0; c < centroids.length; c++) {\n\t\t\tconst newCentroid = centroids[c];\n\t\t\tconst oldCentroid = oldCentroids[c];\n\t\t\tif (newCentroid !== undefined && oldCentroid !== undefined) {\n\t\t\t\tconst shift = euclideanDistance(newCentroid, oldCentroid);\n\t\t\t\tmaxShift = Math.max(maxShift, shift);\n\t\t\t}\n\t\t}\n\n\t\tif (maxShift < tolerance) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Final assignment of all points\n\tfor (const feature of features) {\n\t\tlet minDist = Infinity;\n\t\tlet bestCluster = 0;\n\t\tfor (let c = 0; c < centroids.length; c++) {\n\t\t\tconst centroid = centroids[c];\n\t\t\tif (centroid === undefined) continue;\n\t\t\tconst dist = euclideanDistance(feature, centroid);\n\t\t\tif (dist < minDist) {\n\t\t\t\tminDist = dist;\n\t\t\t\tbestCluster = c;\n\t\t\t}\n\t\t}\n\t\tassignments.set(feature.nodeId, bestCluster);\n\t}\n\n\treturn {\n\t\tcentroids,\n\t\tassignments,\n\t\tk: effectiveK,\n\t};\n}\n\n/**\n * K-means++ initialisation for better centroid seeding.\n */\nfunction initialiseCentroidsKMeansPP(\n\tfeatures: readonly LabelledFeature[],\n\tk: number,\n\trng: () => number,\n): FeatureVector3D[] {\n\tconst centroids: FeatureVector3D[] = [];\n\tconst n = features.length;\n\n\t// Choose first centroid randomly\n\tconst firstIdx = Math.floor(rng() * n);\n\tconst firstFeature = features[firstIdx];\n\tif (firstFeature === undefined) {\n\t\treturn [{ f1: 0, f2: 0, f3: 0 }];\n\t}\n\tcentroids.push({\n\t\tf1: firstFeature.f1,\n\t\tf2: firstFeature.f2,\n\t\tf3: firstFeature.f3,\n\t});\n\n\t// Choose remaining centroids with probability proportional to squared distance\n\tconst distances = Array.from({ length: n }, () => Infinity);\n\n\tfor (let c = 1; c < k; c++) {\n\t\t// Update distances to nearest centroid\n\t\tlet totalDistSq = 0;\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tconst feature = features[i];\n\t\t\tif (feature === undefined) continue;\n\t\t\tconst lastCentroid = centroids[c - 1];\n\t\t\tif (lastCentroid === undefined) continue;\n\t\t\tconst dist = euclideanDistance(feature, lastCentroid);\n\t\t\tconst currentMin = distances[i];\n\t\t\tif (currentMin !== undefined && dist < currentMin) {\n\t\t\t\tdistances[i] = dist;\n\t\t\t}\n\t\t\tconst d = distances[i];\n\t\t\tif (d !== undefined) {\n\t\t\t\ttotalDistSq += d * d;\n\t\t\t}\n\t\t}\n\n\t\t// Choose next centroid with probability proportional to squared distance\n\t\tconst threshold = rng() * totalDistSq;\n\t\tlet cumulative = 0;\n\t\tlet nextIdx = 0;\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tconst d = distances[i];\n\t\t\tif (d !== undefined) {\n\t\t\t\tcumulative += d * d;\n\t\t\t\tif (cumulative >= threshold) {\n\t\t\t\t\tnextIdx = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst nextFeature = features[nextIdx];\n\t\tif (nextFeature !== undefined) {\n\t\t\tcentroids.push({\n\t\t\t\tf1: nextFeature.f1,\n\t\t\t\tf2: nextFeature.f2,\n\t\t\t\tf3: nextFeature.f3,\n\t\t\t});\n\t\t} else {\n\t\t\t// Fallback: use zero centroid\n\t\t\tcentroids.push({ f1: 0, f2: 0, f3: 0 });\n\t\t}\n\t}\n\n\treturn centroids;\n}\n"],"mappings":"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"}
|
|
@@ -22,6 +22,31 @@ function euclideanDistance(a, b) {
|
|
|
22
22
|
const d3 = a.f3 - b.f3;
|
|
23
23
|
return Math.sqrt(d1 * d1 + d2 * d2 + d3 * d3);
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Compute the mean of a set of feature vectors.
|
|
27
|
+
* @internal - Used for testing
|
|
28
|
+
*/
|
|
29
|
+
function _computeMean(vectors) {
|
|
30
|
+
if (vectors.length === 0) return {
|
|
31
|
+
f1: 0,
|
|
32
|
+
f2: 0,
|
|
33
|
+
f3: 0
|
|
34
|
+
};
|
|
35
|
+
let sum1 = 0;
|
|
36
|
+
let sum2 = 0;
|
|
37
|
+
let sum3 = 0;
|
|
38
|
+
for (const v of vectors) {
|
|
39
|
+
sum1 += v.f1;
|
|
40
|
+
sum2 += v.f2;
|
|
41
|
+
sum3 += v.f3;
|
|
42
|
+
}
|
|
43
|
+
const n = vectors.length;
|
|
44
|
+
return {
|
|
45
|
+
f1: sum1 / n,
|
|
46
|
+
f2: sum2 / n,
|
|
47
|
+
f3: sum3 / n
|
|
48
|
+
};
|
|
49
|
+
}
|
|
25
50
|
function normaliseFeatures(features) {
|
|
26
51
|
if (features.length === 0) return [];
|
|
27
52
|
let sum1 = 0;
|
|
@@ -218,6 +243,23 @@ function initialiseCentroidsKMeansPP(features, k, rng) {
|
|
|
218
243
|
return centroids;
|
|
219
244
|
}
|
|
220
245
|
//#endregion
|
|
221
|
-
|
|
246
|
+
Object.defineProperty(exports, "_computeMean", {
|
|
247
|
+
enumerable: true,
|
|
248
|
+
get: function() {
|
|
249
|
+
return _computeMean;
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
Object.defineProperty(exports, "miniBatchKMeans", {
|
|
253
|
+
enumerable: true,
|
|
254
|
+
get: function() {
|
|
255
|
+
return miniBatchKMeans;
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
Object.defineProperty(exports, "normaliseFeatures", {
|
|
259
|
+
enumerable: true,
|
|
260
|
+
get: function() {
|
|
261
|
+
return normaliseFeatures;
|
|
262
|
+
}
|
|
263
|
+
});
|
|
222
264
|
|
|
223
|
-
//# sourceMappingURL=kmeans-
|
|
265
|
+
//# sourceMappingURL=kmeans-BIgSyGKu.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kmeans-B0HEOU6k.cjs","names":[],"sources":["../src/utils/kmeans.ts"],"sourcesContent":["/**\n * Minimal K-means clustering implementation for GRASP seed selection.\n *\n * This is a lightweight implementation specifically designed for 3D feature vectors\n * used in structural seed selection. For general-purpose clustering, consider\n * using a dedicated library.\n *\n * @packageDocumentation\n */\n\n/**\n * A 3D feature vector representing node structural properties.\n */\nexport interface FeatureVector3D {\n\t/** First dimension (e.g., log-degree) */\n\treadonly f1: number;\n\t/** Second dimension (e.g., clustering coefficient) */\n\treadonly f2: number;\n\t/** Third dimension (e.g., approximate PageRank) */\n\treadonly f3: number;\n}\n\n/**\n * A labelled feature vector with associated node ID.\n */\nexport interface LabelledFeature extends FeatureVector3D {\n\t/** Node identifier */\n\treadonly nodeId: string;\n}\n\n/**\n * Result of K-means clustering.\n */\nexport interface KMeansResult {\n\t/** Cluster centroids */\n\treadonly centroids: readonly FeatureVector3D[];\n\t/** Cluster assignments: nodeId -> cluster index */\n\treadonly assignments: ReadonlyMap<string, number>;\n\t/** Number of clusters */\n\treadonly k: number;\n}\n\n/**\n * Options for K-means clustering.\n */\nexport interface KMeansOptions {\n\t/** Number of clusters */\n\treadonly k: number;\n\t/** Maximum iterations (default: 100) */\n\treadonly maxIterations?: number;\n\t/** Convergence threshold (default: 1e-6) */\n\treadonly tolerance?: number;\n\t/** Random seed for reproducibility */\n\treadonly seed?: number;\n}\n\n/** Small epsilon to prevent division by zero */\nconst EPSILON = 1e-10;\n\n/**\n * Simple seeded pseudo-random number generator using mulberry32.\n */\nfunction createRNG(seed: number): () => number {\n\tlet state = seed >>> 0;\n\treturn (): number => {\n\t\tstate = (state + 0x6d2b79f5) >>> 0;\n\t\tlet t = Math.imul(state ^ (state >>> 15), state | 1);\n\t\tt = (t ^ (t >>> 7)) * (t | 0x61c88647);\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\n/**\n * Compute Euclidean distance between two 3D feature vectors.\n */\nfunction euclideanDistance(a: FeatureVector3D, b: FeatureVector3D): number {\n\tconst d1 = a.f1 - b.f1;\n\tconst d2 = a.f2 - b.f2;\n\tconst d3 = a.f3 - b.f3;\n\treturn Math.sqrt(d1 * d1 + d2 * d2 + d3 * d3);\n}\n\n/**\n * Compute the mean of a set of feature vectors.\n * @internal - Used for testing\n */\nexport function _computeMean(\n\tvectors: readonly FeatureVector3D[],\n): FeatureVector3D {\n\tif (vectors.length === 0) {\n\t\treturn { f1: 0, f2: 0, f3: 0 };\n\t}\n\tlet sum1 = 0;\n\tlet sum2 = 0;\n\tlet sum3 = 0;\n\tfor (const v of vectors) {\n\t\tsum1 += v.f1;\n\t\tsum2 += v.f2;\n\t\tsum3 += v.f3;\n\t}\n\tconst n = vectors.length;\n\treturn { f1: sum1 / n, f2: sum2 / n, f3: sum3 / n };\n}\n\n/**\n * Z-score normalise features (zero mean, unit variance).\n */\nexport { normaliseFeatures as zScoreNormalise };\n\nexport function normaliseFeatures(\n\tfeatures: readonly LabelledFeature[],\n): LabelledFeature[] {\n\tif (features.length === 0) {\n\t\treturn [];\n\t}\n\n\t// Compute means\n\tlet sum1 = 0;\n\tlet sum2 = 0;\n\tlet sum3 = 0;\n\tfor (const f of features) {\n\t\tsum1 += f.f1;\n\t\tsum2 += f.f2;\n\t\tsum3 += f.f3;\n\t}\n\tconst n = features.length;\n\tconst mean1 = sum1 / n;\n\tconst mean2 = sum2 / n;\n\tconst mean3 = sum3 / n;\n\n\t// Compute standard deviations\n\tlet var1 = 0;\n\tlet var2 = 0;\n\tlet var3 = 0;\n\tfor (const f of features) {\n\t\tvar1 += (f.f1 - mean1) ** 2;\n\t\tvar2 += (f.f2 - mean2) ** 2;\n\t\tvar3 += (f.f3 - mean3) ** 2;\n\t}\n\tconst std1 = Math.sqrt(var1 / n + EPSILON);\n\tconst std2 = Math.sqrt(var2 / n + EPSILON);\n\tconst std3 = Math.sqrt(var3 / n + EPSILON);\n\n\t// Normalise\n\treturn features.map(\n\t\t(f): LabelledFeature => ({\n\t\t\tnodeId: f.nodeId,\n\t\t\tf1: (f.f1 - mean1) / std1,\n\t\t\tf2: (f.f2 - mean2) / std2,\n\t\t\tf3: (f.f3 - mean3) / std3,\n\t\t}),\n\t);\n}\n\n/**\n * Mini-batch K-means clustering for 3D feature vectors.\n *\n * Uses Mini-batch K-means for efficiency with large datasets.\n * This is specifically designed for the GRASP seed selection algorithm.\n *\n * @param features - Array of labelled feature vectors\n * @param options - Clustering options\n * @returns Clustering result with centroids and assignments\n */\nexport function miniBatchKMeans(\n\tfeatures: readonly LabelledFeature[],\n\toptions: KMeansOptions,\n): KMeansResult {\n\tconst { k, maxIterations = 100, tolerance = 1e-6, seed = 42 } = options;\n\n\tif (features.length === 0) {\n\t\treturn {\n\t\t\tcentroids: [],\n\t\t\tassignments: new Map(),\n\t\t\tk,\n\t\t};\n\t}\n\n\tconst rng = createRNG(seed);\n\tconst n = features.length;\n\tconst effectiveK = Math.min(k, n);\n\n\t// Initialise centroids using k-means++ seeding\n\tconst centroids: FeatureVector3D[] = initialiseCentroidsKMeansPP(\n\t\tfeatures,\n\t\teffectiveK,\n\t\trng,\n\t);\n\n\t// Assignments map\n\tconst assignments = new Map<string, number>();\n\n\t// Mini-batch size (10% of data or at least 10)\n\tconst batchSize = Math.max(10, Math.floor(n / 10));\n\n\tfor (let iter = 0; iter < maxIterations; iter++) {\n\t\t// Sample mini-batch\n\t\tconst batchIndices = new Set<number>();\n\t\twhile (batchIndices.size < Math.min(batchSize, n)) {\n\t\t\tbatchIndices.add(Math.floor(rng() * n));\n\t\t}\n\n\t\t// Assign batch points to nearest centroid\n\t\tconst batchPoints: { feature: LabelledFeature; cluster: number }[] = [];\n\t\tfor (const idx of batchIndices) {\n\t\t\tconst feature = features[idx];\n\t\t\tif (feature === undefined) continue;\n\t\t\tlet minDist = Infinity;\n\t\t\tlet bestCluster = 0;\n\t\t\tfor (let c = 0; c < centroids.length; c++) {\n\t\t\t\tconst centroid = centroids[c];\n\t\t\t\tif (centroid === undefined) continue;\n\t\t\t\tconst dist = euclideanDistance(feature, centroid);\n\t\t\t\tif (dist < minDist) {\n\t\t\t\t\tminDist = dist;\n\t\t\t\t\tbestCluster = c;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbatchPoints.push({ feature, cluster: bestCluster });\n\t\t}\n\n\t\t// Update centroids based on batch\n\t\tconst oldCentroids = centroids.map((c) => ({ ...c }));\n\n\t\t// Compute per-cluster counts and sums from batch\n\t\tconst clusterCounts = Array.from({ length: centroids.length }, () => 0);\n\t\tconst clusterSums: [number, number, number][] = Array.from(\n\t\t\t{ length: centroids.length },\n\t\t\t(): [number, number, number] => [0, 0, 0],\n\t\t);\n\n\t\tfor (const { feature, cluster } of batchPoints) {\n\t\t\tconst currentCount = clusterCounts[cluster];\n\t\t\tif (currentCount !== undefined) {\n\t\t\t\tclusterCounts[cluster] = currentCount + 1;\n\t\t\t}\n\t\t\tconst sum = clusterSums[cluster];\n\t\t\tif (sum !== undefined) {\n\t\t\t\tsum[0] += feature.f1;\n\t\t\t\tsum[1] += feature.f2;\n\t\t\t\tsum[2] += feature.f3;\n\t\t\t}\n\t\t}\n\n\t\t// Update centroids\n\t\tfor (let c = 0; c < centroids.length; c++) {\n\t\t\tconst count = clusterCounts[c] ?? 0;\n\t\t\tif (count > 0) {\n\t\t\t\tconst sum = clusterSums[c];\n\t\t\t\tif (sum !== undefined) {\n\t\t\t\t\tcentroids[c] = {\n\t\t\t\t\t\tf1: sum[0] / count,\n\t\t\t\t\t\tf2: sum[1] / count,\n\t\t\t\t\t\tf3: sum[2] / count,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check convergence\n\t\tlet maxShift = 0;\n\t\tfor (let c = 0; c < centroids.length; c++) {\n\t\t\tconst newCentroid = centroids[c];\n\t\t\tconst oldCentroid = oldCentroids[c];\n\t\t\tif (newCentroid !== undefined && oldCentroid !== undefined) {\n\t\t\t\tconst shift = euclideanDistance(newCentroid, oldCentroid);\n\t\t\t\tmaxShift = Math.max(maxShift, shift);\n\t\t\t}\n\t\t}\n\n\t\tif (maxShift < tolerance) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Final assignment of all points\n\tfor (const feature of features) {\n\t\tlet minDist = Infinity;\n\t\tlet bestCluster = 0;\n\t\tfor (let c = 0; c < centroids.length; c++) {\n\t\t\tconst centroid = centroids[c];\n\t\t\tif (centroid === undefined) continue;\n\t\t\tconst dist = euclideanDistance(feature, centroid);\n\t\t\tif (dist < minDist) {\n\t\t\t\tminDist = dist;\n\t\t\t\tbestCluster = c;\n\t\t\t}\n\t\t}\n\t\tassignments.set(feature.nodeId, bestCluster);\n\t}\n\n\treturn {\n\t\tcentroids,\n\t\tassignments,\n\t\tk: effectiveK,\n\t};\n}\n\n/**\n * K-means++ initialisation for better centroid seeding.\n */\nfunction initialiseCentroidsKMeansPP(\n\tfeatures: readonly LabelledFeature[],\n\tk: number,\n\trng: () => number,\n): FeatureVector3D[] {\n\tconst centroids: FeatureVector3D[] = [];\n\tconst n = features.length;\n\n\t// Choose first centroid randomly\n\tconst firstIdx = Math.floor(rng() * n);\n\tconst firstFeature = features[firstIdx];\n\tif (firstFeature === undefined) {\n\t\treturn [{ f1: 0, f2: 0, f3: 0 }];\n\t}\n\tcentroids.push({\n\t\tf1: firstFeature.f1,\n\t\tf2: firstFeature.f2,\n\t\tf3: firstFeature.f3,\n\t});\n\n\t// Choose remaining centroids with probability proportional to squared distance\n\tconst distances = Array.from({ length: n }, () => Infinity);\n\n\tfor (let c = 1; c < k; c++) {\n\t\t// Update distances to nearest centroid\n\t\tlet totalDistSq = 0;\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tconst feature = features[i];\n\t\t\tif (feature === undefined) continue;\n\t\t\tconst lastCentroid = centroids[c - 1];\n\t\t\tif (lastCentroid === undefined) continue;\n\t\t\tconst dist = euclideanDistance(feature, lastCentroid);\n\t\t\tconst currentMin = distances[i];\n\t\t\tif (currentMin !== undefined && dist < currentMin) {\n\t\t\t\tdistances[i] = dist;\n\t\t\t}\n\t\t\tconst d = distances[i];\n\t\t\tif (d !== undefined) {\n\t\t\t\ttotalDistSq += d * d;\n\t\t\t}\n\t\t}\n\n\t\t// Choose next centroid with probability proportional to squared distance\n\t\tconst threshold = rng() * totalDistSq;\n\t\tlet cumulative = 0;\n\t\tlet nextIdx = 0;\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tconst d = distances[i];\n\t\t\tif (d !== undefined) {\n\t\t\t\tcumulative += d * d;\n\t\t\t\tif (cumulative >= threshold) {\n\t\t\t\t\tnextIdx = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst nextFeature = features[nextIdx];\n\t\tif (nextFeature !== undefined) {\n\t\t\tcentroids.push({\n\t\t\t\tf1: nextFeature.f1,\n\t\t\t\tf2: nextFeature.f2,\n\t\t\t\tf3: nextFeature.f3,\n\t\t\t});\n\t\t} else {\n\t\t\t// Fallback: use zero centroid\n\t\t\tcentroids.push({ f1: 0, f2: 0, f3: 0 });\n\t\t}\n\t}\n\n\treturn centroids;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"kmeans-BIgSyGKu.cjs","names":[],"sources":["../src/utils/kmeans.ts"],"sourcesContent":["/**\n * Minimal K-means clustering implementation for GRASP seed selection.\n *\n * This is a lightweight implementation specifically designed for 3D feature vectors\n * used in structural seed selection. For general-purpose clustering, consider\n * using a dedicated library.\n *\n * @packageDocumentation\n */\n\n/**\n * A 3D feature vector representing node structural properties.\n */\nexport interface FeatureVector3D {\n\t/** First dimension (e.g., log-degree) */\n\treadonly f1: number;\n\t/** Second dimension (e.g., clustering coefficient) */\n\treadonly f2: number;\n\t/** Third dimension (e.g., approximate PageRank) */\n\treadonly f3: number;\n}\n\n/**\n * A labelled feature vector with associated node ID.\n */\nexport interface LabelledFeature extends FeatureVector3D {\n\t/** Node identifier */\n\treadonly nodeId: string;\n}\n\n/**\n * Result of K-means clustering.\n */\nexport interface KMeansResult {\n\t/** Cluster centroids */\n\treadonly centroids: readonly FeatureVector3D[];\n\t/** Cluster assignments: nodeId -> cluster index */\n\treadonly assignments: ReadonlyMap<string, number>;\n\t/** Number of clusters */\n\treadonly k: number;\n}\n\n/**\n * Options for K-means clustering.\n */\nexport interface KMeansOptions {\n\t/** Number of clusters */\n\treadonly k: number;\n\t/** Maximum iterations (default: 100) */\n\treadonly maxIterations?: number;\n\t/** Convergence threshold (default: 1e-6) */\n\treadonly tolerance?: number;\n\t/** Random seed for reproducibility */\n\treadonly seed?: number;\n}\n\n/** Small epsilon to prevent division by zero */\nconst EPSILON = 1e-10;\n\n/**\n * Simple seeded pseudo-random number generator using mulberry32.\n */\nfunction createRNG(seed: number): () => number {\n\tlet state = seed >>> 0;\n\treturn (): number => {\n\t\tstate = (state + 0x6d2b79f5) >>> 0;\n\t\tlet t = Math.imul(state ^ (state >>> 15), state | 1);\n\t\tt = (t ^ (t >>> 7)) * (t | 0x61c88647);\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\n/**\n * Compute Euclidean distance between two 3D feature vectors.\n */\nfunction euclideanDistance(a: FeatureVector3D, b: FeatureVector3D): number {\n\tconst d1 = a.f1 - b.f1;\n\tconst d2 = a.f2 - b.f2;\n\tconst d3 = a.f3 - b.f3;\n\treturn Math.sqrt(d1 * d1 + d2 * d2 + d3 * d3);\n}\n\n/**\n * Compute the mean of a set of feature vectors.\n * @internal - Used for testing\n */\nexport function _computeMean(\n\tvectors: readonly FeatureVector3D[],\n): FeatureVector3D {\n\tif (vectors.length === 0) {\n\t\treturn { f1: 0, f2: 0, f3: 0 };\n\t}\n\tlet sum1 = 0;\n\tlet sum2 = 0;\n\tlet sum3 = 0;\n\tfor (const v of vectors) {\n\t\tsum1 += v.f1;\n\t\tsum2 += v.f2;\n\t\tsum3 += v.f3;\n\t}\n\tconst n = vectors.length;\n\treturn { f1: sum1 / n, f2: sum2 / n, f3: sum3 / n };\n}\n\n/**\n * Z-score normalise features (zero mean, unit variance).\n */\nexport { normaliseFeatures as zScoreNormalise };\n\nexport function normaliseFeatures(\n\tfeatures: readonly LabelledFeature[],\n): LabelledFeature[] {\n\tif (features.length === 0) {\n\t\treturn [];\n\t}\n\n\t// Compute means\n\tlet sum1 = 0;\n\tlet sum2 = 0;\n\tlet sum3 = 0;\n\tfor (const f of features) {\n\t\tsum1 += f.f1;\n\t\tsum2 += f.f2;\n\t\tsum3 += f.f3;\n\t}\n\tconst n = features.length;\n\tconst mean1 = sum1 / n;\n\tconst mean2 = sum2 / n;\n\tconst mean3 = sum3 / n;\n\n\t// Compute standard deviations\n\tlet var1 = 0;\n\tlet var2 = 0;\n\tlet var3 = 0;\n\tfor (const f of features) {\n\t\tvar1 += (f.f1 - mean1) ** 2;\n\t\tvar2 += (f.f2 - mean2) ** 2;\n\t\tvar3 += (f.f3 - mean3) ** 2;\n\t}\n\tconst std1 = Math.sqrt(var1 / n + EPSILON);\n\tconst std2 = Math.sqrt(var2 / n + EPSILON);\n\tconst std3 = Math.sqrt(var3 / n + EPSILON);\n\n\t// Normalise\n\treturn features.map(\n\t\t(f): LabelledFeature => ({\n\t\t\tnodeId: f.nodeId,\n\t\t\tf1: (f.f1 - mean1) / std1,\n\t\t\tf2: (f.f2 - mean2) / std2,\n\t\t\tf3: (f.f3 - mean3) / std3,\n\t\t}),\n\t);\n}\n\n/**\n * Mini-batch K-means clustering for 3D feature vectors.\n *\n * Uses Mini-batch K-means for efficiency with large datasets.\n * This is specifically designed for the GRASP seed selection algorithm.\n *\n * @param features - Array of labelled feature vectors\n * @param options - Clustering options\n * @returns Clustering result with centroids and assignments\n */\nexport function miniBatchKMeans(\n\tfeatures: readonly LabelledFeature[],\n\toptions: KMeansOptions,\n): KMeansResult {\n\tconst { k, maxIterations = 100, tolerance = 1e-6, seed = 42 } = options;\n\n\tif (features.length === 0) {\n\t\treturn {\n\t\t\tcentroids: [],\n\t\t\tassignments: new Map(),\n\t\t\tk,\n\t\t};\n\t}\n\n\tconst rng = createRNG(seed);\n\tconst n = features.length;\n\tconst effectiveK = Math.min(k, n);\n\n\t// Initialise centroids using k-means++ seeding\n\tconst centroids: FeatureVector3D[] = initialiseCentroidsKMeansPP(\n\t\tfeatures,\n\t\teffectiveK,\n\t\trng,\n\t);\n\n\t// Assignments map\n\tconst assignments = new Map<string, number>();\n\n\t// Mini-batch size (10% of data or at least 10)\n\tconst batchSize = Math.max(10, Math.floor(n / 10));\n\n\tfor (let iter = 0; iter < maxIterations; iter++) {\n\t\t// Sample mini-batch\n\t\tconst batchIndices = new Set<number>();\n\t\twhile (batchIndices.size < Math.min(batchSize, n)) {\n\t\t\tbatchIndices.add(Math.floor(rng() * n));\n\t\t}\n\n\t\t// Assign batch points to nearest centroid\n\t\tconst batchPoints: { feature: LabelledFeature; cluster: number }[] = [];\n\t\tfor (const idx of batchIndices) {\n\t\t\tconst feature = features[idx];\n\t\t\tif (feature === undefined) continue;\n\t\t\tlet minDist = Infinity;\n\t\t\tlet bestCluster = 0;\n\t\t\tfor (let c = 0; c < centroids.length; c++) {\n\t\t\t\tconst centroid = centroids[c];\n\t\t\t\tif (centroid === undefined) continue;\n\t\t\t\tconst dist = euclideanDistance(feature, centroid);\n\t\t\t\tif (dist < minDist) {\n\t\t\t\t\tminDist = dist;\n\t\t\t\t\tbestCluster = c;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbatchPoints.push({ feature, cluster: bestCluster });\n\t\t}\n\n\t\t// Update centroids based on batch\n\t\tconst oldCentroids = centroids.map((c) => ({ ...c }));\n\n\t\t// Compute per-cluster counts and sums from batch\n\t\tconst clusterCounts = Array.from({ length: centroids.length }, () => 0);\n\t\tconst clusterSums: [number, number, number][] = Array.from(\n\t\t\t{ length: centroids.length },\n\t\t\t(): [number, number, number] => [0, 0, 0],\n\t\t);\n\n\t\tfor (const { feature, cluster } of batchPoints) {\n\t\t\tconst currentCount = clusterCounts[cluster];\n\t\t\tif (currentCount !== undefined) {\n\t\t\t\tclusterCounts[cluster] = currentCount + 1;\n\t\t\t}\n\t\t\tconst sum = clusterSums[cluster];\n\t\t\tif (sum !== undefined) {\n\t\t\t\tsum[0] += feature.f1;\n\t\t\t\tsum[1] += feature.f2;\n\t\t\t\tsum[2] += feature.f3;\n\t\t\t}\n\t\t}\n\n\t\t// Update centroids\n\t\tfor (let c = 0; c < centroids.length; c++) {\n\t\t\tconst count = clusterCounts[c] ?? 0;\n\t\t\tif (count > 0) {\n\t\t\t\tconst sum = clusterSums[c];\n\t\t\t\tif (sum !== undefined) {\n\t\t\t\t\tcentroids[c] = {\n\t\t\t\t\t\tf1: sum[0] / count,\n\t\t\t\t\t\tf2: sum[1] / count,\n\t\t\t\t\t\tf3: sum[2] / count,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check convergence\n\t\tlet maxShift = 0;\n\t\tfor (let c = 0; c < centroids.length; c++) {\n\t\t\tconst newCentroid = centroids[c];\n\t\t\tconst oldCentroid = oldCentroids[c];\n\t\t\tif (newCentroid !== undefined && oldCentroid !== undefined) {\n\t\t\t\tconst shift = euclideanDistance(newCentroid, oldCentroid);\n\t\t\t\tmaxShift = Math.max(maxShift, shift);\n\t\t\t}\n\t\t}\n\n\t\tif (maxShift < tolerance) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Final assignment of all points\n\tfor (const feature of features) {\n\t\tlet minDist = Infinity;\n\t\tlet bestCluster = 0;\n\t\tfor (let c = 0; c < centroids.length; c++) {\n\t\t\tconst centroid = centroids[c];\n\t\t\tif (centroid === undefined) continue;\n\t\t\tconst dist = euclideanDistance(feature, centroid);\n\t\t\tif (dist < minDist) {\n\t\t\t\tminDist = dist;\n\t\t\t\tbestCluster = c;\n\t\t\t}\n\t\t}\n\t\tassignments.set(feature.nodeId, bestCluster);\n\t}\n\n\treturn {\n\t\tcentroids,\n\t\tassignments,\n\t\tk: effectiveK,\n\t};\n}\n\n/**\n * K-means++ initialisation for better centroid seeding.\n */\nfunction initialiseCentroidsKMeansPP(\n\tfeatures: readonly LabelledFeature[],\n\tk: number,\n\trng: () => number,\n): FeatureVector3D[] {\n\tconst centroids: FeatureVector3D[] = [];\n\tconst n = features.length;\n\n\t// Choose first centroid randomly\n\tconst firstIdx = Math.floor(rng() * n);\n\tconst firstFeature = features[firstIdx];\n\tif (firstFeature === undefined) {\n\t\treturn [{ f1: 0, f2: 0, f3: 0 }];\n\t}\n\tcentroids.push({\n\t\tf1: firstFeature.f1,\n\t\tf2: firstFeature.f2,\n\t\tf3: firstFeature.f3,\n\t});\n\n\t// Choose remaining centroids with probability proportional to squared distance\n\tconst distances = Array.from({ length: n }, () => Infinity);\n\n\tfor (let c = 1; c < k; c++) {\n\t\t// Update distances to nearest centroid\n\t\tlet totalDistSq = 0;\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tconst feature = features[i];\n\t\t\tif (feature === undefined) continue;\n\t\t\tconst lastCentroid = centroids[c - 1];\n\t\t\tif (lastCentroid === undefined) continue;\n\t\t\tconst dist = euclideanDistance(feature, lastCentroid);\n\t\t\tconst currentMin = distances[i];\n\t\t\tif (currentMin !== undefined && dist < currentMin) {\n\t\t\t\tdistances[i] = dist;\n\t\t\t}\n\t\t\tconst d = distances[i];\n\t\t\tif (d !== undefined) {\n\t\t\t\ttotalDistSq += d * d;\n\t\t\t}\n\t\t}\n\n\t\t// Choose next centroid with probability proportional to squared distance\n\t\tconst threshold = rng() * totalDistSq;\n\t\tlet cumulative = 0;\n\t\tlet nextIdx = 0;\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tconst d = distances[i];\n\t\t\tif (d !== undefined) {\n\t\t\t\tcumulative += d * d;\n\t\t\t\tif (cumulative >= threshold) {\n\t\t\t\t\tnextIdx = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst nextFeature = features[nextIdx];\n\t\tif (nextFeature !== undefined) {\n\t\t\tcentroids.push({\n\t\t\t\tf1: nextFeature.f1,\n\t\t\t\tf2: nextFeature.f2,\n\t\t\t\tf3: nextFeature.f3,\n\t\t\t});\n\t\t} else {\n\t\t\t// Fallback: use zero centroid\n\t\t\tcentroids.push({ f1: 0, f2: 0, f3: 0 });\n\t\t}\n\t}\n\n\treturn centroids;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NodeData, EdgeData, ReadableGraph } from '../../graph';
|
|
2
|
+
import { ExpansionPath } from '../../expansion/types';
|
|
3
|
+
import { BaselineConfig, BaselineResult } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Rank paths by sum of betweenness scores.
|
|
6
|
+
*
|
|
7
|
+
* @param graph - Source graph
|
|
8
|
+
* @param paths - Paths to rank
|
|
9
|
+
* @param config - Configuration options
|
|
10
|
+
* @returns Ranked paths (highest betweenness sum first)
|
|
11
|
+
*/
|
|
12
|
+
export declare function betweenness<N extends NodeData, E extends EdgeData>(graph: ReadableGraph<N, E>, paths: readonly ExpansionPath[], config?: BaselineConfig): BaselineResult;
|
|
13
|
+
//# sourceMappingURL=betweenness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"betweenness.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/betweenness.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAc,MAAM,SAAS,CAAC;AAwG1E;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EACjE,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,MAAM,CAAC,EAAE,cAAc,GACrB,cAAc,CAgDhB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"betweenness.unit.test.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/betweenness.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NodeData, EdgeData, ReadableGraph } from '../../graph';
|
|
2
|
+
import { ExpansionPath } from '../../expansion/types';
|
|
3
|
+
import { BaselineConfig, BaselineResult } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Rank paths by communicability between endpoints.
|
|
6
|
+
*
|
|
7
|
+
* @param graph - Source graph
|
|
8
|
+
* @param paths - Paths to rank
|
|
9
|
+
* @param config - Configuration options
|
|
10
|
+
* @returns Ranked paths (highest communicability first)
|
|
11
|
+
*/
|
|
12
|
+
export declare function communicability<N extends NodeData, E extends EdgeData>(graph: ReadableGraph<N, E>, paths: readonly ExpansionPath[], config?: BaselineConfig): BaselineResult;
|
|
13
|
+
//# sourceMappingURL=communicability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"communicability.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/communicability.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAc,MAAM,SAAS,CAAC;AA2E1E;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EACrE,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,MAAM,CAAC,EAAE,cAAc,GACrB,cAAc,CAiDhB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"communicability.unit.test.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/communicability.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NodeData, EdgeData, ReadableGraph } from '../../graph';
|
|
2
|
+
import { ExpansionPath } from '../../expansion/types';
|
|
3
|
+
import { BaselineConfig, BaselineResult } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Rank paths by sum of node degrees.
|
|
6
|
+
*
|
|
7
|
+
* @param graph - Source graph
|
|
8
|
+
* @param paths - Paths to rank
|
|
9
|
+
* @param config - Configuration options
|
|
10
|
+
* @returns Ranked paths (highest degree-sum first)
|
|
11
|
+
*/
|
|
12
|
+
export declare function degreeSum<N extends NodeData, E extends EdgeData>(graph: ReadableGraph<N, E>, paths: readonly ExpansionPath[], config?: BaselineConfig): BaselineResult;
|
|
13
|
+
//# sourceMappingURL=degree-sum.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"degree-sum.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/degree-sum.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAc,MAAM,SAAS,CAAC;AAE1E;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAC/D,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,MAAM,CAAC,EAAE,cAAc,GACrB,cAAc,CA6ChB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"degree-sum.unit.test.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/degree-sum.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Baseline ranking methods module.
|
|
3
|
+
*
|
|
4
|
+
* Provides simple ranking strategies for comparing discovered paths,
|
|
5
|
+
* useful for evaluating PARSE against established graph metrics.
|
|
6
|
+
*
|
|
7
|
+
* @module ranking/baselines
|
|
8
|
+
*/
|
|
9
|
+
export * from './types';
|
|
10
|
+
export * from './shortest';
|
|
11
|
+
export * from './degree-sum';
|
|
12
|
+
export * from './widest-path';
|
|
13
|
+
export * from './jaccard-arithmetic';
|
|
14
|
+
export * from './pagerank';
|
|
15
|
+
export * from './betweenness';
|
|
16
|
+
export * from './katz';
|
|
17
|
+
export * from './communicability';
|
|
18
|
+
export * from './resistance-distance';
|
|
19
|
+
export * from './random-ranking';
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NodeData, EdgeData, ReadableGraph } from '../../graph';
|
|
2
|
+
import { ExpansionPath } from '../../expansion/types';
|
|
3
|
+
import { BaselineConfig, BaselineResult } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Rank paths by arithmetic mean of edge Jaccard similarities.
|
|
6
|
+
*
|
|
7
|
+
* @param graph - Source graph
|
|
8
|
+
* @param paths - Paths to rank
|
|
9
|
+
* @param config - Configuration options
|
|
10
|
+
* @returns Ranked paths (highest arithmetic mean first)
|
|
11
|
+
*/
|
|
12
|
+
export declare function jaccardArithmetic<N extends NodeData, E extends EdgeData>(graph: ReadableGraph<N, E>, paths: readonly ExpansionPath[], config?: BaselineConfig): BaselineResult;
|
|
13
|
+
//# sourceMappingURL=jaccard-arithmetic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jaccard-arithmetic.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/jaccard-arithmetic.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAc,MAAM,SAAS,CAAC;AAG1E;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EACvE,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,MAAM,CAAC,EAAE,cAAc,GACrB,cAAc,CA6DhB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jaccard-arithmetic.unit.test.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/jaccard-arithmetic.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NodeData, EdgeData, ReadableGraph } from '../../graph';
|
|
2
|
+
import { ExpansionPath } from '../../expansion/types';
|
|
3
|
+
import { BaselineConfig, BaselineResult } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Rank paths by Katz centrality between endpoints.
|
|
6
|
+
*
|
|
7
|
+
* @param graph - Source graph
|
|
8
|
+
* @param paths - Paths to rank
|
|
9
|
+
* @param config - Configuration options
|
|
10
|
+
* @returns Ranked paths (highest Katz score first)
|
|
11
|
+
*/
|
|
12
|
+
export declare function katz<N extends NodeData, E extends EdgeData>(graph: ReadableGraph<N, E>, paths: readonly ExpansionPath[], config?: BaselineConfig): BaselineResult;
|
|
13
|
+
//# sourceMappingURL=katz.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"katz.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/katz.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAc,MAAM,SAAS,CAAC;AA0E1E;;;;;;;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,aAAa,EAAE,EAC/B,MAAM,CAAC,EAAE,cAAc,GACrB,cAAc,CAiDhB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"katz.unit.test.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/katz.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NodeData, EdgeData, ReadableGraph } from '../../graph';
|
|
2
|
+
import { ExpansionPath } from '../../expansion/types';
|
|
3
|
+
import { BaselineConfig, BaselineResult } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Rank paths by sum of PageRank scores.
|
|
6
|
+
*
|
|
7
|
+
* @param graph - Source graph
|
|
8
|
+
* @param paths - Paths to rank
|
|
9
|
+
* @param config - Configuration options
|
|
10
|
+
* @returns Ranked paths (highest PageRank sum first)
|
|
11
|
+
*/
|
|
12
|
+
export declare function pagerank<N extends NodeData, E extends EdgeData>(graph: ReadableGraph<N, E>, paths: readonly ExpansionPath[], config?: BaselineConfig): BaselineResult;
|
|
13
|
+
//# sourceMappingURL=pagerank.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagerank.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/pagerank.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAc,MAAM,SAAS,CAAC;AA0E1E;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAC9D,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,MAAM,CAAC,EAAE,cAAc,GACrB,cAAc,CAgDhB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagerank.unit.test.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/pagerank.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { NodeData, EdgeData, ReadableGraph } from '../../graph';
|
|
2
|
+
import { ExpansionPath } from '../../expansion/types';
|
|
3
|
+
import { BaselineConfig, BaselineResult } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Configuration for random ranking.
|
|
6
|
+
*/
|
|
7
|
+
interface RandomRankingConfig extends BaselineConfig {
|
|
8
|
+
/** Random seed for deterministic reproducibility */
|
|
9
|
+
readonly seed?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Rank paths randomly (null hypothesis baseline).
|
|
13
|
+
*
|
|
14
|
+
* @param _graph - Source graph (unused)
|
|
15
|
+
* @param paths - Paths to rank
|
|
16
|
+
* @param config - Configuration options
|
|
17
|
+
* @returns Ranked paths (randomly ordered)
|
|
18
|
+
*/
|
|
19
|
+
export declare function randomRanking<N extends NodeData, E extends EdgeData>(_graph: ReadableGraph<N, E>, paths: readonly ExpansionPath[], config?: RandomRankingConfig): BaselineResult;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=random-ranking.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"random-ranking.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/random-ranking.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAc,MAAM,SAAS,CAAC;AAE1E;;GAEG;AACH,UAAU,mBAAoB,SAAQ,cAAc;IACnD,oDAAoD;IACpD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACvB;AAqBD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EACnE,MAAM,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC3B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,MAAM,CAAC,EAAE,mBAAmB,GAC1B,cAAc,CA2ChB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"random-ranking.unit.test.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/random-ranking.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NodeData, EdgeData, ReadableGraph } from '../../graph';
|
|
2
|
+
import { ExpansionPath } from '../../expansion/types';
|
|
3
|
+
import { BaselineConfig, BaselineResult } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Rank paths by reciprocal of resistance distance between endpoints.
|
|
6
|
+
*
|
|
7
|
+
* @param graph - Source graph
|
|
8
|
+
* @param paths - Paths to rank
|
|
9
|
+
* @param config - Configuration options
|
|
10
|
+
* @returns Ranked paths (highest conductance first)
|
|
11
|
+
*/
|
|
12
|
+
export declare function resistanceDistance<N extends NodeData, E extends EdgeData>(graph: ReadableGraph<N, E>, paths: readonly ExpansionPath[], config?: BaselineConfig): BaselineResult;
|
|
13
|
+
//# sourceMappingURL=resistance-distance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resistance-distance.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/resistance-distance.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAc,MAAM,SAAS,CAAC;AA0L1E;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EACxE,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,MAAM,CAAC,EAAE,cAAc,GACrB,cAAc,CA2DhB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resistance-distance.unit.test.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/resistance-distance.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NodeData, EdgeData, ReadableGraph } from '../../graph';
|
|
2
|
+
import { ExpansionPath } from '../../expansion/types';
|
|
3
|
+
import { BaselineConfig, BaselineResult } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Rank paths by widest bottleneck (minimum edge similarity).
|
|
6
|
+
*
|
|
7
|
+
* @param graph - Source graph
|
|
8
|
+
* @param paths - Paths to rank
|
|
9
|
+
* @param config - Configuration options
|
|
10
|
+
* @returns Ranked paths (highest bottleneck first)
|
|
11
|
+
*/
|
|
12
|
+
export declare function widestPath<N extends NodeData, E extends EdgeData>(graph: ReadableGraph<N, E>, paths: readonly ExpansionPath[], config?: BaselineConfig): BaselineResult;
|
|
13
|
+
//# sourceMappingURL=widest-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widest-path.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/widest-path.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAc,MAAM,SAAS,CAAC;AAG1E;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAChE,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,MAAM,CAAC,EAAE,cAAc,GACrB,cAAc,CA2DhB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widest-path.unit.test.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/widest-path.unit.test.ts"],"names":[],"mappings":""}
|
package/dist/ranking/index.d.ts
CHANGED
|
@@ -6,10 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module ranking
|
|
8
8
|
*/
|
|
9
|
-
export
|
|
10
|
-
export
|
|
11
|
-
export
|
|
12
|
-
export { jaccard, adamicAdar, scale, skew, span, etch, notch, adaptive, } from './mi/index';
|
|
13
|
-
export { shortest } from './baselines/shortest';
|
|
14
|
-
export type { BaselineConfig, BaselineResult, ScoredPath, PathRanker, } from './baselines/types';
|
|
9
|
+
export * from './parse';
|
|
10
|
+
export * from './mi';
|
|
11
|
+
export * from './baselines';
|
|
15
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ranking/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ranking/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,MAAM,CAAC;AACrB,cAAc,aAAa,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adamic-adar.d.ts","sourceRoot":"","sources":["../../../src/ranking/mi/adamic-adar.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"adamic-adar.d.ts","sourceRoot":"","sources":["../../../src/ranking/mi/adamic-adar.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE7E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAChE,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,QAAQ,GACf,MAAM,CA8BR"}
|
|
@@ -4,7 +4,7 @@ import { AdaptiveMIConfig } from './types';
|
|
|
4
4
|
* Compute unified adaptive MI between two connected nodes.
|
|
5
5
|
*
|
|
6
6
|
* Combines structural, degree, and overlap signals with
|
|
7
|
-
*
|
|
7
|
+
* configurable weighting.
|
|
8
8
|
*
|
|
9
9
|
* @param graph - Source graph
|
|
10
10
|
* @param source - Source node ID
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adaptive.d.ts","sourceRoot":"","sources":["../../../src/ranking/mi/adaptive.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"adaptive.d.ts","sourceRoot":"","sources":["../../../src/ranking/mi/adaptive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAIhD;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAC9D,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,gBAAgB,GACvB,MAAM,CA4CR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"etch.d.ts","sourceRoot":"","sources":["../../../src/ranking/mi/etch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"etch.d.ts","sourceRoot":"","sources":["../../../src/ranking/mi/etch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE7E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC;;GAEG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAC1D,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,QAAQ,GACf,MAAM,CAmCR"}
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module ranking/mi
|
|
8
8
|
*/
|
|
9
|
-
export
|
|
10
|
-
export
|
|
11
|
-
export
|
|
12
|
-
export
|
|
13
|
-
export
|
|
14
|
-
export
|
|
15
|
-
export
|
|
16
|
-
export
|
|
17
|
-
export
|
|
9
|
+
export * from './types';
|
|
10
|
+
export * from './jaccard';
|
|
11
|
+
export * from './adamic-adar';
|
|
12
|
+
export * from './scale';
|
|
13
|
+
export * from './skew';
|
|
14
|
+
export * from './span';
|
|
15
|
+
export * from './etch';
|
|
16
|
+
export * from './notch';
|
|
17
|
+
export * from './adaptive';
|
|
18
18
|
//# sourceMappingURL=index.d.ts.map
|