From: Michael Orlitzky Date: Mon, 26 Jan 2026 02:35:59 +0000 (-0500) Subject: mjo/clan: factor out up_hat, down_hat, etc. for matrix clans X-Git-Url: https://gitweb.michael.orlitzky.com/?a=commitdiff_plain;h=1e9eef8b794e674df1105fa95d716e4541a4e500;p=sage.d.git mjo/clan: factor out up_hat, down_hat, etc. for matrix clans --- diff --git a/mjo/clan/unital_clan.py b/mjo/clan/unital_clan.py index 46ed222..5ad9b51 100644 --- a/mjo/clan/unital_clan.py +++ b/mjo/clan/unital_clan.py @@ -187,6 +187,76 @@ class MatrixClan(NormalDecomposition): r""" A clan arising from a T-algebra of Hermitian matrices. """ + @staticmethod + def _up_hat(x): + r""" + The "up-hat" function on a T-algebra. + + This is the "top half" of a matrix, in the sense that we keep + the strictly upper-triangular part, and keep half of the + diagonal (so that ``up_hat(x) + down_hat(x) == x``. It is + defined by Vinberg on page 381, and is used to construct a + clan whose associated cone equals that of the the T-algebra. + """ + one = x.base_ring().one() + two = 2*one + return x.parent().sum_of_terms( + (idx, a*c) + for (idx, c) in x.items() + if idx[0] <= idx[1] + if (a := one - (idx[0] == idx[1])/two) + ) + + @staticmethod + def _down_hat(x): + r""" + The "down-hat" function on a T-algebra. + + This is the "lower half" of a matrix, in the sense that we + keep the strictly lower-triangular part, and keep half of the + diagonal (so that ``up_hat(x) + down_hat(x) == x``. It is + defined by Vinberg on page 381, and is used to construct a + clan whose associated cone equals that of the the T-algebra. + """ + return MatrixClan._up_hat(x.transpose()).transpose() + + @staticmethod + def _cp(x,y): + r""" + The clan product associated with a T-algebra. + + This is defined by Vinberg on page 381 (as Delta), who then + proceeds to explain, over the course of the next few pages, + why it results in a clan when the we take the underlying set + to be the subspace of symmetric elements. + + .. WARNING: + + We use Ishi's version of this product that reverses + the indices. + + """ + # First we lift x,y out of the clan and into + # the general matrix space. + H = x.parent() + x = x.lift() + y = y.lift() + + # Note: within a Hermitian matrix space we can't represent the + # (non-Hermitian) intermediate terms _down_hat(x) and _up_hat(x)! + return H(MatrixClan._down_hat(x)*y + y*MatrixClan._up_hat(x)) + + @staticmethod + def _ip(x,y): + r""" + The Ishi inner product (NOT the canonical one) on a clan. + """ + two = x.base_ring()(2) + p = MatrixClan._cp(x,y) / two + return sum( p[idx] + for idx in p.monomial_coefficients() + if idx[0] == idx[1] ) + def from_matrix(self, x): r""" Construct an element of this clan from a Hermitian matrix. @@ -347,62 +417,7 @@ class SnClan(MatrixClan): support_order=b.keys(), ambient=Mn) - def up_hat(x): - r""" - The "up-hat" function on a T-algebra. - - This is the "top half" of a matrix, in the sense that we keep the - strictly upper-triangular part, and keep half of the diagonal (so - that ``up_hat(x) + down_hat(x) == x``. It is defined by Vinberg on - page 381, and is used to construct a clan whose associated cone - equals that of the the T-algebra. - - """ - def l(i,j): - if i < j: - return x[i,j] - if i == j: - return x[i,j]/scalar_field(2) - else: - return 0 - return Mn(l) - - def down_hat(x): - r""" - The "down-hat" function on a T-algebra. - - This is the "lower half" of a matrix, in the sense that we keep - the strictly lower-triangular part, and keep half of the diagonal - (so that ``up_hat(x) + down_hat(x) == x``. It is defined by - Vinberg on page 381, and is used to construct a clan whose - associated cone equals that of the the T-algebra. - """ - return up_hat(x.T).T - - def cp(x,y): - r""" - The clan product associated with a T-algebra. - - This is defined by Vinberg on page 381 (as Delta), who - then proceeds to explain, over the course of the next few - pages, why it results in a clan when the we take the - underlying set to be the subspace of symmetric elements. - - .. WARNING: - - We use Ishi's version of this product that reverses - the indices. - - """ - x = x.lift() - y = y.lift() - return Sn(down_hat(x)*y + y*up_hat(x)) - - def ip(x,y): - p = cp(x,y) / scalar_field(2) - return sum( p[(i,i,1)] for i in range(n) ) - - super().__init__(Sn, cp, ip, **kwargs) + super().__init__(Sn, MatrixClan._cp, MatrixClan._ip, **kwargs) def __repr__(self) -> str: @@ -504,28 +519,7 @@ class HnClan(MatrixClan): support_order=b.keys(), ambient=Mn) - def up_hat(x): - return Mn.sum_of_terms( - ((i,j,k), a*c) - for ((i,j,k),c) in x.items() - if i <= j - if (a := 1 - (i == j)/scalar_field(2)) - ) - - def down_hat(x): - return up_hat(x.transpose()).transpose() - - def cp(x,y): - x = x.lift() - y = y.lift() - return Hn(down_hat(x)*y + y*up_hat(x)) - - def ip(x,y): - p = cp(x,y) / scalar_field(2) - one = QQbar(1) # weird indexing in Hurwitz matrix algebras - return sum( p[i,i,one] for i in range(n) ) - - super().__init__(Hn, cp, ip, **kwargs) + super().__init__(Hn, MatrixClan._cp, MatrixClan._ip, **kwargs) def __repr__(self) -> str: