|
|
import torch
|
|
|
from safetensors.torch import load_file
|
|
|
|
|
|
def load_model(path='model.safetensors'):
|
|
|
return load_file(path)
|
|
|
|
|
|
def and_gate(x, y, w, name):
|
|
|
inp = torch.tensor([float(x), float(y)])
|
|
|
return int((inp * w[f'{name}.weight']).sum() + w[f'{name}.bias'] >= 0)
|
|
|
|
|
|
def half_adder_sum(x, y, w, prefix):
|
|
|
inp = torch.tensor([float(x), float(y)])
|
|
|
l1 = (inp @ w[f'{prefix}.xor.layer1.weight'].T + w[f'{prefix}.xor.layer1.bias'] >= 0).float()
|
|
|
return int((l1 @ w[f'{prefix}.xor.layer2.weight'].T + w[f'{prefix}.xor.layer2.bias'] >= 0).item())
|
|
|
|
|
|
def half_adder_carry(x, y, w, prefix):
|
|
|
inp = torch.tensor([float(x), float(y)])
|
|
|
return int((inp * w[f'{prefix}.carry.weight']).sum() + w[f'{prefix}.carry.bias'] >= 0)
|
|
|
|
|
|
def multiply_2x2(a0, a1, b0, b1, weights):
|
|
|
"""2x2 binary multiplier.
|
|
|
Inputs: a = (a1, a0), b = (b1, b0) in MSB-first notation
|
|
|
Returns: (p0, p1, p2, p3) LSB-first, representing a × b
|
|
|
"""
|
|
|
|
|
|
pp_a0b0 = and_gate(a0, b0, weights, 'a0b0')
|
|
|
pp_a1b0 = and_gate(a1, b0, weights, 'a1b0')
|
|
|
pp_a0b1 = and_gate(a0, b1, weights, 'a0b1')
|
|
|
pp_a1b1 = and_gate(a1, b1, weights, 'a1b1')
|
|
|
|
|
|
|
|
|
p0 = pp_a0b0
|
|
|
|
|
|
|
|
|
p1 = half_adder_sum(pp_a1b0, pp_a0b1, weights, 'ha_p1')
|
|
|
c1 = half_adder_carry(pp_a1b0, pp_a0b1, weights, 'ha_p1')
|
|
|
|
|
|
|
|
|
p2 = half_adder_sum(pp_a1b1, c1, weights, 'ha_p2')
|
|
|
p3 = half_adder_carry(pp_a1b1, c1, weights, 'ha_p2')
|
|
|
|
|
|
return p0, p1, p2, p3
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
w = load_model()
|
|
|
print('2x2 Binary Multiplier')
|
|
|
print('a × b tests:')
|
|
|
for a in range(4):
|
|
|
for b in range(4):
|
|
|
a0, a1 = a & 1, (a >> 1) & 1
|
|
|
b0, b1 = b & 1, (b >> 1) & 1
|
|
|
p0, p1, p2, p3 = multiply_2x2(a0, a1, b0, b1, w)
|
|
|
result = p0 + (p1 << 1) + (p2 << 2) + (p3 << 3)
|
|
|
print(f'{a} × {b} = {result}')
|
|
|
|