sum-engine 0.1.0__py3-none-any.whl

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 (49) hide show
  1. internal/__init__.py +8 -0
  2. internal/algorithms/__init__.py +1 -0
  3. internal/algorithms/causal_discovery.py +96 -0
  4. internal/algorithms/predicate_canon.py +137 -0
  5. internal/algorithms/semantic_arithmetic.py +890 -0
  6. internal/algorithms/syntactic_sieve.py +452 -0
  7. internal/algorithms/zk_semantics.py +90 -0
  8. internal/ensemble/__init__.py +1 -0
  9. internal/ensemble/automated_scientist.py +138 -0
  10. internal/ensemble/autonomous_agent.py +157 -0
  11. internal/ensemble/causal_triggers.py +121 -0
  12. internal/ensemble/confidence_calibrator.py +284 -0
  13. internal/ensemble/epistemic_arbiter.py +159 -0
  14. internal/ensemble/epistemic_loop.py +136 -0
  15. internal/ensemble/extraction_validator.py +172 -0
  16. internal/ensemble/gauge_orchestrator.py +150 -0
  17. internal/ensemble/live_llm_adapter.py +183 -0
  18. internal/ensemble/llm_entailment.py +117 -0
  19. internal/ensemble/mass_semantic_engine.py +138 -0
  20. internal/ensemble/ouroboros.py +281 -0
  21. internal/ensemble/semantic_dedup.py +261 -0
  22. internal/ensemble/tome_generator.py +286 -0
  23. internal/ensemble/tome_sliders.py +104 -0
  24. internal/ensemble/vector_bridge.py +195 -0
  25. internal/ensemble/venn_abers.py +211 -0
  26. internal/infrastructure/__init__.py +1 -0
  27. internal/infrastructure/akashic_ledger.py +812 -0
  28. internal/infrastructure/canonical_codec.py +452 -0
  29. internal/infrastructure/jcs.py +115 -0
  30. internal/infrastructure/key_manager.py +239 -0
  31. internal/infrastructure/p2p_mesh.py +168 -0
  32. internal/infrastructure/prov_o.py +159 -0
  33. internal/infrastructure/provenance.py +181 -0
  34. internal/infrastructure/rate_limiter.py +81 -0
  35. internal/infrastructure/resource_guards.py +117 -0
  36. internal/infrastructure/scheme_registry.py +136 -0
  37. internal/infrastructure/state_encoding.py +94 -0
  38. internal/infrastructure/telemetry.py +91 -0
  39. internal/infrastructure/tome_parser.py +55 -0
  40. internal/infrastructure/verifiable_credential.py +412 -0
  41. internal/infrastructure/zig_bridge.py +256 -0
  42. sum_cli/__init__.py +18 -0
  43. sum_cli/main.py +688 -0
  44. sum_engine-0.1.0.dist-info/METADATA +590 -0
  45. sum_engine-0.1.0.dist-info/RECORD +49 -0
  46. sum_engine-0.1.0.dist-info/WHEEL +5 -0
  47. sum_engine-0.1.0.dist-info/entry_points.txt +2 -0
  48. sum_engine-0.1.0.dist-info/licenses/LICENSE +201 -0
  49. sum_engine-0.1.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,890 @@
1
+ import sys
2
+ sys.set_int_max_str_digits(0)
3
+
4
+ """
5
+ Semantic Prime Number Theorem (SPNT) & Gödel-State Algebra
6
+
7
+ Maps irreducible semantic axioms to Prime Numbers. Document states become
8
+ massive integers. Merging parallel extractions is an LCM operation, and
9
+ entailment checking is Modulo arithmetic.
10
+
11
+ Mathematical foundations:
12
+ - SPNT Bound: π_sem(N) ~ N / ln(N)
13
+ - Gödel Encoding: state = lcm(prime_1, prime_2, ...) for each distinct
14
+ axiom. Primes are pairwise coprime so this equals
15
+ the product for a set, but is idempotent under
16
+ duplicates (a *set* of axioms, not a multiset).
17
+ - Lock-Free Merge: LCM(state_A, state_B) deduplicates automatically
18
+ - Entailment: global_state % hypothesis_state == 0
19
+
20
+ Author: ototao
21
+ License: Apache License 2.0
22
+ """
23
+
24
+ import math
25
+ import hashlib
26
+ import logging
27
+ from typing import Dict, List, Tuple, Set
28
+
29
+ import sympy
30
+
31
+ from internal.infrastructure.scheme_registry import CURRENT_SCHEME
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+
36
+ class PrimeCollisionError(Exception):
37
+ """Hard failure when two distinct axiom keys hash to the same prime.
38
+
39
+ In sha256_64_v1, collisions are resolved by advancing to the next
40
+ prime (order-dependent, consensus-unsafe for distributed systems).
41
+
42
+ In sha256_128_v2, collisions are fatal. The 128-bit seed space
43
+ makes birthday-bound collisions require ~2^64 distinct axioms.
44
+ If one ever occurs, something is deeply wrong.
45
+ """
46
+
47
+
48
+ def _get_zig_engine():
49
+ """Lazy import of the Zig FFI bridge singleton."""
50
+ try:
51
+ from internal.infrastructure.zig_bridge import zig_engine
52
+ return zig_engine
53
+ except ImportError:
54
+ return None
55
+
56
+
57
+ class SemanticPrimeNumberTheorem:
58
+ """
59
+ The classical PNT states that the density of primes up to N is
60
+ asymptotically N / ln(N). Here we apply the same bound to
61
+ *semantic primes* — the irreducible, highly-surprising axiomatic
62
+ facts inside a document corpus.
63
+
64
+ If an LLM extraction yields more axioms than the SPNT bound,
65
+ it has failed to compress (hallucinated verbosity) and the
66
+ extraction should be rejected.
67
+ """
68
+
69
+ @staticmethod
70
+ def asymptotic_bound(total_raw_claims: int) -> int:
71
+ """
72
+ π_sem(N) ~ N / ln(N)
73
+
74
+ Calculates the theoretical maximum number of irreducible semantic
75
+ primes for a corpus of N raw claims.
76
+
77
+ Args:
78
+ total_raw_claims: Total number of raw claims extracted.
79
+
80
+ Returns:
81
+ The SPNT upper bound on truly novel axioms.
82
+ """
83
+ if total_raw_claims <= 3:
84
+ return total_raw_claims
85
+ return int(total_raw_claims / math.log(total_raw_claims))
86
+
87
+
88
+ class GodelStateAlgebra:
89
+ """
90
+ Reduces Mass-Parallel Graph Merging and SMT Theorem Proving
91
+ to Arbitrary-Precision Integer Arithmetic.
92
+
93
+ Every unique (subject, predicate, object) triple is assigned a unique
94
+ prime number. A document chunk's semantic state is the *product* of
95
+ its primes. Merging states is an LCM. Entailment is a modulo check.
96
+ Paradox detection looks for mutually exclusive primes that both
97
+ divide the global state.
98
+ """
99
+
100
+ def __init__(self):
101
+ # Deterministic primes — no sequential watermark needed
102
+ self.axiom_to_prime: Dict[str, int] = {}
103
+ self.prime_to_axiom: Dict[int, str] = {}
104
+
105
+ # Tracks mutually exclusive primes (Level 3 Curvature / Symmetry Breaking).
106
+ # Maps a context key (subject||predicate) to its set of competing object primes.
107
+ self.exclusion_zones: Dict[str, Set[int]] = {}
108
+
109
+ # Fractal Crystallization provenance.
110
+ # Maps macro-prime → product of micro-primes for lossless decompression.
111
+ self.macro_provenance: Dict[int, int] = {}
112
+
113
+ # Quantum GraphRAG node registry.
114
+ # Maps each node (subject/object) to the product of all primes it participates in.
115
+ self.node_registry: Dict[str, int] = {}
116
+
117
+ # ------------------------------------------------------------------
118
+ # Predicate canonicalization
119
+ # ------------------------------------------------------------------
120
+
121
+ @staticmethod
122
+ def _canonicalize_predicate(predicate: str) -> str:
123
+ """Normalize a free-form predicate to the canonical vocabulary."""
124
+ from internal.algorithms.predicate_canon import canonicalize
125
+ return canonicalize(predicate)
126
+
127
+ # ------------------------------------------------------------------
128
+ # Prime minting
129
+ # ------------------------------------------------------------------
130
+
131
+ def _deterministic_prime(self, axiom_key: str) -> int:
132
+ """
133
+ Generates a globally unique, deterministic prime for a given axiom.
134
+
135
+ Dispatches based on the active scheme:
136
+ sha256_64_v1: SHA-256 → first 8 bytes → nextprime(seed)
137
+ sha256_128_v2: SHA-256 → first 16 bytes → nextprime(seed)
138
+
139
+ HORIZON III — Strangler Fig:
140
+ Routes to the bare-metal Zig core (nanosecond-speed C-ABI)
141
+ when ``libsum_core`` is compiled and available. Falls back
142
+ to Python ``sympy.nextprime`` seamlessly otherwise.
143
+
144
+ Args:
145
+ axiom_key: The normalised axiom string.
146
+
147
+ Returns:
148
+ A deterministic prime number unique to this axiom.
149
+ """
150
+ if CURRENT_SCHEME == "sha256_128_v2":
151
+ return self._deterministic_prime_v2(axiom_key)
152
+ return self._deterministic_prime_v1(axiom_key)
153
+
154
+ def _deterministic_prime_v1(self, axiom_key: str) -> int:
155
+ """v1: SHA-256 → first 8 bytes big-endian → nextprime(seed)."""
156
+ # ── Bare-Metal Fast Path (Zig C-ABI) ──
157
+ zig = _get_zig_engine()
158
+ if zig is not None:
159
+ result = zig.get_deterministic_prime(axiom_key)
160
+ if result is not None:
161
+ return result
162
+
163
+ # ── Python Fallback ──
164
+ h = hashlib.sha256(axiom_key.encode('utf-8')).digest()
165
+ seed = int.from_bytes(h[:8], byteorder='big')
166
+ return sympy.nextprime(seed)
167
+
168
+ def _deterministic_prime_v2(self, axiom_key: str) -> int:
169
+ """v2: SHA-256 → first 16 bytes big-endian → nextprime(seed).
170
+
171
+ Uses sympy.nextprime which internally uses BPSW for large inputs.
172
+ """
173
+ # ── Bare-Metal Fast Path (Zig C-ABI v2) ──
174
+ zig = _get_zig_engine()
175
+ if zig is not None and hasattr(zig, 'get_deterministic_prime_v2'):
176
+ result = zig.get_deterministic_prime_v2(axiom_key)
177
+ if result is not None:
178
+ return result
179
+
180
+ # ── Python path ──
181
+ h = hashlib.sha256(axiom_key.encode('utf-8')).digest()
182
+ seed = int.from_bytes(h[:16], byteorder='big')
183
+ return sympy.nextprime(seed)
184
+
185
+ def get_or_mint_prime(self, subject: str, predicate: str, object_: str) -> int:
186
+ """
187
+ Mint a new Universal Semantic Prime for an irreducible axiom,
188
+ or return the existing one if we have seen this axiom before.
189
+
190
+ Uses cryptographic hashing for deterministic, globally consistent
191
+ prime assignment. Two isolated instances will always generate
192
+ the exact same prime for the same axiom.
193
+
194
+ Args:
195
+ subject: The entity.
196
+ predicate: The relation / property.
197
+ object_: The value.
198
+
199
+ Returns:
200
+ The prime number assigned to this axiom.
201
+ """
202
+ axiom_key = (
203
+ f"{subject.strip().lower()}||"
204
+ f"{self._canonicalize_predicate(predicate)}||"
205
+ f"{object_.strip().lower()}"
206
+ )
207
+
208
+ if axiom_key not in self.axiom_to_prime:
209
+ p = self._deterministic_prime(axiom_key)
210
+
211
+ # Collision handling is scheme-dependent
212
+ if p in self.prime_to_axiom and self.prime_to_axiom[p] != axiom_key:
213
+ if CURRENT_SCHEME == "sha256_128_v2":
214
+ # v2: hard fail — collision loop is hidden nondeterminism
215
+ raise PrimeCollisionError(
216
+ f"128-bit prime collision detected: prime {p} already "
217
+ f"assigned to {self.prime_to_axiom[p]!r}, cannot assign "
218
+ f"to {axiom_key!r}. This should be astronomically rare. "
219
+ f"Investigate immediately."
220
+ )
221
+ else:
222
+ # v1: advance to next prime (order-dependent, legacy behavior)
223
+ while p in self.prime_to_axiom and self.prime_to_axiom[p] != axiom_key:
224
+ p = sympy.nextprime(p)
225
+
226
+ self.axiom_to_prime[axiom_key] = p
227
+ self.prime_to_axiom[p] = axiom_key
228
+
229
+ # Register exclusion zone (subject + predicate).
230
+ # Any two primes in the same zone are mutually exclusive
231
+ # (e.g. "alice||age||30" vs "alice||age||31").
232
+ zone_key = (
233
+ f"{subject.strip().lower()}||"
234
+ f"{predicate.strip().lower()}"
235
+ )
236
+ if zone_key not in self.exclusion_zones:
237
+ self.exclusion_zones[zone_key] = set()
238
+ self.exclusion_zones[zone_key].add(p)
239
+
240
+ # Update node registry for GraphRAG traversal
241
+ self._update_node_registry(
242
+ subject.strip().lower(), object_.strip().lower(), p
243
+ )
244
+
245
+ return self.axiom_to_prime[axiom_key]
246
+
247
+ # ------------------------------------------------------------------
248
+ # State Factorisation
249
+ # ------------------------------------------------------------------
250
+
251
+ def get_active_axioms(self, state: int) -> list:
252
+ """
253
+ Factorise a Gödel state to extract all active axiom keys.
254
+
255
+ Iterates over all known primes and checks divisibility.
256
+ Returns the list of axiom key strings (e.g. "alice||likes||cats")
257
+ whose primes divide the state.
258
+
259
+ Args:
260
+ state: The Gödel integer to factorise.
261
+
262
+ Returns:
263
+ List of axiom key strings.
264
+ """
265
+ if state <= 1:
266
+ return []
267
+ active = []
268
+ for prime, axiom in self.prime_to_axiom.items():
269
+ if state % prime == 0:
270
+ active.append(axiom)
271
+ return active
272
+
273
+ # ------------------------------------------------------------------
274
+ # Quantum GraphRAG (Node Registry)
275
+ # ------------------------------------------------------------------
276
+
277
+ def _update_node_registry(
278
+ self, subject: str, object_: str, prime: int
279
+ ):
280
+ """
281
+ Maintains the Context Integer for each node.
282
+
283
+ Every time a prime is minted, both its subject and object nodes
284
+ accumulate the prime into their integer via LCM.
285
+ """
286
+ if subject not in self.node_registry:
287
+ self.node_registry[subject] = 1
288
+ if object_ not in self.node_registry:
289
+ self.node_registry[object_] = 1
290
+ self.node_registry[subject] = math.lcm(
291
+ self.node_registry[subject], prime
292
+ )
293
+ self.node_registry[object_] = math.lcm(
294
+ self.node_registry[object_], prime
295
+ )
296
+
297
+ def get_quantum_neighborhood(
298
+ self, global_state: int, nodes: List[str], hops: int = 1
299
+ ) -> int:
300
+ """
301
+ GraphRAG Traversal with N-Hop Support.
302
+
303
+ Returns the exact Gödel Integer representing the combined
304
+ topological neighborhood of the requested nodes, filtered to
305
+ only include axioms alive in the current global state.
306
+
307
+ The traversal iteratively expands the frontier: at each hop,
308
+ new neighbor nodes are discovered and their edges are collected.
309
+
310
+ Args:
311
+ global_state: Current Gödel integer.
312
+ nodes: Entity names to query.
313
+ hops: Number of traversal hops (1-hop, 2-hop, etc.).
314
+
315
+ Returns:
316
+ Gödel integer representing the neighbourhood context.
317
+ """
318
+ visited: set = set()
319
+ frontier: set = set(n.strip().lower() for n in nodes)
320
+ context_state = 1
321
+
322
+ for _hop in range(hops):
323
+ next_frontier: set = set()
324
+ for node in frontier:
325
+ if node in visited:
326
+ continue
327
+ visited.add(node)
328
+ if node in self.node_registry:
329
+ node_integer = self.node_registry[node]
330
+ # Filter for only edges alive in the global state
331
+ alive_node_integer = math.gcd(
332
+ global_state, node_integer
333
+ )
334
+ context_state = math.lcm(
335
+ context_state, alive_node_integer
336
+ )
337
+ # Discover neighbor nodes for next hop
338
+ for prime, axiom in self.prime_to_axiom.items():
339
+ if alive_node_integer % prime == 0:
340
+ parts = axiom.split("||")
341
+ if len(parts) == 3:
342
+ next_frontier.add(parts[0])
343
+ next_frontier.add(parts[2])
344
+ frontier = next_frontier - visited
345
+
346
+ return context_state
347
+
348
+ # ------------------------------------------------------------------
349
+ # Encoding
350
+ # ------------------------------------------------------------------
351
+
352
+ def encode_chunk_state(self, axioms: List[Tuple[str, str, str]]) -> int:
353
+ """
354
+ Convert a list of axioms into a single Gödel State Integer via
355
+ iterative LCM over each axiom's derived prime.
356
+
357
+ Idempotent under duplicates: encoding the same triple twice
358
+ produces the same state as encoding it once, because
359
+ ``math.lcm(prime, prime) == prime``. This matches the semantic
360
+ model of a *set* of axioms and aligns with every other merge
361
+ operation in the codebase (``math.lcm`` on lines 287, 331, 391,
362
+ 399, 592, 617, 706, 742).
363
+
364
+ Historical note (pre-M1c cross-runtime harness): this function
365
+ used raw multiplicative accumulation (``state *= prime``), which
366
+ produced ``prime^n`` for duplicated triples. All production
367
+ callers pre-deduplicated their input (the sieve returns
368
+ ``list(set(triples))``), so the difference was invisible in
369
+ running code. The JS port at ``single_file_demo/godel.js`` used
370
+ LCM from day one, and the cross-runtime byte-identity harness
371
+ at ``scripts/verify_godel_cross_runtime.py`` caught the drift
372
+ on the "repeated triple" fixture. The fix aligns the two
373
+ implementations and removes a latent source of non-determinism
374
+ (re-encoding a non-deduplicated list no longer perturbs the
375
+ state integer).
376
+
377
+ For input with only distinct triples (the sieve's output shape),
378
+ ``math.lcm(*primes) == product(primes)`` because the primes are
379
+ pairwise coprime, so every existing test observes identical
380
+ state integers before and after this change.
381
+
382
+ Args:
383
+ axioms: List of (subject, predicate, object) triples.
384
+
385
+ Returns:
386
+ A single integer encoding the full semantic state.
387
+ """
388
+ state = 1
389
+ for subj, pred, obj in axioms:
390
+ state = math.lcm(state, self.get_or_mint_prime(subj, pred, obj))
391
+ return state
392
+
393
+ # ------------------------------------------------------------------
394
+ # Lock-free merge
395
+ # ------------------------------------------------------------------
396
+
397
+ def merge_parallel_states(self, state_integers: List[int]) -> int:
398
+ """
399
+ Lock-Free Mass Parallel Merge.
400
+
401
+ The global semantic state is the Least Common Multiple (LCM) of
402
+ all chunk states. This automatically deduplicates overlapping
403
+ knowledge and is both commutative and associative.
404
+
405
+ Args:
406
+ state_integers: Gödel integers from parallel chunk extractions.
407
+
408
+ Returns:
409
+ The merged global state.
410
+ """
411
+ if not state_integers:
412
+ return 1
413
+
414
+ # ── Bare-Metal Fast Path (Zig BigInt LCM) ──
415
+ zig = _get_zig_engine()
416
+ if zig is not None:
417
+ result = state_integers[0]
418
+ for s in state_integers[1:]:
419
+ r = zig.bigint_lcm(result, s)
420
+ if r is None:
421
+ break
422
+ result = r
423
+ else:
424
+ return result
425
+
426
+ # ── Legacy Python Fallback ──
427
+ return math.lcm(*state_integers)
428
+
429
+ # ------------------------------------------------------------------
430
+ # Entailment
431
+ # ------------------------------------------------------------------
432
+
433
+ def verify_entailment(self, global_state: int, hypothesis_state: int) -> bool:
434
+ """
435
+ Epistemic Fidelity Gate (Tags-to-Tomes).
436
+
437
+ Does the Global State entail the Hypothesis? If the modulo is 0,
438
+ the hypothesis is *mathematically proven* to be a subset of the
439
+ global knowledge.
440
+
441
+ Args:
442
+ global_state: The merged global Gödel integer.
443
+ hypothesis_state: The Gödel integer of the claim to verify.
444
+
445
+ Returns:
446
+ True if the hypothesis is entailed, False otherwise.
447
+ """
448
+ if hypothesis_state == 0:
449
+ return False
450
+
451
+ # ── Bare-Metal Fast Path (Zig) ──
452
+ zig = _get_zig_engine()
453
+ if zig is not None:
454
+ if hypothesis_state.bit_length() <= 64:
455
+ # Single prime — optimized streaming mod (no BigInt needed)
456
+ result = zig.is_divisible_by(global_state, hypothesis_state)
457
+ if result is not None:
458
+ return result
459
+ else:
460
+ # Composite hypothesis — full BigInt modulo
461
+ result = zig.bigint_mod(global_state, hypothesis_state)
462
+ if result is not None:
463
+ return result == 0
464
+
465
+ # ── Legacy Python Fallback ──
466
+ return global_state % hypothesis_state == 0
467
+
468
+ # ------------------------------------------------------------------
469
+ # Curvature / Paradox detection
470
+ # ------------------------------------------------------------------
471
+
472
+ def detect_curvature_paradoxes(self, global_state: int) -> List[str]:
473
+ """
474
+ Scan the global integer for Level 3 Curvature (Semantic Contradictions).
475
+
476
+ If mutually exclusive claims (e.g. "Alice is 30" AND "Alice is 31")
477
+ both divide the global state evenly, a curvature paradox is
478
+ detected and the SMT solver should be triggered to arbitrate.
479
+
480
+ Args:
481
+ global_state: The merged global Gödel integer.
482
+
483
+ Returns:
484
+ List of human-readable paradox descriptions (empty = clean).
485
+ """
486
+ paradoxes: List[str] = []
487
+
488
+ for zone_key, primes in self.exclusion_zones.items():
489
+ if len(primes) < 2:
490
+ continue
491
+
492
+ active_primes = [p for p in primes if global_state % p == 0]
493
+
494
+ if len(active_primes) > 1:
495
+ conflicting = [self.prime_to_axiom[p] for p in active_primes]
496
+ paradoxes.append(
497
+ f"Curvature Contradiction in [{zone_key}]: {conflicting}"
498
+ )
499
+
500
+ return paradoxes
501
+
502
+ # ------------------------------------------------------------------
503
+ # Hallucination isolation (Sieve of Hallucinations)
504
+ # ------------------------------------------------------------------
505
+
506
+ def isolate_hallucinations(
507
+ self, global_state: int, generated_state: int
508
+ ) -> List[str]:
509
+ """
510
+ The Sieve of Hallucinations.
511
+
512
+ If ``generated_state`` does not divide ``global_state`` evenly, the
513
+ LLM hallucinated. This method uses ``math.gcd`` to find the exact
514
+ prime numbers (axioms) the LLM fabricated — in microseconds.
515
+
516
+ Algorithm:
517
+ 1. ``shared_truth = gcd(global_state, generated_state)``
518
+ — the primes that *are* in the global state.
519
+ 2. ``hallucinated_product = generated_state // shared_truth``
520
+ — the product of primes *not* in the global state.
521
+ 3. Factor ``hallucinated_product`` against known primes to
522
+ recover the specific axiom strings.
523
+
524
+ Args:
525
+ global_state: The verified global Gödel integer.
526
+ generated_state: The Gödel integer extracted from LLM output.
527
+
528
+ Returns:
529
+ List of axiom key strings that were hallucinated (empty = clean).
530
+ """
531
+ if global_state % generated_state == 0:
532
+ return [] # Zero hallucinations
533
+
534
+ # ── Bare-Metal Fast Path (Zig BigInt GCD) ──
535
+ zig = _get_zig_engine()
536
+ if zig is not None:
537
+ zig_gcd = zig.bigint_gcd(global_state, generated_state)
538
+ if zig_gcd is not None:
539
+ shared_truth = zig_gcd
540
+ else:
541
+ shared_truth = math.gcd(global_state, generated_state)
542
+ else:
543
+ shared_truth = math.gcd(global_state, generated_state)
544
+
545
+ hallucinated_product = generated_state // shared_truth
546
+
547
+ hallucinated_axioms: List[str] = []
548
+
549
+ for prime, axiom in self.prime_to_axiom.items():
550
+ if hallucinated_product % prime == 0:
551
+ hallucinated_axioms.append(axiom)
552
+ # Divide out the prime to break early if product reaches 1
553
+ while hallucinated_product % prime == 0:
554
+ hallucinated_product //= prime
555
+ if hallucinated_product == 1:
556
+ break
557
+
558
+ return hallucinated_axioms
559
+
560
+ # ------------------------------------------------------------------
561
+ # Temporal evolution (Delete / Update)
562
+ # ------------------------------------------------------------------
563
+
564
+ def delete_axiom(self, global_state: int, axiom_key: str) -> int:
565
+ """
566
+ Semantic Deletion.
567
+
568
+ Removes a fact from the global state by dividing out its prime
569
+ factor. Handles multiple occurrences if merged carelessly.
570
+
571
+ Args:
572
+ global_state: The current global Gödel integer.
573
+ axiom_key: Normalised axiom key (``subject||predicate||object``).
574
+
575
+ Returns:
576
+ The updated global state with the axiom removed.
577
+ """
578
+ axiom_key = axiom_key.strip().lower()
579
+
580
+ if axiom_key not in self.axiom_to_prime:
581
+ return global_state # Axiom was never minted
582
+
583
+ prime = self.axiom_to_prime[axiom_key]
584
+
585
+ # Completely factor out the prime
586
+ while global_state % prime == 0:
587
+ global_state //= prime
588
+
589
+ return global_state
590
+
591
+ def update_axiom(
592
+ self, global_state: int, old_axiom_key: str, new_axiom_key: str
593
+ ) -> int:
594
+ """
595
+ Semantic Update (Curvature Resolution).
596
+
597
+ Divides out the obsolete fact and multiplies in the new fact —
598
+ a single atomic gauge transformation on the state integer.
599
+
600
+ Args:
601
+ global_state: The current global Gödel integer.
602
+ old_axiom_key: Key of the axiom to replace (``subj||pred||obj``).
603
+ new_axiom_key: Key of the replacement axiom (``subj||pred||obj``).
604
+
605
+ Returns:
606
+ The updated global state.
607
+
608
+ Raises:
609
+ ValueError: If the new axiom key is malformed.
610
+ """
611
+ parts = new_axiom_key.split("||")
612
+ if len(parts) != 3:
613
+ raise ValueError(
614
+ "Invalid axiom format. Must be subject||predicate||object"
615
+ )
616
+
617
+ new_prime = self.get_or_mint_prime(parts[0], parts[1], parts[2])
618
+ state_without_old = self.delete_axiom(global_state, old_axiom_key)
619
+
620
+ return math.lcm(state_without_old, new_prime)
621
+
622
+ # ------------------------------------------------------------------
623
+ # Gödel Sync Protocol (Distributed Delta)
624
+ # ------------------------------------------------------------------
625
+
626
+ def calculate_network_delta(
627
+ self, global_state: int, client_state: int
628
+ ) -> dict:
629
+ """
630
+ O(1) Distributed State Synchronization.
631
+
632
+ Compares the server's global integer with the client's integer to
633
+ compute the exact semantic delta:
634
+ shared_truth = gcd(global, client)
635
+ missing_product = global // shared_truth → axioms to ADD
636
+ obsolete_product = client // shared_truth → axioms to DELETE
637
+
638
+ Args:
639
+ global_state: The server's current Gödel integer.
640
+ client_state: The client's cached Gödel integer.
641
+
642
+ Returns:
643
+ Dict with ``"add"`` and ``"delete"`` lists of axiom key strings.
644
+ """
645
+ if global_state == client_state:
646
+ return {"add": [], "delete": []}
647
+
648
+ # ── Bare-Metal Fast Path (Zig BigInt GCD) ──
649
+ zig = _get_zig_engine()
650
+ if zig is not None:
651
+ zig_gcd = zig.bigint_gcd(global_state, client_state)
652
+ if zig_gcd is not None:
653
+ shared_truth = zig_gcd
654
+ else:
655
+ shared_truth = math.gcd(global_state, client_state)
656
+ else:
657
+ shared_truth = math.gcd(global_state, client_state)
658
+
659
+ # Primes the client is missing (server has, client doesn't)
660
+ missing_product = global_state // shared_truth
661
+
662
+ # Primes the client has that are obsolete
663
+ obsolete_product = client_state // shared_truth
664
+
665
+ def _extract_axioms(product: int) -> List[str]:
666
+ axioms: List[str] = []
667
+ for prime, axiom in self.prime_to_axiom.items():
668
+ if product % prime == 0:
669
+ axioms.append(axiom)
670
+ while product % prime == 0:
671
+ product //= prime
672
+ if product == 1:
673
+ break
674
+ return axioms
675
+
676
+ return {
677
+ "add": _extract_axioms(missing_product),
678
+ "delete": _extract_axioms(obsolete_product),
679
+ }
680
+
681
+ # ------------------------------------------------------------------
682
+ # Fractal Crystallization (Semantic Zooming)
683
+ # ------------------------------------------------------------------
684
+
685
+ def crystallize_axioms(
686
+ self,
687
+ global_state: int,
688
+ micro_axiom_keys: List[str],
689
+ macro_axiom_key: str,
690
+ ) -> int:
691
+ """
692
+ O(1) Fractal Compression (Zoom Out).
693
+
694
+ Replaces a cluster of micro-primes with a single Macro-Prime.
695
+ Stores the cluster product as provenance for lossless
696
+ decompression via ``decrystallize_axiom``.
697
+
698
+ Args:
699
+ global_state: Current global Gödel integer.
700
+ micro_axiom_keys: Keys of micro-axioms to compress.
701
+ macro_axiom_key: Key for the new macro-axiom.
702
+
703
+ Returns:
704
+ Updated global state with micro-primes replaced by macro-prime.
705
+ """
706
+ cluster_product = 1
707
+
708
+ for key in micro_axiom_keys:
709
+ key = key.strip().lower()
710
+ if (
711
+ key in self.axiom_to_prime
712
+ and global_state % self.axiom_to_prime[key] == 0
713
+ ):
714
+ prime = self.axiom_to_prime[key]
715
+ cluster_product *= prime
716
+ # Completely factor out the micro-prime
717
+ while global_state % prime == 0:
718
+ global_state //= prime
719
+
720
+ if cluster_product == 1:
721
+ return global_state # No active micro-primes found
722
+
723
+ parts = macro_axiom_key.split("||")
724
+ if len(parts) != 3:
725
+ raise ValueError(
726
+ "Invalid macro axiom format. Must be subject||predicate||object"
727
+ )
728
+
729
+ macro_prime = self.get_or_mint_prime(parts[0], parts[1], parts[2])
730
+
731
+ # Store provenance for lossless decompression
732
+ self.macro_provenance[macro_prime] = cluster_product
733
+
734
+ return math.lcm(global_state, macro_prime)
735
+
736
+ def decrystallize_axiom(
737
+ self, global_state: int, macro_axiom_key: str
738
+ ) -> int:
739
+ """
740
+ O(1) Semantic Decompression (Zoom In).
741
+
742
+ Divides out the Macro-Prime and restores the full cluster of
743
+ micro-primes from stored provenance.
744
+
745
+ Args:
746
+ global_state: Current global Gödel integer.
747
+ macro_axiom_key: Key of the macro-axiom to decompress.
748
+
749
+ Returns:
750
+ Updated global state with micro-primes restored.
751
+ """
752
+ macro_axiom_key = macro_axiom_key.strip().lower()
753
+
754
+ if macro_axiom_key not in self.axiom_to_prime:
755
+ return global_state
756
+
757
+ macro_prime = self.axiom_to_prime[macro_axiom_key]
758
+
759
+ if (
760
+ global_state % macro_prime != 0
761
+ or macro_prime not in self.macro_provenance
762
+ ):
763
+ return global_state
764
+
765
+ # Factor out the macro-prime
766
+ while global_state % macro_prime == 0:
767
+ global_state //= macro_prime
768
+
769
+ # Restore the micro-prime cluster
770
+ return math.lcm(global_state, self.macro_provenance[macro_prime])
771
+
772
+
773
+ # ======================================================================
774
+ # Phase 19D: Active Prime Set Index
775
+ # ======================================================================
776
+
777
+ class ActivePrimeIndex:
778
+ """O(1) active-prime lookup per branch.
779
+
780
+ Maintains a ``Set[int]`` of primes known to divide each branch's
781
+ state integer. This eliminates the O(n) scan over
782
+ ``prime_to_axiom`` that dominated profiling at scale:
783
+
784
+ get_active_axioms : 700 ms → O(k) where k = active primes
785
+ calculate_network_delta: 3.7 s → O(k)
786
+
787
+ Lifecycle:
788
+ rebuild() — cold-start from a state integer (boot / merge)
789
+ add() — O(1) on ingest
790
+ remove() — O(1) on delete
791
+ fork() — O(k) on branch creation
792
+ """
793
+
794
+ def __init__(self):
795
+ self._branches: Dict[str, Set[int]] = {}
796
+
797
+ def rebuild(
798
+ self, branch: str, state: int, algebra: GodelStateAlgebra
799
+ ) -> None:
800
+ """Cold-start: scan once to populate the index from a state integer."""
801
+ if state <= 1:
802
+ self._branches[branch] = set()
803
+ return
804
+ self._branches[branch] = {
805
+ p for p in algebra.prime_to_axiom if state % p == 0
806
+ }
807
+
808
+ def add(self, branch: str, prime: int) -> None:
809
+ """Register a newly-minted prime as active in a branch."""
810
+ self._branches.setdefault(branch, set()).add(prime)
811
+
812
+ def remove(self, branch: str, prime: int) -> None:
813
+ """Remove a prime from a branch (deletion / DIV)."""
814
+ if branch in self._branches:
815
+ self._branches[branch].discard(prime)
816
+
817
+ def fork(self, source: str, target: str) -> None:
818
+ """Copy the active set from one branch to another."""
819
+ self._branches[target] = set(self._branches.get(source, set()))
820
+
821
+ def merge(self, target: str, *sources: str) -> None:
822
+ """Union active sets from multiple branches into target."""
823
+ merged: Set[int] = set()
824
+ for src in sources:
825
+ merged |= self._branches.get(src, set())
826
+ self._branches[target] = merged
827
+
828
+ def get_active_primes(self, branch: str) -> Set[int]:
829
+ """Return the set of active primes for a branch."""
830
+ return self._branches.get(branch, set())
831
+
832
+ def get_active_axioms(
833
+ self, branch: str, algebra: GodelStateAlgebra
834
+ ) -> list:
835
+ """Return axiom key strings for all active primes in a branch."""
836
+ return [
837
+ algebra.prime_to_axiom[p]
838
+ for p in self._branches.get(branch, set())
839
+ if p in algebra.prime_to_axiom
840
+ ]
841
+
842
+ def assert_coherent(
843
+ self,
844
+ branch: str,
845
+ state: int,
846
+ algebra: "GodelStateAlgebra",
847
+ context: str = "",
848
+ ) -> None:
849
+ """Debug assertion: verify index matches brute-force scan."""
850
+ import os
851
+ if not os.getenv("SUM_DEBUG_INDEX"):
852
+ return
853
+
854
+ indexed = sorted(self.get_active_axioms(branch, algebra))
855
+ brute = sorted(algebra.get_active_axioms(state))
856
+ if indexed != brute:
857
+ indexed_set = set(indexed)
858
+ brute_set = set(brute)
859
+ missing = brute_set - indexed_set
860
+ extra = indexed_set - brute_set
861
+ raise AssertionError(
862
+ f"INDEX COHERENCE VIOLATION [{context}] "
863
+ f"branch={branch}: "
864
+ f"index has {len(indexed)} axioms, "
865
+ f"brute-force has {len(brute)} axioms. "
866
+ f"Missing from index: {missing}. "
867
+ f"Extra in index: {extra}."
868
+ )
869
+
870
+ def extract_axioms_from_product(
871
+ self, product: int, algebra: GodelStateAlgebra,
872
+ candidate_primes: Set[int] = None,
873
+ ) -> List[str]:
874
+ """Extract axiom keys from a quotient product, optionally narrowed.
875
+
876
+ When ``candidate_primes`` is provided, only those primes are
877
+ checked — O(k) instead of O(n). Falls back to full scan if
878
+ no candidates are given.
879
+ """
880
+ axioms: List[str] = []
881
+ primes_to_check = candidate_primes or set(algebra.prime_to_axiom.keys())
882
+ for prime in primes_to_check:
883
+ if product % prime == 0:
884
+ if prime in algebra.prime_to_axiom:
885
+ axioms.append(algebra.prime_to_axiom[prime])
886
+ while product % prime == 0:
887
+ product //= prime
888
+ if product == 1:
889
+ break
890
+ return axioms