Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*- """ Lie Algebra Elements
AUTHORS:
- Travis Scrimshaw (2013-05-04): Initial implementation """
#***************************************************************************** # Copyright (C) 2013-2017 Travis Scrimshaw <tcscrims at gmail.com> # # 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. # http://www.gnu.org/licenses/ #*****************************************************************************
from copy import copy from cpython.object cimport Py_EQ, Py_NE
from sage.misc.misc import repr_lincomb from sage.combinat.free_module import CombinatorialFreeModule from sage.structure.element cimport have_same_parent, coercion_model, parent from sage.cpython.wrapperdescr cimport wrapperdescr_fastcall from sage.structure.element_wrapper cimport ElementWrapper from sage.structure.richcmp cimport richcmp from sage.data_structures.blas_dict cimport axpy, add, negate, scal
# TODO: Do we want a dense version? cdef class LieAlgebraElement(IndexedFreeModuleElement): """ A Lie algebra element. """ # Need to bypass the coercion model def __mul__(left, right): """ If we are multiplying two non-zero elements, automatically lift up to the universal enveloping algebra.
EXAMPLES::
sage: L.<x,y,z> = LieAlgebra(QQ, {('x','y'): {'z':1}}) sage: y*x x*y - z
Check that actions work::
sage: L = lie_algebras.VirasoroAlgebra(QQ) sage: d = L.basis() sage: M = L.chargeless_representation(1/2, 3/4) sage: d[-5] * M.basis()[10] -47/4*v[5]
TESTS::
sage: L.<x,y,z> = LieAlgebra(QQ, {('x','y'): {'z':1}}) sage: int(3) * x 3*x sage: x * int(3) 3*x sage: y * x.lift() x*y - z sage: y.lift() * x x*y - z """ # Try the normal coercion first pass
# Lift up to the UEA and try multiplication there # We will eventually want to lift stuff up anyways, # so just do it here.
cpdef lift(self): """ Lift ``self`` to the universal enveloping algebra.
EXAMPLES::
sage: L.<x,y,z> = LieAlgebra(QQ, {('x','y'):{'z':1}}) sage: x.lift().parent() == L.universal_enveloping_algebra() True
TESTS::
sage: L = lie_algebras.pwitt(GF(5), 5); L The 5-Witt Lie algebra over Finite Field of size 5 sage: x = L.basis()[2] sage: y = L.basis()[3] sage: x.lift() b2 sage: y.lift() b3 sage: x * y b2*b3 sage: y * x b2*b3 + b0
sage: L = lie_algebras.regular_vector_fields(QQ) sage: L.an_element() d[-1] + d[0] - 3*d[1] sage: L.an_element().lift() PBW[-1] + PBW[0] - 3*PBW[1] """ return s # Special hook for when the index set of the parent of ``self`` # does not match the generators index set of the UEA. else:
cdef class LieAlgebraElementWrapper(ElementWrapper): """ Wrap an element as a Lie algebra element.
TESTS:
We check comparisons::
sage: L = lie_algebras.sl(QQ, 2, representation='matrix') sage: L.bracket(L.gen(0), L.gen(1)) == -L.bracket(L.gen(1), L.gen(0)) True
The next doctests show similar behavior, although on elements of other classes::
sage: L = lie_algebras.three_dimensional_by_rank(QQ, 3) sage: L.bracket(L.gen(0), L.gen(1)) == -L.bracket(L.gen(1), L.gen(0)) True
sage: L = lie_algebras.three_dimensional_by_rank(QQ, 1) sage: L.bracket(L.gen(0), L.gen(1)) == -L.bracket(L.gen(1), L.gen(0)) True
Check inequality::
sage: L = lie_algebras.sl(QQ, 2, representation='matrix') sage: L.bracket(L.gen(0), L.gen(1)) != -L.bracket(L.gen(1), L.gen(0)) False sage: L.zero() == 0 True sage: L.zero() != 0 False
The next doctests show similar behavior, although on elements of other classes::
sage: L = lie_algebras.three_dimensional_by_rank(QQ, 3) sage: L.bracket(L.gen(0), L.gen(1)) != -L.bracket(L.gen(1), L.gen(0)) False sage: L.an_element() X + Y + Z sage: L.an_element() == 0 False sage: L.an_element() != 0 True
sage: L = lie_algebras.three_dimensional_by_rank(QQ, 1) sage: L.bracket(L.gen(0), L.gen(1)) != -L.bracket(L.gen(1), L.gen(0)) False sage: L.zero() == 0 True sage: L.zero() != 0 False sage: L.zero() >= 0 True sage: L.zero() < 0 False """
def _repr_(self): """ Return a string representation of ``self``.
EXAMPLES::
sage: R = FreeAlgebra(QQ, 3, 'x,y,z') sage: L.<x,y,z> = LieAlgebra(associative=R.gens()) sage: x + y x + y """
def _latex_(self): r""" Return a `\LaTeX` representation of ``self``.
EXAMPLES::
sage: R = FreeAlgebra(QQ, 3, 'x') sage: L.<x0,x1,x2> = LieAlgebra(associative=R.gens()) sage: latex(x0 + x1) x_{0} + x_{1} """
def _ascii_art_(self): """ Return an ascii art representation of ``self``.
EXAMPLES::
sage: s = SymmetricFunctions(QQ).s() sage: L = LieAlgebra(associative=s) sage: P = Partition([4,2,2,1]) sage: x = L.basis()[P] sage: ascii_art(x) s **** ** ** * """
def _unicode_art_(self): """ Return a unicode art representation of ``self``.
EXAMPLES::
sage: s = SymmetricFunctions(QQ).s() sage: L = LieAlgebra(associative=s) sage: P = Partition([4,2,2,1]) sage: x = L.basis()[P] sage: unicode_art(x) s ┌┬┬┬┐ ├┼┼┴┘ ├┼┤ ├┼┘ └┘ """
def __nonzero__(self): """ Return if ``self`` is non-zero.
EXAMPLES::
sage: R = FreeAlgebra(QQ, 3, 'x,y,z') sage: L.<x,y,z> = LieAlgebra(associative=R.gens()) sage: bool(L.zero()) False sage: bool(x + y) True """
cpdef _add_(self, right): """ Add ``self`` and ``rhs``.
EXAMPLES::
sage: R = FreeAlgebra(QQ, 3, 'x,y,z') sage: L.<x,y,z> = LieAlgebra(associative=R.gens()) sage: x + y x + y """
cpdef _sub_(self, right): """ Subtract ``self`` and ``rhs``.
EXAMPLES::
sage: R = FreeAlgebra(QQ, 3, 'x,y,z') sage: L.<x,y,z> = LieAlgebra(associative=R.gens()) sage: x - y x - y """
# Need to bypass the coercion model def __mul__(left, right): """ If we are multiplying two non-zero elements, automatically lift up to the universal enveloping algebra.
.. TODO::
Write more tests for this method.
EXAMPLES::
sage: S = SymmetricGroup(3).algebra(QQ) sage: L = LieAlgebra(associative=S) sage: x = L.gen(2); x (1,2,3) sage: y = L.gen(1); y (1,2) sage: u = x*3; u 3*(1,2,3) sage: parent(u) == L True sage: u = x*(3/2); u 3/2*(1,2,3) sage: parent(u) == L True sage: elt = x*y - y*x; elt b4 - b5 sage: xp, yp = x.lift_associative(), y.lift_associative() sage: eltp = xp*yp - yp*xp; eltp (2,3) - (1,3) sage: G = list(S.basis()) sage: G[4] - G[5] (2,3) - (1,3)
TESTS::
sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) sage: L.<x,y> = LieAlgebra(associative=S.gens()) sage: int(3) * x 3*(1,2,3) sage: y * int(3) 3*(1,2) """ # Try the normal coercion first pass
# Lift up to the UEA and try multiplication there # We will eventually want to lift stuff up anyways, # so just do it here.
def __div__(self, x): """ Division by coefficients.
EXAMPLES::
sage: L = lie_algebras.Heisenberg(QQ, 3) sage: x = L.an_element(); x p1 sage: x / 2 1/2*p1 """
cpdef _acted_upon_(self, scalar, bint self_on_left): """ Return the action of a scalar on ``self``.
EXAMPLES::
sage: R = FreeAlgebra(QQ, 3, 'x,y,z') sage: L.<x,y,z> = LieAlgebra(associative=R.gens()) sage: 3*x 3*x sage: parent(3*x) == parent(x) True sage: x / 2 1/2*x sage: y * (1/2) 1/2*y sage: y * 1/2 1/2*y sage: 1/2 * y 1/2*y sage: QQ(1/2) * y 1/2*y """ # This was copied and IDK if it still applies (TCS): # With the current design, the coercion model does not have # enough information to detect apriori that this method only # accepts scalars; so it tries on some elements(), and we need # to make sure to report an error. # Temporary needed by coercion (see Polynomial/FractionField tests). else:
def __neg__(self): """ Return the negation of ``self``.
EXAMPLES::
sage: R = FreeAlgebra(QQ, 3, 'x,y,z') sage: L.<x,y,z> = LieAlgebra(associative=R.gens()) sage: -x -x """
def __getitem__(self, i): """ Redirect the ``__getitem__()`` to the wrapped element.
EXAMPLES::
sage: L = lie_algebras.sl(QQ, 2, representation='matrix') sage: m = L.gen(0) sage: m[0,0] 0 sage: m[0][1] 1 """
def __iter__(self): """ Iterate over ``self``.
EXAMPLES::
sage: G = SymmetricGroup(3) sage: S = G.algebra(QQ) sage: L = LieAlgebra(associative=S) sage: x = L.an_element() + L.basis()[G.one()] sage: x 2*() + (2,3) + (1,2) + (1,2,3) + (1,3,2) + (1,3) sage: list(x) [((2,3), 1), ((1,2), 1), ((1,3), 1), ((1,2,3), 1), ((1,3,2), 1), ((), 2)] """
# TODO: Also used for vectors, find a better name cdef class LieAlgebraMatrixWrapper(LieAlgebraElementWrapper): """ Lie algebra element wrapper around a matrix. """ def __init__(self, parent, value): """ Initialize ``self``.
EXAMPLES::
sage: L = lie_algebras.Heisenberg(QQ, 1, representation="matrix") sage: z = L.z() sage: z.value.is_immutable() True """
cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): """ An element of a Lie algebra given by structure coefficients. """ def _repr_(self): """ EXAMPLES::
sage: L.<x,y> = LieAlgebra(QQ, {('x','y'): {'x':1}}) sage: x - 3/2 * y x - 3/2*y """
def _latex_(self): r""" EXAMPLES::
sage: L.<x,y> = LieAlgebra(QQ, {('x','y'): {'x':1}}) sage: elt = x - 3/2 * y sage: latex(elt) x - \frac{3}{2}y """
cpdef bracket(self, right): """ Return the Lie bracket ``[self, right]``.
EXAMPLES::
sage: L.<x,y,z> = LieAlgebra(QQ, {('x','y'): {'z':1}, ('y','z'): {'x':1}, ('z','x'): {'y':1}}) sage: x.bracket(y) z sage: y.bracket(x) -z sage: (x + y - z).bracket(x - y + z) -2*y - 2*z """ self, right = coercion_model.canonical_coercion(self, right)
# We need this method because the LieAlgebra.bracket method (from the # category) calls this, where we are guaranteed to have the same parent. cpdef _bracket_(self, right): """ Return the Lie bracket ``[self, right]``.
EXAMPLES::
sage: L.<x,y,z> = LieAlgebra(QQ, {('x','y'): {'z':1}, ('y','z'): {'x':1}, ('z','x'): {'y':1}}) sage: x._bracket_(y) z sage: y._bracket_(x) -z """ cdef int i1, i2, i3
def __iter__(self): """ Iterate over ``self``.
EXAMPLES::
sage: L.<x,y> = LieAlgebra(QQ, {('x','y'): {'x':1}}) sage: elt = x - 3/2 * y sage: list(elt) [('x', 1), ('y', -3/2)] """ cdef int i
cpdef to_vector(self): """ Return ``self`` as a vector.
EXAMPLES::
sage: L.<x,y,z> = LieAlgebra(QQ, {('x','y'): {'z':1}}) sage: a = x + 3*y - z/2 sage: a.to_vector() (1, 3, -1/2) """
def lift(self): """ Return the lift of ``self`` to the universal enveloping algebra.
EXAMPLES::
sage: L.<x,y> = LieAlgebra(QQ, {('x','y'): {'x':1}}) sage: elt = x - 3/2 * y sage: l = elt.lift(); l x - 3/2*y sage: l.parent() Noncommutative Multivariate Polynomial Ring in x, y over Rational Field, nc-relations: {y*x: x*y - x} """
cpdef dict monomial_coefficients(self, bint copy=True): """ Return the monomial coefficients of ``self`` as a dictionary.
EXAMPLES::
sage: L.<x,y,z> = LieAlgebra(QQ, {('x','y'): {'z':1}}) sage: a = 2*x - 3/2*y + z sage: a.monomial_coefficients() {'x': 2, 'y': -3/2, 'z': 1} sage: a = 2*x - 3/2*z sage: a.monomial_coefficients() {'x': 2, 'z': -3/2} """
def __getitem__(self, i): """ Return the coefficient of the basis element indexed by ``i``.
EXAMPLES::
sage: L.<x,y> = LieAlgebra(QQ, {('x','y'): {'x':1}}) sage: elt = x - 3/2 * y sage: elt['y'] -3/2 """
cdef class UntwistedAffineLieAlgebraElement(Element): """ An element of an untwisted affine Lie algebra. """ def __init__(self, parent, dict t_dict, c_coeff, d_coeff): """ Initialize ``self``.
TESTS::
sage: L = lie_algebras.Affine(QQ, ['A',2,1]) sage: x = L.an_element() sage: TestSuite(x).run() """
def __reduce__(self): """ Used in pickling.
TESTS::
sage: L = lie_algebras.Affine(QQ, ['B',3,1]) sage: x = L.an_element() sage: loads(dumps(x)) == x True """
def _repr_(self): """ Return a string representation of ``self``.
EXAMPLES::
sage: L = lie_algebras.Affine(QQ, ['A',1,1]) sage: list(L.lie_algebra_generators()) [(E[alpha[1]])#t^0, (E[-alpha[1]])#t^0, (h1)#t^0, (E[-alpha[1]])#t^1, (E[alpha[1]])#t^-1, c, d] sage: L.an_element() (E[alpha[1]] + h1 + E[-alpha[1]])#t^0 + (E[-alpha[1]])#t^1 + (E[alpha[1]])#t^-1 + c + d sage: L.zero() 0
sage: e1,f1,h1,e0,f0,c,d = list(L.lie_algebra_generators()) sage: e1 + 2*f1 - h1 + e0 + 3*c - 2*d (E[alpha[1]] - h1 + 2*E[-alpha[1]])#t^0 + (E[-alpha[1]])#t^1 + 3*c + -2*d """ else:
else:
def _latex_(self): r""" Return a latex representation of ``self``.
EXAMPLES::
sage: L = lie_algebras.Affine(QQ, ['A',1,1]) sage: [latex(g) for g in L.lie_algebra_generators()] [(E_{\alpha_{1}}) \otimes t^{0}, (E_{-\alpha_{1}}) \otimes t^{0}, (E_{\alpha^\vee_{1}}) \otimes t^{0}, (E_{-\alpha_{1}}) \otimes t^{1}, (E_{\alpha_{1}}) \otimes t^{-1}, c, d] sage: latex(L.an_element()) (E_{\alpha_{1}} + E_{\alpha^\vee_{1}} + E_{-\alpha_{1}}) \otimes t^{0} + (E_{-\alpha_{1}}) \otimes t^{1} + (E_{\alpha_{1}}) \otimes t^{-1} + c + d sage: latex(L.zero()) 0
sage: e1,f1,h1,e0,f0,c,d = list(L.lie_algebra_generators()) sage: latex(e1 + 2*f1 - h1 + e0 + 3*c - 2*d) (E_{\alpha_{1}} - E_{\alpha^\vee_{1}} + 2E_{-\alpha_{1}}) \otimes t^{0} + (E_{-\alpha_{1}}) \otimes t^{1} + 3 c + -2 d """ else:
else:
cpdef dict t_dict(self): r""" Return the ``dict``, whose keys are powers of `t` and values are elements of the classical Lie algebra, of ``self``.
EXAMPLES::
sage: L = lie_algebras.Affine(QQ, ['A',1,1]) sage: x = L.an_element() sage: x.t_dict() {-1: E[alpha[1]], 0: E[alpha[1]] + h1 + E[-alpha[1]], 1: E[-alpha[1]]} """
cpdef c_coefficient(self): r""" Return the coefficient of `c` of ``self``.
EXAMPLES::
sage: L = lie_algebras.Affine(QQ, ['A',1,1]) sage: x = L.an_element() - 3 * L.c() sage: x.c_coefficient() -2 """
cpdef d_coefficient(self): r""" Return the coefficient of `d` of ``self``.
EXAMPLES::
sage: L = lie_algebras.Affine(QQ, ['A',1,1]) sage: x = L.an_element() + L.d() sage: x.d_coefficient() 2 """
cpdef _richcmp_(self, other, int op): """ Return the rich comparison of ``self`` with ``other``.
EXAMPLES::
sage: L = lie_algebras.Affine(QQ, ['C',2,1]) sage: x = L.an_element() sage: c = L.basis()['c'] sage: d = L.basis()['d'] sage: c == d False sage: x != c True sage: 2*c - d == c + c - d True sage: x - c != x - c False sage: x - c != x - d True """ return NotImplemented op)
def __hash__(self): """ Return the hash of ``self``.
EXAMPLES::
sage: asl = lie_algebras.Affine(QQ, ['A',4,1]) sage: x = asl.an_element() sage: hash(x) == hash(x) True sage: hash(asl.zero()) 0 """
def __nonzero__(self): """ Return ``self`` as a boolean.
EXAMPLES::
sage: L = lie_algebras.Affine(QQ, ['C',2,1]) sage: x = L.an_element() sage: bool(x) True sage: bool(L.zero()) False """
cpdef _add_(self, other): """ Add ``self`` and ``other``.
EXAMPLES::
sage: L = lie_algebras.Affine(QQ, ['A',1,1]) sage: e1,f1,h1,e0,f0,c,d = list(L.lie_algebra_generators()) sage: e0.bracket(e1) + d + e1 + c + 3*d (E[alpha[1]])#t^0 + (-h1)#t^1 + c + 4*d """
cpdef _sub_(self, other): """ Subtract ``self`` and ``other``.
EXAMPLES::
sage: L = lie_algebras.Affine(QQ, ['A',1,1]) sage: e1,f1,h1,e0,f0,c,d = list(L.lie_algebra_generators()) sage: e0.bracket(e1) + d - e1 + c - 3*d (-E[alpha[1]])#t^0 + (-h1)#t^1 + c + -2*d sage: 4*c - e0.bracket(f0) (h1)#t^0 sage: 4*c - e0.bracket(f0) - h1 0 sage: 4*c - e0.bracket(f0) - h1 == L.zero() True sage: e1 - f1 (E[alpha[1]] - E[-alpha[1]])#t^0 """
cpdef _neg_(self): """ Negate ``self``.
EXAMPLES::
sage: L = lie_algebras.Affine(QQ, ['A',1,1]) sage: e1,f1,h1,e0,f0,c,d = list(L.lie_algebra_generators()) sage: x = e0.bracket(e1) + d + e1 + c + 3*d sage: -x (-E[alpha[1]])#t^0 + (h1)#t^1 + -1*c + -4*d """
cpdef _acted_upon_(self, x, bint self_on_left): """ Return ``self`` acted upon by ``x``.
EXAMPLES::
sage: L = lie_algebras.Affine(QQ, ['A',1,1]) sage: e1,f1,h1,e0,f0,c,d = list(L.lie_algebra_generators()) sage: x = e1 + f0.bracket(f1) + 3*c - 2/5 * d sage: x (E[alpha[1]])#t^0 + (h1)#t^-1 + 3*c + -2/5*d sage: -2 * x (-2*E[alpha[1]])#t^0 + (-2*h1)#t^-1 + -6*c + 4/5*d """
cpdef monomial_coefficients(self, bint copy=True): """ Return the monomial coefficients of ``self``.
EXAMPLES::
sage: L = lie_algebras.Affine(QQ, ['C',2,1]) sage: x = L.an_element() sage: sorted(x.monomial_coefficients(), key=str) [(-2*alpha[1] - alpha[2], 1), (-alpha[1], 0), (-alpha[2], 0), (2*alpha[1] + alpha[2], -1), (alpha[1], 0), (alpha[2], 0), (alphacheck[1], 0), (alphacheck[2], 0), 'c', 'd'] """
cpdef bracket(self, right): """ Return the Lie bracket ``[self, right]``.
EXAMPLES::
sage: L = LieAlgebra(QQ, cartan_type=['A',1,1]) sage: e1,f1,h1,e0,f0,c,d = list(L.lie_algebra_generators()) sage: e0.bracket(f0) (-h1)#t^0 + 4*c sage: e1.bracket(0) 0 sage: e1.bracket(1) Traceback (most recent call last): ... TypeError: no common canonical parent for objects with parents: 'Affine Kac-Moody algebra of ['A', 1] in the Chevalley basis' and 'Integer Ring' """
cpdef _bracket_(self, y): """ Return the Lie bracket ``[self, y]``.
EXAMPLES::
sage: L = LieAlgebra(QQ, cartan_type=['A',1,1]) sage: e1,f1,h1,e0,f0,c,d = list(L.lie_algebra_generators()) sage: al = RootSystem(['A',1]).root_lattice().simple_roots() sage: x = L.basis()[al[1], 5] sage: y = L.basis()[-al[1], -3] sage: z = L.basis()[-al[1], -5] sage: x._bracket_(y) (h1)#t^2 sage: x._bracket_(z) (h1)#t^0 + 20*c sage: x._bracket_(e1) 0 sage: x._bracket_(f1) (h1)#t^5 sage: x._bracket_(h1) (-2*E[alpha[1]])#t^5 sage: x._bracket_(d) (-5*E[alpha[1]])#t^5 sage: all(c._bracket_(g) == 0 for g in L.lie_algebra_generators()) True """
# d contribution from the left else: # main bracket of the central extension else:
# d contribution from the right else:
cpdef canonical_derivation(self): r""" Return the canonical derivation `d` applied to ``self``.
The canonical derivation `d` is defined as
.. MATH::
d(a \otimes t^m + \alpha c) = a \otimes m t^m.
Another formulation is by `d = t \frac{d}{dt}`.
EXAMPLES::
sage: L = lie_algebras.Affine(QQ, ['E',6,1]) sage: al = RootSystem(['E',6]).root_lattice().simple_roots() sage: x = L.basis()[al[2]+al[3]+2*al[4]+al[5],5] + 4*L.c() + L.d() sage: x.canonical_derivation() (5*E[alpha[2] + alpha[3] + 2*alpha[4] + alpha[5]])#t^5 """
def _build_untwisted_affine_element(P, t_dict, c, d): """ Used to unpickle an element.
EXAMPLES::
sage: L = lie_algebras.Affine(QQ, ['A',2,1]) sage: from sage.algebras.lie_algebras.lie_algebra_element import _build_untwisted_affine_element sage: _build_untwisted_affine_element(L, {}, 0, 0) == L.zero() True sage: x = L.an_element() sage: loads(dumps(x)) == x # indirect doctest True """
|