@aleph-ai/tinyaleph 1.2.0 → 1.3.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.
Files changed (35) hide show
  1. package/README.md +187 -2
  2. package/backends/bioinformatics/binding.js +503 -0
  3. package/backends/bioinformatics/dna-computing.js +664 -0
  4. package/backends/bioinformatics/encoding.js +339 -0
  5. package/backends/bioinformatics/folding.js +454 -0
  6. package/backends/bioinformatics/genetic-code.js +269 -0
  7. package/backends/bioinformatics/index.js +522 -0
  8. package/backends/bioinformatics/transcription.js +221 -0
  9. package/backends/bioinformatics/translation.js +264 -0
  10. package/backends/index.js +25 -1
  11. package/core/compound.js +532 -0
  12. package/core/hilbert.js +454 -1
  13. package/core/index.js +106 -12
  14. package/core/inference.js +605 -0
  15. package/core/resonance.js +245 -616
  16. package/core/symbols/archetypes.js +478 -0
  17. package/core/symbols/base.js +302 -0
  18. package/core/symbols/elements.js +487 -0
  19. package/core/symbols/hieroglyphs.js +303 -0
  20. package/core/symbols/iching.js +471 -0
  21. package/core/symbols/index.js +77 -0
  22. package/core/symbols/tarot.js +211 -0
  23. package/core/symbols.js +22 -0
  24. package/docs/design/BIOINFORMATICS_BACKEND_DESIGN.md +493 -0
  25. package/docs/guide/06-symbolic-ai.md +370 -0
  26. package/docs/guide/README.md +2 -1
  27. package/docs/reference/05-symbolic-ai.md +570 -0
  28. package/docs/reference/06-bioinformatics.md +546 -0
  29. package/docs/reference/README.md +32 -2
  30. package/docs/theory/11-prgraph-memory.md +559 -0
  31. package/docs/theory/12-resonant-attention.md +661 -0
  32. package/modular.js +33 -1
  33. package/package.json +1 -1
  34. package/physics/index.js +16 -0
  35. package/physics/kuramoto-coupled-ladder.js +603 -0
@@ -0,0 +1,605 @@
1
+ /**
2
+ * Semantic Inference Engine
3
+ *
4
+ * Pattern-based inference for mapping text entities to symbols.
5
+ * Uses multiple strategies:
6
+ * 1. Direct lookup in symbol database
7
+ * 2. Regex pattern matching
8
+ * 3. Semantic word overlap
9
+ * 4. Category-based fallback
10
+ * 5. Resonance-enhanced disambiguation (uses ResoFormer attention)
11
+ *
12
+ * Ported from symprime's SemanticInference system.
13
+ * Enhanced with resonance attention from tinyaleph's rformer.
14
+ */
15
+
16
+ const { symbolDatabase, SymbolCategory } = require('./symbols');
17
+ const { SparsePrimeState, resonanceScore, resonantAttention } = require('./rformer');
18
+ const { ResonanceCalculator } = require('./resonance');
19
+
20
+ // ═══════════════════════════════════════════════════════════════════
21
+ // Inference Result Types
22
+ // ═══════════════════════════════════════════════════════════════════
23
+
24
+ const InferenceMethod = {
25
+ DIRECT: 'direct', // Exact match in database
26
+ REGEX: 'regex', // Pattern rule match
27
+ SEMANTIC: 'semantic', // Word overlap match
28
+ CATEGORY_FALLBACK: 'category_fallback' // Category-based guess
29
+ };
30
+
31
+ // ═══════════════════════════════════════════════════════════════════
32
+ // Semantic Inference Engine
33
+ // ═══════════════════════════════════════════════════════════════════
34
+
35
+ class SemanticInference {
36
+ constructor(database = symbolDatabase) {
37
+ this.database = database;
38
+ this.patternRules = [];
39
+ this.initializePatternRules();
40
+ }
41
+
42
+ /**
43
+ * Infer a symbol from entity text
44
+ * Returns { symbol, confidence, method } or null
45
+ */
46
+ inferSymbol(entityText) {
47
+ const normalized = entityText.toLowerCase().trim();
48
+
49
+ // 1. Direct entity lookup
50
+ const direct = this.database.getSymbol(normalized);
51
+ if (direct) {
52
+ return { symbol: direct, confidence: 1.0, method: InferenceMethod.DIRECT };
53
+ }
54
+
55
+ // 2. Regex pattern matching
56
+ const patternResult = this.matchPattern(normalized);
57
+ if (patternResult) {
58
+ return patternResult;
59
+ }
60
+
61
+ // 3. Semantic similarity (word matching)
62
+ const semanticResult = this.semanticMatch(normalized);
63
+ if (semanticResult) {
64
+ return semanticResult;
65
+ }
66
+
67
+ // 4. Category-based fallback
68
+ const categoryResult = this.categoryFallback(normalized);
69
+ if (categoryResult) {
70
+ return categoryResult;
71
+ }
72
+
73
+ return null;
74
+ }
75
+
76
+ /**
77
+ * Batch infer symbols from multiple entities
78
+ */
79
+ inferSymbols(entities) {
80
+ const results = [];
81
+ for (const entity of entities) {
82
+ const result = this.inferSymbol(entity);
83
+ if (result) {
84
+ results.push({ entity, ...result });
85
+ }
86
+ }
87
+ return results;
88
+ }
89
+
90
+ /**
91
+ * Add a custom pattern rule
92
+ */
93
+ addPatternRule(pattern, symbolId, confidence = 0.85) {
94
+ this.patternRules.push({ pattern, symbolId, confidence });
95
+ }
96
+
97
+ /**
98
+ * Initialize common pattern rules
99
+ */
100
+ initializePatternRules() {
101
+ // Warrior patterns
102
+ this.addPatternRule(/\b(warrior|fighter|soldier|combatant)\b/i, 'warrior', 0.85);
103
+ this.addPatternRule(/\b(samurai|ronin)\b/i, 'samurai', 0.9);
104
+ this.addPatternRule(/\b(knight|paladin)\b/i, 'warrior', 0.85);
105
+ this.addPatternRule(/\b(ninja|shinobi)\b/i, 'ninja', 0.9);
106
+
107
+ // Leader patterns
108
+ this.addPatternRule(/\b(king|queen|monarch|royalty)\b/i, 'king', 0.85);
109
+ this.addPatternRule(/\b(emperor|empress)\b/i, 'emperor', 0.85);
110
+ this.addPatternRule(/\b(ruler|sovereign|leader)\b/i, 'ruler', 0.8);
111
+ this.addPatternRule(/\b(pharaoh)\b/i, 'pharaoh', 0.95);
112
+
113
+ // Spiritual patterns
114
+ this.addPatternRule(/\b(monk|meditation|zen)\b/i, 'monk', 0.85);
115
+ this.addPatternRule(/\b(sage|wise\s+one|mentor)\b/i, 'sage', 0.85);
116
+ this.addPatternRule(/\b(shaman|medicine\s+man)\b/i, 'shaman', 0.9);
117
+ this.addPatternRule(/\b(guru|teacher|master)\b/i, 'guru', 0.85);
118
+ this.addPatternRule(/\b(buddha|enlighten)\b/i, 'buddha', 0.9);
119
+ this.addPatternRule(/\b(prophet|messenger)\b/i, 'prophet', 0.85);
120
+
121
+ // Place patterns
122
+ this.addPatternRule(/\b(mountain|peak|summit)\b/i, 'mountain', 0.85);
123
+ this.addPatternRule(/\b(ocean|sea|waters)\b/i, 'ocean', 0.85);
124
+ this.addPatternRule(/\b(forest|woods|jungle)\b/i, 'forest', 0.85);
125
+ this.addPatternRule(/\b(desert|wasteland|dunes)\b/i, 'desert', 0.85);
126
+ this.addPatternRule(/\b(temple|shrine|sanctuary)\b/i, 'temple', 0.85);
127
+ this.addPatternRule(/\b(castle|fortress|citadel)\b/i, 'fortress', 0.85);
128
+ this.addPatternRule(/\b(cave|cavern|grotto)\b/i, 'cave', 0.85);
129
+ this.addPatternRule(/\b(river|stream|creek)\b/i, 'river', 0.85);
130
+ this.addPatternRule(/\b(garden|orchard|paradise)\b/i, 'garden', 0.85);
131
+ this.addPatternRule(/\b(tower|spire|minaret)\b/i, 'tower', 0.85);
132
+ this.addPatternRule(/\b(bridge|crossing|span)\b/i, 'bridge', 0.85);
133
+ this.addPatternRule(/\b(labyrinth|maze)\b/i, 'labyrinth', 0.9);
134
+
135
+ // Object patterns
136
+ this.addPatternRule(/\b(sword|blade|katana)\b/i, 'sword', 0.85);
137
+ this.addPatternRule(/\b(shield|buckler)\b/i, 'shield', 0.85);
138
+ this.addPatternRule(/\b(bow|arrow|archery)\b/i, 'bow', 0.85);
139
+ this.addPatternRule(/\b(hammer|mallet)\b/i, 'hammer_tool', 0.85);
140
+ this.addPatternRule(/\b(book|tome|grimoire)\b/i, 'book', 0.85);
141
+ this.addPatternRule(/\b(key|unlock)\b/i, 'key', 0.85);
142
+ this.addPatternRule(/\b(mirror|reflection)\b/i, 'mirror', 0.85);
143
+ this.addPatternRule(/\b(ring|band)\b/i, 'ring', 0.8);
144
+ this.addPatternRule(/\b(crown|tiara|diadem)\b/i, 'crown', 0.85);
145
+ this.addPatternRule(/\b(scroll|parchment)\b/i, 'scroll', 0.85);
146
+ this.addPatternRule(/\b(lamp|lantern)\b/i, 'lamp', 0.85);
147
+ this.addPatternRule(/\b(candle|taper)\b/i, 'candle', 0.85);
148
+ this.addPatternRule(/\b(chain|shackle|fetter)\b/i, 'chain', 0.85);
149
+ this.addPatternRule(/\b(bell|chime)\b/i, 'bell', 0.85);
150
+ this.addPatternRule(/\b(chalice|grail|goblet)\b/i, 'chalice', 0.85);
151
+ this.addPatternRule(/\b(crystal|gem|jewel)\b/i, 'crystal', 0.85);
152
+
153
+ // Concept patterns
154
+ this.addPatternRule(/\b(love|affection|romance)\b/i, 'love', 0.85);
155
+ this.addPatternRule(/\b(death|mortality|end)\b/i, 'death', 0.85);
156
+ this.addPatternRule(/\b(birth|beginning|origin)\b/i, 'birth', 0.85);
157
+ this.addPatternRule(/\b(wisdom|knowledge|insight)\b/i, 'wisdom_concept', 0.85);
158
+ this.addPatternRule(/\b(courage|bravery|valor)\b/i, 'courage', 0.85);
159
+ this.addPatternRule(/\b(justice|fairness|equity)\b/i, 'justice', 0.85);
160
+ this.addPatternRule(/\b(peace|tranquility|harmony)\b/i, 'peace', 0.85);
161
+ this.addPatternRule(/\b(war|conflict|battle)\b/i, 'war', 0.85);
162
+ this.addPatternRule(/\b(fear|terror|dread)\b/i, 'fear', 0.85);
163
+ this.addPatternRule(/\b(joy|happiness|bliss)\b/i, 'joy', 0.85);
164
+ this.addPatternRule(/\b(sorrow|grief|sadness)\b/i, 'sorrow', 0.85);
165
+ this.addPatternRule(/\b(truth|reality|fact)\b/i, 'truth', 0.85);
166
+ this.addPatternRule(/\b(chaos|disorder|entropy)\b/i, 'chaos', 0.85);
167
+ this.addPatternRule(/\b(order|structure|pattern)\b/i, 'order', 0.85);
168
+ this.addPatternRule(/\b(unity|oneness|wholeness)\b/i, 'unity', 0.85);
169
+ this.addPatternRule(/\b(duality|polarity|opposition)\b/i, 'duality', 0.85);
170
+ this.addPatternRule(/\b(infinity|eternal|endless)\b/i, 'infinity', 0.85);
171
+ this.addPatternRule(/\b(void|emptiness|nothing)\b/i, 'void', 0.85);
172
+ this.addPatternRule(/\b(transform|change|metamorph)\b/i, 'transformation', 0.85);
173
+ this.addPatternRule(/\b(creat|mak|build)\b/i, 'creation', 0.75);
174
+ this.addPatternRule(/\b(destroy|break|ruin)\b/i, 'destruction', 0.75);
175
+ this.addPatternRule(/\b(freedom|liberty|liberation)\b/i, 'freedom', 0.85);
176
+
177
+ // Element patterns
178
+ this.addPatternRule(/\b(fire|flame|blaze)\b/i, 'fire', 0.9);
179
+ this.addPatternRule(/\b(water|aqua|liquid)\b/i, 'water', 0.9);
180
+ this.addPatternRule(/\b(earth|ground|soil)\b/i, 'earth_element', 0.9);
181
+ this.addPatternRule(/\b(air|wind|breeze)\b/i, 'air', 0.9);
182
+ this.addPatternRule(/\b(sun|solar|sunlight)\b/i, 'sun', 0.9);
183
+ this.addPatternRule(/\b(moon|lunar|moonlight)\b/i, 'moon_element', 0.9);
184
+ this.addPatternRule(/\b(star|stellar|constellation)\b/i, 'stars', 0.85);
185
+ this.addPatternRule(/\b(thunder|thunderbolt)\b/i, 'thunder', 0.9);
186
+ this.addPatternRule(/\b(lightning|bolt)\b/i, 'lightning', 0.85);
187
+ this.addPatternRule(/\b(rain|rainfall|shower)\b/i, 'rain', 0.85);
188
+ this.addPatternRule(/\b(snow|frost|ice)\b/i, 'snow', 0.85);
189
+ this.addPatternRule(/\b(storm|tempest|hurricane)\b/i, 'storm', 0.9);
190
+ this.addPatternRule(/\b(rainbow|spectrum)\b/i, 'rainbow', 0.9);
191
+ this.addPatternRule(/\b(tree|oak|pine|elm)\b/i, 'tree', 0.85);
192
+ this.addPatternRule(/\b(flower|blossom|bloom)\b/i, 'flower', 0.85);
193
+ this.addPatternRule(/\b(stone|rock|boulder)\b/i, 'stone', 0.85);
194
+ this.addPatternRule(/\b(gold|golden)\b/i, 'gold', 0.85);
195
+ this.addPatternRule(/\b(silver|silvery)\b/i, 'silver', 0.85);
196
+
197
+ // Archetype patterns
198
+ this.addPatternRule(/\b(hero|protagonist|champion)\b/i, 'hero', 0.85);
199
+ this.addPatternRule(/\b(trickster|deceiver|jester)\b/i, 'trickster', 0.85);
200
+ this.addPatternRule(/\b(mother|maternal|nurturer)\b/i, 'mother', 0.85);
201
+ this.addPatternRule(/\b(father|paternal|protector)\b/i, 'father', 0.85);
202
+ this.addPatternRule(/\b(child|innocent|youth)\b/i, 'child', 0.85);
203
+ this.addPatternRule(/\b(explorer|adventurer|seeker)\b/i, 'explorer', 0.85);
204
+ this.addPatternRule(/\b(magician|wizard|sorcerer)\b/i, 'magician', 0.85);
205
+ this.addPatternRule(/\b(guardian|protector|defender)\b/i, 'guardian', 0.85);
206
+ this.addPatternRule(/\b(creator|maker|artist)\b/i, 'creator', 0.8);
207
+ this.addPatternRule(/\b(destroyer|annihilator)\b/i, 'destroyer', 0.85);
208
+ this.addPatternRule(/\b(shadow|dark\s+side)\b/i, 'shadow', 0.85);
209
+
210
+ // Mythology patterns
211
+ this.addPatternRule(/\b(zeus|jupiter)\b/i, 'zeus', 0.95);
212
+ this.addPatternRule(/\b(athena|minerva)\b/i, 'athena', 0.95);
213
+ this.addPatternRule(/\b(thor|thunder\s+god)\b/i, 'thor', 0.95);
214
+ this.addPatternRule(/\b(odin|allfather)\b/i, 'odin', 0.95);
215
+ this.addPatternRule(/\b(anubis|jackal)\b/i, 'anubis', 0.95);
216
+ this.addPatternRule(/\b(shiva|nataraja)\b/i, 'shiva', 0.95);
217
+ this.addPatternRule(/\b(ganesh|ganesha|elephant\s+god)\b/i, 'ganesh', 0.95);
218
+ this.addPatternRule(/\b(quetzalcoatl|feathered\s+serpent)\b/i, 'quetzalcoatl', 0.95);
219
+ }
220
+
221
+ /**
222
+ * Match entity against pattern rules
223
+ */
224
+ matchPattern(text) {
225
+ for (const rule of this.patternRules) {
226
+ if (rule.pattern.test(text)) {
227
+ const symbol = this.database.getSymbol(rule.symbolId);
228
+ if (symbol) {
229
+ return {
230
+ symbol,
231
+ confidence: rule.confidence,
232
+ method: InferenceMethod.REGEX
233
+ };
234
+ }
235
+ }
236
+ }
237
+ return null;
238
+ }
239
+
240
+ /**
241
+ * Semantic similarity matching using word overlap
242
+ */
243
+ semanticMatch(text) {
244
+ const words = text.split(/\s+/).filter(w => w.length > 2);
245
+ if (words.length === 0) return null;
246
+
247
+ let bestMatch = null;
248
+ let bestScore = 0;
249
+
250
+ const candidates = this.database.search(text);
251
+
252
+ for (const symbol of candidates) {
253
+ const symbolWords = symbol.meaning.toLowerCase().split(/[\s\-]+/);
254
+ const overlapCount = words.filter(word =>
255
+ symbolWords.some(sw => sw.includes(word) || word.includes(sw))
256
+ ).length;
257
+
258
+ const score = overlapCount / Math.max(words.length, symbolWords.length);
259
+
260
+ if (score > bestScore && score > 0.3) {
261
+ bestScore = score;
262
+ bestMatch = {
263
+ symbol,
264
+ confidence: Math.min(0.75, score),
265
+ method: InferenceMethod.SEMANTIC
266
+ };
267
+ }
268
+ }
269
+
270
+ return bestMatch;
271
+ }
272
+
273
+ /**
274
+ * Category-based fallback mapping
275
+ */
276
+ categoryFallback(text) {
277
+ const categoryKeywords = {
278
+ person: 'everyman',
279
+ people: 'everyman',
280
+ human: 'everyman',
281
+ place: 'path',
282
+ location: 'path',
283
+ object: 'crystal',
284
+ thing: 'crystal',
285
+ tool: 'key',
286
+ concept: 'light',
287
+ idea: 'light',
288
+ element: 'ether',
289
+ nature: 'tree',
290
+ animal: 'hero',
291
+ creature: 'hero'
292
+ };
293
+
294
+ for (const [keyword, symbolId] of Object.entries(categoryKeywords)) {
295
+ if (text.includes(keyword)) {
296
+ const symbol = this.database.getSymbol(symbolId);
297
+ if (symbol) {
298
+ return {
299
+ symbol,
300
+ confidence: 0.5,
301
+ method: InferenceMethod.CATEGORY_FALLBACK
302
+ };
303
+ }
304
+ }
305
+ }
306
+
307
+ return null;
308
+ }
309
+
310
+ // ─────────────────────────────────────────────────────────────────
311
+ // Resonance-Enhanced Inference Methods
312
+ // ─────────────────────────────────────────────────────────────────
313
+
314
+ /**
315
+ * Convert a symbol to SparsePrimeState for resonance calculations
316
+ */
317
+ symbolToState(symbol) {
318
+ const { Complex } = require('./hilbert');
319
+ const state = new SparsePrimeState(4096, 8);
320
+
321
+ // Primary prime activation
322
+ state.set(symbol.prime, new Complex(1.0, 0), null);
323
+
324
+ // Add related primes based on cultural tags
325
+ let idx = 0;
326
+ for (const tag of symbol.culturalTags.slice(0, 7)) {
327
+ const related = this.database.getSymbolsByTag(tag);
328
+ if (related && related.length > 1) {
329
+ const relatedSymbol = related.find(s => s.id !== symbol.id);
330
+ if (relatedSymbol) {
331
+ const phase = (2 * Math.PI * idx) / 8;
332
+ state.set(relatedSymbol.prime, new Complex(0.3 * Math.cos(phase), 0.3 * Math.sin(phase)), null);
333
+ idx++;
334
+ }
335
+ }
336
+ }
337
+
338
+ return state;
339
+ }
340
+
341
+ /**
342
+ * Calculate resonance between candidate symbols
343
+ * Returns weighted scores based on how well symbols "harmonize"
344
+ */
345
+ calculateCandidateResonance(candidates) {
346
+ if (candidates.length <= 1) {
347
+ return candidates.map(c => ({ ...c, resonanceBonus: 0 }));
348
+ }
349
+
350
+ const resonanceCalc = new ResonanceCalculator();
351
+ const resonances = [];
352
+
353
+ for (let i = 0; i < candidates.length; i++) {
354
+ let totalResonance = 0;
355
+ for (let j = 0; j < candidates.length; j++) {
356
+ if (i !== j) {
357
+ totalResonance += resonanceCalc.calculateResonance(
358
+ candidates[i].symbol.prime,
359
+ candidates[j].symbol.prime
360
+ );
361
+ }
362
+ }
363
+ resonances.push({
364
+ ...candidates[i],
365
+ resonanceBonus: totalResonance / (candidates.length - 1),
366
+ avgResonance: totalResonance / (candidates.length - 1)
367
+ });
368
+ }
369
+
370
+ return resonances;
371
+ }
372
+
373
+ /**
374
+ * Use resonance attention to select the best symbol set
375
+ * This finds symbols that "harmonize" together
376
+ */
377
+ resonanceSelect(candidates, context = null) {
378
+ if (candidates.length === 0) return [];
379
+ if (candidates.length === 1) return candidates;
380
+
381
+ // Convert all candidates to states
382
+ const states = candidates.map(c => this.symbolToState(c.symbol));
383
+
384
+ // Create context state or use first candidate
385
+ let queryState;
386
+ if (context) {
387
+ queryState = this.symbolToState(context);
388
+ } else {
389
+ queryState = states[0];
390
+ }
391
+
392
+ // Apply resonant attention
393
+ const result = resonantAttention(queryState, states, states);
394
+ if (!result) return candidates;
395
+
396
+ // Rank candidates by attention weight
397
+ const ranked = candidates.map((c, i) => ({
398
+ ...c,
399
+ attentionWeight: result.weights[i],
400
+ resonanceScore: result.scores[i]
401
+ }));
402
+
403
+ return ranked.sort((a, b) => b.attentionWeight - a.attentionWeight);
404
+ }
405
+
406
+ /**
407
+ * Infer symbols with resonance-based disambiguation
408
+ * This finds the most harmonious set of symbols for the text
409
+ */
410
+ inferWithResonance(text, options = {}) {
411
+ const { maxCandidates = 10, useAttention = true } = options;
412
+
413
+ // Extract entities and infer candidates
414
+ const extractor = new EntityExtractor();
415
+ const entities = extractor.extract(text);
416
+ const candidates = this.inferSymbols(entities);
417
+
418
+ if (candidates.length <= 1) {
419
+ return candidates;
420
+ }
421
+
422
+ // Calculate resonance between candidates
423
+ const withResonance = this.calculateCandidateResonance(candidates);
424
+
425
+ if (useAttention) {
426
+ // Use resonant attention for final selection
427
+ const selected = this.resonanceSelect(withResonance);
428
+ return selected.slice(0, maxCandidates);
429
+ }
430
+
431
+ // Sort by combined confidence + resonance
432
+ withResonance.sort((a, b) => {
433
+ const scoreA = a.confidence + (a.resonanceBonus * 0.3);
434
+ const scoreB = b.confidence + (b.resonanceBonus * 0.3);
435
+ return scoreB - scoreA;
436
+ });
437
+
438
+ return withResonance.slice(0, maxCandidates);
439
+ }
440
+
441
+ /**
442
+ * Find the most resonant symbol for a given context
443
+ * Uses resonance attention to find what "fits best"
444
+ */
445
+ inferMostResonant(text, contextSymbols = []) {
446
+ const candidates = this.inferSymbols([text]);
447
+ if (candidates.length === 0) return null;
448
+
449
+ if (contextSymbols.length === 0) {
450
+ return candidates[0];
451
+ }
452
+
453
+ const resonanceCalc = new ResonanceCalculator();
454
+
455
+ // Score each candidate by resonance with context
456
+ let bestCandidate = null;
457
+ let bestScore = -Infinity;
458
+
459
+ for (const candidate of candidates) {
460
+ let totalResonance = 0;
461
+ for (const contextSymbol of contextSymbols) {
462
+ totalResonance += resonanceCalc.calculateResonance(
463
+ candidate.symbol.prime,
464
+ contextSymbol.prime
465
+ );
466
+ }
467
+ const avgResonance = totalResonance / contextSymbols.length;
468
+
469
+ if (avgResonance > bestScore) {
470
+ bestScore = avgResonance;
471
+ bestCandidate = {
472
+ ...candidate,
473
+ contextResonance: avgResonance
474
+ };
475
+ }
476
+ }
477
+
478
+ return bestCandidate;
479
+ }
480
+
481
+ /**
482
+ * Get confidence statistics for a batch of inferences
483
+ */
484
+ getConfidenceStats(results) {
485
+ if (results.length === 0) {
486
+ return { average: 0, high: 0, medium: 0, low: 0 };
487
+ }
488
+
489
+ const confidences = results.map(r => r.confidence);
490
+ const sum = confidences.reduce((a, b) => a + b, 0);
491
+
492
+ return {
493
+ average: sum / results.length,
494
+ high: results.filter(r => r.confidence >= 0.8).length,
495
+ medium: results.filter(r => r.confidence >= 0.5 && r.confidence < 0.8).length,
496
+ low: results.filter(r => r.confidence < 0.5).length
497
+ };
498
+ }
499
+
500
+ /**
501
+ * Get method distribution for a batch of inferences
502
+ */
503
+ getMethodStats(results) {
504
+ const methods = {};
505
+ for (const method of Object.values(InferenceMethod)) {
506
+ methods[method] = 0;
507
+ }
508
+
509
+ for (const result of results) {
510
+ if (result.method) {
511
+ methods[result.method]++;
512
+ }
513
+ }
514
+
515
+ return methods;
516
+ }
517
+
518
+ /**
519
+ * Get all pattern rules (for inspection)
520
+ */
521
+ getPatternRules() {
522
+ return this.patternRules.map(r => ({
523
+ pattern: r.pattern.toString(),
524
+ symbolId: r.symbolId,
525
+ confidence: r.confidence
526
+ }));
527
+ }
528
+
529
+ /**
530
+ * Clear all custom pattern rules (keeps defaults)
531
+ */
532
+ resetPatternRules() {
533
+ this.patternRules = [];
534
+ this.initializePatternRules();
535
+ }
536
+ }
537
+
538
+ // ═══════════════════════════════════════════════════════════════════
539
+ // Entity Extractor (Simple NER-like extraction)
540
+ // ═══════════════════════════════════════════════════════════════════
541
+
542
+ class EntityExtractor {
543
+ constructor() {
544
+ // Patterns for extracting entities from text
545
+ this.entityPatterns = [
546
+ // Capitalized words (potential proper nouns)
547
+ { pattern: /\b[A-Z][a-z]+(?:\s+[A-Z][a-z]+)*/g, type: 'proper_noun' },
548
+ // Quoted strings
549
+ { pattern: /"([^"]+)"/g, type: 'quoted' },
550
+ // The X, A X
551
+ { pattern: /\b(?:the|a|an)\s+([a-z]+(?:\s+[a-z]+)?)\b/gi, type: 'definite' },
552
+ ];
553
+ }
554
+
555
+ /**
556
+ * Extract entities from text
557
+ */
558
+ extract(text) {
559
+ const entities = new Set();
560
+
561
+ for (const { pattern, type } of this.entityPatterns) {
562
+ const matches = text.matchAll(pattern);
563
+ for (const match of matches) {
564
+ const entity = match[1] || match[0];
565
+ if (entity.length > 2) {
566
+ entities.add(entity.toLowerCase().trim());
567
+ }
568
+ }
569
+ }
570
+
571
+ return Array.from(entities);
572
+ }
573
+
574
+ /**
575
+ * Extract and infer symbols from text
576
+ */
577
+ extractAndInfer(text, inference) {
578
+ const entities = this.extract(text);
579
+ return inference.inferSymbols(entities);
580
+ }
581
+ }
582
+
583
+ // Singleton instances
584
+ const defaultInference = new SemanticInference();
585
+ const defaultExtractor = new EntityExtractor();
586
+
587
+ module.exports = {
588
+ SemanticInference,
589
+ EntityExtractor,
590
+ InferenceMethod,
591
+
592
+ // Singleton instances
593
+ semanticInference: defaultInference,
594
+ entityExtractor: defaultExtractor,
595
+
596
+ // Convenience functions
597
+ inferSymbol: (text) => defaultInference.inferSymbol(text),
598
+ inferSymbols: (entities) => defaultInference.inferSymbols(entities),
599
+
600
+ // Resonance-enhanced inference
601
+ inferWithResonance: (text, options) => defaultInference.inferWithResonance(text, options),
602
+ inferMostResonant: (text, contextSymbols) => defaultInference.inferMostResonant(text, contextSymbols),
603
+ extractEntities: (text) => defaultExtractor.extract(text),
604
+ extractAndInfer: (text) => defaultExtractor.extractAndInfer(text, defaultInference)
605
+ };