File size: 4,272 Bytes
2f8703b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
---

license: mit
tags:
- pytorch
- safetensors
- threshold-logic
- neuromorphic
- popcount
- bit-counting
---


# threshold-popcount3

3-bit population count (Hamming weight). Counts the number of 1-bits in a 3-bit input, producing a 2-bit output (0-3).

## Circuit

```

    x0      x1      x2

     β”‚       β”‚       β”‚

     β””β”€β”€β”€β”¬β”€β”€β”€β”΄β”€β”€β”€β”¬β”€β”€β”€β”˜

         β”‚       β”‚

    β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”  β”‚

    β”‚ Layer 1 β”‚  β”‚

    β”‚ atleast1β”‚  β”‚  (sum >= 1)

    β”‚ atleast2β”‚  β”‚  (sum >= 2)

    β”‚ atleast3β”œβ”€β”€β”˜  (sum >= 3)

    β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜

         β”‚

    β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”

    β”‚ Layer 2 β”‚

    β”‚  XOR    β”‚     out1 = atleast1 XOR atleast2

    β”‚  pass   β”‚     out0 = atleast2 XOR atleast3

    β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜

         β”‚

         β–Ό

   [out1, out0]

```

## Function

```

popcount3(x0, x1, x2) -> (out1, out0)



where output = 2*out1 + out0 = number of 1-bits in input

```

## Truth Table

| x0 | x1 | x2 | Count | out1 | out0 |
|:--:|:--:|:--:|:-----:|:----:|:----:|
| 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 1 | 0 | 1 |
| 0 | 1 | 0 | 1 | 0 | 1 |
| 0 | 1 | 1 | 2 | 1 | 0 |
| 1 | 0 | 0 | 1 | 0 | 1 |
| 1 | 0 | 1 | 2 | 1 | 0 |
| 1 | 1 | 0 | 2 | 1 | 0 |
| 1 | 1 | 1 | 3 | 1 | 1 |

## Mechanism

The circuit uses threshold gates to detect "at least k" conditions, then XOR gates to convert to binary:

**Layer 1 - Threshold Detection:**

| Gate | Weights | Bias | Fires when |
|------|---------|------|------------|
| atleast1 | [1,1,1] | -1 | sum >= 1 |
| atleast2 | [1,1,1] | -2 | sum >= 2 |
| atleast3 | [1,1,1] | -3 | sum >= 3 |

**Layer 2 - Binary Encoding:**

The key insight: binary output bits can be computed from threshold outputs:

- **out1** (2's place) = atleast2 XOR atleast3 = (sum >= 2) XOR (sum >= 3)
  - True when sum is exactly 2 or 3
  - Actually: out1 = atleast2 (since atleast3 implies atleast2)
  - Simplified: out1 = atleast2

- **out0** (1's place) = atleast1 XOR atleast2 XOR atleast3
  - True when sum is 1 or 3 (odd from {1,2,3} perspective)
  - Simplified: out0 = parity of threshold outputs

Actually, simpler encoding:
- out1 = atleast2
- out0 = atleast1 XOR atleast2

## Architecture

| Layer | Components | Neurons |
|-------|------------|---------|
| 1 | atleast1, atleast2, atleast3 | 3 |
| 2-3 | XOR for out0 | 3 |

**Total: 6 neurons**

Alternative simpler design:
- out1 = atleast2 (direct wire, 0 extra neurons)
- out0 = atleast1 XOR atleast2 (3 neurons for XOR)

**Using direct threshold for out1:** 4 neurons total

## Parameters

| | |
|---|---|
| Inputs | 3 |
| Outputs | 2 |
| Neurons | 6 |
| Layers | 3 |
| Parameters | 21 |
| Magnitude | 22 |

## Usage

```python

from safetensors.torch import load_file

import torch



w = load_file('model.safetensors')



def popcount3(x0, x1, x2):

    inp = torch.tensor([float(x0), float(x1), float(x2)])



    # Layer 1: Threshold detection

    at1 = int((inp @ w['atleast1.weight'].T + w['atleast1.bias'] >= 0).item())

    at2 = int((inp @ w['atleast2.weight'].T + w['atleast2.bias'] >= 0).item())



    # out1 = atleast2 (sum >= 2 means bit 1 is set)

    out1 = at2



    # out0 = atleast1 XOR atleast2

    l1 = torch.tensor([float(at1), float(at2)])

    or_out = int((l1 @ w['xor.or.weight'].T + w['xor.or.bias'] >= 0).item())

    nand_out = int((l1 @ w['xor.nand.weight'].T + w['xor.nand.bias'] >= 0).item())

    l2 = torch.tensor([float(or_out), float(nand_out)])

    out0 = int((l2 @ w['xor.and.weight'].T + w['xor.and.bias'] >= 0).item())



    return out1, out0



# Examples

print(popcount3(0, 0, 0))  # (0, 0) = 0

print(popcount3(1, 0, 0))  # (0, 1) = 1

print(popcount3(1, 1, 0))  # (1, 0) = 2

print(popcount3(1, 1, 1))  # (1, 1) = 3

```

## Applications

- Hamming distance calculation
- Set cardinality in bit vectors
- Error weight computation
- Branch prediction (counting set bits)
- Cryptographic operations

## Files

```

threshold-popcount3/

β”œβ”€β”€ model.safetensors

β”œβ”€β”€ model.py

β”œβ”€β”€ create_safetensors.py

β”œβ”€β”€ config.json

└── README.md

```

## License

MIT