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,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* R1: Hyperdimensional Computing Pattern Fingerprinting
|
|
3
|
+
*
|
|
4
|
+
* 10,000-bit binary hypervectors with XOR binding for O(1) compositional
|
|
5
|
+
* pattern fingerprinting. TypeScript fallback implementation.
|
|
6
|
+
*
|
|
7
|
+
* When WASM is available (@ruvector/hdc-wasm), delegates to native SIMD-optimized ops.
|
|
8
|
+
* Without WASM, uses TypeScript Uint8Array bit operations.
|
|
9
|
+
*
|
|
10
|
+
* Key properties:
|
|
11
|
+
* - Deterministic: same input always produces the same fingerprint
|
|
12
|
+
* - Compositional: XOR binding combines multiple concepts into a single vector
|
|
13
|
+
* - Associative: bind(A, bind(B, C)) === bind(bind(A, B), C)
|
|
14
|
+
* - Distance-preserving: Hamming distance ≈ dimensions/2 for unrelated patterns
|
|
15
|
+
*
|
|
16
|
+
* @module integrations/ruvector/hdc-fingerprint
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Configuration for the HDC fingerprinter
|
|
20
|
+
*/
|
|
21
|
+
export interface HdcConfig {
|
|
22
|
+
/** Number of bits in each hypervector. Default: 10000 */
|
|
23
|
+
dimensions: number;
|
|
24
|
+
/** Seed for deterministic fingerprint generation */
|
|
25
|
+
seed?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A pattern fingerprint represented as a packed binary hypervector
|
|
29
|
+
*/
|
|
30
|
+
export interface PatternFingerprint {
|
|
31
|
+
/** Packed bits: dimensions/8 bytes (1250 bytes for 10K dimensions) */
|
|
32
|
+
vector: Uint8Array;
|
|
33
|
+
/** Number of bits (dimensions) in the hypervector */
|
|
34
|
+
dimensions: number;
|
|
35
|
+
/** Hex hash for quick equality check */
|
|
36
|
+
hash: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Input data for fingerprinting a pattern
|
|
40
|
+
*/
|
|
41
|
+
export interface PatternInput {
|
|
42
|
+
id: string;
|
|
43
|
+
domain: string;
|
|
44
|
+
type: string;
|
|
45
|
+
content?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Hyperdimensional Computing fingerprinter for QE patterns.
|
|
49
|
+
*
|
|
50
|
+
* Generates deterministic binary hypervectors from pattern metadata,
|
|
51
|
+
* supports XOR-based compositional binding, and provides Hamming
|
|
52
|
+
* distance / similarity metrics.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const hdc = new HdcFingerprinter();
|
|
57
|
+
* const fp = hdc.fingerprint({ id: 'p1', domain: 'security', type: 'xss' });
|
|
58
|
+
* console.log(fp.dimensions); // 10000
|
|
59
|
+
* console.log(fp.vector.length); // 1250
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare class HdcFingerprinter {
|
|
63
|
+
private readonly dimensions;
|
|
64
|
+
private readonly baseSeed;
|
|
65
|
+
constructor(config?: Partial<HdcConfig>);
|
|
66
|
+
/**
|
|
67
|
+
* Generate a deterministic fingerprint from pattern data.
|
|
68
|
+
*
|
|
69
|
+
* The fingerprint is seeded from a composite key of id + domain + type
|
|
70
|
+
* (and optionally content), ensuring identical inputs always produce
|
|
71
|
+
* identical outputs.
|
|
72
|
+
*/
|
|
73
|
+
fingerprint(pattern: PatternInput): PatternFingerprint;
|
|
74
|
+
/**
|
|
75
|
+
* XOR-based compositional binding.
|
|
76
|
+
*
|
|
77
|
+
* Combines two hypervectors into a single vector representing their
|
|
78
|
+
* conjunction. XOR binding is:
|
|
79
|
+
* - Associative: bind(A, bind(B, C)) === bind(bind(A, B), C)
|
|
80
|
+
* - Commutative: bind(A, B) === bind(B, A)
|
|
81
|
+
* - Self-inverse: bind(A, A) === zero vector
|
|
82
|
+
*
|
|
83
|
+
* @param a First packed-bit vector
|
|
84
|
+
* @param b Second packed-bit vector
|
|
85
|
+
* @returns XOR of a and b (same length)
|
|
86
|
+
* @throws If vectors have different lengths
|
|
87
|
+
*/
|
|
88
|
+
compositionalBind(a: Uint8Array, b: Uint8Array): Uint8Array;
|
|
89
|
+
/**
|
|
90
|
+
* Hamming distance between two packed-bit vectors.
|
|
91
|
+
*
|
|
92
|
+
* Counts the number of differing bits. For unrelated (random) vectors
|
|
93
|
+
* the expected distance is approximately dimensions / 2.
|
|
94
|
+
*
|
|
95
|
+
* @returns Number of differing bits (0 = identical, ~dimensions/2 = random)
|
|
96
|
+
* @throws If vectors have different lengths
|
|
97
|
+
*/
|
|
98
|
+
hammingDistance(a: Uint8Array, b: Uint8Array): number;
|
|
99
|
+
/**
|
|
100
|
+
* Normalized similarity between two packed-bit vectors.
|
|
101
|
+
*
|
|
102
|
+
* @returns Value in [0, 1] where 1.0 = identical, 0.5 = random, 0.0 = opposite
|
|
103
|
+
*/
|
|
104
|
+
similarity(a: Uint8Array, b: Uint8Array): number;
|
|
105
|
+
/**
|
|
106
|
+
* Batch fingerprint multiple patterns.
|
|
107
|
+
* Results match calling fingerprint() individually on each pattern.
|
|
108
|
+
*/
|
|
109
|
+
batchFingerprint(patterns: PatternInput[]): PatternFingerprint[];
|
|
110
|
+
/**
|
|
111
|
+
* Generate a packed-bit vector from a seed using xorshift128 PRNG.
|
|
112
|
+
* Each bit is set with 50% probability, producing approximately
|
|
113
|
+
* dimensions/2 set bits on average.
|
|
114
|
+
*/
|
|
115
|
+
private generateVector;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Create an HdcFingerprinter with the given configuration.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* const hdc = createHdcFingerprinter({ dimensions: 10000 });
|
|
123
|
+
* const fp = hdc.fingerprint({ id: 'p1', domain: 'api', type: 'flaky' });
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export declare function createHdcFingerprinter(config?: Partial<HdcConfig>): HdcFingerprinter;
|
|
127
|
+
//# sourceMappingURL=hdc-fingerprint.d.ts.map
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* R1: Hyperdimensional Computing Pattern Fingerprinting
|
|
3
|
+
*
|
|
4
|
+
* 10,000-bit binary hypervectors with XOR binding for O(1) compositional
|
|
5
|
+
* pattern fingerprinting. TypeScript fallback implementation.
|
|
6
|
+
*
|
|
7
|
+
* When WASM is available (@ruvector/hdc-wasm), delegates to native SIMD-optimized ops.
|
|
8
|
+
* Without WASM, uses TypeScript Uint8Array bit operations.
|
|
9
|
+
*
|
|
10
|
+
* Key properties:
|
|
11
|
+
* - Deterministic: same input always produces the same fingerprint
|
|
12
|
+
* - Compositional: XOR binding combines multiple concepts into a single vector
|
|
13
|
+
* - Associative: bind(A, bind(B, C)) === bind(bind(A, B), C)
|
|
14
|
+
* - Distance-preserving: Hamming distance ≈ dimensions/2 for unrelated patterns
|
|
15
|
+
*
|
|
16
|
+
* @module integrations/ruvector/hdc-fingerprint
|
|
17
|
+
*/
|
|
18
|
+
import { Xorshift128 } from '../../shared/utils/xorshift128.js';
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Constants
|
|
21
|
+
// ============================================================================
|
|
22
|
+
const DEFAULT_DIMENSIONS = 10000;
|
|
23
|
+
const DEFAULT_SEED = 0x811c9dc5; // FNV-1a offset basis
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// Internal: FNV-1a Hash
|
|
26
|
+
// ============================================================================
|
|
27
|
+
/**
|
|
28
|
+
* FNV-1a 32-bit hash for deterministic seeding.
|
|
29
|
+
* Produces well-distributed values from arbitrary string input.
|
|
30
|
+
*/
|
|
31
|
+
function fnv1a(input) {
|
|
32
|
+
let hash = 0x811c9dc5; // FNV offset basis
|
|
33
|
+
for (let i = 0; i < input.length; i++) {
|
|
34
|
+
hash ^= input.charCodeAt(i);
|
|
35
|
+
hash = Math.imul(hash, 0x01000193); // FNV prime
|
|
36
|
+
}
|
|
37
|
+
return hash >>> 0; // Ensure unsigned 32-bit
|
|
38
|
+
}
|
|
39
|
+
// ============================================================================
|
|
40
|
+
// Internal: Popcount
|
|
41
|
+
// ============================================================================
|
|
42
|
+
/** Lookup table for popcount of a single byte (0-255) */
|
|
43
|
+
const POPCOUNT_TABLE = new Uint8Array(256);
|
|
44
|
+
for (let i = 0; i < 256; i++) {
|
|
45
|
+
let count = 0;
|
|
46
|
+
let n = i;
|
|
47
|
+
while (n) {
|
|
48
|
+
count++;
|
|
49
|
+
n &= n - 1; // Brian Kernighan's bit trick
|
|
50
|
+
}
|
|
51
|
+
POPCOUNT_TABLE[i] = count;
|
|
52
|
+
}
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// Internal: Hex encoding
|
|
55
|
+
// ============================================================================
|
|
56
|
+
const HEX_CHARS = '0123456789abcdef';
|
|
57
|
+
/**
|
|
58
|
+
* Produce a hex string from the first 16 bytes of a Uint8Array
|
|
59
|
+
* (32-char hex digest, sufficient for quick equality checks).
|
|
60
|
+
*/
|
|
61
|
+
function hexDigest(bytes) {
|
|
62
|
+
const len = Math.min(bytes.length, 16);
|
|
63
|
+
let hex = '';
|
|
64
|
+
for (let i = 0; i < len; i++) {
|
|
65
|
+
const b = bytes[i];
|
|
66
|
+
hex += HEX_CHARS[b >> 4] + HEX_CHARS[b & 0x0f];
|
|
67
|
+
}
|
|
68
|
+
return hex;
|
|
69
|
+
}
|
|
70
|
+
// ============================================================================
|
|
71
|
+
// HdcFingerprinter
|
|
72
|
+
// ============================================================================
|
|
73
|
+
/**
|
|
74
|
+
* Hyperdimensional Computing fingerprinter for QE patterns.
|
|
75
|
+
*
|
|
76
|
+
* Generates deterministic binary hypervectors from pattern metadata,
|
|
77
|
+
* supports XOR-based compositional binding, and provides Hamming
|
|
78
|
+
* distance / similarity metrics.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const hdc = new HdcFingerprinter();
|
|
83
|
+
* const fp = hdc.fingerprint({ id: 'p1', domain: 'security', type: 'xss' });
|
|
84
|
+
* console.log(fp.dimensions); // 10000
|
|
85
|
+
* console.log(fp.vector.length); // 1250
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export class HdcFingerprinter {
|
|
89
|
+
dimensions;
|
|
90
|
+
baseSeed;
|
|
91
|
+
constructor(config) {
|
|
92
|
+
this.dimensions = config?.dimensions ?? DEFAULT_DIMENSIONS;
|
|
93
|
+
this.baseSeed = config?.seed ?? DEFAULT_SEED;
|
|
94
|
+
if (this.dimensions <= 0) {
|
|
95
|
+
throw new Error(`HDC dimensions must be positive, got ${this.dimensions}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// --------------------------------------------------------------------------
|
|
99
|
+
// Public API
|
|
100
|
+
// --------------------------------------------------------------------------
|
|
101
|
+
/**
|
|
102
|
+
* Generate a deterministic fingerprint from pattern data.
|
|
103
|
+
*
|
|
104
|
+
* The fingerprint is seeded from a composite key of id + domain + type
|
|
105
|
+
* (and optionally content), ensuring identical inputs always produce
|
|
106
|
+
* identical outputs.
|
|
107
|
+
*/
|
|
108
|
+
fingerprint(pattern) {
|
|
109
|
+
const seedStr = `${pattern.id}|${pattern.domain}|${pattern.type}|${pattern.content ?? ''}`;
|
|
110
|
+
const seed = fnv1a(seedStr) ^ this.baseSeed;
|
|
111
|
+
const vector = this.generateVector(seed);
|
|
112
|
+
return {
|
|
113
|
+
vector,
|
|
114
|
+
dimensions: this.dimensions,
|
|
115
|
+
hash: hexDigest(vector),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* XOR-based compositional binding.
|
|
120
|
+
*
|
|
121
|
+
* Combines two hypervectors into a single vector representing their
|
|
122
|
+
* conjunction. XOR binding is:
|
|
123
|
+
* - Associative: bind(A, bind(B, C)) === bind(bind(A, B), C)
|
|
124
|
+
* - Commutative: bind(A, B) === bind(B, A)
|
|
125
|
+
* - Self-inverse: bind(A, A) === zero vector
|
|
126
|
+
*
|
|
127
|
+
* @param a First packed-bit vector
|
|
128
|
+
* @param b Second packed-bit vector
|
|
129
|
+
* @returns XOR of a and b (same length)
|
|
130
|
+
* @throws If vectors have different lengths
|
|
131
|
+
*/
|
|
132
|
+
compositionalBind(a, b) {
|
|
133
|
+
if (a.length !== b.length) {
|
|
134
|
+
throw new Error(`Cannot bind vectors of different lengths: ${a.length} vs ${b.length}`);
|
|
135
|
+
}
|
|
136
|
+
const result = new Uint8Array(a.length);
|
|
137
|
+
for (let i = 0; i < a.length; i++) {
|
|
138
|
+
result[i] = a[i] ^ b[i];
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Hamming distance between two packed-bit vectors.
|
|
144
|
+
*
|
|
145
|
+
* Counts the number of differing bits. For unrelated (random) vectors
|
|
146
|
+
* the expected distance is approximately dimensions / 2.
|
|
147
|
+
*
|
|
148
|
+
* @returns Number of differing bits (0 = identical, ~dimensions/2 = random)
|
|
149
|
+
* @throws If vectors have different lengths
|
|
150
|
+
*/
|
|
151
|
+
hammingDistance(a, b) {
|
|
152
|
+
if (a.length !== b.length) {
|
|
153
|
+
throw new Error(`Cannot compute Hamming distance for vectors of different lengths: ${a.length} vs ${b.length}`);
|
|
154
|
+
}
|
|
155
|
+
let distance = 0;
|
|
156
|
+
for (let i = 0; i < a.length; i++) {
|
|
157
|
+
distance += POPCOUNT_TABLE[a[i] ^ b[i]];
|
|
158
|
+
}
|
|
159
|
+
return distance;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Normalized similarity between two packed-bit vectors.
|
|
163
|
+
*
|
|
164
|
+
* @returns Value in [0, 1] where 1.0 = identical, 0.5 = random, 0.0 = opposite
|
|
165
|
+
*/
|
|
166
|
+
similarity(a, b) {
|
|
167
|
+
const dist = this.hammingDistance(a, b);
|
|
168
|
+
return 1 - dist / this.dimensions;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Batch fingerprint multiple patterns.
|
|
172
|
+
* Results match calling fingerprint() individually on each pattern.
|
|
173
|
+
*/
|
|
174
|
+
batchFingerprint(patterns) {
|
|
175
|
+
return patterns.map((p) => this.fingerprint(p));
|
|
176
|
+
}
|
|
177
|
+
// --------------------------------------------------------------------------
|
|
178
|
+
// Internal
|
|
179
|
+
// --------------------------------------------------------------------------
|
|
180
|
+
/**
|
|
181
|
+
* Generate a packed-bit vector from a seed using xorshift128 PRNG.
|
|
182
|
+
* Each bit is set with 50% probability, producing approximately
|
|
183
|
+
* dimensions/2 set bits on average.
|
|
184
|
+
*/
|
|
185
|
+
generateVector(seed) {
|
|
186
|
+
const byteLen = Math.ceil(this.dimensions / 8);
|
|
187
|
+
const vector = new Uint8Array(byteLen);
|
|
188
|
+
const rng = new Xorshift128(seed);
|
|
189
|
+
// Fill 4 bytes at a time from each 32-bit random value
|
|
190
|
+
let byteIdx = 0;
|
|
191
|
+
while (byteIdx < byteLen) {
|
|
192
|
+
const rand = rng.next();
|
|
193
|
+
const remaining = byteLen - byteIdx;
|
|
194
|
+
const count = remaining < 4 ? remaining : 4;
|
|
195
|
+
for (let j = 0; j < count; j++) {
|
|
196
|
+
vector[byteIdx++] = (rand >>> (j * 8)) & 0xff;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// Mask unused trailing bits in the last byte
|
|
200
|
+
const trailingBits = this.dimensions % 8;
|
|
201
|
+
if (trailingBits > 0) {
|
|
202
|
+
vector[byteLen - 1] &= (1 << trailingBits) - 1;
|
|
203
|
+
}
|
|
204
|
+
return vector;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// ============================================================================
|
|
208
|
+
// Factory Functions
|
|
209
|
+
// ============================================================================
|
|
210
|
+
/**
|
|
211
|
+
* Create an HdcFingerprinter with the given configuration.
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* ```typescript
|
|
215
|
+
* const hdc = createHdcFingerprinter({ dimensions: 10000 });
|
|
216
|
+
* const fp = hdc.fingerprint({ id: 'p1', domain: 'api', type: 'flaky' });
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
export function createHdcFingerprinter(config) {
|
|
220
|
+
return new HdcFingerprinter(config);
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=hdc-fingerprint.js.map
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* R5: Modern Hopfield Networks — Associative Pattern Memory
|
|
3
|
+
*
|
|
4
|
+
* Exponential-capacity content-addressable memory for exact pattern recall.
|
|
5
|
+
* Complements HNSW approximate nearest neighbor with exact retrieval:
|
|
6
|
+
* - HNSW: "What patterns are similar?" (approximate)
|
|
7
|
+
* - Hopfield: "Did we see exactly this pattern before?" (exact)
|
|
8
|
+
*
|
|
9
|
+
* Based on Ramsauer et al. 2020 "Hopfield Networks is All You Need".
|
|
10
|
+
* TypeScript implementation; WASM upgrade path via @ruvector/hopfield-wasm.
|
|
11
|
+
*
|
|
12
|
+
* @module integrations/ruvector/hopfield-memory
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Configuration for the Hopfield associative memory
|
|
16
|
+
*/
|
|
17
|
+
export interface HopfieldConfig {
|
|
18
|
+
/** Pattern dimension. Default: 128 */
|
|
19
|
+
dimension: number;
|
|
20
|
+
/** Inverse temperature beta controlling sharpness of retrieval. Higher = more exact. Default: 8.0 */
|
|
21
|
+
beta: number;
|
|
22
|
+
/** Maximum number of stored patterns. Default: 10000 */
|
|
23
|
+
maxPatterns: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A pattern stored in Hopfield memory with associated metadata
|
|
27
|
+
*/
|
|
28
|
+
export interface StoredPattern {
|
|
29
|
+
/** The pattern vector */
|
|
30
|
+
pattern: Float32Array;
|
|
31
|
+
/** Associated metadata */
|
|
32
|
+
metadata: Record<string, unknown>;
|
|
33
|
+
/** Timestamp of storage */
|
|
34
|
+
storedAt: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Result of a Hopfield recall operation
|
|
38
|
+
*/
|
|
39
|
+
export interface RecallResult {
|
|
40
|
+
/** Retrieved pattern (closest stored pattern) */
|
|
41
|
+
pattern: Float32Array;
|
|
42
|
+
/** Metadata associated with the retrieved pattern */
|
|
43
|
+
metadata: Record<string, unknown>;
|
|
44
|
+
/** Hopfield energy of the retrieval (lower = more confident) */
|
|
45
|
+
energy: number;
|
|
46
|
+
/** Cosine similarity between query and retrieved pattern */
|
|
47
|
+
similarity: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Modern Hopfield Network for associative pattern memory.
|
|
51
|
+
*
|
|
52
|
+
* Update rule: new_state = X * softmax(beta * X^T * query).
|
|
53
|
+
* High beta (default 8.0) makes softmax approach argmax for exact recall.
|
|
54
|
+
*/
|
|
55
|
+
export declare class HopfieldMemory {
|
|
56
|
+
private readonly dimension;
|
|
57
|
+
private readonly beta;
|
|
58
|
+
private readonly maxPatterns;
|
|
59
|
+
private readonly patterns;
|
|
60
|
+
constructor(config?: Partial<HopfieldConfig>);
|
|
61
|
+
/** Store a pattern. L2-normalizes, validates dimension; evicts oldest if at capacity. */
|
|
62
|
+
store(pattern: Float32Array, metadata?: Record<string, unknown>): void;
|
|
63
|
+
/**
|
|
64
|
+
* Recall the closest stored pattern via softmax(beta * X^T * query).
|
|
65
|
+
* Returns null if empty.
|
|
66
|
+
*
|
|
67
|
+
* Note: With normalized patterns and beta=8, softmax strongly concentrates
|
|
68
|
+
* on the nearest pattern (argmax), making this equivalent to a single
|
|
69
|
+
* Hopfield fixed-point iteration that converges immediately (Ramsauer 2020,
|
|
70
|
+
* Theorem 3). Full iterative convergence is unnecessary at high beta.
|
|
71
|
+
*/
|
|
72
|
+
recall(query: Float32Array): RecallResult | null;
|
|
73
|
+
/** Recall multiple queries in batch. */
|
|
74
|
+
batchRecall(queries: Float32Array[]): (RecallResult | null)[];
|
|
75
|
+
/** Get the number of stored patterns. */
|
|
76
|
+
getPatternCount(): number;
|
|
77
|
+
/** Remove all stored patterns. */
|
|
78
|
+
clear(): void;
|
|
79
|
+
/**
|
|
80
|
+
* Hopfield energy: E = -lse(beta, X^T * state) + 0.5 * ||state||^2.
|
|
81
|
+
* Lower energy = closer to a stored pattern. State is L2-normalized first.
|
|
82
|
+
*/
|
|
83
|
+
getEnergy(state: Float32Array): number;
|
|
84
|
+
/** Numerically stable softmax: subtract max before exp to avoid overflow. */
|
|
85
|
+
private softmax;
|
|
86
|
+
/** Dot product of two Float32Arrays. */
|
|
87
|
+
private dotProduct;
|
|
88
|
+
/** Cosine similarity in [-1, 1]. */
|
|
89
|
+
private cosineSimilarity;
|
|
90
|
+
/** L2 normalization. Returns unit-length copy (or zero vector if input is zero). */
|
|
91
|
+
private normalize;
|
|
92
|
+
/** Assert that the useHopfieldMemory feature flag is enabled. */
|
|
93
|
+
private assertEnabled;
|
|
94
|
+
}
|
|
95
|
+
/** Create a HopfieldMemory with the given configuration. */
|
|
96
|
+
export declare function createHopfieldMemory(config?: Partial<HopfieldConfig>): HopfieldMemory;
|
|
97
|
+
//# sourceMappingURL=hopfield-memory.d.ts.map
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* R5: Modern Hopfield Networks — Associative Pattern Memory
|
|
3
|
+
*
|
|
4
|
+
* Exponential-capacity content-addressable memory for exact pattern recall.
|
|
5
|
+
* Complements HNSW approximate nearest neighbor with exact retrieval:
|
|
6
|
+
* - HNSW: "What patterns are similar?" (approximate)
|
|
7
|
+
* - Hopfield: "Did we see exactly this pattern before?" (exact)
|
|
8
|
+
*
|
|
9
|
+
* Based on Ramsauer et al. 2020 "Hopfield Networks is All You Need".
|
|
10
|
+
* TypeScript implementation; WASM upgrade path via @ruvector/hopfield-wasm.
|
|
11
|
+
*
|
|
12
|
+
* @module integrations/ruvector/hopfield-memory
|
|
13
|
+
*/
|
|
14
|
+
import { getRuVectorFeatureFlags } from './feature-flags.js';
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Constants
|
|
17
|
+
// ============================================================================
|
|
18
|
+
const DEFAULT_DIMENSION = 128;
|
|
19
|
+
const DEFAULT_BETA = 8.0;
|
|
20
|
+
const DEFAULT_MAX_PATTERNS = 10000;
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// HopfieldMemory
|
|
23
|
+
// ============================================================================
|
|
24
|
+
/**
|
|
25
|
+
* Modern Hopfield Network for associative pattern memory.
|
|
26
|
+
*
|
|
27
|
+
* Update rule: new_state = X * softmax(beta * X^T * query).
|
|
28
|
+
* High beta (default 8.0) makes softmax approach argmax for exact recall.
|
|
29
|
+
*/
|
|
30
|
+
export class HopfieldMemory {
|
|
31
|
+
dimension;
|
|
32
|
+
beta;
|
|
33
|
+
maxPatterns;
|
|
34
|
+
patterns;
|
|
35
|
+
constructor(config) {
|
|
36
|
+
this.dimension = config?.dimension ?? DEFAULT_DIMENSION;
|
|
37
|
+
this.beta = config?.beta ?? DEFAULT_BETA;
|
|
38
|
+
this.maxPatterns = config?.maxPatterns ?? DEFAULT_MAX_PATTERNS;
|
|
39
|
+
this.patterns = [];
|
|
40
|
+
if (this.dimension <= 0) {
|
|
41
|
+
throw new Error(`Hopfield dimension must be positive, got ${this.dimension}`);
|
|
42
|
+
}
|
|
43
|
+
if (this.beta <= 0) {
|
|
44
|
+
throw new Error(`Hopfield beta must be positive, got ${this.beta}`);
|
|
45
|
+
}
|
|
46
|
+
if (this.maxPatterns <= 0) {
|
|
47
|
+
throw new Error(`Hopfield maxPatterns must be positive, got ${this.maxPatterns}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// --------------------------------------------------------------------------
|
|
51
|
+
// Public API
|
|
52
|
+
// --------------------------------------------------------------------------
|
|
53
|
+
/** Store a pattern. L2-normalizes, validates dimension; evicts oldest if at capacity. */
|
|
54
|
+
store(pattern, metadata) {
|
|
55
|
+
this.assertEnabled();
|
|
56
|
+
if (pattern.length !== this.dimension) {
|
|
57
|
+
throw new Error(`Pattern dimension mismatch: expected ${this.dimension}, got ${pattern.length}`);
|
|
58
|
+
}
|
|
59
|
+
// Reject zero-magnitude vectors (would be unretrievable after normalization)
|
|
60
|
+
const mag = this.dotProduct(pattern, pattern);
|
|
61
|
+
if (mag === 0) {
|
|
62
|
+
throw new Error('Cannot store zero-magnitude pattern in Hopfield memory');
|
|
63
|
+
}
|
|
64
|
+
// L2-normalize for consistent softmax attention weights
|
|
65
|
+
const normalized = this.normalize(pattern);
|
|
66
|
+
// Evict oldest if at capacity
|
|
67
|
+
if (this.patterns.length >= this.maxPatterns) {
|
|
68
|
+
this.patterns.shift();
|
|
69
|
+
}
|
|
70
|
+
this.patterns.push({
|
|
71
|
+
pattern: normalized,
|
|
72
|
+
metadata: metadata ?? {},
|
|
73
|
+
storedAt: Date.now(),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Recall the closest stored pattern via softmax(beta * X^T * query).
|
|
78
|
+
* Returns null if empty.
|
|
79
|
+
*
|
|
80
|
+
* Note: With normalized patterns and beta=8, softmax strongly concentrates
|
|
81
|
+
* on the nearest pattern (argmax), making this equivalent to a single
|
|
82
|
+
* Hopfield fixed-point iteration that converges immediately (Ramsauer 2020,
|
|
83
|
+
* Theorem 3). Full iterative convergence is unnecessary at high beta.
|
|
84
|
+
*/
|
|
85
|
+
recall(query) {
|
|
86
|
+
this.assertEnabled();
|
|
87
|
+
if (query.length !== this.dimension) {
|
|
88
|
+
throw new Error(`Query dimension mismatch: expected ${this.dimension}, got ${query.length}`);
|
|
89
|
+
}
|
|
90
|
+
if (this.patterns.length === 0) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
// L2-normalize query for magnitude-invariant comparison
|
|
94
|
+
const normalizedQuery = this.normalize(query);
|
|
95
|
+
// Compute logits: beta * X^T * normalizedQuery
|
|
96
|
+
const logits = new Float32Array(this.patterns.length);
|
|
97
|
+
for (let i = 0; i < this.patterns.length; i++) {
|
|
98
|
+
logits[i] = this.beta * this.dotProduct(this.patterns[i].pattern, normalizedQuery);
|
|
99
|
+
}
|
|
100
|
+
// Softmax to get attention weights
|
|
101
|
+
const weights = this.softmax(logits);
|
|
102
|
+
// Find the pattern with the highest attention weight
|
|
103
|
+
let bestIdx = 0;
|
|
104
|
+
let bestWeight = weights[0];
|
|
105
|
+
for (let i = 1; i < weights.length; i++) {
|
|
106
|
+
if (weights[i] > bestWeight) {
|
|
107
|
+
bestWeight = weights[i];
|
|
108
|
+
bestIdx = i;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const matched = this.patterns[bestIdx];
|
|
112
|
+
const energy = this.getEnergy(normalizedQuery);
|
|
113
|
+
const similarity = this.cosineSimilarity(normalizedQuery, matched.pattern);
|
|
114
|
+
return {
|
|
115
|
+
pattern: new Float32Array(matched.pattern),
|
|
116
|
+
metadata: { ...matched.metadata },
|
|
117
|
+
energy,
|
|
118
|
+
similarity,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/** Recall multiple queries in batch. */
|
|
122
|
+
batchRecall(queries) {
|
|
123
|
+
this.assertEnabled();
|
|
124
|
+
return queries.map((q) => this.recall(q));
|
|
125
|
+
}
|
|
126
|
+
/** Get the number of stored patterns. */
|
|
127
|
+
getPatternCount() {
|
|
128
|
+
return this.patterns.length;
|
|
129
|
+
}
|
|
130
|
+
/** Remove all stored patterns. */
|
|
131
|
+
clear() {
|
|
132
|
+
this.patterns.length = 0;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Hopfield energy: E = -lse(beta, X^T * state) + 0.5 * ||state||^2.
|
|
136
|
+
* Lower energy = closer to a stored pattern. State is L2-normalized first.
|
|
137
|
+
*/
|
|
138
|
+
getEnergy(state) {
|
|
139
|
+
if (state.length !== this.dimension) {
|
|
140
|
+
throw new Error(`State dimension mismatch: expected ${this.dimension}, got ${state.length}`);
|
|
141
|
+
}
|
|
142
|
+
// L2-normalize state for consistent energy computation
|
|
143
|
+
const normalizedState = this.normalize(state);
|
|
144
|
+
if (this.patterns.length === 0) {
|
|
145
|
+
// Only the quadratic term remains; normalized state has ||s||^2 = 1
|
|
146
|
+
return 0.5 * this.dotProduct(normalizedState, normalizedState);
|
|
147
|
+
}
|
|
148
|
+
// Compute z_i = X^T * normalizedState (dot products with each stored pattern)
|
|
149
|
+
const z = new Float32Array(this.patterns.length);
|
|
150
|
+
for (let i = 0; i < this.patterns.length; i++) {
|
|
151
|
+
z[i] = this.dotProduct(this.patterns[i].pattern, normalizedState);
|
|
152
|
+
}
|
|
153
|
+
// Numerically stable lse: (1/beta) * (max + log(sum(exp(beta*z_i - max))))
|
|
154
|
+
const scaledZ = new Float32Array(this.patterns.length);
|
|
155
|
+
let maxVal = -Infinity;
|
|
156
|
+
for (let i = 0; i < this.patterns.length; i++) {
|
|
157
|
+
scaledZ[i] = this.beta * z[i];
|
|
158
|
+
if (scaledZ[i] > maxVal)
|
|
159
|
+
maxVal = scaledZ[i];
|
|
160
|
+
}
|
|
161
|
+
let sumExp = 0;
|
|
162
|
+
for (let i = 0; i < this.patterns.length; i++) {
|
|
163
|
+
sumExp += Math.exp(scaledZ[i] - maxVal);
|
|
164
|
+
}
|
|
165
|
+
const lse = (1 / this.beta) * (maxVal + Math.log(sumExp));
|
|
166
|
+
// E = -lse + 0.5 * ||normalizedState||^2
|
|
167
|
+
const normSq = this.dotProduct(normalizedState, normalizedState);
|
|
168
|
+
return -lse + 0.5 * normSq;
|
|
169
|
+
}
|
|
170
|
+
// --------------------------------------------------------------------------
|
|
171
|
+
// Internal Helpers
|
|
172
|
+
// --------------------------------------------------------------------------
|
|
173
|
+
/** Numerically stable softmax: subtract max before exp to avoid overflow. */
|
|
174
|
+
softmax(logits) {
|
|
175
|
+
const result = new Float32Array(logits.length);
|
|
176
|
+
// Find max for numerical stability
|
|
177
|
+
let maxVal = -Infinity;
|
|
178
|
+
for (let i = 0; i < logits.length; i++) {
|
|
179
|
+
if (logits[i] > maxVal)
|
|
180
|
+
maxVal = logits[i];
|
|
181
|
+
}
|
|
182
|
+
// Compute exp(x - max) and sum
|
|
183
|
+
let sum = 0;
|
|
184
|
+
for (let i = 0; i < logits.length; i++) {
|
|
185
|
+
result[i] = Math.exp(logits[i] - maxVal);
|
|
186
|
+
sum += result[i];
|
|
187
|
+
}
|
|
188
|
+
// Normalize
|
|
189
|
+
if (sum > 0) {
|
|
190
|
+
for (let i = 0; i < result.length; i++) {
|
|
191
|
+
result[i] /= sum;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return result;
|
|
195
|
+
}
|
|
196
|
+
/** Dot product of two Float32Arrays. */
|
|
197
|
+
dotProduct(a, b) {
|
|
198
|
+
let sum = 0;
|
|
199
|
+
for (let i = 0; i < a.length; i++) {
|
|
200
|
+
sum += a[i] * b[i];
|
|
201
|
+
}
|
|
202
|
+
return sum;
|
|
203
|
+
}
|
|
204
|
+
/** Cosine similarity in [-1, 1]. */
|
|
205
|
+
cosineSimilarity(a, b) {
|
|
206
|
+
const dot = this.dotProduct(a, b);
|
|
207
|
+
const normA = Math.sqrt(this.dotProduct(a, a));
|
|
208
|
+
const normB = Math.sqrt(this.dotProduct(b, b));
|
|
209
|
+
if (normA === 0 || normB === 0)
|
|
210
|
+
return 0;
|
|
211
|
+
return dot / (normA * normB);
|
|
212
|
+
}
|
|
213
|
+
/** L2 normalization. Returns unit-length copy (or zero vector if input is zero). */
|
|
214
|
+
normalize(v) {
|
|
215
|
+
const norm = Math.sqrt(this.dotProduct(v, v));
|
|
216
|
+
const result = new Float32Array(v.length);
|
|
217
|
+
if (norm > 0) {
|
|
218
|
+
for (let i = 0; i < v.length; i++) {
|
|
219
|
+
result[i] = v[i] / norm;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
/** Assert that the useHopfieldMemory feature flag is enabled. */
|
|
225
|
+
assertEnabled() {
|
|
226
|
+
if (!getRuVectorFeatureFlags().useHopfieldMemory) {
|
|
227
|
+
throw new Error('Hopfield memory is disabled (useHopfieldMemory feature flag is false)');
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// ============================================================================
|
|
232
|
+
// Factory Functions
|
|
233
|
+
// ============================================================================
|
|
234
|
+
/** Create a HopfieldMemory with the given configuration. */
|
|
235
|
+
export function createHopfieldMemory(config) {
|
|
236
|
+
return new HopfieldMemory(config);
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=hopfield-memory.js.map
|