|
8 | 8 | #include "tiledarray.h" |
9 | 9 | #include "unit_test_config.h" |
10 | 10 |
|
| 11 | +#include <set> |
| 12 | + |
11 | 13 | BOOST_AUTO_TEST_SUITE(general_product_suite, TA_UT_LABEL_SERIAL) |
12 | 14 |
|
13 | 15 | namespace TA = TiledArray; |
@@ -1342,3 +1344,142 @@ BOOST_AUTO_TEST_CASE(einsum_expression_route_matches_legacy) { |
1342 | 1344 | } |
1343 | 1345 |
|
1344 | 1346 | BOOST_AUTO_TEST_SUITE_END() |
| 1347 | + |
| 1348 | +// Distributed (np > 1) coverage of general products. Unlike |
| 1349 | +// general_product_suite (serial-labeled: classification/optimizer unit tests |
| 1350 | +// + np=1 evaluation), this suite carries NO label, so the CI harness runs it |
| 1351 | +// at BOTH np=1 and np=2 (see tests/CMakeLists.txt: np-1 excludes @distributed, |
| 1352 | +// np-2 excludes @serial). It exercises the batched Summa across ranks -- a |
| 1353 | +// path the serial suite never covered. Each case differential-tests the |
| 1354 | +// expression route against the legacy sub-World einsum oracle. |
| 1355 | +// |
| 1356 | +// Most cases evaluate via the ordinary 2-d (proc_h == 1) batched Summa; |
| 1357 | +// dist_no_externals_3d_grid exercises the 3-d (proc_h > 1) grid, where the |
| 1358 | +// heuristic spreads ranks over the slab dimension because M == N == 1. |
| 1359 | +BOOST_AUTO_TEST_SUITE(general_product_distributed_suite) |
| 1360 | + |
| 1361 | +// the fixtures/helpers live in general_product_suite's anonymous namespace |
| 1362 | +using general_product_suite::diff_norm; |
| 1363 | +using general_product_suite::diff_norm_sp; |
| 1364 | +using general_product_suite::ForceLegacyEinsum; |
| 1365 | +using general_product_suite::make_patterned_array; |
| 1366 | +using general_product_suite::make_patterned_sparse_array; |
| 1367 | +using general_product_suite::make_patterned_tot_array; |
| 1368 | +using general_product_suite::TArrayToT; |
| 1369 | +using general_product_suite::tot_max_abs_diff; |
| 1370 | + |
| 1371 | +BOOST_AUTO_TEST_CASE(dist_dense) { |
| 1372 | + // batched general product: b fused, j contracted, i/k free |
| 1373 | + auto& world = TA::get_default_world(); |
| 1374 | + ForceLegacyEinsum legacy_oracle; |
| 1375 | + TA::TiledRange tr_a{{0, 2, 4}, {0, 2, 3}, {0, 2, 5}}; // b, i, j |
| 1376 | + TA::TiledRange tr_b{{0, 2, 4}, {0, 2, 5}, {0, 3, 4}}; // b, j, k |
| 1377 | + auto a = make_patterned_array(world, tr_a, 1.0); |
| 1378 | + auto b = make_patterned_array(world, tr_b, 2.0); |
| 1379 | + TA::TArrayD c; |
| 1380 | + BOOST_REQUIRE_NO_THROW(c("b,i,k") = a("b,i,j") * b("b,j,k")); |
| 1381 | + auto c_ref = TA::einsum(a("b,i,j"), b("b,j,k"), "b,i,k"); |
| 1382 | + BOOST_CHECK_SMALL(diff_norm(c, c_ref, "b,i,k"), 1e-10); |
| 1383 | +} |
| 1384 | + |
| 1385 | +BOOST_AUTO_TEST_CASE(dist_sparse) { |
| 1386 | + // block-sparse batched general product (SparseShape::gemm_batched + |
| 1387 | + // the sparse (h,k)-keyed Summa groups, across ranks) |
| 1388 | + auto& world = TA::get_default_world(); |
| 1389 | + ForceLegacyEinsum legacy_oracle; |
| 1390 | + TA::TiledRange tr_a{{0, 2, 5}, {0, 3, 4}, {0, 2, 6, 7}}; // b, i, j |
| 1391 | + TA::TiledRange tr_b{{0, 2, 5}, {0, 2, 6, 7}, {0, 4, 5}}; // b, j, k |
| 1392 | + auto a = make_patterned_sparse_array(world, tr_a, 1.0, 3); |
| 1393 | + auto b = make_patterned_sparse_array(world, tr_b, 2.0, 4); |
| 1394 | + TA::TSpArrayD c; |
| 1395 | + BOOST_REQUIRE_NO_THROW(c("b,i,k") = a("b,i,j") * b("b,j,k")); |
| 1396 | + auto c_ref = TA::einsum(a("b,i,j"), b("b,j,k"), "b,i,k"); |
| 1397 | + BOOST_CHECK_SMALL(diff_norm_sp(c, c_ref, "b,i,k"), 1e-10); |
| 1398 | +} |
| 1399 | + |
| 1400 | +BOOST_AUTO_TEST_CASE(dist_tot_mixed) { |
| 1401 | + // mixed T x ToT general product (inner Scale) across ranks |
| 1402 | + auto& world = TA::get_default_world(); |
| 1403 | + ForceLegacyEinsum legacy_oracle; |
| 1404 | + TA::TiledRange tr_a{{0, 2, 4}, {0, 2, 3}, {0, 2, 5}}; // b, i, j |
| 1405 | + TA::TiledRange tr_b{{0, 2, 4}, {0, 2, 5}, {0, 3, 4}}; // b, j, k |
| 1406 | + auto a = make_patterned_array(world, tr_a, 1.0); |
| 1407 | + auto b = make_patterned_tot_array(world, tr_b, {3}, 2.0); |
| 1408 | + TArrayToT c; |
| 1409 | + BOOST_REQUIRE_NO_THROW(c("b,i,k;m") = a("b,i,j") * b("b,j,k;m")); |
| 1410 | + auto c_ref = TA::einsum(a("b,i,j"), b("b,j,k;m"), "b,i,k;m"); |
| 1411 | + BOOST_CHECK_SMALL(tot_max_abs_diff(c, c_ref), 1e-10); |
| 1412 | +} |
| 1413 | + |
| 1414 | +BOOST_AUTO_TEST_CASE(dist_no_externals_dense) { |
| 1415 | + // no-external general product (Hadamard reduction shape) across ranks; |
| 1416 | + // the synthetic unit left-external mode handling under distribution |
| 1417 | + auto& world = TA::get_default_world(); |
| 1418 | + ForceLegacyEinsum legacy_oracle; |
| 1419 | + TA::TiledRange tr{{0, 2, 4}, {0, 3, 5}}; // i, j |
| 1420 | + auto a = make_patterned_array(world, tr, 1.0); |
| 1421 | + auto b = make_patterned_array(world, tr, 2.0); |
| 1422 | + TA::TArrayD c; |
| 1423 | + BOOST_REQUIRE_NO_THROW(c("i") = a("i,j") * b("i,j")); |
| 1424 | + auto c_ref = TA::einsum(a("i,j"), b("i,j"), "i"); |
| 1425 | + BOOST_CHECK_SMALL(diff_norm(c, c_ref, "i"), 1e-10); |
| 1426 | +} |
| 1427 | + |
| 1428 | +BOOST_AUTO_TEST_CASE(dist_no_externals_tot) { |
| 1429 | + // no-external ToT general product across ranks |
| 1430 | + auto& world = TA::get_default_world(); |
| 1431 | + ForceLegacyEinsum legacy_oracle; |
| 1432 | + TA::TiledRange tr{{0, 3, 5}, {0, 2, 4}, {0, 2, 3}}; // x, i, j |
| 1433 | + auto a = make_patterned_tot_array(world, tr, {2}, 1.0); |
| 1434 | + auto b = make_patterned_tot_array(world, tr, {3}, 2.0); |
| 1435 | + TArrayToT c; |
| 1436 | + BOOST_REQUIRE_NO_THROW(c("i,j;a,b") = a("x,i,j;a") * b("x,i,j;b")); |
| 1437 | + auto c_ref = TA::einsum(a("x,i,j;a"), b("x,i,j;b"), "i,j;a,b"); |
| 1438 | + BOOST_CHECK_SMALL(tot_max_abs_diff(c, c_ref), 1e-10); |
| 1439 | +} |
| 1440 | + |
| 1441 | +BOOST_AUTO_TEST_CASE(dist_inner_node_thc) { |
| 1442 | + // THC reconstruction in one expression (general products at inner nodes) |
| 1443 | + // across ranks |
| 1444 | + auto& world = TA::get_default_world(); |
| 1445 | + TA::TiledRange tr_x{{0, 2, 4}, {0, 3, 5}}; // orbital x auxiliary |
| 1446 | + TA::TiledRange tr_z{{0, 3, 5}, {0, 3, 5}}; // auxiliary x auxiliary |
| 1447 | + auto x = make_patterned_array(world, tr_x, 1.0); |
| 1448 | + auto z = make_patterned_array(world, tr_z, 2.0); |
| 1449 | + TA::TArrayD g; |
| 1450 | + BOOST_REQUIRE_NO_THROW(g("p,q,r,s") = x("p,r1") * x("q,r1") * z("r1,r2") * |
| 1451 | + x("r,r2") * x("s,r2")); |
| 1452 | + TA::TArrayD i1, i2, i3, g_ref; |
| 1453 | + i1("r1,p,q") = x("p,r1") * x("q,r1"); |
| 1454 | + i2("p,q,r2") = i1("r1,p,q") * z("r1,r2"); |
| 1455 | + i3("r2,p,q,r") = i2("p,q,r2") * x("r,r2"); |
| 1456 | + g_ref("p,q,r,s") = i3("r2,p,q,r") * x("s,r2"); |
| 1457 | + BOOST_CHECK_SMALL(diff_norm(g, g_ref, "p,q,r,s"), 1e-10); |
| 1458 | +} |
| 1459 | + |
| 1460 | +BOOST_AUTO_TEST_CASE(dist_no_externals_3d_grid) { |
| 1461 | + // a no-external product with several slabs: at np>1 the heuristic engages |
| 1462 | + // the 3-d grid (M=N=1 ⇒ proc_h > 1, the ranks spread over the slab axis), |
| 1463 | + // so the result tiles distribute across the h-planes rather than piling on |
| 1464 | + // one rank. Exercises the cross-plane result-tile transfer. |
| 1465 | + auto& world = TA::get_default_world(); |
| 1466 | + ForceLegacyEinsum legacy_oracle; |
| 1467 | + TA::TiledRange tr{{0, 2, 4, 6}, {0, 3, 5}}; // i (3 tiles), j |
| 1468 | + auto a = make_patterned_array(world, tr, 1.0); |
| 1469 | + auto b = make_patterned_array(world, tr, 2.0); |
| 1470 | + TA::TArrayD c; |
| 1471 | + BOOST_REQUIRE_NO_THROW(c("i") = a("i,j") * b("i,j")); |
| 1472 | + auto c_ref = TA::einsum(a("i,j"), b("i,j"), "i"); |
| 1473 | + BOOST_CHECK_SMALL(diff_norm(c, c_ref, "i"), 1e-10); |
| 1474 | + |
| 1475 | + // at np>1 the no-external result must NOT all live on one rank (the |
| 1476 | + // degeneracy the 3-d grid fixes) |
| 1477 | + if (world.size() > 1) { |
| 1478 | + std::set<std::size_t> owners; |
| 1479 | + for (std::size_t o = 0; o < c.trange().tiles_range().volume(); ++o) |
| 1480 | + owners.insert(c.pmap()->owner(o)); |
| 1481 | + BOOST_CHECK_GT(owners.size(), 1u); |
| 1482 | + } |
| 1483 | +} |
| 1484 | + |
| 1485 | +BOOST_AUTO_TEST_SUITE_END() |
0 commit comments