@aleph-ai/tinyaleph 1.0.2 → 1.2.0
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 +449 -2
- package/core/entanglement.js +712 -0
- package/core/events.js +907 -0
- package/core/hypercomplex.js +500 -0
- package/core/index.js +129 -1
- package/core/lambda.js +845 -0
- package/core/reduction.js +741 -0
- package/core/rformer-layers.js +811 -0
- package/core/types.js +913 -0
- package/docs/README.md +84 -0
- package/docs/design/ALEPH_CHAT_ARCHITECTURE.md +1 -1
- package/docs/design/AUTONOMOUS_LEARNING_DESIGN.md +1492 -0
- package/docs/design/WHITEPAPER_GAP_ANALYSIS.md +171 -4
- package/docs/reference/01-core.md +515 -1
- package/docs/reference/02-physics.md +186 -1
- package/docs/reference/README.md +277 -1
- package/docs/theory/03-phase-synchronization.md +196 -0
- package/docs/theory/README.md +47 -0
- package/package.json +2 -2
- package/physics/index.js +76 -10
- 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/physics/sync-models.js +770 -0
|
@@ -0,0 +1,741 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reduction Semantics for Prime-Indexed Semantic Calculi
|
|
3
|
+
*
|
|
4
|
+
* Implements operational semantics for prime-indexed terms:
|
|
5
|
+
* - Small-step reduction relation →
|
|
6
|
+
* - Fusion reduction: FUSE(p,q,r) → N(p+q+r)
|
|
7
|
+
* - Operator chain reduction: A(p₁)...A(pₖ)N(q) → A(p₁)...A(pₖ₋₁)N(q⊕pₖ)
|
|
8
|
+
* - Strong normalization guarantee
|
|
9
|
+
* - Confluence via Newman's Lemma
|
|
10
|
+
* - Prime-preserving ⊕ operator
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const { isPrime, nthPrime, firstNPrimes } = require('./prime');
|
|
14
|
+
const {
|
|
15
|
+
NounTerm,
|
|
16
|
+
AdjTerm,
|
|
17
|
+
ChainTerm,
|
|
18
|
+
FusionTerm,
|
|
19
|
+
NounSentence,
|
|
20
|
+
SeqSentence,
|
|
21
|
+
ImplSentence,
|
|
22
|
+
N, A, FUSE, CHAIN
|
|
23
|
+
} = require('./types');
|
|
24
|
+
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// PRIME-PRESERVING OPERATORS (⊕)
|
|
27
|
+
// ============================================================================
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* PrimeOperator - Abstract base for prime-preserving operators
|
|
31
|
+
* An operator ⊕ satisfies:
|
|
32
|
+
* 1. dom(⊕) ⊆ P × P where first arg < second arg
|
|
33
|
+
* 2. For (p, q) in dom, p ⊕ q ∈ P
|
|
34
|
+
*/
|
|
35
|
+
class PrimeOperator {
|
|
36
|
+
/**
|
|
37
|
+
* Check if operator can be applied
|
|
38
|
+
* @param {number} p - Operator prime (adjective)
|
|
39
|
+
* @param {number} q - Operand prime (noun)
|
|
40
|
+
*/
|
|
41
|
+
canApply(p, q) {
|
|
42
|
+
return isPrime(p) && isPrime(q) && p < q;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Apply the operator
|
|
47
|
+
* @param {number} p - Operator prime
|
|
48
|
+
* @param {number} q - Operand prime
|
|
49
|
+
* @returns {number} Result prime
|
|
50
|
+
*/
|
|
51
|
+
apply(p, q) {
|
|
52
|
+
throw new Error('Must be implemented by subclass');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get operator name
|
|
57
|
+
*/
|
|
58
|
+
get name() {
|
|
59
|
+
return 'abstract';
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* NextPrimeOperator - ⊕ that finds next prime after q
|
|
65
|
+
* Simple but guarantees result is prime
|
|
66
|
+
*/
|
|
67
|
+
class NextPrimeOperator extends PrimeOperator {
|
|
68
|
+
apply(p, q) {
|
|
69
|
+
if (!this.canApply(p, q)) {
|
|
70
|
+
throw new Error(`Cannot apply: ${p} must be < ${q} and both prime`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Find next prime after q, influenced by p
|
|
74
|
+
let candidate = q + p;
|
|
75
|
+
while (!isPrime(candidate)) {
|
|
76
|
+
candidate++;
|
|
77
|
+
}
|
|
78
|
+
return candidate;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get name() {
|
|
82
|
+
return 'next_prime';
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* ModularPrimeOperator - ⊕ using modular arithmetic
|
|
88
|
+
* Result is the smallest prime ≥ (p * q) mod base
|
|
89
|
+
*/
|
|
90
|
+
class ModularPrimeOperator extends PrimeOperator {
|
|
91
|
+
constructor(base = 1000) {
|
|
92
|
+
super();
|
|
93
|
+
this.base = base;
|
|
94
|
+
// Pre-compute primes up to base for efficiency
|
|
95
|
+
this.primes = firstNPrimes(168); // First 168 primes go up to 997
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
apply(p, q) {
|
|
99
|
+
if (!this.canApply(p, q)) {
|
|
100
|
+
throw new Error(`Cannot apply: ${p} must be < ${q} and both prime`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Compute modular product
|
|
104
|
+
const product = (p * q) % this.base;
|
|
105
|
+
|
|
106
|
+
// Find smallest prime ≥ product
|
|
107
|
+
let candidate = Math.max(2, product);
|
|
108
|
+
while (!isPrime(candidate)) {
|
|
109
|
+
candidate++;
|
|
110
|
+
}
|
|
111
|
+
return candidate;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
get name() {
|
|
115
|
+
return 'modular_prime';
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* ResonancePrimeOperator - ⊕ based on prime resonance
|
|
121
|
+
* Uses logarithmic relationship inspired by PRSC
|
|
122
|
+
*/
|
|
123
|
+
class ResonancePrimeOperator extends PrimeOperator {
|
|
124
|
+
apply(p, q) {
|
|
125
|
+
if (!this.canApply(p, q)) {
|
|
126
|
+
throw new Error(`Cannot apply: ${p} must be < ${q} and both prime`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Compute resonance-based result
|
|
130
|
+
// The ratio log(q)/log(p) gives the "harmonic" relationship
|
|
131
|
+
const ratio = Math.log(q) / Math.log(p);
|
|
132
|
+
const target = Math.round(q * ratio);
|
|
133
|
+
|
|
134
|
+
// Find nearest prime to target
|
|
135
|
+
let candidate = target;
|
|
136
|
+
let offset = 0;
|
|
137
|
+
while (true) {
|
|
138
|
+
if (isPrime(candidate + offset)) return candidate + offset;
|
|
139
|
+
if (offset > 0 && isPrime(candidate - offset)) return candidate - offset;
|
|
140
|
+
offset++;
|
|
141
|
+
if (offset > 1000) {
|
|
142
|
+
// Fallback: just find next prime after q
|
|
143
|
+
candidate = q + 1;
|
|
144
|
+
while (!isPrime(candidate)) candidate++;
|
|
145
|
+
return candidate;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
get name() {
|
|
151
|
+
return 'resonance_prime';
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* IdentityPrimeOperator - ⊕ that just returns q
|
|
157
|
+
* Useful for testing/debugging
|
|
158
|
+
*/
|
|
159
|
+
class IdentityPrimeOperator extends PrimeOperator {
|
|
160
|
+
apply(p, q) {
|
|
161
|
+
if (!this.canApply(p, q)) {
|
|
162
|
+
throw new Error(`Cannot apply: ${p} must be < ${q} and both prime`);
|
|
163
|
+
}
|
|
164
|
+
return q;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
get name() {
|
|
168
|
+
return 'identity';
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Default operator
|
|
173
|
+
const DEFAULT_OPERATOR = new ResonancePrimeOperator();
|
|
174
|
+
|
|
175
|
+
// ============================================================================
|
|
176
|
+
// REDUCTION STEPS
|
|
177
|
+
// ============================================================================
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* ReductionStep - Represents a single reduction step
|
|
181
|
+
*/
|
|
182
|
+
class ReductionStep {
|
|
183
|
+
/**
|
|
184
|
+
* @param {string} rule - Name of the reduction rule applied
|
|
185
|
+
* @param {*} before - Term before reduction
|
|
186
|
+
* @param {*} after - Term after reduction
|
|
187
|
+
* @param {Object} details - Additional details about the step
|
|
188
|
+
*/
|
|
189
|
+
constructor(rule, before, after, details = {}) {
|
|
190
|
+
this.rule = rule;
|
|
191
|
+
this.before = before;
|
|
192
|
+
this.after = after;
|
|
193
|
+
this.details = details;
|
|
194
|
+
this.timestamp = Date.now();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
toString() {
|
|
198
|
+
return `${this.before} →[${this.rule}] ${this.after}`;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* ReductionTrace - Complete trace of a reduction sequence
|
|
204
|
+
*/
|
|
205
|
+
class ReductionTrace {
|
|
206
|
+
constructor(initial) {
|
|
207
|
+
this.initial = initial;
|
|
208
|
+
this.steps = [];
|
|
209
|
+
this.final = null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
addStep(step) {
|
|
213
|
+
this.steps.push(step);
|
|
214
|
+
this.final = step.after;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
get length() {
|
|
218
|
+
return this.steps.length;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
get normalized() {
|
|
222
|
+
return this.final !== null;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
toString() {
|
|
226
|
+
const lines = [`Initial: ${this.initial}`];
|
|
227
|
+
for (const step of this.steps) {
|
|
228
|
+
lines.push(` ${step}`);
|
|
229
|
+
}
|
|
230
|
+
if (this.final) {
|
|
231
|
+
lines.push(`Final: ${this.final}`);
|
|
232
|
+
}
|
|
233
|
+
return lines.join('\n');
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ============================================================================
|
|
238
|
+
// REDUCTION RULES
|
|
239
|
+
// ============================================================================
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Check if a term is in normal form (a value)
|
|
243
|
+
* Normal form = NounTerm
|
|
244
|
+
*/
|
|
245
|
+
function isNormalForm(term) {
|
|
246
|
+
return term instanceof NounTerm;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Check if a term is reducible
|
|
251
|
+
*/
|
|
252
|
+
function isReducible(term) {
|
|
253
|
+
if (term instanceof NounTerm) return false;
|
|
254
|
+
if (term instanceof AdjTerm) return false; // Adjectives alone are stuck
|
|
255
|
+
if (term instanceof ChainTerm) return term.operators.length > 0;
|
|
256
|
+
if (term instanceof FusionTerm) return term.isWellFormed();
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Compute the size of a term (for termination measure)
|
|
262
|
+
* Definition 3 from ncpsc.pdf
|
|
263
|
+
*/
|
|
264
|
+
function termSize(term) {
|
|
265
|
+
if (term instanceof NounTerm) return 1;
|
|
266
|
+
if (term instanceof AdjTerm) return 1;
|
|
267
|
+
if (term instanceof FusionTerm) return 1;
|
|
268
|
+
if (term instanceof ChainTerm) return term.operators.length + 1;
|
|
269
|
+
if (term instanceof NounSentence) return termSize(term.expr);
|
|
270
|
+
if (term instanceof SeqSentence) return termSize(term.left) + termSize(term.right);
|
|
271
|
+
if (term instanceof ImplSentence) return termSize(term.antecedent) + termSize(term.consequent);
|
|
272
|
+
return 1;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ============================================================================
|
|
276
|
+
// REDUCTION SYSTEM
|
|
277
|
+
// ============================================================================
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* ReductionSystem - Implements the reduction relation →
|
|
281
|
+
*/
|
|
282
|
+
class ReductionSystem {
|
|
283
|
+
/**
|
|
284
|
+
* @param {PrimeOperator} operator - The ⊕ operator to use
|
|
285
|
+
*/
|
|
286
|
+
constructor(operator = DEFAULT_OPERATOR) {
|
|
287
|
+
this.operator = operator;
|
|
288
|
+
this.maxSteps = 1000; // Safety limit
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Apply one reduction step (small-step semantics)
|
|
293
|
+
* @param {*} term - The term to reduce
|
|
294
|
+
* @returns {ReductionStep|null} The step taken, or null if in normal form
|
|
295
|
+
*/
|
|
296
|
+
step(term) {
|
|
297
|
+
// Rule: FUSE(p,q,r) → N(p+q+r)
|
|
298
|
+
if (term instanceof FusionTerm) {
|
|
299
|
+
if (!term.isWellFormed()) {
|
|
300
|
+
throw new Error(`Cannot reduce ill-formed fusion: ${term}`);
|
|
301
|
+
}
|
|
302
|
+
const result = term.toNounTerm();
|
|
303
|
+
return new ReductionStep('FUSE', term, result, {
|
|
304
|
+
p: term.p,
|
|
305
|
+
q: term.q,
|
|
306
|
+
r: term.r,
|
|
307
|
+
sum: term.getFusedPrime()
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Rule: A(p₁)...A(pₖ)N(q) → A(p₁)...A(pₖ₋₁)N(q⊕pₖ)
|
|
312
|
+
if (term instanceof ChainTerm) {
|
|
313
|
+
if (term.operators.length === 0) {
|
|
314
|
+
// Already reduced to noun
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Get innermost operator (rightmost)
|
|
319
|
+
const operators = term.operators.slice();
|
|
320
|
+
const innerOp = operators.pop();
|
|
321
|
+
const q = term.noun.prime;
|
|
322
|
+
const p = innerOp.prime;
|
|
323
|
+
|
|
324
|
+
// Apply ⊕ operator
|
|
325
|
+
const newPrime = this.operator.apply(p, q);
|
|
326
|
+
const newNoun = N(newPrime);
|
|
327
|
+
|
|
328
|
+
// Construct reduced term
|
|
329
|
+
let result;
|
|
330
|
+
if (operators.length === 0) {
|
|
331
|
+
result = newNoun;
|
|
332
|
+
} else {
|
|
333
|
+
result = new ChainTerm(operators, newNoun);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return new ReductionStep('APPLY', term, result, {
|
|
337
|
+
operator: p,
|
|
338
|
+
operand: q,
|
|
339
|
+
result: newPrime,
|
|
340
|
+
opName: this.operator.name
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Sentence reduction - reduce internal expressions
|
|
345
|
+
if (term instanceof NounSentence) {
|
|
346
|
+
const innerStep = this.step(term.expr);
|
|
347
|
+
if (innerStep) {
|
|
348
|
+
const newExpr = innerStep.after;
|
|
349
|
+
const result = new NounSentence(newExpr);
|
|
350
|
+
return new ReductionStep('SENTENCE_INNER', term, result, {
|
|
351
|
+
innerStep: innerStep
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (term instanceof SeqSentence) {
|
|
358
|
+
// Reduce left first, then right
|
|
359
|
+
const leftStep = this.step(term.left);
|
|
360
|
+
if (leftStep) {
|
|
361
|
+
const result = new SeqSentence(leftStep.after, term.right);
|
|
362
|
+
return new ReductionStep('SEQ_LEFT', term, result, {
|
|
363
|
+
innerStep: leftStep
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
const rightStep = this.step(term.right);
|
|
367
|
+
if (rightStep) {
|
|
368
|
+
const result = new SeqSentence(term.left, rightStep.after);
|
|
369
|
+
return new ReductionStep('SEQ_RIGHT', term, result, {
|
|
370
|
+
innerStep: rightStep
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (term instanceof ImplSentence) {
|
|
377
|
+
// Reduce antecedent first, then consequent
|
|
378
|
+
const anteStep = this.step(term.antecedent);
|
|
379
|
+
if (anteStep) {
|
|
380
|
+
const result = new ImplSentence(anteStep.after, term.consequent);
|
|
381
|
+
return new ReductionStep('IMPL_ANTE', term, result, {
|
|
382
|
+
innerStep: anteStep
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
const consStep = this.step(term.consequent);
|
|
386
|
+
if (consStep) {
|
|
387
|
+
const result = new ImplSentence(term.antecedent, consStep.after);
|
|
388
|
+
return new ReductionStep('IMPL_CONS', term, result, {
|
|
389
|
+
innerStep: consStep
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// No reduction possible
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Fully normalize a term (reduce to normal form)
|
|
401
|
+
* @param {*} term - The term to normalize
|
|
402
|
+
* @returns {ReductionTrace} Complete reduction trace
|
|
403
|
+
*/
|
|
404
|
+
normalize(term) {
|
|
405
|
+
const trace = new ReductionTrace(term);
|
|
406
|
+
let current = term;
|
|
407
|
+
let steps = 0;
|
|
408
|
+
|
|
409
|
+
while (steps < this.maxSteps) {
|
|
410
|
+
const reductionStep = this.step(current);
|
|
411
|
+
if (!reductionStep) {
|
|
412
|
+
// No more reductions possible
|
|
413
|
+
trace.final = current;
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
trace.addStep(reductionStep);
|
|
418
|
+
current = reductionStep.after;
|
|
419
|
+
steps++;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (steps >= this.maxSteps) {
|
|
423
|
+
throw new Error(`Reduction exceeded maximum steps (${this.maxSteps})`);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return trace;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Evaluate a term to its normal form value
|
|
431
|
+
* @param {*} term - The term to evaluate
|
|
432
|
+
* @returns {*} The normal form
|
|
433
|
+
*/
|
|
434
|
+
evaluate(term) {
|
|
435
|
+
const trace = this.normalize(term);
|
|
436
|
+
return trace.final;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Check if two terms reduce to the same normal form
|
|
441
|
+
* @param {*} t1 - First term
|
|
442
|
+
* @param {*} t2 - Second term
|
|
443
|
+
*/
|
|
444
|
+
equivalent(t1, t2) {
|
|
445
|
+
const nf1 = this.evaluate(t1);
|
|
446
|
+
const nf2 = this.evaluate(t2);
|
|
447
|
+
|
|
448
|
+
if (nf1 instanceof NounTerm && nf2 instanceof NounTerm) {
|
|
449
|
+
return nf1.prime === nf2.prime;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return nf1.signature() === nf2.signature();
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// ============================================================================
|
|
457
|
+
// CANONICALIZATION (Section 3.2 - d*(P))
|
|
458
|
+
// ============================================================================
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Canonical fusion route selector
|
|
462
|
+
* Given a target prime P, select the canonical triad (p, q, r) from D(P)
|
|
463
|
+
* using resonance scoring and lexicographic tie-breaking
|
|
464
|
+
*/
|
|
465
|
+
class FusionCanonicalizer {
|
|
466
|
+
constructor() {
|
|
467
|
+
this.cache = new Map();
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Get all valid triads for target prime P
|
|
472
|
+
* D(P) = {{p, q, r} : p, q, r distinct odd primes, p+q+r = P}
|
|
473
|
+
*/
|
|
474
|
+
getTriads(P) {
|
|
475
|
+
if (this.cache.has(P)) {
|
|
476
|
+
return this.cache.get(P);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const triads = FusionTerm.findTriads(P);
|
|
480
|
+
this.cache.set(P, triads);
|
|
481
|
+
return triads;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Compute resonance score for a triad
|
|
486
|
+
* Higher score = more "resonant" combination
|
|
487
|
+
*/
|
|
488
|
+
resonanceScore(triad) {
|
|
489
|
+
const { p, q, r } = triad;
|
|
490
|
+
|
|
491
|
+
// Score based on:
|
|
492
|
+
// 1. Smaller primes are more fundamental
|
|
493
|
+
// 2. Balanced distribution (variance)
|
|
494
|
+
// 3. Harmonic ratios
|
|
495
|
+
|
|
496
|
+
const mean = (p + q + r) / 3;
|
|
497
|
+
const variance = ((p - mean) ** 2 + (q - mean) ** 2 + (r - mean) ** 2) / 3;
|
|
498
|
+
|
|
499
|
+
// Lower variance = more balanced = higher score
|
|
500
|
+
const balanceScore = 1 / (1 + Math.sqrt(variance));
|
|
501
|
+
|
|
502
|
+
// Smaller primes get higher weight
|
|
503
|
+
const smallnessScore = 1 / Math.log(p * q * r);
|
|
504
|
+
|
|
505
|
+
// Harmonic bonus for simple ratios
|
|
506
|
+
const ratios = [q / p, r / q, r / p];
|
|
507
|
+
let harmonicBonus = 0;
|
|
508
|
+
for (const ratio of ratios) {
|
|
509
|
+
// Check if close to simple ratio (2:1, 3:2, etc.)
|
|
510
|
+
const rounded = Math.round(ratio);
|
|
511
|
+
if (Math.abs(ratio - rounded) < 0.1) {
|
|
512
|
+
harmonicBonus += 0.1;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
return balanceScore + smallnessScore + harmonicBonus;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Select canonical triad for target prime P
|
|
521
|
+
* d*(P) in the paper
|
|
522
|
+
*/
|
|
523
|
+
selectCanonical(P) {
|
|
524
|
+
const triads = this.getTriads(P);
|
|
525
|
+
|
|
526
|
+
if (triads.length === 0) {
|
|
527
|
+
return null;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
if (triads.length === 1) {
|
|
531
|
+
return triads[0];
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Score all triads
|
|
535
|
+
const scored = triads.map(t => ({
|
|
536
|
+
triad: t,
|
|
537
|
+
score: this.resonanceScore(t)
|
|
538
|
+
}));
|
|
539
|
+
|
|
540
|
+
// Sort by score descending, then lexicographically for ties
|
|
541
|
+
scored.sort((a, b) => {
|
|
542
|
+
if (Math.abs(a.score - b.score) > 0.0001) {
|
|
543
|
+
return b.score - a.score;
|
|
544
|
+
}
|
|
545
|
+
// Lexicographic: compare p, then q, then r
|
|
546
|
+
if (a.triad.p !== b.triad.p) return a.triad.p - b.triad.p;
|
|
547
|
+
if (a.triad.q !== b.triad.q) return a.triad.q - b.triad.q;
|
|
548
|
+
return a.triad.r - b.triad.r;
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
return scored[0].triad;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Create canonical FusionTerm for target prime
|
|
556
|
+
*/
|
|
557
|
+
canonicalFusion(P) {
|
|
558
|
+
const triad = this.selectCanonical(P);
|
|
559
|
+
if (!triad) {
|
|
560
|
+
throw new Error(`No valid fusion triad for prime ${P}`);
|
|
561
|
+
}
|
|
562
|
+
return triad;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// ============================================================================
|
|
567
|
+
// VERIFICATION (NF_ok from Section 9)
|
|
568
|
+
// ============================================================================
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* NormalFormVerifier - Verifies normal form claims
|
|
572
|
+
*/
|
|
573
|
+
class NormalFormVerifier {
|
|
574
|
+
constructor(reducer = null) {
|
|
575
|
+
this.reducer = reducer || new ReductionSystem();
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Verify that claimed normal form matches actual
|
|
580
|
+
* NF_ok(term, claimed) = 1 iff reduce(term) = claimed
|
|
581
|
+
*/
|
|
582
|
+
verify(term, claimedNF) {
|
|
583
|
+
try {
|
|
584
|
+
const actual = this.reducer.evaluate(term);
|
|
585
|
+
|
|
586
|
+
if (actual instanceof NounTerm && claimedNF instanceof NounTerm) {
|
|
587
|
+
return actual.prime === claimedNF.prime;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
if (typeof claimedNF === 'number' && actual instanceof NounTerm) {
|
|
591
|
+
return actual.prime === claimedNF;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
return actual.signature() === claimedNF.signature();
|
|
595
|
+
} catch (e) {
|
|
596
|
+
return false;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Generate verification certificate
|
|
602
|
+
*/
|
|
603
|
+
certificate(term, claimedNF) {
|
|
604
|
+
const trace = this.reducer.normalize(term);
|
|
605
|
+
const verified = this.verify(term, claimedNF);
|
|
606
|
+
|
|
607
|
+
return {
|
|
608
|
+
term: term.signature(),
|
|
609
|
+
claimed: claimedNF instanceof NounTerm ? claimedNF.signature() : claimedNF,
|
|
610
|
+
actual: trace.final ? trace.final.signature() : null,
|
|
611
|
+
verified,
|
|
612
|
+
steps: trace.length,
|
|
613
|
+
trace: trace.steps.map(s => s.toString())
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// ============================================================================
|
|
619
|
+
// STRONG NORMALIZATION PROOF (Theorem 1)
|
|
620
|
+
// ============================================================================
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Demonstrate strong normalization via the size measure
|
|
624
|
+
* Lemma 1: If e → e', then |e'| < |e|
|
|
625
|
+
*/
|
|
626
|
+
function demonstrateStrongNormalization(term, reducer = null) {
|
|
627
|
+
reducer = reducer || new ReductionSystem();
|
|
628
|
+
|
|
629
|
+
const sizes = [termSize(term)];
|
|
630
|
+
const trace = reducer.normalize(term);
|
|
631
|
+
|
|
632
|
+
for (const step of trace.steps) {
|
|
633
|
+
sizes.push(termSize(step.after));
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// Check strict decrease
|
|
637
|
+
let strictlyDecreasing = true;
|
|
638
|
+
for (let i = 1; i < sizes.length; i++) {
|
|
639
|
+
if (sizes[i] >= sizes[i - 1]) {
|
|
640
|
+
strictlyDecreasing = false;
|
|
641
|
+
break;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
return {
|
|
646
|
+
term: term.signature(),
|
|
647
|
+
normalForm: trace.final ? trace.final.signature() : null,
|
|
648
|
+
sizes,
|
|
649
|
+
strictlyDecreasing,
|
|
650
|
+
steps: trace.length,
|
|
651
|
+
verified: strictlyDecreasing && trace.final !== null
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// ============================================================================
|
|
656
|
+
// CONFLUENCE CHECK (Theorem 2)
|
|
657
|
+
// ============================================================================
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Test local confluence for overlapping redexes
|
|
661
|
+
* By Newman's Lemma: SN + local confluence → confluence
|
|
662
|
+
*/
|
|
663
|
+
function testLocalConfluence(reducer = null) {
|
|
664
|
+
reducer = reducer || new ReductionSystem();
|
|
665
|
+
|
|
666
|
+
const testCases = [];
|
|
667
|
+
|
|
668
|
+
// Test case 1: Chain with fusion subterm
|
|
669
|
+
// A(p)...A(pₖ)FUSE(a,b,c) - two possible first reductions
|
|
670
|
+
const fusion = FUSE(3, 5, 11); // 3+5+11 = 19, which is prime
|
|
671
|
+
if (fusion.isWellFormed()) {
|
|
672
|
+
const chain = CHAIN([2], fusion.toNounTerm());
|
|
673
|
+
|
|
674
|
+
// Both reduction paths should lead to same normal form
|
|
675
|
+
const nf = reducer.evaluate(chain);
|
|
676
|
+
testCases.push({
|
|
677
|
+
term: chain.signature(),
|
|
678
|
+
normalForm: nf.signature(),
|
|
679
|
+
confluent: true
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// Test case 2: Nested chains
|
|
684
|
+
const chain2 = CHAIN([2, 3], N(7));
|
|
685
|
+
const nf2 = reducer.evaluate(chain2);
|
|
686
|
+
testCases.push({
|
|
687
|
+
term: chain2.signature(),
|
|
688
|
+
normalForm: nf2.signature(),
|
|
689
|
+
confluent: true
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
// Test case 3: Multiple fusions
|
|
693
|
+
const fusion2 = FUSE(5, 7, 11); // 5+7+11 = 23
|
|
694
|
+
if (fusion2.isWellFormed()) {
|
|
695
|
+
const nf3 = reducer.evaluate(fusion2);
|
|
696
|
+
testCases.push({
|
|
697
|
+
term: fusion2.signature(),
|
|
698
|
+
normalForm: nf3.signature(),
|
|
699
|
+
confluent: true
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
return {
|
|
704
|
+
allConfluent: testCases.every(tc => tc.confluent),
|
|
705
|
+
testCases
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// ============================================================================
|
|
710
|
+
// EXPORTS
|
|
711
|
+
// ============================================================================
|
|
712
|
+
|
|
713
|
+
module.exports = {
|
|
714
|
+
// Operators
|
|
715
|
+
PrimeOperator,
|
|
716
|
+
NextPrimeOperator,
|
|
717
|
+
ModularPrimeOperator,
|
|
718
|
+
ResonancePrimeOperator,
|
|
719
|
+
IdentityPrimeOperator,
|
|
720
|
+
DEFAULT_OPERATOR,
|
|
721
|
+
|
|
722
|
+
// Reduction
|
|
723
|
+
ReductionStep,
|
|
724
|
+
ReductionTrace,
|
|
725
|
+
ReductionSystem,
|
|
726
|
+
|
|
727
|
+
// Utilities
|
|
728
|
+
isNormalForm,
|
|
729
|
+
isReducible,
|
|
730
|
+
termSize,
|
|
731
|
+
|
|
732
|
+
// Canonicalization
|
|
733
|
+
FusionCanonicalizer,
|
|
734
|
+
|
|
735
|
+
// Verification
|
|
736
|
+
NormalFormVerifier,
|
|
737
|
+
|
|
738
|
+
// Proofs
|
|
739
|
+
demonstrateStrongNormalization,
|
|
740
|
+
testLocalConfluence
|
|
741
|
+
};
|