CharlesCNorton
commited on
Commit
·
49eaae4
1
Parent(s):
7543102
BCD adder
Browse files- README.md +91 -0
- config.json +9 -0
- create_safetensors.py +129 -0
- model.safetensors +0 -0
README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
tags:
|
| 4 |
+
- pytorch
|
| 5 |
+
- safetensors
|
| 6 |
+
- threshold-logic
|
| 7 |
+
- neuromorphic
|
| 8 |
+
- arithmetic
|
| 9 |
+
- bcd
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
# threshold-bcd-adder
|
| 13 |
+
|
| 14 |
+
BCD (Binary-Coded Decimal) single-digit adder as threshold circuit. Adds two decimal digits (0-9) with carry.
|
| 15 |
+
|
| 16 |
+
## Circuit
|
| 17 |
+
|
| 18 |
+
```
|
| 19 |
+
A[3:0] ──┐ (BCD digit 0-9)
|
| 20 |
+
B[3:0] ──┼──► BCD Adder ──┬──► S[3:0] (BCD digit 0-9)
|
| 21 |
+
Cin ──┘ └──► Cout (decimal carry)
|
| 22 |
+
```
|
| 23 |
+
|
| 24 |
+
## Algorithm
|
| 25 |
+
|
| 26 |
+
```
|
| 27 |
+
1. Binary add: Z = A + B + Cin (4-bit result + carry)
|
| 28 |
+
2. Detect overflow: Z > 9 OR binary carry
|
| 29 |
+
3. If overflow: add 6 (0110) for correction
|
| 30 |
+
4. Decimal carry = overflow detected
|
| 31 |
+
```
|
| 32 |
+
|
| 33 |
+
## Why Add 6?
|
| 34 |
+
|
| 35 |
+
BCD uses only values 0-9. When binary sum exceeds 9:
|
| 36 |
+
- 10 (1010) + 6 = 16 (10000) → 0 with carry
|
| 37 |
+
- 11 (1011) + 6 = 17 (10001) → 1 with carry
|
| 38 |
+
- etc.
|
| 39 |
+
|
| 40 |
+
Adding 6 skips the invalid codes A-F (10-15).
|
| 41 |
+
|
| 42 |
+
## Truth Table (examples)
|
| 43 |
+
|
| 44 |
+
| A | B | Cin | S | Cout |
|
| 45 |
+
|---|---|-----|---|------|
|
| 46 |
+
| 5 | 3 | 0 | 8 | 0 |
|
| 47 |
+
| 5 | 5 | 0 | 0 | 1 |
|
| 48 |
+
| 9 | 9 | 0 | 8 | 1 |
|
| 49 |
+
| 9 | 9 | 1 | 9 | 1 |
|
| 50 |
+
|
| 51 |
+
## Architecture
|
| 52 |
+
|
| 53 |
+
| Stage | Component | Neurons |
|
| 54 |
+
|-------|-----------|---------|
|
| 55 |
+
| Binary add | 4 Full Adders | 28 |
|
| 56 |
+
| Detect >9 | AND, OR gates | 4 |
|
| 57 |
+
| Correction | 2 Half Adders + XOR | 11 |
|
| 58 |
+
|
| 59 |
+
**Total: 43 neurons, 133 parameters, 5 layers**
|
| 60 |
+
|
| 61 |
+
## Applications
|
| 62 |
+
|
| 63 |
+
- Decimal arithmetic in calculators
|
| 64 |
+
- Financial calculations requiring exact decimal
|
| 65 |
+
- BCD-based displays (7-segment)
|
| 66 |
+
- Legacy systems using packed BCD
|
| 67 |
+
|
| 68 |
+
## Usage
|
| 69 |
+
|
| 70 |
+
```python
|
| 71 |
+
from safetensors.torch import load_file
|
| 72 |
+
|
| 73 |
+
w = load_file('model.safetensors')
|
| 74 |
+
|
| 75 |
+
# Valid inputs: A, B in range 0-9
|
| 76 |
+
# All 200 test cases verified (10 × 10 × 2)
|
| 77 |
+
```
|
| 78 |
+
|
| 79 |
+
## Files
|
| 80 |
+
|
| 81 |
+
```
|
| 82 |
+
threshold-bcd-adder/
|
| 83 |
+
├── model.safetensors
|
| 84 |
+
├── create_safetensors.py
|
| 85 |
+
├── config.json
|
| 86 |
+
└── README.md
|
| 87 |
+
```
|
| 88 |
+
|
| 89 |
+
## License
|
| 90 |
+
|
| 91 |
+
MIT
|
config.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "threshold-bcd-adder",
|
| 3 |
+
"description": "BCD (Binary-Coded Decimal) adder as threshold circuit",
|
| 4 |
+
"inputs": 9,
|
| 5 |
+
"outputs": 5,
|
| 6 |
+
"neurons": 43,
|
| 7 |
+
"layers": 5,
|
| 8 |
+
"parameters": 133
|
| 9 |
+
}
|
create_safetensors.py
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from safetensors.torch import save_file
|
| 3 |
+
|
| 4 |
+
weights = {}
|
| 5 |
+
|
| 6 |
+
# BCD Adder (single digit)
|
| 7 |
+
# Inputs: a3,a2,a1,a0, b3,b2,b1,b0, cin (9 inputs)
|
| 8 |
+
# Outputs: s3,s2,s1,s0, cout (5 outputs)
|
| 9 |
+
# Valid inputs: 0-9 for A and B
|
| 10 |
+
#
|
| 11 |
+
# Algorithm:
|
| 12 |
+
# 1. Binary add: Z = A + B + Cin
|
| 13 |
+
# 2. If Z > 9 or carry: add 6 for correction
|
| 14 |
+
# 3. Decimal carry if Z > 9 or binary carry
|
| 15 |
+
|
| 16 |
+
def add_xor(name):
|
| 17 |
+
weights[f'{name}.or.weight'] = torch.tensor([[1.0, 1.0]], dtype=torch.float32)
|
| 18 |
+
weights[f'{name}.or.bias'] = torch.tensor([-1.0], dtype=torch.float32)
|
| 19 |
+
weights[f'{name}.nand.weight'] = torch.tensor([[-1.0, -1.0]], dtype=torch.float32)
|
| 20 |
+
weights[f'{name}.nand.bias'] = torch.tensor([1.0], dtype=torch.float32)
|
| 21 |
+
weights[f'{name}.and.weight'] = torch.tensor([[1.0, 1.0]], dtype=torch.float32)
|
| 22 |
+
weights[f'{name}.and.bias'] = torch.tensor([-2.0], dtype=torch.float32)
|
| 23 |
+
|
| 24 |
+
def add_maj(name):
|
| 25 |
+
weights[f'{name}.weight'] = torch.tensor([[1.0, 1.0, 1.0]], dtype=torch.float32)
|
| 26 |
+
weights[f'{name}.bias'] = torch.tensor([-2.0], dtype=torch.float32)
|
| 27 |
+
|
| 28 |
+
def add_fa(name):
|
| 29 |
+
add_xor(f'{name}.xor1')
|
| 30 |
+
add_xor(f'{name}.sum')
|
| 31 |
+
add_maj(f'{name}.carry')
|
| 32 |
+
|
| 33 |
+
def add_ha(name):
|
| 34 |
+
add_xor(f'{name}.sum')
|
| 35 |
+
weights[f'{name}.carry.weight'] = torch.tensor([[1.0, 1.0]], dtype=torch.float32)
|
| 36 |
+
weights[f'{name}.carry.bias'] = torch.tensor([-2.0], dtype=torch.float32)
|
| 37 |
+
|
| 38 |
+
def add_and(name, n_inputs):
|
| 39 |
+
weights[f'{name}.weight'] = torch.tensor([[1.0] * n_inputs], dtype=torch.float32)
|
| 40 |
+
weights[f'{name}.bias'] = torch.tensor([-float(n_inputs)], dtype=torch.float32)
|
| 41 |
+
|
| 42 |
+
def add_or(name, n_inputs):
|
| 43 |
+
weights[f'{name}.weight'] = torch.tensor([[1.0] * n_inputs], dtype=torch.float32)
|
| 44 |
+
weights[f'{name}.bias'] = torch.tensor([-1.0], dtype=torch.float32)
|
| 45 |
+
|
| 46 |
+
# Stage 1: 4-bit binary adder
|
| 47 |
+
add_fa('bin_fa0')
|
| 48 |
+
add_fa('bin_fa1')
|
| 49 |
+
add_fa('bin_fa2')
|
| 50 |
+
add_fa('bin_fa3')
|
| 51 |
+
|
| 52 |
+
# Stage 2: Detect if > 9 or carry
|
| 53 |
+
# Z > 9 means: Z3·Z2 + Z3·Z1 = Z3·(Z2+Z1)
|
| 54 |
+
# Or equivalently: (Z >= 10) = Z3·Z2 + Z3·Z1
|
| 55 |
+
add_and('detect_z3z2', 2)
|
| 56 |
+
add_and('detect_z3z1', 2)
|
| 57 |
+
add_or('detect_gt9', 2)
|
| 58 |
+
add_or('need_correct', 2)
|
| 59 |
+
|
| 60 |
+
# Stage 3: Conditional add 6 (only bits 1,2 affected, bit 0 unchanged)
|
| 61 |
+
# If correction needed: add 0110 to Z
|
| 62 |
+
add_ha('corr_ha1')
|
| 63 |
+
add_ha('corr_ha2')
|
| 64 |
+
add_xor('corr_xor3')
|
| 65 |
+
|
| 66 |
+
save_file(weights, 'model.safetensors')
|
| 67 |
+
|
| 68 |
+
def eval_xor(a, b):
|
| 69 |
+
or_out = int(a + b >= 1)
|
| 70 |
+
nand_out = int(-a - b + 1 >= 0)
|
| 71 |
+
return int(or_out + nand_out >= 2)
|
| 72 |
+
|
| 73 |
+
def eval_maj(a, b, c):
|
| 74 |
+
return int(a + b + c >= 2)
|
| 75 |
+
|
| 76 |
+
def eval_fa(a, b, cin):
|
| 77 |
+
x1 = eval_xor(a, b)
|
| 78 |
+
s = eval_xor(x1, cin)
|
| 79 |
+
c = eval_maj(a, b, cin)
|
| 80 |
+
return s, c
|
| 81 |
+
|
| 82 |
+
def eval_ha(a, b):
|
| 83 |
+
return eval_xor(a, b), int(a + b >= 2)
|
| 84 |
+
|
| 85 |
+
def bcd_add(a3, a2, a1, a0, b3, b2, b1, b0, cin):
|
| 86 |
+
z0, c0 = eval_fa(a0, b0, cin)
|
| 87 |
+
z1, c1 = eval_fa(a1, b1, c0)
|
| 88 |
+
z2, c2 = eval_fa(a2, b2, c1)
|
| 89 |
+
z3, c3 = eval_fa(a3, b3, c2)
|
| 90 |
+
gt9_a = z3 and z2
|
| 91 |
+
gt9_b = z3 and z1
|
| 92 |
+
gt9 = gt9_a or gt9_b
|
| 93 |
+
need_corr = gt9 or c3
|
| 94 |
+
if need_corr:
|
| 95 |
+
s0 = z0
|
| 96 |
+
s1, c_s1 = eval_ha(z1, 1)
|
| 97 |
+
s2, c_s2 = eval_ha(z2, c_s1)
|
| 98 |
+
s2, c_s2b = eval_ha(s2, 1)
|
| 99 |
+
s3 = eval_xor(z3, c_s2 or c_s2b)
|
| 100 |
+
cout = 1
|
| 101 |
+
else:
|
| 102 |
+
s0, s1, s2, s3 = z0, z1, z2, z3
|
| 103 |
+
cout = 0
|
| 104 |
+
return s0, s1, s2, s3, cout
|
| 105 |
+
|
| 106 |
+
print("Verifying BCD Adder...")
|
| 107 |
+
errors = 0
|
| 108 |
+
for a in range(10):
|
| 109 |
+
for b in range(10):
|
| 110 |
+
for cin in range(2):
|
| 111 |
+
a3, a2, a1, a0 = (a>>3)&1, (a>>2)&1, (a>>1)&1, a&1
|
| 112 |
+
b3, b2, b1, b0 = (b>>3)&1, (b>>2)&1, (b>>1)&1, b&1
|
| 113 |
+
s0, s1, s2, s3, cout = bcd_add(a3, a2, a1, a0, b3, b2, b1, b0, cin)
|
| 114 |
+
result = s0 + (s1 << 1) + (s2 << 2) + (s3 << 3)
|
| 115 |
+
decimal_result = result + cout * 10
|
| 116 |
+
expected = a + b + cin
|
| 117 |
+
if decimal_result != expected:
|
| 118 |
+
errors += 1
|
| 119 |
+
if errors <= 5:
|
| 120 |
+
print(f"ERROR: {a}+{b}+{cin} = {decimal_result} (s={result},c={cout}), expected {expected}")
|
| 121 |
+
|
| 122 |
+
if errors == 0:
|
| 123 |
+
print("All 200 test cases passed!")
|
| 124 |
+
else:
|
| 125 |
+
print(f"FAILED: {errors} errors")
|
| 126 |
+
|
| 127 |
+
mag = sum(t.abs().sum().item() for t in weights.values())
|
| 128 |
+
print(f"Magnitude: {mag:.0f}")
|
| 129 |
+
print(f"Parameters: {sum(t.numel() for t in weights.values())}")
|
model.safetensors
ADDED
|
Binary file (7.19 kB). View file
|
|
|