From b2bd4efb6cc1799965f4c615cfbbac7842b07a6a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 1 Sep 2023 14:37:07 +0900 Subject: [PATCH] Implementation of representations of Lie algebras. --- .../en/reference/algebras/lie_algebras.rst | 1 + .../algebras/lie_algebras/representation.py | 300 ++++++++++++++++++ ...ite_dimensional_lie_algebras_with_basis.py | 31 ++ src/sage/categories/lie_algebras.py | 14 + 4 files changed, 346 insertions(+) create mode 100644 src/sage/algebras/lie_algebras/representation.py diff --git a/src/doc/en/reference/algebras/lie_algebras.rst b/src/doc/en/reference/algebras/lie_algebras.rst index 23152ac0449..457eb90f14e 100644 --- a/src/doc/en/reference/algebras/lie_algebras.rst +++ b/src/doc/en/reference/algebras/lie_algebras.rst @@ -19,6 +19,7 @@ Lie Algebras sage/algebras/lie_algebras/poincare_birkhoff_witt sage/algebras/lie_algebras/quotient sage/algebras/lie_algebras/rank_two_heisenberg_virasoro + sage/algebras/lie_algebras/representation sage/algebras/lie_algebras/structure_coefficients sage/algebras/lie_algebras/subalgebra sage/algebras/lie_algebras/symplectic_derivation diff --git a/src/sage/algebras/lie_algebras/representation.py b/src/sage/algebras/lie_algebras/representation.py new file mode 100644 index 00000000000..e818a069809 --- /dev/null +++ b/src/sage/algebras/lie_algebras/representation.py @@ -0,0 +1,300 @@ +r""" +Representations of a Lie algebra + +AUTHORS: + +- Travis Scrimshaw (2023-08-31): initial version +""" + +# **************************************************************************** +# Copyright (C) 2023 Travis Scrimshaw +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.sets.family import Family +from sage.combinat.free_module import CombinatorialFreeModule +from sage.categories.modules import Modules +from copy import copy + + +class Representation_abstract: + """ + Mixin class for (left) representations of Lie algebras. + + INPUT: + + - ``lie_algebra`` -- a Lie algebra + """ + def __init__(self, lie_algebra): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.sp(QQ, 6) + sage: R = L.trivial_representation() + sage: TestSuite(R).run() + """ + self._lie_algebra = lie_algebra + + def lie_algebra(self): + """ + Return the Lie algebra whose representation ``self`` is. + + EXAMPLES:: + + sage: L = lie_algebras.sl(QQ, 4) + sage: R = L.trivial_representation() + sage: R.lie_algebra() is L + True + """ + return self._lie_algebra + + def side(self): + """ + Return whether ``self`` is a left or right. + + OUTPUT: + + - the string ``"left"``, ``"right"``, or ``"twosided"`` + + EXAMPLES:: + + sage: L = lie_algebras.sl(QQ, 4) + sage: R = L.trivial_representation() + sage: R.side() + 'left' + """ + return 'left' + + def _test_representation(self, **options): + """ + Check (on some elements) that ``self`` is a representation of the + given Lie algebra. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, 3) + sage: f = {b: b.adjoint_matrix() for b in L.basis()} + sage: R = L.representation(f) + sage: R._test_representation() + """ + tester = self._tester(**options) + S = tester.some_elements() + elts = self._lie_algebra.basis() + from sage.misc.misc import some_tuples + for x, y in some_tuples(elts, 2, tester._max_runs): + for v in S: + tester.assertEqual(x.bracket(y) * v, x * (y * v) - y * (x * v)) + + +class RepresentationByMorphism(CombinatorialFreeModule, Representation_abstract): + """ + Representation of a Lie algebra defined by a Lie algebra morphism. + + INPUT: + + - ``lie_algebra`` -- a Lie algebra + - ``f`` -- the Lie algebra morphism defining the action of the basis + elements of ``lie_algebra`` encoded as a ``dict`` with keys being + indices of the basis of ``lie_algebra`` and the values being the + corresponding matrix defining the action + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'y':1}}) + sage: f = ({x: Matrix([[1,0],[0,0]]), y: Matrix([[0,1],[0,0]])}) + sage: L.representation(f) + Representation of Lie algebra on 2 generators (x, y) over Rational Field defined by: + [1 0] + x |--> [0 0] + [0 1] + y |--> [0 0] + """ + @staticmethod + def __classcall_private__(cls, lie_algebra, f, **kwargs): + """ + Normalize inpute to ensure a unique representation. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'y':1}}) + sage: f1 = {'x': Matrix([[1,0],[0,0]]), 'y': Matrix([[0,1],[0,0]])} + sage: R1 = L.representation(f1) + sage: f2 = Family({x: Matrix([[1,0],[0,0]]), y: Matrix([[0,1],[0,0]])}) + sage: R2 = L.representation(f2) + sage: R1 is R2 + True + """ + C = Modules(lie_algebra.base_ring()).WithBasis().FiniteDimensional() + C = C.or_subcategory(kwargs.pop('category', C)) + B = lie_algebra.basis() + data = {} + for k, mat in f.items(): + if k in B: + k = k.leading_support() + data[k] = copy(mat) + data[k].set_immutable() + f = Family(data) + return super(cls, RepresentationByMorphism).__classcall__(cls, lie_algebra, f, category=C, **kwargs) + + def __init__(self, lie_algebra, f, category, **kwargs): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'y':1}}) + sage: f = {'x': Matrix([[1,0],[0,0]]), 'y': Matrix([[0,1],[0,0]])} + sage: R = L.representation(f) + sage: TestSuite(R).run() + """ + it = iter(f) + mat = next(it) + if not mat.is_square(): + raise ValueError("all matrices must be square") + dim = mat.nrows() + self._mat_space = mat.parent() + from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + if any(mat.nrows() != dim or mat.ncols() != dim for mat in it): + raise ValueError("all matrices must be square of size {}".format(dim)) + self._f = dict(f) + + I = FiniteEnumeratedSet(range(dim)) + Representation_abstract.__init__(self, lie_algebra) + CombinatorialFreeModule.__init__(self, lie_algebra.base_ring(), I, prefix='R', category=category) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'y':1}}) + sage: f = {'x': Matrix([[1,0],[0,0]]), 'y': Matrix([[0,1],[0,0]])} + sage: L.representation(f) + Representation of Lie algebra on 2 generators (x, y) over Rational Field defined by: + [1 0] + x |--> [0 0] + [0 1] + y |--> [0 0] + """ + ret = "Representation of {} defined by:".format(self._lie_algebra) + from sage.typeset.ascii_art import ascii_art + B = self._lie_algebra.basis() + for k in self._f: + ret += '\n' + repr(ascii_art(B[k], self._f[k], sep=" |--> ", sep_baseline=0)) + return ret + + class Element(CombinatorialFreeModule.Element): + def _acted_upon_(self, scalar, self_on_left=False): + """ + Return the action of ``scalar`` on ``self``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'y':1}}) + sage: f = {'x': Matrix([[1,0],[0,0]]), 'y': Matrix([[0,1],[0,0]])} + sage: R = L.representation(f) + sage: v = R.an_element(); v + 2*R[0] + 2*R[1] + sage: x * v + 2*R[0] + sage: y * v + 2*R[0] + sage: (2*x + 5*y) * v + 14*R[0] + sage: v * x + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for *: ... + + sage: v = sum((i+4) * b for i, b in enumerate(R.basis())); v + 4*R[0] + 5*R[1] + sage: (1/3*x - 5*y) * v + -71/3*R[0] + """ + P = self.parent() + if scalar in P._lie_algebra: + if self_on_left: + return None + scalar = P._lie_algebra(scalar) + f = P._f + mat = P._mat_space.sum(scalar[k] * f[k] for k in f if scalar[k]) + return P.from_vector(mat * self.to_vector()) + + return super()._acted_upon_(scalar, self_on_left) + + +class TrivialRepresentation(CombinatorialFreeModule, Representation_abstract): + """ + The trivial representation of a Lie algebra. + + The trivial representation of a Lie algebra `L` over a commutative ring + `R` is the `1`-dimensional `R`-module on which every element of `L` + acts by zero. + + INPUT: + + - ``lie_algebra`` -- a Lie algebra + + REFERENCES: + + - :wikipedia:`Trivial_representation` + """ + def __init__(self, lie_algebra): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.VirasoroAlgebra(QQ) + sage: R = L.trivial_representation() + sage: TestSuite(R).run() + """ + R = lie_algebra.base_ring() + cat = Modules(R).WithBasis().FiniteDimensional() + Representation_abstract.__init__(self, lie_algebra) + CombinatorialFreeModule.__init__(self, R, ['v'], prefix='T', category=cat) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.VirasoroAlgebra(QQ) + sage: L.trivial_representation() + Trivial representation of The Virasoro algebra over Rational Field + """ + return "Trivial representation of {}".format(self._lie_algebra) + + class Element(CombinatorialFreeModule.Element): + def _acted_upon_(self, scalar, self_on_left=False): + """ + Return the action of ``scalar`` on ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.VirasoroAlgebra(QQ) + sage: R = L.trivial_representation() + sage: L.an_element() * R.an_element() + 0 + sage: R.an_element() * L.an_element() + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for *: ... + sage: 3 / 5 * R.an_element() + 6/5*T['v'] + """ + P = self.parent() + if scalar in P._lie_algebra: + if self_on_left: + return None + return P.zero() + return super()._acted_upon_(scalar, self_on_left) diff --git a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py index 013b30dc281..61510508be9 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -1532,6 +1532,37 @@ def morphism(self, on_generators, codomain=None, base_map=None, check=True): return LieAlgebraMorphism_from_generators(on_generators, domain=self, codomain=codomain, base_map=base_map, check=check) + def representation(self, f=None): + """ + Return a representation of ``self``. + + Currently the only implementated method of constructing a + representation is by explicitly specifying the action of + the basis elements of ``self`` by matrices using a ``dict``. + + If no arguments are given, then this returns the trivial + representation. + + .. SEEALSO:: + + :class:`~sage.algebras.lie_algebras.representation.RepresentationByMorphism` + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'y':1}}) + sage: f = {x: Matrix([[1,0],[0,0]]), y: Matrix([[0,1],[0,0]])} + sage: L.representation(f) + Representation of Lie algebra on 2 generators (x, y) over Rational Field defined by: + [1 0] + x |--> [0 0] + [0 1] + y |--> [0 0] + """ + if f is None: + return self.trivial_representation() + from sage.algebras.lie_algebras.representation import RepresentationByMorphism + return RepresentationByMorphism(self, f) + @cached_method def universal_polynomials(self): r""" diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index 7244eab161b..7d93255e067 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -697,6 +697,20 @@ def lie_group(self, name='G', **kwds): Lie group G of Heisenberg algebra of rank 1 over Rational Field """ + def trivial_representation(self): + """ + Return the trivial representation of ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.strictly_upper_triangular_matrices(QQ, 4) + sage: L.trivial_representation() + Trivial representation of Lie algebra of 4-dimensional + strictly upper triangular matrices over Rational Field + """ + from sage.algebras.lie_algebras.representation import TrivialRepresentation + return TrivialRepresentation(self) + def _test_jacobi_identity(self, **options): """ Test that the Jacobi identity is satisfied on (not