phanerozoic commited on
Commit
76f4679
·
verified ·
1 Parent(s): 0b67817

Upload folder using huggingface_hub

Browse files
Files changed (5) hide show
  1. README.md +159 -0
  2. config.json +9 -0
  3. create_safetensors.py +65 -0
  4. model.py +30 -0
  5. model.safetensors +3 -0
README.md ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ tags:
4
+ - pytorch
5
+ - safetensors
6
+ - threshold-logic
7
+ - neuromorphic
8
+ - multiplexer
9
+ ---
10
+
11
+ # threshold-mux2
12
+
13
+ 2:1 multiplexer. The fundamental building block for data selection, routing one of two inputs to the output based on a select signal.
14
+
15
+ ## Circuit
16
+
17
+ ```
18
+ d0 d1
19
+ │ │
20
+ │ │ s (select)
21
+ │ │ │
22
+ ├───────┼───────┤
23
+ │ │ │
24
+ ▼ │ │
25
+ ┌───────┐ │ │
26
+ │ sel0 │◄──┼───────┤
27
+ │d0∧¬s │ │ │
28
+ └───────┘ │ │
29
+ │ ▼ │
30
+ │ ┌───────┐ │
31
+ │ │ sel1 │◄──┘
32
+ │ │ d1∧s │
33
+ │ └───────┘
34
+ │ │
35
+ └───┬───┘
36
+
37
+ ┌───────┐
38
+ │ OR │
39
+ └───────┘
40
+
41
+
42
+ output
43
+ ```
44
+
45
+ ## Truth Table
46
+
47
+ | s | d0 | d1 | out | Description |
48
+ |---|----|----|-----|-------------|
49
+ | 0 | 0 | 0 | 0 | Select d0 (0) |
50
+ | 0 | 0 | 1 | 0 | Select d0 (0) |
51
+ | 0 | 1 | 0 | 1 | Select d0 (1) |
52
+ | 0 | 1 | 1 | 1 | Select d0 (1) |
53
+ | 1 | 0 | 0 | 0 | Select d1 (0) |
54
+ | 1 | 0 | 1 | 1 | Select d1 (1) |
55
+ | 1 | 1 | 0 | 0 | Select d1 (0) |
56
+ | 1 | 1 | 1 | 1 | Select d1 (1) |
57
+
58
+ Formula: `out = (d0 AND NOT s) OR (d1 AND s)`
59
+
60
+ ## Mechanism
61
+
62
+ **Layer 1 - Selection Gates:**
63
+
64
+ The circuit uses two AND-with-complement gates that fire only when their respective data input is selected:
65
+
66
+ | Gate | Weights [d0, d1, s] | Bias | Function |
67
+ |------|---------------------|------|----------|
68
+ | sel0 | [1, 0, -1] | -1 | d0 AND NOT(s) |
69
+ | sel1 | [0, 1, 1] | -2 | d1 AND s |
70
+
71
+ **sel0** fires when d0=1 AND s=0:
72
+ - The negative weight on s means s=1 inhibits firing
73
+ - Bias -1 requires d0=1 to reach threshold when s=0
74
+
75
+ **sel1** fires when d1=1 AND s=1:
76
+ - Both d1 and s must be 1 to overcome bias -2
77
+
78
+ **Layer 2 - Output:**
79
+
80
+ Simple OR gate combines the two selection paths.
81
+
82
+ ## Architecture
83
+
84
+ | Component | Weights | Bias | Function |
85
+ |-----------|---------|------|----------|
86
+ | sel0 | [1, 0, -1] | -1 | d0 AND NOT(s) |
87
+ | sel1 | [0, 1, 1] | -2 | d1 AND s |
88
+ | or | [1, 1] | -1 | OR(sel0, sel1) |
89
+
90
+ ## Parameters
91
+
92
+ | | |
93
+ |---|---|
94
+ | Inputs | 3 (d0, d1, s) |
95
+ | Outputs | 1 |
96
+ | Neurons | 3 |
97
+ | Layers | 2 |
98
+ | Parameters | 11 |
99
+ | Magnitude | 10 |
100
+
101
+ ## Building Larger Multiplexers
102
+
103
+ The MUX2 is the primitive for constructing larger multiplexers:
104
+
105
+ ```
106
+ MUX4 = MUX2(MUX2(d0,d1,s0), MUX2(d2,d3,s0), s1)
107
+ MUX8 = MUX2(MUX4(d0-d3), MUX4(d4-d7), s2)
108
+ MUX16 = MUX2(MUX8(d0-d7), MUX8(d8-d15), s3)
109
+ ```
110
+
111
+ Each doubling adds one layer of MUX2 gates.
112
+
113
+ ## Usage
114
+
115
+ ```python
116
+ from safetensors.torch import load_file
117
+ import torch
118
+
119
+ w = load_file('model.safetensors')
120
+
121
+ def mux2(d0, d1, s):
122
+ inp = torch.tensor([float(d0), float(d1), float(s)])
123
+
124
+ # Layer 1: Selection
125
+ sel0 = int((inp @ w['sel0.weight'].T + w['sel0.bias'] >= 0).item())
126
+ sel1 = int((inp @ w['sel1.weight'].T + w['sel1.bias'] >= 0).item())
127
+
128
+ # Layer 2: Combine
129
+ l1 = torch.tensor([float(sel0), float(sel1)])
130
+ return int((l1 @ w['or.weight'].T + w['or.bias'] >= 0).item())
131
+
132
+ # Examples
133
+ print(mux2(1, 0, 0)) # 1 (selects d0)
134
+ print(mux2(1, 0, 1)) # 0 (selects d1)
135
+ print(mux2(0, 1, 1)) # 1 (selects d1)
136
+ ```
137
+
138
+ ## Applications
139
+
140
+ - Data routing in ALUs
141
+ - Register file read ports
142
+ - Conditional assignment in hardware
143
+ - Building blocks for barrel shifters
144
+ - Crossbar switches
145
+
146
+ ## Files
147
+
148
+ ```
149
+ threshold-mux2/
150
+ ├── model.safetensors
151
+ ├── model.py
152
+ ├── create_safetensors.py
153
+ ├── config.json
154
+ └── README.md
155
+ ```
156
+
157
+ ## License
158
+
159
+ MIT
config.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "threshold-mux2",
3
+ "description": "2:1 multiplexer - selects one of two inputs based on select signal",
4
+ "inputs": 3,
5
+ "outputs": 1,
6
+ "neurons": 3,
7
+ "layers": 2,
8
+ "parameters": 11
9
+ }
create_safetensors.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from safetensors.torch import save_file
3
+
4
+ weights = {}
5
+
6
+ # 2:1 Multiplexer
7
+ # Inputs: d0, d1, s
8
+ # Output: d0 if s=0, d1 if s=1
9
+ #
10
+ # Formula: out = (d0 AND NOT s) OR (d1 AND s)
11
+ #
12
+ # Layer 1:
13
+ # sel0: d0 AND NOT(s) - fires when d0=1 and s=0
14
+ # sel1: d1 AND s - fires when d1=1 and s=1
15
+ #
16
+ # Layer 2:
17
+ # or: OR(sel0, sel1)
18
+
19
+ # sel0: d0 AND NOT(s)
20
+ # Weights: [d0, d1, s] = [1, 0, -1], bias = -1
21
+ # d0=1, s=0: 1 + 0 - 0 - 1 = 0 >= 0 -> fires
22
+ # d0=1, s=1: 1 + 0 - 1 - 1 = -1 < 0 -> doesn't fire
23
+ weights['sel0.weight'] = torch.tensor([[1.0, 0.0, -1.0]], dtype=torch.float32)
24
+ weights['sel0.bias'] = torch.tensor([-1.0], dtype=torch.float32)
25
+
26
+ # sel1: d1 AND s
27
+ # Weights: [d0, d1, s] = [0, 1, 1], bias = -2
28
+ # d1=1, s=1: 0 + 1 + 1 - 2 = 0 >= 0 -> fires
29
+ # d1=1, s=0: 0 + 1 + 0 - 2 = -1 < 0 -> doesn't fire
30
+ weights['sel1.weight'] = torch.tensor([[0.0, 1.0, 1.0]], dtype=torch.float32)
31
+ weights['sel1.bias'] = torch.tensor([-2.0], dtype=torch.float32)
32
+
33
+ # or: OR(sel0, sel1)
34
+ weights['or.weight'] = torch.tensor([[1.0, 1.0]], dtype=torch.float32)
35
+ weights['or.bias'] = torch.tensor([-1.0], dtype=torch.float32)
36
+
37
+ save_file(weights, 'model.safetensors')
38
+
39
+ # Verification
40
+ def mux2(d0, d1, s):
41
+ inp = torch.tensor([float(d0), float(d1), float(s)])
42
+ sel0 = int((inp @ weights['sel0.weight'].T + weights['sel0.bias'] >= 0).item())
43
+ sel1 = int((inp @ weights['sel1.weight'].T + weights['sel1.bias'] >= 0).item())
44
+ l1 = torch.tensor([float(sel0), float(sel1)])
45
+ return int((l1 @ weights['or.weight'].T + weights['or.bias'] >= 0).item())
46
+
47
+ print("Verifying MUX2...")
48
+ errors = 0
49
+ for s in [0, 1]:
50
+ for d0 in [0, 1]:
51
+ for d1 in [0, 1]:
52
+ result = mux2(d0, d1, s)
53
+ expected = d1 if s else d0
54
+ if result != expected:
55
+ errors += 1
56
+ print(f"ERROR: mux2({d0}, {d1}, {s}) = {result}, expected {expected}")
57
+
58
+ if errors == 0:
59
+ print("All 8 test cases passed!")
60
+ else:
61
+ print(f"FAILED: {errors} errors")
62
+
63
+ mag = sum(t.abs().sum().item() for t in weights.values())
64
+ print(f"Magnitude: {mag:.0f}")
65
+ print(f"Parameters: {sum(t.numel() for t in weights.values())}")
model.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 mux2(d0, d1, s, weights):
8
+ """2:1 Multiplexer: returns d0 if s=0, d1 if s=1."""
9
+ inp = torch.tensor([float(d0), float(d1), float(s)])
10
+
11
+ # Layer 1: Selection gates
12
+ sel0 = int((inp @ weights['sel0.weight'].T + weights['sel0.bias'] >= 0).item())
13
+ sel1 = int((inp @ weights['sel1.weight'].T + weights['sel1.bias'] >= 0).item())
14
+
15
+ # Layer 2: OR gate
16
+ l1 = torch.tensor([float(sel0), float(sel1)])
17
+ return int((l1 @ weights['or.weight'].T + weights['or.bias'] >= 0).item())
18
+
19
+ if __name__ == '__main__':
20
+ w = load_model()
21
+ print('MUX2 Truth Table:')
22
+ print('s d0 d1 | out | expected')
23
+ print('-' * 28)
24
+ for s in [0, 1]:
25
+ for d0 in [0, 1]:
26
+ for d1 in [0, 1]:
27
+ result = mux2(d0, d1, s, w)
28
+ expected = d1 if s else d0
29
+ status = 'OK' if result == expected else 'FAIL'
30
+ print(f'{s} {d0} {d1} | {result} | {expected} {status}')
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:17df49d80c83b1921b229ca946cb0b9a46a0892e640a91a79753047285267c47
3
+ size 436