File size: 8,691 Bytes
a9ea017 | 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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | /* Generations of the ring machine M^alpha_{K,S,L}, and optionally its netlist stepped beside it.
*
* ring_run IN GENERATIONS [NETLIST]
*
* IN, written by src/twohead.py, holds little-endian int32 alpha, K, S, L and kappa; the 2^alpha cells
* of the window; the K banks of S (8 + 3 alpha) bits; the K tapes of L bits; the slots, the bits and
* the cells of the K heads (int32); then an image of a bank and of a tape, one byte per bit. A step
* evaluates the record at the active head on the cells it names, writes v = H(w0 x0 + w1 x1 + beta)
* into the window, under the arm or under the copy head, carries out the requests the window then
* holds, turns the active head by one slot and clears the requests. The active bank is never written,
* so its records are decoded once each time the bank bit changes, and a run of empty records is
* passed in one move unless the netlist is stepped as well.
*
* After every hand-over the program prints the steps of the generation, the bank bit, how many banks
* hold the image and how many tapes the tape, whether the new active head and read head are at their
* origins, and whether the full state equals the state K generations before. With NETLIST, the file
* src/twohead.py writes for the same machine, every step of the netlist is compared with the step
* of the machine on the whole state, and the mismatches are counted.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { SINK, RD, ARM, CPY, AR, AA, AC, RR, RA, RC, CB, CT, HO };
typedef struct { int a0, w0, a1, w1, beta, ao; } rec_t;
static int ALPHA, W, B, K, S, L, kap;
static long N;
static unsigned char *win, **Q, **D;
static int *hs, *hj, *ht;
static void *xmalloc(size_t n) { void *p = malloc(n ? n : 1); if (!p) { fprintf(stderr, "out of memory\n"); exit(2); } return p; }
static void rd(FILE *f, void *p, size_t sz, size_t k) {
if (fread(p, sz, k, f) != k) { fprintf(stderr, "short input\n"); exit(2); }
}
static rec_t decode(const unsigned char *bits) {
int p = 0;
#define GET(w) ({ int v_ = 0; for (int j_ = 0; j_ < (w); j_++) v_ = (v_ << 1) | bits[p++]; v_; })
int c0 = GET(2), c1 = GET(2), beta = GET(4);
int a0 = GET(ALPHA), a1 = GET(ALPHA), ao = GET(ALPHA);
#undef GET
rec_t r;
r.w0 = c0 == 1 ? 1 : c0 == 2 ? -1 : 0;
r.w1 = c1 == 1 ? 1 : c1 == 2 ? -1 : 0;
r.beta = beta >= 8 ? beta - 16 : beta;
r.a0 = a0; r.a1 = a1; r.ao = ao;
return r;
}
static inline int cell(int a, int k, int i) {
switch (a) {
case SINK: return 0;
case RD: return D[k][ht[k]];
case ARM: return Q[i][(long)hs[i] * B + hj[i]];
case CPY: return D[i][ht[i]];
default: return win[a];
}
}
static void step(const rec_t *r) {
int k = kap, i = k + 1 == K ? 0 : k + 1;
int x0 = r->w0 ? cell(r->a0, k, i) : 0, x1 = r->w1 ? cell(r->a1, k, i) : 0;
int v = r->w0 * x0 + r->w1 * x1 + r->beta >= 0;
if (r->ao == ARM) Q[i][(long)hs[i] * B + hj[i]] = v;
else if (r->ao == CPY) D[i][ht[i]] = v;
else if (r->ao > CPY) win[r->ao] = v;
if (win[RR]) ht[k] = 0; else if (win[AR]) ht[k] = ht[k] + 1 == L ? 0 : ht[k] + 1;
if (win[CB]) memset(Q[i], 0, N);
if (win[RA]) hs[i] = hj[i] = 0;
else if (win[AA]) { if (++hj[i] == B) { hj[i] = 0; hs[i] = hs[i] + 1 == S ? 0 : hs[i] + 1; } }
if (win[CT]) memset(D[i], 0, L);
if (win[RC]) ht[i] = 0; else if (win[AC]) ht[i] = ht[i] + 1 == L ? 0 : ht[i] + 1;
hs[k] = hs[k] + 1 == S ? 0 : hs[k] + 1;
if (win[HO]) kap = i;
memset(win + AR, 0, HO - AR + 1);
}
/* the netlist: units in order, each reading earlier signals; the state bits first */
static int nn, U, E, *bias, *fan, *pred, *nxt, *ustart;
static unsigned char *sig, *xs, *ys;
static long encode(unsigned char *x) {
long p = 0;
for (int c = 4; c < W; c++) x[p++] = win[c];
for (int k = 0; k < K; k++) x[p++] = k == kap;
for (int k = 0; k < K; k++) {
memcpy(x + p, Q[k], N); p += N;
for (int s = 0; s < S; s++) x[p++] = s == hs[k];
for (int j = 0; j < B; j++) x[p++] = j == hj[k];
}
for (int k = 0; k < K; k++) {
memcpy(x + p, D[k], L); p += L;
for (int i = 0; i < L; i++) x[p++] = i == ht[k];
}
return p;
}
static void net_step(void) {
memcpy(sig, xs, nn);
for (int u = 0; u < U; u++) {
int s = bias[u];
for (int e = ustart[u]; e < ustart[u + 1]; e++) { int q = pred[e]; s += q > 0 ? sig[q - 1] : -sig[-q - 1]; }
sig[nn + u] = s >= 0;
}
for (int i = 0; i < nn; i++) ys[i] = sig[nxt[i]];
}
static size_t state_size(void) { return (size_t)W + 1 + (size_t)K * (N + 2 * sizeof(int) + L + sizeof(int)); }
static void save_state(unsigned char *p) {
memcpy(p, win, W); p += W; *p++ = (unsigned char)kap;
for (int k = 0; k < K; k++) { memcpy(p, Q[k], N); p += N; memcpy(p, &hs[k], sizeof(int)); p += sizeof(int);
memcpy(p, &hj[k], sizeof(int)); p += sizeof(int); }
for (int k = 0; k < K; k++) { memcpy(p, D[k], L); p += L; memcpy(p, &ht[k], sizeof(int)); p += sizeof(int); }
}
int main(int argc, char **argv) {
if (argc < 3) { fprintf(stderr, "ring_run IN GENERATIONS [NETLIST]\n"); return 2; }
FILE *f = fopen(argv[1], "rb");
if (!f) return 2;
int gens = atoi(argv[2]);
int hdr[5];
rd(f, hdr, 4, 5);
ALPHA = hdr[0]; K = hdr[1]; S = hdr[2]; L = hdr[3]; kap = hdr[4];
W = 1 << ALPHA; B = 8 + 3 * ALPHA; N = (long)S * B;
win = xmalloc(W); rd(f, win, 1, W);
Q = xmalloc(K * sizeof *Q); D = xmalloc(K * sizeof *D);
for (int k = 0; k < K; k++) { Q[k] = xmalloc(N); rd(f, Q[k], 1, N); }
for (int k = 0; k < K; k++) { D[k] = xmalloc(L); rd(f, D[k], 1, L); }
hs = xmalloc(K * sizeof(int)); hj = xmalloc(K * sizeof(int)); ht = xmalloc(K * sizeof(int));
rd(f, hs, 4, K); rd(f, hj, 4, K); rd(f, ht, 4, K);
unsigned char *image = xmalloc(N), *tape = xmalloc(L);
rd(f, image, 1, N); rd(f, tape, 1, L);
fclose(f);
int with_net = argc > 3;
if (with_net) {
f = fopen(argv[3], "rb");
if (!f) return 2;
int h3[3]; rd(f, h3, 4, 3); nn = h3[0]; U = h3[1]; E = h3[2];
bias = xmalloc(4L * U); fan = xmalloc(4L * U); pred = xmalloc(4L * E); nxt = xmalloc(4L * nn);
rd(f, bias, 4, U); rd(f, fan, 4, U); rd(f, pred, 4, E); rd(f, nxt, 4, nn);
fclose(f);
ustart = xmalloc(4L * (U + 1)); ustart[0] = 0;
for (int u = 0; u < U; u++) ustart[u + 1] = ustart[u] + fan[u];
sig = xmalloc(nn + U); xs = xmalloc(nn); ys = xmalloc(nn);
if (encode(xs) != nn) { fprintf(stderr, "the netlist is for another machine\n"); return 2; }
}
rec_t *recs = xmalloc(sizeof(rec_t) * S);
long *next_full = xmalloc(sizeof(long) * (S + 1));
unsigned char *full = xmalloc(S);
size_t ssz = state_size();
unsigned char **hist = xmalloc(sizeof(unsigned char *) * (gens + 1));
long long mism = 0, total = 0;
for (int gen = 1; gen <= gens; gen++) {
int k0 = kap;
for (int s = 0; s < S; s++) {
recs[s] = decode(Q[k0] + (long)s * B);
full[s] = recs[s].w0 || recs[s].w1 || recs[s].beta || recs[s].a0 || recs[s].a1 || recs[s].ao;
}
next_full[S] = S;
for (int s = S - 1; s >= 0; s--) next_full[s] = full[s] ? s : next_full[s + 1];
long long steps = 0;
while (kap == k0) {
int s = hs[k0];
if (!with_net && !full[s]) {
long e = next_full[s];
if (e == S) { steps += S - s; hs[k0] = 0; } else { steps += e - s; hs[k0] = (int)e; }
continue;
}
if (with_net) { encode(xs); net_step(); }
step(&recs[s]);
steps++;
if (with_net) {
encode(xs);
if (memcmp(xs, ys, nn) != 0 && mism++ < 3) fprintf(stderr, "mismatch at step %lld\n", total + steps);
}
}
total += steps;
int copies = 0, descs = 0;
for (int k = 0; k < K; k++) { copies += memcmp(Q[k], image, N) == 0; descs += memcmp(D[k], tape, L) == 0; }
hist[gen] = xmalloc(ssz);
save_state(hist[gen]);
int periodic = gen > K ? memcmp(hist[gen], hist[gen - K], ssz) == 0 : -1;
printf("{\"generation\": %d, \"steps\": %lld, \"kappa\": %d, \"copies\": %d, \"descriptions\": %d, "
"\"heads_at_origin\": %d, \"equals_generation_minus_K\": %d", gen, steps, kap, copies, descs,
hs[kap] == 0 && ht[kap] == 0, periodic);
if (with_net) printf(", \"netlist_mismatches\": %lld", mism);
printf("}\n");
fflush(stdout);
}
return with_net && mism ? 1 : 0;
}
|