dress-graph 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dress.d.ts CHANGED
@@ -24,7 +24,7 @@ export interface DressOptions {
24
24
  maxIterations?: number;
25
25
  /** Convergence threshold (default: 1e-6) */
26
26
  epsilon?: number;
27
- /** Pre-compute neighbourhood intercepts (default: true) */
27
+ /** Pre-compute neighbourhood intercepts (default: false) */
28
28
  precomputeIntercepts?: boolean;
29
29
  }
30
30
 
@@ -50,6 +50,33 @@ export interface DressResult {
50
50
  */
51
51
  export declare function dressFit(opts: DressOptions): Promise<DressResult>;
52
52
 
53
+ export interface DressGraphOptions {
54
+ /** Number of vertices (vertex ids must be in 0..numVertices-1) */
55
+ numVertices: number;
56
+ /** Edge source vertices (0-based) */
57
+ sources: Int32Array | number[];
58
+ /** Edge target vertices (0-based) */
59
+ targets: Int32Array | number[];
60
+ /** Optional edge weights (same length as sources) */
61
+ weights?: Float64Array | number[] | null;
62
+ /** Graph variant (default: Variant.UNDIRECTED) */
63
+ variant?: number;
64
+ /** Pre-compute neighbourhood intercepts (default: false) */
65
+ precomputeIntercepts?: boolean;
66
+ }
67
+
68
+ /**
69
+ * A persistent DRESS graph supporting repeated fit / get calls.
70
+ */
71
+ export declare class DressGraph {
72
+ private constructor();
73
+ static create(opts: DressGraphOptions): Promise<DressGraph>;
74
+ fit(maxIterations?: number, epsilon?: number): { iterations: number; delta: number };
75
+ get(u: number, v: number, maxIterations?: number, epsilon?: number, edgeWeight?: number): number;
76
+ result(): DressResult;
77
+ free(): void;
78
+ }
79
+
53
80
  export interface DeltaDressOptions {
54
81
  /** Number of vertices (vertex ids must be in 0..numVertices-1) */
55
82
  numVertices: number;
@@ -89,3 +116,4 @@ export interface DeltaDressResult {
89
116
  * all k-vertex subsets and measuring edge similarity changes.
90
117
  */
91
118
  export declare function deltaDressFit(opts: DeltaDressOptions): Promise<DeltaDressResult>;
119
+
package/dress.js CHANGED
@@ -66,7 +66,7 @@ export const Variant = Object.freeze({
66
66
  * @property {number} [variant=0] - Variant (see Variant enum)
67
67
  * @property {number} [maxIterations=100] - Max fitting iterations
68
68
  * @property {number} [epsilon=1e-6] - Convergence threshold
69
- * @property {boolean} [precomputeIntercepts=true] - Pre-compute intercepts
69
+ * @property {boolean} [precomputeIntercepts=false] - Pre-compute intercepts
70
70
  */
71
71
 
72
72
  /**
@@ -102,7 +102,7 @@ export async function dressFit(opts) {
102
102
  const variant = opts.variant ?? Variant.UNDIRECTED;
103
103
  const maxIter = opts.maxIterations ?? 100;
104
104
  const epsilon = opts.epsilon ?? 1e-6;
105
- const precompute = (opts.precomputeIntercepts ?? true) ? 1 : 0;
105
+ const precompute = (opts.precomputeIntercepts ?? false) ? 1 : 0;
106
106
 
107
107
  // Allocate C arrays (ownership transfers to dress.c — freed by free_dress_graph)
108
108
  const uPtr = M._malloc(E * 4);
@@ -138,8 +138,8 @@ export async function dressFit(opts) {
138
138
  const iterPtr = M._malloc(4); // int*
139
139
  const deltaPtr = M._malloc(8); // double*
140
140
 
141
- // Call fit
142
- M._fit(g, maxIter, epsilon, iterPtr, deltaPtr);
141
+ // Call dress_fit
142
+ M._dress_fit(g, maxIter, epsilon, iterPtr, deltaPtr);
143
143
 
144
144
  const iterations = M.getValue(iterPtr, 'i32');
145
145
  const delta = M.getValue(deltaPtr, 'double');
@@ -201,6 +201,162 @@ export async function dressFit(opts) {
201
201
  };
202
202
  }
203
203
 
204
+ // ── Persistent DressGraph class ─────────────────────────────────────
205
+
206
+ /**
207
+ * A persistent DRESS graph that supports repeated fit and get calls.
208
+ *
209
+ * Usage:
210
+ * const g = await DressGraph.create({
211
+ * numVertices: 4,
212
+ * sources: [0,1,2,0],
213
+ * targets: [1,2,3,3],
214
+ * });
215
+ * g.fit(); // fit with defaults
216
+ * const d = g.get(0, 2); // virtual edge query
217
+ * const res = g.result(); // snapshot of current results
218
+ * g.free(); // explicitly free C graph
219
+ */
220
+ export class DressGraph {
221
+ /** @private */
222
+ constructor(module, gPtr, n, e, sources, targets) {
223
+ this._M = module;
224
+ this._g = gPtr;
225
+ this._n = n;
226
+ this._e = e;
227
+ this._sources = new Int32Array(sources);
228
+ this._targets = new Int32Array(targets);
229
+ this._iterPtr = module._malloc(4);
230
+ this._deltaPtr = module._malloc(8);
231
+ }
232
+
233
+ /**
234
+ * Create a persistent DressGraph.
235
+ *
236
+ * @param {Object} opts
237
+ * @param {number} opts.numVertices
238
+ * @param {Int32Array|number[]} opts.sources
239
+ * @param {Int32Array|number[]} opts.targets
240
+ * @param {Float64Array|number[]|null} [opts.weights]
241
+ * @param {number} [opts.variant=0]
242
+ * @param {boolean} [opts.precomputeIntercepts=false]
243
+ * @returns {Promise<DressGraph>}
244
+ */
245
+ static async create(opts) {
246
+ const M = await getModule();
247
+
248
+ const N = opts.numVertices;
249
+ const E = opts.sources.length;
250
+
251
+ if (opts.targets.length !== E)
252
+ throw new Error('sources and targets must have equal length');
253
+
254
+ const variant = opts.variant ?? Variant.UNDIRECTED;
255
+ const precompute = (opts.precomputeIntercepts ?? false) ? 1 : 0;
256
+
257
+ const uPtr = M._malloc(E * 4);
258
+ const vPtr = M._malloc(E * 4);
259
+ for (let i = 0; i < E; i++) {
260
+ M.HEAP32[(uPtr >> 2) + i] = opts.sources[i];
261
+ M.HEAP32[(vPtr >> 2) + i] = opts.targets[i];
262
+ }
263
+
264
+ let wPtr = 0;
265
+ if (opts.weights && opts.weights.length === E) {
266
+ wPtr = M._malloc(E * 8);
267
+ for (let i = 0; i < E; i++) {
268
+ M.HEAPF64[(wPtr >> 3) + i] = opts.weights[i];
269
+ }
270
+ }
271
+
272
+ const g = M._init_dress_graph(N, E, uPtr, vPtr, wPtr, variant, precompute);
273
+ if (g === 0) throw new Error('init_dress_graph returned NULL');
274
+
275
+ return new DressGraph(M, g, N, E, opts.sources, opts.targets);
276
+ }
277
+
278
+ /**
279
+ * Fit the DRESS model.
280
+ * @param {number} [maxIterations=100]
281
+ * @param {number} [epsilon=1e-6]
282
+ * @returns {{iterations: number, delta: number}}
283
+ */
284
+ fit(maxIterations = 100, epsilon = 1e-6) {
285
+ if (!this._g) throw new Error('DressGraph already freed');
286
+ const M = this._M;
287
+ M._dress_fit(this._g, maxIterations, epsilon, this._iterPtr, this._deltaPtr);
288
+ return {
289
+ iterations: M.getValue(this._iterPtr, 'i32'),
290
+ delta: M.getValue(this._deltaPtr, 'double'),
291
+ };
292
+ }
293
+
294
+ /**
295
+ * Query the DRESS value for an edge (existing or virtual).
296
+ * @param {number} u - source vertex (0-based)
297
+ * @param {number} v - target vertex (0-based)
298
+ * @param {number} [maxIterations=100]
299
+ * @param {number} [epsilon=1e-6]
300
+ * @param {number} [edgeWeight=1.0]
301
+ * @returns {number}
302
+ */
303
+ get(u, v, maxIterations = 100, epsilon = 1e-6, edgeWeight = 1.0) {
304
+ if (!this._g) throw new Error('DressGraph already freed');
305
+ return this._M._dress_get(this._g, u, v, maxIterations, epsilon, edgeWeight);
306
+ }
307
+
308
+ /**
309
+ * Extract a snapshot of the current results.
310
+ * @returns {DressResult}
311
+ */
312
+ result() {
313
+ if (!this._g) throw new Error('DressGraph already freed');
314
+ const M = this._M;
315
+ const E = this._e;
316
+ const N = this._n;
317
+
318
+ // WASM32 offsets
319
+ const ewPtr = M.getValue(this._g + 36, 'i32');
320
+ const edPtr = M.getValue(this._g + 40, 'i32');
321
+ const ndPtr = M.getValue(this._g + 48, 'i32');
322
+
323
+ const edgeWeight = new Float64Array(E);
324
+ const edgeDress = new Float64Array(E);
325
+ const nodeDress = new Float64Array(N);
326
+
327
+ for (let i = 0; i < E; i++) {
328
+ edgeWeight[i] = M.HEAPF64[(ewPtr >> 3) + i];
329
+ edgeDress[i] = M.HEAPF64[(edPtr >> 3) + i];
330
+ }
331
+ for (let i = 0; i < N; i++) {
332
+ nodeDress[i] = M.HEAPF64[(ndPtr >> 3) + i];
333
+ }
334
+
335
+ return {
336
+ sources: new Int32Array(this._sources),
337
+ targets: new Int32Array(this._targets),
338
+ edgeWeight,
339
+ edgeDress,
340
+ nodeDress,
341
+ iterations: 0,
342
+ delta: 0,
343
+ };
344
+ }
345
+
346
+ /**
347
+ * Free the underlying C graph.
348
+ */
349
+ free() {
350
+ if (this._g) {
351
+ const M = this._M;
352
+ M._free_dress_graph(this._g);
353
+ M._free(this._iterPtr);
354
+ M._free(this._deltaPtr);
355
+ this._g = 0;
356
+ }
357
+ }
358
+ }
359
+
204
360
  // ── Delta-k-DRESS API ───────────────────────────────────────────────
205
361
 
206
362
  /**
@@ -288,8 +444,8 @@ export async function deltaDressFit(opts) {
288
444
  M.setValue(numSubPtr + 4, 0, 'i32');
289
445
  }
290
446
 
291
- // Call delta_fit (returns int64_t* — pointer to histogram on heap)
292
- const histPtr = M._delta_fit(g, k, maxIter, epsilon, histSizePtr,
447
+ // Call delta_dress_fit (returns int64_t* — pointer to histogram on heap)
448
+ const histPtr = M._delta_dress_fit(g, k, maxIter, epsilon, histSizePtr,
293
449
  keepMS, msPtrPtr, numSubPtr);
294
450
 
295
451
  const histSize = M.getValue(histSizePtr, 'i32');
@@ -337,3 +493,4 @@ export async function deltaDressFit(opts) {
337
493
  numSubgraphs: numSubgraphs,
338
494
  };
339
495
  }
496
+
package/dress_wasm.wasm CHANGED
Binary file
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dress-graph",
3
- "version": "0.3.1",
4
- "description": "DRESS A Continuous Framework for Structural Graph Refinement (WebAssembly)",
3
+ "version": "0.4.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.",
5
5
  "type": "module",
6
6
  "main": "dress.js",
7
7
  "types": "dress.d.ts",