CharlesCNorton commited on
Commit
55a7cc7
·
1 Parent(s): cbc9ef0

neural_reversible: structured reversible programs over the reversible ALU (reversible multiply with inputs preserved, Fibonacci whose inverse recovers the seed, a Janus conditional with an exit assertion); inverting a program is reversing the statement order and inverting each, and running the inverse recovers the input

Browse files
Files changed (1) hide show
  1. src/reversible_prog.py +162 -0
src/reversible_prog.py ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Structured reversible programs over the reversible ALU.
2
+
3
+ The flat instruction machine (reversible_cpu.py) proves the per-step transition
4
+ is a bijection. This file is the structured layer that makes real programs
5
+ convenient and their reversibility obvious: statements are reversible register
6
+ updates and a bounded loop whose count register is read-only, so inverting a
7
+ program is a purely syntactic transform (reverse the statement order and invert
8
+ each statement) and running the inverse recovers the input exactly.
9
+
10
+ ADD d,s : d += s inverse SUB d,s
11
+ SUB d,s : d -= s inverse ADD d,s
12
+ ADDI d,k : d += k inverse ADDI d,-k
13
+ XOR d,s : d ^= s self-inverse
14
+ NEG d : d = -d self-inverse
15
+ SWAP a,b : a,b = b,a self-inverse
16
+ FOR c B : run B, c times inverse FOR c invert(B) (B must not write c)
17
+ IF p T E : Janus conditional with an exit assertion (reversible)
18
+
19
+ Every update is the value-level image of the verified reversible threshold
20
+ circuits in reversible.py; a FOR whose count register is preserved is a
21
+ reversible loop because both directions read the same count.
22
+ """
23
+ from __future__ import annotations
24
+ from typing import Dict, List, Tuple
25
+
26
+ WIDTH = 8
27
+ MASK = (1 << WIDTH) - 1
28
+
29
+
30
+ def _regs_written(stmts) -> set:
31
+ w = set()
32
+ for st in stmts:
33
+ op = st[0]
34
+ if op in ("ADD", "SUB", "ADDI", "XOR", "NEG"):
35
+ w.add(st[1])
36
+ elif op == "SWAP":
37
+ w.add(st[1]); w.add(st[2])
38
+ elif op == "FOR":
39
+ w |= _regs_written(st[2])
40
+ elif op == "IF":
41
+ w |= _regs_written(st[2]) | _regs_written(st[3])
42
+ return w
43
+
44
+
45
+ def invert(stmts: List[tuple]) -> List[tuple]:
46
+ out = []
47
+ for st in reversed(stmts):
48
+ op = st[0]
49
+ if op == "ADD":
50
+ out.append(("SUB", st[1], st[2]))
51
+ elif op == "SUB":
52
+ out.append(("ADD", st[1], st[2]))
53
+ elif op == "ADDI":
54
+ out.append(("ADDI", st[1], -st[2]))
55
+ elif op in ("XOR", "NEG", "SWAP"):
56
+ out.append(st)
57
+ elif op == "FOR":
58
+ out.append(("FOR", st[1], invert(st[2])))
59
+ elif op == "IF":
60
+ # Janus: reverse swaps predicate and exit assertion, inverts branches
61
+ out.append(("IF", st[4], invert(st[2]), invert(st[3]), st[1]))
62
+ return out
63
+
64
+
65
+ def run(stmts: List[tuple], s: Dict[str, int]) -> Dict[str, int]:
66
+ for st in stmts:
67
+ op = st[0]
68
+ if op == "ADD":
69
+ s[st[1]] = (s[st[1]] + s[st[2]]) & MASK
70
+ elif op == "SUB":
71
+ s[st[1]] = (s[st[1]] - s[st[2]]) & MASK
72
+ elif op == "ADDI":
73
+ s[st[1]] = (s[st[1]] + st[2]) & MASK
74
+ elif op == "XOR":
75
+ s[st[1]] ^= s[st[2]]
76
+ elif op == "NEG":
77
+ s[st[1]] = (-s[st[1]]) & MASK
78
+ elif op == "SWAP":
79
+ s[st[1]], s[st[2]] = s[st[2]], s[st[1]]
80
+ elif op == "FOR":
81
+ cnt, body = st[1], st[2]
82
+ if cnt in _regs_written(body):
83
+ raise ValueError("FOR count register must be read-only (irreversible otherwise)")
84
+ for _ in range(s[cnt]):
85
+ run(body, s)
86
+ elif op == "IF":
87
+ pred, then, els, exit_assert = st[1], st[2], st[3], st[4]
88
+ if pred(s):
89
+ run(then, s)
90
+ assert exit_assert(s), "exit assertion violated (not reversible)"
91
+ else:
92
+ run(els, s)
93
+ assert not exit_assert(s), "exit assertion violated (not reversible)"
94
+ return s
95
+
96
+
97
+ # --- demonstration programs ---
98
+ MULTIPLY = [("FOR", "b", [("ADD", "acc", "a")])] # acc += a, b times; a,b preserved
99
+ FIB = [("FOR", "n", [("ADD", "a", "b"), ("SWAP", "a", "b")])] # (a,b)->(b,a+b), n times
100
+
101
+
102
+ def _test():
103
+ ok = True
104
+
105
+ # reversible multiply: acc = a*b, inputs preserved; inverse clears acc
106
+ bad = 0
107
+ for a in range(16):
108
+ for b in range(16):
109
+ s = {"a": a, "b": b, "acc": 0}
110
+ run(MULTIPLY, s)
111
+ if s["acc"] != (a * b) & MASK or s["a"] != a or s["b"] != b:
112
+ bad += 1
113
+ run(invert(MULTIPLY), s) # run backward
114
+ if s != {"a": a, "b": b, "acc": 0}:
115
+ bad += 1
116
+ print(f" reversible multiply acc=a*b, inputs preserved, inverse clears acc: "
117
+ f"{'OK' if bad == 0 else f'FAIL({bad})'}")
118
+ ok &= bad == 0
119
+
120
+ # reversible Fibonacci: n steps forward, inverse recovers the seed
121
+ bad = 0
122
+ for n in range(12):
123
+ s = {"a": 0, "b": 1, "n": n}
124
+ run(FIB, s)
125
+ # forward value check against a plain reference
126
+ ra, rb = 0, 1
127
+ for _ in range(n):
128
+ ra, rb = rb, (ra + rb) & MASK
129
+ if (s["a"], s["b"]) != (ra, rb):
130
+ bad += 1
131
+ run(invert(FIB), s)
132
+ if s != {"a": 0, "b": 1, "n": n}:
133
+ bad += 1
134
+ print(f" reversible Fibonacci n steps, inverse recovers seed: "
135
+ f"{'OK' if bad == 0 else f'FAIL({bad})'}")
136
+ ok &= bad == 0
137
+
138
+ # a reversible conditional (Janus IF): swap when the operands differ. The
139
+ # exit assertion a != b is true exactly when the then-branch ran (swapping
140
+ # distinct values keeps them distinct; equal values are skipped), so the
141
+ # reverse picks the right branch.
142
+ prog = [("IF", lambda s: s["a"] != s["b"], [("SWAP", "a", "b")], [],
143
+ lambda s: s["a"] != s["b"])]
144
+ bad = 0
145
+ for a in range(16):
146
+ for b in range(16):
147
+ s = {"a": a, "b": b}
148
+ run(prog, s)
149
+ if sorted([s["a"], s["b"]]) != sorted([a, b]):
150
+ bad += 1
151
+ run(invert(prog), s)
152
+ if s != {"a": a, "b": b}:
153
+ bad += 1
154
+ print(f" reversible conditional (Janus IF with exit assertion): "
155
+ f"{'OK' if bad == 0 else f'FAIL({bad})'}")
156
+ ok &= bad == 0
157
+ return ok
158
+
159
+
160
+ if __name__ == "__main__":
161
+ print("Reversible structured programs")
162
+ print("PASS" if _test() else "FAIL")