Skip to content

Commit da4c250

Browse files
committed
tests: distributed (np>1) general-product suite
Adds general_product_distributed_suite (UNLABELED, so the CI harness runs it at both np=1 and np=2 -- the existing general_product_suite is serial-labeled and never exercised the batched Summa across ranks). Six differential cases vs the legacy sub-World einsum oracle: dense, sparse, mixed T x ToT, no-external (dense + ToT), and the one-expression THC reconstruction. All evaluate via the shared-grid (hgroups == 1) batched Summa.
1 parent 4023636 commit da4c250

1 file changed

Lines changed: 114 additions & 0 deletions

File tree

tests/general_product.cpp

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,3 +1342,117 @@ BOOST_AUTO_TEST_CASE(einsum_expression_route_matches_legacy) {
13421342
}
13431343

13441344
BOOST_AUTO_TEST_SUITE_END()
1345+
1346+
// Distributed (np > 1) coverage of general products. Unlike
1347+
// general_product_suite (serial-labeled: classification/optimizer unit tests
1348+
// + np=1 evaluation), this suite carries NO label, so the CI harness runs it
1349+
// at BOTH np=1 and np=2 (see tests/CMakeLists.txt: np-1 excludes @distributed,
1350+
// np-2 excludes @serial). It exercises the batched Summa across ranks -- a
1351+
// path the serial suite never covered. Each case differential-tests the
1352+
// expression route against the legacy sub-World einsum oracle.
1353+
//
1354+
// N.B. these all evaluate via the shared-grid (hgroups == 1) batched Summa;
1355+
// the experimental h-grouped 3-d grid (TA_SUMMA_HGROUPS) is not yet correct
1356+
// at np > 1 and is intentionally not exercised here.
1357+
BOOST_AUTO_TEST_SUITE(general_product_distributed_suite)
1358+
1359+
// the fixtures/helpers live in general_product_suite's anonymous namespace
1360+
using general_product_suite::diff_norm;
1361+
using general_product_suite::diff_norm_sp;
1362+
using general_product_suite::ForceLegacyEinsum;
1363+
using general_product_suite::make_patterned_array;
1364+
using general_product_suite::make_patterned_sparse_array;
1365+
using general_product_suite::make_patterned_tot_array;
1366+
using general_product_suite::TArrayToT;
1367+
using general_product_suite::tot_max_abs_diff;
1368+
1369+
BOOST_AUTO_TEST_CASE(dist_dense) {
1370+
// batched general product: b fused, j contracted, i/k free
1371+
auto& world = TA::get_default_world();
1372+
ForceLegacyEinsum legacy_oracle;
1373+
TA::TiledRange tr_a{{0, 2, 4}, {0, 2, 3}, {0, 2, 5}}; // b, i, j
1374+
TA::TiledRange tr_b{{0, 2, 4}, {0, 2, 5}, {0, 3, 4}}; // b, j, k
1375+
auto a = make_patterned_array(world, tr_a, 1.0);
1376+
auto b = make_patterned_array(world, tr_b, 2.0);
1377+
TA::TArrayD c;
1378+
BOOST_REQUIRE_NO_THROW(c("b,i,k") = a("b,i,j") * b("b,j,k"));
1379+
auto c_ref = TA::einsum(a("b,i,j"), b("b,j,k"), "b,i,k");
1380+
BOOST_CHECK_SMALL(diff_norm(c, c_ref, "b,i,k"), 1e-10);
1381+
}
1382+
1383+
BOOST_AUTO_TEST_CASE(dist_sparse) {
1384+
// block-sparse batched general product (SparseShape::gemm_batched +
1385+
// the sparse (h,k)-keyed Summa groups, across ranks)
1386+
auto& world = TA::get_default_world();
1387+
ForceLegacyEinsum legacy_oracle;
1388+
TA::TiledRange tr_a{{0, 2, 5}, {0, 3, 4}, {0, 2, 6, 7}}; // b, i, j
1389+
TA::TiledRange tr_b{{0, 2, 5}, {0, 2, 6, 7}, {0, 4, 5}}; // b, j, k
1390+
auto a = make_patterned_sparse_array(world, tr_a, 1.0, 3);
1391+
auto b = make_patterned_sparse_array(world, tr_b, 2.0, 4);
1392+
TA::TSpArrayD c;
1393+
BOOST_REQUIRE_NO_THROW(c("b,i,k") = a("b,i,j") * b("b,j,k"));
1394+
auto c_ref = TA::einsum(a("b,i,j"), b("b,j,k"), "b,i,k");
1395+
BOOST_CHECK_SMALL(diff_norm_sp(c, c_ref, "b,i,k"), 1e-10);
1396+
}
1397+
1398+
BOOST_AUTO_TEST_CASE(dist_tot_mixed) {
1399+
// mixed T x ToT general product (inner Scale) across ranks
1400+
auto& world = TA::get_default_world();
1401+
ForceLegacyEinsum legacy_oracle;
1402+
TA::TiledRange tr_a{{0, 2, 4}, {0, 2, 3}, {0, 2, 5}}; // b, i, j
1403+
TA::TiledRange tr_b{{0, 2, 4}, {0, 2, 5}, {0, 3, 4}}; // b, j, k
1404+
auto a = make_patterned_array(world, tr_a, 1.0);
1405+
auto b = make_patterned_tot_array(world, tr_b, {3}, 2.0);
1406+
TArrayToT c;
1407+
BOOST_REQUIRE_NO_THROW(c("b,i,k;m") = a("b,i,j") * b("b,j,k;m"));
1408+
auto c_ref = TA::einsum(a("b,i,j"), b("b,j,k;m"), "b,i,k;m");
1409+
BOOST_CHECK_SMALL(tot_max_abs_diff(c, c_ref), 1e-10);
1410+
}
1411+
1412+
BOOST_AUTO_TEST_CASE(dist_no_externals_dense) {
1413+
// no-external general product (Hadamard reduction shape) across ranks;
1414+
// the synthetic unit left-external mode handling under distribution
1415+
auto& world = TA::get_default_world();
1416+
ForceLegacyEinsum legacy_oracle;
1417+
TA::TiledRange tr{{0, 2, 4}, {0, 3, 5}}; // i, j
1418+
auto a = make_patterned_array(world, tr, 1.0);
1419+
auto b = make_patterned_array(world, tr, 2.0);
1420+
TA::TArrayD c;
1421+
BOOST_REQUIRE_NO_THROW(c("i") = a("i,j") * b("i,j"));
1422+
auto c_ref = TA::einsum(a("i,j"), b("i,j"), "i");
1423+
BOOST_CHECK_SMALL(diff_norm(c, c_ref, "i"), 1e-10);
1424+
}
1425+
1426+
BOOST_AUTO_TEST_CASE(dist_no_externals_tot) {
1427+
// no-external ToT general product across ranks
1428+
auto& world = TA::get_default_world();
1429+
ForceLegacyEinsum legacy_oracle;
1430+
TA::TiledRange tr{{0, 3, 5}, {0, 2, 4}, {0, 2, 3}}; // x, i, j
1431+
auto a = make_patterned_tot_array(world, tr, {2}, 1.0);
1432+
auto b = make_patterned_tot_array(world, tr, {3}, 2.0);
1433+
TArrayToT c;
1434+
BOOST_REQUIRE_NO_THROW(c("i,j;a,b") = a("x,i,j;a") * b("x,i,j;b"));
1435+
auto c_ref = TA::einsum(a("x,i,j;a"), b("x,i,j;b"), "i,j;a,b");
1436+
BOOST_CHECK_SMALL(tot_max_abs_diff(c, c_ref), 1e-10);
1437+
}
1438+
1439+
BOOST_AUTO_TEST_CASE(dist_inner_node_thc) {
1440+
// THC reconstruction in one expression (general products at inner nodes)
1441+
// across ranks
1442+
auto& world = TA::get_default_world();
1443+
TA::TiledRange tr_x{{0, 2, 4}, {0, 3, 5}}; // orbital x auxiliary
1444+
TA::TiledRange tr_z{{0, 3, 5}, {0, 3, 5}}; // auxiliary x auxiliary
1445+
auto x = make_patterned_array(world, tr_x, 1.0);
1446+
auto z = make_patterned_array(world, tr_z, 2.0);
1447+
TA::TArrayD g;
1448+
BOOST_REQUIRE_NO_THROW(g("p,q,r,s") = x("p,r1") * x("q,r1") * z("r1,r2") *
1449+
x("r,r2") * x("s,r2"));
1450+
TA::TArrayD i1, i2, i3, g_ref;
1451+
i1("r1,p,q") = x("p,r1") * x("q,r1");
1452+
i2("p,q,r2") = i1("r1,p,q") * z("r1,r2");
1453+
i3("r2,p,q,r") = i2("p,q,r2") * x("r,r2");
1454+
g_ref("p,q,r,s") = i3("r2,p,q,r") * x("s,r2");
1455+
BOOST_CHECK_SMALL(diff_norm(g, g_ref, "p,q,r,s"), 1e-10);
1456+
}
1457+
1458+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)