From e13e3014feea2d1e53cd5eb91b78dade6faa5c4b Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 14 Jan 2026 22:07:38 -0500 Subject: [PATCH] mjo/clan: get inner products working; implement one() for SnClan --- mjo/clan/clan_element.py | 24 ++++++++++++++++++++ mjo/clan/unital_clan.py | 47 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/mjo/clan/clan_element.py b/mjo/clan/clan_element.py index 1d358ef..2b578a1 100644 --- a/mjo/clan/clan_element.py +++ b/mjo/clan/clan_element.py @@ -16,3 +16,27 @@ class ClanElement(IndexedFreeModuleElement): will be needed to get the actual matrix. """ return self.parent()._vector_space.sum_of_terms(self.items()) + + + def inner_product(self, other): + r""" + The inner product of this element with ``other``. + + EXAMPLES: + + In the clan of real symmetric matrices under the Ishi norm, + it is easy to check that the idempotents all have norm 1/2:: + + sage: from mjo.clan.unital_clan import SnClan + sage: C = SnClan(3) + sage: all( e_ii.inner_product(e_ii) == 1/2 + ....: for i in range(C.rank()) + ....: if (e_ii := C.basis()[(i,i)]) ) + True + + """ + return sum( + xi*yj*self.parent().inner_product_on_basis(bi, bj) + for (bi, xi) in self.items() + for (bj, yj) in other.items() + ) diff --git a/mjo/clan/unital_clan.py b/mjo/clan/unital_clan.py index 37aa8ab..e576d52 100644 --- a/mjo/clan/unital_clan.py +++ b/mjo/clan/unital_clan.py @@ -34,6 +34,12 @@ class UnitalClan(CombinatorialFreeModule): for j in basis.keys() } for i in basis.keys() } + # And inner product table. We assume the supplied inner + # product is symmetric. + self._ipt = { i: { j : inner_product(basis[i], basis[j]) + for j in basis.keys() if j <= i } + for i in basis.keys() } + # Use the vector_space basis keys so we can convert # easily between them. CombinatorialFreeModule.__init__(self, @@ -64,6 +70,18 @@ class UnitalClan(CombinatorialFreeModule): return None + def inner_product_on_basis(self, i, j): + r""" + Return the inner product of the `i` and `j`th basis elements. + + This completely defines the inner product. + """ + if j <= i: + return self._ipt[i][j] + else: + return self._ipt[j][i] + + def product_on_basis(self, i, j): r""" Returns the Jordan product of the `i` and `j`th basis elements. @@ -74,6 +92,7 @@ class UnitalClan(CombinatorialFreeModule): """ return self._mt[i][j] + def rank(self) -> int: r""" The rank of this clan. Not implemented by default, @@ -84,9 +103,10 @@ class UnitalClan(CombinatorialFreeModule): class SnClan(UnitalClan): r""" - The clan of real symmetric matrices of a given size with the - clan product and lower-triangular basis ordering of Ishi, - based on the up-hat and down-hat products of Vinberg. + The normally-decomposed clan of real symmetric matrices of a + given size with the clan product and lower-triangular basis + ordering of Ishi, based on the up-hat and down-hat products of + Vinberg. EXAMPLES: @@ -137,6 +157,7 @@ class SnClan(UnitalClan): def __init__(self, n, scalar_field=QQ, **kwargs): self._rank = n + from sage.matrix.matrix_space import MatrixSpace Mn = MatrixSpace(scalar_field, n) b = Mn.basis() @@ -227,3 +248,23 @@ class SnClan(UnitalClan): """ return f"Clan S^{self.rank()} over {self._vector_space().base_ring()}" + + + def one(self): + r""" + Return the unit element of this clan. + + EXAMPLES:: + + sage: C = SnClan(4) + sage: I = C.one() + sage: I.lift().lift() + [1 0 0 0] + [0 1 0 0] + [0 0 1 0] + [0 0 0 1] + sage: all( I*b == b and b*I == b for b in C.basis() ) + True + + """ + return sum( self.basis()[i,i] for i in range(self.rank()) ) -- 2.51.0