--- 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