From 7a6678fdcc2d5c305f2e833691fcae9ab2e71295 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sat, 24 Jan 2026 11:16:27 -0500 Subject: [PATCH] mjo/clan: move matrix-clan methods to an intermediate class --- mjo/clan/unital_clan.py | 147 +++++++++++++++++++++++++++------------- 1 file changed, 100 insertions(+), 47 deletions(-) diff --git a/mjo/clan/unital_clan.py b/mjo/clan/unital_clan.py index 9079af8..46ed222 100644 --- a/mjo/clan/unital_clan.py +++ b/mjo/clan/unital_clan.py @@ -183,7 +183,92 @@ class NormalDecomposition(UnitalClan): """ return self._rank -class SnClan(NormalDecomposition): +class MatrixClan(NormalDecomposition): + r""" + A clan arising from a T-algebra of Hermitian matrices. + """ + def from_matrix(self, x): + r""" + Construct an element of this clan from a Hermitian matrix. + + EXAMPLES:: + + sage: C = SnClan(2) + sage: X = matrix(QQ, [[2,1], + ....: [1,4]]) + sage: C.from_matrix(X).lift().lift() + [2 1] + [1 4] + + :: + + sage: from mjo.hurwitz import ComplexMatrixAlgebra + sage: C = HnClan(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()})" + " does not match clan ({self.base_ring()})") + if not x == x.conjugate_transpose(): + raise ValueError("matrix is not Hermitian") + if not self.rank() == x.nrows(): + raise ValueError(f"matrix must have {self.rank()} rows/columns") + + try: + # HurwitzMatrixAlgebra + return self.sum_of_terms( (idx, x[idx]) + for idx in self.indices() ) + except IndexError: + # MatrixSpace + return self.sum_of_terms( ((i,j,k), x[i,j]) + for (i,j,k) in self.indices() ) + + + + + def from_list(self, l): + r""" + Construct an element of this clan from a list. + + This is a shortcut for :meth:`from_matrix`, as the clan knows + what the ambient matrix space was. + + EXAMPLES:: + + sage: C = HnClan(2) + sage: X = C.from_list([[0,I],[-I,0]]) + sage: X.lift().lift() + ┌────┬───┐ + │ 0 │ I │ + ├────┼───┤ + │ -I │ 0 │ + └────┴───┘ + + This relies on the ambient vector space to convert a list to a + matrix, so in the real case, we can use one long list (as + opposed to a list of lists): + + sage: C = SnClan(3) + sage: X = C.from_list([2,6,10,6,10,14,10,14,18]) + sage: X.lift().lift() + [ 2 6 10] + [ 6 10 14] + [10 14 18] + + """ + return self.from_matrix(self._vector_space.ambient()(l)) + + +class SnClan(MatrixClan): r""" The normally-decomposed clan of real symmetric matrices of a given size with the clan product and lower-triangular basis @@ -333,52 +418,7 @@ class SnClan(NormalDecomposition): return f"Clan S^{self.rank()} over {self.base_ring()}" - def from_matrix(self, x): - r""" - Construct an element of this clan from a symmetric matrix. - - EXAMPLES:: - - sage: C = SnClan(2) - sage: X = matrix(QQ, [[2,1], - ....: [1,4]]) - sage: C.from_matrix(X).lift().lift() - [2 1] - [1 4] - - """ - if not x.base_ring() == self.base_ring(): - raise ValueError - if not x == x.transpose(): - raise ValueError - if not self.rank() == x.nrows(): - raise ValueError - return self.sum_of_terms( ((i,j,k), x[i,j]) - for (i,j,k) in self.indices() ) - - - def from_list(self, l): - r""" - Construct an element of this clan from a list. - - This is a shortcut for :meth:`from_matrix`, as the clan knows - what the ambient matrix space was. - - EXAMPLES:: - - sage: C = SnClan(3) - sage: X = C.from_list([2,6,10,6,10,14,10,14,18]) - sage: X.lift().lift() - [ 2 6 10] - [ 6 10 14] - [10 14 18] - - """ - return self.from_matrix(self._vector_space.ambient()(l)) - - - -class HnClan(NormalDecomposition): +class HnClan(MatrixClan): r""" The normally-decomposed clan of complex Hermitian matrices of a given size with the clan product and lower-triangular basis @@ -486,3 +526,16 @@ class HnClan(NormalDecomposition): return sum( p[i,i,one] for i in range(n) ) super().__init__(Hn, cp, ip, **kwargs) + + + def __repr__(self) -> str: + r""" + The string representation of this clan. + + EXAMPLES:: + + sage: HnClan(1) + Clan H^1 over Rational Field + + """ + return f"Clan H^{self.rank()} over {self.base_ring()}" -- 2.51.0