From 7599e07ec057b435e31d5f537ea11e752fd4f97b Mon Sep 17 00:00:00 2001 From: Ulysses Tiberious Date: Tue, 31 Mar 2026 17:03:05 +0800 Subject: [PATCH 1/2] fix(interop): reset dual mode to galgebra default in interop.Cl galgebra.interop.Cl now calls Ga.dual_mode('I+') before building the algebra, mirroring what kingdon.Cl does for 'Iinv+'. This prevents silent session contamination when both Cl variants are used in the same session (#555). Update kingdon.Cl docstring: the save/restore warning becomes a note explaining that interop.Cl resets the mode, so sequential calls are safe without manual save/restore. Fixes #555 (short-term). Long-term per-instance fix tracked on feat/issue-555-interop-dual-mode-per-instance. --- galgebra/interop/_cl.py | 12 ++++++++++++ galgebra/interop/kingdon.py | 13 ++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/galgebra/interop/_cl.py b/galgebra/interop/_cl.py index cecff2c1..3d11e942 100644 --- a/galgebra/interop/_cl.py +++ b/galgebra/interop/_cl.py @@ -16,6 +16,15 @@ def Cl(p: int, q: int = 0, r: int = 0, root: str = 'e', **kwargs): Uses galgebra defaults (basis numbered from 1, dual mode ``'I+'``). For kingdon conventions, use ``galgebra.interop.kingdon.Cl`` instead. + .. note:: + + This function resets the session-wide dual mode to ``'I+'`` + (galgebra default) before building the algebra. If you have + previously called ``galgebra.interop.kingdon.Cl`` in the same + session, that call will have set ``'Iinv+'`` globally; this call + restores the galgebra default. See :issue:`555` for the + long-term per-instance fix. + Parameters ---------- p : int @@ -52,6 +61,9 @@ def Cl(p: int, q: int = 0, r: int = 0, root: str = 'e', **kwargs): if n == 0: raise ValueError("Total dimension p + q + r must be positive.") + # Reset to galgebra default dual convention + Ga.dual_mode('I+') + # Build diagonal metric: p ones, q negative ones, r zeros g = [1] * p + [-1] * q + [0] * r diff --git a/galgebra/interop/kingdon.py b/galgebra/interop/kingdon.py index e245c87b..f3e29304 100644 --- a/galgebra/interop/kingdon.py +++ b/galgebra/interop/kingdon.py @@ -20,11 +20,14 @@ def Cl(p: int, q: int = 0, r: int = 0, root: str = 'e', **kwargs): - **Basis naming**: uses 0-indexed names (``e_0, e_1, ...``) to match kingdon's default for PGA algebras. - .. warning:: - - The dual mode change is session-wide. If you mix kingdon and - galgebra conventions in the same session, save and restore - ``Ga.dual_mode_value`` around the kingdon block:: + .. note:: + + This function sets the session-wide dual mode to ``'Iinv+'`` + before building the algebra. ``galgebra.interop.Cl`` resets it + back to ``'I+'``, so mixing the two in one session is safe as long + as each call is followed by the code that uses that algebra before + the next ``Cl`` call. For full isolation, save and restore + ``Ga.dual_mode_value`` manually:: saved = Ga.dual_mode_value try: From 9a682a7c047fc6b211ba9a6616dbea58128f437c Mon Sep 17 00:00:00 2001 From: Ulysses Tiberious Date: Tue, 31 Mar 2026 17:48:10 +0800 Subject: [PATCH 2/2] test(interop): add regression test for dual mode reset in interop.Cl Add test_Cl_dual_mode_reset: calls kingdon.Cl (sets Iinv+) then galgebra.interop.Cl and asserts dual mode is reset to I+. Without the fix in _cl.py this test fails. Clarify kingdon.Cl note: explicitly warn that algebras built under Iinv+ will compute duals with I+ once a subsequent galgebra.interop.Cl call is made. --- galgebra/interop/kingdon.py | 7 ++++--- test/test_test.py | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/galgebra/interop/kingdon.py b/galgebra/interop/kingdon.py index f3e29304..bd73e47c 100644 --- a/galgebra/interop/kingdon.py +++ b/galgebra/interop/kingdon.py @@ -24,9 +24,10 @@ def Cl(p: int, q: int = 0, r: int = 0, root: str = 'e', **kwargs): This function sets the session-wide dual mode to ``'Iinv+'`` before building the algebra. ``galgebra.interop.Cl`` resets it - back to ``'I+'``, so mixing the two in one session is safe as long - as each call is followed by the code that uses that algebra before - the next ``Cl`` call. For full isolation, save and restore + back to ``'I+'``. This means any algebra built under ``'Iinv+'`` + will compute duals with ``'I+'`` once a subsequent + ``galgebra.interop.Cl`` call is made. For full isolation over a + block of kingdon-convention code, save and restore ``Ga.dual_mode_value`` manually:: saved = Ga.dual_mode_value diff --git a/test/test_test.py b/test/test_test.py index aa8d77a6..7d0e1c63 100644 --- a/test/test_test.py +++ b/test/test_test.py @@ -734,3 +734,18 @@ def test_Cl_kingdon(self): assert Ga.dual_mode_value == 'Iinv+' finally: Ga.dual_mode(saved) + + def test_Cl_dual_mode_reset(self): + """galgebra.interop.Cl must reset dual mode to I+ after kingdon.Cl set Iinv+.""" + from galgebra.interop.kingdon import Cl as KCl + from galgebra.interop import Cl + from galgebra.ga import Ga + + saved = Ga.dual_mode_value + try: + KCl(3) + assert Ga.dual_mode_value == 'Iinv+' + Cl(3) + assert Ga.dual_mode_value == 'I+' + finally: + Ga.dual_mode(saved)