]> gitweb.michael.orlitzky.com - sage.d.git/commitdiff
mjo/clan/t_algebra_clan.py: speed up ComplexHermitianClan
authorMichael Orlitzky <michael@orlitzky.com>
Wed, 4 Mar 2026 15:36:42 +0000 (10:36 -0500)
committerMichael Orlitzky <michael@orlitzky.com>
Wed, 4 Mar 2026 15:36:42 +0000 (10:36 -0500)
To speed up ComplexHermitianClan, we use a quadratic field extension
for the entries of the ambient matrix space rather than (basically)
assuming QQ and QQbar. But before we can do that, we need to adjust
from_matrix() to reject mismatched entry algebras. We also need to
special case several real/complex field pairs, because the quadratic
extension procedure does not always give us something usable -- our
Hurwitz matrix algebras are finicky.

mjo/clan/t_algebra_clan.py

index 6f475c4939aa34e1897cefaff54266932f6cfa3f..1d33a1391990fd540aad1f7616baa17305bf6dec 100644 (file)
@@ -82,10 +82,8 @@ class TAlgebraClan(NormalDecomposition):
         SETUP::
 
             sage: from mjo.clan.t_algebra_clan import (
-            ....:     ComplexHermitianClan,
             ....:     RealSymmetricClan
             ....: )
-            sage: from mjo.hurwitz import ComplexMatrixAlgebra
 
         EXAMPLES::
 
@@ -96,19 +94,6 @@ class TAlgebraClan(NormalDecomposition):
             [2 1]
             [1 4]
 
-        ::
-
-            sage: C = ComplexHermitianClan(2)
-            sage: A = ComplexMatrixAlgebra(2, QQbar, QQ)
-            sage: X = A([ [ 2,       1 + 2*I],
-            ....:         [ 1 - 2*I,      -1] ])
-            sage: C.from_matrix(X).lift().lift()
-            ┌──────────┬─────────┐
-            │ 2        │ 2*I + 1 │
-            ├──────────┼─────────┤
-            │ -2*I + 1 │ -1      │
-            └──────────┴─────────┘
-
         """
         if not x.base_ring() == self.base_ring():
             raise ValueError(f"base ring of matrix ({x.base_ring()})"
@@ -383,12 +368,48 @@ class ComplexHermitianClan(TAlgebraClan):
         sage: C.one()
         0
 
+    Special cases for the entry algebra of the ambient matrix space::
+
+        sage: C = ComplexHermitianClan(2, scalar_field=AA)
+        sage: C.entry_algebra
+        Algebraic Field
+        sage: C = ComplexHermitianClan(2, scalar_field=RR)
+        sage: C.entry_algebra
+        Complex Field with 53 bits of precision
+        sage: C = ComplexHermitianClan(2, scalar_field=RDF)
+        sage: C.entry_algebra
+        Complex Double Field
+
     """
     from sage.rings.rational_field import QQ
     def __init__(self, n, scalar_field=QQ, **kwargs):
         from mjo.hurwitz import ComplexMatrixAlgebra
-        from sage.rings.qqbar import QQbar
-        Mn = ComplexMatrixAlgebra(n, QQbar, scalar_field)
+        from sage.rings.polynomial.polynomial_ring import polygen
+
+        # The way we construct the underlying vector space is finicky.
+        # We need the entries of our matrix to have a conjugate() method,
+        # but sometimes (most of the time) the quadratic extension below
+        # returns something wacky. Here we handle two special cases where
+        # the extension field is known.
+        from sage.rings.qqbar import AA
+        from sage.rings.real_mpfr import RR
+        from sage.rings.real_double import RDF
+        if scalar_field is AA:
+            from sage.rings.qqbar import QQbar
+            self.entry_algebra = QQbar
+        elif scalar_field is RR:
+            from sage.rings.cc import CC
+            self.entry_algebra = CC
+        elif scalar_field is RDF:
+            from sage.rings.complex_double import CDF
+            self.entry_algebra = CDF
+        else:
+            # Works for QQ, but not much else.
+            x = polygen(scalar_field, 'x')
+            self.entry_algebra = scalar_field.extension(x**2 + 1,
+                                                        names=['I'])
+
+        Mn = ComplexMatrixAlgebra(n, self.entry_algebra, scalar_field)
         b = Mn.basis()
 
         from sage.sets.family import Family
@@ -429,3 +450,55 @@ class ComplexHermitianClan(TAlgebraClan):
 
         """
         return f"Clan H^{self.rank()} over {self.base_ring()}"
+
+    def from_matrix(self, x):
+        r"""
+        Construct an element of this clan from a Hermitian matrix.
+
+        A special case is needed for matrices with complex entries,
+        to ensure that the entry algebras agree.
+
+        SETUP::
+
+            sage: from mjo.clan.t_algebra_clan import (
+            ....:     ComplexHermitianClan
+            ....: )
+            sage: from mjo.hurwitz import ComplexMatrixAlgebra
+
+        EXAMPLES::
+
+        The entry algebra must be a quadratic extension of the scalar
+        field; if you pass in a matrix whose entries come from the
+        wrong algebra, it won't work::
+
+            sage: C = ComplexHermitianClan(2)
+            sage: A = ComplexMatrixAlgebra(2, QQbar, QQ)
+            sage: X = A([ [ 2,       1 + 2*I],
+            ....:         [ 1 - 2*I,      -1] ])
+            sage: C.from_matrix(X)
+            Traceback (most recent call last):
+            ...
+            ValueError: entry algebra of matrix (Algebraic Field) does
+            not match clan (Number Field in I with defining polynomial
+            x^2 + 1)
+
+        The easy way to obtain the correct entry algebra is to borrow
+        it from the clan::
+
+            sage: C = ComplexHermitianClan(2)
+            sage: A = ComplexMatrixAlgebra(2, C.entry_algebra, C.base_ring())
+            sage: X = A([ [ 2,       1 + 2*I],
+            ....:         [ 1 - 2*I,      -1] ])
+            sage: C.from_matrix(X).lift().lift()
+            ┌──────────┬─────────┐
+            │ 2        │ 2*I + 1 │
+            ├──────────┼─────────┤
+            │ -2*I + 1 │ -1      │
+            └──────────┴─────────┘
+
+        """
+        ea = x.parent().entry_algebra()
+        if not ea == self.entry_algebra:
+            raise ValueError(f"entry algebra of matrix ({ea}) does not"
+                             f" match clan ({self.entry_algebra})")
+        return super().from_matrix(x)