diff --git a/src/numsim_cas/tensor/simplifier/tensor_simplifier_sub.cpp b/src/numsim_cas/tensor/simplifier/tensor_simplifier_sub.cpp index 84e311d5..36f7277f 100644 --- a/src/numsim_cas/tensor/simplifier/tensor_simplifier_sub.cpp +++ b/src/numsim_cas/tensor/simplifier/tensor_simplifier_sub.cpp @@ -56,18 +56,17 @@ sub_base::expr_holder_t sub_base::dispatch(tensor const &) { return _rhs.accept(visitor); } -// 0 - expr +// 0 - expr --> -expr sub_base::expr_holder_t sub_base::dispatch(tensor_zero const &) { - if (is_same(m_rhs)) - return make_expression(m_rhs.get().dim(), m_rhs.get().rank()); - return make_expression(std::move(m_rhs)); + return -std::move(m_rhs); } // - expr_lhs - expr_rhs --> -(expr_lhs+expr_rhs) +// operator-, not a raw node: the sum may already be zero or negative sub_base::expr_holder_t sub_base::dispatch(tensor_negative const &lhs) { auto expr{lhs.expr() + std::move(m_rhs)}; if (expr.is_valid()) { - return make_expression(expr); + return -std::move(expr); } return make_expression(lhs.dim(), lhs.rank()); } diff --git a/tests/CoreBugFixTest.h b/tests/CoreBugFixTest.h index d3bfcc6d..c1785a04 100644 --- a/tests/CoreBugFixTest.h +++ b/tests/CoreBugFixTest.h @@ -1446,6 +1446,42 @@ TEST(RoundSevenReview, AddCancelsAgainstNegativeChild) { EXPECT_TRUE(*f == *(trace(A) + w(c4))) << to_string(f); } +TEST(RoundSevenReview, TensorSubNormalizesLikeScalarAndT2s) { + auto [A, B] = + make_tensor_variable(std::tuple{"A", std::size_t{3}, std::size_t{2}}, + std::tuple{"B", std::size_t{3}, std::size_t{2}}); + auto zero = make_expression(3, 2); + // operator- short-circuits these before sub_base + auto e1 = zero - (-A); + EXPECT_TRUE(*e1 == *A) << to_string(e1); + auto e0 = zero - make_expression(3, 2); + EXPECT_TRUE(is_same(e0)) << to_string(e0); + auto e2 = (-A) - (-A); + EXPECT_TRUE(is_same(e2)) << to_string(e2); + auto e3 = (-A) - B; + EXPECT_TRUE(*e3 == *(-(A + B))) << to_string(e3); + + auto e4 = (-A) - (make_expression(-1) * A); + EXPECT_TRUE(is_same(e4)) << to_string(e4); + + // call sub_base directly to reach its zero/negative dispatches + auto direct = [](expression_holder const &lhs, + expression_holder const &rhs) { + tensor_detail::simplifier::sub_base visitor(lhs, rhs); + return lhs.get().accept(visitor); + }; + auto d1 = direct(zero, -A); + EXPECT_TRUE(*d1 == *A) << to_string(d1); + auto d2 = direct(zero, make_expression(3, 2)); + EXPECT_TRUE(is_same(d2)) << to_string(d2); + auto d3 = direct(zero, B); + EXPECT_TRUE(*d3 == *(-B)) << to_string(d3); + auto d4 = direct(-A, -A); + EXPECT_TRUE(is_same(d4)) << to_string(d4); + auto d5 = direct(make_expression(zero), -B); + EXPECT_TRUE(*d5 == *B) << to_string(d5); +} + // Round-8 review: regressions from the round-7 negation probe. // R8-1: merge_add consumed the same rhs child twice when the lhs held an