phanerozoic commited on
Commit
ee234cb
·
verified ·
1 Parent(s): 60f0cc6

Rename from tiny-XNOR-verified

Browse files
Files changed (4) hide show
  1. README.md +103 -0
  2. config.json +24 -0
  3. model.py +80 -0
  4. model.safetensors +3 -0
README.md ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ tags:
4
+ - pytorch
5
+ - safetensors
6
+ - threshold-logic
7
+ - neuromorphic
8
+ - multi-layer
9
+ ---
10
+
11
+ # threshold-xnor
12
+
13
+ The equality detector. Fires when both inputs match - both 0 or both 1. Like XOR, this function is not linearly separable and requires two layers.
14
+
15
+ ## Circuit
16
+
17
+ ```
18
+ x y
19
+ │ │
20
+ ├───┬───┤
21
+ │ │ │
22
+ ▼ │ ▼
23
+ ┌──────┐│┌──────┐
24
+ │ NOR │││ AND │ Layer 1
25
+ │w:-1,-1││w:1,1 │
26
+ │b: 0 │││b: -2 │
27
+ └──────┘│└──────┘
28
+ │ │ │
29
+ └───┼───┘
30
+
31
+ ┌──────┐
32
+ │ OR │ Layer 2
33
+ │w: 1,1│
34
+ │b: -1 │
35
+ └──────┘
36
+
37
+
38
+ XNOR(x,y)
39
+ ```
40
+
41
+ ## Mechanism
42
+
43
+ XNOR catches equality via two cases:
44
+
45
+ - NOR fires when both inputs are 0 (both quiet)
46
+ - AND fires when both inputs are 1 (both active)
47
+ - OR combines: at least one case holds
48
+
49
+ | x | y | NOR | AND | OR(NOR,AND) |
50
+ |---|---|-----|-----|-------------|
51
+ | 0 | 0 | 1 | 0 | 1 |
52
+ | 0 | 1 | 0 | 0 | 0 |
53
+ | 1 | 0 | 0 | 0 | 0 |
54
+ | 1 | 1 | 0 | 1 | 1 |
55
+
56
+ XNOR = NOT(XOR). Same non-linear structure, opposite meaning.
57
+
58
+ ## Parameters
59
+
60
+ | Layer | Weights | Bias |
61
+ |-------|---------|------|
62
+ | NOR | [-1, -1] | 0 |
63
+ | AND | [1, 1] | -2 |
64
+ | OR | [1, 1] | -1 |
65
+ | **Total** | | **9** |
66
+
67
+ ## Properties
68
+
69
+ - Commutative: XNOR(x,y) = XNOR(y,x)
70
+ - Reflexive: XNOR(x,x) = 1
71
+ - Equality: x = y iff XNOR(x,y) = 1
72
+
73
+ ## Usage
74
+
75
+ ```python
76
+ from safetensors.torch import load_file
77
+ import torch
78
+
79
+ w = load_file('model.safetensors')
80
+
81
+ def xnor_gate(x, y):
82
+ inp = torch.tensor([float(x), float(y)])
83
+
84
+ nor_out = int((inp * w['layer1.neuron1.weight']).sum() + w['layer1.neuron1.bias'] >= 0)
85
+ and_out = int((inp * w['layer1.neuron2.weight']).sum() + w['layer1.neuron2.bias'] >= 0)
86
+
87
+ l1 = torch.tensor([float(nor_out), float(and_out)])
88
+ return int((l1 * w['layer2.weight']).sum() + w['layer2.bias'] >= 0)
89
+ ```
90
+
91
+ ## Files
92
+
93
+ ```
94
+ threshold-xnor/
95
+ ├── model.safetensors
96
+ ├── model.py
97
+ ├── config.json
98
+ └── README.md
99
+ ```
100
+
101
+ ## License
102
+
103
+ MIT
config.json ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model_type": "threshold_network",
3
+ "task": "xnor_gate",
4
+ "architecture": "2 -> 2 -> 1",
5
+ "input_size": 2,
6
+ "hidden_size": 2,
7
+ "output_size": 1,
8
+ "num_neurons": 3,
9
+ "num_layers": 2,
10
+ "num_parameters": 9,
11
+ "activation": "heaviside",
12
+ "weight_constraints": "integer",
13
+ "verification": {
14
+ "method": "coq_proof",
15
+ "exhaustive": true,
16
+ "inputs_tested": 4
17
+ },
18
+ "accuracy": {
19
+ "all_inputs": "4/4",
20
+ "percentage": 100.0
21
+ },
22
+ "properties": ["not_linearly_separable", "equivalence_relation"],
23
+ "github": "https://github.com/CharlesCNorton/coq-circuits"
24
+ }
model.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Threshold Network for XNOR Gate
3
+
4
+ A formally verified two-layer threshold network computing equivalence.
5
+ XNOR is not linearly separable, requiring at least 2 layers.
6
+ Architecture: Layer1 computes NOR and AND, Layer2 computes OR of results.
7
+ """
8
+
9
+ import torch
10
+ from safetensors.torch import load_file
11
+
12
+
13
+ class ThresholdXNOR:
14
+ """
15
+ XNOR gate implemented as a 2-layer threshold network.
16
+
17
+ Layer 1: NOR (neuron 1) and AND (neuron 2) in parallel
18
+ Layer 2: OR of layer 1 outputs
19
+
20
+ XNOR(x,y) = OR(NOR(x,y), AND(x,y))
21
+ """
22
+
23
+ def __init__(self, weights_dict):
24
+ self.l1_n1_weight = weights_dict['layer1.neuron1.weight']
25
+ self.l1_n1_bias = weights_dict['layer1.neuron1.bias']
26
+ self.l1_n2_weight = weights_dict['layer1.neuron2.weight']
27
+ self.l1_n2_bias = weights_dict['layer1.neuron2.bias']
28
+ self.l2_weight = weights_dict['layer2.weight']
29
+ self.l2_bias = weights_dict['layer2.bias']
30
+
31
+ def __call__(self, x1, x2):
32
+ inputs = torch.tensor([float(x1), float(x2)])
33
+
34
+ nor_out = ((inputs * self.l1_n1_weight).sum() + self.l1_n1_bias >= 0).float()
35
+ and_out = ((inputs * self.l1_n2_weight).sum() + self.l1_n2_bias >= 0).float()
36
+
37
+ layer1_out = torch.tensor([nor_out, and_out])
38
+ output = ((layer1_out * self.l2_weight).sum() + self.l2_bias >= 0).float()
39
+
40
+ return output
41
+
42
+ @classmethod
43
+ def from_safetensors(cls, path="model.safetensors"):
44
+ return cls(load_file(path))
45
+
46
+
47
+ def forward(x1, x2, weights):
48
+ """
49
+ Forward pass with Heaviside activation.
50
+
51
+ Args:
52
+ x1, x2: Input values (0 or 1)
53
+ weights: Dict with layer weights and biases
54
+
55
+ Returns:
56
+ XNOR(x1, x2)
57
+ """
58
+ inputs = torch.tensor([float(x1), float(x2)])
59
+
60
+ nor_out = ((inputs * weights['layer1.neuron1.weight']).sum() + weights['layer1.neuron1.bias'] >= 0).float()
61
+ and_out = ((inputs * weights['layer1.neuron2.weight']).sum() + weights['layer1.neuron2.bias'] >= 0).float()
62
+
63
+ layer1_out = torch.tensor([nor_out, and_out])
64
+ output = ((layer1_out * weights['layer2.weight']).sum() + weights['layer2.bias'] >= 0).float()
65
+
66
+ return output
67
+
68
+
69
+ if __name__ == "__main__":
70
+ weights = load_file("model.safetensors")
71
+ model = ThresholdXNOR(weights)
72
+
73
+ print("XNOR Gate Truth Table:")
74
+ print("-" * 25)
75
+ for x1 in [0, 1]:
76
+ for x2 in [0, 1]:
77
+ out = int(model(x1, x2).item())
78
+ expected = 1 - (x1 ^ x2)
79
+ status = "OK" if out == expected else "FAIL"
80
+ print(f"XNOR({x1}, {x2}) = {out} [{status}]")
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:051878b75a25ed752b6d05dabef132c98842fc47d2d68bd6b9db3614866e4dc1
3
+ size 476