CharlesCNorton commited on
Commit
b933255
·
1 Parent(s): f4a8367

Fix sbc8bit test: pass borrow input to subtractor eval

Browse files

PROBLEM:
- arithmetic.sbc8bit was failing 67/134 tests
- Test had borrow variable but never passed it to eval_subtractor
- eval_subtractor defaulted to carry_in=1, which is correct for sub8bit
but wrong for sbc8bit which takes external borrow input

ANALYSIS:
- sbc8bit has $cin input (signal 2355) for borrow
- $cin goes directly into fa0.xor2 (first full adder's carry input)
- No carry_in gate like sub8bit has

FIX:
1. Modified eval_subtractor() to accept optional initial_carry parameter
2. Updated sbc8bit test to compute: initial_carry = 1.0 - borrow
- When borrow=0: carry_in=1, computes a - b
- When borrow=1: carry_in=0, computes a - b - 1

MATH:
- sbc computes: a - b - borrow
- Using two's complement: a + ~b + ~borrow
- So carry_in = ~borrow (inverted borrow)

RESULT:
- arithmetic.sbc8bit: 67/134 -> 134/134 PASS
- Overall: 206,124/206,124 (100.0000%)
- Fitness: 1.000000

All circuits now pass!

Files changed (1) hide show
  1. eval.py +18 -9
eval.py CHANGED
@@ -662,20 +662,25 @@ def test_clz(ctx: EvalContext) -> List[TestResult]:
662
  # =============================================================================
663
 
664
  def eval_subtractor(ctx: EvalContext, prefix: str, a_bits: List[float],
665
- b_bits: List[float]) -> Tuple[List[float], float]:
666
- """Evaluate 8-bit subtractor (a - b) using full adders with b inverted + carry-in=1.
667
 
668
  The subtractor circuit has internal NOT gates (notb0-notb7) that invert b,
669
- then uses full adders to compute a + ~b + 1.
 
 
 
670
  """
671
  n = len(a_bits)
672
  result = []
673
 
674
- # Get initial carry (should be 1 for subtraction via two's complement)
675
- if f"{prefix}.carry_in.weight" in ctx.tensors:
 
 
676
  carry = eval_gate_direct(ctx, f"{prefix}.carry_in", [1.0])
677
  else:
678
- carry = 1.0
679
 
680
  # First, invert b bits using the circuit's NOT gates
681
  notb_bits = []
@@ -856,20 +861,24 @@ def test_adders(ctx: EvalContext) -> List[TestResult]:
856
  results.append(TestResult("arithmetic.adc8bit", passed, total))
857
 
858
  # 8-bit subtract with borrow (sbc8bit)
 
 
859
  if f"arithmetic.sbc8bit.fa0.xor1.layer1.or.weight" in ctx.tensors:
860
  passed, total = 0, 0
861
  test_cases = [(0, 0, 0), (0, 0, 1), (255, 1, 0), (255, 1, 1), (100, 50, 0), (100, 50, 1)]
862
  if not ctx.quick:
863
  test_cases.extend((a, b, c) for a in range(0, 256, 32) for b in range(0, 256, 32) for c in [0, 1])
864
 
865
- for a, b, bin_val in test_cases:
866
  a_bits = [float((a >> i) & 1) for i in range(8)]
867
  b_bits = [float((b >> i) & 1) for i in range(8)]
868
 
869
- result_bits, _ = eval_subtractor(ctx, "arithmetic.sbc8bit", a_bits, b_bits)
 
 
870
  result = sum(int(bit) << i for i, bit in enumerate(result_bits))
871
  # sbc: a - b - borrow
872
- expected = (a - b - bin_val) % 256
873
 
874
  total += 1
875
  if result == expected:
 
662
  # =============================================================================
663
 
664
  def eval_subtractor(ctx: EvalContext, prefix: str, a_bits: List[float],
665
+ b_bits: List[float], initial_carry: float = None) -> Tuple[List[float], float]:
666
+ """Evaluate 8-bit subtractor (a - b) using full adders with b inverted + carry-in.
667
 
668
  The subtractor circuit has internal NOT gates (notb0-notb7) that invert b,
669
+ then uses full adders to compute a + ~b + carry_in.
670
+
671
+ For sub8bit: carry_in = 1 (computes a - b)
672
+ For sbc8bit: carry_in = ~borrow (computes a - b - borrow)
673
  """
674
  n = len(a_bits)
675
  result = []
676
 
677
+ # Get initial carry
678
+ if initial_carry is not None:
679
+ carry = initial_carry
680
+ elif f"{prefix}.carry_in.weight" in ctx.tensors:
681
  carry = eval_gate_direct(ctx, f"{prefix}.carry_in", [1.0])
682
  else:
683
+ carry = 1.0 # Default for sub8bit
684
 
685
  # First, invert b bits using the circuit's NOT gates
686
  notb_bits = []
 
861
  results.append(TestResult("arithmetic.adc8bit", passed, total))
862
 
863
  # 8-bit subtract with borrow (sbc8bit)
864
+ # sbc computes: a - b - borrow = a + ~b + ~borrow
865
+ # So carry_in = ~borrow (1 when borrow=0, 0 when borrow=1)
866
  if f"arithmetic.sbc8bit.fa0.xor1.layer1.or.weight" in ctx.tensors:
867
  passed, total = 0, 0
868
  test_cases = [(0, 0, 0), (0, 0, 1), (255, 1, 0), (255, 1, 1), (100, 50, 0), (100, 50, 1)]
869
  if not ctx.quick:
870
  test_cases.extend((a, b, c) for a in range(0, 256, 32) for b in range(0, 256, 32) for c in [0, 1])
871
 
872
+ for a, b, borrow in test_cases:
873
  a_bits = [float((a >> i) & 1) for i in range(8)]
874
  b_bits = [float((b >> i) & 1) for i in range(8)]
875
 
876
+ # carry_in = ~borrow for sbc (inverted borrow)
877
+ initial_carry = 1.0 - float(borrow)
878
+ result_bits, _ = eval_subtractor(ctx, "arithmetic.sbc8bit", a_bits, b_bits, initial_carry)
879
  result = sum(int(bit) << i for i, bit in enumerate(result_bits))
880
  # sbc: a - b - borrow
881
+ expected = (a - b - borrow) % 256
882
 
883
  total += 1
884
  if result == expected: