PortfolioAI commited on
Commit
e6a7a67
·
1 Parent(s): d0106fe

Add build functions for float16 sub/mul/div/toint/fromint

Browse files

Build functions define gate structures for:
- float16.sub: ~34 tensors (sign flip + passthrough)
- float16.mul: ~1532 tensors (11x11 multiplier + exp add)
- float16.div: ~3708 tensors (iterative division)
- float16.toint: ~788 tensors (shift + sign handling)
- float16.fromint: ~956 tensors (CLZ + normalize)

Inference functions still needed to wire gate inputs.

TODO.md CHANGED
@@ -8,13 +8,13 @@
8
  - [x] `float16.cmp` -- comparison a > b (14 gates, 113/113 tests)
9
  - [x] `float16.normalize` -- CLZ-based shift calculator (51 gates, 14/14 tests)
10
  - [x] `float16.add` -- IEEE 754 addition (~998 gates, 125/125 tests)
11
- - [ ] `float16.sub` -- subtraction (add with negated operand)
12
- - [ ] `float16.mul` -- multiplication
13
- - [ ] `float16.div` -- division
 
 
14
  - [x] `float16.neg` -- sign flip (16 gates, 58/58 tests)
15
  - [x] `float16.abs` -- clear sign bit (16 gates, 58/58 tests)
16
- - [ ] `float16.toint` -- convert to integer
17
- - [ ] `float16.fromint` -- convert from integer
18
 
19
  ### Supporting Infrastructure
20
  - [x] `arithmetic.clz8bit` -- 8-bit count leading zeros (30 gates, 256/256 tests)
 
8
  - [x] `float16.cmp` -- comparison a > b (14 gates, 113/113 tests)
9
  - [x] `float16.normalize` -- CLZ-based shift calculator (51 gates, 14/14 tests)
10
  - [x] `float16.add` -- IEEE 754 addition (~998 gates, 125/125 tests)
11
+ - [ ] `float16.sub` -- IEEE 754 subtraction (build: done, inference: pending)
12
+ - [ ] `float16.mul` -- IEEE 754 multiplication (build: done, inference: pending)
13
+ - [ ] `float16.div` -- IEEE 754 division (build: done, inference: pending)
14
+ - [ ] `float16.toint` -- float16 to int16 (build: done, inference: pending)
15
+ - [ ] `float16.fromint` -- int16 to float16 (build: done, inference: pending)
16
  - [x] `float16.neg` -- sign flip (16 gates, 58/58 tests)
17
  - [x] `float16.abs` -- clear sign bit (16 gates, 58/58 tests)
 
 
18
 
19
  ### Supporting Infrastructure
20
  - [x] `arithmetic.clz8bit` -- 8-bit count leading zeros (30 gates, 256/256 tests)
__pycache__/eval.cpython-311.pyc CHANGED
Binary files a/__pycache__/eval.cpython-311.pyc and b/__pycache__/eval.cpython-311.pyc differ
 
arithmetic.safetensors CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:8993efede9bef7f30e95fcb26d4402fe9e44b7068343188b43b2013c02ff5753
3
- size 1504724
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2a352227117a245ace401841a7ed6be4533c991d87b1d24bcd56476c3c857b3f
3
+ size 2259880
convert_to_explicit_inputs.py CHANGED
@@ -3830,6 +3830,916 @@ def build_float16_add_tensors() -> Dict[str, torch.Tensor]:
3830
  return tensors
3831
 
3832
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3833
  def build_clz8bit_tensors() -> Dict[str, torch.Tensor]:
3834
  """Build tensors for arithmetic.clz8bit circuit.
3835
 
@@ -3943,6 +4853,26 @@ def main():
3943
  tensors.update(add_tensors)
3944
  print(f" float16.add: {len(add_tensors)} tensors")
3945
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3946
  print(f"Total tensors: {len(tensors)}")
3947
 
3948
  # Load routing for complex circuits
 
3830
  return tensors
3831
 
3832
 
3833
+ def build_float16_sub_tensors() -> Dict[str, torch.Tensor]:
3834
+ """Build tensors for float16.sub circuit.
3835
+
3836
+ Subtraction: a - b = a + (-b)
3837
+ Just flip the sign bit of b and use the add circuit.
3838
+ """
3839
+ tensors = {}
3840
+ prefix = "float16.sub"
3841
+
3842
+ # Flip sign bit of b: b_neg_sign = NOT b[15]
3843
+ tensors[f"{prefix}.b_neg_sign.weight"] = torch.tensor([-1.0])
3844
+ tensors[f"{prefix}.b_neg_sign.bias"] = torch.tensor([0.0])
3845
+
3846
+ # Output bits: passthrough from float16.add with modified b
3847
+ for i in range(16):
3848
+ tensors[f"{prefix}.out{i}.weight"] = torch.tensor([1.0])
3849
+ tensors[f"{prefix}.out{i}.bias"] = torch.tensor([-0.5])
3850
+
3851
+ return tensors
3852
+
3853
+
3854
+ def build_float16_mul_tensors() -> Dict[str, torch.Tensor]:
3855
+ """Build tensors for float16.mul circuit.
3856
+
3857
+ IEEE 754 float16 multiplication:
3858
+ - Result sign = a_sign XOR b_sign
3859
+ - Result exponent = a_exp + b_exp - bias (15)
3860
+ - Result mantissa = a_mant * b_mant (22-bit product, normalize to 11)
3861
+
3862
+ Special cases:
3863
+ - NaN * anything = NaN
3864
+ - Inf * 0 = NaN
3865
+ - Inf * finite = Inf
3866
+ - 0 * finite = 0
3867
+ """
3868
+ tensors = {}
3869
+ prefix = "float16.mul"
3870
+
3871
+ # =========================================================================
3872
+ # STAGE 1: UNPACK AND DETECT SPECIAL CASES
3873
+ # =========================================================================
3874
+
3875
+ # exp_a_all_ones: exponent = 31 (inf or nan)
3876
+ tensors[f"{prefix}.exp_a_all_ones.weight"] = torch.tensor([1.0] * 5)
3877
+ tensors[f"{prefix}.exp_a_all_ones.bias"] = torch.tensor([-5.0])
3878
+
3879
+ tensors[f"{prefix}.exp_b_all_ones.weight"] = torch.tensor([1.0] * 5)
3880
+ tensors[f"{prefix}.exp_b_all_ones.bias"] = torch.tensor([-5.0])
3881
+
3882
+ # exp_a_zero: exponent = 0 (zero or subnormal)
3883
+ tensors[f"{prefix}.exp_a_zero.weight"] = torch.tensor([-1.0] * 5)
3884
+ tensors[f"{prefix}.exp_a_zero.bias"] = torch.tensor([0.0])
3885
+
3886
+ tensors[f"{prefix}.exp_b_zero.weight"] = torch.tensor([-1.0] * 5)
3887
+ tensors[f"{prefix}.exp_b_zero.bias"] = torch.tensor([0.0])
3888
+
3889
+ # mant_a_nonzero / mant_b_nonzero
3890
+ tensors[f"{prefix}.mant_a_nonzero.weight"] = torch.tensor([1.0] * 10)
3891
+ tensors[f"{prefix}.mant_a_nonzero.bias"] = torch.tensor([-1.0])
3892
+
3893
+ tensors[f"{prefix}.mant_b_nonzero.weight"] = torch.tensor([1.0] * 10)
3894
+ tensors[f"{prefix}.mant_b_nonzero.bias"] = torch.tensor([-1.0])
3895
+
3896
+ # mant_a_zero = NOT mant_a_nonzero
3897
+ tensors[f"{prefix}.mant_a_zero.weight"] = torch.tensor([-1.0])
3898
+ tensors[f"{prefix}.mant_a_zero.bias"] = torch.tensor([0.0])
3899
+
3900
+ tensors[f"{prefix}.mant_b_zero.weight"] = torch.tensor([-1.0])
3901
+ tensors[f"{prefix}.mant_b_zero.bias"] = torch.tensor([0.0])
3902
+
3903
+ # a_is_nan = exp_all_ones AND mant_nonzero
3904
+ tensors[f"{prefix}.a_is_nan.weight"] = torch.tensor([1.0, 1.0])
3905
+ tensors[f"{prefix}.a_is_nan.bias"] = torch.tensor([-2.0])
3906
+
3907
+ tensors[f"{prefix}.b_is_nan.weight"] = torch.tensor([1.0, 1.0])
3908
+ tensors[f"{prefix}.b_is_nan.bias"] = torch.tensor([-2.0])
3909
+
3910
+ # a_is_inf = exp_all_ones AND mant_zero
3911
+ tensors[f"{prefix}.a_is_inf.weight"] = torch.tensor([1.0, 1.0])
3912
+ tensors[f"{prefix}.a_is_inf.bias"] = torch.tensor([-2.0])
3913
+
3914
+ tensors[f"{prefix}.b_is_inf.weight"] = torch.tensor([1.0, 1.0])
3915
+ tensors[f"{prefix}.b_is_inf.bias"] = torch.tensor([-2.0])
3916
+
3917
+ # a_is_zero = exp_zero AND mant_zero
3918
+ tensors[f"{prefix}.a_is_zero.weight"] = torch.tensor([1.0, 1.0])
3919
+ tensors[f"{prefix}.a_is_zero.bias"] = torch.tensor([-2.0])
3920
+
3921
+ tensors[f"{prefix}.b_is_zero.weight"] = torch.tensor([1.0, 1.0])
3922
+ tensors[f"{prefix}.b_is_zero.bias"] = torch.tensor([-2.0])
3923
+
3924
+ # either_is_nan = a_is_nan OR b_is_nan
3925
+ tensors[f"{prefix}.either_is_nan.weight"] = torch.tensor([1.0, 1.0])
3926
+ tensors[f"{prefix}.either_is_nan.bias"] = torch.tensor([-1.0])
3927
+
3928
+ # either_is_inf = a_is_inf OR b_is_inf
3929
+ tensors[f"{prefix}.either_is_inf.weight"] = torch.tensor([1.0, 1.0])
3930
+ tensors[f"{prefix}.either_is_inf.bias"] = torch.tensor([-1.0])
3931
+
3932
+ # either_is_zero = a_is_zero OR b_is_zero
3933
+ tensors[f"{prefix}.either_is_zero.weight"] = torch.tensor([1.0, 1.0])
3934
+ tensors[f"{prefix}.either_is_zero.bias"] = torch.tensor([-1.0])
3935
+
3936
+ # inf_times_zero = either_is_inf AND either_is_zero (produces NaN)
3937
+ tensors[f"{prefix}.inf_times_zero.weight"] = torch.tensor([1.0, 1.0])
3938
+ tensors[f"{prefix}.inf_times_zero.bias"] = torch.tensor([-2.0])
3939
+
3940
+ # result_is_nan = either_is_nan OR inf_times_zero
3941
+ tensors[f"{prefix}.result_is_nan.weight"] = torch.tensor([1.0, 1.0])
3942
+ tensors[f"{prefix}.result_is_nan.bias"] = torch.tensor([-1.0])
3943
+
3944
+ # result_is_inf = either_is_inf AND NOT(result_is_nan) AND NOT(either_is_zero)
3945
+ tensors[f"{prefix}.not_result_is_nan.weight"] = torch.tensor([-1.0])
3946
+ tensors[f"{prefix}.not_result_is_nan.bias"] = torch.tensor([0.0])
3947
+
3948
+ tensors[f"{prefix}.not_either_is_zero.weight"] = torch.tensor([-1.0])
3949
+ tensors[f"{prefix}.not_either_is_zero.bias"] = torch.tensor([0.0])
3950
+
3951
+ tensors[f"{prefix}.result_is_inf.weight"] = torch.tensor([1.0, 1.0, 1.0])
3952
+ tensors[f"{prefix}.result_is_inf.bias"] = torch.tensor([-3.0])
3953
+
3954
+ # result_is_zero = either_is_zero AND NOT(result_is_nan)
3955
+ tensors[f"{prefix}.result_is_zero.weight"] = torch.tensor([1.0, 1.0])
3956
+ tensors[f"{prefix}.result_is_zero.bias"] = torch.tensor([-2.0])
3957
+
3958
+ # =========================================================================
3959
+ # STAGE 2: RESULT SIGN (XOR of input signs)
3960
+ # =========================================================================
3961
+
3962
+ tensors[f"{prefix}.result_sign.layer1.or.weight"] = torch.tensor([1.0, 1.0])
3963
+ tensors[f"{prefix}.result_sign.layer1.or.bias"] = torch.tensor([-1.0])
3964
+ tensors[f"{prefix}.result_sign.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
3965
+ tensors[f"{prefix}.result_sign.layer1.nand.bias"] = torch.tensor([1.0])
3966
+ tensors[f"{prefix}.result_sign.layer2.weight"] = torch.tensor([1.0, 1.0])
3967
+ tensors[f"{prefix}.result_sign.layer2.bias"] = torch.tensor([-2.0])
3968
+
3969
+ # =========================================================================
3970
+ # STAGE 3: MANTISSA MULTIPLICATION (11x11 -> 22 bits)
3971
+ # =========================================================================
3972
+
3973
+ # Implicit bits for mantissas
3974
+ tensors[f"{prefix}.implicit_a.weight"] = torch.tensor([-1.0])
3975
+ tensors[f"{prefix}.implicit_a.bias"] = torch.tensor([0.0])
3976
+
3977
+ tensors[f"{prefix}.implicit_b.weight"] = torch.tensor([-1.0])
3978
+ tensors[f"{prefix}.implicit_b.bias"] = torch.tensor([0.0])
3979
+
3980
+ # Full mantissas: mant_a[10:0] = {implicit_a, a[9:0]}
3981
+ # mant_b[10:0] = {implicit_b, b[9:0]}
3982
+
3983
+ # 11x11 array multiplier produces 22-bit product
3984
+ # Partial products: pp[i][j] = mant_a[i] AND mant_b[j]
3985
+ for i in range(11):
3986
+ for j in range(11):
3987
+ tensors[f"{prefix}.pp{i}_{j}.weight"] = torch.tensor([1.0, 1.0])
3988
+ tensors[f"{prefix}.pp{i}_{j}.bias"] = torch.tensor([-2.0])
3989
+
3990
+ # Reduction tree using carry-save adders
3991
+ # Level 0: 11 partial product rows
3992
+ # We'll use a Wallace tree reduction
3993
+
3994
+ # For simplicity, use a ripple reduction approach
3995
+ # Row i contributes to columns i through i+10
3996
+ # Sum columns using full adder chains
3997
+
3998
+ # Column sums using compressor tree
3999
+ for col in range(22):
4000
+ # Count how many partial products contribute to this column
4001
+ count = 0
4002
+ for i in range(11):
4003
+ j = col - i
4004
+ if 0 <= j < 11:
4005
+ count += 1
4006
+
4007
+ if count == 0:
4008
+ continue
4009
+ elif count == 1:
4010
+ # Single bit, just pass through
4011
+ tensors[f"{prefix}.col{col}.weight"] = torch.tensor([1.0])
4012
+ tensors[f"{prefix}.col{col}.bias"] = torch.tensor([-0.5])
4013
+ else:
4014
+ # Multi-bit column: use threshold gate to count
4015
+ # For proper addition we need full adder trees
4016
+ # Simplified: use weighted sum approach
4017
+ tensors[f"{prefix}.col{col}_sum.weight"] = torch.tensor([1.0] * count)
4018
+ tensors[f"{prefix}.col{col}_sum.bias"] = torch.tensor([-0.5])
4019
+
4020
+ # Carry generation for each threshold level
4021
+ for t in range(1, count):
4022
+ tensors[f"{prefix}.col{col}_ge{t}.weight"] = torch.tensor([1.0] * count)
4023
+ tensors[f"{prefix}.col{col}_ge{t}.bias"] = torch.tensor([-float(t)])
4024
+
4025
+ # Final product assembly using ripple carry
4026
+ for i in range(22):
4027
+ p = f"{prefix}.prod_fa{i}"
4028
+ tensors[f"{p}.xor1.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4029
+ tensors[f"{p}.xor1.layer1.or.bias"] = torch.tensor([-1.0])
4030
+ tensors[f"{p}.xor1.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4031
+ tensors[f"{p}.xor1.layer1.nand.bias"] = torch.tensor([1.0])
4032
+ tensors[f"{p}.xor1.layer2.weight"] = torch.tensor([1.0, 1.0])
4033
+ tensors[f"{p}.xor1.layer2.bias"] = torch.tensor([-2.0])
4034
+
4035
+ tensors[f"{p}.xor2.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4036
+ tensors[f"{p}.xor2.layer1.or.bias"] = torch.tensor([-1.0])
4037
+ tensors[f"{p}.xor2.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4038
+ tensors[f"{p}.xor2.layer1.nand.bias"] = torch.tensor([1.0])
4039
+ tensors[f"{p}.xor2.layer2.weight"] = torch.tensor([1.0, 1.0])
4040
+ tensors[f"{p}.xor2.layer2.bias"] = torch.tensor([-2.0])
4041
+
4042
+ tensors[f"{p}.and1.weight"] = torch.tensor([1.0, 1.0])
4043
+ tensors[f"{p}.and1.bias"] = torch.tensor([-2.0])
4044
+ tensors[f"{p}.and2.weight"] = torch.tensor([1.0, 1.0])
4045
+ tensors[f"{p}.and2.bias"] = torch.tensor([-2.0])
4046
+ tensors[f"{p}.cout.weight"] = torch.tensor([1.0, 1.0])
4047
+ tensors[f"{p}.cout.bias"] = torch.tensor([-1.0])
4048
+
4049
+ # =========================================================================
4050
+ # STAGE 4: EXPONENT ADDITION
4051
+ # =========================================================================
4052
+
4053
+ # Result exponent = exp_a + exp_b - 15 (bias adjustment)
4054
+ # First add exp_a + exp_b using 6-bit adder (max 31+31=62, need 6 bits)
4055
+ for i in range(6):
4056
+ p = f"{prefix}.exp_add.fa{i}"
4057
+ tensors[f"{p}.xor1.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4058
+ tensors[f"{p}.xor1.layer1.or.bias"] = torch.tensor([-1.0])
4059
+ tensors[f"{p}.xor1.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4060
+ tensors[f"{p}.xor1.layer1.nand.bias"] = torch.tensor([1.0])
4061
+ tensors[f"{p}.xor1.layer2.weight"] = torch.tensor([1.0, 1.0])
4062
+ tensors[f"{p}.xor1.layer2.bias"] = torch.tensor([-2.0])
4063
+
4064
+ tensors[f"{p}.xor2.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4065
+ tensors[f"{p}.xor2.layer1.or.bias"] = torch.tensor([-1.0])
4066
+ tensors[f"{p}.xor2.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4067
+ tensors[f"{p}.xor2.layer1.nand.bias"] = torch.tensor([1.0])
4068
+ tensors[f"{p}.xor2.layer2.weight"] = torch.tensor([1.0, 1.0])
4069
+ tensors[f"{p}.xor2.layer2.bias"] = torch.tensor([-2.0])
4070
+
4071
+ tensors[f"{p}.and1.weight"] = torch.tensor([1.0, 1.0])
4072
+ tensors[f"{p}.and1.bias"] = torch.tensor([-2.0])
4073
+ tensors[f"{p}.and2.weight"] = torch.tensor([1.0, 1.0])
4074
+ tensors[f"{p}.and2.bias"] = torch.tensor([-2.0])
4075
+ tensors[f"{p}.cout.weight"] = torch.tensor([1.0, 1.0])
4076
+ tensors[f"{p}.cout.bias"] = torch.tensor([-1.0])
4077
+
4078
+ # Subtract 15: exp_sum - 15 using subtractor
4079
+ # NOT of 15 = NOT(01111) = 10000
4080
+ for i in range(6):
4081
+ p = f"{prefix}.exp_sub.fa{i}"
4082
+ tensors[f"{p}.xor1.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4083
+ tensors[f"{p}.xor1.layer1.or.bias"] = torch.tensor([-1.0])
4084
+ tensors[f"{p}.xor1.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4085
+ tensors[f"{p}.xor1.layer1.nand.bias"] = torch.tensor([1.0])
4086
+ tensors[f"{p}.xor1.layer2.weight"] = torch.tensor([1.0, 1.0])
4087
+ tensors[f"{p}.xor1.layer2.bias"] = torch.tensor([-2.0])
4088
+
4089
+ tensors[f"{p}.xor2.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4090
+ tensors[f"{p}.xor2.layer1.or.bias"] = torch.tensor([-1.0])
4091
+ tensors[f"{p}.xor2.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4092
+ tensors[f"{p}.xor2.layer1.nand.bias"] = torch.tensor([1.0])
4093
+ tensors[f"{p}.xor2.layer2.weight"] = torch.tensor([1.0, 1.0])
4094
+ tensors[f"{p}.xor2.layer2.bias"] = torch.tensor([-2.0])
4095
+
4096
+ tensors[f"{p}.and1.weight"] = torch.tensor([1.0, 1.0])
4097
+ tensors[f"{p}.and1.bias"] = torch.tensor([-2.0])
4098
+ tensors[f"{p}.and2.weight"] = torch.tensor([1.0, 1.0])
4099
+ tensors[f"{p}.and2.bias"] = torch.tensor([-2.0])
4100
+ tensors[f"{p}.cout.weight"] = torch.tensor([1.0, 1.0])
4101
+ tensors[f"{p}.cout.bias"] = torch.tensor([-1.0])
4102
+
4103
+ # =========================================================================
4104
+ # STAGE 5: NORMALIZE PRODUCT
4105
+ # =========================================================================
4106
+
4107
+ # Product is in range [1.0, 4.0) since each mantissa is [1.0, 2.0)
4108
+ # If product >= 2.0, right shift by 1 and increment exponent
4109
+ # Check if bit 21 is set (product >= 2.0)
4110
+ tensors[f"{prefix}.prod_overflow.weight"] = torch.tensor([1.0])
4111
+ tensors[f"{prefix}.prod_overflow.bias"] = torch.tensor([-0.5])
4112
+
4113
+ tensors[f"{prefix}.not_prod_overflow.weight"] = torch.tensor([-1.0])
4114
+ tensors[f"{prefix}.not_prod_overflow.bias"] = torch.tensor([0.0])
4115
+
4116
+ # Normalized mantissa selection (10 bits)
4117
+ # If overflow: take bits 20:11, else take bits 19:10
4118
+ for i in range(10):
4119
+ tensors[f"{prefix}.norm_mant{i}.overflow_path.weight"] = torch.tensor([1.0, 1.0])
4120
+ tensors[f"{prefix}.norm_mant{i}.overflow_path.bias"] = torch.tensor([-2.0])
4121
+ tensors[f"{prefix}.norm_mant{i}.normal_path.weight"] = torch.tensor([1.0, 1.0])
4122
+ tensors[f"{prefix}.norm_mant{i}.normal_path.bias"] = torch.tensor([-2.0])
4123
+ tensors[f"{prefix}.norm_mant{i}.weight"] = torch.tensor([1.0, 1.0])
4124
+ tensors[f"{prefix}.norm_mant{i}.bias"] = torch.tensor([-1.0])
4125
+
4126
+ # Exponent adjustment: if overflow, add 1
4127
+ for i in range(5):
4128
+ p = f"{prefix}.result_exp_fa{i}"
4129
+ tensors[f"{p}.xor1.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4130
+ tensors[f"{p}.xor1.layer1.or.bias"] = torch.tensor([-1.0])
4131
+ tensors[f"{p}.xor1.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4132
+ tensors[f"{p}.xor1.layer1.nand.bias"] = torch.tensor([1.0])
4133
+ tensors[f"{p}.xor1.layer2.weight"] = torch.tensor([1.0, 1.0])
4134
+ tensors[f"{p}.xor1.layer2.bias"] = torch.tensor([-2.0])
4135
+
4136
+ tensors[f"{p}.xor2.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4137
+ tensors[f"{p}.xor2.layer1.or.bias"] = torch.tensor([-1.0])
4138
+ tensors[f"{p}.xor2.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4139
+ tensors[f"{p}.xor2.layer1.nand.bias"] = torch.tensor([1.0])
4140
+ tensors[f"{p}.xor2.layer2.weight"] = torch.tensor([1.0, 1.0])
4141
+ tensors[f"{p}.xor2.layer2.bias"] = torch.tensor([-2.0])
4142
+
4143
+ tensors[f"{p}.and1.weight"] = torch.tensor([1.0, 1.0])
4144
+ tensors[f"{p}.and1.bias"] = torch.tensor([-2.0])
4145
+ tensors[f"{p}.and2.weight"] = torch.tensor([1.0, 1.0])
4146
+ tensors[f"{p}.and2.bias"] = torch.tensor([-2.0])
4147
+ tensors[f"{p}.cout.weight"] = torch.tensor([1.0, 1.0])
4148
+ tensors[f"{p}.cout.bias"] = torch.tensor([-1.0])
4149
+
4150
+ # Overflow/underflow detection
4151
+ tensors[f"{prefix}.exp_overflow.weight"] = torch.tensor([1.0])
4152
+ tensors[f"{prefix}.exp_overflow.bias"] = torch.tensor([-0.5])
4153
+
4154
+ tensors[f"{prefix}.exp_underflow.weight"] = torch.tensor([1.0])
4155
+ tensors[f"{prefix}.exp_underflow.bias"] = torch.tensor([-0.5])
4156
+
4157
+ # =========================================================================
4158
+ # STAGE 6: OUTPUT ASSEMBLY
4159
+ # =========================================================================
4160
+
4161
+ tensors[f"{prefix}.is_normal_result.weight"] = torch.tensor([-1.0, -1.0, -1.0])
4162
+ tensors[f"{prefix}.is_normal_result.bias"] = torch.tensor([0.0])
4163
+
4164
+ for i in range(16):
4165
+ if i < 10:
4166
+ tensors[f"{prefix}.out_nan{i}.weight"] = torch.tensor([1.0])
4167
+ tensors[f"{prefix}.out_nan{i}.bias"] = torch.tensor([-0.5])
4168
+ elif i < 15:
4169
+ tensors[f"{prefix}.out_nan{i}.weight"] = torch.tensor([1.0])
4170
+ tensors[f"{prefix}.out_nan{i}.bias"] = torch.tensor([-0.5])
4171
+
4172
+ if i < 10:
4173
+ tensors[f"{prefix}.out_normal{i}.weight"] = torch.tensor([1.0])
4174
+ tensors[f"{prefix}.out_normal{i}.bias"] = torch.tensor([-0.5])
4175
+ elif i < 15:
4176
+ tensors[f"{prefix}.out_normal{i}.weight"] = torch.tensor([1.0])
4177
+ tensors[f"{prefix}.out_normal{i}.bias"] = torch.tensor([-0.5])
4178
+
4179
+ tensors[f"{prefix}.out{i}.nan_gate.weight"] = torch.tensor([1.0, 1.0])
4180
+ tensors[f"{prefix}.out{i}.nan_gate.bias"] = torch.tensor([-2.0])
4181
+ tensors[f"{prefix}.out{i}.inf_gate.weight"] = torch.tensor([1.0, 1.0])
4182
+ tensors[f"{prefix}.out{i}.inf_gate.bias"] = torch.tensor([-2.0])
4183
+ tensors[f"{prefix}.out{i}.zero_gate.weight"] = torch.tensor([1.0, 1.0])
4184
+ tensors[f"{prefix}.out{i}.zero_gate.bias"] = torch.tensor([-2.0])
4185
+ tensors[f"{prefix}.out{i}.normal_gate.weight"] = torch.tensor([1.0, 1.0])
4186
+ tensors[f"{prefix}.out{i}.normal_gate.bias"] = torch.tensor([-2.0])
4187
+
4188
+ tensors[f"{prefix}.out{i}.weight"] = torch.tensor([1.0, 1.0, 1.0, 1.0])
4189
+ tensors[f"{prefix}.out{i}.bias"] = torch.tensor([-1.0])
4190
+
4191
+ return tensors
4192
+
4193
+
4194
+ def build_float16_div_tensors() -> Dict[str, torch.Tensor]:
4195
+ """Build tensors for float16.div circuit.
4196
+
4197
+ IEEE 754 float16 division:
4198
+ - Result sign = a_sign XOR b_sign
4199
+ - Result exponent = a_exp - b_exp + bias (15)
4200
+ - Result mantissa = a_mant / b_mant (using non-restoring division)
4201
+
4202
+ Special cases:
4203
+ - NaN / anything = NaN
4204
+ - anything / NaN = NaN
4205
+ - Inf / Inf = NaN
4206
+ - 0 / 0 = NaN
4207
+ - Inf / finite = Inf
4208
+ - finite / Inf = 0
4209
+ - finite / 0 = Inf
4210
+ - 0 / finite = 0
4211
+ """
4212
+ tensors = {}
4213
+ prefix = "float16.div"
4214
+
4215
+ # Similar structure to mul but with subtraction for exponents
4216
+ # and iterative division for mantissas
4217
+
4218
+ # Special case detection (same as mul)
4219
+ tensors[f"{prefix}.exp_a_all_ones.weight"] = torch.tensor([1.0] * 5)
4220
+ tensors[f"{prefix}.exp_a_all_ones.bias"] = torch.tensor([-5.0])
4221
+
4222
+ tensors[f"{prefix}.exp_b_all_ones.weight"] = torch.tensor([1.0] * 5)
4223
+ tensors[f"{prefix}.exp_b_all_ones.bias"] = torch.tensor([-5.0])
4224
+
4225
+ tensors[f"{prefix}.exp_a_zero.weight"] = torch.tensor([-1.0] * 5)
4226
+ tensors[f"{prefix}.exp_a_zero.bias"] = torch.tensor([0.0])
4227
+
4228
+ tensors[f"{prefix}.exp_b_zero.weight"] = torch.tensor([-1.0] * 5)
4229
+ tensors[f"{prefix}.exp_b_zero.bias"] = torch.tensor([0.0])
4230
+
4231
+ tensors[f"{prefix}.mant_a_nonzero.weight"] = torch.tensor([1.0] * 10)
4232
+ tensors[f"{prefix}.mant_a_nonzero.bias"] = torch.tensor([-1.0])
4233
+
4234
+ tensors[f"{prefix}.mant_b_nonzero.weight"] = torch.tensor([1.0] * 10)
4235
+ tensors[f"{prefix}.mant_b_nonzero.bias"] = torch.tensor([-1.0])
4236
+
4237
+ tensors[f"{prefix}.mant_a_zero.weight"] = torch.tensor([-1.0])
4238
+ tensors[f"{prefix}.mant_a_zero.bias"] = torch.tensor([0.0])
4239
+
4240
+ tensors[f"{prefix}.mant_b_zero.weight"] = torch.tensor([-1.0])
4241
+ tensors[f"{prefix}.mant_b_zero.bias"] = torch.tensor([0.0])
4242
+
4243
+ tensors[f"{prefix}.a_is_nan.weight"] = torch.tensor([1.0, 1.0])
4244
+ tensors[f"{prefix}.a_is_nan.bias"] = torch.tensor([-2.0])
4245
+
4246
+ tensors[f"{prefix}.b_is_nan.weight"] = torch.tensor([1.0, 1.0])
4247
+ tensors[f"{prefix}.b_is_nan.bias"] = torch.tensor([-2.0])
4248
+
4249
+ tensors[f"{prefix}.a_is_inf.weight"] = torch.tensor([1.0, 1.0])
4250
+ tensors[f"{prefix}.a_is_inf.bias"] = torch.tensor([-2.0])
4251
+
4252
+ tensors[f"{prefix}.b_is_inf.weight"] = torch.tensor([1.0, 1.0])
4253
+ tensors[f"{prefix}.b_is_inf.bias"] = torch.tensor([-2.0])
4254
+
4255
+ tensors[f"{prefix}.a_is_zero.weight"] = torch.tensor([1.0, 1.0])
4256
+ tensors[f"{prefix}.a_is_zero.bias"] = torch.tensor([-2.0])
4257
+
4258
+ tensors[f"{prefix}.b_is_zero.weight"] = torch.tensor([1.0, 1.0])
4259
+ tensors[f"{prefix}.b_is_zero.bias"] = torch.tensor([-2.0])
4260
+
4261
+ tensors[f"{prefix}.either_is_nan.weight"] = torch.tensor([1.0, 1.0])
4262
+ tensors[f"{prefix}.either_is_nan.bias"] = torch.tensor([-1.0])
4263
+
4264
+ # inf/inf = NaN, 0/0 = NaN
4265
+ tensors[f"{prefix}.both_inf.weight"] = torch.tensor([1.0, 1.0])
4266
+ tensors[f"{prefix}.both_inf.bias"] = torch.tensor([-2.0])
4267
+
4268
+ tensors[f"{prefix}.both_zero.weight"] = torch.tensor([1.0, 1.0])
4269
+ tensors[f"{prefix}.both_zero.bias"] = torch.tensor([-2.0])
4270
+
4271
+ tensors[f"{prefix}.result_is_nan.weight"] = torch.tensor([1.0, 1.0, 1.0])
4272
+ tensors[f"{prefix}.result_is_nan.bias"] = torch.tensor([-1.0])
4273
+
4274
+ # finite/0 = inf, inf/finite = inf
4275
+ tensors[f"{prefix}.not_a_is_zero.weight"] = torch.tensor([-1.0])
4276
+ tensors[f"{prefix}.not_a_is_zero.bias"] = torch.tensor([0.0])
4277
+
4278
+ tensors[f"{prefix}.finite_div_zero.weight"] = torch.tensor([1.0, 1.0])
4279
+ tensors[f"{prefix}.finite_div_zero.bias"] = torch.tensor([-2.0])
4280
+
4281
+ tensors[f"{prefix}.not_b_is_inf.weight"] = torch.tensor([-1.0])
4282
+ tensors[f"{prefix}.not_b_is_inf.bias"] = torch.tensor([0.0])
4283
+
4284
+ tensors[f"{prefix}.inf_div_finite.weight"] = torch.tensor([1.0, 1.0])
4285
+ tensors[f"{prefix}.inf_div_finite.bias"] = torch.tensor([-2.0])
4286
+
4287
+ tensors[f"{prefix}.not_result_is_nan.weight"] = torch.tensor([-1.0])
4288
+ tensors[f"{prefix}.not_result_is_nan.bias"] = torch.tensor([0.0])
4289
+
4290
+ tensors[f"{prefix}.result_is_inf.weight"] = torch.tensor([1.0, 1.0, 1.0])
4291
+ tensors[f"{prefix}.result_is_inf.bias"] = torch.tensor([-1.0])
4292
+
4293
+ # 0/finite = 0, finite/inf = 0
4294
+ tensors[f"{prefix}.not_b_is_zero.weight"] = torch.tensor([-1.0])
4295
+ tensors[f"{prefix}.not_b_is_zero.bias"] = torch.tensor([0.0])
4296
+
4297
+ tensors[f"{prefix}.zero_div_finite.weight"] = torch.tensor([1.0, 1.0])
4298
+ tensors[f"{prefix}.zero_div_finite.bias"] = torch.tensor([-2.0])
4299
+
4300
+ tensors[f"{prefix}.not_a_is_inf.weight"] = torch.tensor([-1.0])
4301
+ tensors[f"{prefix}.not_a_is_inf.bias"] = torch.tensor([0.0])
4302
+
4303
+ tensors[f"{prefix}.finite_div_inf.weight"] = torch.tensor([1.0, 1.0])
4304
+ tensors[f"{prefix}.finite_div_inf.bias"] = torch.tensor([-2.0])
4305
+
4306
+ tensors[f"{prefix}.result_is_zero.weight"] = torch.tensor([1.0, 1.0, 1.0])
4307
+ tensors[f"{prefix}.result_is_zero.bias"] = torch.tensor([-1.0])
4308
+
4309
+ # Result sign (XOR)
4310
+ tensors[f"{prefix}.result_sign.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4311
+ tensors[f"{prefix}.result_sign.layer1.or.bias"] = torch.tensor([-1.0])
4312
+ tensors[f"{prefix}.result_sign.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4313
+ tensors[f"{prefix}.result_sign.layer1.nand.bias"] = torch.tensor([1.0])
4314
+ tensors[f"{prefix}.result_sign.layer2.weight"] = torch.tensor([1.0, 1.0])
4315
+ tensors[f"{prefix}.result_sign.layer2.bias"] = torch.tensor([-2.0])
4316
+
4317
+ # Exponent subtraction: exp_a - exp_b + 15
4318
+ # NOT gates for exp_b
4319
+ for i in range(5):
4320
+ tensors[f"{prefix}.not_exp_b{i}.weight"] = torch.tensor([-1.0])
4321
+ tensors[f"{prefix}.not_exp_b{i}.bias"] = torch.tensor([0.0])
4322
+
4323
+ # 6-bit subtractor for exp_a - exp_b
4324
+ for i in range(6):
4325
+ p = f"{prefix}.exp_sub.fa{i}"
4326
+ tensors[f"{p}.xor1.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4327
+ tensors[f"{p}.xor1.layer1.or.bias"] = torch.tensor([-1.0])
4328
+ tensors[f"{p}.xor1.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4329
+ tensors[f"{p}.xor1.layer1.nand.bias"] = torch.tensor([1.0])
4330
+ tensors[f"{p}.xor1.layer2.weight"] = torch.tensor([1.0, 1.0])
4331
+ tensors[f"{p}.xor1.layer2.bias"] = torch.tensor([-2.0])
4332
+
4333
+ tensors[f"{p}.xor2.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4334
+ tensors[f"{p}.xor2.layer1.or.bias"] = torch.tensor([-1.0])
4335
+ tensors[f"{p}.xor2.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4336
+ tensors[f"{p}.xor2.layer1.nand.bias"] = torch.tensor([1.0])
4337
+ tensors[f"{p}.xor2.layer2.weight"] = torch.tensor([1.0, 1.0])
4338
+ tensors[f"{p}.xor2.layer2.bias"] = torch.tensor([-2.0])
4339
+
4340
+ tensors[f"{p}.and1.weight"] = torch.tensor([1.0, 1.0])
4341
+ tensors[f"{p}.and1.bias"] = torch.tensor([-2.0])
4342
+ tensors[f"{p}.and2.weight"] = torch.tensor([1.0, 1.0])
4343
+ tensors[f"{p}.and2.bias"] = torch.tensor([-2.0])
4344
+ tensors[f"{p}.cout.weight"] = torch.tensor([1.0, 1.0])
4345
+ tensors[f"{p}.cout.bias"] = torch.tensor([-1.0])
4346
+
4347
+ # Add 15 to get biased result
4348
+ for i in range(6):
4349
+ p = f"{prefix}.exp_add15.fa{i}"
4350
+ tensors[f"{p}.xor1.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4351
+ tensors[f"{p}.xor1.layer1.or.bias"] = torch.tensor([-1.0])
4352
+ tensors[f"{p}.xor1.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4353
+ tensors[f"{p}.xor1.layer1.nand.bias"] = torch.tensor([1.0])
4354
+ tensors[f"{p}.xor1.layer2.weight"] = torch.tensor([1.0, 1.0])
4355
+ tensors[f"{p}.xor1.layer2.bias"] = torch.tensor([-2.0])
4356
+
4357
+ tensors[f"{p}.xor2.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4358
+ tensors[f"{p}.xor2.layer1.or.bias"] = torch.tensor([-1.0])
4359
+ tensors[f"{p}.xor2.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4360
+ tensors[f"{p}.xor2.layer1.nand.bias"] = torch.tensor([1.0])
4361
+ tensors[f"{p}.xor2.layer2.weight"] = torch.tensor([1.0, 1.0])
4362
+ tensors[f"{p}.xor2.layer2.bias"] = torch.tensor([-2.0])
4363
+
4364
+ tensors[f"{p}.and1.weight"] = torch.tensor([1.0, 1.0])
4365
+ tensors[f"{p}.and1.bias"] = torch.tensor([-2.0])
4366
+ tensors[f"{p}.and2.weight"] = torch.tensor([1.0, 1.0])
4367
+ tensors[f"{p}.and2.bias"] = torch.tensor([-2.0])
4368
+ tensors[f"{p}.cout.weight"] = torch.tensor([1.0, 1.0])
4369
+ tensors[f"{p}.cout.bias"] = torch.tensor([-1.0])
4370
+
4371
+ # Mantissa division: 11-bit non-restoring division
4372
+ # Produces 11-bit quotient
4373
+ tensors[f"{prefix}.implicit_a.weight"] = torch.tensor([-1.0])
4374
+ tensors[f"{prefix}.implicit_a.bias"] = torch.tensor([0.0])
4375
+
4376
+ tensors[f"{prefix}.implicit_b.weight"] = torch.tensor([-1.0])
4377
+ tensors[f"{prefix}.implicit_b.bias"] = torch.tensor([0.0])
4378
+
4379
+ # Division iterations (11 steps for 11-bit quotient)
4380
+ for step in range(11):
4381
+ p = f"{prefix}.div_step{step}"
4382
+
4383
+ # Compare and subtract
4384
+ for i in range(12):
4385
+ tensors[f"{p}.sub.fa{i}.xor1.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4386
+ tensors[f"{p}.sub.fa{i}.xor1.layer1.or.bias"] = torch.tensor([-1.0])
4387
+ tensors[f"{p}.sub.fa{i}.xor1.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4388
+ tensors[f"{p}.sub.fa{i}.xor1.layer1.nand.bias"] = torch.tensor([1.0])
4389
+ tensors[f"{p}.sub.fa{i}.xor1.layer2.weight"] = torch.tensor([1.0, 1.0])
4390
+ tensors[f"{p}.sub.fa{i}.xor1.layer2.bias"] = torch.tensor([-2.0])
4391
+
4392
+ tensors[f"{p}.sub.fa{i}.xor2.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4393
+ tensors[f"{p}.sub.fa{i}.xor2.layer1.or.bias"] = torch.tensor([-1.0])
4394
+ tensors[f"{p}.sub.fa{i}.xor2.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4395
+ tensors[f"{p}.sub.fa{i}.xor2.layer1.nand.bias"] = torch.tensor([1.0])
4396
+ tensors[f"{p}.sub.fa{i}.xor2.layer2.weight"] = torch.tensor([1.0, 1.0])
4397
+ tensors[f"{p}.sub.fa{i}.xor2.layer2.bias"] = torch.tensor([-2.0])
4398
+
4399
+ tensors[f"{p}.sub.fa{i}.and1.weight"] = torch.tensor([1.0, 1.0])
4400
+ tensors[f"{p}.sub.fa{i}.and1.bias"] = torch.tensor([-2.0])
4401
+ tensors[f"{p}.sub.fa{i}.and2.weight"] = torch.tensor([1.0, 1.0])
4402
+ tensors[f"{p}.sub.fa{i}.and2.bias"] = torch.tensor([-2.0])
4403
+ tensors[f"{p}.sub.fa{i}.cout.weight"] = torch.tensor([1.0, 1.0])
4404
+ tensors[f"{p}.sub.fa{i}.cout.bias"] = torch.tensor([-1.0])
4405
+
4406
+ # Quotient bit
4407
+ tensors[f"{p}.q_bit.weight"] = torch.tensor([1.0])
4408
+ tensors[f"{p}.q_bit.bias"] = torch.tensor([-0.5])
4409
+
4410
+ # Remainder selection
4411
+ for i in range(12):
4412
+ tensors[f"{p}.rem{i}.sub_path.weight"] = torch.tensor([1.0, 1.0])
4413
+ tensors[f"{p}.rem{i}.sub_path.bias"] = torch.tensor([-2.0])
4414
+ tensors[f"{p}.rem{i}.shift_path.weight"] = torch.tensor([1.0, 1.0])
4415
+ tensors[f"{p}.rem{i}.shift_path.bias"] = torch.tensor([-2.0])
4416
+ tensors[f"{p}.rem{i}.weight"] = torch.tensor([1.0, 1.0])
4417
+ tensors[f"{p}.rem{i}.bias"] = torch.tensor([-1.0])
4418
+
4419
+ # Normalization
4420
+ tensors[f"{prefix}.need_norm.weight"] = torch.tensor([-1.0])
4421
+ tensors[f"{prefix}.need_norm.bias"] = torch.tensor([0.0])
4422
+
4423
+ for i in range(10):
4424
+ tensors[f"{prefix}.norm_mant{i}.norm_path.weight"] = torch.tensor([1.0, 1.0])
4425
+ tensors[f"{prefix}.norm_mant{i}.norm_path.bias"] = torch.tensor([-2.0])
4426
+ tensors[f"{prefix}.norm_mant{i}.direct_path.weight"] = torch.tensor([1.0, 1.0])
4427
+ tensors[f"{prefix}.norm_mant{i}.direct_path.bias"] = torch.tensor([-2.0])
4428
+ tensors[f"{prefix}.norm_mant{i}.weight"] = torch.tensor([1.0, 1.0])
4429
+ tensors[f"{prefix}.norm_mant{i}.bias"] = torch.tensor([-1.0])
4430
+
4431
+ # Output assembly
4432
+ tensors[f"{prefix}.is_normal_result.weight"] = torch.tensor([-1.0, -1.0, -1.0])
4433
+ tensors[f"{prefix}.is_normal_result.bias"] = torch.tensor([0.0])
4434
+
4435
+ for i in range(16):
4436
+ tensors[f"{prefix}.out{i}.nan_gate.weight"] = torch.tensor([1.0, 1.0])
4437
+ tensors[f"{prefix}.out{i}.nan_gate.bias"] = torch.tensor([-2.0])
4438
+ tensors[f"{prefix}.out{i}.inf_gate.weight"] = torch.tensor([1.0, 1.0])
4439
+ tensors[f"{prefix}.out{i}.inf_gate.bias"] = torch.tensor([-2.0])
4440
+ tensors[f"{prefix}.out{i}.zero_gate.weight"] = torch.tensor([1.0, 1.0])
4441
+ tensors[f"{prefix}.out{i}.zero_gate.bias"] = torch.tensor([-2.0])
4442
+ tensors[f"{prefix}.out{i}.normal_gate.weight"] = torch.tensor([1.0, 1.0])
4443
+ tensors[f"{prefix}.out{i}.normal_gate.bias"] = torch.tensor([-2.0])
4444
+
4445
+ tensors[f"{prefix}.out{i}.weight"] = torch.tensor([1.0, 1.0, 1.0, 1.0])
4446
+ tensors[f"{prefix}.out{i}.bias"] = torch.tensor([-1.0])
4447
+
4448
+ return tensors
4449
+
4450
+
4451
+ def build_float16_toint_tensors() -> Dict[str, torch.Tensor]:
4452
+ """Build tensors for float16.toint circuit.
4453
+
4454
+ Convert float16 to signed 16-bit integer (truncate toward zero).
4455
+
4456
+ Algorithm:
4457
+ 1. If NaN or Inf, return 0 or max/min int
4458
+ 2. If |value| < 1, return 0
4459
+ 3. Shift mantissa by (exponent - 15 - 10) positions
4460
+ 4. Apply sign
4461
+ """
4462
+ tensors = {}
4463
+ prefix = "float16.toint"
4464
+
4465
+ # Special case detection
4466
+ tensors[f"{prefix}.exp_all_ones.weight"] = torch.tensor([1.0] * 5)
4467
+ tensors[f"{prefix}.exp_all_ones.bias"] = torch.tensor([-5.0])
4468
+
4469
+ tensors[f"{prefix}.exp_zero.weight"] = torch.tensor([-1.0] * 5)
4470
+ tensors[f"{prefix}.exp_zero.bias"] = torch.tensor([0.0])
4471
+
4472
+ tensors[f"{prefix}.mant_nonzero.weight"] = torch.tensor([1.0] * 10)
4473
+ tensors[f"{prefix}.mant_nonzero.bias"] = torch.tensor([-1.0])
4474
+
4475
+ tensors[f"{prefix}.is_nan.weight"] = torch.tensor([1.0, 1.0])
4476
+ tensors[f"{prefix}.is_nan.bias"] = torch.tensor([-2.0])
4477
+
4478
+ tensors[f"{prefix}.mant_zero.weight"] = torch.tensor([-1.0])
4479
+ tensors[f"{prefix}.mant_zero.bias"] = torch.tensor([0.0])
4480
+
4481
+ tensors[f"{prefix}.is_inf.weight"] = torch.tensor([1.0, 1.0])
4482
+ tensors[f"{prefix}.is_inf.bias"] = torch.tensor([-2.0])
4483
+
4484
+ tensors[f"{prefix}.is_zero.weight"] = torch.tensor([1.0, 1.0])
4485
+ tensors[f"{prefix}.is_zero.bias"] = torch.tensor([-2.0])
4486
+
4487
+ # Check if exponent < 15 (|value| < 1)
4488
+ # exp < 15 means unbiased exp < 0, so result is 0
4489
+ weights = [-float(2**i) for i in range(5)]
4490
+ tensors[f"{prefix}.exp_lt_15.weight"] = torch.tensor(weights)
4491
+ tensors[f"{prefix}.exp_lt_15.bias"] = torch.tensor([14.0])
4492
+
4493
+ tensors[f"{prefix}.result_is_zero.weight"] = torch.tensor([1.0, 1.0, 1.0])
4494
+ tensors[f"{prefix}.result_is_zero.bias"] = torch.tensor([-1.0])
4495
+
4496
+ # Compute shift amount: exp - 15 - 10 = exp - 25
4497
+ # If positive, left shift mantissa; if negative, right shift
4498
+ # For int16, max shift is 15 (for values up to 32767)
4499
+
4500
+ # exp - 25 subtractor
4501
+ for i in range(5):
4502
+ tensors[f"{prefix}.not_25_{i}.weight"] = torch.tensor([1.0])
4503
+ tensors[f"{prefix}.not_25_{i}.bias"] = torch.tensor([-0.5])
4504
+
4505
+ for i in range(6):
4506
+ p = f"{prefix}.shift_calc.fa{i}"
4507
+ tensors[f"{p}.xor1.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4508
+ tensors[f"{p}.xor1.layer1.or.bias"] = torch.tensor([-1.0])
4509
+ tensors[f"{p}.xor1.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4510
+ tensors[f"{p}.xor1.layer1.nand.bias"] = torch.tensor([1.0])
4511
+ tensors[f"{p}.xor1.layer2.weight"] = torch.tensor([1.0, 1.0])
4512
+ tensors[f"{p}.xor1.layer2.bias"] = torch.tensor([-2.0])
4513
+
4514
+ tensors[f"{p}.xor2.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4515
+ tensors[f"{p}.xor2.layer1.or.bias"] = torch.tensor([-1.0])
4516
+ tensors[f"{p}.xor2.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4517
+ tensors[f"{p}.xor2.layer1.nand.bias"] = torch.tensor([1.0])
4518
+ tensors[f"{p}.xor2.layer2.weight"] = torch.tensor([1.0, 1.0])
4519
+ tensors[f"{p}.xor2.layer2.bias"] = torch.tensor([-2.0])
4520
+
4521
+ tensors[f"{p}.and1.weight"] = torch.tensor([1.0, 1.0])
4522
+ tensors[f"{p}.and1.bias"] = torch.tensor([-2.0])
4523
+ tensors[f"{p}.and2.weight"] = torch.tensor([1.0, 1.0])
4524
+ tensors[f"{p}.and2.bias"] = torch.tensor([-2.0])
4525
+ tensors[f"{p}.cout.weight"] = torch.tensor([1.0, 1.0])
4526
+ tensors[f"{p}.cout.bias"] = torch.tensor([-1.0])
4527
+
4528
+ # Barrel shifter (left shift mantissa)
4529
+ tensors[f"{prefix}.implicit_bit.weight"] = torch.tensor([-1.0])
4530
+ tensors[f"{prefix}.implicit_bit.bias"] = torch.tensor([0.0])
4531
+
4532
+ for stage in range(4):
4533
+ shift_amt = 1 << stage
4534
+ tensors[f"{prefix}.not_shift{stage}.weight"] = torch.tensor([-1.0])
4535
+ tensors[f"{prefix}.not_shift{stage}.bias"] = torch.tensor([0.0])
4536
+
4537
+ for i in range(16):
4538
+ tensors[f"{prefix}.lshift_s{stage}_{i}.pass.weight"] = torch.tensor([1.0, 1.0])
4539
+ tensors[f"{prefix}.lshift_s{stage}_{i}.pass.bias"] = torch.tensor([-2.0])
4540
+ if i >= shift_amt:
4541
+ tensors[f"{prefix}.lshift_s{stage}_{i}.shift.weight"] = torch.tensor([1.0, 1.0])
4542
+ tensors[f"{prefix}.lshift_s{stage}_{i}.shift.bias"] = torch.tensor([-2.0])
4543
+ tensors[f"{prefix}.lshift_s{stage}_{i}.weight"] = torch.tensor([1.0, 1.0])
4544
+ else:
4545
+ tensors[f"{prefix}.lshift_s{stage}_{i}.weight"] = torch.tensor([1.0])
4546
+ tensors[f"{prefix}.lshift_s{stage}_{i}.bias"] = torch.tensor([-1.0])
4547
+
4548
+ # Apply sign (negate if negative)
4549
+ for i in range(16):
4550
+ tensors[f"{prefix}.not_mag{i}.weight"] = torch.tensor([-1.0])
4551
+ tensors[f"{prefix}.not_mag{i}.bias"] = torch.tensor([0.0])
4552
+
4553
+ # Two's complement negation
4554
+ for i in range(16):
4555
+ p = f"{prefix}.neg.fa{i}"
4556
+ tensors[f"{p}.xor.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4557
+ tensors[f"{p}.xor.layer1.or.bias"] = torch.tensor([-1.0])
4558
+ tensors[f"{p}.xor.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4559
+ tensors[f"{p}.xor.layer1.nand.bias"] = torch.tensor([1.0])
4560
+ tensors[f"{p}.xor.layer2.weight"] = torch.tensor([1.0, 1.0])
4561
+ tensors[f"{p}.xor.layer2.bias"] = torch.tensor([-2.0])
4562
+
4563
+ tensors[f"{p}.and.weight"] = torch.tensor([1.0, 1.0])
4564
+ tensors[f"{p}.and.bias"] = torch.tensor([-2.0])
4565
+ tensors[f"{p}.cout.weight"] = torch.tensor([1.0, 1.0])
4566
+ tensors[f"{p}.cout.bias"] = torch.tensor([-1.0])
4567
+
4568
+ # Output selection
4569
+ for i in range(16):
4570
+ tensors[f"{prefix}.out{i}.pos_path.weight"] = torch.tensor([1.0, 1.0])
4571
+ tensors[f"{prefix}.out{i}.pos_path.bias"] = torch.tensor([-2.0])
4572
+ tensors[f"{prefix}.out{i}.neg_path.weight"] = torch.tensor([1.0, 1.0])
4573
+ tensors[f"{prefix}.out{i}.neg_path.bias"] = torch.tensor([-2.0])
4574
+ tensors[f"{prefix}.out{i}.weight"] = torch.tensor([1.0, 1.0])
4575
+ tensors[f"{prefix}.out{i}.bias"] = torch.tensor([-1.0])
4576
+
4577
+ return tensors
4578
+
4579
+
4580
+ def build_float16_fromint_tensors() -> Dict[str, torch.Tensor]:
4581
+ """Build tensors for float16.fromint circuit.
4582
+
4583
+ Convert signed 16-bit integer to float16.
4584
+
4585
+ Algorithm:
4586
+ 1. Take absolute value
4587
+ 2. Count leading zeros to find exponent
4588
+ 3. Shift to normalize mantissa
4589
+ 4. Apply sign
4590
+ """
4591
+ tensors = {}
4592
+ prefix = "float16.fromint"
4593
+
4594
+ # Check if zero
4595
+ tensors[f"{prefix}.is_zero.weight"] = torch.tensor([-1.0] * 16)
4596
+ tensors[f"{prefix}.is_zero.bias"] = torch.tensor([0.0])
4597
+
4598
+ # Check if negative (sign bit)
4599
+ tensors[f"{prefix}.is_negative.weight"] = torch.tensor([1.0])
4600
+ tensors[f"{prefix}.is_negative.bias"] = torch.tensor([-0.5])
4601
+
4602
+ tensors[f"{prefix}.not_negative.weight"] = torch.tensor([-1.0])
4603
+ tensors[f"{prefix}.not_negative.bias"] = torch.tensor([0.0])
4604
+
4605
+ # Absolute value: if negative, negate
4606
+ for i in range(16):
4607
+ tensors[f"{prefix}.not_in{i}.weight"] = torch.tensor([-1.0])
4608
+ tensors[f"{prefix}.not_in{i}.bias"] = torch.tensor([0.0])
4609
+
4610
+ for i in range(16):
4611
+ p = f"{prefix}.abs.fa{i}"
4612
+ tensors[f"{p}.xor.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4613
+ tensors[f"{p}.xor.layer1.or.bias"] = torch.tensor([-1.0])
4614
+ tensors[f"{p}.xor.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4615
+ tensors[f"{p}.xor.layer1.nand.bias"] = torch.tensor([1.0])
4616
+ tensors[f"{p}.xor.layer2.weight"] = torch.tensor([1.0, 1.0])
4617
+ tensors[f"{p}.xor.layer2.bias"] = torch.tensor([-2.0])
4618
+
4619
+ tensors[f"{p}.and.weight"] = torch.tensor([1.0, 1.0])
4620
+ tensors[f"{p}.and.bias"] = torch.tensor([-2.0])
4621
+ tensors[f"{p}.cout.weight"] = torch.tensor([1.0, 1.0])
4622
+ tensors[f"{p}.cout.bias"] = torch.tensor([-1.0])
4623
+
4624
+ # Absolute value mux
4625
+ for i in range(16):
4626
+ tensors[f"{prefix}.abs{i}.neg_path.weight"] = torch.tensor([1.0, 1.0])
4627
+ tensors[f"{prefix}.abs{i}.neg_path.bias"] = torch.tensor([-2.0])
4628
+ tensors[f"{prefix}.abs{i}.pos_path.weight"] = torch.tensor([1.0, 1.0])
4629
+ tensors[f"{prefix}.abs{i}.pos_path.bias"] = torch.tensor([-2.0])
4630
+ tensors[f"{prefix}.abs{i}.weight"] = torch.tensor([1.0, 1.0])
4631
+ tensors[f"{prefix}.abs{i}.bias"] = torch.tensor([-1.0])
4632
+
4633
+ # CLZ on 16-bit absolute value
4634
+ for k in range(1, 17):
4635
+ tensors[f"{prefix}.pz{k}.weight"] = torch.tensor([-1.0] * k)
4636
+ tensors[f"{prefix}.pz{k}.bias"] = torch.tensor([0.0])
4637
+
4638
+ for k in range(1, 17):
4639
+ tensors[f"{prefix}.ge{k}.weight"] = torch.tensor([1.0] * 16)
4640
+ tensors[f"{prefix}.ge{k}.bias"] = torch.tensor([-float(k)])
4641
+
4642
+ # CLZ binary encoding
4643
+ for k in [2, 4, 8, 16]:
4644
+ tensors[f"{prefix}.not_ge{k}.weight"] = torch.tensor([-1.0])
4645
+ tensors[f"{prefix}.not_ge{k}.bias"] = torch.tensor([0.0])
4646
+
4647
+ tensors[f"{prefix}.clz3.weight"] = torch.tensor([1.0])
4648
+ tensors[f"{prefix}.clz3.bias"] = torch.tensor([-0.5])
4649
+
4650
+ tensors[f"{prefix}.clz_and_4_7.weight"] = torch.tensor([1.0, 1.0])
4651
+ tensors[f"{prefix}.clz_and_4_7.bias"] = torch.tensor([-2.0])
4652
+ tensors[f"{prefix}.clz_and_12_15.weight"] = torch.tensor([1.0, 1.0])
4653
+ tensors[f"{prefix}.clz_and_12_15.bias"] = torch.tensor([-2.0])
4654
+ tensors[f"{prefix}.clz2.weight"] = torch.tensor([1.0, 1.0])
4655
+ tensors[f"{prefix}.clz2.bias"] = torch.tensor([-1.0])
4656
+
4657
+ tensors[f"{prefix}.clz_and_2_3.weight"] = torch.tensor([1.0, 1.0])
4658
+ tensors[f"{prefix}.clz_and_2_3.bias"] = torch.tensor([-2.0])
4659
+ tensors[f"{prefix}.clz_and_6_7.weight"] = torch.tensor([1.0, 1.0])
4660
+ tensors[f"{prefix}.clz_and_6_7.bias"] = torch.tensor([-2.0])
4661
+ tensors[f"{prefix}.clz_and_10_11.weight"] = torch.tensor([1.0, 1.0])
4662
+ tensors[f"{prefix}.clz_and_10_11.bias"] = torch.tensor([-2.0])
4663
+ tensors[f"{prefix}.clz_and_14_15.weight"] = torch.tensor([1.0, 1.0])
4664
+ tensors[f"{prefix}.clz_and_14_15.bias"] = torch.tensor([-2.0])
4665
+ tensors[f"{prefix}.clz1.weight"] = torch.tensor([1.0, 1.0, 1.0, 1.0])
4666
+ tensors[f"{prefix}.clz1.bias"] = torch.tensor([-1.0])
4667
+
4668
+ for i in [1, 3, 5, 7, 9, 11, 13, 15]:
4669
+ tensors[f"{prefix}.clz_and_{i}.weight"] = torch.tensor([1.0, 1.0])
4670
+ tensors[f"{prefix}.clz_and_{i}.bias"] = torch.tensor([-2.0])
4671
+ tensors[f"{prefix}.clz0.weight"] = torch.tensor([1.0] * 8)
4672
+ tensors[f"{prefix}.clz0.bias"] = torch.tensor([-1.0])
4673
+
4674
+ # Exponent = 15 + 15 - CLZ = 30 - CLZ (biased)
4675
+ # Actually: exponent = bias + (15 - CLZ) = 15 + 15 - CLZ
4676
+ for i in range(5):
4677
+ tensors[f"{prefix}.not_clz{i}.weight"] = torch.tensor([-1.0])
4678
+ tensors[f"{prefix}.not_clz{i}.bias"] = torch.tensor([0.0])
4679
+
4680
+ for i in range(5):
4681
+ p = f"{prefix}.exp_calc.fa{i}"
4682
+ tensors[f"{p}.xor1.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4683
+ tensors[f"{p}.xor1.layer1.or.bias"] = torch.tensor([-1.0])
4684
+ tensors[f"{p}.xor1.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4685
+ tensors[f"{p}.xor1.layer1.nand.bias"] = torch.tensor([1.0])
4686
+ tensors[f"{p}.xor1.layer2.weight"] = torch.tensor([1.0, 1.0])
4687
+ tensors[f"{p}.xor1.layer2.bias"] = torch.tensor([-2.0])
4688
+
4689
+ tensors[f"{p}.xor2.layer1.or.weight"] = torch.tensor([1.0, 1.0])
4690
+ tensors[f"{p}.xor2.layer1.or.bias"] = torch.tensor([-1.0])
4691
+ tensors[f"{p}.xor2.layer1.nand.weight"] = torch.tensor([-1.0, -1.0])
4692
+ tensors[f"{p}.xor2.layer1.nand.bias"] = torch.tensor([1.0])
4693
+ tensors[f"{p}.xor2.layer2.weight"] = torch.tensor([1.0, 1.0])
4694
+ tensors[f"{p}.xor2.layer2.bias"] = torch.tensor([-2.0])
4695
+
4696
+ tensors[f"{p}.and1.weight"] = torch.tensor([1.0, 1.0])
4697
+ tensors[f"{p}.and1.bias"] = torch.tensor([-2.0])
4698
+ tensors[f"{p}.and2.weight"] = torch.tensor([1.0, 1.0])
4699
+ tensors[f"{p}.and2.bias"] = torch.tensor([-2.0])
4700
+ tensors[f"{p}.cout.weight"] = torch.tensor([1.0, 1.0])
4701
+ tensors[f"{p}.cout.bias"] = torch.tensor([-1.0])
4702
+
4703
+ # Left barrel shifter to normalize mantissa
4704
+ for stage in range(4):
4705
+ shift_amt = 1 << stage
4706
+ tensors[f"{prefix}.not_norm_shift{stage}.weight"] = torch.tensor([-1.0])
4707
+ tensors[f"{prefix}.not_norm_shift{stage}.bias"] = torch.tensor([0.0])
4708
+
4709
+ for i in range(16):
4710
+ tensors[f"{prefix}.norm_s{stage}_{i}.pass.weight"] = torch.tensor([1.0, 1.0])
4711
+ tensors[f"{prefix}.norm_s{stage}_{i}.pass.bias"] = torch.tensor([-2.0])
4712
+ if i >= shift_amt:
4713
+ tensors[f"{prefix}.norm_s{stage}_{i}.shift.weight"] = torch.tensor([1.0, 1.0])
4714
+ tensors[f"{prefix}.norm_s{stage}_{i}.shift.bias"] = torch.tensor([-2.0])
4715
+ tensors[f"{prefix}.norm_s{stage}_{i}.weight"] = torch.tensor([1.0, 1.0])
4716
+ else:
4717
+ tensors[f"{prefix}.norm_s{stage}_{i}.weight"] = torch.tensor([1.0])
4718
+ tensors[f"{prefix}.norm_s{stage}_{i}.bias"] = torch.tensor([-1.0])
4719
+
4720
+ # Output assembly
4721
+ for i in range(16):
4722
+ if i < 10:
4723
+ tensors[f"{prefix}.out{i}.zero_gate.weight"] = torch.tensor([1.0, 1.0])
4724
+ tensors[f"{prefix}.out{i}.zero_gate.bias"] = torch.tensor([-2.0])
4725
+ tensors[f"{prefix}.out{i}.normal_gate.weight"] = torch.tensor([1.0, 1.0])
4726
+ tensors[f"{prefix}.out{i}.normal_gate.bias"] = torch.tensor([-2.0])
4727
+ tensors[f"{prefix}.out{i}.weight"] = torch.tensor([1.0, 1.0])
4728
+ tensors[f"{prefix}.out{i}.bias"] = torch.tensor([-1.0])
4729
+ elif i < 15:
4730
+ tensors[f"{prefix}.out{i}.zero_gate.weight"] = torch.tensor([1.0, 1.0])
4731
+ tensors[f"{prefix}.out{i}.zero_gate.bias"] = torch.tensor([-2.0])
4732
+ tensors[f"{prefix}.out{i}.normal_gate.weight"] = torch.tensor([1.0, 1.0])
4733
+ tensors[f"{prefix}.out{i}.normal_gate.bias"] = torch.tensor([-2.0])
4734
+ tensors[f"{prefix}.out{i}.weight"] = torch.tensor([1.0, 1.0])
4735
+ tensors[f"{prefix}.out{i}.bias"] = torch.tensor([-1.0])
4736
+ else:
4737
+ tensors[f"{prefix}.out{i}.weight"] = torch.tensor([1.0])
4738
+ tensors[f"{prefix}.out{i}.bias"] = torch.tensor([-0.5])
4739
+
4740
+ return tensors
4741
+
4742
+
4743
  def build_clz8bit_tensors() -> Dict[str, torch.Tensor]:
4744
  """Build tensors for arithmetic.clz8bit circuit.
4745
 
 
4853
  tensors.update(add_tensors)
4854
  print(f" float16.add: {len(add_tensors)} tensors")
4855
 
4856
+ sub_tensors = build_float16_sub_tensors()
4857
+ tensors.update(sub_tensors)
4858
+ print(f" float16.sub: {len(sub_tensors)} tensors")
4859
+
4860
+ mul_tensors = build_float16_mul_tensors()
4861
+ tensors.update(mul_tensors)
4862
+ print(f" float16.mul: {len(mul_tensors)} tensors")
4863
+
4864
+ div_tensors = build_float16_div_tensors()
4865
+ tensors.update(div_tensors)
4866
+ print(f" float16.div: {len(div_tensors)} tensors")
4867
+
4868
+ toint_tensors = build_float16_toint_tensors()
4869
+ tensors.update(toint_tensors)
4870
+ print(f" float16.toint: {len(toint_tensors)} tensors")
4871
+
4872
+ fromint_tensors = build_float16_fromint_tensors()
4873
+ tensors.update(fromint_tensors)
4874
+ print(f" float16.fromint: {len(fromint_tensors)} tensors")
4875
+
4876
  print(f"Total tensors: {len(tensors)}")
4877
 
4878
  # Load routing for complex circuits