CharlesCNorton commited on
Commit
5174d28
·
0 Parent(s):

Initial commit: threshold-sklansky threshold circuit

Browse files
Files changed (4) hide show
  1. README.md +60 -0
  2. config.json +9 -0
  3. create_safetensors.py +95 -0
  4. model.safetensors +0 -0
README.md ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ tags:
4
+ - pytorch
5
+ - safetensors
6
+ - threshold-logic
7
+ - neuromorphic
8
+ - arithmetic
9
+ - parallel-prefix
10
+ ---
11
+
12
+ # threshold-sklansky
13
+
14
+ 4-bit Sklansky parallel prefix adder. Achieves minimum depth at the cost of maximum fanout.
15
+
16
+ ## Circuit
17
+
18
+ ```
19
+ Inputs: A[3:0], B[3:0], Cin (9 inputs)
20
+ Outputs: S[3:0], Cout (5 outputs)
21
+ ```
22
+
23
+ ## Sklansky Structure (4-bit)
24
+
25
+ ```
26
+ G3,P3 G2,P2 G1,P1 G0,P0
27
+ │ │ │ │
28
+ L1 ●────────┤ ●────────┤
29
+ │ │ │ │
30
+ L2 ●────────●────────┴────────┘ (high fanout from G1:0)
31
+ │ │
32
+ G3:0 G2:0 G1:0 G0
33
+ ```
34
+
35
+ All positions at level 2 combine with the same prefix (G1:0, P1:0), creating high fanout but minimum depth.
36
+
37
+ ## Trade-off
38
+
39
+ | Property | Value |
40
+ |----------|-------|
41
+ | Depth | O(log n) - optimal |
42
+ | Fanout | O(n) - maximum |
43
+ | Cells | O(n log n) |
44
+
45
+ Best for small adders where fanout is not a concern.
46
+
47
+ ## Parameters
48
+
49
+ | | |
50
+ |---|---|
51
+ | Inputs | 9 |
52
+ | Outputs | 5 |
53
+ | Neurons | 32 |
54
+ | Layers | 4 |
55
+ | Parameters | 132 |
56
+ | Magnitude | 56 |
57
+
58
+ ## License
59
+
60
+ MIT
config.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "threshold-sklansky",
3
+ "description": "4-bit Sklansky parallel prefix adder",
4
+ "inputs": 9,
5
+ "outputs": 5,
6
+ "neurons": 32,
7
+ "layers": 4,
8
+ "parameters": 132
9
+ }
create_safetensors.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from safetensors.torch import save_file
3
+
4
+ weights = {}
5
+
6
+ # 4-bit Sklansky Parallel Prefix Adder
7
+ # Minimum depth, maximum fanout
8
+
9
+ def add_and(name, idx_a, idx_b, n_inputs):
10
+ w = [0.0] * n_inputs
11
+ w[idx_a] = 1.0
12
+ w[idx_b] = 1.0
13
+ weights[f'{name}.weight'] = torch.tensor([w], dtype=torch.float32)
14
+ weights[f'{name}.bias'] = torch.tensor([-2.0], dtype=torch.float32)
15
+
16
+ def add_xor_stage1(name, idx_a, idx_b, n_inputs):
17
+ w_or = [0.0] * n_inputs
18
+ w_or[idx_a] = 1.0
19
+ w_or[idx_b] = 1.0
20
+ weights[f'{name}.or.weight'] = torch.tensor([w_or], dtype=torch.float32)
21
+ weights[f'{name}.or.bias'] = torch.tensor([-1.0], dtype=torch.float32)
22
+ w_nand = [0.0] * n_inputs
23
+ w_nand[idx_a] = -1.0
24
+ w_nand[idx_b] = -1.0
25
+ weights[f'{name}.nand.weight'] = torch.tensor([w_nand], dtype=torch.float32)
26
+ weights[f'{name}.nand.bias'] = torch.tensor([1.0], dtype=torch.float32)
27
+
28
+ def add_xor_stage2(name):
29
+ weights[f'{name}.and.weight'] = torch.tensor([[1.0, 1.0]], dtype=torch.float32)
30
+ weights[f'{name}.and.bias'] = torch.tensor([-2.0], dtype=torch.float32)
31
+
32
+ for i in range(4):
33
+ a_idx = 3 - i
34
+ b_idx = 7 - i
35
+ add_and(f'g{i}', a_idx, b_idx, 9)
36
+ add_xor_stage1(f'p{i}', a_idx, b_idx, 9)
37
+
38
+ for i in range(4):
39
+ add_xor_stage2(f'p{i}')
40
+
41
+ save_file(weights, 'model.safetensors')
42
+
43
+ def sklansky_add(a3, a2, a1, a0, b3, b2, b1, b0, cin):
44
+ a = [a0, a1, a2, a3]
45
+ b = [b0, b1, b2, b3]
46
+
47
+ g = [a[i] & b[i] for i in range(4)]
48
+ p = [a[i] ^ b[i] for i in range(4)]
49
+
50
+ # Level 1: combine pairs
51
+ g10 = g[1] | (p[1] & g[0])
52
+ p10 = p[1] & p[0]
53
+ g32 = g[3] | (p[3] & g[2])
54
+ p32 = p[3] & p[2]
55
+
56
+ # Level 2: all combine with bit 1 prefix (high fanout)
57
+ g20 = g[2] | (p[2] & g10)
58
+ g30 = g32 | (p32 & g10)
59
+ p30 = p32 & p10
60
+
61
+ c0 = g[0] | (p[0] & cin)
62
+ c1 = g10 | (p10 & cin)
63
+ c2 = g20 | (p[2] & p10 & cin)
64
+ c3 = g30 | (p30 & cin)
65
+
66
+ s0 = p[0] ^ cin
67
+ s1 = p[1] ^ c0
68
+ s2 = p[2] ^ c1
69
+ s3 = p[3] ^ c2
70
+
71
+ return s3, s2, s1, s0, c3
72
+
73
+ print("Verifying 4-bit Sklansky adder...")
74
+ errors = 0
75
+ for a in range(16):
76
+ for b in range(16):
77
+ for cin in range(2):
78
+ a3, a2, a1, a0 = (a>>3)&1, (a>>2)&1, (a>>1)&1, a&1
79
+ b3, b2, b1, b0 = (b>>3)&1, (b>>2)&1, (b>>1)&1, b&1
80
+ s3, s2, s1, s0, cout = sklansky_add(a3, a2, a1, a0, b3, b2, b1, b0, cin)
81
+ result = cout*16 + s3*8 + s2*4 + s1*2 + s0
82
+ expected = a + b + cin
83
+ if result != expected:
84
+ errors += 1
85
+ if errors <= 3:
86
+ print(f"ERROR: {a}+{b}+{cin} = {result}, expected {expected}")
87
+
88
+ if errors == 0:
89
+ print("All 512 test cases passed!")
90
+ else:
91
+ print(f"FAILED: {errors} errors")
92
+
93
+ mag = sum(t.abs().sum().item() for t in weights.values())
94
+ print(f"Magnitude: {mag:.0f}")
95
+ print(f"Parameters: {sum(t.numel() for t in weights.values())}")
model.safetensors ADDED
Binary file (2.7 kB). View file