phanerozoic commited on
Commit
1c68242
·
verified ·
1 Parent(s): 984e450

Rename from tiny-mod3-verified

Browse files
Files changed (5) hide show
  1. README.md +109 -0
  2. config.json +30 -0
  3. model.py +119 -0
  4. model.safetensors +3 -0
  5. tmpclaude-9499-cwd +1 -0
README.md ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ tags:
4
+ - pytorch
5
+ - safetensors
6
+ - threshold-logic
7
+ - neuromorphic
8
+ - modular-arithmetic
9
+ ---
10
+
11
+ # threshold-mod3
12
+
13
+ Computes Hamming weight mod 3 for 8-bit inputs. Multi-layer network using thermometer encoding.
14
+
15
+ ## Circuit
16
+
17
+ ```
18
+ x₀ x₁ x₂ x₃ x₄ x₅ x₆ x₇
19
+ │ │ │ │ │ │ │ │
20
+ └──┴──┴──┴──┼──┴──┴──┴──┘
21
+
22
+ ┌─────────────┐
23
+ │ Thermometer │ Layer 1: 9 neurons
24
+ │ Encoding │ Fires when HW ≥ k
25
+ └─────────────┘
26
+
27
+
28
+ ┌─────────────┐
29
+ │ MOD-3 │ Layer 2: 2 neurons
30
+ │ Detection │ Weight pattern (1,1,-2)
31
+ └─────────────┘
32
+
33
+
34
+ ┌─────────────┐
35
+ │ Classify │ Output: 3 classes
36
+ └─────────────┘
37
+
38
+
39
+ {0, 1, 2}
40
+ ```
41
+
42
+ ## Algebraic Insight
43
+
44
+ The weight pattern `(1, 1, -2)` causes cumulative sums to cycle mod 3:
45
+
46
+ ```
47
+ HW=0: sum=0 → 0 mod 3
48
+ HW=1: sum=1 → 1 mod 3
49
+ HW=2: sum=2 → 2 mod 3
50
+ HW=3: sum=0 → 0 mod 3 (reset: 1+1-2=0)
51
+ HW=4: sum=1 → 1 mod 3
52
+ ...
53
+ ```
54
+
55
+ The key: `1 + 1 + (1-3) = 0`. Every 3 increments, the sum resets.
56
+
57
+ This generalizes to MOD-m: use `(1, 1, ..., 1, 1-m)` with m-1 ones.
58
+
59
+ ## Architecture
60
+
61
+ | Layer | Neurons | Function |
62
+ |-------|---------|----------|
63
+ | Input | 8 | Binary bits |
64
+ | Hidden 1 | 9 | Thermometer: fires when HW ≥ k |
65
+ | Hidden 2 | 2 | MOD-3 detection |
66
+ | Output | 3 | One-hot classification |
67
+
68
+ **Total: 14 neurons, 110 parameters**
69
+
70
+ ## Output Distribution
71
+
72
+ | Class | HW values | Count/256 |
73
+ |-------|-----------|-----------|
74
+ | 0 | 0, 3, 6 | 85 |
75
+ | 1 | 1, 4, 7 | 86 |
76
+ | 2 | 2, 5, 8 | 85 |
77
+
78
+ ## Usage
79
+
80
+ ```python
81
+ from safetensors.torch import load_file
82
+ import torch
83
+
84
+ w = load_file('model.safetensors')
85
+
86
+ def forward(x):
87
+ x = x.float()
88
+ x = (x @ w['layer1.weight'].T + w['layer1.bias'] >= 0).float()
89
+ x = (x @ w['layer2.weight'].T + w['layer2.bias'] >= 0).float()
90
+ out = x @ w['output.weight'].T + w['output.bias']
91
+ return out.argmax(dim=-1)
92
+
93
+ inp = torch.tensor([[1,0,1,1,0,0,1,0]]) # HW=4
94
+ print(forward(inp).item()) # 1 (4 mod 3 = 1)
95
+ ```
96
+
97
+ ## Files
98
+
99
+ ```
100
+ threshold-mod3/
101
+ ├── model.safetensors
102
+ ├── model.py
103
+ ├── config.json
104
+ └── README.md
105
+ ```
106
+
107
+ ## License
108
+
109
+ MIT
config.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model_type": "threshold_network",
3
+ "task": "mod3_classification",
4
+ "architecture": "8 -> 9 -> 2 -> 3",
5
+ "input_size": 8,
6
+ "hidden1_size": 9,
7
+ "hidden2_size": 2,
8
+ "output_size": 3,
9
+ "num_parameters": 110,
10
+ "num_neurons": 14,
11
+ "activation": "heaviside",
12
+ "weight_constraints": "integer",
13
+ "verification": {
14
+ "method": "coq_proof",
15
+ "exhaustive": true,
16
+ "constructive": true,
17
+ "algebraic": true,
18
+ "axiom_free": true
19
+ },
20
+ "accuracy": {
21
+ "all_inputs": "256/256",
22
+ "percentage": 100.0
23
+ },
24
+ "algebraic_insight": "Weights (1,1,-2) on thermometer encoding produce cumsum = HW mod 3",
25
+ "github": "https://github.com/CharlesCNorton/mod3-verified",
26
+ "related": {
27
+ "parity_model": "https://huggingface.co/phanerozoic/tiny-parity-prover",
28
+ "parity_proofs": "https://github.com/CharlesCNorton/threshold-logic-verified"
29
+ }
30
+ }
model.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Inference code for mod3-verified threshold network.
3
+
4
+ This network computes MOD-3 (Hamming weight mod 3) on 8-bit binary inputs.
5
+ """
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+ from safetensors.torch import load_file
10
+
11
+
12
+ def heaviside(x):
13
+ """Heaviside step function: 1 if x >= 0, else 0."""
14
+ return (x >= 0).float()
15
+
16
+
17
+ class Mod3Network(nn.Module):
18
+ """
19
+ Verified threshold network for MOD-3 computation.
20
+
21
+ Architecture: 8 -> 9 -> 2 -> 3
22
+ - Layer 1: Thermometer encoding (9 neurons detect HW >= k)
23
+ - Layer 2: MOD-3 detection using (1,1,-2) weight pattern
24
+ - Output: 3-class classification
25
+ """
26
+
27
+ def __init__(self):
28
+ super().__init__()
29
+ self.layer1 = nn.Linear(8, 9)
30
+ self.layer2 = nn.Linear(9, 2)
31
+ self.output = nn.Linear(2, 3)
32
+
33
+ def forward(self, x):
34
+ """Forward pass with Heaviside activation."""
35
+ x = x.float()
36
+ x = heaviside(self.layer1(x))
37
+ x = heaviside(self.layer2(x))
38
+ x = self.output(x)
39
+ return x
40
+
41
+ def predict(self, x):
42
+ """Get predicted class (0, 1, or 2)."""
43
+ return self.forward(x).argmax(dim=-1)
44
+
45
+ @classmethod
46
+ def from_safetensors(cls, path):
47
+ """Load model from safetensors file."""
48
+ model = cls()
49
+ weights = load_file(path)
50
+
51
+ model.layer1.weight.data = weights['layer1.weight']
52
+ model.layer1.bias.data = weights['layer1.bias']
53
+ model.layer2.weight.data = weights['layer2.weight']
54
+ model.layer2.bias.data = weights['layer2.bias']
55
+ model.output.weight.data = weights['output.weight']
56
+ model.output.bias.data = weights['output.bias']
57
+
58
+ return model
59
+
60
+
61
+ def mod3_reference(x):
62
+ """Reference implementation: Hamming weight mod 3."""
63
+ return (x.sum(dim=-1) % 3).long()
64
+
65
+
66
+ def verify(model, verbose=True):
67
+ """Verify model on all 256 inputs."""
68
+ inputs = torch.zeros(256, 8)
69
+ for i in range(256):
70
+ for j in range(8):
71
+ inputs[i, j] = (i >> j) & 1
72
+
73
+ targets = mod3_reference(inputs)
74
+ predictions = model.predict(inputs)
75
+
76
+ correct = (predictions == targets).sum().item()
77
+
78
+ if verbose:
79
+ print(f"Verification: {correct}/256 ({100*correct/256:.1f}%)")
80
+
81
+ if correct < 256:
82
+ errors = (predictions != targets).nonzero(as_tuple=True)[0]
83
+ print(f"Errors at indices: {errors[:10].tolist()}")
84
+
85
+ return correct == 256
86
+
87
+
88
+ def demo():
89
+ """Demonstration of MOD-3 computation."""
90
+ print("Loading mod3-verified model...")
91
+ model = Mod3Network.from_safetensors('model.safetensors')
92
+
93
+ print("\nVerifying on all 256 inputs...")
94
+ verify(model)
95
+
96
+ print("\nExample predictions:")
97
+ test_cases = [
98
+ [0, 0, 0, 0, 0, 0, 0, 0], # HW=0, 0 mod 3 = 0
99
+ [1, 0, 0, 0, 0, 0, 0, 0], # HW=1, 1 mod 3 = 1
100
+ [1, 1, 0, 0, 0, 0, 0, 0], # HW=2, 2 mod 3 = 2
101
+ [1, 1, 1, 0, 0, 0, 0, 0], # HW=3, 3 mod 3 = 0
102
+ [1, 1, 1, 1, 0, 0, 0, 0], # HW=4, 4 mod 3 = 1
103
+ [1, 1, 1, 1, 1, 0, 0, 0], # HW=5, 5 mod 3 = 2
104
+ [1, 1, 1, 1, 1, 1, 0, 0], # HW=6, 6 mod 3 = 0
105
+ [1, 1, 1, 1, 1, 1, 1, 0], # HW=7, 7 mod 3 = 1
106
+ [1, 1, 1, 1, 1, 1, 1, 1], # HW=8, 8 mod 3 = 2
107
+ ]
108
+
109
+ for bits in test_cases:
110
+ x = torch.tensor([bits], dtype=torch.float32)
111
+ hw = sum(bits)
112
+ pred = model.predict(x).item()
113
+ expected = hw % 3
114
+ status = "OK" if pred == expected else "ERROR"
115
+ print(f" {bits} -> HW={hw}, pred={pred}, expected={expected} [{status}]")
116
+
117
+
118
+ if __name__ == '__main__':
119
+ demo()
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a4dfa3053aa3ab1ec347bd4099c326bb03a2fe05da16a6beeed66cfc35bd1b57
3
+ size 864
tmpclaude-9499-cwd ADDED
@@ -0,0 +1 @@
 
 
1
+ /d/mod3-verified/hf