@aleph-ai/tinyaleph 1.5.5 → 1.5.7
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/observer/agency.js +885 -0
- package/observer/assays.js +973 -0
- package/observer/boundary.js +1155 -0
- package/observer/entanglement.js +673 -0
- package/observer/hqe.js +1465 -0
- package/observer/index.js +158 -0
- package/observer/prsc.js +1289 -0
- package/observer/safety.js +815 -0
- package/observer/smf.js +1015 -0
- package/observer/symbolic-smf.js +726 -0
- package/observer/symbolic-temporal.js +790 -0
- package/observer/temporal.js +669 -0
- package/package.json +2 -1
package/observer/hqe.js
ADDED
|
@@ -0,0 +1,1465 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Holographic Quantum Encoding (HQE)
|
|
4
|
+
*
|
|
5
|
+
* Implements the holographic projection mechanism from "A Design for a
|
|
6
|
+
* Sentient Observer" paper, Section 5.
|
|
7
|
+
*
|
|
8
|
+
* Key features:
|
|
9
|
+
* - Discrete Fourier Transform holographic projection
|
|
10
|
+
* - Spatial interference patterns from prime states
|
|
11
|
+
* - Pattern reconstruction via inverse DFT
|
|
12
|
+
* - Similarity metrics between holographic patterns
|
|
13
|
+
* - Distributed, non-local semantic representation
|
|
14
|
+
* - Dynamic λ(t) stabilization control (equation 12)
|
|
15
|
+
* - CRT-Homology integration for consistency detection
|
|
16
|
+
*
|
|
17
|
+
* Browser-compatible: No Node.js-specific dependencies
|
|
18
|
+
*
|
|
19
|
+
* @module observer/hqe
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { Complex, PrimeState } from '../core/hilbert.js';
|
|
23
|
+
import { firstNPrimes } from '../core/prime.js';
|
|
24
|
+
|
|
25
|
+
// CRT-Homology components for consistency detection
|
|
26
|
+
import { CRTReconstructor, HomologyLoss, CoprimeSelector, ResidueEncoder, BirkhoffProjector } from '../core/crt-homology.js';
|
|
27
|
+
|
|
28
|
+
// ════════════════════════════════════════════════════════════════════
|
|
29
|
+
// TICK GATE (from discrete.pdf Section 4.2)
|
|
30
|
+
// Gates expensive holographic operations to tick events only
|
|
31
|
+
// ════════════════════════════════════════════════════════════════════
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Tick Gate for HQE operations
|
|
35
|
+
*
|
|
36
|
+
* From discrete.pdf: HQE computation should only occur on valid tick events
|
|
37
|
+
* to prevent continuous CPU usage and maintain discrete-time semantics.
|
|
38
|
+
*
|
|
39
|
+
* Tick conditions:
|
|
40
|
+
* 1. Minimum time elapsed since last tick
|
|
41
|
+
* 2. Coherence threshold crossed
|
|
42
|
+
* 3. External event trigger
|
|
43
|
+
*/
|
|
44
|
+
class TickGate {
|
|
45
|
+
/**
|
|
46
|
+
* Create a tick gate
|
|
47
|
+
* @param {Object} options - Configuration
|
|
48
|
+
* @param {number} [options.minTickInterval=16] - Minimum ms between ticks (~60fps max)
|
|
49
|
+
* @param {number} [options.coherenceThreshold=0.7] - Coherence threshold for auto-tick
|
|
50
|
+
* @param {number} [options.maxTickHistory=50] - Maximum tick history size
|
|
51
|
+
* @param {'strict'|'adaptive'|'free'} [options.mode='adaptive'] - Gating mode
|
|
52
|
+
*/
|
|
53
|
+
constructor(options = {}) {
|
|
54
|
+
// Minimum milliseconds between ticks
|
|
55
|
+
this.minTickInterval = options.minTickInterval || 16; // ~60fps max
|
|
56
|
+
|
|
57
|
+
// Coherence threshold for triggering tick
|
|
58
|
+
this.coherenceThreshold = options.coherenceThreshold || 0.7;
|
|
59
|
+
|
|
60
|
+
// Last tick timestamp
|
|
61
|
+
this.lastTickTime = 0;
|
|
62
|
+
|
|
63
|
+
// Tick counter
|
|
64
|
+
this.tickCount = 0;
|
|
65
|
+
|
|
66
|
+
// Pending tick flag (set by external events)
|
|
67
|
+
this.pendingTick = false;
|
|
68
|
+
|
|
69
|
+
// Tick history for analysis
|
|
70
|
+
this.tickHistory = [];
|
|
71
|
+
this.maxTickHistory = options.maxTickHistory || 50;
|
|
72
|
+
|
|
73
|
+
// Gating mode
|
|
74
|
+
// 'strict' - only process on explicit ticks
|
|
75
|
+
// 'adaptive' - allow through if coherence is high
|
|
76
|
+
// 'free' - no gating (legacy behavior)
|
|
77
|
+
this.mode = options.mode || 'adaptive';
|
|
78
|
+
|
|
79
|
+
// Statistics
|
|
80
|
+
this.gatedCount = 0; // Number of operations gated (blocked)
|
|
81
|
+
this.passedCount = 0; // Number of operations passed
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Register an external tick event
|
|
86
|
+
* Called by PRSC or SMF when coherence spikes
|
|
87
|
+
*/
|
|
88
|
+
tick() {
|
|
89
|
+
const now = Date.now();
|
|
90
|
+
this.pendingTick = true;
|
|
91
|
+
this.lastTickTime = now;
|
|
92
|
+
this.tickCount++;
|
|
93
|
+
|
|
94
|
+
this.tickHistory.push({
|
|
95
|
+
time: now,
|
|
96
|
+
count: this.tickCount
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
if (this.tickHistory.length > this.maxTickHistory) {
|
|
100
|
+
this.tickHistory.shift();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Check if an operation should proceed (tick gate)
|
|
106
|
+
*
|
|
107
|
+
* @param {Object} state - Current system state
|
|
108
|
+
* @param {number} [state.coherence=0] - Current coherence level
|
|
109
|
+
* @returns {Object} Gate result
|
|
110
|
+
*/
|
|
111
|
+
shouldProcess(state = {}) {
|
|
112
|
+
const now = Date.now();
|
|
113
|
+
const timeSinceLastTick = now - this.lastTickTime;
|
|
114
|
+
const coherence = state.coherence || 0;
|
|
115
|
+
|
|
116
|
+
let shouldPass = false;
|
|
117
|
+
let reason = '';
|
|
118
|
+
|
|
119
|
+
switch (this.mode) {
|
|
120
|
+
case 'free':
|
|
121
|
+
// No gating - always pass
|
|
122
|
+
shouldPass = true;
|
|
123
|
+
reason = 'free_mode';
|
|
124
|
+
break;
|
|
125
|
+
|
|
126
|
+
case 'strict':
|
|
127
|
+
// Only pass on explicit pending tick
|
|
128
|
+
shouldPass = this.pendingTick;
|
|
129
|
+
reason = shouldPass ? 'pending_tick' : 'no_tick';
|
|
130
|
+
break;
|
|
131
|
+
|
|
132
|
+
case 'adaptive':
|
|
133
|
+
default:
|
|
134
|
+
// Pass if:
|
|
135
|
+
// 1. Pending tick exists, OR
|
|
136
|
+
// 2. Coherence exceeds threshold AND minimum interval elapsed
|
|
137
|
+
if (this.pendingTick) {
|
|
138
|
+
shouldPass = true;
|
|
139
|
+
reason = 'pending_tick';
|
|
140
|
+
} else if (coherence >= this.coherenceThreshold &&
|
|
141
|
+
timeSinceLastTick >= this.minTickInterval) {
|
|
142
|
+
shouldPass = true;
|
|
143
|
+
reason = 'coherence_threshold';
|
|
144
|
+
// Auto-register this as a tick
|
|
145
|
+
this.tick();
|
|
146
|
+
} else if (timeSinceLastTick >= this.minTickInterval * 10) {
|
|
147
|
+
// Fallback: allow through if way too long since last tick
|
|
148
|
+
shouldPass = true;
|
|
149
|
+
reason = 'timeout_fallback';
|
|
150
|
+
this.tick();
|
|
151
|
+
} else {
|
|
152
|
+
reason = 'gated';
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Clear pending tick if we're processing
|
|
158
|
+
if (shouldPass) {
|
|
159
|
+
this.pendingTick = false;
|
|
160
|
+
this.passedCount++;
|
|
161
|
+
} else {
|
|
162
|
+
this.gatedCount++;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
shouldPass,
|
|
167
|
+
reason,
|
|
168
|
+
tickCount: this.tickCount,
|
|
169
|
+
timeSinceLastTick,
|
|
170
|
+
coherence,
|
|
171
|
+
mode: this.mode
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Get tick rate (ticks per second)
|
|
177
|
+
* @returns {number} Ticks per second
|
|
178
|
+
*/
|
|
179
|
+
getTickRate() {
|
|
180
|
+
if (this.tickHistory.length < 2) return 0;
|
|
181
|
+
|
|
182
|
+
const recent = this.tickHistory.slice(-10);
|
|
183
|
+
const duration = recent[recent.length - 1].time - recent[0].time;
|
|
184
|
+
|
|
185
|
+
if (duration <= 0) return 0;
|
|
186
|
+
return ((recent.length - 1) / duration) * 1000;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Get gating statistics
|
|
191
|
+
* @returns {Object} Statistics
|
|
192
|
+
*/
|
|
193
|
+
getStats() {
|
|
194
|
+
const total = this.passedCount + this.gatedCount;
|
|
195
|
+
return {
|
|
196
|
+
tickCount: this.tickCount,
|
|
197
|
+
tickRate: this.getTickRate(),
|
|
198
|
+
passedCount: this.passedCount,
|
|
199
|
+
gatedCount: this.gatedCount,
|
|
200
|
+
gateRatio: total > 0 ? this.gatedCount / total : 0,
|
|
201
|
+
mode: this.mode,
|
|
202
|
+
lastTickTime: this.lastTickTime
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Reset gate state
|
|
208
|
+
*/
|
|
209
|
+
reset() {
|
|
210
|
+
this.tickCount = 0;
|
|
211
|
+
this.lastTickTime = 0;
|
|
212
|
+
this.pendingTick = false;
|
|
213
|
+
this.tickHistory = [];
|
|
214
|
+
this.gatedCount = 0;
|
|
215
|
+
this.passedCount = 0;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Set gating mode
|
|
220
|
+
* @param {'strict'|'adaptive'|'free'} mode - New mode
|
|
221
|
+
*/
|
|
222
|
+
setMode(mode) {
|
|
223
|
+
if (['strict', 'adaptive', 'free'].includes(mode)) {
|
|
224
|
+
this.mode = mode;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// ════════════════════════════════════════════════════════════════════
|
|
230
|
+
// STABILIZATION CONTROLLER (equation 12) with CRT-Homology Integration
|
|
231
|
+
// ════════════════════════════════════════════════════════════════════
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Stabilization Controller with Homology-Aware Dynamics
|
|
235
|
+
*
|
|
236
|
+
* Implements dynamic λ(t) from equation 12, enhanced with CRT-Homology:
|
|
237
|
+
* λ(t) = λ₀ · σ(aC·C(t) - aS·S(t) - aSMF·SSMF(s(t)) + aH·H(t))
|
|
238
|
+
*
|
|
239
|
+
* Where H(t) = homology penalty from detected semantic holes.
|
|
240
|
+
*
|
|
241
|
+
* Key insight: "Holes are consistency failures that persist under perturbation"
|
|
242
|
+
* - Ker(ℛ) detection identifies CRT reconstruction failures
|
|
243
|
+
* - Betti numbers (β₀, β₁) serve as topological invariants
|
|
244
|
+
* - Hole persistence correlates with Lyapunov instability (λ > 0)
|
|
245
|
+
*
|
|
246
|
+
* Controls the "condensation pressure" - balance between
|
|
247
|
+
* unitary evolution and dissipative stabilization.
|
|
248
|
+
*/
|
|
249
|
+
class StabilizationController {
|
|
250
|
+
/**
|
|
251
|
+
* Create a stabilization controller
|
|
252
|
+
* @param {Object} options - Configuration
|
|
253
|
+
* @param {number} [options.lambda0=0.1] - Base stabilization rate λ₀
|
|
254
|
+
* @param {number} [options.aC=1.0] - Coherence weight
|
|
255
|
+
* @param {number} [options.aS=0.8] - Entropy weight
|
|
256
|
+
* @param {number} [options.aSMF=0.5] - SMF entropy weight
|
|
257
|
+
* @param {number} [options.aH=0.3] - Homology weight (new)
|
|
258
|
+
* @param {number} [options.steepness=2.0] - Sigmoid steepness
|
|
259
|
+
* @param {number} [options.lambdaMin=0.01] - Minimum λ
|
|
260
|
+
* @param {number} [options.lambdaMax=0.5] - Maximum λ
|
|
261
|
+
* @param {number} [options.maxHistory=100] - History size
|
|
262
|
+
* @param {Object} [options.homology] - Homology detection options
|
|
263
|
+
*/
|
|
264
|
+
constructor(options = {}) {
|
|
265
|
+
// Base stabilization rate λ₀
|
|
266
|
+
this.lambda0 = options.lambda0 || 0.1;
|
|
267
|
+
|
|
268
|
+
// Weighting coefficients
|
|
269
|
+
this.aC = options.aC || 1.0; // Coherence weight (positive: high C increases λ)
|
|
270
|
+
this.aS = options.aS || 0.8; // Entropy weight (positive: high S decreases λ)
|
|
271
|
+
this.aSMF = options.aSMF || 0.5; // SMF entropy weight
|
|
272
|
+
this.aH = options.aH || 0.3; // Homology weight (new: holes increase λ)
|
|
273
|
+
|
|
274
|
+
// Sigmoid steepness
|
|
275
|
+
this.steepness = options.steepness || 2.0;
|
|
276
|
+
|
|
277
|
+
// Bounds for λ
|
|
278
|
+
this.lambdaMin = options.lambdaMin || 0.01;
|
|
279
|
+
this.lambdaMax = options.lambdaMax || 0.5;
|
|
280
|
+
|
|
281
|
+
// History for analysis
|
|
282
|
+
this.history = [];
|
|
283
|
+
this.maxHistory = options.maxHistory || 100;
|
|
284
|
+
|
|
285
|
+
// CRT-Homology integration
|
|
286
|
+
const homologyOpts = options.homology || {};
|
|
287
|
+
this.homologyEnabled = homologyOpts.enabled !== false;
|
|
288
|
+
|
|
289
|
+
if (this.homologyEnabled) {
|
|
290
|
+
// Select coprime moduli for CRT
|
|
291
|
+
const selector = new CoprimeSelector(homologyOpts.numModuli || 4);
|
|
292
|
+
this.moduli = selector.selectMinimal();
|
|
293
|
+
|
|
294
|
+
// Initialize CRT components
|
|
295
|
+
this.crt = new CRTReconstructor(this.moduli);
|
|
296
|
+
this.homologyLoss = new HomologyLoss({
|
|
297
|
+
tau: homologyOpts.tau || 0.1,
|
|
298
|
+
alpha: homologyOpts.alpha || 0.5,
|
|
299
|
+
beta: homologyOpts.beta || 1.0,
|
|
300
|
+
gamma: homologyOpts.gamma || 0.5
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Residue encoder (hidden dimension = moduli product for now)
|
|
304
|
+
const hiddenDim = homologyOpts.hiddenDim || 32;
|
|
305
|
+
this.residueEncoder = new ResidueEncoder(this.moduli, hiddenDim);
|
|
306
|
+
|
|
307
|
+
// Track homology state
|
|
308
|
+
this.homologyState = {
|
|
309
|
+
bettiNumbers: [1, 0], // [β₀, β₁]
|
|
310
|
+
holesDetected: 0,
|
|
311
|
+
lastError: 0,
|
|
312
|
+
cycleCount: 0
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Sigmoid squashing function σ
|
|
319
|
+
* Maps (-∞, ∞) → (0, 1)
|
|
320
|
+
* @param {number} x - Input value
|
|
321
|
+
* @returns {number} Sigmoid output
|
|
322
|
+
*/
|
|
323
|
+
sigmoid(x) {
|
|
324
|
+
return 1 / (1 + Math.exp(-this.steepness * x));
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Compute homology penalty from residue vector
|
|
329
|
+
* H(t) = β₁ * (1 + log(1 + cycles)) * kernelError
|
|
330
|
+
*
|
|
331
|
+
* @param {Array<number>} residues - Expected residues from current state
|
|
332
|
+
* @returns {number} Homology penalty
|
|
333
|
+
*/
|
|
334
|
+
computeHomologyPenalty(residues) {
|
|
335
|
+
if (!this.homologyEnabled || !residues || residues.length === 0) {
|
|
336
|
+
return 0;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
try {
|
|
340
|
+
// Detect if current residues are in kernel (CRT failure)
|
|
341
|
+
const inKernel = this.crt.detectKernel(residues, this.homologyLoss.tau);
|
|
342
|
+
const error = this.crt.reconstructionError(residues);
|
|
343
|
+
|
|
344
|
+
// Update homology state
|
|
345
|
+
this.homologyState.lastError = error;
|
|
346
|
+
|
|
347
|
+
if (inKernel) {
|
|
348
|
+
this.homologyState.holesDetected++;
|
|
349
|
+
|
|
350
|
+
// Compute Betti numbers from residue batch (simplified)
|
|
351
|
+
// In full implementation, would track residue history
|
|
352
|
+
this.homologyState.bettiNumbers = [
|
|
353
|
+
1, // β₀: always at least one component
|
|
354
|
+
Math.min(5, this.homologyState.holesDetected) // β₁: capped estimate
|
|
355
|
+
];
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const beta1 = this.homologyState.bettiNumbers[1];
|
|
359
|
+
const penalty = beta1 * (1 + Math.log(1 + this.homologyState.cycleCount)) * error;
|
|
360
|
+
|
|
361
|
+
return penalty;
|
|
362
|
+
} catch (e) {
|
|
363
|
+
// Fallback if homology computation fails
|
|
364
|
+
return 0;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Encode state to residues for homology analysis
|
|
370
|
+
* @param {Object} state - System state with prime activations
|
|
371
|
+
* @returns {Array<number>} Expected residues
|
|
372
|
+
*/
|
|
373
|
+
stateToResidues(state) {
|
|
374
|
+
if (!this.homologyEnabled) return [];
|
|
375
|
+
|
|
376
|
+
// Convert state to hidden vector
|
|
377
|
+
const hiddenDim = this.residueEncoder.hiddenDim;
|
|
378
|
+
const h = new Float64Array(hiddenDim);
|
|
379
|
+
|
|
380
|
+
if (state.amplitudes) {
|
|
381
|
+
// Direct amplitude array
|
|
382
|
+
for (let i = 0; i < Math.min(state.amplitudes.length, hiddenDim); i++) {
|
|
383
|
+
h[i] = state.amplitudes[i];
|
|
384
|
+
}
|
|
385
|
+
} else if (state.primeActivations) {
|
|
386
|
+
// Prime -> activation map
|
|
387
|
+
let i = 0;
|
|
388
|
+
for (const [prime, value] of Object.entries(state.primeActivations)) {
|
|
389
|
+
if (i >= hiddenDim) break;
|
|
390
|
+
h[i++] = typeof value === 'number' ? value : (value.norm ? value.norm() : 0);
|
|
391
|
+
}
|
|
392
|
+
} else if (typeof state.coherence === 'number') {
|
|
393
|
+
// Use coherence and entropy as proxy
|
|
394
|
+
h[0] = state.coherence || 0;
|
|
395
|
+
h[1] = state.entropy || 0;
|
|
396
|
+
h[2] = state.smfEntropy || 0;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Encode to residues
|
|
400
|
+
const residueDistributions = this.residueEncoder.encode(h);
|
|
401
|
+
return this.residueEncoder.expectedResidues(residueDistributions);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Compute current λ(t) value with homology awareness
|
|
406
|
+
*
|
|
407
|
+
* λ(t) = λ₀ · σ(aC·C(t) - aS·S(t) - aSMF·SSMF(s(t)) + aH·H(t))
|
|
408
|
+
*
|
|
409
|
+
* The homology term H(t) increases λ when semantic holes are detected,
|
|
410
|
+
* encouraging faster stabilization to resolve consistency failures.
|
|
411
|
+
*
|
|
412
|
+
* @param {number} coherence - Global coherence C(t) ∈ [0, 1]
|
|
413
|
+
* @param {number} entropy - System entropy S(t)
|
|
414
|
+
* @param {number} [smfEntropy=0] - SMF entropy SSMF
|
|
415
|
+
* @param {Object} [state=null] - Optional state for homology analysis
|
|
416
|
+
* @returns {number} Stabilization rate λ(t)
|
|
417
|
+
*/
|
|
418
|
+
computeLambda(coherence, entropy, smfEntropy = 0, state = null) {
|
|
419
|
+
// Compute homology penalty if state provided
|
|
420
|
+
let homologyPenalty = 0;
|
|
421
|
+
if (this.homologyEnabled && state) {
|
|
422
|
+
const residues = this.stateToResidues(state);
|
|
423
|
+
homologyPenalty = this.computeHomologyPenalty(residues);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Compute the argument to the sigmoid
|
|
427
|
+
// Note: homology penalty INCREASES λ (more stabilization when holes detected)
|
|
428
|
+
const arg = this.aC * coherence - this.aS * entropy - this.aSMF * smfEntropy + this.aH * homologyPenalty;
|
|
429
|
+
|
|
430
|
+
// Apply sigmoid and scale by λ₀
|
|
431
|
+
const lambda = this.lambda0 * this.sigmoid(arg);
|
|
432
|
+
|
|
433
|
+
// Clamp to bounds
|
|
434
|
+
const clampedLambda = Math.max(this.lambdaMin, Math.min(this.lambdaMax, lambda));
|
|
435
|
+
|
|
436
|
+
// Record to history
|
|
437
|
+
this.history.push({
|
|
438
|
+
timestamp: Date.now(),
|
|
439
|
+
coherence,
|
|
440
|
+
entropy,
|
|
441
|
+
smfEntropy,
|
|
442
|
+
homologyPenalty,
|
|
443
|
+
arg,
|
|
444
|
+
lambda: clampedLambda,
|
|
445
|
+
bettiNumbers: this.homologyEnabled ? [...this.homologyState.bettiNumbers] : null
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
if (this.history.length > this.maxHistory) {
|
|
449
|
+
this.history.shift();
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return clampedLambda;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Get the interpretation of current λ
|
|
457
|
+
* @param {number} lambda - Current λ value
|
|
458
|
+
* @returns {string} Interpretation
|
|
459
|
+
*/
|
|
460
|
+
interpret(lambda) {
|
|
461
|
+
if (lambda > 0.3) {
|
|
462
|
+
return 'high_stabilization'; // Strong condensation pressure
|
|
463
|
+
} else if (lambda > 0.1) {
|
|
464
|
+
return 'normal'; // Balanced
|
|
465
|
+
} else {
|
|
466
|
+
return 'low_stabilization'; // More unitary/exploratory
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Get recent lambda trend
|
|
472
|
+
* @returns {number} Trend (positive = increasing, negative = decreasing)
|
|
473
|
+
*/
|
|
474
|
+
getTrend() {
|
|
475
|
+
if (this.history.length < 5) return 0;
|
|
476
|
+
|
|
477
|
+
const recent = this.history.slice(-10);
|
|
478
|
+
const first = recent.slice(0, Math.floor(recent.length / 2));
|
|
479
|
+
const second = recent.slice(Math.floor(recent.length / 2));
|
|
480
|
+
|
|
481
|
+
const firstAvg = first.reduce((s, h) => s + h.lambda, 0) / first.length;
|
|
482
|
+
const secondAvg = second.reduce((s, h) => s + h.lambda, 0) / second.length;
|
|
483
|
+
|
|
484
|
+
return secondAvg - firstAvg;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Get statistics
|
|
489
|
+
* @returns {Object} Statistics
|
|
490
|
+
*/
|
|
491
|
+
getStats() {
|
|
492
|
+
if (this.history.length === 0) {
|
|
493
|
+
return { current: this.lambda0, mean: this.lambda0, trend: 0 };
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const lambdas = this.history.map(h => h.lambda);
|
|
497
|
+
const current = lambdas[lambdas.length - 1];
|
|
498
|
+
const mean = lambdas.reduce((a, b) => a + b, 0) / lambdas.length;
|
|
499
|
+
|
|
500
|
+
const stats = {
|
|
501
|
+
current,
|
|
502
|
+
mean,
|
|
503
|
+
min: Math.min(...lambdas),
|
|
504
|
+
max: Math.max(...lambdas),
|
|
505
|
+
trend: this.getTrend(),
|
|
506
|
+
interpretation: this.interpret(current)
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
// Add homology stats if enabled
|
|
510
|
+
if (this.homologyEnabled) {
|
|
511
|
+
stats.homology = {
|
|
512
|
+
enabled: true,
|
|
513
|
+
bettiNumbers: this.homologyState.bettiNumbers,
|
|
514
|
+
holesDetected: this.homologyState.holesDetected,
|
|
515
|
+
lastError: this.homologyState.lastError,
|
|
516
|
+
cycleCount: this.homologyState.cycleCount,
|
|
517
|
+
moduli: this.moduli
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
return stats;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Get homology state (topological invariants)
|
|
526
|
+
* @returns {Object} Homology state
|
|
527
|
+
*/
|
|
528
|
+
getHomologyState() {
|
|
529
|
+
if (!this.homologyEnabled) {
|
|
530
|
+
return { enabled: false };
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return {
|
|
534
|
+
enabled: true,
|
|
535
|
+
...this.homologyState,
|
|
536
|
+
moduli: this.moduli,
|
|
537
|
+
P: this.crt.P // Product of moduli
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Detect if system is in kernel (semantic hole)
|
|
543
|
+
* @param {Object} state - System state
|
|
544
|
+
* @returns {Object} Kernel detection result
|
|
545
|
+
*/
|
|
546
|
+
detectKernel(state) {
|
|
547
|
+
if (!this.homologyEnabled) {
|
|
548
|
+
return { inKernel: false, error: 0 };
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
const residues = this.stateToResidues(state);
|
|
552
|
+
const inKernel = this.crt.detectKernel(residues, this.homologyLoss.tau);
|
|
553
|
+
const error = this.crt.reconstructionError(residues);
|
|
554
|
+
|
|
555
|
+
return {
|
|
556
|
+
inKernel,
|
|
557
|
+
error,
|
|
558
|
+
residues,
|
|
559
|
+
reconstructed: this.crt.reconstruct(residues)
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Reset controller
|
|
565
|
+
*/
|
|
566
|
+
reset() {
|
|
567
|
+
this.history = [];
|
|
568
|
+
if (this.homologyEnabled) {
|
|
569
|
+
this.homologyState = {
|
|
570
|
+
bettiNumbers: [1, 0],
|
|
571
|
+
holesDetected: 0,
|
|
572
|
+
lastError: 0,
|
|
573
|
+
cycleCount: 0
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Serialize to JSON
|
|
580
|
+
* @returns {Object} JSON representation
|
|
581
|
+
*/
|
|
582
|
+
toJSON() {
|
|
583
|
+
const json = {
|
|
584
|
+
config: {
|
|
585
|
+
lambda0: this.lambda0,
|
|
586
|
+
aC: this.aC,
|
|
587
|
+
aS: this.aS,
|
|
588
|
+
aSMF: this.aSMF,
|
|
589
|
+
aH: this.aH
|
|
590
|
+
},
|
|
591
|
+
stats: this.getStats()
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
if (this.homologyEnabled) {
|
|
595
|
+
json.homology = this.getHomologyState();
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
return json;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// ════════════════════════════════════════════════════════════════════
|
|
603
|
+
// HOLOGRAPHIC ENCODER (equations 13-15)
|
|
604
|
+
// ════════════════════════════════════════════════════════════════════
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Holographic Quantum Encoding system
|
|
608
|
+
*
|
|
609
|
+
* Projects prime-amplitude states into spatial interference patterns
|
|
610
|
+
* using DFT, enabling distributed, reconstruction-capable memory.
|
|
611
|
+
*/
|
|
612
|
+
class HolographicEncoder {
|
|
613
|
+
/**
|
|
614
|
+
* Create a holographic encoder
|
|
615
|
+
* @param {number} [gridSize=64] - Size of the 2D holographic grid
|
|
616
|
+
* @param {Array<number>|number} [primes=64] - Primes to use or count
|
|
617
|
+
* @param {Object} [options={}] - Configuration options
|
|
618
|
+
* @param {number} [options.wavelengthScale=10] - Wavelength scaling factor
|
|
619
|
+
* @param {number} [options.phaseOffset=0] - Global phase offset
|
|
620
|
+
* @param {Object} [options.stabilization] - StabilizationController options
|
|
621
|
+
* @param {Object} [options.tickGate] - TickGate options
|
|
622
|
+
*/
|
|
623
|
+
constructor(gridSize = 64, primes = 64, options = {}) {
|
|
624
|
+
this.gridSize = gridSize;
|
|
625
|
+
|
|
626
|
+
// Handle primes argument
|
|
627
|
+
if (typeof primes === 'number') {
|
|
628
|
+
this.primes = firstNPrimes(primes);
|
|
629
|
+
} else if (Array.isArray(primes)) {
|
|
630
|
+
this.primes = primes;
|
|
631
|
+
} else {
|
|
632
|
+
this.primes = firstNPrimes(64);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
this.primeToIndex = new Map(this.primes.map((p, i) => [p, i]));
|
|
636
|
+
|
|
637
|
+
// Configuration
|
|
638
|
+
this.wavelengthScale = options.wavelengthScale || 10;
|
|
639
|
+
this.phaseOffset = options.phaseOffset || 0;
|
|
640
|
+
|
|
641
|
+
// Stabilization controller for dynamic λ(t) (equation 12)
|
|
642
|
+
this.stabilization = new StabilizationController(options.stabilization || {});
|
|
643
|
+
|
|
644
|
+
// Tick gate for HQE operations (discrete.pdf Section 4.2)
|
|
645
|
+
this.tickGate = new TickGate(options.tickGate || {});
|
|
646
|
+
|
|
647
|
+
// Precompute spatial frequencies for each prime
|
|
648
|
+
this.spatialFrequencies = this.computeSpatialFrequencies();
|
|
649
|
+
|
|
650
|
+
// Holographic field (2D complex array)
|
|
651
|
+
this.field = this.createField();
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Create an empty holographic field
|
|
656
|
+
* @returns {Array<Array<Complex>>} Empty 2D complex field
|
|
657
|
+
*/
|
|
658
|
+
createField() {
|
|
659
|
+
const field = new Array(this.gridSize);
|
|
660
|
+
for (let i = 0; i < this.gridSize; i++) {
|
|
661
|
+
field[i] = new Array(this.gridSize);
|
|
662
|
+
for (let j = 0; j < this.gridSize; j++) {
|
|
663
|
+
field[i][j] = new Complex(0, 0);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
return field;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Compute spatial frequencies for each prime
|
|
671
|
+
* Maps primes to (kx, ky) frequency pairs using golden ratio spiral
|
|
672
|
+
* @returns {Array<Object>} Frequency data for each prime
|
|
673
|
+
*/
|
|
674
|
+
computeSpatialFrequencies() {
|
|
675
|
+
const phi = (1 + Math.sqrt(5)) / 2; // Golden ratio
|
|
676
|
+
const frequencies = [];
|
|
677
|
+
|
|
678
|
+
for (let i = 0; i < this.primes.length; i++) {
|
|
679
|
+
const p = this.primes[i];
|
|
680
|
+
// Use logarithmic prime mapping for wavelength
|
|
681
|
+
const wavelength = this.wavelengthScale * (1 + Math.log(p) / Math.log(2));
|
|
682
|
+
const k = 2 * Math.PI / wavelength;
|
|
683
|
+
|
|
684
|
+
// Distribute angles using golden ratio for optimal coverage
|
|
685
|
+
const angle = 2 * Math.PI * i * phi;
|
|
686
|
+
|
|
687
|
+
frequencies.push({
|
|
688
|
+
prime: p,
|
|
689
|
+
kx: k * Math.cos(angle),
|
|
690
|
+
ky: k * Math.sin(angle),
|
|
691
|
+
wavelength
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
return frequencies;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Project a prime state into the holographic field (equation 13)
|
|
700
|
+
* H(x,y,t) = Σp αp(t) exp(i[kp·r + φp(t)])
|
|
701
|
+
*
|
|
702
|
+
* @param {PrimeState|Object} state - Prime state or {prime: Complex} map
|
|
703
|
+
* @param {Object} [options={}] - Projection options
|
|
704
|
+
* @param {boolean} [options.clear=true] - Clear field before projection
|
|
705
|
+
* @returns {Array<Array<Complex>>} The holographic field
|
|
706
|
+
*/
|
|
707
|
+
project(state, options = {}) {
|
|
708
|
+
const clear = options.clear !== false;
|
|
709
|
+
|
|
710
|
+
if (clear) {
|
|
711
|
+
this.clearField();
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// Handle different state formats
|
|
715
|
+
let amplitudes;
|
|
716
|
+
if (state instanceof PrimeState) {
|
|
717
|
+
amplitudes = this.primes.map(p => state.get(p) || new Complex(0, 0));
|
|
718
|
+
} else if (typeof state === 'object') {
|
|
719
|
+
amplitudes = this.primes.map(p => {
|
|
720
|
+
const amp = state[p];
|
|
721
|
+
if (!amp) return new Complex(0, 0);
|
|
722
|
+
if (amp instanceof Complex) return amp;
|
|
723
|
+
if (typeof amp === 'number') return new Complex(amp, 0);
|
|
724
|
+
if (amp.re !== undefined) return new Complex(amp.re, amp.im || 0);
|
|
725
|
+
return new Complex(0, 0);
|
|
726
|
+
});
|
|
727
|
+
} else {
|
|
728
|
+
throw new Error('Invalid state format');
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// Project each prime's contribution
|
|
732
|
+
for (let i = 0; i < this.primes.length; i++) {
|
|
733
|
+
const freq = this.spatialFrequencies[i];
|
|
734
|
+
const alpha = amplitudes[i];
|
|
735
|
+
|
|
736
|
+
if (alpha.norm() < 1e-10) continue;
|
|
737
|
+
|
|
738
|
+
// Add this prime's plane wave to the field
|
|
739
|
+
for (let x = 0; x < this.gridSize; x++) {
|
|
740
|
+
for (let y = 0; y < this.gridSize; y++) {
|
|
741
|
+
// k·r = kx*x + ky*y
|
|
742
|
+
const phase = freq.kx * x + freq.ky * y + this.phaseOffset;
|
|
743
|
+
const wave = Complex.fromPolar(1, phase);
|
|
744
|
+
|
|
745
|
+
// H(x,y) += αp * exp(i*k·r)
|
|
746
|
+
this.field[x][y] = this.field[x][y].add(alpha.mul(wave));
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
return this.field;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* Reconstruct amplitudes from holographic field (equation 15)
|
|
756
|
+
* Uses inverse DFT to recover prime amplitudes
|
|
757
|
+
*
|
|
758
|
+
* @returns {Map<number, Complex>} Reconstructed amplitudes by prime
|
|
759
|
+
*/
|
|
760
|
+
reconstruct() {
|
|
761
|
+
const amplitudes = new Map();
|
|
762
|
+
|
|
763
|
+
for (let i = 0; i < this.primes.length; i++) {
|
|
764
|
+
const freq = this.spatialFrequencies[i];
|
|
765
|
+
const prime = this.primes[i];
|
|
766
|
+
|
|
767
|
+
// Inverse DFT at this frequency
|
|
768
|
+
let sum = new Complex(0, 0);
|
|
769
|
+
|
|
770
|
+
for (let x = 0; x < this.gridSize; x++) {
|
|
771
|
+
for (let y = 0; y < this.gridSize; y++) {
|
|
772
|
+
// Inverse: exp(-i*k·r)
|
|
773
|
+
const phase = -(freq.kx * x + freq.ky * y + this.phaseOffset);
|
|
774
|
+
const wave = Complex.fromPolar(1, phase);
|
|
775
|
+
|
|
776
|
+
sum = sum.add(this.field[x][y].mul(wave));
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// Normalize by grid size
|
|
781
|
+
sum = new Complex(
|
|
782
|
+
sum.re / (this.gridSize * this.gridSize),
|
|
783
|
+
sum.im / (this.gridSize * this.gridSize)
|
|
784
|
+
);
|
|
785
|
+
|
|
786
|
+
amplitudes.set(prime, sum);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
return amplitudes;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* Reconstruct to PrimeState
|
|
794
|
+
* @returns {PrimeState} Reconstructed prime state
|
|
795
|
+
*/
|
|
796
|
+
reconstructToState() {
|
|
797
|
+
const amplitudes = this.reconstruct();
|
|
798
|
+
const state = new PrimeState(this.primes);
|
|
799
|
+
|
|
800
|
+
for (const [prime, amp] of amplitudes) {
|
|
801
|
+
state.set(prime, amp);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
return state;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* Compute intensity pattern (equation 14)
|
|
809
|
+
* I(x,y,t) = |H(x,y,t)|²
|
|
810
|
+
*
|
|
811
|
+
* @returns {Array<Array<number>>} Intensity at each grid point
|
|
812
|
+
*/
|
|
813
|
+
intensity() {
|
|
814
|
+
const I = new Array(this.gridSize);
|
|
815
|
+
for (let x = 0; x < this.gridSize; x++) {
|
|
816
|
+
I[x] = new Array(this.gridSize);
|
|
817
|
+
for (let y = 0; y < this.gridSize; y++) {
|
|
818
|
+
const cell = this.field[x][y];
|
|
819
|
+
// Handle both Complex objects and plain {re, im} objects
|
|
820
|
+
if (typeof cell.normSq === 'function') {
|
|
821
|
+
I[x][y] = cell.normSq();
|
|
822
|
+
} else {
|
|
823
|
+
const re = cell.re !== undefined ? cell.re : 0;
|
|
824
|
+
const im = cell.im !== undefined ? cell.im : 0;
|
|
825
|
+
I[x][y] = re * re + im * im;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
return I;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
/**
|
|
833
|
+
* Compute real part pattern (for visualization)
|
|
834
|
+
* @returns {Array<Array<number>>} Real part at each grid point
|
|
835
|
+
*/
|
|
836
|
+
realPart() {
|
|
837
|
+
const R = new Array(this.gridSize);
|
|
838
|
+
for (let x = 0; x < this.gridSize; x++) {
|
|
839
|
+
R[x] = new Array(this.gridSize);
|
|
840
|
+
for (let y = 0; y < this.gridSize; y++) {
|
|
841
|
+
R[x][y] = this.field[x][y].re;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
return R;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* Compute phase pattern (for visualization)
|
|
849
|
+
* @returns {Array<Array<number>>} Phase at each grid point
|
|
850
|
+
*/
|
|
851
|
+
phasePattern() {
|
|
852
|
+
const P = new Array(this.gridSize);
|
|
853
|
+
for (let x = 0; x < this.gridSize; x++) {
|
|
854
|
+
P[x] = new Array(this.gridSize);
|
|
855
|
+
for (let y = 0; y < this.gridSize; y++) {
|
|
856
|
+
P[x][y] = this.field[x][y].phase();
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
return P;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
/**
|
|
863
|
+
* Clear the holographic field
|
|
864
|
+
*/
|
|
865
|
+
clearField() {
|
|
866
|
+
for (let x = 0; x < this.gridSize; x++) {
|
|
867
|
+
for (let y = 0; y < this.gridSize; y++) {
|
|
868
|
+
this.field[x][y] = new Complex(0, 0);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
/**
|
|
874
|
+
* Add another field to this one (superposition)
|
|
875
|
+
* @param {Array<Array<Complex>>} otherField - Field to add
|
|
876
|
+
*/
|
|
877
|
+
superpose(otherField) {
|
|
878
|
+
for (let x = 0; x < this.gridSize; x++) {
|
|
879
|
+
for (let y = 0; y < this.gridSize; y++) {
|
|
880
|
+
this.field[x][y] = this.field[x][y].add(otherField[x][y]);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
/**
|
|
886
|
+
* Multiply field by a scalar
|
|
887
|
+
* @param {number} scalar - Multiplication factor
|
|
888
|
+
*/
|
|
889
|
+
scale(scalar) {
|
|
890
|
+
for (let x = 0; x < this.gridSize; x++) {
|
|
891
|
+
for (let y = 0; y < this.gridSize; y++) {
|
|
892
|
+
this.field[x][y] = new Complex(
|
|
893
|
+
this.field[x][y].re * scalar,
|
|
894
|
+
this.field[x][y].im * scalar
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
/**
|
|
901
|
+
* Clone this encoder with its current field
|
|
902
|
+
* @returns {HolographicEncoder} Cloned encoder
|
|
903
|
+
*/
|
|
904
|
+
clone() {
|
|
905
|
+
const cloned = new HolographicEncoder(this.gridSize, this.primes.slice(), {
|
|
906
|
+
wavelengthScale: this.wavelengthScale,
|
|
907
|
+
phaseOffset: this.phaseOffset
|
|
908
|
+
});
|
|
909
|
+
|
|
910
|
+
for (let x = 0; x < this.gridSize; x++) {
|
|
911
|
+
for (let y = 0; y < this.gridSize; y++) {
|
|
912
|
+
cloned.field[x][y] = new Complex(
|
|
913
|
+
this.field[x][y].re,
|
|
914
|
+
this.field[x][y].im
|
|
915
|
+
);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
return cloned;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
/**
|
|
923
|
+
* Compute total field energy
|
|
924
|
+
* @returns {number} Total energy
|
|
925
|
+
*/
|
|
926
|
+
totalEnergy() {
|
|
927
|
+
let energy = 0;
|
|
928
|
+
for (let x = 0; x < this.gridSize; x++) {
|
|
929
|
+
for (let y = 0; y < this.gridSize; y++) {
|
|
930
|
+
const cell = this.field[x][y];
|
|
931
|
+
// Handle both Complex objects and plain {re, im} objects
|
|
932
|
+
if (typeof cell.normSq === 'function') {
|
|
933
|
+
energy += cell.normSq();
|
|
934
|
+
} else {
|
|
935
|
+
const re = cell.re !== undefined ? cell.re : 0;
|
|
936
|
+
const im = cell.im !== undefined ? cell.im : 0;
|
|
937
|
+
energy += re * re + im * im;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
return energy;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
/**
|
|
945
|
+
* Compute field entropy (based on intensity distribution)
|
|
946
|
+
* @returns {number} Field entropy in bits
|
|
947
|
+
*/
|
|
948
|
+
fieldEntropy() {
|
|
949
|
+
const I = this.intensity();
|
|
950
|
+
const total = this.totalEnergy();
|
|
951
|
+
|
|
952
|
+
if (total < 1e-10) return 0;
|
|
953
|
+
|
|
954
|
+
let H = 0;
|
|
955
|
+
for (let x = 0; x < this.gridSize; x++) {
|
|
956
|
+
for (let y = 0; y < this.gridSize; y++) {
|
|
957
|
+
const p = I[x][y] / total;
|
|
958
|
+
if (p > 1e-10) {
|
|
959
|
+
H -= p * Math.log2(p);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
return H;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* Get state snapshot (compressed for storage)
|
|
969
|
+
* @returns {Object} Compressed state
|
|
970
|
+
*/
|
|
971
|
+
getState() {
|
|
972
|
+
// Only store non-zero cells to save space
|
|
973
|
+
const cells = [];
|
|
974
|
+
for (let x = 0; x < this.gridSize; x++) {
|
|
975
|
+
for (let y = 0; y < this.gridSize; y++) {
|
|
976
|
+
const cell = this.field[x][y];
|
|
977
|
+
// Handle both Complex objects and plain {re, im} objects
|
|
978
|
+
const re = cell.re !== undefined ? cell.re : 0;
|
|
979
|
+
const im = cell.im !== undefined ? cell.im : 0;
|
|
980
|
+
const normSq = re * re + im * im;
|
|
981
|
+
|
|
982
|
+
if (normSq > 1e-10) {
|
|
983
|
+
cells.push({ x, y, re, im });
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
return {
|
|
989
|
+
gridSize: this.gridSize,
|
|
990
|
+
cells,
|
|
991
|
+
totalEnergy: this.totalEnergy()
|
|
992
|
+
};
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
/**
|
|
996
|
+
* Load state from snapshot
|
|
997
|
+
* @param {Object} state - State snapshot
|
|
998
|
+
*/
|
|
999
|
+
loadState(state) {
|
|
1000
|
+
if (state.gridSize !== this.gridSize) {
|
|
1001
|
+
throw new Error('Grid size mismatch');
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
this.clearField();
|
|
1005
|
+
|
|
1006
|
+
for (const cell of state.cells) {
|
|
1007
|
+
this.field[cell.x][cell.y] = new Complex(cell.re, cell.im);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
/**
|
|
1012
|
+
* Evolve the holographic field with stabilization (equation 11)
|
|
1013
|
+
*
|
|
1014
|
+
* d|Ψ(t)⟩/dt = iĤ|Ψ(t)⟩ - λ(t)D̂(Ψ,s)|Ψ(t)⟩
|
|
1015
|
+
*
|
|
1016
|
+
* The first term is unitary (phase evolution), the second is dissipative
|
|
1017
|
+
* (stabilization toward coherent attractors).
|
|
1018
|
+
*
|
|
1019
|
+
* @param {Object} state - Current system state
|
|
1020
|
+
* @param {number} state.coherence - Global coherence C(t)
|
|
1021
|
+
* @param {number} state.entropy - System entropy S(t)
|
|
1022
|
+
* @param {number} [state.smfEntropy=0] - SMF entropy SSMF
|
|
1023
|
+
* @param {number} [dt=0.016] - Time step
|
|
1024
|
+
* @returns {Object} Evolution result with lambda value
|
|
1025
|
+
*/
|
|
1026
|
+
evolve(state, dt = 0.016) {
|
|
1027
|
+
const { coherence, entropy, smfEntropy = 0 } = state;
|
|
1028
|
+
|
|
1029
|
+
// Check tick gate before expensive HQE operations
|
|
1030
|
+
const gateResult = this.tickGate.shouldProcess({ coherence });
|
|
1031
|
+
|
|
1032
|
+
if (!gateResult.shouldPass) {
|
|
1033
|
+
// Return gated result without processing
|
|
1034
|
+
return {
|
|
1035
|
+
lambda: 0,
|
|
1036
|
+
interpretation: 'gated',
|
|
1037
|
+
totalEnergy: this.totalEnergy(),
|
|
1038
|
+
fieldEntropy: this.fieldEntropy(),
|
|
1039
|
+
gated: true,
|
|
1040
|
+
gateReason: gateResult.reason,
|
|
1041
|
+
tickCount: gateResult.tickCount
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
// Compute dynamic λ(t) using stabilization controller
|
|
1046
|
+
const lambda = this.stabilization.computeLambda(coherence, entropy, smfEntropy);
|
|
1047
|
+
|
|
1048
|
+
// For each cell, apply damped evolution:
|
|
1049
|
+
// New amplitude = old amplitude * exp(-λ * dt)
|
|
1050
|
+
// This implements the dissipative term -λD̂|Ψ⟩
|
|
1051
|
+
const dampingFactor = Math.exp(-lambda * dt);
|
|
1052
|
+
|
|
1053
|
+
// Apply stabilization damping
|
|
1054
|
+
for (let x = 0; x < this.gridSize; x++) {
|
|
1055
|
+
for (let y = 0; y < this.gridSize; y++) {
|
|
1056
|
+
const cell = this.field[x][y];
|
|
1057
|
+
// Dampen high-energy cells more than low-energy (stabilization)
|
|
1058
|
+
const intensity = cell.re * cell.re + cell.im * cell.im;
|
|
1059
|
+
const localDamping = dampingFactor * (1 + lambda * intensity * 0.1);
|
|
1060
|
+
|
|
1061
|
+
this.field[x][y] = new Complex(
|
|
1062
|
+
cell.re * localDamping,
|
|
1063
|
+
cell.im * localDamping
|
|
1064
|
+
);
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
return {
|
|
1069
|
+
lambda,
|
|
1070
|
+
interpretation: this.stabilization.interpret(lambda),
|
|
1071
|
+
totalEnergy: this.totalEnergy(),
|
|
1072
|
+
fieldEntropy: this.fieldEntropy(),
|
|
1073
|
+
gated: false,
|
|
1074
|
+
tickCount: gateResult.tickCount
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
/**
|
|
1079
|
+
* Register a tick event (from PRSC or SMF coherence spike)
|
|
1080
|
+
*/
|
|
1081
|
+
tick() {
|
|
1082
|
+
this.tickGate.tick();
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
/**
|
|
1086
|
+
* Get tick gate statistics
|
|
1087
|
+
* @returns {Object} Statistics
|
|
1088
|
+
*/
|
|
1089
|
+
getTickStats() {
|
|
1090
|
+
return this.tickGate.getStats();
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
/**
|
|
1094
|
+
* Set tick gate mode
|
|
1095
|
+
* @param {'strict'|'adaptive'|'free'} mode - Gating mode
|
|
1096
|
+
*/
|
|
1097
|
+
setTickMode(mode) {
|
|
1098
|
+
this.tickGate.setMode(mode);
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
/**
|
|
1102
|
+
* Get stabilization statistics
|
|
1103
|
+
* @returns {Object} Statistics
|
|
1104
|
+
*/
|
|
1105
|
+
getStabilizationStats() {
|
|
1106
|
+
return this.stabilization.getStats();
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
// ════════════════════════════════════════════════════════════════════
|
|
1111
|
+
// HOLOGRAPHIC MEMORY
|
|
1112
|
+
// ════════════════════════════════════════════════════════════════════
|
|
1113
|
+
|
|
1114
|
+
/**
|
|
1115
|
+
* Holographic Memory
|
|
1116
|
+
*
|
|
1117
|
+
* Stores and retrieves patterns using holographic interference.
|
|
1118
|
+
* Enables content-addressable, distributed, fault-tolerant memory.
|
|
1119
|
+
*/
|
|
1120
|
+
class HolographicMemory {
|
|
1121
|
+
/**
|
|
1122
|
+
* Create a holographic memory
|
|
1123
|
+
* @param {number} [gridSize=64] - Size of holographic grid
|
|
1124
|
+
* @param {number|Array} [primes=64] - Primes to use
|
|
1125
|
+
* @param {Object} [options={}] - Configuration options
|
|
1126
|
+
* @param {number} [options.maxMemories=100] - Maximum memories
|
|
1127
|
+
* @param {number} [options.decayRate=0.01] - Memory decay rate
|
|
1128
|
+
*/
|
|
1129
|
+
constructor(gridSize = 64, primes = 64, options = {}) {
|
|
1130
|
+
this.encoder = new HolographicEncoder(gridSize, primes, options);
|
|
1131
|
+
this.memories = [];
|
|
1132
|
+
this.maxMemories = options.maxMemories || 100;
|
|
1133
|
+
this.decayRate = options.decayRate || 0.01;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
/**
|
|
1137
|
+
* Store a pattern in memory
|
|
1138
|
+
* @param {PrimeState|Object} state - State to store
|
|
1139
|
+
* @param {Object} [metadata={}] - Associated metadata
|
|
1140
|
+
* @returns {number} Memory index
|
|
1141
|
+
*/
|
|
1142
|
+
store(state, metadata = {}) {
|
|
1143
|
+
// Create a new encoder for this memory
|
|
1144
|
+
const encoder = new HolographicEncoder(
|
|
1145
|
+
this.encoder.gridSize,
|
|
1146
|
+
this.encoder.primes.slice(),
|
|
1147
|
+
{
|
|
1148
|
+
wavelengthScale: this.encoder.wavelengthScale,
|
|
1149
|
+
phaseOffset: this.encoder.phaseOffset
|
|
1150
|
+
}
|
|
1151
|
+
);
|
|
1152
|
+
|
|
1153
|
+
encoder.project(state);
|
|
1154
|
+
|
|
1155
|
+
this.memories.push({
|
|
1156
|
+
encoder,
|
|
1157
|
+
metadata,
|
|
1158
|
+
timestamp: Date.now(),
|
|
1159
|
+
accessCount: 0,
|
|
1160
|
+
strength: 1.0
|
|
1161
|
+
});
|
|
1162
|
+
|
|
1163
|
+
// Prune if over capacity
|
|
1164
|
+
if (this.memories.length > this.maxMemories) {
|
|
1165
|
+
this.prune();
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
return this.memories.length - 1;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
/**
|
|
1172
|
+
* Recall the best matching memory
|
|
1173
|
+
* @param {PrimeState|Object} cue - Retrieval cue
|
|
1174
|
+
* @param {number} [threshold=0.3] - Minimum similarity threshold
|
|
1175
|
+
* @returns {Object|null} Best matching memory or null
|
|
1176
|
+
*/
|
|
1177
|
+
recall(cue, threshold = 0.3) {
|
|
1178
|
+
if (this.memories.length === 0) return null;
|
|
1179
|
+
|
|
1180
|
+
// Project cue to holographic form
|
|
1181
|
+
const cueEncoder = new HolographicEncoder(
|
|
1182
|
+
this.encoder.gridSize,
|
|
1183
|
+
this.encoder.primes.slice()
|
|
1184
|
+
);
|
|
1185
|
+
cueEncoder.project(cue);
|
|
1186
|
+
|
|
1187
|
+
// Find best match by holographic correlation
|
|
1188
|
+
let bestMatch = null;
|
|
1189
|
+
let bestScore = threshold;
|
|
1190
|
+
|
|
1191
|
+
for (const memory of this.memories) {
|
|
1192
|
+
const score = this.correlate(cueEncoder, memory.encoder);
|
|
1193
|
+
if (score > bestScore) {
|
|
1194
|
+
bestScore = score;
|
|
1195
|
+
bestMatch = memory;
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
if (bestMatch) {
|
|
1200
|
+
bestMatch.accessCount++;
|
|
1201
|
+
bestMatch.strength = Math.min(1.0, bestMatch.strength + 0.1);
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
return bestMatch ? {
|
|
1205
|
+
state: bestMatch.encoder.reconstructToState(),
|
|
1206
|
+
metadata: bestMatch.metadata,
|
|
1207
|
+
score: bestScore,
|
|
1208
|
+
strength: bestMatch.strength
|
|
1209
|
+
} : null;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
/**
|
|
1213
|
+
* Correlate two holographic fields
|
|
1214
|
+
* Returns normalized correlation coefficient
|
|
1215
|
+
*
|
|
1216
|
+
* @param {HolographicEncoder} enc1 - First encoder
|
|
1217
|
+
* @param {HolographicEncoder} enc2 - Second encoder
|
|
1218
|
+
* @returns {number} Correlation coefficient
|
|
1219
|
+
*/
|
|
1220
|
+
correlate(enc1, enc2) {
|
|
1221
|
+
let sumProduct = 0;
|
|
1222
|
+
let sumSq1 = 0;
|
|
1223
|
+
let sumSq2 = 0;
|
|
1224
|
+
|
|
1225
|
+
for (let x = 0; x < enc1.gridSize; x++) {
|
|
1226
|
+
for (let y = 0; y < enc1.gridSize; y++) {
|
|
1227
|
+
// Compute normSq for each cell (handling both Complex and plain objects)
|
|
1228
|
+
const cell1 = enc1.field[x][y];
|
|
1229
|
+
const cell2 = enc2.field[x][y];
|
|
1230
|
+
|
|
1231
|
+
let v1, v2;
|
|
1232
|
+
if (typeof cell1.normSq === 'function') {
|
|
1233
|
+
v1 = cell1.normSq();
|
|
1234
|
+
} else {
|
|
1235
|
+
const re1 = cell1.re !== undefined ? cell1.re : 0;
|
|
1236
|
+
const im1 = cell1.im !== undefined ? cell1.im : 0;
|
|
1237
|
+
v1 = re1 * re1 + im1 * im1;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
if (typeof cell2.normSq === 'function') {
|
|
1241
|
+
v2 = cell2.normSq();
|
|
1242
|
+
} else {
|
|
1243
|
+
const re2 = cell2.re !== undefined ? cell2.re : 0;
|
|
1244
|
+
const im2 = cell2.im !== undefined ? cell2.im : 0;
|
|
1245
|
+
v2 = re2 * re2 + im2 * im2;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
sumProduct += v1 * v2;
|
|
1249
|
+
sumSq1 += v1 * v1;
|
|
1250
|
+
sumSq2 += v2 * v2;
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
const norm = Math.sqrt(sumSq1) * Math.sqrt(sumSq2);
|
|
1255
|
+
return norm > 1e-10 ? sumProduct / norm : 0;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
/**
|
|
1259
|
+
* Apply decay to all memories
|
|
1260
|
+
*/
|
|
1261
|
+
decay() {
|
|
1262
|
+
for (const memory of this.memories) {
|
|
1263
|
+
memory.strength *= (1 - this.decayRate);
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
// Remove very weak memories
|
|
1267
|
+
this.memories = this.memories.filter(m => m.strength > 0.1);
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
/**
|
|
1271
|
+
* Prune memories to capacity
|
|
1272
|
+
* Removes weakest or oldest memories
|
|
1273
|
+
*/
|
|
1274
|
+
prune() {
|
|
1275
|
+
if (this.memories.length <= this.maxMemories) return;
|
|
1276
|
+
|
|
1277
|
+
// Sort by strength * accessCount
|
|
1278
|
+
this.memories.sort((a, b) =>
|
|
1279
|
+
(b.strength * (b.accessCount + 1)) -
|
|
1280
|
+
(a.strength * (a.accessCount + 1))
|
|
1281
|
+
);
|
|
1282
|
+
|
|
1283
|
+
// Keep top memories
|
|
1284
|
+
this.memories = this.memories.slice(0, this.maxMemories);
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
/**
|
|
1288
|
+
* Find all memories above similarity threshold
|
|
1289
|
+
* @param {PrimeState|Object} cue - Retrieval cue
|
|
1290
|
+
* @param {number} [threshold=0.3] - Minimum similarity
|
|
1291
|
+
* @returns {Array<Object>} Matching memories
|
|
1292
|
+
*/
|
|
1293
|
+
findSimilar(cue, threshold = 0.3) {
|
|
1294
|
+
const cueEncoder = new HolographicEncoder(
|
|
1295
|
+
this.encoder.gridSize,
|
|
1296
|
+
this.encoder.primes.slice()
|
|
1297
|
+
);
|
|
1298
|
+
cueEncoder.project(cue);
|
|
1299
|
+
|
|
1300
|
+
const results = [];
|
|
1301
|
+
for (const memory of this.memories) {
|
|
1302
|
+
const score = this.correlate(cueEncoder, memory.encoder);
|
|
1303
|
+
if (score > threshold) {
|
|
1304
|
+
results.push({
|
|
1305
|
+
state: memory.encoder.reconstructToState(),
|
|
1306
|
+
metadata: memory.metadata,
|
|
1307
|
+
score,
|
|
1308
|
+
strength: memory.strength
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
return results.sort((a, b) => b.score - a.score);
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
/**
|
|
1317
|
+
* Get memory count
|
|
1318
|
+
* @returns {number} Number of stored memories
|
|
1319
|
+
*/
|
|
1320
|
+
get count() {
|
|
1321
|
+
return this.memories.length;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
/**
|
|
1325
|
+
* Clear all memories
|
|
1326
|
+
*/
|
|
1327
|
+
clear() {
|
|
1328
|
+
this.memories = [];
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
/**
|
|
1332
|
+
* Serialize to JSON (compact form)
|
|
1333
|
+
* @returns {Object} JSON representation
|
|
1334
|
+
*/
|
|
1335
|
+
toJSON() {
|
|
1336
|
+
return {
|
|
1337
|
+
gridSize: this.encoder.gridSize,
|
|
1338
|
+
primes: this.encoder.primes,
|
|
1339
|
+
memories: this.memories.map(m => ({
|
|
1340
|
+
state: m.encoder.getState(),
|
|
1341
|
+
metadata: m.metadata,
|
|
1342
|
+
timestamp: m.timestamp,
|
|
1343
|
+
accessCount: m.accessCount,
|
|
1344
|
+
strength: m.strength
|
|
1345
|
+
}))
|
|
1346
|
+
};
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
/**
|
|
1350
|
+
* Load from JSON
|
|
1351
|
+
* @param {Object} data - Serialized memory
|
|
1352
|
+
* @returns {HolographicMemory} Restored memory
|
|
1353
|
+
*/
|
|
1354
|
+
static fromJSON(data) {
|
|
1355
|
+
const memory = new HolographicMemory(data.gridSize, data.primes);
|
|
1356
|
+
|
|
1357
|
+
for (const saved of data.memories) {
|
|
1358
|
+
const encoder = new HolographicEncoder(data.gridSize, data.primes);
|
|
1359
|
+
encoder.loadState(saved.state);
|
|
1360
|
+
|
|
1361
|
+
memory.memories.push({
|
|
1362
|
+
encoder,
|
|
1363
|
+
metadata: saved.metadata,
|
|
1364
|
+
timestamp: saved.timestamp,
|
|
1365
|
+
accessCount: saved.accessCount,
|
|
1366
|
+
strength: saved.strength
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
return memory;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
// ════════════════════════════════════════════════════════════════════
|
|
1375
|
+
// HOLOGRAPHIC SIMILARITY
|
|
1376
|
+
// ════════════════════════════════════════════════════════════════════
|
|
1377
|
+
|
|
1378
|
+
/**
|
|
1379
|
+
* Pattern similarity using holographic comparison
|
|
1380
|
+
*/
|
|
1381
|
+
class HolographicSimilarity {
|
|
1382
|
+
/**
|
|
1383
|
+
* Create a similarity calculator
|
|
1384
|
+
* @param {number} [gridSize=32] - Holographic grid size
|
|
1385
|
+
* @param {number|Array} [primes=32] - Primes to use
|
|
1386
|
+
*/
|
|
1387
|
+
constructor(gridSize = 32, primes = 32) {
|
|
1388
|
+
this.encoder1 = new HolographicEncoder(gridSize, primes);
|
|
1389
|
+
this.encoder2 = new HolographicEncoder(gridSize, primes);
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* Compute holographic similarity between two states
|
|
1394
|
+
* @param {PrimeState|Object} state1 - First state
|
|
1395
|
+
* @param {PrimeState|Object} state2 - Second state
|
|
1396
|
+
* @returns {number} Similarity score (0-1)
|
|
1397
|
+
*/
|
|
1398
|
+
similarity(state1, state2) {
|
|
1399
|
+
this.encoder1.project(state1);
|
|
1400
|
+
this.encoder2.project(state2);
|
|
1401
|
+
|
|
1402
|
+
// Compute intensity correlation
|
|
1403
|
+
const I1 = this.encoder1.intensity();
|
|
1404
|
+
const I2 = this.encoder2.intensity();
|
|
1405
|
+
|
|
1406
|
+
let sumProduct = 0;
|
|
1407
|
+
let sumSq1 = 0;
|
|
1408
|
+
let sumSq2 = 0;
|
|
1409
|
+
|
|
1410
|
+
for (let x = 0; x < this.encoder1.gridSize; x++) {
|
|
1411
|
+
for (let y = 0; y < this.encoder1.gridSize; y++) {
|
|
1412
|
+
sumProduct += I1[x][y] * I2[x][y];
|
|
1413
|
+
sumSq1 += I1[x][y] * I1[x][y];
|
|
1414
|
+
sumSq2 += I2[x][y] * I2[x][y];
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
const norm = Math.sqrt(sumSq1) * Math.sqrt(sumSq2);
|
|
1419
|
+
return norm > 1e-10 ? sumProduct / norm : 0;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
/**
|
|
1423
|
+
* Compute difference pattern
|
|
1424
|
+
* @param {PrimeState|Object} state1 - First state
|
|
1425
|
+
* @param {PrimeState|Object} state2 - Second state
|
|
1426
|
+
* @returns {HolographicEncoder} Difference encoder
|
|
1427
|
+
*/
|
|
1428
|
+
difference(state1, state2) {
|
|
1429
|
+
this.encoder1.project(state1);
|
|
1430
|
+
this.encoder2.project(state2);
|
|
1431
|
+
|
|
1432
|
+
const diff = this.encoder1.clone();
|
|
1433
|
+
|
|
1434
|
+
for (let x = 0; x < diff.gridSize; x++) {
|
|
1435
|
+
for (let y = 0; y < diff.gridSize; y++) {
|
|
1436
|
+
diff.field[x][y] = new Complex(
|
|
1437
|
+
diff.field[x][y].re - this.encoder2.field[x][y].re,
|
|
1438
|
+
diff.field[x][y].im - this.encoder2.field[x][y].im
|
|
1439
|
+
);
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
return diff;
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
// ════════════════════════════════════════════════════════════════════
|
|
1448
|
+
// EXPORTS
|
|
1449
|
+
// ════════════════════════════════════════════════════════════════════
|
|
1450
|
+
|
|
1451
|
+
export {
|
|
1452
|
+
TickGate,
|
|
1453
|
+
StabilizationController,
|
|
1454
|
+
HolographicEncoder,
|
|
1455
|
+
HolographicMemory,
|
|
1456
|
+
HolographicSimilarity
|
|
1457
|
+
};
|
|
1458
|
+
|
|
1459
|
+
export default {
|
|
1460
|
+
TickGate,
|
|
1461
|
+
StabilizationController,
|
|
1462
|
+
HolographicEncoder,
|
|
1463
|
+
HolographicMemory,
|
|
1464
|
+
HolographicSimilarity
|
|
1465
|
+
};
|