#!/usr/bin/env python3 """ Hyperdimensional Vocab Memory — oscillator associative memory for a language model. - Encode vocab as 256 complex oscillator hypervectors (random projection). - Burn in token co-occurrence from text corpus (Hebbian relationship modulation). - Query: context string → recall associated tokens by phase-coherent pattern completion. - Fuse: memory scores boost model logits (3B params for reasoning, memory for knowledge → functions like a larger model). Real Llama 3B tokenizer + bf16 embeddings, text corpus from the local disk. python3 hyper_vocab_memory.py """ import glob, json, math, os, struct, sys, time import numpy as np # ── tokenizer + embeddings (llama 3B, mmap'd bf16) ────────────────────── BASE = glob.glob("/home/compunerd/.cache/huggingface/hub/" "models--huihui-ai--Hermes-3-Llama-3.2-3B-abliterated/" "snapshots/*")[0] sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "bqsm_assist")) # use the Safetensors helper inline rather than import (avoids directory issues) C = json.load(open(os.path.join(BASE, "config.json"))) D = C["hidden_size"] TK = json.load(open(os.path.join(BASE, "tokenizer.json"))) VOCAB = TK["model"]["vocab"] # token -> id INV = {v: k for k, v in VOCAB.items()} class ST: """Minimal safetensors reader — mmap, no copy on parse.""" def __init__(self): self.shards, self.idx = [], {} for p in sorted(glob.glob(os.path.join(BASE, "*.safetensors"))): mm = np.memmap(p, dtype=np.uint8, mode="r") n = struct.unpack("/\\|+-=*&^%$#@~`").strip() if not w: continue key = ("Ġ" + w) if i else w if key in VOCAB: ids.append(VOCAB[key]) elif w in VOCAB: ids.append(VOCAB[w]) else: for ch in key: if ch in VOCAB: ids.append(VOCAB[ch]) return ids def dec(i): return INV.get(i, f"[{i}]").replace("Ġ", " ").replace("Ċ", "\n") # ── Hyperdimensional encoding: token embedding → oscillator state ─────── N_OSC = 256 rng = np.random.default_rng(42) # random projection matrix [2*N_OSC, D] PROJ = rng.standard_normal((N_OSC * 2, D), dtype=np.float32) / np.sqrt(D) def osc_vector(tok, cache): """Complex oscillator state for a token (from cache), or zeros if unseen.""" v = cache.get(tok) return v if v is not None else np.zeros(N_OSC, dtype=np.complex64) def build_cache(token_ids, chunk=4096, label=""): """Encode token IDs into normalized complex oscillator states (batched). Reads the bf16 embedding matrix via mmap in chunks, projects each chunk, and stores a compact complex64 vector per token. Full vocab (~128K) is ~262 MB of cache — built chunk-wise so peak memory stays ~100 MB.""" si, v = st.idx["model.embed_tokens.weight"] mm, st_off = st.shards[si] D_emb = v["shape"][1] a, b = v["data_offsets"] base = st_off + a ids = list(token_ids) cache = {} for i in range(0, len(ids), chunk): batch = ids[i:i + chunk] lo, hi = batch[0], batch[-1] off = base + lo * D_emb * 2 raw = np.asarray(mm[off: off + (hi - lo + 1) * D_emb * 2]) E = ((raw.view(np.uint16).astype(np.uint32) << 16) ).view(np.float32).reshape(hi - lo + 1, D_emb) P = E[[t - lo for t in batch]] @ PROJ.T # [batch, 2*N_OSC] P /= (np.linalg.norm(P, axis=1, keepdims=True) + 1e-8) C = (P[:, :N_OSC] + 1j * P[:, N_OSC:]).astype(np.complex64) for j, t in enumerate(batch): cache[t] = C[j] if label and (i == 0 or (i + chunk) >= len(ids)): print(f" {label} {min(i + chunk, len(ids))}/{len(ids)}", flush=True) return cache # ── Gather the tokens that actually matter (corpus + queries) ─────────── corpus_files = [ "/home/compunerd/agent_framework/README.md", "/home/compunerd/agent_framework/bqsm_assist/WAVE_RIDER_BREAKTHROUGH.md", "/home/compunerd/Desktop/bqsm/basin-quotient-machine/LENS_CONTROL_METHODS.md", "/home/compunerd/Desktop/bqsm/basin-quotient-machine/README.md", ] test_queries = [ "The capital of France is", "BQSM uses coupled", "The ring computes through mode", "lens site 0 enhances the", "Phase 0 Gate", "a transformer forward pass as", "the model with real bf16", "attention becomes geometric", ] used_ids = set() corpus_texts = [] for fp in corpus_files: if os.path.exists(fp): text = open(fp).read()[:50000] corpus_texts.append(text) used_ids.update(encode(text)) for q in test_queries: used_ids.update(encode(q)) # Full-dictionary coverage: encode the entire vocab so ANY token the model # emits can be scored/recalled. Corpus-derived associations still come from # `used_ids`, but every token now has a hypervector. BQSM_FULL_VOCAB=off # reverts to the corpus-subset cache for fast smoke tests. FULL_VOCAB = os.environ.get("BQSM_FULL_VOCAB", "on") != "off" if FULL_VOCAB: V = st.idx["model.embed_tokens.weight"][1]["shape"][0] print(f"encoding full vocab ({V} tokens) — one-time, ~30s...") t0 = time.time() cache = build_cache(range(V), label="vocab") print(f" {time.time()-t0:.1f}s ({len(cache)} tokens cached)") else: print(f"encoding {len(used_ids)} distinct tokens (corpus + queries)...") t0 = time.time() cache = build_cache(sorted(used_ids)) print(f" {time.time()-t0:.1f}s") # Burn-in + build sparse "following" index (skip-gram, distance-decayed) from collections import Counter, defaultdict print("\nBurn-in corpus (skip-gram PMI, window=3)...") MAX_DIST = 3 unigram = Counter() skipgram = {d: Counter() for d in range(1, MAX_DIST + 1)} total_tokens = 0 for text in corpus_texts: ids = encode(text) total_tokens += len(ids) unigram.update(ids) for d in range(1, MAX_DIST + 1): skipgram[d].update(zip(ids[:-d], ids[d:])) # Distance-decayed PMI: tokens d apart get weight 1/d. This captures # "France -> is -> Paris" as "France -> Paris" (d=2, weight 0.5), which is # what a pure bigram memory misses. W = np.zeros((N_OSC, N_OSC), dtype=np.complex64) following = defaultdict(list) # token_id -> [(target_id, weight), ...] n_pairs = 0 for d in range(1, MAX_DIST + 1): decay = 1.0 / d for (a, b), cnt in skipgram[d].items(): za = cache.get(a); zb = cache.get(b) if za is None or zb is None: continue pmi = math.log((cnt * total_tokens) / (unigram[a] * unigram[b]) + 1e-12) if pmi <= 0: continue w = decay * pmi W += w * np.outer(za, np.conj(zb)) following[a].append((b, w)) n_pairs += 1 print(f" {n_pairs} associations burned in (PMI>0), from {total_tokens} tokens") norm = np.linalg.norm(W) if norm > 0: W /= norm # ── Sparse recall: per context token, aggregate its strongest followers ─── def query_sparse(context_str, top_k=20): ids = encode(context_str) scores = defaultdict(float) for i, cid in enumerate(ids): if cid not in following: continue # last token gets 2× weight for next-token prediction w = 2.0 if i == len(ids) - 1 else 1.0 for tid, pmi in following[cid]: scores[tid] += w * pmi ranked = sorted(scores.items(), key=lambda x: x[1], reverse=True) return [r for r in ranked if r[0] in cache][:top_k] # ── Query: context → associative recall ────────────────────────────────── def query(context_str, top_k=20): """Encode context as oscillator state, recall associated tokens via W.""" ids = encode(context_str) ctx = np.zeros(N_OSC, dtype=np.complex64) n_valid = 0 for t in ids: z = cache.get(t) if z is not None: ctx += z n_valid += 1 if n_valid == 0: return [] ctx /= n_valid + 1e-8 recalled = W @ ctx recalled = recalled / (np.linalg.norm(recalled) + 1e-8) scores = [] for t, zt in cache.items(): score = float(abs(np.dot(np.conj(zt), recalled))) scores.append((t, score)) scores.sort(key=lambda x: x[1], reverse=True) return scores[:top_k] # ── Demo (only when run directly) ───────────────────────────────────────── if __name__ == "__main__": print("\n" + "=" * 66) print("HYPERDIMENSIONAL VOCAB MEMORY — recall demo") print("=" * 66) tests = [ ("The capital of France is", "Paris"), ("BQSM uses coupled", "oscillator"), ("The ring computes through mode", "coupling"), ("lens site 0 enhances the", "channel"), ("Phase 0 Gate", "FAILURE"), ("a transformer forward pass as", "coupled"), ("the model with real bf16", "weights"), ("attention becomes geometric", "adjacency"), ] def find_token(text): for t in cache: if dec(t).strip() == text: return t return None for context, expected in tests: results = query_sparse(context) expected_id = find_token(expected) rank = None for i, (t, s) in enumerate(results): if t == expected_id: rank = i + 1 break print(f"\n \"{context}\"") print(f" expect: \"{expected}\" rank: " f"{rank if rank else '-- (not in top %d)' % len(results)}") print(f" top 5: ", end="") for t, s in results[:5]: print(f"{dec(t)!r}({s:.4f})", end=" ") print() print("\n" + "=" * 66) print("FUSION — memory boosts model logits (simulated)") print("=" * 66) context = "The capital of France is" model_logits = {t: float(rng.standard_normal()) * 0.5 for t in cache} results = query_sparse(context) for t, mem_score in results: model_logits[t] = model_logits.get(t, 0.0) + 2.0 * mem_score top_after = sorted(model_logits, key=lambda t: model_logits[t], reverse=True)[:10] print(f" context: {context!r}") print(f" top-10 after fusion: {[dec(t) for t in top_after]}") paris_id = find_token("Paris") if paris_id: rank = top_after.index(paris_id) + 1 if paris_id in top_after else None print(f" 'Paris' rank after fusion: " f"{'#' + str(rank) if rank else '-- (out of top 10)'}") print("\n" + "=" * 66) print("HOW IT SCALES TO 30B-CLASS:") print(" - 3B model: grammar, reasoning, common patterns (its parameters)") print(" - Oscillator memory: facts, entity links, co-occurrence (burn-in)") print(" - The memory costs N² oscillators (~256² = 65K couplings), not GBs") print(" - Continually learns: new facts burn in without retraining the model") print(" - Hyperdimensional encoding: near-orthogonal random projections") print(" = associative memory for 128K vocab in ~65K complex couplings") print("=" * 66)