Round-7 (001164d, "Both domains' sub_base dispatch(negative) and dispatch(zero) now route through operator-") fixed the scalar and tensor_to_scalar domains — the tensor domain was missed and still builds raw negative nodes:
src/numsim_cas/tensor/simplifier/tensor_simplifier_sub.cpp (main):
dispatch(tensor_zero): make_expression<tensor_negative>(std::move(m_rhs)) with no already-negative check → 0 - (-A) produces negative(negative(A)) instead of A.
dispatch(tensor_negative): make_expression<tensor_negative>(lhs.expr() + m_rhs) — a sum that itself normalizes to a negative re-wraps into a nested negative (same class as the scalar R7-1 finding).
The tensor unary operator- (tensor_expression.cpp tag_invoke(neg_fn, ...)) already folds -0 → 0 and -(-x) → x, so the fix is the same one-liner routing the other two domains got.
Downstream impact (how this was found): numsim-codegen's emitters received the nested-negative node and emitted invalid C++ (--A, a decrement) until they grew a defensive paren guard (numsim-codegen#136 / PR numsim-codegen#147, which now keeps -(-A) well-formed). The emitters' guard stays as defense-in-depth, but the canonical form should never leave the simplifier.
PR with the fix + RoundSevenReview-parity tests to follow.
Round-7 (001164d, "Both domains' sub_base dispatch(negative) and dispatch(zero) now route through operator-") fixed the scalar and tensor_to_scalar domains — the tensor domain was missed and still builds raw negative nodes:
src/numsim_cas/tensor/simplifier/tensor_simplifier_sub.cpp(main):dispatch(tensor_zero):make_expression<tensor_negative>(std::move(m_rhs))with no already-negative check →0 - (-A)producesnegative(negative(A))instead ofA.dispatch(tensor_negative):make_expression<tensor_negative>(lhs.expr() + m_rhs)— a sum that itself normalizes to a negative re-wraps into a nested negative (same class as the scalar R7-1 finding).The tensor unary
operator-(tensor_expression.cpptag_invoke(neg_fn, ...)) already folds-0 → 0and-(-x) → x, so the fix is the same one-liner routing the other two domains got.Downstream impact (how this was found): numsim-codegen's emitters received the nested-negative node and emitted invalid C++ (
--A, a decrement) until they grew a defensive paren guard (numsim-codegen#136 / PR numsim-codegen#147, which now keeps-(-A)well-formed). The emitters' guard stays as defense-in-depth, but the canonical form should never leave the simplifier.PR with the fix + RoundSevenReview-parity tests to follow.