File size: 2,495 Bytes
7ed141b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Compile a circuit into the attractor computer's coupling matrix and ship it
as variants/neural_attractor.safetensors, a peer artifact to the other machines:
here the weights are the couplings Q (with linear terms L), and running is
relaxation. Round-trips the file and checks forward evaluation and a backward
inversion (factoring)."""
from __future__ import annotations
import os
import random
import sys

import torch
from safetensors.torch import save_file, load_file
from safetensors import safe_open

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(ROOT, "src"))
from attractor import multiplier, to_tensors, from_tensors

OUT = os.path.join(ROOT, "variants", "neural_attractor.safetensors")
BITS = 8


def main() -> int:
    c, io = multiplier(BITS)
    tensors, meta = to_tensors(c, io)
    save_file(tensors, OUT, metadata=meta)
    size = os.path.getsize(OUT)
    print(f"Built {os.path.relpath(OUT, ROOT)}: {BITS}x{BITS} multiplier as couplings")
    print(f"  wires={c.n}  Q entries={len(c.Q)}  L entries={len(c.L)}  size={size/1024:.1f} KB")

    # round-trip
    t = load_file(OUT)
    with safe_open(OUT, framework="pt") as f:
        m = f.metadata()
    c2, io2 = from_tensors(t, m)
    xs, ys, zero, prod = io2["xs"], io2["ys"], io2["zero"], io2["prod"]

    rng = random.Random(0)
    bad = 0
    for _ in range(200):
        a, b = rng.randint(0, 255), rng.randint(0, 255)
        clamp = {zero: 0}
        for k in range(BITS):
            clamp[xs[k]] = (a >> k) & 1
            clamp[ys[k]] = (b >> k) & 1
        s = c2.forward_eval(clamp)
        got = sum(s[w] << k for k, w in enumerate(prod))
        if got != a * b or c2.energy(s) != 0:
            bad += 1
    print(f"  round-trip forward multiply (200 cases): {'OK' if bad == 0 else f'FAIL({bad})'}")

    # backward: factor a small product through the loaded couplings
    N = 35
    target = {prod[k]: (N >> k) & 1 for k in range(2 * BITS)}
    s = c2.solve(xs + ys, {zero: 0}, target, sweeps=2500, restarts=120, seed=N)
    if s is not None:
        fa = sum(s[xs[k]] << k for k in range(BITS))
        fb = sum(s[ys[k]] << k for k in range(BITS))
        print(f"  round-trip backward factor {N}: {fa} x {fb} {'OK' if fa * fb == N else 'WRONG'}")
        ok = fa * fb == N
    else:
        print(f"  round-trip backward factor {N}: not found")
        ok = False
    return 0 if (bad == 0 and ok) else 1


if __name__ == "__main__":
    sys.exit(main())