From 2fdf67f12d4cd656e785d0d9d2bc633f0d7c1bc3 Mon Sep 17 00:00:00 2001 From: Gausshj Date: Fri, 1 Aug 2025 15:05:20 +0800 Subject: [PATCH 1/5] test(parity_tensor): add some tests on arithmetic --- .gitignore | 2 + test/test_parity_tensor.py | 134 +++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 test/test_parity_tensor.py diff --git a/.gitignore b/.gitignore index 2e5e403..8bc44c1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ env __pycache__ parity_tensor/_version.py build +.idea +.venv \ No newline at end of file diff --git a/test/test_parity_tensor.py b/test/test_parity_tensor.py new file mode 100644 index 0000000..fbd4ee1 --- /dev/null +++ b/test/test_parity_tensor.py @@ -0,0 +1,134 @@ +""" +[#22](https://github.com/hzhangxyz/parity_tensor/issues/22) +Test essential functions. +""" +import torch +import random +import pytest + +from parity_tensor import ParityTensor + + +@pytest.fixture( + params = [ParityTensor((False, False), ((2, 2), (1, 3)), torch.randn([4, 4])), + ParityTensor((False, False), ((2, 2) ,(1, 3)), torch.randn([4, 4]))] +) + +def parity_instance(request): + return request.param + +@pytest.fixture(params=[(0, 1)]) +def permute_tuple(request): + return request.param + +def test_arithmetic(parity_instance) -> None: + """Test the arithmetic.""" + # Test __pos__ method. + print("-" * 5, "Test __pos__ method", "-" * 5) + print(parity_instance) + print(+parity_instance) + # Test __neg__ method. + print("-" * 5, "Test __neg__ method", "-" * 5) + print(parity_instance) + print(-parity_instance) + # Test __add__ method. + print("-" * 5, "Test __add__ method", "-" * 5) + print(parity_instance) + print(parity_instance + 1) + # Test __radd__ method. + print("-" * 5, "Test __radd__ method", "-" * 5) + print(parity_instance) + print(1 + parity_instance) + # Test __iadd__ method. + print("-" * 5, "Test __iadd__ method", "-" * 5) + print(parity_instance) + parity_instance += 1 + print(parity_instance) + # Test __sub__ method. + print("-" * 5, "Test __sub__ method", "-" * 5) + print(parity_instance) + print(parity_instance - 1) + # Test __rsub__ method. + print("-" * 5, "Test __rsub__ method", "-" * 5) + print(parity_instance) + print(1 - parity_instance) + # Test __isub__ method. + print("-" * 5, "Test __isub__ method", "-" * 5) + print(parity_instance) + parity_instance -= 1 + print(parity_instance) + # Test __mul__ method. + print("-" * 5, "Test __mul__ method", "-" * 5) + print(parity_instance) + print(parity_instance * 2) + # Test __rmul__ method. + print("-" * 5, "Test __rmul__ method", "-" * 5) + print(parity_instance) + print(2 * parity_instance) + # Test __imul__ method. + print("-" * 5, "Test __imul__ method", "-" * 5) + print(parity_instance) + parity_instance *= 2 + print(parity_instance) + # Test __truediv__ method. + print("-" * 5, "Test __truediv__ method", "-" * 5) + print(parity_instance) + print(parity_instance / 2) + # Test __rtruediv__ method. + print("-" * 5, "Test __rtruediv__ method", "-" * 5) + print(parity_instance) + print(2 / parity_instance) + # Test __itruediv__ method. + print("-" * 5, "Test __itruediv__ method", "-" * 5) + print(parity_instance) + parity_instance /= 2 + print(parity_instance) + +def test_masking() -> None: + """Test masking.""" + pass + +def test_permute(parity_instance, permute_tuple) -> None: + """Test permute.""" + parity_instance.permute(permute_tuple) + +def test_reverse(parity_instance) -> None: + """Test tensor reverse.""" + print(parity_instance) + print(parity_instance) + +def test_split_edge() -> None: + """Test split edge.""" + pass + +def test_merge_edge() -> None: + """Test merge edge.""" + pass + +def test_contract() -> None: + """Test contract.""" + pass + +def test_trace() -> None: + """Test trace.""" + pass + +def test_conjugate() -> None: + """Test conjugate.""" + pass + +def test_svd() -> None: + """Test svd.""" + pass + +def test_qr() -> None: + """Test qr.""" + pass + +def test_identity() -> None: + """Test identity.""" + pass + +def test_exponential() -> None: + """Test tensor exponential.""" + pass \ No newline at end of file From 0f86f044d25b15027ae77de49c99b1c6a82c1028 Mon Sep 17 00:00:00 2001 From: Gausshj Date: Fri, 1 Aug 2025 15:14:28 +0800 Subject: [PATCH 2/5] fix: add missing newline at the end of the file --- test/test_parity_tensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_parity_tensor.py b/test/test_parity_tensor.py index fbd4ee1..c8dae5c 100644 --- a/test/test_parity_tensor.py +++ b/test/test_parity_tensor.py @@ -131,4 +131,4 @@ def test_identity() -> None: def test_exponential() -> None: """Test tensor exponential.""" - pass \ No newline at end of file + pass From aa0078c86ebe7193344bfee69765da79f38560e3 Mon Sep 17 00:00:00 2001 From: Gausshj Date: Fri, 1 Aug 2025 16:53:44 +0800 Subject: [PATCH 3/5] refactor!: reorganize project structure - move test into tests --- test/test_parity_tensor.py => tests/parity_tensor_test.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/test_parity_tensor.py => tests/parity_tensor_test.py (100%) diff --git a/test/test_parity_tensor.py b/tests/parity_tensor_test.py similarity index 100% rename from test/test_parity_tensor.py rename to tests/parity_tensor_test.py From 9e35506864115c0f5361e7881d8583309c93f209 Mon Sep 17 00:00:00 2001 From: Gausshj Date: Wed, 6 Aug 2025 11:14:11 +0800 Subject: [PATCH 4/5] test(#22): add new tests for arithmetic --- tests/parity_tensor_test.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/parity_tensor_test.py b/tests/parity_tensor_test.py index 65ba93d..218cffd 100644 --- a/tests/parity_tensor_test.py +++ b/tests/parity_tensor_test.py @@ -24,61 +24,84 @@ def permute_tuple_fixture(request: pytest.FixtureRequest) -> Tuple[int, int]: def test_arithmetic(parity_instance_fx: ParityTensor) -> None: """Test the arithmetic operators on ParityTensor.""" + instance = ParityTensor((False, False), ((2, 2), (1, 3)), torch.randn([4, 4])) # Test __pos__ method. print("-" * 5, "Test __pos__ method", "-" * 5) print(parity_instance_fx) print(+parity_instance_fx) + # Test __neg__ method. print("-" * 5, "Test __neg__ method", "-" * 5) print(parity_instance_fx) print(-parity_instance_fx) + # Test __add__ method. print("-" * 5, "Test __add__ method", "-" * 5) print(parity_instance_fx) print(parity_instance_fx + 1) + print(parity_instance_fx + instance) + # Test __radd__ method. print("-" * 5, "Test __radd__ method", "-" * 5) print(parity_instance_fx) print(1 + parity_instance_fx) + print(instance + parity_instance_fx) + # Test __iadd__ method. print("-" * 5, "Test __iadd__ method", "-" * 5) print(parity_instance_fx) parity_instance_fx += 1 print(parity_instance_fx) + parity_instance_fx += instance + print(parity_instance_fx) + # Test __sub__ method. print("-" * 5, "Test __sub__ method", "-" * 5) print(parity_instance_fx) print(parity_instance_fx - 1) + print(parity_instance_fx - instance) + # Test __rsub__ method. print("-" * 5, "Test __rsub__ method", "-" * 5) print(parity_instance_fx) print(1 - parity_instance_fx) + print(instance - parity_instance_fx) + # Test __isub__ method. print("-" * 5, "Test __isub__ method", "-" * 5) print(parity_instance_fx) parity_instance_fx -= 1 print(parity_instance_fx) + parity_instance_fx -= instance + print(parity_instance_fx) + # Test __mul__ method. print("-" * 5, "Test __mul__ method", "-" * 5) print(parity_instance_fx) print(parity_instance_fx * 2) + # Test __rmul__ method. print("-" * 5, "Test __rmul__ method", "-" * 5) print(parity_instance_fx) print(2 * parity_instance_fx) + # Test __imul__ method. print("-" * 5, "Test __imul__ method", "-" * 5) print(parity_instance_fx) parity_instance_fx *= 2 print(parity_instance_fx) + # Test __truediv__ method. print("-" * 5, "Test __truediv__ method", "-" * 5) print(parity_instance_fx) print(parity_instance_fx / 2) + print(parity_instance_fx / instance) + # Test __rtruediv__ method. print("-" * 5, "Test __rtruediv__ method", "-" * 5) print(parity_instance_fx) print(2 / parity_instance_fx) + # Test __itruediv__ method. print("-" * 5, "Test __itruediv__ method", "-" * 5) print(parity_instance_fx) From 247497a7d271df1edd8e1182fc48a2b38c312a25 Mon Sep 17 00:00:00 2001 From: Gausshj Date: Wed, 6 Aug 2025 17:17:46 +0800 Subject: [PATCH 5/5] test(#22): add and improve tests for masking and permute --- tests/parity_tensor_test.py | 135 +++++++++++++++++++++--------------- 1 file changed, 81 insertions(+), 54 deletions(-) diff --git a/tests/parity_tensor_test.py b/tests/parity_tensor_test.py index 218cffd..b98dad5 100644 --- a/tests/parity_tensor_test.py +++ b/tests/parity_tensor_test.py @@ -10,115 +10,142 @@ from parity_tensor import ParityTensor -@pytest.fixture(name="parity_instance_fx", params=[ParityTensor((False, False), ((2, 2), (1, 3)), torch.randn([4, 4])), ParityTensor((False, False), ((2, 2), (1, 3)), torch.randn([4, 4]))]) -def _parity_instance_fixture(request: pytest.FixtureRequest) -> ParityTensor: +@pytest.fixture(name="parity_instance_fx", + params=[( + ParityTensor((False, False), ((2, 2), (1, 3)), torch.randn([4, 4])), + ParityTensor((False, False), ((2, 2), (1, 3)), torch.randn([4, 4])), + ), ( + ParityTensor((True, False, True), ((1, 1), (2, 2), (3, 1)), torch.randn([2, 4, 4])), + ParityTensor((True, False, True), ((1, 1), (2, 2), (3, 1)), torch.randn([2, 4, 4])), + ), + (ParityTensor((True, True, False, False), ((1, 2), (2, 2), (1, 1), (3, 1)), + torch.randn([3, 4, 2, 4])), ParityTensor((True, True, False, False), ((1, 2), (2, 2), (1, 1), (3, 1)), torch.randn([3, 4, 2, 4])))]) +def _parity_instance_fixture(request: pytest.FixtureRequest) -> Tuple[ParityTensor, ParityTensor]: """Fixture for a parity tensor instance.""" return request.param -@pytest.fixture(name="permute_tuple_fx", params=[(0, 1)]) -def permute_tuple_fixture(request: pytest.FixtureRequest) -> Tuple[int, int]: +@pytest.fixture +def permute_tuple_fx(parity_instance_fx: Tuple[ParityTensor, ParityTensor]) -> Tuple[int, ...]: """Fixture for a permutation tuple.""" - return request.param + parity_tensor, _ = parity_instance_fx + rank = parity_tensor.tensor.ndim + return tuple(reversed(range(rank))) -def test_arithmetic(parity_instance_fx: ParityTensor) -> None: +def test_arithmetic(parity_instance_fx: Tuple[ParityTensor, ParityTensor]) -> None: """Test the arithmetic operators on ParityTensor.""" - instance = ParityTensor((False, False), ((2, 2), (1, 3)), torch.randn([4, 4])) + parity_tensor, instance = parity_instance_fx + # Test __pos__ method. print("-" * 5, "Test __pos__ method", "-" * 5) - print(parity_instance_fx) - print(+parity_instance_fx) + print(parity_tensor) + print(+parity_tensor) # Test __neg__ method. print("-" * 5, "Test __neg__ method", "-" * 5) - print(parity_instance_fx) - print(-parity_instance_fx) + print(parity_tensor) + print(-parity_tensor) # Test __add__ method. print("-" * 5, "Test __add__ method", "-" * 5) - print(parity_instance_fx) - print(parity_instance_fx + 1) - print(parity_instance_fx + instance) + print(parity_tensor) + print(parity_tensor + 1) + print(parity_tensor + instance) # Test __radd__ method. print("-" * 5, "Test __radd__ method", "-" * 5) - print(parity_instance_fx) - print(1 + parity_instance_fx) - print(instance + parity_instance_fx) + print(parity_tensor) + print(1 + parity_tensor) + print(instance + parity_tensor) # Test __iadd__ method. print("-" * 5, "Test __iadd__ method", "-" * 5) - print(parity_instance_fx) - parity_instance_fx += 1 - print(parity_instance_fx) - parity_instance_fx += instance - print(parity_instance_fx) + print(parity_tensor) + parity_tensor += 1 + print(parity_tensor) + parity_tensor += instance + print(parity_tensor) # Test __sub__ method. print("-" * 5, "Test __sub__ method", "-" * 5) - print(parity_instance_fx) - print(parity_instance_fx - 1) - print(parity_instance_fx - instance) + print(parity_tensor) + print(parity_tensor - 1) + print(parity_tensor - instance) # Test __rsub__ method. print("-" * 5, "Test __rsub__ method", "-" * 5) - print(parity_instance_fx) - print(1 - parity_instance_fx) - print(instance - parity_instance_fx) + print(parity_tensor) + print(1 - parity_tensor) + print(instance - parity_tensor) # Test __isub__ method. print("-" * 5, "Test __isub__ method", "-" * 5) - print(parity_instance_fx) - parity_instance_fx -= 1 - print(parity_instance_fx) - parity_instance_fx -= instance - print(parity_instance_fx) + print(parity_tensor) + parity_tensor -= 1 + print(parity_tensor) + parity_tensor -= instance + print(parity_tensor) # Test __mul__ method. print("-" * 5, "Test __mul__ method", "-" * 5) - print(parity_instance_fx) - print(parity_instance_fx * 2) + print(parity_tensor) + print(parity_tensor * 2) # Test __rmul__ method. print("-" * 5, "Test __rmul__ method", "-" * 5) - print(parity_instance_fx) - print(2 * parity_instance_fx) + print(parity_tensor) + print(2 * parity_tensor) # Test __imul__ method. print("-" * 5, "Test __imul__ method", "-" * 5) - print(parity_instance_fx) - parity_instance_fx *= 2 - print(parity_instance_fx) + print(parity_tensor) + parity_tensor *= 2 + print(parity_tensor) # Test __truediv__ method. print("-" * 5, "Test __truediv__ method", "-" * 5) - print(parity_instance_fx) - print(parity_instance_fx / 2) - print(parity_instance_fx / instance) + print(parity_tensor) + print(parity_tensor / 2) + print(parity_tensor / instance) # Test __rtruediv__ method. print("-" * 5, "Test __rtruediv__ method", "-" * 5) - print(parity_instance_fx) - print(2 / parity_instance_fx) + print(parity_tensor) + print(2 / parity_tensor) # Test __itruediv__ method. print("-" * 5, "Test __itruediv__ method", "-" * 5) - print(parity_instance_fx) - parity_instance_fx /= 2 - print(parity_instance_fx) + print(parity_tensor) + parity_tensor /= 2 + print(parity_tensor) -def test_masking() -> None: +def test_masking(parity_instance_fx: tuple[ParityTensor, ParityTensor]) -> None: """Test masking.""" - assert True + parity_tensor, _ = parity_instance_fx + + mask = parity_tensor.mask + assert mask.shape == parity_tensor.tensor.shape, "Mask shape mismatch" + + assert mask.dtype == torch.bool, "Mask must be of dtype bool" + + original_tensor = parity_tensor.tensor.clone() + update_tensor = parity_tensor.update_mask().tensor + + assert torch.all(update_tensor[~mask] == 0), "Masked-out positions must be zero" + + assert torch.all(update_tensor[mask] == original_tensor[mask]), ("Unmasked positions must be preserved") + + assert parity_tensor.mask is not None, "Mask should be cached after first access" -def test_permute(parity_instance_fx: ParityTensor, permute_tuple_fx: Tuple[int, ...]) -> None: +def test_permute(parity_instance_fx: Tuple[ParityTensor, ParityTensor], permute_tuple_fx: Tuple[int, ...]) -> None: """Test permute.""" - print(parity_instance_fx) - parity_instance_fx.permute(permute_tuple_fx) - print(parity_instance_fx) + parity_tensor, _ = parity_instance_fx + print("Before permute:", parity_tensor) + parity_tensor.permute(permute_tuple_fx) + print("After permute:", parity_tensor) def test_reverse() -> None: