diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..6007871 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,27 @@ +name: Run pyECT E2E Tests + +on: + pull_request: + branches: ["main"] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install dependencies + run: | + pip install --upgrade pip + pip install pytest + pip install -e . + + - name: Run tests + run: pytest tests/ diff --git a/tests/compiled_image_ecf_test.py b/examples/compilation/compiled_image_ecf_test.py similarity index 100% rename from tests/compiled_image_ecf_test.py rename to examples/compilation/compiled_image_ecf_test.py diff --git a/tests/compiled_wect_test.py b/examples/compilation/compiled_wect_test.py similarity index 100% rename from tests/compiled_wect_test.py rename to examples/compilation/compiled_wect_test.py diff --git a/pyproject.toml b/pyproject.toml index cabf9c7..7cc80ef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "pyect" -version = "0.1.7" +version = "0.1.8" description = "Generalized computation of the weighted Euler characteristic transform using PyTorch." readme = "README.md" requires-python = ">=3.8" diff --git a/tests/test_wect_triangle.py b/tests/test_wect_triangle.py new file mode 100644 index 0000000..1d418e4 --- /dev/null +++ b/tests/test_wect_triangle.py @@ -0,0 +1,72 @@ +import torch +import pytest + +from pyect import WECT +from pyect import Complex + + +def build_triangle_complexes(device="cpu"): + vcoords = torch.tensor( + [[-1.0, 0.0], + [ 0.0, 1.0], + [ 1.0, 0.0]], device=device + ) + vweights_ones = torch.ones(3, device=device) + vweights = torch.tensor([0.5, 1.0, 1.5], device=device) + + ecoords = torch.tensor( + [[0, 1], + [1, 2], + [2, 0]], device=device + ) + eweights_ones = torch.ones(3, device=device) + eweights = torch.tensor([.5, 1.0, 0.5], device=device) + + fcoords = torch.tensor([[0, 1, 2]], device=device) + fweights_ones = torch.ones(1, device=device) + fweights = torch.tensor([0.5], device=device) + + return Complex( + (vcoords, vweights_ones), + (ecoords, eweights_ones), + (fcoords, fweights_ones), + ), Complex( + (vcoords, vweights), + (ecoords, eweights), + (fcoords, fweights), + ), + + +# ---------------------------------------------------------- +# WECT TEST +# ---------------------------------------------------------- + +def test_wect_exact_triangle_direction_10(): + device = torch.device("cpu") + + complex_unweighted, complex_weighted = build_triangle_complexes(device=device) + + + # UNWEIGHTED COMPLEX + # single direction (1,0) + dirs = torch.tensor([[1.0, 0.0]], device=device) + + num_bins = 3 + wect = WECT(dirs, num_bins).eval() + + result = wect(complex_unweighted) # shape (1,3) + + assert result.shape == (1, num_bins) + assert torch.isfinite(result).all() + + expected = torch.tensor([1.0, 1.0, 1.0], device=device) + + assert torch.allclose(result[0], expected, atol=1e-6) + + # WEIGHTED COMPLEX + result = wect(complex_weighted) # shape (1,3) + assert result.shape == (1, num_bins) + assert torch.isfinite(result).all() + + expected = torch.tensor([0.5, 1.0, 1.5], device=device) + assert torch.allclose(result[0], expected, atol=1e-6)