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.
- package/.claude/skills/qe-code-intelligence/SKILL.md +29 -20
- package/.claude/skills/qe-code-intelligence/evals/qe-code-intelligence.yaml +3 -3
- package/.claude/skills/qe-quality-assessment/SKILL.md +1 -1
- package/.claude/skills/qe-test-generation/SKILL.md +1 -1
- package/.claude/skills/skills-manifest.json +1 -1
- package/CHANGELOG.md +45 -0
- package/README.md +9 -0
- package/assets/skills/qe-code-intelligence/SKILL.md +29 -20
- package/assets/skills/qe-code-intelligence/evals/qe-code-intelligence.yaml +3 -3
- package/assets/skills/qe-quality-assessment/SKILL.md +1 -1
- package/assets/skills/qe-test-generation/SKILL.md +1 -1
- package/dist/cli/bundle.js +1162 -1046
- package/dist/cli/commands/code.js +149 -11
- package/dist/cli/commands/init.js +3 -2
- package/dist/cli/commands/ruvector-commands.js +17 -0
- package/dist/cli/handlers/init-handler.d.ts +1 -0
- package/dist/cli/handlers/init-handler.js +15 -10
- package/dist/cli/utils/file-discovery.d.ts +1 -0
- package/dist/cli/utils/file-discovery.js +1 -1
- package/dist/domains/code-intelligence/coordinator-gnn.d.ts +21 -0
- package/dist/domains/code-intelligence/coordinator-gnn.js +102 -0
- package/dist/domains/contract-testing/coordinator.js +13 -0
- package/dist/domains/coverage-analysis/coordinator.js +5 -0
- package/dist/domains/defect-intelligence/coordinator.d.ts +1 -0
- package/dist/domains/defect-intelligence/coordinator.js +43 -0
- package/dist/domains/quality-assessment/coordinator.js +26 -0
- package/dist/domains/test-generation/coordinator.js +14 -0
- package/dist/init/orchestrator.js +1 -0
- package/dist/init/phases/08-mcp.js +4 -4
- package/dist/init/phases/phase-interface.d.ts +3 -1
- package/dist/integrations/agentic-flow/reasoning-bank/experience-replay.d.ts +11 -0
- package/dist/integrations/agentic-flow/reasoning-bank/experience-replay.js +44 -1
- package/dist/integrations/rl-suite/algorithms/eprop.d.ts +79 -0
- package/dist/integrations/rl-suite/algorithms/eprop.js +284 -0
- package/dist/integrations/rl-suite/algorithms/index.d.ts +2 -1
- package/dist/integrations/rl-suite/algorithms/index.js +2 -1
- package/dist/integrations/rl-suite/index.d.ts +2 -2
- package/dist/integrations/rl-suite/index.js +2 -2
- package/dist/integrations/rl-suite/interfaces.d.ts +3 -3
- package/dist/integrations/rl-suite/interfaces.js +1 -1
- package/dist/integrations/rl-suite/orchestrator.d.ts +2 -2
- package/dist/integrations/rl-suite/orchestrator.js +3 -2
- package/dist/integrations/rl-suite/reward-signals.d.ts +1 -1
- package/dist/integrations/rl-suite/reward-signals.js +1 -1
- package/dist/integrations/ruvector/coherence-gate-cohomology.d.ts +41 -0
- package/dist/integrations/ruvector/coherence-gate-cohomology.js +47 -0
- package/dist/integrations/ruvector/coherence-gate-core.d.ts +200 -0
- package/dist/integrations/ruvector/coherence-gate-core.js +294 -0
- package/dist/integrations/ruvector/coherence-gate-energy.d.ts +136 -0
- package/dist/integrations/ruvector/coherence-gate-energy.js +373 -0
- package/dist/integrations/ruvector/coherence-gate-vector.d.ts +38 -0
- package/dist/integrations/ruvector/coherence-gate-vector.js +76 -0
- package/dist/integrations/ruvector/coherence-gate.d.ts +10 -311
- package/dist/integrations/ruvector/coherence-gate.js +10 -652
- package/dist/integrations/ruvector/cold-tier-trainer.d.ts +103 -0
- package/dist/integrations/ruvector/cold-tier-trainer.js +377 -0
- package/dist/integrations/ruvector/cusum-detector.d.ts +70 -0
- package/dist/integrations/ruvector/cusum-detector.js +142 -0
- package/dist/integrations/ruvector/delta-tracker.d.ts +122 -0
- package/dist/integrations/ruvector/delta-tracker.js +311 -0
- package/dist/integrations/ruvector/domain-transfer.d.ts +79 -1
- package/dist/integrations/ruvector/domain-transfer.js +158 -2
- package/dist/integrations/ruvector/eprop-learner.d.ts +135 -0
- package/dist/integrations/ruvector/eprop-learner.js +351 -0
- package/dist/integrations/ruvector/feature-flags.d.ts +177 -0
- package/dist/integrations/ruvector/feature-flags.js +145 -0
- package/dist/integrations/ruvector/graphmae-encoder.d.ts +88 -0
- package/dist/integrations/ruvector/graphmae-encoder.js +360 -0
- package/dist/integrations/ruvector/hdc-fingerprint.d.ts +127 -0
- package/dist/integrations/ruvector/hdc-fingerprint.js +222 -0
- package/dist/integrations/ruvector/hopfield-memory.d.ts +97 -0
- package/dist/integrations/ruvector/hopfield-memory.js +238 -0
- package/dist/integrations/ruvector/index.d.ts +13 -2
- package/dist/integrations/ruvector/index.js +46 -2
- package/dist/integrations/ruvector/mincut-wrapper.d.ts +7 -0
- package/dist/integrations/ruvector/mincut-wrapper.js +54 -2
- package/dist/integrations/ruvector/reservoir-replay.d.ts +172 -0
- package/dist/integrations/ruvector/reservoir-replay.js +335 -0
- package/dist/integrations/ruvector/solver-adapter.d.ts +93 -0
- package/dist/integrations/ruvector/solver-adapter.js +299 -0
- package/dist/integrations/ruvector/sona-persistence.d.ts +33 -0
- package/dist/integrations/ruvector/sona-persistence.js +47 -0
- package/dist/integrations/ruvector/spectral-sparsifier.d.ts +154 -0
- package/dist/integrations/ruvector/spectral-sparsifier.js +389 -0
- package/dist/integrations/ruvector/temporal-causality.d.ts +63 -0
- package/dist/integrations/ruvector/temporal-causality.js +317 -0
- package/dist/learning/pattern-promotion.d.ts +63 -0
- package/dist/learning/pattern-promotion.js +235 -1
- package/dist/learning/pattern-store.d.ts +2 -0
- package/dist/learning/pattern-store.js +187 -1
- package/dist/learning/sqlite-persistence.d.ts +2 -0
- package/dist/learning/sqlite-persistence.js +4 -0
- package/dist/mcp/bundle.js +506 -427
- package/dist/shared/utils/index.d.ts +1 -0
- package/dist/shared/utils/index.js +1 -0
- package/dist/shared/utils/xorshift128.d.ts +24 -0
- package/dist/shared/utils/xorshift128.js +50 -0
- 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
|