phanerozoic commited on
Commit
e1404bc
·
verified ·
1 Parent(s): de7e62d

Rename from tiny-BiImplies-verified

Browse files
Files changed (4) hide show
  1. README.md +107 -0
  2. config.json +24 -0
  3. model.py +80 -0
  4. model.safetensors +3 -0
README.md ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ tags:
4
+ - pytorch
5
+ - safetensors
6
+ - threshold-logic
7
+ - neuromorphic
8
+ - multi-layer
9
+ ---
10
+
11
+ # threshold-biimplies
12
+
13
+ The biconditional: x ↔ y ("if and only if"). Functionally identical to XNOR, but framed as the logical equivalence relation.
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
+ x ↔ y
39
+ ```
40
+
41
+ ## Mechanism
42
+
43
+ The biconditional tests whether x and y have the same truth value:
44
+
45
+ | x | y | NOR | AND | x ↔ y |
46
+ |---|---|-----|-----|-------|
47
+ | 0 | 0 | 1 | 0 | 1 |
48
+ | 0 | 1 | 0 | 0 | 0 |
49
+ | 1 | 0 | 0 | 0 | 0 |
50
+ | 1 | 1 | 0 | 1 | 1 |
51
+
52
+ NOR catches "both false," AND catches "both true," OR combines.
53
+
54
+ ## Why Two Layers?
55
+
56
+ Unlike simple implication (x → y), the biconditional is not linearly separable. It requires detecting two diagonal cases - same problem as XOR.
57
+
58
+ Implication x → y can be computed with weights [-1, +1] because it fails only at (1,0). Biimplication fails at both (0,1) and (1,0) - these points cannot be separated from (0,0) and (1,1) by a single hyperplane.
59
+
60
+ ## Parameters
61
+
62
+ | Layer | Weights | Bias |
63
+ |-------|---------|------|
64
+ | NOR | [-1, -1] | 0 |
65
+ | AND | [1, 1] | -2 |
66
+ | OR | [1, 1] | -1 |
67
+ | **Total** | | **9** |
68
+
69
+ ## Properties
70
+
71
+ - Reflexive: x ↔ x = 1
72
+ - Symmetric: (x ↔ y) = (y ↔ x)
73
+ - Transitive: (x ↔ y) ∧ (y ↔ z) → (x ↔ z)
74
+
75
+ Full equivalence relation.
76
+
77
+ ## Usage
78
+
79
+ ```python
80
+ from safetensors.torch import load_file
81
+ import torch
82
+
83
+ w = load_file('model.safetensors')
84
+
85
+ def biimplies_gate(x, y):
86
+ inp = torch.tensor([float(x), float(y)])
87
+
88
+ nor_out = int((inp * w['layer1.neuron1.weight']).sum() + w['layer1.neuron1.bias'] >= 0)
89
+ and_out = int((inp * w['layer1.neuron2.weight']).sum() + w['layer1.neuron2.bias'] >= 0)
90
+
91
+ l1 = torch.tensor([float(nor_out), float(and_out)])
92
+ return int((l1 * w['layer2.weight']).sum() + w['layer2.bias'] >= 0)
93
+ ```
94
+
95
+ ## Files
96
+
97
+ ```
98
+ threshold-biimplies/
99
+ ├── model.safetensors
100
+ ├── model.py
101
+ ├── config.json
102
+ └── README.md
103
+ ```
104
+
105
+ ## License
106
+
107
+ MIT
config.json ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model_type": "threshold_network",
3
+ "task": "biconditional_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": ["equivalence_relation"],
23
+ "github": "https://github.com/CharlesCNorton/coq-circuits"
24
+ }
model.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Threshold Network for Biconditional Gate
3
+
4
+ A formally verified two-layer threshold network computing logical equivalence (iff).
5
+ Biconditional 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 ThresholdBiImplies:
14
+ """
15
+ Biconditional 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
+ BiImplies(x,y) = OR(NOR(x,y), AND(x,y)) = (x iff 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
+ BiImplies(x1, x2) = (x1 iff 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 = ThresholdBiImplies(weights)
72
+
73
+ print("Biconditional Gate Truth Table:")
74
+ print("-" * 30)
75
+ for x1 in [0, 1]:
76
+ for x2 in [0, 1]:
77
+ out = int(model(x1, x2).item())
78
+ expected = 1 if x1 == x2 else 0
79
+ status = "OK" if out == expected else "FAIL"
80
+ print(f"BiImplies({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