h4-polytopic-attention / python /h4_mcp_server.py
grapheneaffiliates's picture
Upload python/h4_mcp_server.py with huggingface_hub
04cee0c verified
"""
H4 Polytopic Attention — MCP Server (Phase 4)
===============================================
Exposes the H4 transformer executor as an MCP server for Claude Code.
Phase 4 adds E8 lattice-indexed RAM with STORE_MEM/LOAD_MEM opcodes.
Usage:
Add to Claude Code settings.json:
{
"mcpServers": {
"h4-executor": {
"command": "py",
"args": ["C:/Users/atchi/h4-polytopic-attention/python/h4_mcp_server.py"]
}
}
}
Author: Timothy McGirl
"""
import sys
import os
import json
# Add parent to path for imports
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
import numpy as np
from weight_compiler import (
Program, fibonacci_program, H4Executor,
StateEncoder, CompiledTransformer,
generate_600_cell_vertices, h4_simple_roots,
PHI, PHI_INV,
)
server = Server("h4-executor")
@server.list_tools()
async def list_tools():
return [
Tool(
name="h4_fibonacci",
description="Compute Fibonacci sequence using the H4 polytopic attention transformer executor. Runs through analytically constructed transformer weights with 4D H4 (600-cell) attention heads. Returns F(0) through F(n+1).",
inputSchema={
"type": "object",
"properties": {
"n": {"type": "integer", "description": "Number of Fibonacci iterations (computes up to F(n+1)), max 30"}
},
"required": ["n"]
},
),
Tool(
name="h4_compile_and_run",
description=(
"Compile and run a custom program on the H4 transformer executor. "
"Phase 4 ISA: LOAD (immediate to register), ADD, SUB, MUL (register ops), "
"STORE (copy), STORE_MEM (R[a] to E8 lattice at addr R[b]), "
"LOAD_MEM (E8 lattice at addr R[a] to R[dest]), "
"JMP, JNZ, HALT. 8 registers R0-R7. "
"Memory ops use E8 Voronoi cell bucketing with 240 kissing-neighbor lookup."
),
inputSchema={
"type": "object",
"properties": {
"instructions": {
"type": "array",
"description": "List of instructions",
"items": {
"type": "object",
"properties": {
"opcode": {
"type": "string",
"enum": ["LOAD", "ADD", "SUB", "MUL", "STORE",
"STORE_MEM", "LOAD_MEM",
"JMP", "JNZ", "HALT"]
},
"a": {"type": "integer", "description": "First operand (register index or immediate)"},
"b": {"type": "integer", "description": "Second operand (register index)"},
"dest": {"type": "integer", "description": "Destination register"}
},
"required": ["opcode"]
}
},
"max_steps": {"type": "integer", "description": "Max execution steps (default 500)"}
},
"required": ["instructions"]
},
),
Tool(
name="h4_geometry_info",
description="Get H4 polytope geometry info: 600-cell vertices, Coxeter chambers, dot products, golden ratio structure. Aspects: vertices, chambers, dot_products, golden_ratio, all.",
inputSchema={
"type": "object",
"properties": {
"aspect": {
"type": "string",
"enum": ["vertices", "chambers", "dot_products", "golden_ratio", "all"],
"description": "Which aspect to query"
}
},
"required": ["aspect"]
},
),
Tool(
name="h4_benchmark",
description="Benchmark the H4 attention system: encoding throughput and forward pass timing at different trace lengths.",
inputSchema={
"type": "object",
"properties": {
"n_steps": {"type": "integer", "description": "Number of steps (default 500)"}
},
},
),
Tool(
name="h4_lattice_memory",
description=(
"Phase 4: E8 lattice memory diagnostics. "
"Run a program that exercises STORE_MEM/LOAD_MEM and return "
"E8 Voronoi cell utilization stats: occupied cells, bucket distribution, "
"primary hit rate, kissing number verification (240). "
"Actions: 'benchmark' (store+load n entries), 'info' (E8 lattice constants)."
),
inputSchema={
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["benchmark", "info"],
"description": "Action to perform"
},
"n_entries": {
"type": "integer",
"description": "Number of entries for benchmark (default 1000)"
}
},
"required": ["action"]
},
),
]
@server.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "h4_fibonacci":
return await _h4_fibonacci(arguments)
elif name == "h4_compile_and_run":
return await _h4_compile_and_run(arguments)
elif name == "h4_geometry_info":
return await _h4_geometry_info(arguments)
elif name == "h4_benchmark":
return await _h4_benchmark(arguments)
elif name == "h4_lattice_memory":
return await _h4_lattice_memory(arguments)
else:
return [TextContent(type="text", text=f"Unknown tool: {name}")]
async def _h4_fibonacci(args):
n = min(args["n"], 30)
prog = fibonacci_program(n)
executor = H4Executor(prog, d_model=32)
old_stdout = sys.stdout
sys.stdout = open(os.devnull, 'w')
try:
result = executor.run(max_steps=500)
finally:
sys.stdout.close()
sys.stdout = old_stdout
seen = set()
fib_seq = []
for regs in executor.register_history:
v = int(regs[1])
if v not in seen:
seen.add(v)
fib_seq.append(v)
expected = [0, 1]
for _ in range(n):
expected.append(expected[-1] + expected[-2])
output = {
"fibonacci_n": n,
"result": int(result['registers'][1]),
"expected": expected[n + 1],
"correct": int(result['registers'][1]) == expected[n + 1],
"steps": result['steps'],
"sequence": fib_seq[:n + 2],
"registers": [int(r) for r in result['registers'][:6]],
"transformer": {"d_model": 32, "n_heads": 8, "n_layers": 4, "head_dim": "4D_H4"},
}
return [TextContent(type="text", text=json.dumps(output, indent=2))]
async def _h4_compile_and_run(args):
instructions = args["instructions"]
max_steps = args.get("max_steps", 500)
prog = Program()
for instr in instructions:
prog.add(
instr.get("opcode", "HALT"),
a=instr.get("a", 0),
b=instr.get("b", 0),
dest=instr.get("dest", 0),
)
executor = H4Executor(prog, d_model=32)
old_stdout = sys.stdout
sys.stdout = open(os.devnull, 'w')
try:
result = executor.run(max_steps=max_steps)
finally:
sys.stdout.close()
sys.stdout = old_stdout
output = {
"program_length": len(prog),
"steps": result['steps'],
"halted": result['halted'],
"registers": [int(r) for r in result['registers']],
"lattice_memory": result.get('lattice_memory', {}),
}
return [TextContent(type="text", text=json.dumps(output, indent=2))]
async def _h4_geometry_info(args):
aspect = args["aspect"]
vertices = generate_600_cell_vertices()
roots = h4_simple_roots()
info = {}
if aspect in ("vertices", "all"):
info["vertices"] = {
"count": len(vertices),
"on_unit_sphere": bool(np.allclose(np.linalg.norm(vertices, axis=1), 1.0)),
"orbits": ["8: perms of (+-1,0,0,0)", "16: (+-1/2)^4", "96: even perms of (0,+-1/2,+-phi/2,+-1/2phi)"],
}
if aspect in ("chambers", "all"):
info["chambers"] = {
"group": "W(H4)", "order": 14400,
"simple_roots": [[round(x, 6) for x in r] for r in roots.tolist()],
}
if aspect in ("dot_products", "all"):
dots = vertices @ vertices.T
unique = np.unique(np.round(dots[~np.eye(len(vertices), dtype=bool)].flatten(), 6))
info["dot_products"] = {
"unique_count": len(unique),
"values": [round(v, 6) for v in sorted(unique.tolist())],
"has_phi_half": bool(any(abs(d - PHI/2) < 0.01 for d in unique)),
}
if aspect in ("golden_ratio", "all"):
info["golden_ratio"] = {
"phi": round(PHI, 15), "phi_inv": round(PHI_INV, 15),
"phi^2 = phi+1": abs(PHI**2 - PHI - 1) < 1e-12,
"roles": [
"vertex coordinates",
"Coxeter eigenvalues",
"E8->H4 projection (cos(pi/5) = phi/2)",
"Fibonacci checkpoint spacing",
"Lattice memory Voronoi cell geometry",
],
}
return [TextContent(type="text", text=json.dumps(info, indent=2))]
async def _h4_benchmark(args):
import time
n = args.get("n_steps", 500)
encoder = StateEncoder(32)
transformer = CompiledTransformer(32)
dummy = type('obj', (object,), {'opcode': 'ADD', 'operand_a': 0, 'operand_b': 1, 'dest': 2})()
regs = np.zeros(8)
start = time.time()
states = [encoder.encode_state(i % 12, regs, dummy, i) for i in range(n)]
enc_time = time.time() - start
timings = {}
for cp in [50, 100, 250, min(n, 500)]:
if cp > len(states):
break
t0 = time.time()
trace = np.array(states[:cp])
_ = transformer.forward_layer(trace, transformer.layers[0])
timings[f"{cp}_steps"] = f"{time.time()-t0:.3f}s"
output = {
"n_steps": n,
"encoding": f"{enc_time:.3f}s ({n/enc_time:.0f} states/s)",
"forward_pass": timings,
}
return [TextContent(type="text", text=json.dumps(output, indent=2))]
async def _h4_lattice_memory(args):
import time
from h4_polytopic_attention import E8LatticeIndex
action = args["action"]
if action == "info":
lattice = E8LatticeIndex()
proj = lattice.projection_matrix
output = {
"e8_lattice": {
"dimension": 8,
"kissing_number": len(lattice.kissing_vectors),
"kissing_vectors_verified": len(lattice.kissing_vectors) == 240,
"voronoi_cell_structure": "D8 union (D8 + [1/2]^8)",
"decoder": "O(1) closest-lattice-point",
},
"e8_to_h4_projection": {
"shape": "4x8",
"eigenvalues": {
"cos(pi/5)": round(float(proj[0, 0]), 10),
"phi/2": round(float(PHI / 2), 10),
"match": abs(float(proj[0, 0]) - PHI / 2) < 1e-10,
"cos(2pi/5)": round(float(proj[0, 2]), 10),
"1/(2phi)": round(float(PHI_INV / 2), 10),
},
"purpose": "Unifies 8D memory addressing with 4D H4 attention geometry",
},
"memory_opcodes": {
"STORE_MEM": "R[a] -> E8 Voronoi cell at address R[b]",
"LOAD_MEM": "E8 Voronoi cell at address R[a] -> R[dest]",
},
"max_cell_size": lattice.max_cell_size,
}
return [TextContent(type="text", text=json.dumps(output, indent=2))]
elif action == "benchmark":
n = args.get("n_entries", 1000)
lattice = E8LatticeIndex()
# Store phase
start = time.time()
embeddings = []
for i in range(n):
emb = np.zeros(8)
for j in range(4):
theta = i * PHI_INV * (2 * np.pi) * (j + 1)
emb[2*j] = np.cos(theta) * (1.0 + i * 0.001)
emb[2*j + 1] = np.sin(theta) * (1.0 + i * 0.001)
lattice.insert(emb, value=float(i), address=i)
embeddings.append(emb)
store_time = time.time() - start
# Load phase (query same embeddings back)
start = time.time()
hits = 0
for emb in embeddings:
results = lattice.query_nearest(emb, k=1)
if results:
hits += 1
load_time = time.time() - start
stats = lattice.stats()
output = {
"benchmark": {
"n_entries": n,
"store_time_s": round(store_time, 4),
"store_rate": f"{n/store_time:.0f} ops/s",
"load_time_s": round(load_time, 4),
"load_rate": f"{n/load_time:.0f} ops/s",
"hit_rate": f"{hits}/{n} ({hits/n*100:.1f}%)",
},
"lattice_stats": {
"total_entries": stats['total_entries'],
"occupied_cells": stats['occupied_cells'],
"utilization": f"{stats['utilization']:.1%}",
"max_bucket_size": stats['max_bucket_size'],
"avg_bucket_size": round(stats['avg_bucket_size'], 2),
"primary_hit_rate": f"{stats['primary_hit_rate']:.1%}",
},
}
return [TextContent(type="text", text=json.dumps(output, indent=2))]
async def main():
async with stdio_server() as (read, write):
await server.run(read, write, server.create_initialization_options())
if __name__ == "__main__":
import asyncio
asyncio.run(main())