dress-graph 0.6.0 → 0.7.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 +3 -3
- package/dress.d.ts +67 -6
- package/dress.js +365 -41
- package/dress_wasm.cjs +2 -0
- package/dress_wasm.wasm +0 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
**A Continuous Framework for Structural Graph Refinement**
|
|
4
4
|
|
|
5
|
-
DRESS is a deterministic, parameter-free framework that iteratively refines the structural similarity of edges in a graph to produce a canonical fingerprint: a real-valued edge vector, obtained by converging a non-linear dynamical system to its unique fixed point. The fingerprint is isomorphism-invariant by construction, guaranteed bitwise-equal across any vertex labeling, numerically stable (no overflow, no error amplification, no undefined behavior), fast and embarrassingly parallel to compute: DRESS total runtime is O(I * m * d_max) for I iterations to convergence, and convergence is guaranteed by Birkhoff contraction.
|
|
5
|
+
DRESS is a deterministic, parameter-free framework that iteratively refines the structural similarity of edges in a graph to produce a canonical fingerprint: a real-valued edge vector, obtained by converging a non-linear dynamical system to its unique fixed point. The fingerprint is self-contained, isomorphism-invariant by construction, guaranteed bitwise-equal across any vertex labeling, numerically stable (no overflow, no error amplification, no undefined behavior), fast and embarrassingly parallel to compute: DRESS total runtime is O(I * m * d_max) for I iterations to convergence, and convergence is guaranteed by Birkhoff contraction.
|
|
6
6
|
|
|
7
7
|
## Quick start
|
|
8
8
|
|
|
9
9
|
```javascript
|
|
10
|
-
import {
|
|
10
|
+
import { fit } from 'dress-graph';
|
|
11
11
|
|
|
12
|
-
const result = await
|
|
12
|
+
const result = await fit({
|
|
13
13
|
numVertices: 4,
|
|
14
14
|
sources: [0, 1, 2, 0],
|
|
15
15
|
targets: [1, 2, 3, 3],
|
package/dress.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export interface DressOptions {
|
|
|
18
18
|
targets: Int32Array | number[];
|
|
19
19
|
/** Optional edge weights (same length as sources) */
|
|
20
20
|
weights?: Float64Array | number[] | null;
|
|
21
|
+
/** Optional node weights (length numVertices) */
|
|
22
|
+
nodeWeights?: Float64Array | number[] | null;
|
|
21
23
|
/** Graph variant (default: Variant.UNDIRECTED) */
|
|
22
24
|
variant?: number;
|
|
23
25
|
/** Maximum fitting iterations (default: 100) */
|
|
@@ -48,7 +50,7 @@ export interface DressResult {
|
|
|
48
50
|
/**
|
|
49
51
|
* Run the DRESS iterative fitting algorithm on an edge list.
|
|
50
52
|
*/
|
|
51
|
-
export declare function
|
|
53
|
+
export declare function fit(opts: DressOptions): Promise<DressResult>;
|
|
52
54
|
|
|
53
55
|
export interface DRESSOptions {
|
|
54
56
|
/** Number of vertices (vertex ids must be in 0..numVertices-1) */
|
|
@@ -59,6 +61,8 @@ export interface DRESSOptions {
|
|
|
59
61
|
targets: Int32Array | number[];
|
|
60
62
|
/** Optional edge weights (same length as sources) */
|
|
61
63
|
weights?: Float64Array | number[] | null;
|
|
64
|
+
/** Optional node weights (length numVertices) */
|
|
65
|
+
nodeWeights?: Float64Array | number[] | null;
|
|
62
66
|
/** Graph variant (default: Variant.UNDIRECTED) */
|
|
63
67
|
variant?: number;
|
|
64
68
|
/** Pre-compute neighbourhood intercepts (default: false) */
|
|
@@ -86,6 +90,8 @@ export interface DeltaDressOptions {
|
|
|
86
90
|
targets: Int32Array | number[];
|
|
87
91
|
/** Optional edge weights (same length as sources) */
|
|
88
92
|
weights?: Float64Array | number[] | null;
|
|
93
|
+
/** Optional node weights (length numVertices) */
|
|
94
|
+
nodeWeights?: Float64Array | number[] | null;
|
|
89
95
|
/** Vertices to remove per subset (default: 0 = original graph) */
|
|
90
96
|
k?: number;
|
|
91
97
|
/** Graph variant (default: Variant.UNDIRECTED) */
|
|
@@ -94,26 +100,81 @@ export interface DeltaDressOptions {
|
|
|
94
100
|
maxIterations?: number;
|
|
95
101
|
/** Convergence threshold / bin width (default: 1e-6) */
|
|
96
102
|
epsilon?: number;
|
|
103
|
+
/** Number of random subgraphs to sample (0 = exhaustive, default: 0) */
|
|
104
|
+
nSamples?: number;
|
|
105
|
+
/** Random seed for sampling (default: 0) */
|
|
106
|
+
seed?: number;
|
|
97
107
|
/** Pre-compute neighbourhood intercepts (default: false) */
|
|
98
108
|
precompute?: boolean;
|
|
99
109
|
/** Return per-subgraph edge values (default: false) */
|
|
100
110
|
keepMultisets?: boolean;
|
|
111
|
+
/** Compute histogram (default: true) */
|
|
112
|
+
computeHistogram?: boolean;
|
|
101
113
|
}
|
|
102
114
|
|
|
103
115
|
export interface DeltaDressResult {
|
|
104
|
-
/**
|
|
105
|
-
histogram:
|
|
106
|
-
/** Number of histogram bins (floor(dmax/epsilon) + 1; dmax = 2 unweighted) */
|
|
107
|
-
histSize: number;
|
|
116
|
+
/** Exact sparse histogram entries as (value, count) pairs */
|
|
117
|
+
histogram: HistogramEntry[];
|
|
108
118
|
/** Per-subgraph edge values, row-major C(N,k) × E (NaN = removed edge; null when not requested) */
|
|
109
119
|
multisets: Float64Array | null;
|
|
110
120
|
/** Number of subgraphs C(N,k) */
|
|
111
121
|
numSubgraphs: number;
|
|
112
122
|
}
|
|
113
123
|
|
|
124
|
+
export interface HistogramEntry {
|
|
125
|
+
value: number;
|
|
126
|
+
count: number;
|
|
127
|
+
}
|
|
128
|
+
|
|
114
129
|
/**
|
|
115
130
|
* Compute the Delta-k-DRESS histogram by exhaustively removing
|
|
116
131
|
* all k-vertex subsets and measuring edge similarity changes.
|
|
117
132
|
*/
|
|
118
|
-
export declare function
|
|
133
|
+
export declare function deltaFit(opts: DeltaDressOptions): Promise<DeltaDressResult>;
|
|
134
|
+
|
|
135
|
+
export interface NablaDressOptions {
|
|
136
|
+
/** Number of vertices (vertex ids must be in 0..numVertices-1) */
|
|
137
|
+
numVertices: number;
|
|
138
|
+
/** Edge source vertices (0-based) */
|
|
139
|
+
sources: Int32Array | number[];
|
|
140
|
+
/** Edge target vertices (0-based) */
|
|
141
|
+
targets: Int32Array | number[];
|
|
142
|
+
/** Optional edge weights (same length as sources) */
|
|
143
|
+
weights?: Float64Array | number[] | null;
|
|
144
|
+
/** Optional node weights (length numVertices) */
|
|
145
|
+
nodeWeights?: Float64Array | number[] | null;
|
|
146
|
+
/** Vertices to remove per tuple (default: 0 = original graph) */
|
|
147
|
+
k?: number;
|
|
148
|
+
/** Graph variant (default: Variant.UNDIRECTED) */
|
|
149
|
+
variant?: number;
|
|
150
|
+
/** Maximum fitting iterations (default: 100) */
|
|
151
|
+
maxIterations?: number;
|
|
152
|
+
/** Convergence threshold / bin width (default: 1e-6) */
|
|
153
|
+
epsilon?: number;
|
|
154
|
+
/** Number of random tuples to sample (0 = exhaustive, default: 0) */
|
|
155
|
+
nSamples?: number;
|
|
156
|
+
/** Random seed for sampling (default: 0) */
|
|
157
|
+
seed?: number;
|
|
158
|
+
/** Pre-compute neighbourhood intercepts (default: false) */
|
|
159
|
+
precompute?: boolean;
|
|
160
|
+
/** Return per-tuple edge values (default: false) */
|
|
161
|
+
keepMultisets?: boolean;
|
|
162
|
+
/** Compute histogram (default: true) */
|
|
163
|
+
computeHistogram?: boolean;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface NablaDressResult {
|
|
167
|
+
/** Exact sparse histogram entries as (value, count) pairs */
|
|
168
|
+
histogram: HistogramEntry[];
|
|
169
|
+
/** Per-tuple edge values, row-major (null when not requested) */
|
|
170
|
+
multisets: Float64Array | null;
|
|
171
|
+
/** Number of tuples */
|
|
172
|
+
numTuples: number;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Compute the Nabla-k-DRESS histogram by exhaustively removing
|
|
177
|
+
* all k-vertex tuples and measuring edge similarity changes.
|
|
178
|
+
*/
|
|
179
|
+
export declare function nablaFit(opts: NablaDressOptions): Promise<NablaDressResult>;
|
|
119
180
|
|
package/dress.js
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Usage (ES module):
|
|
7
7
|
*
|
|
8
|
-
* import {
|
|
8
|
+
* import { fit } from './dress.js';
|
|
9
9
|
*
|
|
10
|
-
* const result = await
|
|
10
|
+
* const result = await fit({
|
|
11
11
|
* numVertices: 4,
|
|
12
12
|
* sources: [0, 1, 2, 0],
|
|
13
13
|
* targets: [1, 2, 3, 3],
|
|
@@ -86,7 +86,7 @@ export const Variant = Object.freeze({
|
|
|
86
86
|
* @param {DressOptions} opts
|
|
87
87
|
* @returns {Promise<DressResult>}
|
|
88
88
|
*/
|
|
89
|
-
export async function
|
|
89
|
+
export async function fit(opts) {
|
|
90
90
|
const M = await getModule();
|
|
91
91
|
|
|
92
92
|
const N = opts.numVertices;
|
|
@@ -104,7 +104,7 @@ export async function dressFit(opts) {
|
|
|
104
104
|
const epsilon = opts.epsilon ?? 1e-6;
|
|
105
105
|
const precompute = (opts.precomputeIntercepts ?? false) ? 1 : 0;
|
|
106
106
|
|
|
107
|
-
// Allocate C arrays (ownership transfers to dress.c — freed by
|
|
107
|
+
// Allocate C arrays (ownership transfers to dress.c — freed by dress_free_graph)
|
|
108
108
|
const uPtr = M._malloc(E * 4);
|
|
109
109
|
const vPtr = M._malloc(E * 4);
|
|
110
110
|
|
|
@@ -128,10 +128,24 @@ export async function dressFit(opts) {
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
//
|
|
132
|
-
|
|
131
|
+
// Node weights (nullable)
|
|
132
|
+
let nwPtr = 0; // NULL
|
|
133
|
+
if (opts.nodeWeights) {
|
|
134
|
+
if (opts.nodeWeights.length !== N) {
|
|
135
|
+
throw new Error(`nodeWeights (${opts.nodeWeights.length}) must equal vertex count (${N})`);
|
|
136
|
+
}
|
|
137
|
+
nwPtr = M._malloc(N * 8);
|
|
138
|
+
const heapF64 = M.HEAPF64;
|
|
139
|
+
const nw = opts.nodeWeights;
|
|
140
|
+
for (let i = 0; i < N; i++) {
|
|
141
|
+
heapF64[(nwPtr >> 3) + i] = nw[i];
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Call dress_init_graph
|
|
146
|
+
const g = M._dress_init_graph(N, E, uPtr, vPtr, wPtr, nwPtr, variant, precompute);
|
|
133
147
|
if (g === 0) {
|
|
134
|
-
throw new Error('
|
|
148
|
+
throw new Error('dress_init_graph returned NULL');
|
|
135
149
|
}
|
|
136
150
|
|
|
137
151
|
// Allocate output params
|
|
@@ -154,15 +168,16 @@ export async function dressFit(opts) {
|
|
|
154
168
|
// offset 20: *adj_offset (ptr32)
|
|
155
169
|
// offset 24: *adj_target (ptr32)
|
|
156
170
|
// offset 28: *adj_edge_idx (ptr32)
|
|
157
|
-
// offset 32: max_degree
|
|
158
|
-
// offset 36: *W (ptr32)
|
|
171
|
+
// offset 32: max_degree (i32)
|
|
172
|
+
// offset 36: *W (ptr32)
|
|
159
173
|
// offset 40: *edge_weight (ptr32)
|
|
160
|
-
// offset
|
|
161
|
-
// offset
|
|
162
|
-
// offset
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
const
|
|
174
|
+
// offset 44: *edge_dress (ptr32)
|
|
175
|
+
// offset 48: *edge_dress_next (ptr32)
|
|
176
|
+
// offset 52: *node_dress (ptr32)
|
|
177
|
+
// offset 56: *NW (ptr32)
|
|
178
|
+
const ewPtr = M.getValue(g + 40, 'i32'); // edge_weight pointer
|
|
179
|
+
const edPtr = M.getValue(g + 44, 'i32'); // edge_dress pointer
|
|
180
|
+
const ndPtr = M.getValue(g + 52, 'i32'); // node_dress pointer
|
|
166
181
|
|
|
167
182
|
// Copy results into JS-owned typed arrays
|
|
168
183
|
const edgeWeight = new Float64Array(E);
|
|
@@ -187,7 +202,7 @@ export async function dressFit(opts) {
|
|
|
187
202
|
}
|
|
188
203
|
|
|
189
204
|
// Clean up
|
|
190
|
-
M.
|
|
205
|
+
M._dress_free_graph(g);
|
|
191
206
|
M._free(iterPtr);
|
|
192
207
|
M._free(deltaPtr);
|
|
193
208
|
|
|
@@ -270,8 +285,16 @@ export class DRESS {
|
|
|
270
285
|
}
|
|
271
286
|
}
|
|
272
287
|
|
|
273
|
-
|
|
274
|
-
if (
|
|
288
|
+
let nwPtr = 0;
|
|
289
|
+
if (opts.nodeWeights && opts.nodeWeights.length === N) {
|
|
290
|
+
nwPtr = M._malloc(N * 8);
|
|
291
|
+
for (let i = 0; i < N; i++) {
|
|
292
|
+
M.HEAPF64[(nwPtr >> 3) + i] = opts.nodeWeights[i];
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const g = M._dress_init_graph(N, E, uPtr, vPtr, wPtr, nwPtr, variant, precompute);
|
|
297
|
+
if (g === 0) throw new Error('dress_init_graph returned NULL');
|
|
275
298
|
|
|
276
299
|
return new DRESS(M, g, N, E, opts.sources, opts.targets);
|
|
277
300
|
}
|
|
@@ -317,9 +340,9 @@ export class DRESS {
|
|
|
317
340
|
const N = this._n;
|
|
318
341
|
|
|
319
342
|
// WASM32 offsets
|
|
320
|
-
const ewPtr = M.getValue(this._g +
|
|
321
|
-
const edPtr = M.getValue(this._g +
|
|
322
|
-
const ndPtr = M.getValue(this._g +
|
|
343
|
+
const ewPtr = M.getValue(this._g + 40, 'i32');
|
|
344
|
+
const edPtr = M.getValue(this._g + 44, 'i32');
|
|
345
|
+
const ndPtr = M.getValue(this._g + 52, 'i32');
|
|
323
346
|
|
|
324
347
|
const edgeWeight = new Float64Array(E);
|
|
325
348
|
const edgeDress = new Float64Array(E);
|
|
@@ -344,13 +367,160 @@ export class DRESS {
|
|
|
344
367
|
};
|
|
345
368
|
}
|
|
346
369
|
|
|
370
|
+
/**
|
|
371
|
+
* Compute Δ^k-DRESS on this persistent graph.
|
|
372
|
+
* @param {number} [k=0]
|
|
373
|
+
* @param {number} [maxIterations=100]
|
|
374
|
+
* @param {number} [epsilon=1e-6]
|
|
375
|
+
* @param {number} [nSamples=0]
|
|
376
|
+
* @param {number} [seed=0]
|
|
377
|
+
* @param {boolean} [keepMultisets=false]
|
|
378
|
+
* @param {boolean} [computeHistogram=true]
|
|
379
|
+
* @returns {DeltaDressResult}
|
|
380
|
+
*/
|
|
381
|
+
deltaFit(k = 0, maxIterations = 100, epsilon = 1e-6,
|
|
382
|
+
nSamples = 0, seed = 0,
|
|
383
|
+
keepMultisets = false, computeHistogram = true) {
|
|
384
|
+
if (!this._g) throw new Error('DRESS already freed');
|
|
385
|
+
const M = this._M;
|
|
386
|
+
const E = this._e;
|
|
387
|
+
|
|
388
|
+
const keepMS = keepMultisets ? 1 : 0;
|
|
389
|
+
const histSizePtr = M._malloc(4);
|
|
390
|
+
|
|
391
|
+
let msPtrPtr = 0;
|
|
392
|
+
let numSubPtr = 0;
|
|
393
|
+
if (keepMS) {
|
|
394
|
+
msPtrPtr = M._malloc(4);
|
|
395
|
+
numSubPtr = M._malloc(8);
|
|
396
|
+
M.setValue(msPtrPtr, 0, 'i32');
|
|
397
|
+
M.setValue(numSubPtr, 0, 'i32');
|
|
398
|
+
M.setValue(numSubPtr + 4, 0, 'i32');
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const histPtr = M._dress_delta_fit_strided(
|
|
402
|
+
this._g, k, maxIterations, epsilon,
|
|
403
|
+
nSamples, seed,
|
|
404
|
+
computeHistogram ? histSizePtr : 0,
|
|
405
|
+
keepMS, msPtrPtr || 0, numSubPtr || 0,
|
|
406
|
+
0, 1);
|
|
407
|
+
|
|
408
|
+
const histSize = M.getValue(histSizePtr, 'i32');
|
|
409
|
+
|
|
410
|
+
const histogram = new Array(histSize);
|
|
411
|
+
for (let i = 0; i < histSize; i++) {
|
|
412
|
+
const value = M.HEAPF64[(histPtr >> 3) + i * 2];
|
|
413
|
+
const countLo = M.HEAPU32[(histPtr >> 2) + i * 4 + 2];
|
|
414
|
+
const countHi = M.HEAPU32[(histPtr >> 2) + i * 4 + 3];
|
|
415
|
+
histogram[i] = { value, count: countHi * 4294967296 + countLo };
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
let multisets = null;
|
|
419
|
+
let numSubgraphs = 0;
|
|
420
|
+
if (keepMS && msPtrPtr) {
|
|
421
|
+
const msPtr = M.getValue(msPtrPtr, 'i32');
|
|
422
|
+
const nsLo = M.HEAPU32[(numSubPtr >> 2)];
|
|
423
|
+
const nsHi = M.HEAP32[(numSubPtr >> 2) + 1];
|
|
424
|
+
numSubgraphs = nsHi * 4294967296 + nsLo;
|
|
425
|
+
|
|
426
|
+
if (msPtr !== 0 && numSubgraphs > 0) {
|
|
427
|
+
const totalVals = numSubgraphs * E;
|
|
428
|
+
multisets = new Float64Array(totalVals);
|
|
429
|
+
for (let i = 0; i < totalVals; i++) {
|
|
430
|
+
multisets[i] = M.HEAPF64[(msPtr >> 3) + i];
|
|
431
|
+
}
|
|
432
|
+
M._free(msPtr);
|
|
433
|
+
}
|
|
434
|
+
M._free(msPtrPtr);
|
|
435
|
+
M._free(numSubPtr);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (histPtr) M._free(histPtr);
|
|
439
|
+
M._free(histSizePtr);
|
|
440
|
+
|
|
441
|
+
return { histogram, multisets, numSubgraphs };
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Compute ∇^k-DRESS on this persistent graph.
|
|
446
|
+
* @param {number} [k=0]
|
|
447
|
+
* @param {number} [maxIterations=100]
|
|
448
|
+
* @param {number} [epsilon=1e-6]
|
|
449
|
+
* @param {number} [nSamples=0]
|
|
450
|
+
* @param {number} [seed=0]
|
|
451
|
+
* @param {boolean} [keepMultisets=false]
|
|
452
|
+
* @param {boolean} [computeHistogram=true]
|
|
453
|
+
* @returns {NablaDressResult}
|
|
454
|
+
*/
|
|
455
|
+
nablaFit(k = 0, maxIterations = 100, epsilon = 1e-6,
|
|
456
|
+
nSamples = 0, seed = 0,
|
|
457
|
+
keepMultisets = false, computeHistogram = true) {
|
|
458
|
+
if (!this._g) throw new Error('DRESS already freed');
|
|
459
|
+
const M = this._M;
|
|
460
|
+
const E = this._e;
|
|
461
|
+
|
|
462
|
+
const keepMS = keepMultisets ? 1 : 0;
|
|
463
|
+
const histSizePtr = M._malloc(4);
|
|
464
|
+
|
|
465
|
+
let msPtrPtr = 0;
|
|
466
|
+
let numTupPtr = 0;
|
|
467
|
+
if (keepMS) {
|
|
468
|
+
msPtrPtr = M._malloc(4);
|
|
469
|
+
numTupPtr = M._malloc(8);
|
|
470
|
+
M.setValue(msPtrPtr, 0, 'i32');
|
|
471
|
+
M.setValue(numTupPtr, 0, 'i32');
|
|
472
|
+
M.setValue(numTupPtr + 4, 0, 'i32');
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const histPtr = M._dress_nabla_fit(
|
|
476
|
+
this._g, k, maxIterations, epsilon,
|
|
477
|
+
nSamples, seed,
|
|
478
|
+
computeHistogram ? histSizePtr : 0,
|
|
479
|
+
keepMS, msPtrPtr || 0, numTupPtr || 0);
|
|
480
|
+
|
|
481
|
+
const histSize = M.getValue(histSizePtr, 'i32');
|
|
482
|
+
|
|
483
|
+
const histogram = new Array(histSize);
|
|
484
|
+
for (let i = 0; i < histSize; i++) {
|
|
485
|
+
const value = M.HEAPF64[(histPtr >> 3) + i * 2];
|
|
486
|
+
const countLo = M.HEAPU32[(histPtr >> 2) + i * 4 + 2];
|
|
487
|
+
const countHi = M.HEAPU32[(histPtr >> 2) + i * 4 + 3];
|
|
488
|
+
histogram[i] = { value, count: countHi * 4294967296 + countLo };
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
let multisets = null;
|
|
492
|
+
let numTuples = 0;
|
|
493
|
+
if (keepMS && msPtrPtr) {
|
|
494
|
+
const msPtr = M.getValue(msPtrPtr, 'i32');
|
|
495
|
+
const ntLo = M.HEAPU32[(numTupPtr >> 2)];
|
|
496
|
+
const ntHi = M.HEAP32[(numTupPtr >> 2) + 1];
|
|
497
|
+
numTuples = ntHi * 4294967296 + ntLo;
|
|
498
|
+
|
|
499
|
+
if (msPtr !== 0 && numTuples > 0) {
|
|
500
|
+
const totalVals = numTuples * E;
|
|
501
|
+
multisets = new Float64Array(totalVals);
|
|
502
|
+
for (let i = 0; i < totalVals; i++) {
|
|
503
|
+
multisets[i] = M.HEAPF64[(msPtr >> 3) + i];
|
|
504
|
+
}
|
|
505
|
+
M._free(msPtr);
|
|
506
|
+
}
|
|
507
|
+
M._free(msPtrPtr);
|
|
508
|
+
M._free(numTupPtr);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (histPtr) M._free(histPtr);
|
|
512
|
+
M._free(histSizePtr);
|
|
513
|
+
|
|
514
|
+
return { histogram, multisets, numTuples };
|
|
515
|
+
}
|
|
516
|
+
|
|
347
517
|
/**
|
|
348
518
|
* Free the underlying C graph.
|
|
349
519
|
*/
|
|
350
520
|
free() {
|
|
351
521
|
if (this._g) {
|
|
352
522
|
const M = this._M;
|
|
353
|
-
M.
|
|
523
|
+
M._dress_free_graph(this._g);
|
|
354
524
|
M._free(this._iterPtr);
|
|
355
525
|
M._free(this._deltaPtr);
|
|
356
526
|
this._g = 0;
|
|
@@ -372,10 +542,17 @@ export class DRESS {
|
|
|
372
542
|
* @property {boolean} [precompute=false] - Pre-compute intercepts
|
|
373
543
|
*/
|
|
374
544
|
|
|
545
|
+
/**
|
|
546
|
+
* @typedef {Object} HistogramEntry
|
|
547
|
+
* @property {number} value - Exact DRESS value
|
|
548
|
+
* @property {number} count - Number of occurrences of that value
|
|
549
|
+
*/
|
|
550
|
+
|
|
375
551
|
/**
|
|
376
552
|
* @typedef {Object} DeltaDressResult
|
|
377
|
-
* @property {
|
|
378
|
-
* @property {
|
|
553
|
+
* @property {HistogramEntry[]} histogram - Exact sparse histogram entries
|
|
554
|
+
* @property {Float64Array|null} multisets - Per-subgraph edge values, row-major C(N,k) x E
|
|
555
|
+
* @property {number} numSubgraphs - Number of subgraphs C(N,k)
|
|
379
556
|
*/
|
|
380
557
|
|
|
381
558
|
/**
|
|
@@ -387,7 +564,7 @@ export class DRESS {
|
|
|
387
564
|
* @param {DeltaDressOptions} opts
|
|
388
565
|
* @returns {Promise<DeltaDressResult>}
|
|
389
566
|
*/
|
|
390
|
-
export async function
|
|
567
|
+
export async function deltaFit(opts) {
|
|
391
568
|
const M = await getModule();
|
|
392
569
|
|
|
393
570
|
const N = opts.numVertices;
|
|
@@ -401,12 +578,13 @@ export async function deltaDressFit(opts) {
|
|
|
401
578
|
const variant = opts.variant ?? Variant.UNDIRECTED;
|
|
402
579
|
const maxIter = opts.maxIterations ?? 100;
|
|
403
580
|
const epsilon = opts.epsilon ?? 1e-6;
|
|
581
|
+
const nSamples = opts.nSamples ?? 0;
|
|
582
|
+
const seed = opts.seed ?? 0;
|
|
404
583
|
const precompute = (opts.precompute ?? false) ? 1 : 0;
|
|
405
584
|
const keepMS = (opts.keepMultisets ?? false) ? 1 : 0;
|
|
406
|
-
const
|
|
407
|
-
const stride = opts.stride ?? 1;
|
|
585
|
+
const computeHist = (opts.computeHistogram ?? true) ? 1 : 0;
|
|
408
586
|
|
|
409
|
-
// Allocate C arrays (ownership transfers to
|
|
587
|
+
// Allocate C arrays (ownership transfers to dress_init_graph)
|
|
410
588
|
const uPtr = M._malloc(E * 4);
|
|
411
589
|
const vPtr = M._malloc(E * 4);
|
|
412
590
|
|
|
@@ -427,10 +605,19 @@ export async function deltaDressFit(opts) {
|
|
|
427
605
|
}
|
|
428
606
|
}
|
|
429
607
|
|
|
608
|
+
let nwPtr = 0;
|
|
609
|
+
if (opts.nodeWeights && opts.nodeWeights.length === N) {
|
|
610
|
+
nwPtr = M._malloc(N * 8);
|
|
611
|
+
const heapF64 = M.HEAPF64;
|
|
612
|
+
for (let i = 0; i < N; i++) {
|
|
613
|
+
heapF64[(nwPtr >> 3) + i] = opts.nodeWeights[i];
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
430
617
|
// Build graph
|
|
431
|
-
const g = M.
|
|
618
|
+
const g = M._dress_init_graph(N, E, uPtr, vPtr, wPtr, nwPtr, variant, precompute);
|
|
432
619
|
if (g === 0) {
|
|
433
|
-
throw new Error('
|
|
620
|
+
throw new Error('dress_init_graph returned NULL');
|
|
434
621
|
}
|
|
435
622
|
|
|
436
623
|
// Allocate out-param for hist_size
|
|
@@ -447,19 +634,24 @@ export async function deltaDressFit(opts) {
|
|
|
447
634
|
M.setValue(numSubPtr + 4, 0, 'i32');
|
|
448
635
|
}
|
|
449
636
|
|
|
450
|
-
// Call
|
|
451
|
-
const histPtr = M.
|
|
452
|
-
|
|
637
|
+
// Call dress_delta_fit_strided (returns dress_hist_pair_t* on heap)
|
|
638
|
+
const histPtr = M._dress_delta_fit_strided(g, k, maxIter, epsilon,
|
|
639
|
+
nSamples, seed,
|
|
640
|
+
computeHist ? histSizePtr : 0,
|
|
641
|
+
keepMS, msPtrPtr, numSubPtr, 0, 1);
|
|
453
642
|
|
|
454
643
|
const histSize = M.getValue(histSizePtr, 'i32');
|
|
455
644
|
|
|
456
|
-
// Copy histogram into JS
|
|
457
|
-
|
|
458
|
-
const histogram = new Float64Array(histSize);
|
|
645
|
+
// Copy histogram pairs into JS objects.
|
|
646
|
+
const histogram = new Array(histSize);
|
|
459
647
|
for (let i = 0; i < histSize; i++) {
|
|
460
|
-
const
|
|
461
|
-
const
|
|
462
|
-
|
|
648
|
+
const value = M.HEAPF64[(histPtr >> 3) + i * 2];
|
|
649
|
+
const countLo = M.HEAPU32[(histPtr >> 2) + i * 4 + 2];
|
|
650
|
+
const countHi = M.HEAPU32[(histPtr >> 2) + i * 4 + 3];
|
|
651
|
+
histogram[i] = {
|
|
652
|
+
value,
|
|
653
|
+
count: countHi * 4294967296 + countLo,
|
|
654
|
+
};
|
|
463
655
|
}
|
|
464
656
|
|
|
465
657
|
// Extract multisets if requested
|
|
@@ -487,13 +679,145 @@ export async function deltaDressFit(opts) {
|
|
|
487
679
|
// Cleanup
|
|
488
680
|
M._free(histPtr);
|
|
489
681
|
M._free(histSizePtr);
|
|
490
|
-
M.
|
|
682
|
+
M._dress_free_graph(g);
|
|
491
683
|
|
|
492
684
|
return {
|
|
493
685
|
histogram: histogram,
|
|
494
|
-
histSize: histSize,
|
|
495
686
|
multisets: multisets,
|
|
496
687
|
numSubgraphs: numSubgraphs,
|
|
497
688
|
};
|
|
498
689
|
}
|
|
499
690
|
|
|
691
|
+
/**
|
|
692
|
+
* Compute the Nabla-k-DRESS histogram.
|
|
693
|
+
*
|
|
694
|
+
* Exhaustively removes all k-vertex tuples and measures
|
|
695
|
+
* the change in edge similarity values.
|
|
696
|
+
*
|
|
697
|
+
* @param {NablaDressOptions} opts
|
|
698
|
+
* @returns {Promise<NablaDressResult>}
|
|
699
|
+
*/
|
|
700
|
+
export async function nablaFit(opts) {
|
|
701
|
+
const M = await getModule();
|
|
702
|
+
|
|
703
|
+
const N = opts.numVertices;
|
|
704
|
+
const E = opts.sources.length;
|
|
705
|
+
|
|
706
|
+
if (opts.targets.length !== E) {
|
|
707
|
+
throw new Error(`sources (${E}) and targets (${opts.targets.length}) must have equal length`);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
const k = opts.k ?? 0;
|
|
711
|
+
const variant = opts.variant ?? Variant.UNDIRECTED;
|
|
712
|
+
const maxIter = opts.maxIterations ?? 100;
|
|
713
|
+
const epsilon = opts.epsilon ?? 1e-6;
|
|
714
|
+
const nSamples = opts.nSamples ?? 0;
|
|
715
|
+
const seed = opts.seed ?? 0;
|
|
716
|
+
const precompute = (opts.precompute ?? false) ? 1 : 0;
|
|
717
|
+
const keepMS = (opts.keepMultisets ?? false) ? 1 : 0;
|
|
718
|
+
const computeHist = (opts.computeHistogram ?? true) ? 1 : 0;
|
|
719
|
+
|
|
720
|
+
// Allocate C arrays (ownership transfers to dress_init_graph)
|
|
721
|
+
const uPtr = M._malloc(E * 4);
|
|
722
|
+
const vPtr = M._malloc(E * 4);
|
|
723
|
+
|
|
724
|
+
const heap32 = M.HEAP32;
|
|
725
|
+
const src = opts.sources;
|
|
726
|
+
const tgt = opts.targets;
|
|
727
|
+
for (let i = 0; i < E; i++) {
|
|
728
|
+
heap32[(uPtr >> 2) + i] = src[i];
|
|
729
|
+
heap32[(vPtr >> 2) + i] = tgt[i];
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
let wPtr = 0;
|
|
733
|
+
if (opts.weights && opts.weights.length === E) {
|
|
734
|
+
wPtr = M._malloc(E * 8);
|
|
735
|
+
const heapF64 = M.HEAPF64;
|
|
736
|
+
for (let i = 0; i < E; i++) {
|
|
737
|
+
heapF64[(wPtr >> 3) + i] = opts.weights[i];
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
let nwPtr = 0;
|
|
742
|
+
if (opts.nodeWeights && opts.nodeWeights.length === N) {
|
|
743
|
+
nwPtr = M._malloc(N * 8);
|
|
744
|
+
const heapF64 = M.HEAPF64;
|
|
745
|
+
for (let i = 0; i < N; i++) {
|
|
746
|
+
heapF64[(nwPtr >> 3) + i] = opts.nodeWeights[i];
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// Build graph
|
|
751
|
+
const g = M._dress_init_graph(N, E, uPtr, vPtr, wPtr, nwPtr, variant, precompute);
|
|
752
|
+
if (g === 0) {
|
|
753
|
+
throw new Error('dress_init_graph returned NULL');
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
// Allocate out-param for hist_size
|
|
757
|
+
const histSizePtr = M._malloc(4);
|
|
758
|
+
|
|
759
|
+
// Allocate out-params for multisets (pointer-to-pointer and num_tuples)
|
|
760
|
+
let msPtrPtr = 0;
|
|
761
|
+
let numTupPtr = 0;
|
|
762
|
+
if (keepMS) {
|
|
763
|
+
msPtrPtr = M._malloc(4); // pointer to double*
|
|
764
|
+
numTupPtr = M._malloc(8); // int64_t
|
|
765
|
+
M.setValue(msPtrPtr, 0, 'i32');
|
|
766
|
+
M.setValue(numTupPtr, 0, 'i32');
|
|
767
|
+
M.setValue(numTupPtr + 4, 0, 'i32');
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// Call dress_nabla_fit (returns dress_hist_pair_t* on heap)
|
|
771
|
+
const histPtr = M._dress_nabla_fit(g, k, maxIter, epsilon,
|
|
772
|
+
nSamples, seed,
|
|
773
|
+
computeHist ? histSizePtr : 0,
|
|
774
|
+
keepMS, msPtrPtr, numTupPtr);
|
|
775
|
+
|
|
776
|
+
const histSize = M.getValue(histSizePtr, 'i32');
|
|
777
|
+
|
|
778
|
+
// Copy histogram pairs into JS objects.
|
|
779
|
+
const histogram = new Array(histSize);
|
|
780
|
+
for (let i = 0; i < histSize; i++) {
|
|
781
|
+
const value = M.HEAPF64[(histPtr >> 3) + i * 2];
|
|
782
|
+
const countLo = M.HEAPU32[(histPtr >> 2) + i * 4 + 2];
|
|
783
|
+
const countHi = M.HEAPU32[(histPtr >> 2) + i * 4 + 3];
|
|
784
|
+
histogram[i] = {
|
|
785
|
+
value,
|
|
786
|
+
count: countHi * 4294967296 + countLo,
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// Extract multisets if requested
|
|
791
|
+
let multisets = null;
|
|
792
|
+
let numTuples = 0;
|
|
793
|
+
if (keepMS && msPtrPtr) {
|
|
794
|
+
const msPtr = M.getValue(msPtrPtr, 'i32'); // double*
|
|
795
|
+
// Read int64 num_tuples as lo/hi pair
|
|
796
|
+
const ntLo = M.HEAPU32[(numTupPtr >> 2)];
|
|
797
|
+
const ntHi = M.HEAP32[(numTupPtr >> 2) + 1];
|
|
798
|
+
numTuples = ntHi * 4294967296 + ntLo;
|
|
799
|
+
|
|
800
|
+
if (msPtr !== 0 && numTuples > 0) {
|
|
801
|
+
const totalVals = numTuples * E;
|
|
802
|
+
multisets = new Float64Array(totalVals);
|
|
803
|
+
for (let i = 0; i < totalVals; i++) {
|
|
804
|
+
multisets[i] = M.HEAPF64[(msPtr >> 3) + i];
|
|
805
|
+
}
|
|
806
|
+
M._free(msPtr);
|
|
807
|
+
}
|
|
808
|
+
M._free(msPtrPtr);
|
|
809
|
+
M._free(numTupPtr);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// Cleanup
|
|
813
|
+
M._free(histPtr);
|
|
814
|
+
M._free(histSizePtr);
|
|
815
|
+
M._dress_free_graph(g);
|
|
816
|
+
|
|
817
|
+
return {
|
|
818
|
+
histogram: histogram,
|
|
819
|
+
multisets: multisets,
|
|
820
|
+
numTuples: numTuples,
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
|
package/dress_wasm.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var createDressModule=(()=>{var _scriptName=globalThis.document?.currentScript?.src;return async function(moduleArg={}){var moduleRtn;var Module=moduleArg;var ENVIRONMENT_IS_WEB=!!globalThis.window;var ENVIRONMENT_IS_WORKER=!!globalThis.WorkerGlobalScope;var ENVIRONMENT_IS_NODE=globalThis.process?.versions?.node&&globalThis.process?.type!="renderer";var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};if(typeof __filename!="undefined"){_scriptName=__filename}else{}var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("node:fs");scriptDirectory=__dirname+"/";readBinary=filename=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename);return ret};readAsync=async(filename,binary=true)=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename,binary?undefined:"utf8");return ret};if(process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){try{scriptDirectory=new URL(".",_scriptName).href}catch{}{readAsync=async url=>{var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=console.log.bind(console);var err=console.error.bind(console);var wasmBinary;var ABORT=false;var isFileURI=filename=>filename.startsWith("file://");var readyPromiseResolve,readyPromiseReject;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;var HEAP64,HEAPU64;var runtimeInitialized=false;function updateMemoryViews(){var b=wasmMemory.buffer;HEAP8=new Int8Array(b);HEAP16=new Int16Array(b);HEAPU8=new Uint8Array(b);HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b);HEAP64=new BigInt64Array(b);HEAPU64=new BigUint64Array(b)}function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(onPreRuns)}function initRuntime(){runtimeInitialized=true;wasmExports["c"]()}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(onPostRuns)}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject?.(e);throw e}var wasmBinaryFile;function findWasmBinary(){return locateFile("dress_wasm.wasm")}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}async function getWasmBinary(binaryFile){if(!wasmBinary){try{var response=await readAsync(binaryFile);return new Uint8Array(response)}catch{}}return getBinarySync(binaryFile)}async function instantiateArrayBuffer(binaryFile,imports){try{var binary=await getWasmBinary(binaryFile);var instance=await WebAssembly.instantiate(binary,imports);return instance}catch(reason){err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)}}async function instantiateAsync(binary,binaryFile,imports){if(!binary&&!ENVIRONMENT_IS_NODE){try{var response=fetch(binaryFile,{credentials:"same-origin"});var instantiationResult=await WebAssembly.instantiateStreaming(response,imports);return instantiationResult}catch(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation")}}return instantiateArrayBuffer(binaryFile,imports)}function getWasmImports(){var imports={a:wasmImports};return imports}async function createWasm(){function receiveInstance(instance,module){wasmExports=instance.exports;assignWasmExports(wasmExports);updateMemoryViews();return wasmExports}function receiveInstantiationResult(result){return receiveInstance(result["instance"])}var info=getWasmImports();if(Module["instantiateWasm"]){return new Promise((resolve,reject)=>{Module["instantiateWasm"](info,(inst,mod)=>{resolve(receiveInstance(inst,mod))})})}wasmBinaryFile??=findWasmBinary();var result=await instantiateAsync(wasmBinary,wasmBinaryFile,info);var exports=receiveInstantiationResult(result);return exports}class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var onPostRuns=[];var addOnPostRun=cb=>onPostRuns.push(cb);var onPreRuns=[];var addOnPreRun=cb=>onPreRuns.push(cb);function getValue(ptr,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":return HEAP8[ptr];case"i8":return HEAP8[ptr];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":return HEAP64[ptr>>3];case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];case"*":return HEAPU32[ptr>>2];default:abort(`invalid type for getValue: ${type}`)}}var noExitRuntime=true;function setValue(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":HEAP8[ptr]=value;break;case"i8":HEAP8[ptr]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":HEAP64[ptr>>3]=BigInt(value);break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;case"*":HEAPU32[ptr>>2]=value;break;default:abort(`invalid type for setValue: ${type}`)}}var stackRestore=val=>__emscripten_stack_restore(val);var stackSave=()=>_emscripten_stack_get_current();var getHeapMax=()=>2147483648;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var growMemory=size=>{var oldHeapSize=wasmMemory.buffer.byteLength;var pages=(size-oldHeapSize+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer)};var lengthBytesUTF8=str=>{var len=0;for(var i=0;i<str.length;++i){var c=str.charCodeAt(i);if(c<=127){len++}else if(c<=2047){len+=2}else if(c>=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.codePointAt(i);if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;i++}}heap[outIdx]=0;return outIdx-startIdx};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var UTF8Decoder=globalThis.TextDecoder&&new TextDecoder;var findStringEnd=(heapOrArray,idx,maxBytesToRead,ignoreNul)=>{var maxIdx=idx+maxBytesToRead;if(ignoreNul)return maxIdx;while(heapOrArray[idx]&&!(idx>=maxIdx))++idx;return idx};var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead,ignoreNul)=>{var endPtr=findStringEnd(heapOrArray,idx,maxBytesToRead,ignoreNul);if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx<endPtr){var u0=heapOrArray[idx++];if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=heapOrArray[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=heapOrArray[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|heapOrArray[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead,ignoreNul)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead,ignoreNul):"";var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i<args.length;i++){var converter=toC[argTypes[i]];if(converter){if(stack===0)stack=stackSave();cArgs[i]=converter(args[i])}else{cArgs[i]=args[i]}}}var ret=func(...cArgs);function onDone(ret){if(stack!==0)stackRestore(stack);return convertReturnValue(ret)}ret=onDone(ret);return ret};var cwrap=(ident,returnType,argTypes,opts)=>{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};{if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(Module["print"])out=Module["print"];if(Module["printErr"])err=Module["printErr"];if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].shift()()}}}Module["ccall"]=ccall;Module["cwrap"]=cwrap;Module["setValue"]=setValue;Module["getValue"]=getValue;var _dress_init_graph,_malloc,_free,_dress_fit,_dress_free_graph,_dress_get,_dress_delta_fit,_dress_delta_fit_strided,_dress_nabla_fit,__emscripten_stack_restore,__emscripten_stack_alloc,_emscripten_stack_get_current,memory,__indirect_function_table,wasmMemory;function assignWasmExports(wasmExports){_dress_init_graph=Module["_dress_init_graph"]=wasmExports["d"];_malloc=Module["_malloc"]=wasmExports["e"];_free=Module["_free"]=wasmExports["f"];_dress_fit=Module["_dress_fit"]=wasmExports["g"];_dress_free_graph=Module["_dress_free_graph"]=wasmExports["h"];_dress_get=Module["_dress_get"]=wasmExports["i"];_dress_delta_fit=Module["_dress_delta_fit"]=wasmExports["j"];_dress_delta_fit_strided=Module["_dress_delta_fit_strided"]=wasmExports["k"];_dress_nabla_fit=Module["_dress_nabla_fit"]=wasmExports["l"];__emscripten_stack_restore=wasmExports["m"];__emscripten_stack_alloc=wasmExports["n"];_emscripten_stack_get_current=wasmExports["o"];memory=wasmMemory=wasmExports["b"];__indirect_function_table=wasmExports["__indirect_function_table"]}var wasmImports={a:_emscripten_resize_heap};function run(){preRun();function doRun(){Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve?.(Module);Module["onRuntimeInitialized"]?.();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(()=>{setTimeout(()=>Module["setStatus"](""),1);doRun()},1)}else{doRun()}}var wasmExports;wasmExports=await (createWasm());run();if(runtimeInitialized){moduleRtn=Module}else{moduleRtn=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject})}
|
|
2
|
+
;return moduleRtn}})();if(typeof exports==="object"&&typeof module==="object"){module.exports=createDressModule;module.exports.default=createDressModule}else if(typeof define==="function"&&define["amd"])define([],()=>createDressModule);
|
package/dress_wasm.wasm
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dress-graph",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "DRESS is a deterministic, parameter-free framework that iteratively refines the structural similarity of edges in a graph to produce a canonical fingerprint: a real-valued edge vector, obtained by converging a non-linear dynamical system to its unique fixed point. The fingerprint is isomorphism-invariant by construction, numerically stable (no overflow, no error amplification, no undefined behavior), fast and embarrassingly parallel to compute: DRESS total runtime is O(I * m * d_max) for I iterations to convergence, and convergence is guaranteed by Birkhoff contraction.",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "DRESS is a deterministic, parameter-free framework that iteratively refines the structural similarity of edges in a graph to produce a canonical fingerprint: a real-valued edge vector, obtained by converging a non-linear dynamical system to its unique fixed point. The fingerprint is self-contained, isomorphism-invariant by construction, numerically stable (no overflow, no error amplification, no undefined behavior), fast and embarrassingly parallel to compute: DRESS total runtime is O(I * m * d_max) for I iterations to convergence, and convergence is guaranteed by Birkhoff contraction.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dress.js",
|
|
7
7
|
"types": "dress.d.ts",
|