From: Michael Orlitzky Date: Thu, 15 Jan 2026 01:40:18 +0000 (-0500) Subject: mjo/clan: begin implementing the clan on S^n X-Git-Url: https://gitweb.michael.orlitzky.com/?a=commitdiff_plain;h=deaa1fb3279fe3ab8e415cd58a3ff8618b1ca43d;p=sage.d.git mjo/clan: begin implementing the clan on S^n --- diff --git a/mjo/clan/unital_clan.py b/mjo/clan/unital_clan.py index 927dd3b..37aa8ab 100644 --- a/mjo/clan/unital_clan.py +++ b/mjo/clan/unital_clan.py @@ -5,6 +5,8 @@ Proper implementation of unital clans (real, finite dimensional from sage.categories.magmatic_algebras import MagmaticAlgebras from sage.combinat.free_module import CombinatorialFreeModule +from sage.modules.with_basis.subquotient import SubmoduleWithBasis +from sage.rings.rational_field import QQ from mjo.clan.clan_element import ClanElement @@ -71,3 +73,157 @@ class UnitalClan(CombinatorialFreeModule): """ return self._mt[i][j] + + def rank(self) -> int: + r""" + The rank of this clan. Not implemented by default, + because it is only easy to deduce from a normal decomposition. + """ + raise NotImplementedError + + +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. + + EXAMPLES: + + Verifying the axioms:: + + sage: n = 3 + sage: C = SnClan(n) + sage: e = C.basis() + sage: all( e[i,i]*e[i,i] == e[i,i] for i in range(n) ) + True + sage: all( e[i,i]*e[j,i] == e[j,i]/2 + ....: for i in range(n) + ....: for j in range(i+1,n)) + True + sage: all( e[i,i]*e[i,k] == e[i,k]/2 + ....: for i in range(n) + ....: for k in range(i)) + True + sage: all( (e[i,i]*e[j,k]).is_zero() + ....: for i in range(n) + ....: for j in range(n) + ....: for k in range(j+1) + ....: if not i in [j,k] ) + True + sage: all( (e[i,k]*e[i,i]).is_zero() + ....: for i in range(n) + ....: for k in range(i) ) + True + sage: all( (e[j,k]*e[i,i]).is_zero() + ....: for i in range(n) + ....: for j in range(n) + ....: for k in range(j) + ....: if not i in [j,k] ) + True + + With a little effort, we can lift elements of the clan back into + the original (asymmetric) matrix space:: + + sage: C = SnClan(3) + sage: x = C.an_element(); x + 2*B(0, 0) + 2*B(1, 0) + 3*B(1, 1) + sage: x.lift().lift() + [2 2 0] + [2 3 0] + [0 0 0] + + """ + def __init__(self, n, scalar_field=QQ, **kwargs): + self._rank = n + + Mn = MatrixSpace(scalar_field, n) + b = Mn.basis() + + from sage.sets.family import Family + Sn_basis = Family({ (i,j) : + a*(b[(i,j)] + b[(j,i)]) + for i in range(n) + for j in range(i+1) + if (a := 1 - (i == j)/scalar_field(2)) + }) + + # Mn.submodule() destroys our basis keys, so use + # SubmoduleWithBasis directly. + Sn = SubmoduleWithBasis(Sn_basis, + 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)] for i in range(n) ) + + super().__init__(Sn, cp, ip, **kwargs) + + + def rank(self) -> int: + return self._rank + + + def __repr__(self) -> str: + r""" + The string representation of this clan. + + EXAMPLES:: + + sage: SnClan(5) + Clan S^5 over Rational Field + + """ + return f"Clan S^{self.rank()} over {self._vector_space().base_ring()}"