CharlesCNorton commited on
Commit ·
8337959
1
Parent(s): 2e204e8
4x4 binary multiplier
Browse files- README.md +86 -0
- config.json +9 -0
- create_safetensors.py +137 -0
- model.safetensors +0 -0
README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
tags:
|
| 4 |
+
- pytorch
|
| 5 |
+
- safetensors
|
| 6 |
+
- threshold-logic
|
| 7 |
+
- neuromorphic
|
| 8 |
+
- arithmetic
|
| 9 |
+
- multiplier
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
# threshold-multiplier4x4
|
| 13 |
+
|
| 14 |
+
4x4 binary multiplier as threshold circuit. Multiplies two 4-bit unsigned integers to produce an 8-bit product.
|
| 15 |
+
|
| 16 |
+
## Circuit
|
| 17 |
+
|
| 18 |
+
```
|
| 19 |
+
A[3:0] ──┐
|
| 20 |
+
├──► 4x4 MUL ──► P[7:0]
|
| 21 |
+
B[3:0] ──┘
|
| 22 |
+
|
| 23 |
+
P = A × B
|
| 24 |
+
Range: 0-15 × 0-15 = 0-225
|
| 25 |
+
```
|
| 26 |
+
|
| 27 |
+
## Architecture
|
| 28 |
+
|
| 29 |
+
```
|
| 30 |
+
Partial Products (16 AND gates):
|
| 31 |
+
b3 b2 b1 b0
|
| 32 |
+
× a3 a2 a1 a0
|
| 33 |
+
─────────────────────────
|
| 34 |
+
a0b3 a0b2 a0b1 a0b0
|
| 35 |
+
a1b3 a1b2 a1b1 a1b0
|
| 36 |
+
a2b3 a2b2 a2b1 a2b0
|
| 37 |
+
+ a3b3 a3b2 a3b1 a3b0
|
| 38 |
+
─────────────────────────────────────
|
| 39 |
+
p7 p6 p5 p4 p3 p2 p1 p0
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
| Component | Count | Neurons |
|
| 43 |
+
|-----------|-------|---------|
|
| 44 |
+
| AND (partial products) | 16 | 16 |
|
| 45 |
+
| Half Adders | 4 | 16 |
|
| 46 |
+
| Full Adders | 8 | 56 |
|
| 47 |
+
|
| 48 |
+
**Total: 88 neurons, 368 parameters, 6 layers**
|
| 49 |
+
|
| 50 |
+
## Adder Tree Structure
|
| 51 |
+
|
| 52 |
+
```
|
| 53 |
+
Column 1: HA(pp10, pp01) → p1, c1
|
| 54 |
+
Column 2: FA(pp20, pp11, pp02) → s, c
|
| 55 |
+
HA(s, c1) → p2, c
|
| 56 |
+
Column 3: FA(pp30, pp21, pp12) → s, c
|
| 57 |
+
FA(s, pp03, c) → s', c'
|
| 58 |
+
HA(s', c) → p3, c
|
| 59 |
+
Column 4-6: Similar carry-propagate structure
|
| 60 |
+
Column 7: Final carry → p7
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
## Usage
|
| 64 |
+
|
| 65 |
+
```python
|
| 66 |
+
from safetensors.torch import load_file
|
| 67 |
+
|
| 68 |
+
w = load_file('model.safetensors')
|
| 69 |
+
|
| 70 |
+
# Verify: 15 × 15 = 225
|
| 71 |
+
# All 256 input combinations tested
|
| 72 |
+
```
|
| 73 |
+
|
| 74 |
+
## Files
|
| 75 |
+
|
| 76 |
+
```
|
| 77 |
+
threshold-multiplier4x4/
|
| 78 |
+
├── model.safetensors
|
| 79 |
+
├── create_safetensors.py
|
| 80 |
+
├── config.json
|
| 81 |
+
└── README.md
|
| 82 |
+
```
|
| 83 |
+
|
| 84 |
+
## License
|
| 85 |
+
|
| 86 |
+
MIT
|
config.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "threshold-multiplier4x4",
|
| 3 |
+
"description": "4x4 binary multiplier as threshold circuit",
|
| 4 |
+
"inputs": 8,
|
| 5 |
+
"outputs": 8,
|
| 6 |
+
"neurons": 88,
|
| 7 |
+
"layers": 6,
|
| 8 |
+
"parameters": 368
|
| 9 |
+
}
|
create_safetensors.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from safetensors.torch import save_file
|
| 3 |
+
|
| 4 |
+
weights = {}
|
| 5 |
+
|
| 6 |
+
# 4x4 binary multiplier
|
| 7 |
+
# Inputs: a3,a2,a1,a0, b3,b2,b1,b0 (8 inputs)
|
| 8 |
+
# Outputs: p7,p6,p5,p4,p3,p2,p1,p0 (8 outputs)
|
| 9 |
+
|
| 10 |
+
# Partial products: pp[i][j] = a[i] AND b[j]
|
| 11 |
+
# Column c gets all pp[i][j] where i+j = c
|
| 12 |
+
|
| 13 |
+
def add_and_gate(name, a_idx, b_idx, total_inputs):
|
| 14 |
+
w = [0.0] * total_inputs
|
| 15 |
+
w[a_idx] = 1.0
|
| 16 |
+
w[b_idx] = 1.0
|
| 17 |
+
weights[f'{name}.weight'] = torch.tensor([w], dtype=torch.float32)
|
| 18 |
+
weights[f'{name}.bias'] = torch.tensor([-2.0], dtype=torch.float32)
|
| 19 |
+
|
| 20 |
+
def add_xor_gate(name, total_inputs):
|
| 21 |
+
weights[f'{name}.or.weight'] = torch.tensor([[1.0, 1.0]], dtype=torch.float32)
|
| 22 |
+
weights[f'{name}.or.bias'] = torch.tensor([-1.0], dtype=torch.float32)
|
| 23 |
+
weights[f'{name}.nand.weight'] = torch.tensor([[-1.0, -1.0]], dtype=torch.float32)
|
| 24 |
+
weights[f'{name}.nand.bias'] = torch.tensor([1.0], dtype=torch.float32)
|
| 25 |
+
weights[f'{name}.and.weight'] = torch.tensor([[1.0, 1.0]], dtype=torch.float32)
|
| 26 |
+
weights[f'{name}.and.bias'] = torch.tensor([-2.0], dtype=torch.float32)
|
| 27 |
+
|
| 28 |
+
def add_ha(name):
|
| 29 |
+
add_xor_gate(f'{name}.sum', 2)
|
| 30 |
+
weights[f'{name}.carry.weight'] = torch.tensor([[1.0, 1.0]], dtype=torch.float32)
|
| 31 |
+
weights[f'{name}.carry.bias'] = torch.tensor([-2.0], dtype=torch.float32)
|
| 32 |
+
|
| 33 |
+
def add_fa(name):
|
| 34 |
+
add_xor_gate(f'{name}.xor1', 2)
|
| 35 |
+
add_xor_gate(f'{name}.sum', 2)
|
| 36 |
+
weights[f'{name}.maj.weight'] = torch.tensor([[1.0, 1.0, 1.0]], dtype=torch.float32)
|
| 37 |
+
weights[f'{name}.maj.bias'] = torch.tensor([-2.0], dtype=torch.float32)
|
| 38 |
+
|
| 39 |
+
# Input indices: a3=0, a2=1, a1=2, a0=3, b3=4, b2=5, b1=6, b0=7
|
| 40 |
+
|
| 41 |
+
# Layer 1: 16 AND gates for partial products
|
| 42 |
+
for i in range(4):
|
| 43 |
+
for j in range(4):
|
| 44 |
+
a_idx = 3 - i
|
| 45 |
+
b_idx = 7 - j
|
| 46 |
+
add_and_gate(f'pp{i}{j}', a_idx, b_idx, 8)
|
| 47 |
+
|
| 48 |
+
# Adder structure for summing partial products
|
| 49 |
+
add_ha('ha_c1')
|
| 50 |
+
add_fa('fa_c2_0')
|
| 51 |
+
add_ha('ha_c2_1')
|
| 52 |
+
add_fa('fa_c3_0')
|
| 53 |
+
add_fa('fa_c3_1')
|
| 54 |
+
add_ha('ha_c3_2')
|
| 55 |
+
add_fa('fa_c4_0')
|
| 56 |
+
add_fa('fa_c4_1')
|
| 57 |
+
add_ha('ha_c4_2')
|
| 58 |
+
add_fa('fa_c5_0')
|
| 59 |
+
add_fa('fa_c5_1')
|
| 60 |
+
add_fa('fa_c6')
|
| 61 |
+
|
| 62 |
+
save_file(weights, 'model.safetensors')
|
| 63 |
+
|
| 64 |
+
def eval_and(a, b):
|
| 65 |
+
return int(a + b >= 2)
|
| 66 |
+
|
| 67 |
+
def eval_xor(a, b):
|
| 68 |
+
or_out = int(a + b >= 1)
|
| 69 |
+
nand_out = int(-a - b + 1 >= 0)
|
| 70 |
+
return int(or_out + nand_out >= 2)
|
| 71 |
+
|
| 72 |
+
def eval_ha(a, b):
|
| 73 |
+
s = eval_xor(a, b)
|
| 74 |
+
c = eval_and(a, b)
|
| 75 |
+
return s, c
|
| 76 |
+
|
| 77 |
+
def eval_fa(a, b, cin):
|
| 78 |
+
x1 = eval_xor(a, b)
|
| 79 |
+
s = eval_xor(x1, cin)
|
| 80 |
+
c = int(a + b + cin >= 2)
|
| 81 |
+
return s, c
|
| 82 |
+
|
| 83 |
+
def multiply_4x4(a3, a2, a1, a0, b3, b2, b1, b0):
|
| 84 |
+
pp = [[eval_and([a0,a1,a2,a3][i], [b0,b1,b2,b3][j]) for j in range(4)] for i in range(4)]
|
| 85 |
+
|
| 86 |
+
p0 = pp[0][0]
|
| 87 |
+
|
| 88 |
+
s1, c1 = eval_ha(pp[1][0], pp[0][1])
|
| 89 |
+
p1 = s1
|
| 90 |
+
|
| 91 |
+
s2_0, c2_0 = eval_fa(pp[2][0], pp[1][1], pp[0][2])
|
| 92 |
+
s2_1, c2_1 = eval_ha(s2_0, c1)
|
| 93 |
+
p2 = s2_1
|
| 94 |
+
|
| 95 |
+
s3_0, c3_0 = eval_fa(pp[3][0], pp[2][1], pp[1][2])
|
| 96 |
+
s3_1, c3_1 = eval_fa(s3_0, pp[0][3], c2_0)
|
| 97 |
+
s3_2, c3_2 = eval_ha(s3_1, c2_1)
|
| 98 |
+
p3 = s3_2
|
| 99 |
+
|
| 100 |
+
s4_0, c4_0 = eval_fa(pp[3][1], pp[2][2], pp[1][3])
|
| 101 |
+
s4_1, c4_1 = eval_fa(s4_0, c3_0, c3_1)
|
| 102 |
+
s4_2, c4_2 = eval_ha(s4_1, c3_2)
|
| 103 |
+
p4 = s4_2
|
| 104 |
+
|
| 105 |
+
s5_0, c5_0 = eval_fa(pp[3][2], pp[2][3], c4_0)
|
| 106 |
+
s5_1, c5_1 = eval_fa(s5_0, c4_1, c4_2)
|
| 107 |
+
p5 = s5_1
|
| 108 |
+
|
| 109 |
+
s6, c6 = eval_fa(pp[3][3], c5_0, c5_1)
|
| 110 |
+
p6 = s6
|
| 111 |
+
|
| 112 |
+
p7 = c6
|
| 113 |
+
|
| 114 |
+
return p0, p1, p2, p3, p4, p5, p6, p7
|
| 115 |
+
|
| 116 |
+
print("Verifying 4x4 multiplier...")
|
| 117 |
+
errors = 0
|
| 118 |
+
for a in range(16):
|
| 119 |
+
for b in range(16):
|
| 120 |
+
a3, a2, a1, a0 = (a>>3)&1, (a>>2)&1, (a>>1)&1, a&1
|
| 121 |
+
b3, b2, b1, b0 = (b>>3)&1, (b>>2)&1, (b>>1)&1, b&1
|
| 122 |
+
p = multiply_4x4(a3, a2, a1, a0, b3, b2, b1, b0)
|
| 123 |
+
result = sum(p[i] << i for i in range(8))
|
| 124 |
+
expected = a * b
|
| 125 |
+
if result != expected:
|
| 126 |
+
errors += 1
|
| 127 |
+
if errors <= 5:
|
| 128 |
+
print(f"ERROR: {a} * {b} = {result}, expected {expected}")
|
| 129 |
+
|
| 130 |
+
if errors == 0:
|
| 131 |
+
print("All 256 test cases passed!")
|
| 132 |
+
else:
|
| 133 |
+
print(f"FAILED: {errors} errors")
|
| 134 |
+
|
| 135 |
+
mag = sum(t.abs().sum().item() for t in weights.values())
|
| 136 |
+
print(f"Magnitude: {mag:.0f}")
|
| 137 |
+
print(f"Parameters: {sum(t.numel() for t in weights.values())}")
|
model.safetensors
ADDED
|
Binary file (14.8 kB). View file
|
|
|