@@ -528,6 +528,75 @@ BOOST_AUTO_TEST_CASE(expression_general_product_t_times_tot) {
528528 BOOST_CHECK_SMALL (tot_max_abs_diff (c, c_ref), 1e-10 );
529529}
530530
531+ BOOST_AUTO_TEST_CASE (expression_mixed_t_tot_depth2_chains) {
532+ // mixed T/ToT products at INNER nodes of the expression tree:
533+ // left-deep: w("i,k;x") = (s("i,j") * t("j,m")) * c("m,k;x")
534+ // right-deep: w("i,k;x") = s("i,j") * (t("j,m") * c("m,k;x"))
535+ // (plain contraction at every node, inner Scale where a plain factor
536+ // meets the nested one)
537+ auto & world = TA::get_default_world ();
538+ TA ::TiledRange tr_s{{0 , 2 , 4 }, {0 , 2 , 5 }}; // i, j
539+ TA ::TiledRange tr_t {{0 , 2 , 5 }, {0 , 3 , 4 }}; // j, m
540+ TA ::TiledRange tr_c{{0 , 3 , 4 }, {0 , 2 , 3 }}; // m, k
541+ auto s = make_patterned_array (world, tr_s, 1.0 );
542+ auto t = make_patterned_array (world, tr_t , 2.0 );
543+ auto c = make_patterned_tot_array (world, tr_c, {3 }, 3.0 );
544+
545+ // staged reference
546+ TArrayToT i1, w_ref;
547+ i1 (" j,k;x" ) = t (" j,m" ) * c (" m,k;x" );
548+ w_ref (" i,k;x" ) = s (" i,j" ) * i1 (" j,k;x" );
549+
550+ TArrayToT w_l, w_r;
551+ BOOST_REQUIRE_NO_THROW (w_l (" i,k;x" ) = (s (" i,j" ) * t (" j,m" )) * c (" m,k;x" ));
552+ BOOST_CHECK_SMALL (tot_max_abs_diff (w_l, w_ref), 1e-10 );
553+ BOOST_REQUIRE_NO_THROW (w_r (" i,k;x" ) = s (" i,j" ) * (t (" j,m" ) * c (" m,k;x" )));
554+ BOOST_CHECK_SMALL (tot_max_abs_diff (w_r, w_ref), 1e-10 );
555+ }
556+
557+ BOOST_AUTO_TEST_CASE (expression_mixed_t_tot_inner_general) {
558+ // a mixed T x ToT GENERAL product at an INNER node:
559+ // w("i,j;x") = (g("b,i") * c("b,j;x")) * h("b")
560+ // b is fused where g meets c (demanded by the h factor above) and
561+ // contracted at the root
562+ auto & world = TA::get_default_world ();
563+ TA ::TiledRange tr_g{{0 , 3 , 5 }, {0 , 2 , 4 }}; // b, i
564+ TA ::TiledRange tr_c{{0 , 3 , 5 }, {0 , 2 , 3 }}; // b, j
565+ TA ::TiledRange tr_h{{0 , 3 , 5 }}; // b
566+ auto g = make_patterned_array (world, tr_g, 1.0 );
567+ auto c = make_patterned_tot_array (world, tr_c, {3 }, 2.0 );
568+ TA ::TArrayD h (world, tr_h);
569+ h.fill (1.5 );
570+
571+ TArrayToT i1, w_ref;
572+ i1 (" b,i,j;x" ) = g (" b,i" ) * c (" b,j;x" ); // depth-1 mixed general
573+ w_ref (" i,j;x" ) = i1 (" b,i,j;x" ) * h (" b" );
574+
575+ TArrayToT w;
576+ try {
577+ w (" i,j;x" ) = (g (" b,i" ) * c (" b,j;x" )) * h (" b" );
578+ } catch (std::exception& e) {
579+ BOOST_FAIL (std::string (" threw: " ) + e.what ());
580+ }
581+ BOOST_CHECK_SMALL (tot_max_abs_diff (w, w_ref), 1e-10 );
582+ }
583+
584+ BOOST_AUTO_TEST_CASE (expression_mixed_t_tot_scaled) {
585+ // scaled mixed T x ToT general product (ScalMultEngine path):
586+ // w("b,i,k;x") = 2 * (a("b,i,j") * c("b,j,k;x"))
587+ auto & world = TA::get_default_world ();
588+ TA ::TiledRange tr_a{{0 , 2 , 4 }, {0 , 2 , 3 }, {0 , 2 , 5 }}; // b, i, j
589+ TA ::TiledRange tr_c{{0 , 2 , 4 }, {0 , 2 , 5 }, {0 , 3 , 4 }}; // b, j, k
590+ auto a = make_patterned_array (world, tr_a, 1.0 );
591+ auto c = make_patterned_tot_array (world, tr_c, {3 }, 2.0 );
592+
593+ TArrayToT w_ref0, w_ref, w;
594+ w_ref0 (" b,i,k;x" ) = a (" b,i,j" ) * c (" b,j,k;x" );
595+ w_ref (" b,i,k;x" ) = 2.0 * w_ref0 (" b,i,k;x" );
596+ BOOST_REQUIRE_NO_THROW (w (" b,i,k;x" ) = 2.0 * (a (" b,i,j" ) * c (" b,j,k;x" )));
597+ BOOST_CHECK_SMALL (tot_max_abs_diff (w, w_ref), 1e-10 );
598+ }
599+
531600BOOST_AUTO_TEST_CASE (expression_general_product_tot_inner_outer_product) {
532601 // the PNO-CC PPL building-block shape: ToT x ToT with an EMPTY right
533602 // outer-external set and an inner OUTER-product:
0 commit comments