File size: 4,577 Bytes
4a3e194
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
"""The cost of instantiation against the cost of the network.

One generation of the host is: inst splits the emitted bytes, sigma^-1 parses
the first field into the netlist, Lev places the rows and entries of the
layered map, and the device is applied once per step. This script counts those
operations, one per byte read by inst and by sigma^-1, one per row and one per
nonzero entry placed by Lev, and one per device application, times each of
them, and compares the total with the T * M unit evaluations of the run.
"""
import json
import os
import sys
import time

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


def runs_path(name: str) -> str:
    d = os.path.join(REPO, "paper", "runs")
    os.makedirs(d, exist_ok=True)
    return os.path.join(d, name)


def main() -> int:
    from selfrep import (M_STAR, inst, ser, tau_star, run_reference, read_host,
                         host_netlist, sigma_host)
    from netlist_io import net_of_sigma
    from matrix8 import compile_net

    sigma_bytes = read_host()
    tau = tau_star(sigma_bytes, M_STAR)
    s = ser(sigma_bytes, bytes(M_STAR), tau)

    # sigma: parameters and predecessor entries stored, and the time to write
    t0 = time.perf_counter()
    net, inputs, outputs = host_netlist()
    t_build = time.perf_counter() - t0
    t0 = time.perf_counter()
    encoded = sigma_host()
    t_sigma = time.perf_counter() - t0
    assert encoded == sigma_bytes
    stored, _, _, _ = net_of_sigma(sigma_bytes)
    entries = (2 * len(stored.gates)                       # bias and fan-in
               + sum(len(i) for i, _ in stored.gates.values())
               + len(outputs))
    print(f"  sigma: {entries:,} stored entries -> {len(encoded):,} bytes "
          f"in {t_sigma * 1e3:.0f} ms ({t_build * 1e3:.0f} ms to assemble "
          f"the netlist from source)")

    # inst: one pass over the serialized instance, then sigma^-1 on its first field
    t0 = time.perf_counter()
    reps = 50
    for _ in range(reps):
        a, b, c = inst(s)
    t_inst = (time.perf_counter() - t0) / reps
    assert (a, b, c) == (sigma_bytes, bytes(M_STAR), tau)
    t0 = time.perf_counter()
    for _ in range(5):
        N, I, O, _ = net_of_sigma(a)
    t_sigma_inv = (time.perf_counter() - t0) / 5
    assert len(N.gates) == len(stored.gates)
    print(f"  inst: {len(s):,} bytes parsed in {t_inst * 1e3:.2f} ms, and "
          f"{len(N.gates):,} units rebuilt from the first field in "
          f"{t_sigma_inv * 1e3:.0f} ms")

    # Lev: the units placed, and the time to place them
    t0 = time.perf_counter()
    layers, info = compile_net(N, I, O)
    t_lev = time.perf_counter() - t0
    M = sum(int(W.shape[0]) for W, _ in layers)
    nnz = sum(int((W != 0).sum()) for W, _ in layers)
    print(f"  Lev: {len(N.gates):,} units in, {M:,} rows and {nnz:,} nonzero "
          f"entries placed over {info['layers']} layers in {t_lev:.1f} s")

    # the device: one application per step, at most one byte moved
    t0 = time.perf_counter()
    emitted, T = run_reference(M_STAR, tau)
    t_run = time.perf_counter() - t0
    assert emitted == s
    print(f"  device: {T:,} applications, {len(emitted):,} bytes emitted "
          f"({t_run:.2f} s for the whole reference run)")

    env_ops = len(s) + len(sigma_bytes) + M + nnz + T
    closed = 2 * len(sigma_bytes) + len(bytes(M_STAR)) + len(tau) + 16 + M + nnz + T
    assert env_ops == closed, (env_ops, closed)
    net_ops = T * M
    print(f"  instantiation: {env_ops:,} elementary operations per generation, "
          f"which is the closed form 2|sigma|+|m|+|tau|+16+M+nnz+T")
    print(f"  network:     {net_ops:,} unit evaluations (T = {T:,}, M = {M:,})")
    print(f"  ratio: {env_ops / net_ops:.3e}")

    out = {"sigma_entries": entries, "sigma_bytes": len(encoded),
           "sigma_seconds": t_sigma, "build_seconds": t_build,
           "inst_bytes": len(s), "inst_seconds": t_inst,
           "sigma_inverse_seconds": t_sigma_inv,
           "lev_units_in": len(N.gates), "lev_units_out": M, "lev_nonzero": nnz,
           "lev_layers": info["layers"], "lev_seconds": t_lev,
           "lev_entries": info["total_weights"],
           "steps": T, "emitted_bytes": len(emitted),
           "reference_seconds": t_run,
           "environment_ops": env_ops, "network_ops": net_ops,
           "ratio": env_ops / net_ops}
    json.dump(out, open(runs_path("paper_environment.json"), "w"), indent=1)
    return 0


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