Skip to content

Commit 7c5d1c2

Browse files
committed
tests: inner-node general products (THC, depth-2, non-canonical root target)
1 parent e9980d1 commit 7c5d1c2

1 file changed

Lines changed: 59 additions & 15 deletions

File tree

tests/general_product.cpp

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -235,26 +235,70 @@ BOOST_AUTO_TEST_CASE(expression_general_product_dense_batched_outer) {
235235
BOOST_CHECK_SMALL(diff_norm(c, c_ref, "b,i,k"), 1e-10);
236236
}
237237

238-
BOOST_AUTO_TEST_CASE(expression_general_product_inner_node_gated) {
239-
// THC-style reconstruction:
238+
BOOST_AUTO_TEST_CASE(expression_general_product_noncanonical_root_target) {
239+
// a root-level general product with a NON-canonical target layout: the
240+
// product evaluates canonically (r1,p,q) and is re-permuted to the target
241+
// by the streaming unary eval
242+
auto& world = TA::get_default_world();
243+
TA::TiledRange tr_x{{0, 2, 4}, {0, 3, 5}}; // orbital x auxiliary
244+
auto x = make_patterned_array(world, tr_x, 1.0);
245+
246+
TA::TArrayD w, i1, w_ref;
247+
BOOST_REQUIRE_NO_THROW(w("p,q,r1") = x("p,r1") * x("q,r1"));
248+
i1("r1,p,q") = x("p,r1") * x("q,r1"); // canonical evaluation
249+
w_ref("p,q,r1") = i1("r1,p,q"); // plain permute assignment
250+
251+
BOOST_CHECK_SMALL(diff_norm(w, w_ref, "p,q,r1"), 1e-10);
252+
}
253+
254+
BOOST_AUTO_TEST_CASE(expression_general_product_inner_node_depth2) {
255+
// minimal inner-node case: a general product (fused r1) feeding a
256+
// contraction over r1 -- the general child evaluates canonically
257+
// (r1,p,q) and is re-permuted on the fly to the consumer's GEMM layout
258+
auto& world = TA::get_default_world();
259+
TA::TiledRange tr_x{{0, 2, 4}, {0, 3, 5}}; // orbital x auxiliary
260+
TA::TiledRange tr_z{{0, 3, 5}, {0, 3, 5}}; // auxiliary x auxiliary
261+
auto x = make_patterned_array(world, tr_x, 1.0);
262+
auto z = make_patterned_array(world, tr_z, 2.0);
263+
264+
TA::TArrayD w;
265+
BOOST_REQUIRE_NO_THROW(w("p,q,r2") = (x("p,r1") * x("q,r1")) * z("r1,r2"));
266+
267+
TA::TArrayD i1, w_ref;
268+
i1("r1,p,q") = x("p,r1") * x("q,r1");
269+
w_ref("p,q,r2") = i1("r1,p,q") * z("r1,r2");
270+
271+
BOOST_CHECK_SMALL(diff_norm(w, w_ref, "p,q,r2"), 1e-10);
272+
}
273+
274+
BOOST_AUTO_TEST_CASE(expression_general_product_inner_node_thc) {
275+
// THC-style reconstruction in ONE expression:
240276
// g("p,q,r,s") = X("p,r1") * X("q,r1") * Z("r1,r2") * X("r,r2") * X("s,r2")
241-
// r1 is fused in X("p,r1") * X("q,r1") but contracted downstream. The
242-
// first product is an INNER node of the expression tree, where the role of
243-
// r1 cannot be deduced bottom-up (the target reaches only the root);
244-
// resolving this requires top-down index-set deduction (deferred). Until
245-
// then: an informative error, not garbage (bottom-up, X*X would contract
246-
// r1, orphaning the r1 of Z).
277+
// r1 is fused in X("p,r1") * X("q,r1") but contracted downstream, so the
278+
// first product is a general product at an INNER node of the (left-deep)
279+
// expression tree. The top-down index-set deduction demands r1 of the X*X
280+
// node (its consumer carries it) and contracts it where Z meets that
281+
// subtree; higher up, r1 is dropped from the demand (consumed entirely
282+
// within). Verified against the same chain staged through explicit
283+
// intermediates (the pre-deduction recipe, itself differential-tested
284+
// against einsum in expression_general_product_thc_intermediates).
247285
auto& world = TA::get_default_world();
248286
TA::TiledRange tr_x{{0, 2, 4}, {0, 3, 5}}; // orbital x auxiliary
249287
TA::TiledRange tr_z{{0, 3, 5}, {0, 3, 5}}; // auxiliary x auxiliary
250-
TA::TArrayD x(world, tr_x);
251-
TA::TArrayD z(world, tr_z);
252-
x.fill(1.0);
253-
z.fill(1.0);
288+
auto x = make_patterned_array(world, tr_x, 1.0);
289+
auto z = make_patterned_array(world, tr_z, 2.0);
290+
254291
TA::TArrayD g;
255-
BOOST_CHECK_THROW(
256-
g("p,q,r,s") = x("p,r1") * x("q,r1") * z("r1,r2") * x("r,r2") * x("s,r2"),
257-
TiledArray::Exception);
292+
BOOST_REQUIRE_NO_THROW(g("p,q,r,s") = x("p,r1") * x("q,r1") * z("r1,r2") *
293+
x("r,r2") * x("s,r2"));
294+
295+
TA::TArrayD i1, i2, i3, g_ref;
296+
i1("r1,p,q") = x("p,r1") * x("q,r1");
297+
i2("p,q,r2") = i1("r1,p,q") * z("r1,r2");
298+
i3("r2,p,q,r") = i2("p,q,r2") * x("r,r2");
299+
g_ref("p,q,r,s") = i3("r2,p,q,r") * x("s,r2");
300+
301+
BOOST_CHECK_SMALL(diff_norm(g, g_ref, "p,q,r,s"), 1e-10);
258302
}
259303

260304
BOOST_AUTO_TEST_CASE(expression_general_product_thc_intermediates) {

0 commit comments

Comments
 (0)