From c68cff3825c54f5e4649fe1c6579ae5e8ee52cbd Mon Sep 17 00:00:00 2001 From: Ying-Jer Kao Date: Mon, 6 Jul 2026 08:48:49 +0800 Subject: [PATCH 1/2] fix(tests): match blocks by qindices in apply() pybind test helper The two BlockFermionicUniTensor apply()/apply_() signflip tests failed because _are_nearly_eq compared get_blocks_() by list position, but block order is not canonical: permute().contiguous() keeps the source tensor's block enumeration order, while a freshly constructed reference enumerates blocks in canonical qnum order. The backend apply() output is element-wise identical to the C++ LinAlgElementwise expectation; only the comparison was wrong. Match blocks by get_qindices() and require signflip() flags to agree before comparing raw block data, mirroring the C++ AreNearlyEqUniTensor (tests/test_tools.cpp) while staying sensitive to whether apply() actually folded the pending signs in. Also use the public Bond redirect_() instead of the c_redirect_ shadow binding. Co-Authored-By: Claude Fable 5 --- tests/test_apply_pybind.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/tests/test_apply_pybind.py b/tests/test_apply_pybind.py index abaa4af42..82d965a9f 100644 --- a/tests/test_apply_pybind.py +++ b/tests/test_apply_pybind.py @@ -13,14 +13,30 @@ # --------------------------------------------------------------------------- def _are_nearly_eq(a, b, tol=1e-12): - """Return True if two UniTensors have the same labels and nearly equal values.""" + """Return True if two block UniTensors have nearly equal raw block data. + + Blocks are matched by their quantum-number indices, not by position: + e.g. permute().contiguous() keeps the source tensor's block enumeration + order, which differs from that of a freshly constructed tensor (see the + C++ AreNearlyEqUniTensor in tests/test_tools.cpp). Pending signflips must + agree so that raw block data can be compared directly -- this keeps the + comparison sensitive to whether apply() actually folded the signs in. + """ a = a.permute(b.labels()) blocks_a = a.get_blocks_() blocks_b = b.get_blocks_() if len(blocks_a) != len(blocks_b): return False - for ba, bb in zip(blocks_a, blocks_b): - if (ba - bb).Norm().item() > tol: + flips_a = a.signflip() + flips_b = b.signflip() + idx_b = {tuple(b.get_qindices(j)): j for j in range(len(blocks_b))} + for i, ba in enumerate(blocks_a): + j = idx_b.get(tuple(a.get_qindices(i))) + if j is None: + return False + if flips_a[i] != flips_b[j]: + return False + if (ba - blocks_b[j]).Norm().item() > tol: return False return True @@ -30,7 +46,7 @@ def _make_bfut3(): fp = cytnx.Symmetry.FermionParity() B1 = cytnx.Bond(cytnx.BD_IN, [cytnx.Qs(0) >> 1, cytnx.Qs(1) >> 1], [fp]) B2 = cytnx.Bond(cytnx.BD_IN, [cytnx.Qs(0) >> 1, cytnx.Qs(1) >> 1], [fp]) - B12 = B1.combineBond(B2).c_redirect_() + B12 = B1.combineBond(B2).redirect_() B3 = cytnx.Bond(cytnx.BD_OUT, [cytnx.Qs(0) >> 1, cytnx.Qs(1) >> 1], [fp]) B4 = cytnx.Bond(cytnx.BD_IN, [cytnx.Qs(0) >> 1, cytnx.Qs(1) >> 1], [fp]) From 52091dcb09712a7c4530aa4a5721d4982d77fa6b Mon Sep 17 00:00:00 2001 From: Ying-Jer Kao Date: Mon, 13 Jul 2026 13:51:53 +0800 Subject: [PATCH 2/2] test(apply): relocate apply test to pytests/ so CI runs it The apply() pybind tests lived in tests/test_apply_pybind.py, but CI only runs `pytest pytests/` (ci-cmake_tests.yml), which does not discover files under tests/. So the helper fix in this PR was never enforced by CI -- the now-passing tests stayed silently unrun. Move the file to pytests/apply_test.py (matching the pytests/ *_test.py naming) so CI discovers and enforces it. Pure relocation: the test body is unchanged and self-contained (imports only pytest + cytnx). Verified against current master: pytests/apply_test.py -> 9 passed; full pytests/ -> 135 passed, 1 skipped. Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/test_apply_pybind.py => pytests/apply_test.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/test_apply_pybind.py => pytests/apply_test.py (100%) diff --git a/tests/test_apply_pybind.py b/pytests/apply_test.py similarity index 100% rename from tests/test_apply_pybind.py rename to pytests/apply_test.py