/* Exact and noisy runs of Lev(N_host) and of its r-fold amplification, written * independently of the artifact. A row of the r-fold map reads every copy of its * inputs, so all r copies of row i share the pre-activation * z = sum_j w_ij cnt_j + r b_i + (r - 1) / 2, cnt_j = copies of input j at 1, * and copy c outputs H(z) unless its noise crosses the comparator at -1/2, which * under centred Gaussian noise of deviation s happens with probability * Q(|z + 1/2| / s). Each copy of each row draws that event independently. * * nsim FILE exact INST T HSTEPS HISTOUT exact orbit: histogram of z, K*, A*, output * nsim FILE curve INST s COPIES T SEED R first step at which a copy of the state deviates * nsim FILE run s R SEED one noisy run of Omega* to its end * nsim FILE fail s COPIES T SEED R first wrong majority-read state, per copy * INST 0 is the self-describing instance (m_P, r_H), 1 the self-reproducing one. */ #include #include #include #include #include #include static int n, L, M, nnz; static int *width, *rowoff; /* rowoff[l]: first row of layer l (1-based layers) */ static int *bias, *fanin, *estart, *esrc, *ew; static int maxw; static int PCB, HALT, MEMB; static int C_WR, C_EOT, C_RW, C_RD, R_IN, R_OUT, HALT_PC; static unsigned char *blob[5]; static int bloblen[5]; static void rd(void *p, size_t sz, size_t k, FILE *f) { if (fread(p, sz, k, f) != k) { fprintf(stderr, "short\n"); exit(1); } } static void load(const char *path) { FILE *f = fopen(path, "rb"); int h[4]; rd(h, 4, 4, f); n = h[0]; L = h[1]; M = h[2]; nnz = h[3]; width = malloc(sizeof(int) * (L + 1)); rd(width, 4, L + 1, f); rowoff = malloc(sizeof(int) * (L + 2)); rowoff[1] = 0; for (int l = 1; l <= L; l++) rowoff[l + 1] = rowoff[l] + width[l]; maxw = 0; for (int l = 0; l <= L; l++) if (width[l] > maxw) maxw = width[l]; bias = malloc(sizeof(int) * M); fanin = malloc(sizeof(int) * M); estart = malloc(sizeof(int) * (M + 1)); for (int i = 0; i < M; i++) { int bf[2]; rd(bf, 4, 2, f); bias[i] = bf[0]; fanin[i] = bf[1]; } estart[0] = 0; for (int i = 0; i < M; i++) estart[i + 1] = estart[i] + fanin[i]; esrc = malloc(sizeof(int) * nnz); ew = malloc(sizeof(int) * nnz); for (int e = 0; e < nnz; e++) { int sw[2]; rd(sw, 4, 2, f); esrc[e] = sw[0]; ew[e] = sw[1]; } int lay[3]; rd(lay, 4, 3, f); PCB = lay[0]; HALT = lay[1]; MEMB = lay[2]; int io[7]; rd(io, 4, 7, f); C_WR = io[0]; C_EOT = io[1]; C_RW = io[2]; C_RD = io[3]; R_IN = io[4]; R_OUT = io[5]; HALT_PC = io[6]; for (int k = 0; k < 5; k++) { rd(&bloblen[k], 4, 1, f); blob[k] = malloc(bloblen[k]); rd(blob[k], 1, bloblen[k], f); } fclose(f); } /* ---- random numbers: xoshiro256** seeded by splitmix64 ---- */ typedef struct { uint64_t s[4]; } rng_t; static uint64_t splitmix(uint64_t *x) { uint64_t z = (*x += 0x9e3779b97f4a7c15ULL); z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL; z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL; return z ^ (z >> 31); } static void rng_seed(rng_t *r, uint64_t seed) { for (int i = 0; i < 4; i++) r->s[i] = splitmix(&seed); } static inline uint64_t rotl(uint64_t x, int k) { return (x << k) | (x >> (64 - k)); } static inline uint64_t rng_next(rng_t *r) { uint64_t *s = r->s, res = rotl(s[1] * 5, 7) * 9, t = s[1] << 17; s[2] ^= s[0]; s[3] ^= s[1]; s[1] ^= s[2]; s[0] ^= s[3]; s[2] ^= t; s[3] = rotl(s[3], 45); return res; } /* flip thresholds: a copy at distance k + 1/2 from the comparator flips when a draw is below thr[k] */ #define KMAX 4096 static uint64_t thr[KMAX]; static void set_noise(double s) { for (int k = 0; k < KMAX; k++) { double q = 0.5 * erfc((k + 0.5) / s / sqrt(2.0)); double v = q * 18446744073709551616.0; thr[k] = v >= 18446744073709551615.0 ? UINT64_MAX : (uint64_t)v; } } /* ---- the device of Definition 5.1 on copies of the state ---- */ typedef struct { int head; long nout; } devst; static int get_byte(const unsigned char *x, int r, int j) { /* majority of the r copies */ int v = 0; for (int k = 0; k < 8; k++) { int c = 0; for (int q = 0; q < r; q++) c += x[q * n + MEMB + 8 * j + k]; v = (v << 1) | (2 * c > r); } return v; } static void put_byte(unsigned char *x, int r, int j, int v) { for (int k = 0; k < 8; k++) { int b = (v >> (7 - k)) & 1; for (int q = 0; q < r; q++) x[q * n + MEMB + 8 * j + k] = b; } } /* returns the byte emitted, or -1 */ static int device(unsigned char *x, int r, devst *d, const unsigned char *tape, int tlen) { int emit = -1; if (get_byte(x, r, C_WR) == 1) { emit = get_byte(x, r, R_OUT); put_byte(x, r, R_OUT, 0); d->nout++; } if (get_byte(x, r, C_RD) == 1) { if (d->head < tlen) { put_byte(x, r, R_IN, tape[d->head]); put_byte(x, r, C_EOT, 0); d->head++; } else put_byte(x, r, C_EOT, 1); } if (get_byte(x, r, C_RW) == 1) d->head = 0; put_byte(x, r, C_RD, 0); put_byte(x, r, C_RW, 0); put_byte(x, r, C_WR, 0); return emit; } static int halted(const unsigned char *x, int r) { int c = 0; for (int q = 0; q < r; q++) c += x[q * n + HALT]; return 2 * c > r; } /* ---- one step of the r-fold map on x (r copies of n bits) into y ---- */ typedef struct { unsigned char *a, *b; } buf_t; static buf_t newbuf(int r) { buf_t B; B.a = malloc((size_t)r * maxw); B.b = malloc((size_t)r * maxw); return B; } /* noisy: rng may be NULL for the exact map. hist (exact, r = 1): counts of k per step. stats: K*, A* */ static void step(const unsigned char *x, unsigned char *y, int r, rng_t *g, buf_t *B, long *hist, int *kstar, int *astar) { unsigned char *in = B->a, *out = B->b; for (int q = 0; q < r; q++) memcpy(in + (size_t)q * maxw, x + (size_t)q * n, n); int half = (r - 1) / 2; for (int l = 1; l <= L; l++) { int W = width[l], Wp = width[l - 1]; int active = 0; if (astar) for (int j = 0; j < Wp; j++) active += in[j]; for (int i = 0; i < W; i++) { int row = rowoff[l] + i, z = r * bias[row] + half, k1 = 0; for (int e = estart[row]; e < estart[row + 1]; e++) { int c = 0; for (int q = 0; q < r; q++) c += in[(size_t)q * maxw + esrc[e]]; z += ew[e] * c; k1 += c; } int v = z >= 0, kk = z >= 0 ? z : -z - 1; if (hist) hist[kk < KMAX ? kk : KMAX - 1]++; if (kstar && k1 > *kstar) *kstar = k1; if (astar && active - k1 > *astar) *astar = active - k1; for (int q = 0; q < r; q++) { int o = v; if (g && kk < KMAX && thr[kk] && rng_next(g) < thr[kk]) o ^= 1; out[(size_t)q * maxw + i] = o; } } unsigned char *t = in; in = out; out = t; } for (int q = 0; q < r; q++) memcpy(y + (size_t)q * n, in + (size_t)q * maxw, n); } static unsigned char *initial(int inst, int r) { const unsigned char *m = blob[inst == 0 ? 0 : 2]; unsigned char *x = calloc((size_t)r * n, 1); for (int j = 0; j < 256; j++) put_byte(x, r, j, m[j]); return x; } int main(int argc, char **argv) { load(argv[1]); const char *mode = argv[2]; if (!strcmp(mode, "exact")) { int inst = atoi(argv[3]); long T = atol(argv[4]); long H = atol(argv[5]); FILE *hf = fopen(argv[6], "wb"); const unsigned char *tape = blob[inst == 0 ? 1 : 3]; int tlen = bloblen[inst == 0 ? 1 : 3]; const unsigned char *expect = inst == 0 ? NULL : blob[4]; unsigned char *x = initial(inst, 1), *y = malloc(n); buf_t B = newbuf(1); devst d = {0, 0}; long *hist = calloc(KMAX, sizeof(long)); int kstar = 0, astar = 0, kstar_h = 0, astar_h = 0; long t; long wrong = 0; long out = 0; unsigned char *outbuf = malloc(1 << 20); for (t = 0; t < T; t++) { memset(hist, 0, KMAX * sizeof(long)); step(x, y, 1, NULL, &B, hist, &kstar, &astar); if (t < H) { fwrite(hist, sizeof(long), 64, hf); kstar_h = kstar; astar_h = astar; } int e = device(y, 1, &d, tape, tlen); if (e >= 0) { if (expect && (out >= bloblen[4] || e != expect[out])) wrong++; if (out < (1 << 20)) outbuf[out] = e; out++; } memcpy(x, y, n); if (halted(x, 1)) { t++; break; } } fclose(hf); printf("{\"steps\": %ld, \"halted\": %d, \"bytes\": %ld, \"wrong_bytes\": %ld, \"Kstar_first\": %d, \"Astar_first\": %d, \"Kstar\": %d, \"Astar\": %d, \"head\": %d}\n", t, halted(x, 1), out, wrong, kstar_h, astar_h, kstar, astar, d.head); return 0; } if (!strcmp(mode, "curve")) { int inst = atoi(argv[3]); double s = atof(argv[4]); int C = atoi(argv[5]); long T = atol(argv[6]); uint64_t seed = strtoull(argv[7], NULL, 10); int r = atoi(argv[8]); set_noise(s); const unsigned char *tape = blob[inst == 0 ? 1 : 3]; int tlen = bloblen[inst == 0 ? 1 : 3]; /* the exact orbit and the device state along it */ unsigned char *orb = malloc((size_t)(T + 1) * r * n); int *heads = malloc(sizeof(int) * (T + 1)); unsigned char *x0 = initial(inst, r); memcpy(orb, x0, (size_t)r * n); buf_t B = newbuf(r); devst d = {0, 0}; heads[0] = 0; for (long t = 0; t < T; t++) { step(orb + (size_t)t * r * n, orb + (size_t)(t + 1) * r * n, r, NULL, &B, NULL, NULL, NULL); device(orb + (size_t)(t + 1) * r * n, r, &d, tape, tlen); heads[t + 1] = d.head; } long *first = calloc(C, sizeof(long)); #pragma omp parallel { buf_t Bt = newbuf(r); unsigned char *y = malloc((size_t)r * n); #pragma omp for schedule(dynamic, 1) for (int c = 0; c < C; c++) { rng_t g; rng_seed(&g, seed * 1000003ULL + c); for (long t = 0; t < T; t++) { step(orb + (size_t)t * r * n, y, r, &g, &Bt, NULL, NULL, NULL); devst dc = {heads[t], 0}; device(y, r, &dc, tape, tlen); if (memcmp(y, orb + (size_t)(t + 1) * r * n, (size_t)r * n)) { first[c] = t + 1; break; } } } } printf("["); for (int c = 0; c < C; c++) printf("%ld%s", first[c], c + 1 < C ? ", " : ""); printf("]\n"); return 0; } if (!strcmp(mode, "run")) { double s = atof(argv[3]); int r = atoi(argv[4]); uint64_t seed = strtoull(argv[5], NULL, 10); set_noise(s); const unsigned char *tape = blob[3]; int tlen = bloblen[3]; const unsigned char *expect = blob[4]; unsigned char *x = initial(1, r), *y = malloc((size_t)r * n); buf_t B = newbuf(r); devst d = {0, 0}; rng_t g; rng_seed(&g, seed); long t, out = 0; const char *why = "steps exhausted"; for (t = 0; t < 4000000; t++) { step(x, y, r, &g, &B, NULL, NULL, NULL); int e = device(y, r, &d, tape, tlen); memcpy(x, y, (size_t)r * n); if (e >= 0) { if (out >= bloblen[4] || e != expect[out]) { why = "a wrong byte"; t++; break; } out++; } if (halted(x, r)) { why = out == bloblen[4] ? "the whole instance" : "the halt bit set"; t++; break; } } printf("{\"s\": %g, \"r\": %d, \"seed\": %llu, \"steps\": %ld, \"bytes\": %ld, \"outcome\": \"%s\"}\n", s, r, (unsigned long long)seed, t, out, why); return 0; } if (!strcmp(mode, "fail")) { double s = atof(argv[3]); int C = atoi(argv[4]); long T = atol(argv[5]); uint64_t seed = strtoull(argv[6], NULL, 10); int r = atoi(argv[7]); set_noise(s); const unsigned char *tape = blob[1]; int tlen = bloblen[1]; /* the exact orbit, one copy suffices: majority reads are compared with it */ unsigned char *orb = malloc((size_t)(T + 1) * n); int *heads = malloc(sizeof(int) * (T + 1)); unsigned char *x0 = initial(0, 1); memcpy(orb, x0, n); buf_t B = newbuf(1); devst d = {0, 0}; heads[0] = 0; for (long t = 0; t < T; t++) { step(orb + (size_t)t * n, orb + (size_t)(t + 1) * n, 1, NULL, &B, NULL, NULL, NULL); device(orb + (size_t)(t + 1) * n, 1, &d, tape, tlen); heads[t + 1] = d.head; } long *first = calloc(C, sizeof(long)); #pragma omp parallel { buf_t Bt = newbuf(r); unsigned char *x = malloc((size_t)r * n), *y = malloc((size_t)r * n); #pragma omp for schedule(dynamic, 1) for (int c = 0; c < C; c++) { rng_t g; rng_seed(&g, seed * 1000003ULL + c); unsigned char *xi = initial(0, r); memcpy(x, xi, (size_t)r * n); free(xi); for (long t = 0; t < T; t++) { step(x, y, r, &g, &Bt, NULL, NULL, NULL); devst dc = {heads[t], 0}; device(y, r, &dc, tape, tlen); int bad = 0; for (int i = 0; i < n && !bad; i++) { int cnt = 0; for (int q = 0; q < r; q++) cnt += y[(size_t)q * n + i]; bad = (2 * cnt > r) != orb[(size_t)(t + 1) * n + i]; } if (bad) { first[c] = t + 1; break; } memcpy(x, y, (size_t)r * n); } } } printf("["); for (int c = 0; c < C; c++) printf("%ld%s", first[c], c + 1 < C ? ", " : ""); printf("]\n"); return 0; } fprintf(stderr, "unknown mode\n"); return 1; }