From 4e8a33fda3a402ac8132320a3a90506bb1a38164 Mon Sep 17 00:00:00 2001 From: "Michael A. Perlin" Date: Tue, 16 Jun 2026 15:16:07 -0400 Subject: [PATCH 01/11] simpler abstract algebra tests --- src/qldpc/abstract/rings_test.py | 24 +++++++++--------- src/qldpc/abstract/wedderburn_artin_test.py | 14 ++++++++++- src/qldpc/conftest.py | 28 +++++++++++++++------ 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/qldpc/abstract/rings_test.py b/src/qldpc/abstract/rings_test.py index b3f79a235..d9c8b941b 100644 --- a/src/qldpc/abstract/rings_test.py +++ b/src/qldpc/abstract/rings_test.py @@ -219,7 +219,7 @@ def test_regular_rep(ring: abstract.GroupRing, pytestconfig: pytest.Config) -> N def test_ring_row_reduction( - ring_alternating4_gf5: abstract.GroupRing, pytestconfig: pytest.Config + ring_dihedral3_gf5: abstract.GroupRing, pytestconfig: pytest.Config ) -> None: """RingArrays can be row reduced in various ways.""" np.random.seed(pytestconfig.getoption("randomly_seed")) @@ -246,25 +246,25 @@ def test_ring_row_reduction( assert np.array_equal(matrix.howell_normal_form(poly=True), matrix_hnf) # matrix components of non-commutative rings get "standardized" to place pivots on the diagonal - ring = ring_alternating4_gf5 + ring = ring_dihedral3_gf5 transformer = ring.get_transformer() component_transformer = transformer.transformers[-1] - e3_13 = component_transformer.embed( - component_transformer.extended_field([[0, 0, 1], [0, 0, 0], [0, 0, 0]]) + e2_12 = component_transformer.embed( + component_transformer.extended_field([[0, 1], [0, 0]]) ) - e3_31 = component_transformer.embed( - component_transformer.extended_field([[0, 0, 0], [0, 0, 0], [1, 0, 0]]) + e2_21 = component_transformer.embed( + component_transformer.extended_field([[0, 0], [1, 0]]) ) - e3_33 = component_transformer.embed( - component_transformer.extended_field([[0, 0, 0], [0, 0, 0], [0, 0, 1]]) + e2_22 = component_transformer.embed( + component_transformer.extended_field([[0, 0], [0, 1]]) ) assert np.array_equal( - abstract.RingArray.build([[e3_13]]).howell_normal_form_semisimple(), - abstract.RingArray.build([[e3_33]]), + abstract.RingArray.build([[e2_12]]).howell_normal_form_semisimple(), + abstract.RingArray.build([[e2_22]]), ) assert np.array_equal( - abstract.RingArray.build([[e3_31]]).howell_normal_form_semisimple(right=True), - abstract.RingArray.build([[e3_33]]), + abstract.RingArray.build([[e2_21]]).howell_normal_form_semisimple(right=True), + abstract.RingArray.build([[e2_22]]), ) # RingArray.row_reduce requires semisimple rings diff --git a/src/qldpc/abstract/wedderburn_artin_test.py b/src/qldpc/abstract/wedderburn_artin_test.py index ab6a7681b..51f607566 100644 --- a/src/qldpc/abstract/wedderburn_artin_test.py +++ b/src/qldpc/abstract/wedderburn_artin_test.py @@ -32,7 +32,7 @@ def test_wedderburn_artin_transformations( ) -> None: """Decompose semisimple rings into simple components. - Runs for GroupRing(CyclicGroup(3), field=4) and GroupRing(AlternatingGroup(4), field=5). + Runs for GroupRing(CyclicGroup(3), field=4) and GroupRing(DihedralGroup(3), field=5). """ seed = pytestconfig.getoption("randomly_seed") @@ -122,6 +122,18 @@ def get_random_ring_member(ring: abstract.GroupRing, seed: int) -> abstract.Ring return abstract.RingMember(ring, *terms) +def test_matrix_basis_size_three(ring_alternating4_gf5: abstract.GroupRing) -> None: + """The matrix basis construction uses cross-terms for components of size >= 3. + + AlternatingGroup(4) is the smallest group with a 3-dimensional irreducible representation, + giving a Wedderburn-Artin component of size=3 that exercises the off-diagonal construction + loop in _get_matrix_basis (which only runs when size >= 3). + """ + transformer = ring_alternating4_gf5.get_transformer() + size_three_ct = next(ct for ct in transformer.transformers if ct.size == 3) + assert size_three_ct.matrix_basis.shape == (9, ring_alternating4_gf5.group.order) + + def test_wedderburn_artin_errors( ring_cyclic3_gf2: abstract.GroupRing, pytestconfig: pytest.Config ) -> None: diff --git a/src/qldpc/conftest.py b/src/qldpc/conftest.py index ba604841b..c25d03999 100644 --- a/src/qldpc/conftest.py +++ b/src/qldpc/conftest.py @@ -23,27 +23,41 @@ def ring_cyclic3_gf4(pytestconfig: pytest.Config) -> abstract.GroupRing: return ring +@pytest.fixture(scope="session") +def ring_dihedral3_gf5(pytestconfig: pytest.Config) -> abstract.GroupRing: + """Construct a non-commutative ring with a pre-built Wedderburn-Artin transformer. + + Uses DihedralGroup(3) over GF(5), whose primitive central idempotents are pre-cached in + KNOWN_PRIMITIVE_CENTRAL_IDEMPOTENTS (avoiding a GAP computation). + """ + ring = abstract.GroupRing(abstract.DihedralGroup(3), field=5) + ring.get_transformer(seed=pytestconfig.getoption("randomly_seed")) + return ring + + @pytest.fixture(scope="session") def ring_alternating4_gf5(pytestconfig: pytest.Config) -> abstract.GroupRing: - """Construct a non-commutative ring with a pre-built Wedderburn-Artin transformer.""" + """Construct a non-commutative ring with a size-3 matrix component. + + Used specifically to test WedderburnArtinComponentTransformer code paths that only + arise for matrix components of size >= 3 (A4 is the smallest group with a 3-dim irrep). + """ ring = abstract.GroupRing(abstract.AlternatingGroup(4), field=5) ring.get_transformer(seed=pytestconfig.getoption("randomly_seed")) return ring -@pytest.fixture(name="ring", scope="session", params=["cyclic3_gf4", "alternating4_gf5"]) +@pytest.fixture(name="ring", scope="session", params=["cyclic3_gf4", "dihedral3_gf5"]) def rings_to_test( request: pytest.FixtureRequest, ring_cyclic3_gf2: abstract.GroupRing, ring_cyclic3_gf4: abstract.GroupRing, - ring_alternating4_gf5: abstract.GroupRing, + ring_dihedral3_gf5: abstract.GroupRing, ) -> abstract.GroupRing: """Retrieve a ring for which we have pre-built a Wedderburn-Artin transformer.""" match request.param: - case "cyclic3_gf2": - return ring_cyclic3_gf2 case "cyclic3_gf4": return ring_cyclic3_gf4 - case "alternating4_gf5": - return ring_alternating4_gf5 + case "dihedral3_gf5": + return ring_dihedral3_gf5 raise ValueError(f"Invalid fixture name: {request.param}") # pragma: no cover From 01f09cfe13d9ca3b87b980e4f996abdfc49d9491 Mon Sep 17 00:00:00 2001 From: "Michael A. Perlin" Date: Tue, 16 Jun 2026 15:31:09 -0400 Subject: [PATCH 02/11] docstring update --- src/qldpc/abstract/wedderburn_artin_test.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/qldpc/abstract/wedderburn_artin_test.py b/src/qldpc/abstract/wedderburn_artin_test.py index 51f607566..6b522ce0a 100644 --- a/src/qldpc/abstract/wedderburn_artin_test.py +++ b/src/qldpc/abstract/wedderburn_artin_test.py @@ -123,11 +123,16 @@ def get_random_ring_member(ring: abstract.GroupRing, seed: int) -> abstract.Ring def test_matrix_basis_size_three(ring_alternating4_gf5: abstract.GroupRing) -> None: - """The matrix basis construction uses cross-terms for components of size >= 3. + """The matrix basis construction handles size-3 components correctly. + + _get_matrix_basis builds the standard basis {|i><0|) directly + from projections, then it derives the remaining off-diagonal elements |i>= 1) as + compositions |i><0|·|0>= 3 (for size=2 there are no + pairs (i,j) with i,j >= 1). AlternatingGroup(4) is the smallest group with a 3-dimensional irreducible representation, - giving a Wedderburn-Artin component of size=3 that exercises the off-diagonal construction - loop in _get_matrix_basis (which only runs when size >= 3). + giving a size=3 Wedderburn-Artin component that exercises this second phase. """ transformer = ring_alternating4_gf5.get_transformer() size_three_ct = next(ct for ct in transformer.transformers if ct.size == 3) From de4d2146b0d112b43214f9fe155cf0a8b7752e0f Mon Sep 17 00:00:00 2001 From: "Michael A. Perlin" Date: Tue, 16 Jun 2026 15:31:32 -0400 Subject: [PATCH 03/11] formatting fix --- src/qldpc/abstract/rings_test.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/qldpc/abstract/rings_test.py b/src/qldpc/abstract/rings_test.py index d9c8b941b..fe95bbc45 100644 --- a/src/qldpc/abstract/rings_test.py +++ b/src/qldpc/abstract/rings_test.py @@ -249,15 +249,9 @@ def test_ring_row_reduction( ring = ring_dihedral3_gf5 transformer = ring.get_transformer() component_transformer = transformer.transformers[-1] - e2_12 = component_transformer.embed( - component_transformer.extended_field([[0, 1], [0, 0]]) - ) - e2_21 = component_transformer.embed( - component_transformer.extended_field([[0, 0], [1, 0]]) - ) - e2_22 = component_transformer.embed( - component_transformer.extended_field([[0, 0], [0, 1]]) - ) + e2_12 = component_transformer.embed(component_transformer.extended_field([[0, 1], [0, 0]])) + e2_21 = component_transformer.embed(component_transformer.extended_field([[0, 0], [1, 0]])) + e2_22 = component_transformer.embed(component_transformer.extended_field([[0, 0], [0, 1]])) assert np.array_equal( abstract.RingArray.build([[e2_12]]).howell_normal_form_semisimple(), abstract.RingArray.build([[e2_22]]), From 6c15b9c20f55bc7279c87840fe013a39c1b8ec54 Mon Sep 17 00:00:00 2001 From: "Michael A. Perlin" Date: Tue, 16 Jun 2026 16:34:26 -0400 Subject: [PATCH 04/11] minor test fixes --- src/qldpc/abstract/wedderburn_artin_test.py | 5 ++++- src/qldpc/conftest.py | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/qldpc/abstract/wedderburn_artin_test.py b/src/qldpc/abstract/wedderburn_artin_test.py index 6b522ce0a..28d0337ef 100644 --- a/src/qldpc/abstract/wedderburn_artin_test.py +++ b/src/qldpc/abstract/wedderburn_artin_test.py @@ -136,7 +136,10 @@ def test_matrix_basis_size_three(ring_alternating4_gf5: abstract.GroupRing) -> N """ transformer = ring_alternating4_gf5.get_transformer() size_three_ct = next(ct for ct in transformer.transformers if ct.size == 3) - assert size_three_ct.matrix_basis.shape == (9, ring_alternating4_gf5.group.order) + assert size_three_ct.matrix_basis.shape == ( + size_three_ct.size**2, + ring_alternating4_gf5.group.order, + ) def test_wedderburn_artin_errors( diff --git a/src/qldpc/conftest.py b/src/qldpc/conftest.py index c25d03999..9fe92b0d4 100644 --- a/src/qldpc/conftest.py +++ b/src/qldpc/conftest.py @@ -50,7 +50,6 @@ def ring_alternating4_gf5(pytestconfig: pytest.Config) -> abstract.GroupRing: @pytest.fixture(name="ring", scope="session", params=["cyclic3_gf4", "dihedral3_gf5"]) def rings_to_test( request: pytest.FixtureRequest, - ring_cyclic3_gf2: abstract.GroupRing, ring_cyclic3_gf4: abstract.GroupRing, ring_dihedral3_gf5: abstract.GroupRing, ) -> abstract.GroupRing: From 0ba2083bd782b37611692efae01289597ae105ce Mon Sep 17 00:00:00 2001 From: "Michael A. Perlin" Date: Tue, 16 Jun 2026 16:36:25 -0400 Subject: [PATCH 05/11] increase timeout limit --- .github/workflows/continuous-integration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index c8e8377e8..eec5b96a4 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -80,7 +80,7 @@ jobs: name: Pytest and coverage check if: github.event.pull_request.draft == false runs-on: ubuntu-latest - timeout-minutes: 6 + timeout-minutes: 7 needs: install steps: - uses: actions/checkout@v6 From d5db1e59577c37f89ce5f981eb1e16715cdc8366 Mon Sep 17 00:00:00 2001 From: "Michael A. Perlin" Date: Tue, 16 Jun 2026 16:40:17 -0400 Subject: [PATCH 06/11] robust extraction --- src/qldpc/abstract/rings_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qldpc/abstract/rings_test.py b/src/qldpc/abstract/rings_test.py index fe95bbc45..d5d7c688f 100644 --- a/src/qldpc/abstract/rings_test.py +++ b/src/qldpc/abstract/rings_test.py @@ -248,7 +248,7 @@ def test_ring_row_reduction( # matrix components of non-commutative rings get "standardized" to place pivots on the diagonal ring = ring_dihedral3_gf5 transformer = ring.get_transformer() - component_transformer = transformer.transformers[-1] + component_transformer = next(ct for ct in transformer.transformers if ct.size == 2) e2_12 = component_transformer.embed(component_transformer.extended_field([[0, 1], [0, 0]])) e2_21 = component_transformer.embed(component_transformer.extended_field([[0, 0], [1, 0]])) e2_22 = component_transformer.embed(component_transformer.extended_field([[0, 0], [0, 1]])) From e4aa3a10314b7f15a288e6e8df626266f1584acc Mon Sep 17 00:00:00 2001 From: "Michael A. Perlin" Date: Tue, 16 Jun 2026 16:58:49 -0400 Subject: [PATCH 07/11] test cleanup --- src/qldpc/abstract/wedderburn_artin_test.py | 43 ++++++++++----------- src/qldpc/conftest.py | 12 +----- 2 files changed, 22 insertions(+), 33 deletions(-) diff --git a/src/qldpc/abstract/wedderburn_artin_test.py b/src/qldpc/abstract/wedderburn_artin_test.py index 28d0337ef..90ab01225 100644 --- a/src/qldpc/abstract/wedderburn_artin_test.py +++ b/src/qldpc/abstract/wedderburn_artin_test.py @@ -30,12 +30,29 @@ def test_wedderburn_artin_transformations( ring: abstract.GroupRing, pytestconfig: pytest.Config ) -> None: - """Decompose semisimple rings into simple components. + """Randomized tests for the Wedderburn-Artin transformation of a group ring. - Runs for GroupRing(CyclicGroup(3), field=4) and GroupRing(DihedralGroup(3), field=5). + Runs for the default rings to test in this library (defined in an appropriate conftest.py). """ - seed = pytestconfig.getoption("randomly_seed") + _test_wedderburn_artin_transformations(ring, pytestconfig.getoption("randomly_seed")) + +def test_wedderburn_artin_transformations_size_three( + ring_alternating4_gf5: abstract.GroupRing, pytestconfig: pytest.Config +) -> None: + """Randomized tests for the Wedderburn-Artin transformation of a group ring. + + AlternatingGroup(4) is the smallest group with a 3-dimensional irreducible representation, + giving a Wedderburn-Artin component of size=3. This test covers the cross-term construction + in WedderburnArtinComponentTransformer._get_matrix_basis, which only runs when size >= 3. + """ + _test_wedderburn_artin_transformations( + ring_alternating4_gf5, pytestconfig.getoption("randomly_seed") + ) + + +def _test_wedderburn_artin_transformations(ring: abstract.GroupRing, seed: int) -> None: + """Randomized tests for the Wedderburn-Artin transformation of a group ring.""" transformer = ring.get_transformer() # the embedding of ring.field = GF(q) scalars is an isomorphism @@ -122,26 +139,6 @@ def get_random_ring_member(ring: abstract.GroupRing, seed: int) -> abstract.Ring return abstract.RingMember(ring, *terms) -def test_matrix_basis_size_three(ring_alternating4_gf5: abstract.GroupRing) -> None: - """The matrix basis construction handles size-3 components correctly. - - _get_matrix_basis builds the standard basis {|i><0|) directly - from projections, then it derives the remaining off-diagonal elements |i>= 1) as - compositions |i><0|·|0>= 3 (for size=2 there are no - pairs (i,j) with i,j >= 1). - - AlternatingGroup(4) is the smallest group with a 3-dimensional irreducible representation, - giving a size=3 Wedderburn-Artin component that exercises this second phase. - """ - transformer = ring_alternating4_gf5.get_transformer() - size_three_ct = next(ct for ct in transformer.transformers if ct.size == 3) - assert size_three_ct.matrix_basis.shape == ( - size_three_ct.size**2, - ring_alternating4_gf5.group.order, - ) - - def test_wedderburn_artin_errors( ring_cyclic3_gf2: abstract.GroupRing, pytestconfig: pytest.Config ) -> None: diff --git a/src/qldpc/conftest.py b/src/qldpc/conftest.py index 9fe92b0d4..aecff2057 100644 --- a/src/qldpc/conftest.py +++ b/src/qldpc/conftest.py @@ -25,11 +25,7 @@ def ring_cyclic3_gf4(pytestconfig: pytest.Config) -> abstract.GroupRing: @pytest.fixture(scope="session") def ring_dihedral3_gf5(pytestconfig: pytest.Config) -> abstract.GroupRing: - """Construct a non-commutative ring with a pre-built Wedderburn-Artin transformer. - - Uses DihedralGroup(3) over GF(5), whose primitive central idempotents are pre-cached in - KNOWN_PRIMITIVE_CENTRAL_IDEMPOTENTS (avoiding a GAP computation). - """ + """Construct a non-commutative ring with a pre-built Wedderburn-Artin transformer.""" ring = abstract.GroupRing(abstract.DihedralGroup(3), field=5) ring.get_transformer(seed=pytestconfig.getoption("randomly_seed")) return ring @@ -37,11 +33,7 @@ def ring_dihedral3_gf5(pytestconfig: pytest.Config) -> abstract.GroupRing: @pytest.fixture(scope="session") def ring_alternating4_gf5(pytestconfig: pytest.Config) -> abstract.GroupRing: - """Construct a non-commutative ring with a size-3 matrix component. - - Used specifically to test WedderburnArtinComponentTransformer code paths that only - arise for matrix components of size >= 3 (A4 is the smallest group with a 3-dim irrep). - """ + """Construct a non-commutative ring with a size-3 matrix component.""" ring = abstract.GroupRing(abstract.AlternatingGroup(4), field=5) ring.get_transformer(seed=pytestconfig.getoption("randomly_seed")) return ring From 387342a32e356df9887881fc4dad694e53f3b60d Mon Sep 17 00:00:00 2001 From: "Michael A. Perlin" Date: Tue, 16 Jun 2026 21:17:37 -0400 Subject: [PATCH 08/11] compile GF with python-calculate --- src/qldpc/abstract/wedderburn_artin.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/qldpc/abstract/wedderburn_artin.py b/src/qldpc/abstract/wedderburn_artin.py index fdf9df775..8d867c5f5 100644 --- a/src/qldpc/abstract/wedderburn_artin.py +++ b/src/qldpc/abstract/wedderburn_artin.py @@ -192,10 +192,23 @@ class WedderburnArtinComponentTransformer: decomposition_coefficient_extractor: galois.FieldArray decomposition_coefficient_recombiner: galois.FieldArray - def __init__(self, pci: RingMember, *, seed: np.random.Generator | None = None) -> None: + def __init__( + self, + pci: RingMember, + *, + seed: np.random.Generator | None = None, + galois_compile: str | None = "python-calculate", + ) -> None: """Initialize from a primitive central idempotent (PCI) of a ring. WARNING: This class assumes--and does not verify--that the provided RingMember is a PCI. + + Args: + pci: A primitive central idempotent that projects onto the simple component of a ring. + seed: Random number generator seed. + galois_compile: The ufunc calculation mode for the galois field extension GF(q^d). + Default: 'python-calculate', which is empirically faster for small field arrays. + See help(galois.GF), and the 'compile' argument in particular. """ if not pci.ring.is_semisimple: raise ValueError("The Wedderburn-Artin decomposition only exists for semisimple rings") @@ -215,7 +228,7 @@ def __init__(self, pci: RingMember, *, seed: np.random.Generator | None = None) self.power_basis = self._get_power_basis(seed) self.power_basis_dual = qldpc.math.get_dual_basis(self.power_basis, validate=False) - self.extended_field = galois.GF(self.field.order**self.degree) + self.extended_field = galois.GF(self.field.order**self.degree, compile=galois_compile) self.embedded_scalars, self.embedded_power_basis = self._get_center_embeddings() self.embedded_power_basis_dual = self._get_embedded_power_basis_dual() From fb03205d61f95ee1dbc5a7b4fcf3f87b1a7410a3 Mon Sep 17 00:00:00 2001 From: "Michael A. Perlin" Date: Tue, 16 Jun 2026 21:18:24 -0400 Subject: [PATCH 09/11] docstring update --- src/qldpc/abstract/wedderburn_artin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qldpc/abstract/wedderburn_artin.py b/src/qldpc/abstract/wedderburn_artin.py index 8d867c5f5..eef7fb81d 100644 --- a/src/qldpc/abstract/wedderburn_artin.py +++ b/src/qldpc/abstract/wedderburn_artin.py @@ -204,7 +204,7 @@ def __init__( WARNING: This class assumes--and does not verify--that the provided RingMember is a PCI. Args: - pci: A primitive central idempotent that projects onto the simple component of a ring. + pci: A primitive central idempotent of a ring. seed: Random number generator seed. galois_compile: The ufunc calculation mode for the galois field extension GF(q^d). Default: 'python-calculate', which is empirically faster for small field arrays. From a09d5f0350e19e7f7aebc1629bfa24a0d9473154 Mon Sep 17 00:00:00 2001 From: "Michael A. Perlin" Date: Tue, 16 Jun 2026 21:20:47 -0400 Subject: [PATCH 10/11] literal --- src/qldpc/abstract/wedderburn_artin.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/qldpc/abstract/wedderburn_artin.py b/src/qldpc/abstract/wedderburn_artin.py index eef7fb81d..e10f150ad 100644 --- a/src/qldpc/abstract/wedderburn_artin.py +++ b/src/qldpc/abstract/wedderburn_artin.py @@ -23,6 +23,7 @@ import math import operator from collections.abc import Sequence +from typing import Literal import galois import numpy as np @@ -197,7 +198,8 @@ def __init__( pci: RingMember, *, seed: np.random.Generator | None = None, - galois_compile: str | None = "python-calculate", + galois_compile: Literal["auto", "jit-lookup", "jit-calculate", "python-calculate"] + | None = "python-calculate", ) -> None: """Initialize from a primitive central idempotent (PCI) of a ring. From fc93feac070bd82d94d10a21e0529e9f98b7d9b7 Mon Sep 17 00:00:00 2001 From: "Michael A. Perlin" Date: Tue, 16 Jun 2026 21:36:42 -0400 Subject: [PATCH 11/11] revert timeout limit --- .github/workflows/continuous-integration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index eec5b96a4..c8e8377e8 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -80,7 +80,7 @@ jobs: name: Pytest and coverage check if: github.event.pull_request.draft == false runs-on: ubuntu-latest - timeout-minutes: 7 + timeout-minutes: 6 needs: install steps: - uses: actions/checkout@v6