Skip to content

t2s constant_mul drops a non-numeric scalar_wrapper factor: wrapper(x)*(trace(A)*det(A)) → 1*det(A)*tr(A) #354

Description

@petlenz

Summary

constant_mul::dispatch(tensor_to_scalar_mul) (src/numsim_cas/tensor_to_scalar/simplifier/tensor_to_scalar_simplifier_mul.cpp:31-44) silently drops a non-numeric scalar_wrapper LHS when multiplying into an existing product (reproduced at 0f6c0b9):

// x scalar symbol, A tensor
wrapper(x) * (trace(A) * det(A))   // → "1*det(A)*tr(A)" — x has vanished, coeff reset to 1

When lhs_val (numeric extraction) is nullopt, the code computes coeff{get_coefficient(mul,1)}, skips the coeff * *lhs_val merge, and never inserts m_lhs into the product. The promoted path x * (f*g) happens to route through mul_base::dispatch and is correct — which is why tests miss it; the bug fires whenever the wrapper is the visitor's LHS (e.g. (x*f)*g built in an order that puts the wrapper first, or internal simplifier calls).

Severity: high (silent factor loss). Confirmed. Related: #104 (mul×mul merge consolidation — this is a concrete drift instance of that risk).

Fix

In the !lhs_val branch, insert m_lhs as a child (push_or_combine(mul, m_lhs), merging with an existing scalar_wrapper child the way n_ary_add::dispatch(scalar_wrapper) does) instead of touching only the numeric coefficient.

Tests (lock-in)

TEST(T2sConstantMul, SymbolicWrapperFactorSurvives) {
  auto [x] = make_scalar_variable("x");
  auto [A] = make_tensor_variable(std::tuple{"A", 3, 2});
  auto f = trace(A) * det(A);
  auto e = /* wrapper-first product, e.g. via promote/explicit wrapper */ wrap(x) * f;
  // evaluate with x=2, A=diag(1,2,3): trace=6, det=6 → expect 72, not 36
  EXPECT_NE(to_string(e).find("x"), std::string::npos);
}

(Construct the wrapper-first path the same way the probe did — building tensor_to_scalar_scalar_wrapper(x) explicitly and multiplying it by an existing tensor_to_scalar_mul — so the regression can't dodge through the promoted route.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions