File size: 8,616 Bytes
a4326d5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65db75b
a4326d5
ca99a3e
7090afb
65db75b
7090afb
65db75b
 
6c2c63e
 
947fcab
a4326d5
65db75b
a4326d5
65db75b
 
6c2c63e
 
 
65db75b
 
 
a4326d5
65db75b
a4326d5
6c2c63e
 
 
 
 
 
 
 
 
 
 
a4326d5
65db75b
 
a4326d5
65db75b
 
a4326d5
65db75b
 
 
a4326d5
65db75b
 
 
 
a4326d5
65db75b
 
 
 
a4326d5
65db75b
a4326d5
65db75b
a4326d5
65db75b
ca99a3e
65db75b
a4326d5
65db75b
a4326d5
65db75b
ca99a3e
 
 
 
a4326d5
65db75b
 
 
a4326d5
ca99a3e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65db75b
a4326d5
65db75b
ca99a3e
 
 
a4326d5
65db75b
a4326d5
 
 
 
 
 
 
65db75b
 
 
a4326d5
 
65db75b
ca99a3e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a4326d5
65db75b
a4326d5
 
65db75b
a4326d5
 
ca99a3e
e669ef2
a4326d5
d4442da
 
 
 
 
 
e669ef2
d4442da
58a9bad
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65db75b
a4326d5
ca99a3e
a4326d5
ca99a3e
a4326d5
65db75b
a4326d5
65db75b
a4326d5
7090afb
 
65db75b
 
 
939c167
b8c48ca
6c2c63e
 
65db75b
a4326d5
65db75b
58a9bad
 
a4326d5
65db75b
6c2c63e
a4326d5
10e432e
 
58a9bad
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10e432e
a4326d5
 
65db75b
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
---
license: apache-2.0
language:
- en
tags:
- threshold-logic
- arithmetic
- verified-computing
- neuromorphic
- digital-circuits
- frozen-weights
pipeline_tag: other
---

# Threshold Calculus

Digital circuits encoded as neural network weights.

Each gate is a threshold logic unit: `output = step(weights * inputs + bias)`. The step function fires when the weighted sum >= 0. This maps digital logic to tensor operations.

## What's Here

| File | Description |
|------|-------------|
| `arithmetic.safetensors` | 626,374 tensors encoding 208,788 gates |
| `eval.py` | Test harness (211,581 tests) |
| `build.py` | Builds tensors and infers gate connectivity |

## Circuits

**Float16 (IEEE 754)**
- `float16.add`, `float16.sub`, `float16.mul`, `float16.div`
- `float16.sqrt`, `float16.rsqrt`, `float16.pow`
- `float16.exp`, `float16.ln`, `float16.log2`
- `float16.sin`, `float16.cos`, `float16.tan`, `float16.tanh`
- `float16.neg`, `float16.abs`, `float16.cmp`
- `float16.toint`, `float16.fromint`
- `float16.pack`, `float16.unpack`, `float16.normalize`

Handles NaN, Inf, zero, subnormals. Mantissa alignment via barrel shifter. Normalization via CLZ.

Accuracy/rounding:
- Unary transcendental ops are LUT-backed over all 65,536 float16 inputs.
- Outputs match torch.float16 results (round-to-nearest-even); NaNs are canonicalized to 0x7E00.
- `float16.pow` is defined as exp(b * ln(a)) with float16 rounding at each stage.

**16-bit Integer**
- Adders: half, full, ripple carry (2/4/16 bit), add-with-carry (adc16bit)
- Subtraction: sub16bit, sbc16bit, neg16bit
- Comparison: cmp16bit, equality16bit
- Shifts: asr16bit, rol16bit, ror16bit
- CLZ: 16-bit

**Modular Arithmetic**
- mod2 through mod12 (divisibility testing)

**Boolean**
- AND, OR, NOT, NAND, NOR, XOR, XNOR, IMPLIES, BIIMPLIES

**Threshold**
- k-of-n gates (1-of-8 through 8-of-8)
- majority, minority, atleastk, atmostk, exactlyk

**Pattern Recognition**
- popcount, allzeros, allones, onehotdetector
- symmetry8bit, alternating8bit, hammingdistance8bit
- leadingones, trailingones, runlength

**Combinational**
- decoder3to8, encoder
- multiplexer (2/4/8 to 1), demultiplexer (1 to 2/4/8)
- barrelshifter8bit, priorityencoder8bit

## How It Works

A threshold gate computes:

```
output = 1 if (w1*x1 + w2*x2 + ... + wn*xn + bias) >= 0 else 0
```

This is a perceptron with Heaviside step activation.

**AND gate**: weights = [1, 1], bias = -1.5
- (0,0): 0 + 0 - 1.5 = -1.5 < 0 -> 0
- (0,1): 0 + 1 - 1.5 = -0.5 < 0 -> 0
- (1,0): 1 + 0 - 1.5 = -0.5 < 0 -> 0
- (1,1): 1 + 1 - 1.5 = 0.5 >= 0 -> 1

**XOR** requires two layers (not linearly separable):
- Layer 1: OR and NAND in parallel
- Layer 2: AND of both outputs

## Float16 Architecture (Short)

High-level dataflow:

```
float16.<op>
  a,b -> unpack -> classify -> core op -> normalize/round -> pack -> out
```

Step-by-step (condensed):
1) Unpack sign/exponent/mantissa. Subnormals use implicit 0, normals use implicit 1.
2) Classify inputs: zero, subnormal, normal, inf, NaN.
3) Core op:
   - add/sub: align exponents, add/sub mantissas, compute sign.
   - mul/div: add/sub exponents (minus bias), multiply/divide mantissas.
   - unary LUT: lookup output for each 16-bit input (torch.float16), with NaN canonicalization.
   - pow: ln(a) -> mul(b, ln(a)) -> exp, rounded at each stage.
4) Normalize and round-to-nearest-even (CLZ + shifts).
5) Pack sign/exponent/mantissa and mux special cases (NaN/Inf/zero).

## Self-Documenting Format

Each gate has three tensors in `arithmetic.safetensors`:
- `.weight` -- input weights
- `.bias` -- threshold
- `.inputs` -- int64 tensor of signal IDs (ordered to match `.weight`)

Signal registry in metadata maps IDs to names:

```python
from safetensors import safe_open
import json

with safe_open('arithmetic.safetensors', framework='pt') as f:
    registry = json.loads(f.metadata()['signal_registry'])
    inputs = f.get_tensor('boolean.and.inputs')
    names = [registry[str(i.item())] for i in inputs]
    # ['$a', '$b']
```

Signal naming:
- `$name` -- circuit input (e.g., `$a`, `$dividend[0]`)
- `#0`, `#1` -- constants
- `gate.path` -- output of another gate

Format details:
- Metadata includes `signal_registry` (JSON map from ID to name) and `format_version` (currently `2.0`).
- `.inputs` stores global signal IDs; these IDs are resolved through `signal_registry`.
- External inputs are names starting with `$` or containing `.$` (e.g., `float16.add.$a[3]`).
- All gates include `.inputs`; `build.py` infers them and `--inputs-coverage` fails if resolution is missing.

## How to Reproduce

Rebuild tensors:

```bash
python build.py
```

Run full evaluation (always full + verbose):

```bash
python eval.py
```

Run coverage and input-routing validation:

```bash
python eval.py --coverage --inputs-coverage
```

Expected runtimes (ballpark, CPU dependent):
- `build.py`: ~1-2 minutes, produces ~247 MB `arithmetic.safetensors`
- `eval.py --coverage --inputs-coverage`: ~3-4 minutes for 211,581 tests

## Running Eval

```bash
python eval.py
```

Tests all circuits. Small circuits are exhaustive; 16-bit arithmetic is sampled on grids (plus edge cases). Float16 tests cover special cases (NaN, Inf, +/-0, subnormals) plus normal arithmetic.
Eval runs full + verbose by default; there is no quick/verbose mode. Use --circuit to filter reported circuits.

For coverage and input-routing validation:

```bash
python eval.py --coverage --inputs-coverage
```

`--inputs-coverage` evaluates gates via their `.inputs` tensors using seeded external inputs and explicit overrides, and fails if inputs cannot be resolved. This is for coverage and routing sanity, not a correctness proof.

## Python Calculator Interface (Gate-Level)

`calculator.py` provides a pure gate-level evaluator that uses only `.inputs` + `.weight`/`.bias` (no arithmetic shortcuts). This is intended as a rigorous proof-of-concept for using the weights as a calculator.
Expression mode routes even constants through a circuit (via `float16.add` with +0) to ensure gate-level evaluation.

Examples:

```bash
python calculator.py float16.add 1.0 2.0
python calculator.py float16.sqrt 2.0
python calculator.py float16.add --inputs a=0x3c00 b=0x4000 --hex
python calculator.py --expr "1 + 1"
python calculator.py "sin(pi / 2)"
python calculator.py --expr "1 + 1" --json
python calculator.py "pi" --strict
```

Programmatic use:

```python
from calculator import ThresholdCalculator

calc = ThresholdCalculator("arithmetic.safetensors")
out, _ = calc.float16_binop("add", 1.0, 2.0)
print(out)
```

## Development History

Started as an 8-bit CPU project. Built boolean gates, then arithmetic (adders -> multipliers -> dividers), then CPU control logic. The CPU worked but the arithmetic core turned out to be the useful part, so it was extracted.

Float16 was added later. The commit history shows the iterative process--float16.add went through multiple rounds of bug fixes for edge cases (zero handling, sign logic, normalization). Mul and div required multi-bit carry infrastructure.

## Project Origin

This began as an attempt to build a complete threshold-logic CPU. The CPU is in a separate repo (phanerozoic/8bit-threshold-computer). This repo focuses on the arithmetic core.

## Roadmap

**Done:**
- Float16 core (add/sub/mul/div)
- Float16 utilities (pack/unpack/normalize/conversions)
- Float16 IEEE-754 half compliance for add/sub/mul/div + toint/fromint (including subnormals)
- Float16 unary LUTs (sqrt/rsqrt/exp/ln/log2/log10/sin/cos/tan/tanh/asin/acos/atan/sinh/cosh/floor/ceil/round)
- Float16 pow via exp(b * ln(a))
- 16-bit integer arithmetic (add/sub/cmp/shifts/CLZ)
- Boolean, threshold, modular, pattern recognition, combinational

**Next:**
- Add 32-bit integer arithmetic circuits (add/sub/shift/compare, then mul/div).
- Add higher precision modes (float32 or fixed-point) for typical calculator accuracy.

**Cleanup:**
- None (8-bit arithmetic scaffolding removed)

## TODO (Unified)

- 32-bit integer circuits and an int32 calculator mode.
- Degree-mode trig and implicit multiplication parsing.
- Higher-precision arithmetic (float32 or fixed-point).
- Complex-number support (or explicit domain errors).

## Hugging Face Space (Proof of Concept)

A minimal Space UI is included in `app.py`. It uses the gate-level evaluator only (no arithmetic shortcuts) and exposes a normal calculator-style expression input.

Example expressions:
- `1 + 1`
- `sin(pi / 2)`
- `exp(ln(2))`

Notes:
- All results are **float16** (IEEE-754 half) and may be rounded.
- `pow` uses the `exp(b*ln(a))` definition; negative bases yield NaN.

## License

Apache 2.0