CharlesCNorton commited on
Commit
3635a46
·
0 Parent(s):

4-bit left barrel shifter, magnitude 61

Browse files
Files changed (5) hide show
  1. README.md +78 -0
  2. config.json +9 -0
  3. create_safetensors.py +117 -0
  4. model.py +40 -0
  5. model.safetensors +0 -0
README.md ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ tags:
4
+ - pytorch
5
+ - safetensors
6
+ - threshold-logic
7
+ - neuromorphic
8
+ ---
9
+
10
+ # threshold-barrelshift4
11
+
12
+ 4-bit left barrel shifter. Shifts by variable amount 0-3.
13
+
14
+ ## Function
15
+
16
+ barrelshift4(a3, a2, a1, a0, s1, s0) = [a3, a2, a1, a0] << s
17
+
18
+ where s = 2*s1 + s0 (shift amount 0-3)
19
+
20
+ ## Examples
21
+
22
+ | Input | Shift | Output |
23
+ |-------|-------|--------|
24
+ | 0001 | 0 | 0001 |
25
+ | 0001 | 1 | 0010 |
26
+ | 0001 | 2 | 0100 |
27
+ | 0001 | 3 | 1000 |
28
+ | 1010 | 1 | 0100 |
29
+ | 1111 | 2 | 1100 |
30
+
31
+ ## Architecture
32
+
33
+ ```
34
+ Layer 1: (data_bit AND shift_match) detectors (10 neurons)
35
+ Each neuron fires when a specific data bit is 1 AND shift amount matches.
36
+
37
+ a3_s00: a3 AND s=00 (y3 source when s=0)
38
+ a2_s00: a2 AND s=00 (y2 source when s=0)
39
+ a2_s01: a2 AND s=01 (y3 source when s=1)
40
+ a1_s00: a1 AND s=00 (y1 source when s=0)
41
+ a1_s01: a1 AND s=01 (y2 source when s=1)
42
+ a1_s10: a1 AND s=10 (y3 source when s=2)
43
+ a0_s00: a0 AND s=00 (y0 source when s=0)
44
+ a0_s01: a0 AND s=01 (y1 source when s=1)
45
+ a0_s10: a0 AND s=10 (y2 source when s=2)
46
+ a0_s11: a0 AND s=11 (y3 source when s=3)
47
+
48
+ Layer 2: OR gates combining relevant sources (4 neurons)
49
+ y3 = a3_s00 OR a2_s01 OR a1_s10 OR a0_s11
50
+ y2 = a2_s00 OR a1_s01 OR a0_s10
51
+ y1 = a1_s00 OR a0_s01
52
+ y0 = a0_s00
53
+ ```
54
+
55
+ ## Parameters
56
+
57
+ | | |
58
+ |---|---|
59
+ | Inputs | 6 (4 data + 2 shift) |
60
+ | Outputs | 4 |
61
+ | Neurons | 14 |
62
+ | Layers | 2 |
63
+ | Parameters | 114 |
64
+ | Magnitude | 61 |
65
+
66
+ ## Usage
67
+
68
+ ```python
69
+ from safetensors.torch import load_file
70
+ # See model.py for full implementation
71
+
72
+ # barrelshift4(0,0,0,1, 0,1) = [0,0,1,0] # 0001 << 1 = 0010
73
+ # barrelshift4(0,0,0,1, 1,1) = [1,0,0,0] # 0001 << 3 = 1000
74
+ ```
75
+
76
+ ## License
77
+
78
+ MIT
config.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "threshold-barrelshift4",
3
+ "description": "4-bit left barrel shifter",
4
+ "inputs": 6,
5
+ "outputs": 4,
6
+ "neurons": 14,
7
+ "layers": 2,
8
+ "parameters": 114
9
+ }
create_safetensors.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from safetensors.torch import save_file
3
+
4
+ weights = {}
5
+
6
+ # Input order: [a3, a2, a1, a0, s1, s0] (6 inputs)
7
+ # 4-bit left barrel shift by s (0-3)
8
+ # s=0: [a3, a2, a1, a0], s=1: [a2, a1, a0, 0], s=2: [a1, a0, 0, 0], s=3: [a0, 0, 0, 0]
9
+
10
+ # Layer 1: (data_bit AND shift_match) neurons
11
+ # Each fires when specific data bit is 1 AND shift amount matches
12
+
13
+ # a3_s00: a3 AND s=00 (for y3 when s=0)
14
+ weights['a3_s00.weight'] = torch.tensor([[1.0, 0.0, 0.0, 0.0, -1.0, -1.0]], dtype=torch.float32)
15
+ weights['a3_s00.bias'] = torch.tensor([-1.0], dtype=torch.float32)
16
+
17
+ # a2_s00: a2 AND s=00 (for y2 when s=0)
18
+ weights['a2_s00.weight'] = torch.tensor([[0.0, 1.0, 0.0, 0.0, -1.0, -1.0]], dtype=torch.float32)
19
+ weights['a2_s00.bias'] = torch.tensor([-1.0], dtype=torch.float32)
20
+
21
+ # a2_s01: a2 AND s=01 (for y3 when s=1)
22
+ weights['a2_s01.weight'] = torch.tensor([[0.0, 1.0, 0.0, 0.0, -1.0, 1.0]], dtype=torch.float32)
23
+ weights['a2_s01.bias'] = torch.tensor([-2.0], dtype=torch.float32)
24
+
25
+ # a1_s00: a1 AND s=00 (for y1 when s=0)
26
+ weights['a1_s00.weight'] = torch.tensor([[0.0, 0.0, 1.0, 0.0, -1.0, -1.0]], dtype=torch.float32)
27
+ weights['a1_s00.bias'] = torch.tensor([-1.0], dtype=torch.float32)
28
+
29
+ # a1_s01: a1 AND s=01 (for y2 when s=1)
30
+ weights['a1_s01.weight'] = torch.tensor([[0.0, 0.0, 1.0, 0.0, -1.0, 1.0]], dtype=torch.float32)
31
+ weights['a1_s01.bias'] = torch.tensor([-2.0], dtype=torch.float32)
32
+
33
+ # a1_s10: a1 AND s=10 (for y3 when s=2)
34
+ weights['a1_s10.weight'] = torch.tensor([[0.0, 0.0, 1.0, 0.0, 1.0, -1.0]], dtype=torch.float32)
35
+ weights['a1_s10.bias'] = torch.tensor([-2.0], dtype=torch.float32)
36
+
37
+ # a0_s00: a0 AND s=00 (for y0 when s=0)
38
+ weights['a0_s00.weight'] = torch.tensor([[0.0, 0.0, 0.0, 1.0, -1.0, -1.0]], dtype=torch.float32)
39
+ weights['a0_s00.bias'] = torch.tensor([-1.0], dtype=torch.float32)
40
+
41
+ # a0_s01: a0 AND s=01 (for y1 when s=1)
42
+ weights['a0_s01.weight'] = torch.tensor([[0.0, 0.0, 0.0, 1.0, -1.0, 1.0]], dtype=torch.float32)
43
+ weights['a0_s01.bias'] = torch.tensor([-2.0], dtype=torch.float32)
44
+
45
+ # a0_s10: a0 AND s=10 (for y2 when s=2)
46
+ weights['a0_s10.weight'] = torch.tensor([[0.0, 0.0, 0.0, 1.0, 1.0, -1.0]], dtype=torch.float32)
47
+ weights['a0_s10.bias'] = torch.tensor([-2.0], dtype=torch.float32)
48
+
49
+ # a0_s11: a0 AND s=11 (for y3 when s=3)
50
+ weights['a0_s11.weight'] = torch.tensor([[0.0, 0.0, 0.0, 1.0, 1.0, 1.0]], dtype=torch.float32)
51
+ weights['a0_s11.bias'] = torch.tensor([-3.0], dtype=torch.float32)
52
+
53
+ # Layer 2: OR gates for each output
54
+ # Layer 1 order: [a3_s00, a2_s00, a2_s01, a1_s00, a1_s01, a1_s10, a0_s00, a0_s01, a0_s10, a0_s11]
55
+ # 0 1 2 3 4 5 6 7 8 9
56
+
57
+ # y3 = a3_s00 OR a2_s01 OR a1_s10 OR a0_s11 (indices 0, 2, 5, 9)
58
+ weights['y3.weight'] = torch.tensor([[1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]], dtype=torch.float32)
59
+ weights['y3.bias'] = torch.tensor([-1.0], dtype=torch.float32)
60
+
61
+ # y2 = a2_s00 OR a1_s01 OR a0_s10 (indices 1, 4, 8)
62
+ weights['y2.weight'] = torch.tensor([[0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0]], dtype=torch.float32)
63
+ weights['y2.bias'] = torch.tensor([-1.0], dtype=torch.float32)
64
+
65
+ # y1 = a1_s00 OR a0_s01 (indices 3, 7)
66
+ weights['y1.weight'] = torch.tensor([[0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0]], dtype=torch.float32)
67
+ weights['y1.bias'] = torch.tensor([-1.0], dtype=torch.float32)
68
+
69
+ # y0 = a0_s00 (index 6)
70
+ weights['y0.weight'] = torch.tensor([[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0]], dtype=torch.float32)
71
+ weights['y0.bias'] = torch.tensor([-1.0], dtype=torch.float32)
72
+
73
+ save_file(weights, 'model.safetensors')
74
+
75
+ # Verify
76
+ def barrelshift4(a3, a2, a1, a0, s1, s0):
77
+ inp = torch.tensor([float(a3), float(a2), float(a1), float(a0), float(s1), float(s0)])
78
+
79
+ # Layer 1
80
+ l1_names = ['a3_s00', 'a2_s00', 'a2_s01', 'a1_s00', 'a1_s01', 'a1_s10', 'a0_s00', 'a0_s01', 'a0_s10', 'a0_s11']
81
+ l1 = []
82
+ for name in l1_names:
83
+ v = int((inp @ weights[f'{name}.weight'].T + weights[f'{name}.bias'] >= 0).item())
84
+ l1.append(float(v))
85
+ l1_tensor = torch.tensor(l1)
86
+
87
+ # Layer 2
88
+ outputs = []
89
+ for name in ['y3', 'y2', 'y1', 'y0']:
90
+ v = int((l1_tensor @ weights[f'{name}.weight'].T + weights[f'{name}.bias'] >= 0).item())
91
+ outputs.append(v)
92
+ return outputs
93
+
94
+ print("Verifying barrelshift4...")
95
+ errors = 0
96
+ for val in range(16): # all 4-bit values
97
+ a3, a2, a1, a0 = (val >> 3) & 1, (val >> 2) & 1, (val >> 1) & 1, val & 1
98
+ for s in range(4): # all shift amounts
99
+ s1, s0 = (s >> 1) & 1, s & 1
100
+ result = barrelshift4(a3, a2, a1, a0, s1, s0)
101
+
102
+ # Expected: left shift by s
103
+ shifted = (val << s) & 0xF
104
+ expected = [(shifted >> 3) & 1, (shifted >> 2) & 1, (shifted >> 1) & 1, shifted & 1]
105
+
106
+ if result != expected:
107
+ errors += 1
108
+ if errors <= 5:
109
+ print(f"ERROR: val={val:04b} s={s} -> {result}, expected {expected}")
110
+
111
+ if errors == 0:
112
+ print("All 64 test cases passed!")
113
+ else:
114
+ print(f"FAILED: {errors} errors")
115
+
116
+ mag = sum(t.abs().sum().item() for t in weights.values())
117
+ print(f"Magnitude: {mag:.0f}")
model.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from safetensors.torch import load_file
3
+
4
+ def load_model(path='model.safetensors'):
5
+ return load_file(path)
6
+
7
+ def barrelshift4(a3, a2, a1, a0, s1, s0, weights):
8
+ """4-bit left barrel shifter. Shifts left by s = 2*s1 + s0 positions."""
9
+ inp = torch.tensor([float(a3), float(a2), float(a1), float(a0), float(s1), float(s0)])
10
+
11
+ # Layer 1
12
+ l1_names = ['a3_s00', 'a2_s00', 'a2_s01', 'a1_s00', 'a1_s01', 'a1_s10', 'a0_s00', 'a0_s01', 'a0_s10', 'a0_s11']
13
+ l1 = []
14
+ for name in l1_names:
15
+ v = int((inp @ weights[f'{name}.weight'].T + weights[f'{name}.bias'] >= 0).item())
16
+ l1.append(float(v))
17
+ l1_tensor = torch.tensor(l1)
18
+
19
+ # Layer 2
20
+ outputs = []
21
+ for name in ['y3', 'y2', 'y1', 'y0']:
22
+ v = int((l1_tensor @ weights[f'{name}.weight'].T + weights[f'{name}.bias'] >= 0).item())
23
+ outputs.append(v)
24
+ return outputs
25
+
26
+ if __name__ == '__main__':
27
+ w = load_model()
28
+ print('barrelshift4 examples:')
29
+ test_cases = [
30
+ (0, 0, 0, 1, 0, 0), # 0001 << 0 = 0001
31
+ (0, 0, 0, 1, 0, 1), # 0001 << 1 = 0010
32
+ (0, 0, 0, 1, 1, 0), # 0001 << 2 = 0100
33
+ (0, 0, 0, 1, 1, 1), # 0001 << 3 = 1000
34
+ (1, 0, 1, 0, 0, 1), # 1010 << 1 = 0100
35
+ ]
36
+ for args in test_cases:
37
+ a3, a2, a1, a0, s1, s0 = args
38
+ result = barrelshift4(a3, a2, a1, a0, s1, s0, w)
39
+ s = s1 * 2 + s0
40
+ print(f' {a3}{a2}{a1}{a0} << {s} = {result[0]}{result[1]}{result[2]}{result[3]}')
model.safetensors ADDED
Binary file (2.35 kB). View file