@aleph-ai/tinyaleph 1.1.0 → 1.2.1
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/README.md +230 -2
- package/core/entanglement.js +712 -0
- package/core/events.js +907 -0
- package/core/hypercomplex.js +500 -0
- package/core/index.js +46 -0
- package/core/rformer-layers.js +811 -0
- package/docs/reference/01-core.md +515 -1
- package/docs/reference/02-physics.md +186 -1
- package/package.json +1 -1
- package/physics/index.js +62 -0
- package/physics/kuramoto-coupled-ladder.js +603 -0
- package/physics/primeon_z_ladder_multi.js +669 -0
- package/physics/primeon_z_ladder_u.js +493 -0
- package/physics/stochastic-kuramoto.js +566 -0
package/core/events.js
ADDED
|
@@ -0,0 +1,907 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aleph Event System
|
|
3
|
+
*
|
|
4
|
+
* Event-driven monitoring for real-time applications.
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - EventEmitter-based for Node.js compatibility
|
|
8
|
+
* - Named events for different state changes
|
|
9
|
+
* - Subscription management
|
|
10
|
+
* - Throttling and debouncing
|
|
11
|
+
* - Event history buffer
|
|
12
|
+
*
|
|
13
|
+
* Events:
|
|
14
|
+
* - 'tick': Each time step {t, state, entropy, coherence}
|
|
15
|
+
* - 'collapse': State collapse {from, to, probability}
|
|
16
|
+
* - 'resonance': Strong resonance {primes, strength}
|
|
17
|
+
* - 'sync': Synchronization crossed {orderParameter, clusters}
|
|
18
|
+
* - 'entropy:low': Entropy below threshold {value, threshold}
|
|
19
|
+
* - 'entropy:high': Entropy above threshold {value, threshold}
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
'use strict';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* AlephEventEmitter - Core event system
|
|
26
|
+
*
|
|
27
|
+
* Compatible with Node.js EventEmitter pattern but standalone.
|
|
28
|
+
*/
|
|
29
|
+
class AlephEventEmitter {
|
|
30
|
+
constructor(options = {}) {
|
|
31
|
+
this._listeners = new Map();
|
|
32
|
+
this._onceListeners = new Map();
|
|
33
|
+
this._history = [];
|
|
34
|
+
this._maxHistoryLength = options.maxHistory ?? 1000;
|
|
35
|
+
this._throttleIntervals = new Map();
|
|
36
|
+
this._lastEmitTime = new Map();
|
|
37
|
+
this._paused = false;
|
|
38
|
+
|
|
39
|
+
// Statistics
|
|
40
|
+
this._stats = {
|
|
41
|
+
totalEmitted: 0,
|
|
42
|
+
eventCounts: new Map()
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Add event listener
|
|
48
|
+
* @param {string} event - Event name
|
|
49
|
+
* @param {Function} callback - Handler function
|
|
50
|
+
* @returns {AlephEventEmitter} this for chaining
|
|
51
|
+
*/
|
|
52
|
+
on(event, callback) {
|
|
53
|
+
if (!this._listeners.has(event)) {
|
|
54
|
+
this._listeners.set(event, new Set());
|
|
55
|
+
}
|
|
56
|
+
this._listeners.get(event).add(callback);
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Add one-time event listener
|
|
62
|
+
* @param {string} event - Event name
|
|
63
|
+
* @param {Function} callback - Handler function
|
|
64
|
+
* @returns {AlephEventEmitter} this for chaining
|
|
65
|
+
*/
|
|
66
|
+
once(event, callback) {
|
|
67
|
+
if (!this._onceListeners.has(event)) {
|
|
68
|
+
this._onceListeners.set(event, new Set());
|
|
69
|
+
}
|
|
70
|
+
this._onceListeners.get(event).add(callback);
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Remove event listener
|
|
76
|
+
* @param {string} event - Event name
|
|
77
|
+
* @param {Function} callback - Handler function to remove
|
|
78
|
+
* @returns {AlephEventEmitter} this for chaining
|
|
79
|
+
*/
|
|
80
|
+
off(event, callback) {
|
|
81
|
+
if (this._listeners.has(event)) {
|
|
82
|
+
this._listeners.get(event).delete(callback);
|
|
83
|
+
}
|
|
84
|
+
if (this._onceListeners.has(event)) {
|
|
85
|
+
this._onceListeners.get(event).delete(callback);
|
|
86
|
+
}
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Remove all listeners for an event (or all events if no event specified)
|
|
92
|
+
* @param {string} [event] - Event name (optional)
|
|
93
|
+
*/
|
|
94
|
+
removeAllListeners(event) {
|
|
95
|
+
if (event) {
|
|
96
|
+
this._listeners.delete(event);
|
|
97
|
+
this._onceListeners.delete(event);
|
|
98
|
+
} else {
|
|
99
|
+
this._listeners.clear();
|
|
100
|
+
this._onceListeners.clear();
|
|
101
|
+
}
|
|
102
|
+
return this;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Emit an event
|
|
107
|
+
* @param {string} event - Event name
|
|
108
|
+
* @param {*} data - Event data
|
|
109
|
+
* @returns {boolean} Whether any listeners were called
|
|
110
|
+
*/
|
|
111
|
+
emit(event, data) {
|
|
112
|
+
if (this._paused) return false;
|
|
113
|
+
|
|
114
|
+
// Check throttling
|
|
115
|
+
if (this._throttleIntervals.has(event)) {
|
|
116
|
+
const interval = this._throttleIntervals.get(event);
|
|
117
|
+
const lastTime = this._lastEmitTime.get(event) || 0;
|
|
118
|
+
const now = Date.now();
|
|
119
|
+
|
|
120
|
+
if (now - lastTime < interval) {
|
|
121
|
+
return false; // Throttled
|
|
122
|
+
}
|
|
123
|
+
this._lastEmitTime.set(event, now);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const eventData = {
|
|
127
|
+
event,
|
|
128
|
+
data,
|
|
129
|
+
timestamp: Date.now()
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// Add to history
|
|
133
|
+
this._history.push(eventData);
|
|
134
|
+
if (this._history.length > this._maxHistoryLength) {
|
|
135
|
+
this._history.shift();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Update stats
|
|
139
|
+
this._stats.totalEmitted++;
|
|
140
|
+
this._stats.eventCounts.set(
|
|
141
|
+
event,
|
|
142
|
+
(this._stats.eventCounts.get(event) || 0) + 1
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
let called = false;
|
|
146
|
+
|
|
147
|
+
// Call regular listeners
|
|
148
|
+
if (this._listeners.has(event)) {
|
|
149
|
+
for (const callback of this._listeners.get(event)) {
|
|
150
|
+
try {
|
|
151
|
+
callback(data);
|
|
152
|
+
called = true;
|
|
153
|
+
} catch (err) {
|
|
154
|
+
console.error(`Error in event listener for '${event}':`, err);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Call and remove once listeners
|
|
160
|
+
if (this._onceListeners.has(event)) {
|
|
161
|
+
const onceCallbacks = this._onceListeners.get(event);
|
|
162
|
+
this._onceListeners.delete(event);
|
|
163
|
+
|
|
164
|
+
for (const callback of onceCallbacks) {
|
|
165
|
+
try {
|
|
166
|
+
callback(data);
|
|
167
|
+
called = true;
|
|
168
|
+
} catch (err) {
|
|
169
|
+
console.error(`Error in once listener for '${event}':`, err);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Emit wildcard event
|
|
175
|
+
if (event !== '*' && this._listeners.has('*')) {
|
|
176
|
+
for (const callback of this._listeners.get('*')) {
|
|
177
|
+
try {
|
|
178
|
+
callback(eventData);
|
|
179
|
+
called = true;
|
|
180
|
+
} catch (err) {
|
|
181
|
+
console.error(`Error in wildcard listener:`, err);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return called;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Set throttle interval for an event
|
|
191
|
+
* @param {string} event - Event name
|
|
192
|
+
* @param {number} interval - Minimum ms between emissions
|
|
193
|
+
*/
|
|
194
|
+
throttle(event, interval) {
|
|
195
|
+
this._throttleIntervals.set(event, interval);
|
|
196
|
+
return this;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Remove throttling for an event
|
|
201
|
+
* @param {string} event - Event name
|
|
202
|
+
*/
|
|
203
|
+
unthrottle(event) {
|
|
204
|
+
this._throttleIntervals.delete(event);
|
|
205
|
+
this._lastEmitTime.delete(event);
|
|
206
|
+
return this;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Pause all event emissions
|
|
211
|
+
*/
|
|
212
|
+
pause() {
|
|
213
|
+
this._paused = true;
|
|
214
|
+
return this;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Resume event emissions
|
|
219
|
+
*/
|
|
220
|
+
resume() {
|
|
221
|
+
this._paused = false;
|
|
222
|
+
return this;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Check if paused
|
|
227
|
+
*/
|
|
228
|
+
isPaused() {
|
|
229
|
+
return this._paused;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Get listener count for an event
|
|
234
|
+
* @param {string} event - Event name
|
|
235
|
+
*/
|
|
236
|
+
listenerCount(event) {
|
|
237
|
+
const regular = this._listeners.get(event)?.size || 0;
|
|
238
|
+
const once = this._onceListeners.get(event)?.size || 0;
|
|
239
|
+
return regular + once;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Get all registered event names
|
|
244
|
+
*/
|
|
245
|
+
eventNames() {
|
|
246
|
+
const names = new Set([
|
|
247
|
+
...this._listeners.keys(),
|
|
248
|
+
...this._onceListeners.keys()
|
|
249
|
+
]);
|
|
250
|
+
return Array.from(names);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Get event history
|
|
255
|
+
* @param {string} [event] - Filter by event name
|
|
256
|
+
* @param {number} [limit] - Maximum entries to return
|
|
257
|
+
*/
|
|
258
|
+
getHistory(event = null, limit = 100) {
|
|
259
|
+
let history = this._history;
|
|
260
|
+
|
|
261
|
+
if (event) {
|
|
262
|
+
history = history.filter(h => h.event === event);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return history.slice(-limit);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Clear event history
|
|
270
|
+
*/
|
|
271
|
+
clearHistory() {
|
|
272
|
+
this._history = [];
|
|
273
|
+
return this;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Get event statistics
|
|
278
|
+
*/
|
|
279
|
+
getStats() {
|
|
280
|
+
return {
|
|
281
|
+
totalEmitted: this._stats.totalEmitted,
|
|
282
|
+
eventCounts: Object.fromEntries(this._stats.eventCounts),
|
|
283
|
+
historyLength: this._history.length,
|
|
284
|
+
listenerCounts: Object.fromEntries(
|
|
285
|
+
this.eventNames().map(e => [e, this.listenerCount(e)])
|
|
286
|
+
)
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Reset statistics
|
|
292
|
+
*/
|
|
293
|
+
resetStats() {
|
|
294
|
+
this._stats.totalEmitted = 0;
|
|
295
|
+
this._stats.eventCounts.clear();
|
|
296
|
+
return this;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Create a filtered emitter that only emits matching events
|
|
301
|
+
* @param {Function} predicate - Filter function (eventData) => boolean
|
|
302
|
+
*/
|
|
303
|
+
filter(predicate) {
|
|
304
|
+
const filtered = new AlephEventEmitter();
|
|
305
|
+
|
|
306
|
+
this.on('*', (eventData) => {
|
|
307
|
+
if (predicate(eventData)) {
|
|
308
|
+
filtered.emit(eventData.event, eventData.data);
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
return filtered;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Create a mapped emitter that transforms event data
|
|
317
|
+
* @param {Function} transform - Transform function (data) => newData
|
|
318
|
+
*/
|
|
319
|
+
map(transform) {
|
|
320
|
+
const mapped = new AlephEventEmitter();
|
|
321
|
+
|
|
322
|
+
this.on('*', (eventData) => {
|
|
323
|
+
mapped.emit(eventData.event, transform(eventData.data));
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
return mapped;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Promise-based wait for next event
|
|
331
|
+
* @param {string} event - Event name
|
|
332
|
+
* @param {number} [timeout] - Timeout in ms
|
|
333
|
+
*/
|
|
334
|
+
waitFor(event, timeout = null) {
|
|
335
|
+
return new Promise((resolve, reject) => {
|
|
336
|
+
const handler = (data) => {
|
|
337
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
338
|
+
resolve(data);
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
let timeoutId = null;
|
|
342
|
+
if (timeout) {
|
|
343
|
+
timeoutId = setTimeout(() => {
|
|
344
|
+
this.off(event, handler);
|
|
345
|
+
reject(new Error(`Timeout waiting for event '${event}'`));
|
|
346
|
+
}, timeout);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
this.once(event, handler);
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Collect events into batches
|
|
355
|
+
* @param {string} event - Event name
|
|
356
|
+
* @param {number} size - Batch size
|
|
357
|
+
* @param {Function} callback - Handler for batch
|
|
358
|
+
*/
|
|
359
|
+
batch(event, size, callback) {
|
|
360
|
+
const buffer = [];
|
|
361
|
+
|
|
362
|
+
this.on(event, (data) => {
|
|
363
|
+
buffer.push(data);
|
|
364
|
+
|
|
365
|
+
if (buffer.length >= size) {
|
|
366
|
+
callback([...buffer]);
|
|
367
|
+
buffer.length = 0;
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
return this;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Debounce an event (emit only after silence)
|
|
376
|
+
* @param {string} event - Event name
|
|
377
|
+
* @param {number} delay - Delay in ms
|
|
378
|
+
* @param {Function} callback - Handler function
|
|
379
|
+
*/
|
|
380
|
+
debounce(event, delay, callback) {
|
|
381
|
+
let timeoutId = null;
|
|
382
|
+
let lastData = null;
|
|
383
|
+
|
|
384
|
+
this.on(event, (data) => {
|
|
385
|
+
lastData = data;
|
|
386
|
+
|
|
387
|
+
if (timeoutId) {
|
|
388
|
+
clearTimeout(timeoutId);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
timeoutId = setTimeout(() => {
|
|
392
|
+
callback(lastData);
|
|
393
|
+
timeoutId = null;
|
|
394
|
+
}, delay);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
return this;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* AlephMonitor - High-level monitoring for AlephEngine
|
|
403
|
+
*
|
|
404
|
+
* Wraps an AlephEngine and emits structured events.
|
|
405
|
+
*/
|
|
406
|
+
class AlephMonitor {
|
|
407
|
+
/**
|
|
408
|
+
* @param {object} engine - AlephEngine instance
|
|
409
|
+
* @param {object} options - Configuration
|
|
410
|
+
*/
|
|
411
|
+
constructor(engine, options = {}) {
|
|
412
|
+
this.engine = engine;
|
|
413
|
+
this.emitter = new AlephEventEmitter({
|
|
414
|
+
maxHistory: options.maxHistory ?? 1000
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
// Thresholds
|
|
418
|
+
this.thresholds = {
|
|
419
|
+
entropyLow: options.entropyLow ?? 1.0,
|
|
420
|
+
entropyHigh: options.entropyHigh ?? 3.0,
|
|
421
|
+
coherenceHigh: options.coherenceHigh ?? 0.8,
|
|
422
|
+
resonanceStrong: options.resonanceStrong ?? 0.7,
|
|
423
|
+
syncThreshold: options.syncThreshold ?? 0.7
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
// State tracking
|
|
427
|
+
this._lastState = null;
|
|
428
|
+
this._stepCount = 0;
|
|
429
|
+
this._startTime = Date.now();
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Get event emitter for subscribing
|
|
434
|
+
*/
|
|
435
|
+
getEmitter() {
|
|
436
|
+
return this.emitter;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Convenience method to subscribe to events
|
|
441
|
+
*/
|
|
442
|
+
on(event, callback) {
|
|
443
|
+
this.emitter.on(event, callback);
|
|
444
|
+
return this;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Wrap engine.tick() with monitoring
|
|
449
|
+
* @param {number} dt - Time step
|
|
450
|
+
*/
|
|
451
|
+
tick(dt) {
|
|
452
|
+
const prevState = this._lastState;
|
|
453
|
+
|
|
454
|
+
// Call engine tick
|
|
455
|
+
this.engine.tick(dt);
|
|
456
|
+
|
|
457
|
+
// Get current state
|
|
458
|
+
const state = this.engine.getPhysicsState();
|
|
459
|
+
this._lastState = state;
|
|
460
|
+
this._stepCount++;
|
|
461
|
+
|
|
462
|
+
// Emit tick event
|
|
463
|
+
this.emitter.emit('tick', {
|
|
464
|
+
t: this._stepCount,
|
|
465
|
+
dt,
|
|
466
|
+
entropy: state.entropy,
|
|
467
|
+
coherence: state.coherence,
|
|
468
|
+
orderParameter: state.orderParameter,
|
|
469
|
+
stability: state.stability,
|
|
470
|
+
coupling: state.coupling
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
// Check for threshold crossings
|
|
474
|
+
this._checkThresholds(state, prevState);
|
|
475
|
+
|
|
476
|
+
return state;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Check threshold crossings and emit events
|
|
481
|
+
* @private
|
|
482
|
+
*/
|
|
483
|
+
_checkThresholds(state, prevState) {
|
|
484
|
+
// Entropy crossings
|
|
485
|
+
if (state.entropy < this.thresholds.entropyLow) {
|
|
486
|
+
if (!prevState || prevState.entropy >= this.thresholds.entropyLow) {
|
|
487
|
+
this.emitter.emit('entropy:low', {
|
|
488
|
+
value: state.entropy,
|
|
489
|
+
threshold: this.thresholds.entropyLow
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (state.entropy > this.thresholds.entropyHigh) {
|
|
495
|
+
if (!prevState || prevState.entropy <= this.thresholds.entropyHigh) {
|
|
496
|
+
this.emitter.emit('entropy:high', {
|
|
497
|
+
value: state.entropy,
|
|
498
|
+
threshold: this.thresholds.entropyHigh
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// Synchronization
|
|
504
|
+
if (state.orderParameter > this.thresholds.syncThreshold) {
|
|
505
|
+
if (!prevState || prevState.orderParameter <= this.thresholds.syncThreshold) {
|
|
506
|
+
this.emitter.emit('sync', {
|
|
507
|
+
orderParameter: state.orderParameter,
|
|
508
|
+
threshold: this.thresholds.syncThreshold
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Coherence
|
|
514
|
+
if (state.coherence > this.thresholds.coherenceHigh) {
|
|
515
|
+
if (!prevState || prevState.coherence <= this.thresholds.coherenceHigh) {
|
|
516
|
+
this.emitter.emit('coherence:high', {
|
|
517
|
+
value: state.coherence,
|
|
518
|
+
threshold: this.thresholds.coherenceHigh
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Emit collapse event
|
|
526
|
+
* @param {object} from - State before collapse
|
|
527
|
+
* @param {object} to - State after collapse
|
|
528
|
+
* @param {number} probability - Collapse probability
|
|
529
|
+
*/
|
|
530
|
+
emitCollapse(from, to, probability) {
|
|
531
|
+
this.emitter.emit('collapse', { from, to, probability });
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Emit resonance event
|
|
536
|
+
* @param {number[]} primes - Resonating primes
|
|
537
|
+
* @param {number} strength - Resonance strength
|
|
538
|
+
*/
|
|
539
|
+
emitResonance(primes, strength) {
|
|
540
|
+
if (strength > this.thresholds.resonanceStrong) {
|
|
541
|
+
this.emitter.emit('resonance', { primes, strength });
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Wrap engine.run() with monitoring
|
|
547
|
+
* @param {string} input - Input to process
|
|
548
|
+
*/
|
|
549
|
+
run(input) {
|
|
550
|
+
const startTime = Date.now();
|
|
551
|
+
|
|
552
|
+
this.emitter.emit('run:start', { input, startTime });
|
|
553
|
+
|
|
554
|
+
const result = this.engine.run(input);
|
|
555
|
+
|
|
556
|
+
const endTime = Date.now();
|
|
557
|
+
|
|
558
|
+
this.emitter.emit('run:complete', {
|
|
559
|
+
input,
|
|
560
|
+
output: result.output,
|
|
561
|
+
entropy: result.entropy,
|
|
562
|
+
coherence: result.coherence,
|
|
563
|
+
fieldBased: result.fieldBased,
|
|
564
|
+
duration: endTime - startTime
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
// Check for collapse
|
|
568
|
+
if (result.collapsed) {
|
|
569
|
+
this.emitCollapse(
|
|
570
|
+
{ entropy: result.entropy, primes: result.inputPrimes },
|
|
571
|
+
{ primes: result.resultPrimes },
|
|
572
|
+
result.collapseProbability || 1.0
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return result;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Get monitoring statistics
|
|
581
|
+
*/
|
|
582
|
+
getStats() {
|
|
583
|
+
return {
|
|
584
|
+
stepCount: this._stepCount,
|
|
585
|
+
runTime: Date.now() - this._startTime,
|
|
586
|
+
events: this.emitter.getStats()
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Reset monitor state
|
|
592
|
+
*/
|
|
593
|
+
reset() {
|
|
594
|
+
this._lastState = null;
|
|
595
|
+
this._stepCount = 0;
|
|
596
|
+
this._startTime = Date.now();
|
|
597
|
+
this.emitter.clearHistory();
|
|
598
|
+
this.emitter.resetStats();
|
|
599
|
+
return this;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* EvolutionStream - Async iterator for engine evolution
|
|
605
|
+
*
|
|
606
|
+
* Enables for-await-of loops over engine state.
|
|
607
|
+
*/
|
|
608
|
+
class EvolutionStream {
|
|
609
|
+
/**
|
|
610
|
+
* @param {object} engine - AlephEngine instance or evolvable object
|
|
611
|
+
* @param {object} options - Configuration
|
|
612
|
+
*/
|
|
613
|
+
constructor(engine, options = {}) {
|
|
614
|
+
this.engine = engine;
|
|
615
|
+
this.dt = options.dt ?? 0.01;
|
|
616
|
+
this.maxSteps = options.maxSteps ?? Infinity;
|
|
617
|
+
this.stopCondition = options.stopCondition ?? null;
|
|
618
|
+
this._step = 0;
|
|
619
|
+
this._stopped = false;
|
|
620
|
+
|
|
621
|
+
// Adapter functions for different engine types
|
|
622
|
+
this._tick = options.tickFn ?? ((dt) => {
|
|
623
|
+
if (typeof this.engine.tick === 'function') {
|
|
624
|
+
this.engine.tick(dt);
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
this._getState = options.getStateFn ?? (() => {
|
|
629
|
+
if (typeof this.engine.getPhysicsState === 'function') {
|
|
630
|
+
return this.engine.getPhysicsState();
|
|
631
|
+
}
|
|
632
|
+
// Try common patterns
|
|
633
|
+
const state = {};
|
|
634
|
+
if (typeof this.engine.orderParameter === 'function') {
|
|
635
|
+
state.orderParameter = this.engine.orderParameter();
|
|
636
|
+
}
|
|
637
|
+
if (typeof this.engine.synchronization === 'function') {
|
|
638
|
+
state.synchronization = this.engine.synchronization();
|
|
639
|
+
}
|
|
640
|
+
if (typeof this.engine.entropy === 'function') {
|
|
641
|
+
state.entropy = this.engine.entropy();
|
|
642
|
+
}
|
|
643
|
+
if (this.engine.oscillators) {
|
|
644
|
+
state.oscillators = this.engine.oscillators.length;
|
|
645
|
+
}
|
|
646
|
+
return state;
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Create stream from any evolvable object
|
|
652
|
+
* @param {object} evolvable - Object with tick-like method
|
|
653
|
+
* @param {object} options - Configuration
|
|
654
|
+
*/
|
|
655
|
+
static fromEvolvable(evolvable, options = {}) {
|
|
656
|
+
return new EvolutionStream(evolvable, options);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Stop the stream
|
|
661
|
+
*/
|
|
662
|
+
stop() {
|
|
663
|
+
this._stopped = true;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Make stream async iterable
|
|
668
|
+
*/
|
|
669
|
+
async *[Symbol.asyncIterator]() {
|
|
670
|
+
while (!this._stopped && this._step < this.maxSteps) {
|
|
671
|
+
this._tick(this.dt);
|
|
672
|
+
|
|
673
|
+
const state = this._getState();
|
|
674
|
+
const data = {
|
|
675
|
+
step: this._step,
|
|
676
|
+
t: this._step * this.dt,
|
|
677
|
+
...state
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
yield data;
|
|
681
|
+
|
|
682
|
+
// Check stop condition
|
|
683
|
+
if (this.stopCondition && this.stopCondition(data)) {
|
|
684
|
+
this._stopped = true;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
this._step++;
|
|
688
|
+
|
|
689
|
+
// Yield to event loop
|
|
690
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Collect stream into array
|
|
696
|
+
* @param {number} maxItems - Maximum items to collect
|
|
697
|
+
*/
|
|
698
|
+
async collect(maxItems = 1000) {
|
|
699
|
+
const items = [];
|
|
700
|
+
|
|
701
|
+
for await (const state of this) {
|
|
702
|
+
items.push(state);
|
|
703
|
+
if (items.length >= maxItems) break;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
return items;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* Batch items into groups
|
|
711
|
+
* @param {number} size - Batch size
|
|
712
|
+
*/
|
|
713
|
+
batch(size) {
|
|
714
|
+
const source = this;
|
|
715
|
+
|
|
716
|
+
return {
|
|
717
|
+
async *[Symbol.asyncIterator]() {
|
|
718
|
+
let batch = [];
|
|
719
|
+
for await (const state of source) {
|
|
720
|
+
batch.push(state);
|
|
721
|
+
if (batch.length >= size) {
|
|
722
|
+
yield batch;
|
|
723
|
+
batch = [];
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
if (batch.length > 0) {
|
|
727
|
+
yield batch;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* Apply filter to stream
|
|
735
|
+
* @param {Function} predicate - Filter function
|
|
736
|
+
*/
|
|
737
|
+
filter(predicate) {
|
|
738
|
+
const source = this;
|
|
739
|
+
|
|
740
|
+
const result = {
|
|
741
|
+
async *[Symbol.asyncIterator]() {
|
|
742
|
+
for await (const state of source) {
|
|
743
|
+
if (predicate(state)) {
|
|
744
|
+
yield state;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
},
|
|
748
|
+
take(n) {
|
|
749
|
+
return EvolutionStream.prototype.take.call({ [Symbol.asyncIterator]: result[Symbol.asyncIterator] }, n);
|
|
750
|
+
},
|
|
751
|
+
collect(max) {
|
|
752
|
+
return EvolutionStream.prototype.collect.call({ [Symbol.asyncIterator]: result[Symbol.asyncIterator] }, max);
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
return result;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Apply transform to stream
|
|
760
|
+
* @param {Function} transform - Transform function
|
|
761
|
+
*/
|
|
762
|
+
map(transform) {
|
|
763
|
+
const source = this;
|
|
764
|
+
|
|
765
|
+
const result = {
|
|
766
|
+
async *[Symbol.asyncIterator]() {
|
|
767
|
+
for await (const state of source) {
|
|
768
|
+
yield transform(state);
|
|
769
|
+
}
|
|
770
|
+
},
|
|
771
|
+
take(n) {
|
|
772
|
+
return EvolutionStream.prototype.take.call({ [Symbol.asyncIterator]: result[Symbol.asyncIterator] }, n);
|
|
773
|
+
},
|
|
774
|
+
collect(max) {
|
|
775
|
+
return EvolutionStream.prototype.collect.call({ [Symbol.asyncIterator]: result[Symbol.asyncIterator] }, max);
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
return result;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Take first n items
|
|
783
|
+
* @param {number} n - Number of items
|
|
784
|
+
*/
|
|
785
|
+
take(n) {
|
|
786
|
+
const source = this;
|
|
787
|
+
|
|
788
|
+
const result = {
|
|
789
|
+
async *[Symbol.asyncIterator]() {
|
|
790
|
+
let count = 0;
|
|
791
|
+
for await (const state of source) {
|
|
792
|
+
yield state;
|
|
793
|
+
count++;
|
|
794
|
+
if (count >= n) break;
|
|
795
|
+
}
|
|
796
|
+
},
|
|
797
|
+
async collect(max) {
|
|
798
|
+
const items = [];
|
|
799
|
+
for await (const state of this) {
|
|
800
|
+
items.push(state);
|
|
801
|
+
if (max && items.length >= max) break;
|
|
802
|
+
}
|
|
803
|
+
return items;
|
|
804
|
+
},
|
|
805
|
+
async reduce(reducer, initial) {
|
|
806
|
+
let acc = initial;
|
|
807
|
+
for await (const state of this) {
|
|
808
|
+
acc = reducer(acc, state);
|
|
809
|
+
}
|
|
810
|
+
return acc;
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
return result;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* Skip first n items
|
|
818
|
+
* @param {number} n - Number of items to skip
|
|
819
|
+
*/
|
|
820
|
+
skip(n) {
|
|
821
|
+
const source = this;
|
|
822
|
+
|
|
823
|
+
return {
|
|
824
|
+
async *[Symbol.asyncIterator]() {
|
|
825
|
+
let count = 0;
|
|
826
|
+
for await (const state of source) {
|
|
827
|
+
if (count >= n) {
|
|
828
|
+
yield state;
|
|
829
|
+
}
|
|
830
|
+
count++;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* Take while condition is true
|
|
838
|
+
* @param {Function} predicate - Condition function
|
|
839
|
+
*/
|
|
840
|
+
takeWhile(predicate) {
|
|
841
|
+
const source = this;
|
|
842
|
+
|
|
843
|
+
return {
|
|
844
|
+
async *[Symbol.asyncIterator]() {
|
|
845
|
+
for await (const state of source) {
|
|
846
|
+
if (!predicate(state)) break;
|
|
847
|
+
yield state;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* Reduce stream to single value
|
|
855
|
+
* @param {Function} reducer - Reducer function
|
|
856
|
+
* @param {*} initial - Initial value
|
|
857
|
+
*/
|
|
858
|
+
async reduce(reducer, initial) {
|
|
859
|
+
let acc = initial;
|
|
860
|
+
|
|
861
|
+
for await (const state of this) {
|
|
862
|
+
acc = reducer(acc, state);
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
return acc;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
/**
|
|
869
|
+
* Find first matching item
|
|
870
|
+
* @param {Function} predicate - Match function
|
|
871
|
+
*/
|
|
872
|
+
async find(predicate) {
|
|
873
|
+
for await (const state of this) {
|
|
874
|
+
if (predicate(state)) {
|
|
875
|
+
this.stop();
|
|
876
|
+
return state;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
return null;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* Create monitored evolution stream
|
|
885
|
+
* @param {object} engine - AlephEngine instance
|
|
886
|
+
* @param {object} options - Configuration
|
|
887
|
+
*/
|
|
888
|
+
function createEvolutionStream(engine, options = {}) {
|
|
889
|
+
return new EvolutionStream(engine, options);
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* Create monitor for engine
|
|
894
|
+
* @param {object} engine - AlephEngine instance
|
|
895
|
+
* @param {object} options - Configuration
|
|
896
|
+
*/
|
|
897
|
+
function createMonitor(engine, options = {}) {
|
|
898
|
+
return new AlephMonitor(engine, options);
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
module.exports = {
|
|
902
|
+
AlephEventEmitter,
|
|
903
|
+
AlephMonitor,
|
|
904
|
+
EvolutionStream,
|
|
905
|
+
createEvolutionStream,
|
|
906
|
+
createMonitor
|
|
907
|
+
};
|