agentic-qe 3.8.11 → 3.8.13

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.
Files changed (98) hide show
  1. package/.claude/skills/qe-code-intelligence/SKILL.md +29 -20
  2. package/.claude/skills/qe-code-intelligence/evals/qe-code-intelligence.yaml +3 -3
  3. package/.claude/skills/qe-quality-assessment/SKILL.md +1 -1
  4. package/.claude/skills/qe-test-generation/SKILL.md +1 -1
  5. package/.claude/skills/skills-manifest.json +1 -1
  6. package/CHANGELOG.md +45 -0
  7. package/README.md +9 -0
  8. package/assets/skills/qe-code-intelligence/SKILL.md +29 -20
  9. package/assets/skills/qe-code-intelligence/evals/qe-code-intelligence.yaml +3 -3
  10. package/assets/skills/qe-quality-assessment/SKILL.md +1 -1
  11. package/assets/skills/qe-test-generation/SKILL.md +1 -1
  12. package/dist/cli/bundle.js +1162 -1046
  13. package/dist/cli/commands/code.js +149 -11
  14. package/dist/cli/commands/init.js +3 -2
  15. package/dist/cli/commands/ruvector-commands.js +17 -0
  16. package/dist/cli/handlers/init-handler.d.ts +1 -0
  17. package/dist/cli/handlers/init-handler.js +15 -10
  18. package/dist/cli/utils/file-discovery.d.ts +1 -0
  19. package/dist/cli/utils/file-discovery.js +1 -1
  20. package/dist/domains/code-intelligence/coordinator-gnn.d.ts +21 -0
  21. package/dist/domains/code-intelligence/coordinator-gnn.js +102 -0
  22. package/dist/domains/contract-testing/coordinator.js +13 -0
  23. package/dist/domains/coverage-analysis/coordinator.js +5 -0
  24. package/dist/domains/defect-intelligence/coordinator.d.ts +1 -0
  25. package/dist/domains/defect-intelligence/coordinator.js +43 -0
  26. package/dist/domains/quality-assessment/coordinator.js +26 -0
  27. package/dist/domains/test-generation/coordinator.js +14 -0
  28. package/dist/init/orchestrator.js +1 -0
  29. package/dist/init/phases/08-mcp.js +4 -4
  30. package/dist/init/phases/phase-interface.d.ts +3 -1
  31. package/dist/integrations/agentic-flow/reasoning-bank/experience-replay.d.ts +11 -0
  32. package/dist/integrations/agentic-flow/reasoning-bank/experience-replay.js +44 -1
  33. package/dist/integrations/rl-suite/algorithms/eprop.d.ts +79 -0
  34. package/dist/integrations/rl-suite/algorithms/eprop.js +284 -0
  35. package/dist/integrations/rl-suite/algorithms/index.d.ts +2 -1
  36. package/dist/integrations/rl-suite/algorithms/index.js +2 -1
  37. package/dist/integrations/rl-suite/index.d.ts +2 -2
  38. package/dist/integrations/rl-suite/index.js +2 -2
  39. package/dist/integrations/rl-suite/interfaces.d.ts +3 -3
  40. package/dist/integrations/rl-suite/interfaces.js +1 -1
  41. package/dist/integrations/rl-suite/orchestrator.d.ts +2 -2
  42. package/dist/integrations/rl-suite/orchestrator.js +3 -2
  43. package/dist/integrations/rl-suite/reward-signals.d.ts +1 -1
  44. package/dist/integrations/rl-suite/reward-signals.js +1 -1
  45. package/dist/integrations/ruvector/coherence-gate-cohomology.d.ts +41 -0
  46. package/dist/integrations/ruvector/coherence-gate-cohomology.js +47 -0
  47. package/dist/integrations/ruvector/coherence-gate-core.d.ts +200 -0
  48. package/dist/integrations/ruvector/coherence-gate-core.js +294 -0
  49. package/dist/integrations/ruvector/coherence-gate-energy.d.ts +136 -0
  50. package/dist/integrations/ruvector/coherence-gate-energy.js +373 -0
  51. package/dist/integrations/ruvector/coherence-gate-vector.d.ts +38 -0
  52. package/dist/integrations/ruvector/coherence-gate-vector.js +76 -0
  53. package/dist/integrations/ruvector/coherence-gate.d.ts +10 -311
  54. package/dist/integrations/ruvector/coherence-gate.js +10 -652
  55. package/dist/integrations/ruvector/cold-tier-trainer.d.ts +103 -0
  56. package/dist/integrations/ruvector/cold-tier-trainer.js +377 -0
  57. package/dist/integrations/ruvector/cusum-detector.d.ts +70 -0
  58. package/dist/integrations/ruvector/cusum-detector.js +142 -0
  59. package/dist/integrations/ruvector/delta-tracker.d.ts +122 -0
  60. package/dist/integrations/ruvector/delta-tracker.js +311 -0
  61. package/dist/integrations/ruvector/domain-transfer.d.ts +79 -1
  62. package/dist/integrations/ruvector/domain-transfer.js +158 -2
  63. package/dist/integrations/ruvector/eprop-learner.d.ts +135 -0
  64. package/dist/integrations/ruvector/eprop-learner.js +351 -0
  65. package/dist/integrations/ruvector/feature-flags.d.ts +177 -0
  66. package/dist/integrations/ruvector/feature-flags.js +145 -0
  67. package/dist/integrations/ruvector/graphmae-encoder.d.ts +88 -0
  68. package/dist/integrations/ruvector/graphmae-encoder.js +360 -0
  69. package/dist/integrations/ruvector/hdc-fingerprint.d.ts +127 -0
  70. package/dist/integrations/ruvector/hdc-fingerprint.js +222 -0
  71. package/dist/integrations/ruvector/hopfield-memory.d.ts +97 -0
  72. package/dist/integrations/ruvector/hopfield-memory.js +238 -0
  73. package/dist/integrations/ruvector/index.d.ts +13 -2
  74. package/dist/integrations/ruvector/index.js +46 -2
  75. package/dist/integrations/ruvector/mincut-wrapper.d.ts +7 -0
  76. package/dist/integrations/ruvector/mincut-wrapper.js +54 -2
  77. package/dist/integrations/ruvector/reservoir-replay.d.ts +172 -0
  78. package/dist/integrations/ruvector/reservoir-replay.js +335 -0
  79. package/dist/integrations/ruvector/solver-adapter.d.ts +93 -0
  80. package/dist/integrations/ruvector/solver-adapter.js +299 -0
  81. package/dist/integrations/ruvector/sona-persistence.d.ts +33 -0
  82. package/dist/integrations/ruvector/sona-persistence.js +47 -0
  83. package/dist/integrations/ruvector/spectral-sparsifier.d.ts +154 -0
  84. package/dist/integrations/ruvector/spectral-sparsifier.js +389 -0
  85. package/dist/integrations/ruvector/temporal-causality.d.ts +63 -0
  86. package/dist/integrations/ruvector/temporal-causality.js +317 -0
  87. package/dist/learning/pattern-promotion.d.ts +63 -0
  88. package/dist/learning/pattern-promotion.js +235 -1
  89. package/dist/learning/pattern-store.d.ts +2 -0
  90. package/dist/learning/pattern-store.js +187 -1
  91. package/dist/learning/sqlite-persistence.d.ts +2 -0
  92. package/dist/learning/sqlite-persistence.js +4 -0
  93. package/dist/mcp/bundle.js +506 -427
  94. package/dist/shared/utils/index.d.ts +1 -0
  95. package/dist/shared/utils/index.js +1 -0
  96. package/dist/shared/utils/xorshift128.d.ts +24 -0
  97. package/dist/shared/utils/xorshift128.js +50 -0
  98. package/package.json +1 -1
@@ -0,0 +1,299 @@
1
+ /**
2
+ * Agentic QE v3 - PageRank Pattern Importance Solver (ADR-087, Milestone 3)
3
+ *
4
+ * Provides graph-based importance scoring for QE patterns using PageRank.
5
+ *
6
+ * Two execution paths:
7
+ * - **Native** (@ruvector/solver-node): O(log n) sublinear via Neumann series.
8
+ * Requires the optional NAPI dependency to be installed.
9
+ * - **TypeScript fallback**: Standard power iteration, O(n * m * iterations).
10
+ * Always available, correct results, linear-time.
11
+ *
12
+ * Usage:
13
+ * ```typescript
14
+ * import { createPageRankSolver } from './solver-adapter';
15
+ *
16
+ * const solver = createPageRankSolver({ dampingFactor: 0.85 });
17
+ * const scores = solver.computeImportance(graph);
18
+ * const ranked = solver.rankPatterns(graph);
19
+ * ```
20
+ *
21
+ * @module integrations/ruvector/solver-adapter
22
+ */
23
+ // ============================================================================
24
+ // Default Configuration
25
+ // ============================================================================
26
+ const DEFAULT_SOLVER_CONFIG = {
27
+ dampingFactor: 0.85,
28
+ tolerance: 1e-6,
29
+ maxIterations: 100,
30
+ };
31
+ // ============================================================================
32
+ // Native Module Detection
33
+ // ============================================================================
34
+ /**
35
+ * Cached reference to the @ruvector/solver-node native module.
36
+ * `null` means we haven't attempted to load yet; `false` means load failed.
37
+ */
38
+ let _nativeModule = null;
39
+ /**
40
+ * Attempt to load the optional @ruvector/solver-node native bindings.
41
+ * The result is cached so the cost is paid at most once per process.
42
+ */
43
+ function tryLoadNativeSync() {
44
+ if (_nativeModule === false)
45
+ return false;
46
+ if (_nativeModule != null)
47
+ return true;
48
+ try {
49
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
50
+ _nativeModule = require('@ruvector/solver-node');
51
+ return true;
52
+ }
53
+ catch {
54
+ _nativeModule = false;
55
+ return false;
56
+ }
57
+ }
58
+ // ============================================================================
59
+ // Input Validation
60
+ // ============================================================================
61
+ /**
62
+ * Validate a PatternGraph, throwing on invalid structure.
63
+ * Returns the number of nodes (N) for convenience.
64
+ */
65
+ function validateGraph(graph) {
66
+ const n = graph.nodes.length;
67
+ for (const [from, to, weight] of graph.edges) {
68
+ if (from < 0 || from >= n) {
69
+ throw new RangeError(`Edge source index ${from} is out of bounds [0, ${n})`);
70
+ }
71
+ if (to < 0 || to >= n) {
72
+ throw new RangeError(`Edge target index ${to} is out of bounds [0, ${n})`);
73
+ }
74
+ if (!Number.isFinite(weight) || weight < 0) {
75
+ throw new RangeError(`Edge weight must be a non-negative finite number, got ${weight}`);
76
+ }
77
+ }
78
+ return n;
79
+ }
80
+ // ============================================================================
81
+ // TypeScript Power-Iteration PageRank
82
+ // ============================================================================
83
+ /**
84
+ * Compute PageRank scores using the standard power-iteration method.
85
+ *
86
+ * Algorithm (per Wikipedia / original Brin-Page paper):
87
+ * 1. scores[i] = 1 / N for all i
88
+ * 2. For each iteration:
89
+ * new[i] = (1 - d) / N
90
+ * + d * SUM_{j -> i} ( scores[j] * edgeWeight(j,i) / weightedOutDegree[j] )
91
+ * 3. Converge when max |new[i] - old[i]| < tolerance
92
+ *
93
+ * Self-loops are included in outDegree computation but their contribution
94
+ * flows back to the same node (standard PageRank semantics).
95
+ *
96
+ * Dangling nodes (zero out-degree) distribute their score uniformly to all
97
+ * nodes, matching the standard random-surfer model.
98
+ */
99
+ function powerIterationPageRank(graph, config) {
100
+ const n = graph.nodes.length;
101
+ const { dampingFactor: d, tolerance, maxIterations } = config;
102
+ // Pre-compute weighted out-degree for each node
103
+ const weightedOutDegree = new Float64Array(n);
104
+ for (const [from, , weight] of graph.edges) {
105
+ weightedOutDegree[from] += weight;
106
+ }
107
+ // Build adjacency list for incoming edges: inEdges[toIndex] = [[fromIndex, weight], ...]
108
+ const inEdges = new Array(n);
109
+ for (let i = 0; i < n; i++) {
110
+ inEdges[i] = [];
111
+ }
112
+ for (const [from, to, weight] of graph.edges) {
113
+ inEdges[to].push([from, weight]);
114
+ }
115
+ // Identify dangling nodes (no outgoing edges)
116
+ const danglingNodes = [];
117
+ for (let i = 0; i < n; i++) {
118
+ if (weightedOutDegree[i] === 0) {
119
+ danglingNodes.push(i);
120
+ }
121
+ }
122
+ // Initialize scores uniformly
123
+ let scores = new Float64Array(n);
124
+ const uniformShare = 1 / n;
125
+ scores.fill(uniformShare);
126
+ const base = (1 - d) / n;
127
+ for (let iter = 0; iter < maxIterations; iter++) {
128
+ // Dangling node contribution: their total score is redistributed uniformly
129
+ let danglingSum = 0;
130
+ for (const di of danglingNodes) {
131
+ danglingSum += scores[di];
132
+ }
133
+ const danglingContrib = d * danglingSum / n;
134
+ const next = new Float64Array(n);
135
+ for (let i = 0; i < n; i++) {
136
+ let incoming = 0;
137
+ for (const [from, weight] of inEdges[i]) {
138
+ incoming += (scores[from] * weight) / weightedOutDegree[from];
139
+ }
140
+ next[i] = base + d * incoming + danglingContrib;
141
+ }
142
+ // Check convergence (L-infinity norm)
143
+ let maxDelta = 0;
144
+ for (let i = 0; i < n; i++) {
145
+ const delta = Math.abs(next[i] - scores[i]);
146
+ if (delta > maxDelta)
147
+ maxDelta = delta;
148
+ }
149
+ scores = next;
150
+ if (maxDelta < tolerance) {
151
+ break;
152
+ }
153
+ }
154
+ return scores;
155
+ }
156
+ // ============================================================================
157
+ // PageRankSolver Class
158
+ // ============================================================================
159
+ /**
160
+ * Computes importance scores for pattern graphs using PageRank.
161
+ *
162
+ * Prefers the native @ruvector/solver-node NAPI bindings when available
163
+ * (O(log n) via Neumann series). Falls back to a TypeScript power-iteration
164
+ * implementation (O(n * m * iterations)) when the native module is absent.
165
+ */
166
+ export class PageRankSolver {
167
+ config;
168
+ constructor(config) {
169
+ this.config = { ...DEFAULT_SOLVER_CONFIG, ...config };
170
+ // Validate config ranges
171
+ if (this.config.dampingFactor <= 0 || this.config.dampingFactor >= 1) {
172
+ throw new RangeError('dampingFactor must be in (0, 1)');
173
+ }
174
+ if (this.config.tolerance <= 0) {
175
+ throw new RangeError('tolerance must be positive');
176
+ }
177
+ if (this.config.maxIterations < 1) {
178
+ throw new RangeError('maxIterations must be >= 1');
179
+ }
180
+ // Eagerly attempt native load so isNativeAvailable() is stable
181
+ tryLoadNativeSync();
182
+ }
183
+ /**
184
+ * Check whether the native @ruvector/solver-node module is available.
185
+ */
186
+ isNativeAvailable() {
187
+ return tryLoadNativeSync();
188
+ }
189
+ /**
190
+ * Compute importance scores for all nodes in a pattern graph.
191
+ *
192
+ * @param graph - The pattern graph to analyze
193
+ * @returns Map from node ID to its importance score (scores sum to ~1.0)
194
+ */
195
+ computeImportance(graph) {
196
+ const n = validateGraph(graph);
197
+ const result = new Map();
198
+ // Empty graph: nothing to score
199
+ if (n === 0) {
200
+ return result;
201
+ }
202
+ // Single node: trivially 1.0
203
+ if (n === 1) {
204
+ result.set(graph.nodes[0], 1.0);
205
+ return result;
206
+ }
207
+ let scores;
208
+ if (this.isNativeAvailable() && _nativeModule?.pagerank) {
209
+ // Delegate to native solver
210
+ scores = this.computeNative(graph);
211
+ }
212
+ else {
213
+ // TypeScript power iteration fallback
214
+ scores = powerIterationPageRank(graph, this.config);
215
+ }
216
+ for (let i = 0; i < n; i++) {
217
+ result.set(graph.nodes[i], scores[i]);
218
+ }
219
+ return result;
220
+ }
221
+ /**
222
+ * Rank all patterns in the graph by importance, highest first.
223
+ *
224
+ * @param graph - The pattern graph to analyze
225
+ * @returns Array of ImportanceScore sorted by score descending
226
+ */
227
+ rankPatterns(graph) {
228
+ const scores = this.computeImportance(graph);
229
+ const ranked = [];
230
+ for (const [patternId, score] of scores) {
231
+ ranked.push({ patternId, score, rank: 0 });
232
+ }
233
+ // Sort descending by score, stable by patternId for ties
234
+ ranked.sort((a, b) => {
235
+ if (b.score !== a.score)
236
+ return b.score - a.score;
237
+ return a.patternId.localeCompare(b.patternId);
238
+ });
239
+ // Assign ranks (1-based)
240
+ for (let i = 0; i < ranked.length; i++) {
241
+ ranked[i].rank = i + 1;
242
+ }
243
+ return ranked;
244
+ }
245
+ // --------------------------------------------------------------------------
246
+ // Private: native solver delegation
247
+ // --------------------------------------------------------------------------
248
+ /**
249
+ * Delegate PageRank computation to the native @ruvector/solver-node module.
250
+ *
251
+ * The native API is expected to accept the graph in a compatible format
252
+ * and return a Float64Array of scores indexed by node position.
253
+ */
254
+ computeNative(graph) {
255
+ const n = graph.nodes.length;
256
+ // Build edge arrays in the format expected by native solver
257
+ const fromIndices = new Int32Array(graph.edges.length);
258
+ const toIndices = new Int32Array(graph.edges.length);
259
+ const weights = new Float64Array(graph.edges.length);
260
+ for (let i = 0; i < graph.edges.length; i++) {
261
+ fromIndices[i] = graph.edges[i][0];
262
+ toIndices[i] = graph.edges[i][1];
263
+ weights[i] = graph.edges[i][2];
264
+ }
265
+ try {
266
+ const result = _nativeModule.pagerank({
267
+ nodeCount: n,
268
+ fromIndices,
269
+ toIndices,
270
+ weights,
271
+ dampingFactor: this.config.dampingFactor,
272
+ tolerance: this.config.tolerance,
273
+ maxIterations: this.config.maxIterations,
274
+ });
275
+ // Expect Float64Array or plain number[]
276
+ if (result instanceof Float64Array) {
277
+ return result;
278
+ }
279
+ return Float64Array.from(result);
280
+ }
281
+ catch {
282
+ // If native call fails, fall back gracefully to TS implementation
283
+ return powerIterationPageRank(graph, this.config);
284
+ }
285
+ }
286
+ }
287
+ // ============================================================================
288
+ // Factory Function
289
+ // ============================================================================
290
+ /**
291
+ * Create a PageRankSolver instance with the given configuration.
292
+ *
293
+ * @param config - Partial solver configuration (defaults applied)
294
+ * @returns A configured PageRankSolver
295
+ */
296
+ export function createPageRankSolver(config) {
297
+ return new PageRankSolver(config);
298
+ }
299
+ //# sourceMappingURL=solver-adapter.js.map
@@ -184,6 +184,39 @@ export declare class PersistentSONAEngine {
184
184
  * Clear all in-memory patterns (does not affect SQLite)
185
185
  */
186
186
  clearMemory(): void;
187
+ /**
188
+ * Perform instant per-request MicroLoRA adaptation (Loop 1).
189
+ *
190
+ * Delegates to the three-loop engine's instant loop.
191
+ * Returns null if the three-loop engine is not initialized.
192
+ *
193
+ * @param requestFeatures - Feature vector for the current request
194
+ * @returns Adaptation result, or null if three-loop engine not initialized
195
+ */
196
+ instantAdapt(requestFeatures: number[]): import('./sona-three-loop.js').AdaptationResult | null;
197
+ /**
198
+ * Record the outcome of a request for REINFORCE-style gradient estimation (Loop 1b).
199
+ *
200
+ * Must be called after instantAdapt() with the reward signal.
201
+ * Delegates to the three-loop engine's recordOutcome().
202
+ *
203
+ * @param reward - Scalar reward (e.g., 1.0 for success, -1.0 for failure)
204
+ * @param requestIndex - Optional requestIndex from AdaptationResult for matching
205
+ */
206
+ recordOutcome(reward: number, requestIndex?: number): void;
207
+ /**
208
+ * Run background consolidation cycle (Loop 2).
209
+ *
210
+ * Delegates to the three-loop engine's background loop.
211
+ * Returns null if the three-loop engine is not initialized.
212
+ *
213
+ * @returns Consolidation result, or null if three-loop engine not initialized
214
+ */
215
+ backgroundConsolidate(): import('./sona-three-loop.js').ConsolidationResult | null;
216
+ /**
217
+ * Check if the three-loop engine is initialized and active.
218
+ */
219
+ isThreeLoopEnabled(): boolean;
187
220
  /**
188
221
  * Apply Micro-LoRA transformation
189
222
  */
@@ -554,6 +554,53 @@ export class PersistentSONAEngine {
554
554
  this.baseEngine.clear();
555
555
  }
556
556
  // ==========================================================================
557
+ // Three-Loop Engine Pass-Through (instantAdapt -> recordOutcome -> backgroundConsolidate)
558
+ // ==========================================================================
559
+ /**
560
+ * Perform instant per-request MicroLoRA adaptation (Loop 1).
561
+ *
562
+ * Delegates to the three-loop engine's instant loop.
563
+ * Returns null if the three-loop engine is not initialized.
564
+ *
565
+ * @param requestFeatures - Feature vector for the current request
566
+ * @returns Adaptation result, or null if three-loop engine not initialized
567
+ */
568
+ instantAdapt(requestFeatures) {
569
+ this.ensureInitialized();
570
+ return this.baseEngine.instantAdapt(requestFeatures);
571
+ }
572
+ /**
573
+ * Record the outcome of a request for REINFORCE-style gradient estimation (Loop 1b).
574
+ *
575
+ * Must be called after instantAdapt() with the reward signal.
576
+ * Delegates to the three-loop engine's recordOutcome().
577
+ *
578
+ * @param reward - Scalar reward (e.g., 1.0 for success, -1.0 for failure)
579
+ * @param requestIndex - Optional requestIndex from AdaptationResult for matching
580
+ */
581
+ recordOutcome(reward, requestIndex) {
582
+ this.ensureInitialized();
583
+ this.baseEngine.recordOutcome(reward, requestIndex);
584
+ }
585
+ /**
586
+ * Run background consolidation cycle (Loop 2).
587
+ *
588
+ * Delegates to the three-loop engine's background loop.
589
+ * Returns null if the three-loop engine is not initialized.
590
+ *
591
+ * @returns Consolidation result, or null if three-loop engine not initialized
592
+ */
593
+ backgroundConsolidate() {
594
+ this.ensureInitialized();
595
+ return this.baseEngine.backgroundConsolidate();
596
+ }
597
+ /**
598
+ * Check if the three-loop engine is initialized and active.
599
+ */
600
+ isThreeLoopEnabled() {
601
+ return this.baseEngine.isThreeLoopEnabled();
602
+ }
603
+ // ==========================================================================
557
604
  // Learning Operations (Delegates to base engine)
558
605
  // ==========================================================================
559
606
  /**
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Spectral Graph Sparsification (ADR-087, Milestone 3, R9)
3
+ *
4
+ * Spectral graph sparsifier using degree-based leverage score sampling.
5
+ *
6
+ * Compresses weighted undirected graphs while approximately preserving
7
+ * Laplacian spectral properties within a (1 +/- epsilon) factor.
8
+ *
9
+ * Algorithm overview:
10
+ * 1. Approximate leverage scores via degree-based heuristic:
11
+ * leverage(u,v) ≈ w(u,v) * (1/deg_w(u) + 1/deg_w(v)).
12
+ * This is a practical O(m) approximation — NOT true effective
13
+ * resistance (which requires the Laplacian pseudoinverse, O(n^3)).
14
+ * 2. Sample each edge with probability proportional to its leverage
15
+ * score, scaled to a target edge budget.
16
+ * 3. Rescale surviving edge weights by 1/p_e to keep expectations unbiased.
17
+ * 4. Validate by comparing top-k Laplacian eigenvalues of both graphs.
18
+ *
19
+ * Limitations: The degree-based heuristic can misjudge edges between
20
+ * high-degree nodes (retained when redundant) and low-degree bridges
21
+ * (dropped when structurally important). For production use on critical
22
+ * graphs, upgrade to JL-projected effective resistance or spanning-tree
23
+ * sampling when @ruvector/sparsifier-wasm becomes available.
24
+ *
25
+ * The implementation is fully synchronous --- matrix operations are fast
26
+ * enough in TypeScript for graphs up to ~10K nodes.
27
+ *
28
+ * @module integrations/ruvector/spectral-sparsifier
29
+ */
30
+ /**
31
+ * A weighted undirected graph for sparsification.
32
+ * Edges are undirected: (a, b, w) and (b, a, w) are the same edge.
33
+ */
34
+ export interface SparsifierGraph {
35
+ /** Number of nodes (nodes are labelled 0 .. nodeCount-1) */
36
+ nodeCount: number;
37
+ /** Edges as [nodeA, nodeB, weight] triples (undirected) */
38
+ edges: Array<[number, number, number]>;
39
+ }
40
+ /**
41
+ * Result of spectral validation comparing original and sparsified graphs.
42
+ */
43
+ export interface SpectralValidation {
44
+ /** Whether the sparsified graph is within epsilon bounds */
45
+ isValid: boolean;
46
+ /**
47
+ * Ratio of eigenvalues (sparsified / original) for each of the top-k
48
+ * non-trivial eigenvalues. Valid when all ratios lie in [1-eps, 1+eps].
49
+ */
50
+ eigenvalueRatios: number[];
51
+ /** Number of edges in the original graph */
52
+ originalEdgeCount: number;
53
+ /** Number of edges in the sparsified graph */
54
+ sparsifiedEdgeCount: number;
55
+ /** Compression ratio: sparsifiedEdgeCount / originalEdgeCount */
56
+ compressionRatio: number;
57
+ }
58
+ /**
59
+ * Configuration for the spectral sparsifier.
60
+ */
61
+ export interface SparsifierConfig {
62
+ /**
63
+ * Approximation quality parameter. Lower values preserve spectral
64
+ * properties more faithfully but retain more edges.
65
+ * @default 0.3
66
+ */
67
+ epsilon: number;
68
+ /**
69
+ * Optional seed for the internal PRNG. When provided, sparsification
70
+ * results are fully reproducible.
71
+ */
72
+ seed?: number;
73
+ }
74
+ /**
75
+ * Spectral graph sparsifier using degree-based leverage score sampling.
76
+ *
77
+ * Compresses a weighted undirected graph while approximately preserving the
78
+ * spectrum of its Laplacian. Uses a degree-based heuristic for leverage
79
+ * scores (not true effective resistance). The approximation quality is
80
+ * controlled by `epsilon`: eigenvalues of the sparsified Laplacian should
81
+ * lie within a (1 +/- epsilon) factor of the original.
82
+ */
83
+ export declare class SpectralSparsifier {
84
+ private readonly epsilon;
85
+ private readonly seed;
86
+ constructor(config?: Partial<SparsifierConfig>);
87
+ /**
88
+ * Sparsify a graph while preserving spectral properties.
89
+ *
90
+ * @param graph - The input weighted undirected graph
91
+ * @returns A new graph with fewer edges whose Laplacian spectrum
92
+ * approximates the original within (1 +/- epsilon).
93
+ */
94
+ sparsify(graph: SparsifierGraph): SparsifierGraph;
95
+ /**
96
+ * Validate that a sparsified graph preserves the spectral properties of
97
+ * the original. Compares the top-k non-trivial Laplacian eigenvalues.
98
+ *
99
+ * @param original - The original graph
100
+ * @param sparsified - The sparsified graph
101
+ * @returns Validation result including eigenvalue ratios and compression info
102
+ */
103
+ validateSpectral(original: SparsifierGraph, sparsified: SparsifierGraph): SpectralValidation;
104
+ /**
105
+ * Compute the dense graph Laplacian matrix L = D - W.
106
+ *
107
+ * For weighted undirected graphs, L[i][i] = sum of weights of edges
108
+ * incident to i, and L[i][j] = -w(i,j).
109
+ *
110
+ * @param graph - Input graph
111
+ * @returns n x n Laplacian matrix as number[][]
112
+ */
113
+ computeLaplacian(graph: SparsifierGraph): number[][];
114
+ /**
115
+ * Compute the top-k eigenvalues of a symmetric matrix using power
116
+ * iteration with deflation.
117
+ *
118
+ * Eigenvalues are returned in descending order.
119
+ *
120
+ * @param matrix - Symmetric n x n matrix
121
+ * @param k - Number of eigenvalues to compute
122
+ * @returns Array of up to k eigenvalues in descending order
123
+ */
124
+ computeTopEigenvalues(matrix: number[][], k: number): number[];
125
+ /**
126
+ * Approximate effective resistance for every edge using a leverage-score
127
+ * heuristic based on node degrees.
128
+ *
129
+ * For edge (u, v) with weight w:
130
+ * R_eff(u, v) ~= 1/deg_w(u) + 1/deg_w(v)
131
+ *
132
+ * where deg_w(u) is the weighted degree of u.
133
+ * This is a rough but computationally cheap O(m) approximation that
134
+ * captures the intuition that edges between low-degree nodes have higher
135
+ * effective resistance.
136
+ */
137
+ private approximateEffectiveResistances;
138
+ /**
139
+ * Single round of power iteration to find the dominant eigenvalue/vector,
140
+ * deflating away previously found eigenvectors.
141
+ *
142
+ * Uses a deterministic but well-spread initial vector and handles
143
+ * near-zero eigenvalues by checking the matrix's remaining Frobenius norm.
144
+ */
145
+ private powerIteration;
146
+ }
147
+ /**
148
+ * Create a spectral sparsifier with the given configuration.
149
+ *
150
+ * @param config - Optional partial configuration
151
+ * @returns A new SpectralSparsifier instance
152
+ */
153
+ export declare function createSpectralSparsifier(config?: Partial<SparsifierConfig>): SpectralSparsifier;
154
+ //# sourceMappingURL=spectral-sparsifier.d.ts.map