From 21d467337ca6a52624bfd4bba8791fd59439a19c Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 4 Mar 2026 10:36:42 -0500 Subject: [PATCH] mjo/clan/t_algebra_clan.py: speed up ComplexHermitianClan 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 | 107 +++++++++++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 17 deletions(-) diff --git a/mjo/clan/t_algebra_clan.py b/mjo/clan/t_algebra_clan.py index 6f475c4..1d33a13 100644 --- a/mjo/clan/t_algebra_clan.py +++ b/mjo/clan/t_algebra_clan.py @@ -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) -- 2.51.0