SPIRA / python /spira /hashing.py
thefinalboss's picture
SPIRA v2: entropy-patch tokenization + hierarchical dopamine-gated spiking cortex + hippocampal one-shot memory with replay consolidation
032a961 verified
Raw History Blame Contribute Delete
2.97 kB
"""Deterministic hashing utilities shared between the Python prototype and the
TypeScript web port.
Every function here is specified to be bit-identical to its TypeScript
counterpart (see web demo ``src/lib/spira/hashing.ts``). All arithmetic is
64-bit unsigned wrapped (Python ints / BigInt in TS) or 32-bit unsigned where
noted. No platform-dependent behaviour is allowed in this module.
"""
from __future__ import annotations
MASK32 = 0xFFFFFFFF
MASK64 = 0xFFFFFFFFFFFFFFFF
FNV_OFFSET_BASIS = 0xCBF29CE484222325
FNV_PRIME_64 = 0x100000001B3
# Salts for hippocampal lane keys (one per context slot).
LANE_SALTS = (
0x9E3779B97F4A7C15,
0xBF58476D1CE4E5B9,
0x94D049BB133111EB,
0x2545F4914F6DDC1D,
)
def fnv1a64(data: bytes, seed: int = 0) -> int:
"""FNV-1a 64-bit hash of a byte string, with an optional seed XORed into
the offset basis. Used to content-address EPT patches."""
h = (FNV_OFFSET_BASIS ^ (seed & MASK64)) & MASK64
for b in data:
h ^= b
h = (h * FNV_PRIME_64) & MASK64
return h
def splitmix64(x: int) -> int:
"""splitmix64 finalizer (MurmurHash3 helper). 64-bit in, 64-bit out."""
z = (x + 0x9E3779B97F4A7C15) & MASK64
z = ((z ^ (z >> 30)) * 0xBF58476D1CE4E5B9) & MASK64
z = ((z ^ (z >> 27)) * 0x94D049BB133111EB) & MASK64
return (z ^ (z >> 31)) & MASK64
def lane_key32(patch_id: int, lane: int) -> int:
"""32-bit key for one hippocampal lane (context slot ``lane``).
High 32 bits of splitmix64 give excellent avalanche while staying
representable as a JS ``number`` (via >>> ops) in the TypeScript port.
"""
return splitmix64(patch_id ^ LANE_SALTS[lane]) >> 32
class Mulberry32:
"""mulberry32 PRNG (bryc, public domain).
Produces the exact same float sequence as the TS implementation, so
network weights regenerated from a seed are bit-identical across
languages. Returns uniforms in [0, 1).
"""
__slots__ = ("state",)
def __init__(self, seed: int) -> None:
self.state = seed & MASK32
def next_float(self) -> float:
self.state = (self.state + 0x6D2B79F5) & MASK32
t = self.state
t = ((t ^ (t >> 15)) * (t | 1)) & MASK32
t = (t ^ (t + ((((t ^ (t >> 7)) * (t | 61)) & MASK32)))) & MASK32
return ((t ^ (t >> 14)) & MASK32) / 4294967296.0
def next_weight(self, scale: float) -> float:
"""Symmetric uniform weight in [-scale, scale]."""
return (self.next_float() * 2.0 - 1.0) * scale
def input_neurons(patch_id: int, d_in: int, k_in: int) -> list[int]:
"""Map a patch id to ``k_in`` input-neuron indices (hashing trick).
No embedding table: the projection is a pure function of the patch id,
so any patch ever seen (or never seen) projects consistently.
"""
out = []
for j in range(k_in):
h = splitmix64(patch_id ^ (0x51ED270B733D4C31 + j * 0x9E3779B97F4A7C15))
out.append((h >> 32) % d_in)
return out