File size: 2,969 Bytes
032a961
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
"""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