From 9cbd3bd10613c33483b057ff30bb3ee04fb5ac3a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 13 Aug 2014 09:35:04 +0900 Subject: [PATCH 001/223] Initial import from #14901 and started another example. --- ...ite_dimensional_lie_algebras_with_basis.py | 125 +++++ src/sage/categories/examples/lie_algebras.py | 111 +++++ ...ite_dimensional_lie_algebras_with_basis.py | 426 ++++++++++++++++++ src/sage/categories/lie_algebras.py | 389 ++++++++++++++++ .../categories/lie_algebras_with_basis.py | 68 +++ 5 files changed, 1119 insertions(+) create mode 100644 src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py create mode 100644 src/sage/categories/examples/lie_algebras.py create mode 100644 src/sage/categories/finite_dimensional_lie_algebras_with_basis.py create mode 100644 src/sage/categories/lie_algebras.py create mode 100644 src/sage/categories/lie_algebras_with_basis.py diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py new file mode 100644 index 00000000000..1748df31e45 --- /dev/null +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -0,0 +1,125 @@ +r""" +Examples of a finite dimensional Lie algebra with basis +""" +#***************************************************************************** +# Copyright (C) 2014 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.sets.family import Family +from sage.categories.all import LieAlgebras +from sage.modules.free_module import FreeModule +from sage.structure.parent import parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.element_wrapper import ElementWrapper + +class AbelianLieAlgebra(Parent, UniqueRepresentation): + r""" + An example of a finite dimensional Lie algebra with basis: + the abelian Lie algebra. + + This class illustrates a minimal implementation of a finite dimensional + Lie algebra with basis. + """ + @staticmethod + def __classcall_private__(cls, R, names): + """ + Normalize input to ensure a unique representation. + """ + return super(AbelianLieAlgebra, cls).__classcall__(cls, R, tuple(names)) + + def __init__(self, R, names): + """ + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example(); L + An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field + sage: TestSuite(L).run() + """ + self._M = FreeModule(R, len(names)) + cat = LieAlgebras(R).FiniteDimensional().WithBasis() + Parent.__init__(self, names=names, category=cat) + + def _construct_UEA(self): + """ + Construct the universal enveloping algebra of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L._construct_UEA() + Multivariate Polynomial Ring in a, b, c over Rational Field + """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(self.base_ring(), self.variable_names()) + + def _repr_(self): + """ + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field + """ + return "An example of a finite dimensional Lie algebra with basis:"\ + " the abelian Lie algebra on the generators "\ + " {} over {}".format(self.lie_algebra_generators(), self.base_ring()) + + def basis(self): + """ + Return the basis of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.basis() + """ + d = {} + names = self.variable_names() + for i,b in enumerate(self._M.basis()): + d[names[i]] = self.element_class(self, b) + return Family(d) + + def lie_algebra_generators(self): + """ + Return the generators of ``self`` as a Lie algebra. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.lie_algebra_generators() + """ + return self.basis() + + def bracket_on_basis(self, x, y): + """ + Return the Lie bracket on basis elements indexed by ``x`` and ``y``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.bracket_on_basis('a', 'c') + 0 + """ + return self.zero() + + class Element(ElementWrapper): + def lift(self): + """ + Return the lift of ``self`` to the universal enveloping algebra. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: elt = L.an_element() + sage: elt.lift() + 2*a + 2*b + 3*c + """ + UEA = self.parent().universal_enveloping_algebra() + gens_dict = UEA.gens_dict() + return UEA.sum(c * gens_dict[t] for t, c in self) + +Example = AbelianLieAlgebra + diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py new file mode 100644 index 00000000000..4516df2599b --- /dev/null +++ b/src/sage/categories/examples/lie_algebras.py @@ -0,0 +1,111 @@ +r""" +Examples of a Lie algebra +""" +#***************************************************************************** +# Copyright (C) 2014 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.sets.family import Family +from sage.categories.all import LieAlgebras +from sage.combinat.free_module import CombinatorialFreeModule + +class AbelianLieAlgebra(CombinatorialFreeModule): + r""" + An example of a Lie algebra: the abelian Lie algebra. + + This class illustrates a minimal implementation of a Lie algebra. + """ + def __init__(self, R, gens): + """ + EXAMPLES:: + + sage: A = LieAlgebras(QQ).example(); A + An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field + sage: TestSuite(A).run() + """ + cat = LieAlgebras(R).WithBasis() + CombinatorialFreeModule.__init__(self, R, gens, category=cat) + + def _construct_UEA(self): + """ + Construct the universal enveloping algebra of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: L._construct_UEA() + Multivariate Polynomial Ring in a, b, c over Rational Field + """ + # TODO: Implement using a combinatorial free module with a free abelian monoid + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(self.base_ring(), self.variable_names()) + + def _repr_(self): + """ + EXAMPLES:: + + sage: LieAlgebras(QQ).example() + An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field + """ + return "An example of a Lie algebra: the abelian Lie algebra on the" \ + " generators indexed by {} over {}".format( + self.basis().keys(), self.base_ring()) + + def lie_algebra_generators(self): + """ + Return the generators of ``self`` as a Lie algebra. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: L.lie_algebra_generators() + (B['a'], B['b'], B['c']) + """ + return self.basis() + + def bracket_on_basis(self, x, y): + """ + Return the Lie bracket on basis elements indexed by ``x`` and ``y``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: L.bracket_on_basis('a', 'c') + 0 + """ + return self.zero() + + def is_solvable(self): + """ + Return if ``self`` is a solvable Lie algebra. + """ + return True + + def is_nilpotent(self): + """ + Return if ``self`` is a nilpotent Lie algebra. + """ + return True + + class Element(CombinatorialFreeModule.Element): + def lift(self): + """ + Return the lift of ``self`` to the universal enveloping algebra. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: elt = L.an_element() + sage: elt.lift() + 2*a + 2*b + 3*c + """ + UEA = self.parent().universal_enveloping_algebra() + gens_dict = UEA.gens_dict() + return UEA.sum(c * gens_dict[t] for t, c in self) + +Example = AbelianLieAlgebra + diff --git a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py new file mode 100644 index 00000000000..f6c191cff53 --- /dev/null +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -0,0 +1,426 @@ +r""" +Finite Dimensional Lie Algebras With Basis + +AUTHORS: + +- Travis Scrimshaw (07-15-2013): Initial implementation +""" +#***************************************************************************** +# Copyright (C) 2013 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method +from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring +from sage.categories.lie_algebras import LieAlgebras +from sage.rings.all import ZZ +from sage.algebras.free_algebra import FreeAlgebra +from sage.algebras.lie_algebras.lie_algebra_element import LieBracket +from sage.sets.family import Family +from sage.matrix.constructor import matrix + +class FiniteDimensionalLieAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): + """ + Category of finite dimensional Lie algebras with a basis. + """ + _base_category_class_and_axiom = [LieAlgebras.FiniteDimensional, "WithBasis"] + + def example(self, names=('a', 'b', 'c')): + """ + Return an example of a finite dimensional Lie algebra with basis as per + :meth:`Category.example `. + + EXAMPLES:: + + sage: C = LieAlgebras(QQ).FiniteDimensional().WithBasis() + sage: C.example() + An example of a Lie algebra: the abelian Lie algebra on the generators ('a', 'b', 'c') over Rational Field + + Other names of generators can be specified as an optional argument:: + + sage: C.example(('x','y','z')) + An example of a Lie algebra: the abelian Lie algebra on the generators ('a', 'b', 'c') over Rational Field + """ + from sage.categories.examples.finite_dimensional_lie_algebras_with_basis import Example + return Example(self.base_ring(), gens) + + class ParentMethods: + @cached_method + def _construct_UEA(self): + """ + Construct the universal enveloping algebra of ``self``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) + sage: L._construct_UEA() + """ + # Create the UEA relations + # We need to get names for the basis elements, not just the generators + try: + names = self.variable_names() + except ValueError: + names = tuple('b{}'.format(i) for i in range(self.dimension())) + I = self._indices + F = FreeAlgebra(self.base_ring(), names) + gens = F.gens() + d = F.gens_dict() + rels = {} + S = self.structure_coefficients() + for k in S.keys(): + g0 = d[names[I.index(k._left)]] + g1 = d[names[I.index(k._right)]] + if g0 < g1: + rels[g1*g0] = g0*g1 - sum(val*d[g._name] for g, val in S[k]) + else: + rels[g0*g1] = g1*g0 + sum(val*d[g._name] for g, val in S[k]) + return F.g_algebra(rels) + + def killing_matrix(self, x, y): + r""" + Return the Killing matrix of ``x`` and ``y``. + + The Killing form is defined as the matrix corresponding to the + action of `\mathrm{ad}_x \circ \mathrm{ad}_y` in the basis + of ``self``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: L.killing_matrix(x, y) + [ 0 0] + [-1 0] + """ + return x.adjoint_matrix() * y.adjoint_matrix() + + def killing_form(self, x, y): + r""" + Return the Killing form on ``x`` and ``y``. + + The Killing form is defined as + + .. MATH:: + + \langle x \mid y \rangle = \mathrm{tr}\left( \mathrm{ad}_x + \circ \mathrm{ad}_y \right). + """ + return self.killing_matrix(x, y).trace() + + @cached_method + def killing_form_matrix(self): + """ + Return the matrix of the Killing form of ``self``. + """ + B = self.basis() + m = matrix([[self.killing_form(x, y) for x in B] for y in B]) + m.set_immutable() + return m + + @cached_method + def structure_coefficients(self): + """ + Return the non-trivial structure coefficients of ``self``. + In particular, if `[x, y] = 0`, then we don't include it in the + output. + """ + d = {} + B = self.basis() + K = self.basis().keys() + one = self.base_ring().one() + for i,x in enumerate(K): + for y in K[i+1:]: + bx = B[x] + by = B[x] + if self._basis_cmp(x, y) > 0: + d[(y, x)] = self.bracket(by, bx) + else: + d[(x, y)] = self.bracket(bx, by) + return Family(d) + + # TODO: This will be removed once the generic LieSubalgebra is + # included from #14901 + @abstract_method + def subalgebra(self, gens): + """ + Return the subalgebra of ``self`` generated by ``gens``. + """ + + def centralizer(self, S): + """ + Return the centralizer of ``S`` in ``self``. + """ + #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra + #if isinstance(S, LieSubalgebra) or S is self: + if S is self: + K = S + else: + K = self.subalgebra(S) + + m = K.basis_matrix() + S = self.structure_coefficients() + sc = {k: S[k].to_vector() for k in S} + X = self.basis() + d = self.dimension() + c_mat = matrix([[sum(r[j]*sc[x,X[j]][k] for j in range(d)) for x in X] + for r in m for k in range(d)]) + C = c_mat.right_kernel() + return self.subalgebra(C) # TODO: convert C back to elements of ``self`` + + def center(self): + """ + Return the center of ``self``. + """ + return self.centralizer(self) + + def normalizer(self, V): + """ + Return the normalizer of ``V`` in ``self``. + """ + #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra + #if not isinstance(V, LieSubalgebra) and V is not self: + if V is not self: + V = self.subalgebra(V) + + m = V.basis_matrix() + S = self.structure_coefficients() + sc = {k: S[k].to_vector() for k in S} + X = self.basis() + d = self.dimension() + t = m.nrows() + n_mat = matrix([[sum(r[j]*sc[x,X[j]][k] for j in range(d)) for x in X] + + [0]*(t*l) + [m[j][k] for j in range(t)] + [0]*(t*(t-l-1)) + for l,r in enumerate(m.rows()) for k in range(d)]) + N = n_mat.right_kernel() + # TODO: convert N back to elements of ``self`` by taking the first ``n`` coefficients + return self.subalgebra(N) + + def product_space(self, L): + r""" + Return the product space ``[self, L]``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: Lp = L.product_space(L) + sage: Lp + Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: + (x,) + sage: Lp.product_space(L) + Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: + (x,) + sage: L.product_space(Lp) + Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: + (x,) + sage: Lp.product_space(Lp) + Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: + () + """ + # Make sure we lift everything to the ambient space + try: + A = self._ambient + except AttributeError: + try: + A = L._ambient + except AttributeError: + A = self + + B = self.basis() + LB = L.basis() + K = B.keys() + LK = LB.keys() + # We echelonize the matrix here + b_mat = matrix(A.base_ring(), [A.bracket(B[a], LB[b]).to_vector() + for a in K for b in LK]) + b_mat.echelonize() + r = b_mat.rank() + I = A._ordered_indices + gens = [A.element_class(A, {I[i]: v for i,v in row.iteritems()}) + for row in b_mat.rows()[:r]] + return A.subalgebra(gens) + + @cached_method + def derived_subalgebra(self): + """ + Return the derived subalgebra of ``self``. + + EXAMPLES:: + """ + return self.product_space(self) + + @cached_method + def derived_series(self): + r""" + Return the derived series `(\mathfrak{g}^{(i)})_i` of ``self`` + where the rightmost + `\mathfrak{g}^{(k)} = \mathfrak{g}^{(k+1)} = \cdots`. + + We define the derived series of a Lie algebra `\mathfrak{g}` + recursively by `\mathfrak{g}^{(0)} := \mathfrak{g}` and + + .. MATH:: + + \mathfrak{g}^{(k+1)} = + [\mathfrak{g}^{(k)}, \mathfrak{g}^{(k)}] + + and recall that + `\mathfrak{g}^{(k)} \subseteq \mathfrak{g}^{(k+1)}`. + Alternatively we canexpress this as + + .. MATH:: + + \mathfrak{g} \subseteq [\mathfrak{g}, \mathfrak{g}] \subseteq + \bigl[ [\mathfrak{g}, \mathfrak{g}], [\mathfrak{g}, + \mathfrak{g}] \bigr] \subseteq + \biggl[ \bigl[ [\mathfrak{g}, \mathfrak{g}], [\mathfrak{g}, + \mathfrak{g}] \bigr], \bigl[ [\mathfrak{g}, \mathfrak{g}], + [\mathfrak{g}, \mathfrak{g}] \bigr] \biggr] \subseteq \cdots. + + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: L.derived_series() + (Lie algebra on 2 generators (x, y) over Rational Field, + Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: + (x,), + Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: + ()) + """ + L = [self] + while L[-1].dimension() > 0: + p = L[-1].derived_subalgebra() + if L[-1].dimension() == p.dimension(): + break + L.append(p) + return tuple(L) + + @cached_method + def lower_central_series(self): + r""" + Return the lower central series `(\mathfrak{g}_{i})_i` + of ``self`` where the rightmost + `\mathfrak{g}_k = \mathfrak{g}_{k+1} = \cdots`. + + We define the lower central series of a Lie algebra `\mathfrak{g}` + recursively by `\mathfrak{g}_0 := \mathfrak{g}` and + + .. MATH:: + + \mathfrak{g}_{k+1} = [\mathfrak{g}, \mathfrak{g}_{k}] + + and recall that `\mathfrak{g}_k} \subseteq \mathfrak{g}_{k+1}`. + Alternatively we can express this as + + .. MATH:: + + \mathfrak{g} \subseteq [\mathfrak{g}, \mathfrak{g}] \subseteq + \bigl[ [\mathfrak{g}, \mathfrak{g}], \mathfrak{g} \bigr] + \subseteq\biggl[\bigl[ [\mathfrak{g}, \mathfrak{g}], + \mathfrak{g} \bigr], \mathfrak{g}\biggr] \subseteq \cdots. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: L.derived_series() + (Lie algebra on 2 generators (x, y) over Rational Field, + Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: + (x,)) + """ + L = [self] + while L[-1].dimension() > 0: + s = self.product_space(L[-1]) + if L[-1].dimension() == s.dimension(): + break + L.append(s) + return tuple(L) + + def is_abelian(self): + """ + Return if ``self`` is an abelian Lie algebra. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: L.is_abelian() + False + """ + return not self.structure_coefficients() + + def is_solvable(self): + r""" + Return if ``self`` is a solvable Lie algebra. + + A Lie algebra is solvable if the derived series eventually + becomes `0`. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: L.is_abelian() + False + """ + return not self.derived_series()[-1].dimension() + + def is_nilpotent(self): + r""" + Return if ``self`` is a nilpotent Lie algebra. + + A Lie algebra is nilpotent if the lower central series eventually + becomes `0`. + """ + return not self.lower_central_series()[-1].dimension() + + def is_semisimple(self): + """ + Return if ``self`` if a semisimple Lie algebra. + + A Lie algebra is semisimple if the solvable radical is zero. This + is equivalent to saying the Killing form is non-degenerate + (in characteristic 0). + """ + return not self.killing_form_matrix().is_singular() + + def dimension(self): + """ + Return the dimension of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, 'x,y', {('x','y'): {'x':1}}) + sage: L.dimension() + 2 + """ + return ZZ(len(self.basis())) + + class ElementMethods: + def to_vector(self): + """ + Return ``self`` as a vector. + """ + M = self.parent().free_module() + if not self: + return M.zero() + B = M.basis() + return M.sum(B[k]*self[k] for k in self.parent()._ordered_indices) + + def adjoint_matrix(self): # In #11111 (more or less) by using matrix of a mophism + """ + Return the matrix of the adjoint action of ``self``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: x.adjoint_matrix() + [1 0] + [0 0] + sage: y.adjoint_matrix() + [ 0 0] + [-1 0] + """ + P = self.parent() + basis = P.basis() + return matrix([P.bracket(self, b).to_vector() for b in basis]) + diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py new file mode 100644 index 00000000000..e7e0d607f3c --- /dev/null +++ b/src/sage/categories/lie_algebras.py @@ -0,0 +1,389 @@ +r""" +Lie Algebras + +AUTHORS: + +- Travis Scrimshaw (07-15-2013): Initial implementation +""" +#***************************************************************************** +# Copyright (C) 2013 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.lazy_import import LazyImport +from sage.categories.category_types import Category_over_base_ring +from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring +from sage.categories.distributive_magmas_and_additive_magmas import DistributiveMagmasAndAdditiveMagmas +from sage.categories.finite_enuemrated_sets import FiniteEnumeratedSets +from sage.categories.modules import Modules +from sage.categories.sets_cat import Sets +from sage.categories.homset import Hom +from sage.categories.morphism import Morphism +from sage.structure.sage_object import have_same_parent +from sage.structure.element import get_coercion_model, coerce_binop + +class LieAlgebras(Category_over_base_ring): + """ + The category of Lie algebras. + + EXAMPLES:: + + sage: C = LieAlgebras(QQ); C + Category of Lie algebras over Rational Field + sage: sorted(C.super_categories(), key=str) + [Category of vector spaces over Rational Field] + + We construct a typical parent in this category, and do some + computations with it:: + + sage: A = C.example(); A + An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field + + sage: A.category() + Category of Lie algebras with basis over Rational Field + + sage: A.base_ring() + Rational Field + sage: A.basis().keys() + {'a', 'b', 'c'} + + sage: (a,b,c) = A.gens() + sage: a^3, b^2 + (a^3, b^2) + sage: a*c*b + a*b*c + + sage: A.product + + sage: A.product(a*b,b) + a*b^2 + + sage: TestSuite(A).run(verbose=True) + running ._test_additive_associativity() . . . pass + running ._test_an_element() . . . pass + running ._test_category() . . . pass + running ._test_characteristic() . . . pass + running ._test_distributivity() . . . pass + running ._test_elements() . . . + Running the test suite of self.an_element() + running ._test_category() . . . pass + running ._test_eq() . . . pass + running ._test_nonzero_equal() . . . pass + running ._test_not_implemented_methods() . . . pass + running ._test_pickling() . . . pass + pass + running ._test_elements_eq_reflexive() . . . pass + running ._test_elements_eq_symmetric() . . . pass + running ._test_elements_eq_transitive() . . . pass + running ._test_elements_neq() . . . pass + running ._test_eq() . . . pass + running ._test_not_implemented_methods() . . . pass + running ._test_pickling() . . . pass + running ._test_prod() . . . pass + running ._test_some_elements() . . . pass + running ._test_zero() . . . pass + sage: A.__class__ + + sage: A.element_class + + + Please see the source code of `A` (with ``A??``) for how to + implement other Lie algebras. + + TESTS:: + + sage: TestSuite(LieAlgebras(QQ)).run() + """ + @cached_method + def super_categories(self): + """ + EXAMPLES:: + + sage: LieAlgebras(QQ).super_categories() + [Category of vector spaces over Rational Field] + """ + # We do not also derive from (Magmatic) algebras since we don't want * + # to be our Lie bracket + # Also this doesn't inherit the ability to add axioms like Associative + # and Unital, both of which do not make sense for Lie algebras + return [Modules(self.base_ring())] + + def example(self, gens=None): + """ + Return an example of a Lie algebra as per + :meth:`Category.example `. + + EXAMPLES:: + + sage: LieAlgebras(QQ).example() + An example of a Lie algebra: the abelian Lie algebra on the generators ('a', 'b', 'c') over Rational Field + + Another set of generators can be specified as an optional argument:: + + sage: LieAlgebras(QQ).example(('x','y','z')) + An example of a Lie algebra: the abelian Lie algebra on the generators ('a', 'b', 'c') over Rational Field + """ + if gens is None: + from sage.combinat.partition import Partitions + gens = Partitions() + from sage.categories.examples.lie_algebras import Example + return Example(self.base_ring(), gens) + + WithBasis = LazyImport('sage.categories.lie_algebras_with_basis', + 'LieAlgebrasWithBasis', as_name='WithBasis') + + class FiniteDimensional(CategoryWithAxiom_over_base_ring): + WithBasis = LazyImport('sage.categories.finite_dimensional_lie_algebras_with_basis', + 'FiniteDimensionalLieAlgebrasWithBasis', as_name='WithBasis') + + def extra_super_categories(self): + """ + Implements the fact that a finite dimensional Lie algebra over + a finite ring is finite. + + EXAMPLES:: + + sage: Modules(IntegerModRing(4)).FiniteDimensional().extra_super_categories() + [Category of finite sets] + sage: Modules(ZZ).FiniteDimensional().extra_super_categories() + [] + sage: Modules(GF(5)).FiniteDimensional().is_subcategory(Sets().Finite()) + True + sage: Modules(ZZ).FiniteDimensional().is_subcategory(Sets().Finite()) + False + """ + if self.base_ring() in Sets().Finite(): + return [Sets().Finite()] + return [] + + class ParentMethods: + def bracket(self, lhs, rhs): + """ + Return the Lie bracket ``[lhs, rhs]`` after coercing ``lhs`` and + ``rhs`` into elements of ``self``. + """ + return self(lhs)._bracket_(self(rhs)) + + # Do not override this, instead implement _construct_UEA() in order + # to automatically setup the coercion + def universal_enveloping_algebra(self): + """ + Return the universal enveloping algebra of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) + sage: L.universal_enveloping_algebra() + Multivariate Polynomial Ring in x0, x1, x2 over Rational Field + """ + return self.lift.codomain() + + @abstract_method(optional=True) + def _construct_UEA(self): + """ + Construct the universal enveloping algebra of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) + sage: L.universal_enveloping_algebra() # indirect doctest + Multivariate Polynomial Ring in x0, x1, x2 over Rational Field + """ + + @lazy_attribute + def lift(self): + """ + Construct the lift morphism from ``self`` to the universal + enveloping algebra of ``self``. + """ + M = LiftMorphism(self, self._construct_UEA()) + M.register_as_coercion() + return M + + @abstract_method(optional=True) + def killing_form(self, x, y): + """ + Return the Killing form of ``x`` and ``y``. + """ + + def is_abelian(self): + r""" + Return ``True`` if this Lie algebra is abelian. + + A Lie algebra `\mathfrak{g}` is abelian if `[x, y] = 0` for all + `x, y \in \mathfrak{g}`. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ,1) + sage: L.is_abelian() + True + sage: L. = LieAlgebra(QQ,2) + sage: L.is_abelian() + False + """ + G = self.lie_algebra_generators() + if G not in FiniteEnumeratedSets(): + raise NotImplementedError("infinite number of generators") + zero = self.zero() + return all(x._bracket_(y) == zero for x in G for y in G) + + def is_commutative(self): + """ + Return if ``self`` is commutative. This is equivalent to ``self`` + being abelian. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, 1) + sage: L.is_commutative() + True + """ + return self.is_abelian() + + def is_field(self, proof=True): + """ + Return ``False`` since Lie algebras are never a field since + they are not associative and antisymmetric. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, 1, 'x', abelian=True) + sage: L.is_field() + False + """ + return False + + @abstract_method(optional=True) + def is_solvable(self): + """ + Return if ``self`` is a solvable Lie algebra. + """ + + @abstract_method(optional=True) + def is_nilpotent(self): + """ + Return if ``self`` is a nilpotent Lie algebra. + """ + + def _test_jacobi_identity(self, **options): + """ + Test that the Jacobi identity is satisfied. + """ + tester = self._tester(**options) + elts = self.some_elements() + jacobi = lambda x, y, z: self.bracket(x, self.bracket(y, z)) + \ + self.bracket(y, self.bracket(z, x)) + \ + self.bracket(z, self.bracket(x, y)) + zero = self.zero() + for x in elts: + for y in elts: + if x == y: + continue + for z in elts: + if x == z or y == z: # Trivial + continue + tester.assert_(jacobi(x, y, z) == zero) + + def _test_distributivity(self, **options): + r""" + Test the distributivity of the Lie bracket `[,]` on `+` on (not + necessarily all) elements of this set. + + INPUT:: + + - ``options`` -- any keyword arguments accepted by :meth:`_tester`. + + EXAMPLES: + + By default, this method runs the tests only on the + elements returned by ``self.some_elements()``:: + + sage: LieAlgebra(QQ, 3, 'x,y,z').some_elements() + [x] + sage: LieAlgebra(QQ, 3, 'x,y,z')._test_distributivity() + + However, the elements tested can be customized with the + ``elements`` keyword argument:: + + sage: L = LieAlgebra(QQ, cartan_type=['A', 2]) + sage: h1 = L.gen(0) + sage: h2 = L.gen(1) + sage: e2 = L.gen(3) + sage: L._test_distributivity(elements=[h1, h2, e2]) + + See the documentation for :class:`TestSuite` for more information. + """ + tester = self._tester(**options) + S = tester.some_elements() + P = S[0].parent() + from sage.combinat.cartesian_product import CartesianProduct + for x,y,z in tester.some_elements(CartesianProduct(S,S,S)): + # left distributivity + tester.assert_(P.bracket(x, (y + z)) == P.bracket(x, y) + P.bracket(x, z)) + # right distributivity + tester.assert_(P.bracket((x + y), z) == P.bracket(x, z) + P.bracket(y, z)) + + class ElementMethods: + @coerce_binop + def bracket(self, rhs): + """ + Return the Lie bracket ``[self, rhs]``. + """ + return self._bracket_(rhs) + + # Implement this in order to avoid having to deal with the coercions + @abstract_method(optional=True) + def _bracket_(self, y): + """ + Return the Lie bracket ``[self, y]``. + + EXAMPLES:: + """ + + def lift(self): + """ + Lift ``self`` into an element of the universal enveloping algebra. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, abelian=True) + sage: x.lift() + x + """ + return self.parent().lift(self) + + def killing_form(self, x): + """ + Return the Killing form of ``self`` and ``x``. + """ + return self.parent().killing_form(self, x) + +class LiftMorphism(Morphism): + """ + The natural lifting morphism from a Lie algebra to its universal + enveloping algebra. + """ + def __init__(self, domain, codomain): + """ + Initialize ``self``. + """ + Morphism.__init__(self, Hom(domain, codomain)) + + def _call_(self, x): + """ + Lift ``x`` to the universal enveloping algebra. + """ + return x.lift() + + def section(self): + """ + Return the section map of ``self``. + """ + raise NotImplementedError + diff --git a/src/sage/categories/lie_algebras_with_basis.py b/src/sage/categories/lie_algebras_with_basis.py new file mode 100644 index 00000000000..50bd064379b --- /dev/null +++ b/src/sage/categories/lie_algebras_with_basis.py @@ -0,0 +1,68 @@ +r""" +Lie Algebras With Basis + +AUTHORS: + +- Travis Scrimshaw (07-15-2013): Initial implementation +""" +#***************************************************************************** +# Copyright (C) 2013 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method +from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring +from sage.categories.lie_algebras import LieAlgebras +from sage.algebras.lie_algebras.lie_algebra_element import LieBracket + +class LieAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): + """ + Category of Lie algebras with a basis. + """ + _base_category_class_and_axiom = [LieAlgebras, "WithBasis"] + + class ParentMethods: + def _basis_cmp(self, x, y): + """ + Compare two basis element indices. The default is to call ``cmp``. + """ + return cmp(x, y) + + @abstract_method(optional=True) + def bracket_on_basis(self, x, y): + """ + Return the bracket of basis elements indexed by ``x`` and ``y`` + where ``x < y``. If this is not implemented, then the method + ``_bracket_()`` for the elements must be overwritten. + """ + + def free_module(self): + """ + Return ``self`` as a free module. + """ + from sage.combinat.free_module import CombinatorialFreeModule + try: + # Try to see if it has an indexing set + return CombinatorialFreeModule(self.base_ring(), self.basis().keys()) + except AttributeError: + # Otherwise just index by the basis of ``self`` as a fallback + return CombinatorialFreeModule(self.base_ring(), self.basis()) + + class ElementMethods: + def _bracket_(self, y): + """ + Return the Lie bracket of ``[self, y]``. + """ + P = self.parent() + def term(ml,mr): + comp = P._basis_cmp(ml,mr) + if comp == 0: + return P.zero() + if comp < 0: + return P.bracket_on_basis(ml, mr) + return -P.bracket_on_basis(mr, ml) + return P.sum(cl*cr * term(ml,mr) for ml,cl in self for mr,cr in y) + From 16aaa7270832d441530967f6bbdc004e12e55b58 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 15 Aug 2014 09:53:36 +0530 Subject: [PATCH 002/223] Better implementation of Lie algebra examples. --- src/sage/categories/all.py | 1 + src/sage/categories/examples/lie_algebras.py | 127 ++++++++++-------- .../examples/lie_algebras_with_basis.py | 112 +++++++++++++++ ...ite_dimensional_lie_algebras_with_basis.py | 13 +- src/sage/categories/lie_algebras.py | 23 +++- .../categories/lie_algebras_with_basis.py | 22 ++- 6 files changed, 224 insertions(+), 74 deletions(-) create mode 100644 src/sage/categories/examples/lie_algebras_with_basis.py diff --git a/src/sage/categories/all.py b/src/sage/categories/all.py index 989e04d536d..3f920211c13 100644 --- a/src/sage/categories/all.py +++ b/src/sage/categories/all.py @@ -69,6 +69,7 @@ from coalgebras import Coalgebras from bialgebras import Bialgebras from hopf_algebras import HopfAlgebras +from lie_algebras import LieAlgebras # specific algebras from monoid_algebras import MonoidAlgebras diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py index 4516df2599b..35ffea9d560 100644 --- a/src/sage/categories/examples/lie_algebras.py +++ b/src/sage/categories/examples/lie_algebras.py @@ -11,15 +11,24 @@ from sage.misc.cachefunc import cached_method from sage.sets.family import Family from sage.categories.all import LieAlgebras -from sage.combinat.free_module import CombinatorialFreeModule +from sage.structure.parent import Parent +from sage.structure.element import ModuleElement +from sage.structure.unique_representation import UniqueRepresentation -class AbelianLieAlgebra(CombinatorialFreeModule): +class LieAlgebraFromAssociative(Parent, UniqueRepresentation): r""" - An example of a Lie algebra: the abelian Lie algebra. + An example of a Lie algebra: a Lie algebra from an associative algebra. This class illustrates a minimal implementation of a Lie algebra. """ - def __init__(self, R, gens): + @staticmethod + def __classcall_private__(cls, gens): + """ + Normalize input to ensure a unique representation. + """ + return super(LieAlgebraFromAssociative, cls).__classcall__(cls, tuple(gens)) + + def __init__(self, gens): """ EXAMPLES:: @@ -27,33 +36,35 @@ def __init__(self, R, gens): An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field sage: TestSuite(A).run() """ - cat = LieAlgebras(R).WithBasis() - CombinatorialFreeModule.__init__(self, R, gens, category=cat) + if not gens: + raise ValueError("need at least one generator") + self._gens = gens + self._A = gens[0].parent() + R = self._A.base_ring() + Parent.__init__(self, base=R, category=LieAlgebras(R)) - def _construct_UEA(self): + def _repr_(self): """ - Construct the universal enveloping algebra of ``self``. - EXAMPLES:: - sage: L = LieAlgebras(QQ).example() - sage: L._construct_UEA() - Multivariate Polynomial Ring in a, b, c over Rational Field + sage: LieAlgebras(QQ).example() + An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field """ - # TODO: Implement using a combinatorial free module with a free abelian monoid - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - return PolynomialRing(self.base_ring(), self.variable_names()) + return "An example of a Lie algebra: the Lie algebra from an" \ + " associative algebra generated by {} over {}".format( + self._gens, self.base_ring()) - def _repr_(self): + def _element_constructor_(self, value): """ - EXAMPLES:: + Return an element of ``self``. + """ + return self.element_class(self, self._A(value)) - sage: LieAlgebras(QQ).example() - An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field + def zero(self): """ - return "An example of a Lie algebra: the abelian Lie algebra on the" \ - " generators indexed by {} over {}".format( - self.basis().keys(), self.base_ring()) + Return the element 0. + """ + return self.element_class(self, self._A.zero()) def lie_algebra_generators(self): """ @@ -65,47 +76,53 @@ def lie_algebra_generators(self): sage: L.lie_algebra_generators() (B['a'], B['b'], B['c']) """ - return self.basis() - - def bracket_on_basis(self, x, y): - """ - Return the Lie bracket on basis elements indexed by ``x`` and ``y``. + return Family([self.element_class(self, g) for g in self._gens]) - EXAMPLES:: + class Element(ModuleElement): + def __init__(self, parent, value): + """ + Initialize ``self``. + """ + self._value = value + ModuleElement.__init__(self, parent) - sage: L = LieAlgebras(QQ).example() - sage: L.bracket_on_basis('a', 'c') - 0 - """ - return self.zero() + def _repr_(self): + """ + Return a string representation of ``self``. + """ + return repr(self._value) - def is_solvable(self): - """ - Return if ``self`` is a solvable Lie algebra. - """ - return True + def __eq__(self, rhs): + """ + Check equality. + """ + if not isinstance(rhs, LieAlgebraFromAssociative.Element): + return False + return self.parent() == rhs.parent() and self._value == rhs._value - def is_nilpotent(self): - """ - Return if ``self`` is a nilpotent Lie algebra. - """ - return True + def __nonzero__(self): + """ + Check non-zero. + """ + return not self._value - class Element(CombinatorialFreeModule.Element): - def lift(self): + def _add_(self, rhs): + """ + Add ``self`` to ``rhs``. """ - Return the lift of ``self`` to the universal enveloping algebra. + return self.__class__(self.parent(), self._value + rhs._value) - EXAMPLES:: + def _bracket_(self, rhs): + """ + Return the Lie bracket ``[self, rhs]``. + """ + return self.__class__(self.parent(), self._value * rhs._value - rhs._value * self._value) - sage: L = LieAlgebras(QQ).example() - sage: elt = L.an_element() - sage: elt.lift() - 2*a + 2*b + 3*c + def _mul_(self, rhs): + r""" + When multiplying elements, lift up to the associative algebra. """ - UEA = self.parent().universal_enveloping_algebra() - gens_dict = UEA.gens_dict() - return UEA.sum(c * gens_dict[t] for t, c in self) + return self._value * rhs._value -Example = AbelianLieAlgebra +Example = LieAlgebraFromAssociative diff --git a/src/sage/categories/examples/lie_algebras_with_basis.py b/src/sage/categories/examples/lie_algebras_with_basis.py new file mode 100644 index 00000000000..851b256c453 --- /dev/null +++ b/src/sage/categories/examples/lie_algebras_with_basis.py @@ -0,0 +1,112 @@ +r""" +Examples of a Lie algebra with basis +""" +#***************************************************************************** +# Copyright (C) 2014 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.sets.family import Family +from sage.categories.all import LieAlgebras +from sage.combinat.free_module import CombinatorialFreeModule + +class AbelianLieAlgebra(CombinatorialFreeModule): + r""" + An example of a Lie algebra: the abelian Lie algebra. + + This class illustrates a minimal implementation of a Lie algebra with + a distinguished basis. + """ + def __init__(self, R, gens): + """ + EXAMPLES:: + + sage: A = LieAlgebras(QQ).example(); A + An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field + sage: TestSuite(A).run() + """ + cat = LieAlgebras(R).WithBasis() + CombinatorialFreeModule.__init__(self, R, gens, category=cat) + + def _construct_UEA(self): + """ + Construct the universal enveloping algebra of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: L._construct_UEA() + Multivariate Polynomial Ring in a, b, c over Rational Field + """ + # TODO: Implement using a combinatorial free module with a free abelian monoid + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(self.base_ring(), self.variable_names()) + + def _repr_(self): + """ + EXAMPLES:: + + sage: LieAlgebras(QQ).example() + An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field + """ + return "An example of a Lie algebra: the abelian Lie algebra on the" \ + " generators indexed by {} over {}".format( + self.basis().keys(), self.base_ring()) + + def lie_algebra_generators(self): + """ + Return the generators of ``self`` as a Lie algebra. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: L.lie_algebra_generators() + (B['a'], B['b'], B['c']) + """ + return self.basis() + + def bracket_on_basis(self, x, y): + """ + Return the Lie bracket on basis elements indexed by ``x`` and ``y``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: L.bracket_on_basis('a', 'c') + 0 + """ + return self.zero() + + def is_solvable(self): + """ + Return if ``self`` is a solvable Lie algebra. + """ + return True + + def is_nilpotent(self): + """ + Return if ``self`` is a nilpotent Lie algebra. + """ + return True + + class Element(CombinatorialFreeModule.Element): + def lift(self): + """ + Return the lift of ``self`` to the universal enveloping algebra. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: elt = L.an_element() + sage: elt.lift() + 2*a + 2*b + 3*c + """ + UEA = self.parent().universal_enveloping_algebra() + gens_dict = UEA.gens_dict() + return UEA.sum(c * gens_dict[t] for t, c in self) + +Example = AbelianLieAlgebra + 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 f6c191cff53..92d83605b2a 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -18,7 +18,6 @@ from sage.categories.lie_algebras import LieAlgebras from sage.rings.all import ZZ from sage.algebras.free_algebra import FreeAlgebra -from sage.algebras.lie_algebras.lie_algebra_element import LieBracket from sage.sets.family import Family from sage.matrix.constructor import matrix @@ -45,7 +44,7 @@ def example(self, names=('a', 'b', 'c')): An example of a Lie algebra: the abelian Lie algebra on the generators ('a', 'b', 'c') over Rational Field """ from sage.categories.examples.finite_dimensional_lie_algebras_with_basis import Example - return Example(self.base_ring(), gens) + return Example(self.base_ring(), names) class ParentMethods: @cached_method @@ -66,7 +65,7 @@ def _construct_UEA(self): names = tuple('b{}'.format(i) for i in range(self.dimension())) I = self._indices F = FreeAlgebra(self.base_ring(), names) - gens = F.gens() + #gens = F.gens() d = F.gens_dict() rels = {} S = self.structure_coefficients() @@ -140,14 +139,6 @@ def structure_coefficients(self): d[(x, y)] = self.bracket(bx, by) return Family(d) - # TODO: This will be removed once the generic LieSubalgebra is - # included from #14901 - @abstract_method - def subalgebra(self, gens): - """ - Return the subalgebra of ``self`` generated by ``gens``. - """ - def centralizer(self, S): """ Return the centralizer of ``S`` in ``self``. diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index e7e0d607f3c..c45f87c9736 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -19,7 +19,7 @@ from sage.categories.category_types import Category_over_base_ring from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.distributive_magmas_and_additive_magmas import DistributiveMagmasAndAdditiveMagmas -from sage.categories.finite_enuemrated_sets import FiniteEnumeratedSets +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.modules import Modules from sage.categories.sets_cat import Sets from sage.categories.homset import Hom @@ -129,10 +129,11 @@ def example(self, gens=None): An example of a Lie algebra: the abelian Lie algebra on the generators ('a', 'b', 'c') over Rational Field """ if gens is None: - from sage.combinat.partition import Partitions - gens = Partitions() + from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + from sage.rings.all import QQ + gens = SymmetricGroupAlgebra(QQ, 3).algebra_generators() from sage.categories.examples.lie_algebras import Example - return Example(self.base_ring(), gens) + return Example(gens) WithBasis = LazyImport('sage.categories.lie_algebras_with_basis', 'LieAlgebrasWithBasis', as_name='WithBasis') @@ -201,10 +202,19 @@ def lift(self): Construct the lift morphism from ``self`` to the universal enveloping algebra of ``self``. """ - M = LiftMorphism(self, self._construct_UEA()) + UEA = self._construct_UEA() + if UEA is NotImplemented: + raise NotImplementedError("no universal enveloping algebra implemented") + M = LiftMorphism(self, UEA) M.register_as_coercion() return M + @abstract_method(optional=True) + def subalgebra(self, gens): + """ + Return the subalgebra of ``self`` generated by ``gens``. + """ + @abstract_method(optional=True) def killing_form(self, x, y): """ @@ -366,8 +376,7 @@ def killing_form(self, x): class LiftMorphism(Morphism): """ - The natural lifting morphism from a Lie algebra to its universal - enveloping algebra. + The natural lifting morphism from a Lie algebra to an enveloping algebra. """ def __init__(self, domain, codomain): """ diff --git a/src/sage/categories/lie_algebras_with_basis.py b/src/sage/categories/lie_algebras_with_basis.py index 50bd064379b..8bda6d9f012 100644 --- a/src/sage/categories/lie_algebras_with_basis.py +++ b/src/sage/categories/lie_algebras_with_basis.py @@ -16,7 +16,6 @@ from sage.misc.cachefunc import cached_method from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.lie_algebras import LieAlgebras -from sage.algebras.lie_algebras.lie_algebra_element import LieBracket class LieAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ @@ -24,6 +23,27 @@ class LieAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ _base_category_class_and_axiom = [LieAlgebras, "WithBasis"] + def example(self, gens=None): + """ + Return an example of a Lie algebra as per + :meth:`Category.example `. + + EXAMPLES:: + + sage: LieAlgebras(QQ).WithBasis().example() + An example of a Lie algebra: the abelian Lie algebra on the generators ('a', 'b', 'c') over Rational Field + + Another set of generators can be specified as an optional argument:: + + sage: LieAlgebras(QQ).WithBasis().example(Compositions()) + An example of a Lie algebra: the abelian Lie algebra on the generators ('a', 'b', 'c') over Rational Field + """ + if gens is None: + from sage.combinat.partition import Partitions + gens = Partitions() + from sage.categories.examples.lie_algebras_with_basis import Example + return Example(self.base_ring(), gens) + class ParentMethods: def _basis_cmp(self, x, y): """ From aae396b856d1ca11318445cc8781fae76d068394 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 15 Aug 2014 12:40:52 +0530 Subject: [PATCH 003/223] Finished 2 of the 3 examples for Lie algebras. --- src/sage/algebras/lie_algebras/__init__.py | 0 .../lie_algebras/lie_algebra_element.py | 277 ++++++++++++++++++ src/sage/categories/examples/lie_algebras.py | 96 +++--- .../examples/lie_algebras_with_basis.py | 141 +++++++-- src/sage/categories/lie_algebras.py | 13 +- .../categories/lie_algebras_with_basis.py | 7 +- 6 files changed, 446 insertions(+), 88 deletions(-) create mode 100644 src/sage/algebras/lie_algebras/__init__.py create mode 100644 src/sage/algebras/lie_algebras/lie_algebra_element.py diff --git a/src/sage/algebras/lie_algebras/__init__.py b/src/sage/algebras/lie_algebras/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py new file mode 100644 index 00000000000..b554acc8ded --- /dev/null +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -0,0 +1,277 @@ +""" +Lie Algebra Elements + +AUTHORS: + +- Travis Scrimshaw (2005-05-04): Initial implementation +""" + +#***************************************************************************** +# Copyright (C) 2013 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# This code is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# See the GNU General Public License for more details; the full text +# is available at: +# +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.misc.abstract_method import abstract_method +from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall +from sage.misc.misc import repr_lincomb +from copy import copy +from functools import total_ordering +from sage.structure.element import ModuleElement, RingElement, coerce_binop +from sage.structure.sage_object import SageObject +from sage.combinat.free_module import CombinatorialFreeModuleElement +from sage.structure.element_wrapper import ElementWrapper + +# TODO: Have the other classes inherit from this? +# TODO: Should this be a mixin class (or moved to the category)? +class LieAlgebraElement_generic(ModuleElement): + """ + Generic methods for all Lie algebra elements. + """ + def _mul_(self, other): + """ + If we are multiplying two non-zero elements, automatically + lift up to the universal enveloping algebra. + + EXAMPLES:: + """ + if self == 0 or other == 0: + return self.parent().zero() + # Otherwise we lift to the UEA + return self.lift() * other.lift() + +# TODO: factor out parts of CombinatorialFreeModuleElement into a SparseFreeModuleElement? +# TODO: Call this class LieAlgebraElement_sparse? +# TODO: Inherit from LieAlgebraElement_generic? +class LieAlgebraElement(CombinatorialFreeModuleElement): + """ + A Lie algebra element. + """ + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + """ + if not self._monomial_coefficients: + return '0' + return repr_lincomb(self.list()) + + # Default implementation + def _latex_monomial(self, m): + """ + Return a `\LaTeX` representation of the monomial ``m``. + + EXAMPLES:: + """ + from sage.misc.latex import latex + return latex(m) + + def _latex_(self): + r""" + Return a `\LaTeX` representation of ``self``. + + EXAMPLES:: + """ + if not self._monomial_coefficients: + return '0' + return repr_lincomb(self.list(), repr_monomial=self._latex_monomial, is_latex=True) + + def _mul_(self, y): + """ + If we are multiplying two non-zero elements, automatically + lift up to the universal enveloping algebra. + + EXAMPLES:: + """ + if self == 0 or y == 0: + return self.parent().zero() + # Otherwise we lift to the UEA + return self.lift() * y.lift() + + def _im_gens_(self, codomain, im_gens): + """ + Return the image of ``self`` in ``codomain`` under the map that sends + the images of the generators of the parent of ``self`` to the + tuple of elements of ``im_gens``. + + EXAMPLES:: + """ + s = codomain.zero() + if not self: # If we are 0 + return s + names = self.parent().variable_names() + return codomain.sum(c * t._im_gens_(codomain, im_gens, names) + for t, c in self._monomial_coefficients.iteritems()) + + # TODO: Move to the category/lift morphism + def lift(self): + """ + Lift ``self`` to the universal enveloping algebra. + + EXAMPLES:: + """ + UEA = self.parent().universal_enveloping_algebra() + gen_dict = UEA.gens_dict() + s = UEA.zero() + if not self: + return s + for t, c in self._monomial_coefficients.iteritems(): + if isinstance(t, LieBracket): + s += c * t.lift(gen_dict) + else: + s += c * gen_dict[t._name] + return s + + def is_constant(self): + """ + Check if ``self`` is a constant (i.e. zero). + + EXAMPLES:: + """ + return notself._monomial_coefficients + + def dict(self): + """ + Return ``self`` as a dictionary mapping monomials to coefficients. + + EXAMPLES:: + """ + return copy(self._monomial_coefficients) + + def list(self): + """ + Return ``self`` as a list of pairs ``(m, c)`` where ``m`` is a + monomial and ``c`` is the coefficient. + + EXAMPLES:: + """ + return sorted(self._monomial_coefficients.items()) + +class LieAlgebraElementWrapper(ElementWrapper): + """ + Wrap an element as a Lie algebra element. + """ + def __eq__(self, rhs): + """ + Check equality. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, cartan_type=['A',3], representation='matrix') + sage: L.bracket(L.e(2), L.e(1)) == -L.bracket(L.e(1), L.e(2)) + True + """ + if not isinstance(rhs, LieAlgebraElementWrapper): + return self.value == 0 and rhs == 0 + return self.parent() == rhs.parent() and self.value == rhs.value + + def __nonzero__(self): + """ + Check non-zero. + """ + return bool(self.value) + + def _add_(self, rhs): + """ + Add ``self`` and ``rhs``. + + EXAMPLES:: + + sage: R = FreeAlgebra(QQ, 3, 'x,y,z') + sage: L. = LieAlgebra(QQ, R) + sage: x + y + x + y + """ + return self.__class__(self.parent(), self.value + rhs.value) + + def _sub_(self, rhs): + """ + Subtract ``self`` and ``rhs``. + + EXAMPLES:: + + sage: R = FreeAlgebra(QQ, 3, 'x,y,z') + sage: L. = LieAlgebra(QQ, R) + sage: x - y + x - y + """ + return self.__class__(self.parent(), self.value - rhs.value) + + # This seems to work with 2 underscores and I don't understand why... + def _mul_(self, x): + """ + If we are multiplying two non-zero elements, automatically + lift up to the universal enveloping algebra. + + EXAMPLES:: + + sage: G = SymmetricGroup(3) + sage: S = GroupAlgebra(G, QQ) + sage: L. = LieAlgebra(QQ, S) + sage: x*y - y*x + (2,3) - (1,3) + """ + if self.value == 0 or x == 0: + return self.parent().zero() + # Otherwise we lift to the UEA + return self.lift() * x.lift() + + def _acted_upon_(self, scalar, self_on_left=False): + """ + Return the action of a scalar on ``self``. + + EXAMPLES:: + """ + # This was copied and IDK if it still applies: + # 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. + if hasattr( scalar, 'parent' ) and scalar.parent() != self.base_ring(): + # Temporary needed by coercion (see Polynomial/FractionField tests). + if self.base_ring().has_coerce_map_from(scalar.parent()): + scalar = self.base_ring()( scalar ) + else: + return None + if self_on_left: + return self.__class__(self.parent(), self.value * scalar) + return self.__class__(self.parent(), scalar * self.value) + + def __neg__(self): + """ + Return the negation of ``self``. + + EXAMPLES:: + + sage: R = FreeAlgebra(QQ, 3, 'x,y,z') + sage: L. = LieAlgebra(QQ, R) + sage: -x + -x + """ + return self.__class__(self.parent(), -self.value) + + def __getitem__(self, i): + """ + Redirect the ``__getitem__()`` to the wrapped element. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, cartan_type=['A',2], representation='matrix') + sage: m = L.e(0) + sage: m[0,0] + 0 + sage: m[0][1] + 1 + """ + return self.value.__getitem__(i) + diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py index 35ffea9d560..567309a2096 100644 --- a/src/sage/categories/examples/lie_algebras.py +++ b/src/sage/categories/examples/lie_algebras.py @@ -12,7 +12,7 @@ from sage.sets.family import Family from sage.categories.all import LieAlgebras from sage.structure.parent import Parent -from sage.structure.element import ModuleElement +from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElementWrapper from sage.structure.unique_representation import UniqueRepresentation class LieAlgebraFromAssociative(Parent, UniqueRepresentation): @@ -25,6 +25,15 @@ class LieAlgebraFromAssociative(Parent, UniqueRepresentation): def __classcall_private__(cls, gens): """ Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: S3 = SymmetricGroupAlgebra(QQ, 3) + sage: L1 = LieAlgebras(QQ).example() + sage: gens = list(S3.algebra_generators()) + sage: L2 = LieAlgebras(QQ).example(gens) + sage: L1 is L2 + True """ return super(LieAlgebraFromAssociative, cls).__classcall__(cls, tuple(gens)) @@ -32,9 +41,8 @@ def __init__(self, gens): """ EXAMPLES:: - sage: A = LieAlgebras(QQ).example(); A - An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field - sage: TestSuite(A).run() + sage: L = LieAlgebras(QQ).example() + sage: TestSuite(L).run() """ if not gens: raise ValueError("need at least one generator") @@ -48,21 +56,37 @@ def _repr_(self): EXAMPLES:: sage: LieAlgebras(QQ).example() - An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field + An example of a Lie algebra: the Lie algebra from the associative algebra + Symmetric group algebra of order 3 over Rational Field + generated by ([2, 1, 3], [2, 3, 1]) """ - return "An example of a Lie algebra: the Lie algebra from an" \ - " associative algebra generated by {} over {}".format( - self._gens, self.base_ring()) + return "An example of a Lie algebra: the Lie algebra from the" \ + " associative algebra {} generated by {}".format( + self._A, self._gens) def _element_constructor_(self, value): """ Return an element of ``self``. + + EXAMPLES:: + + sage: S3 = SymmetricGroupAlgebra(ZZ, 3) + sage: gens = S3.algebra_generators() + sage: L = LieAlgebras(QQ).example() + sage: L(3*gens[0] + gens[1]) + 3*[2, 1, 3] + [2, 3, 1] """ return self.element_class(self, self._A(value)) def zero(self): """ Return the element 0. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: L.zero() + 0 """ return self.element_class(self, self._A.zero()) @@ -74,55 +98,29 @@ def lie_algebra_generators(self): sage: L = LieAlgebras(QQ).example() sage: L.lie_algebra_generators() - (B['a'], B['b'], B['c']) + Family ([2, 1, 3], [2, 3, 1]) """ return Family([self.element_class(self, g) for g in self._gens]) - class Element(ModuleElement): - def __init__(self, parent, value): - """ - Initialize ``self``. - """ - self._value = value - ModuleElement.__init__(self, parent) - - def _repr_(self): - """ - Return a string representation of ``self``. - """ - return repr(self._value) - - def __eq__(self, rhs): - """ - Check equality. - """ - if not isinstance(rhs, LieAlgebraFromAssociative.Element): - return False - return self.parent() == rhs.parent() and self._value == rhs._value - - def __nonzero__(self): - """ - Check non-zero. - """ - return not self._value - - def _add_(self, rhs): - """ - Add ``self`` to ``rhs``. - """ - return self.__class__(self.parent(), self._value + rhs._value) - + class Element(LieAlgebraElementWrapper): def _bracket_(self, rhs): """ Return the Lie bracket ``[self, rhs]``. - """ - return self.__class__(self.parent(), self._value * rhs._value - rhs._value * self._value) - def _mul_(self, rhs): - r""" - When multiplying elements, lift up to the associative algebra. + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: x,y = L.lie_algebra_generators() + sage: elt = 2*x - y + sage: elt.bracket(elt) + 0 + sage: elt.bracket(x) + -[1, 3, 2] + [3, 2, 1] + sage: elt2 = x.bracket(y) + x + sage: elt.bracket(elt2) + -2*[2, 1, 3] + 4*[2, 3, 1] - 4*[3, 1, 2] + 2*[3, 2, 1] """ - return self._value * rhs._value + return self.__class__(self.parent(), self.value * rhs.value - rhs.value * self.value) Example = LieAlgebraFromAssociative diff --git a/src/sage/categories/examples/lie_algebras_with_basis.py b/src/sage/categories/examples/lie_algebras_with_basis.py index 851b256c453..55737b473a1 100644 --- a/src/sage/categories/examples/lie_algebras_with_basis.py +++ b/src/sage/categories/examples/lie_algebras_with_basis.py @@ -10,7 +10,9 @@ from sage.misc.cachefunc import cached_method from sage.sets.family import Family -from sage.categories.all import LieAlgebras +from sage.categories.lie_algebras import LieAlgebras +from sage.categories.algebras import Algebras +from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid from sage.combinat.free_module import CombinatorialFreeModule class AbelianLieAlgebra(CombinatorialFreeModule): @@ -24,9 +26,8 @@ def __init__(self, R, gens): """ EXAMPLES:: - sage: A = LieAlgebras(QQ).example(); A - An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field - sage: TestSuite(A).run() + sage: L = LieAlgebras(QQ).WithBasis().example() + sage: TestSuite(L).run() """ cat = LieAlgebras(R).WithBasis() CombinatorialFreeModule.__init__(self, R, gens, category=cat) @@ -37,20 +38,19 @@ def _construct_UEA(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).example() + sage: L = LieAlgebras(QQ).WithBasis().example() sage: L._construct_UEA() - Multivariate Polynomial Ring in a, b, c over Rational Field + Polynomial algebra with generators indexed by Partitions over Rational Field """ - # TODO: Implement using a combinatorial free module with a free abelian monoid - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - return PolynomialRing(self.base_ring(), self.variable_names()) + return IndexedPolynomialRing(self.base_ring(), self._indices) def _repr_(self): """ EXAMPLES:: - sage: LieAlgebras(QQ).example() - An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field + sage: LieAlgebras(QQ).WithBasis().example() + An example of a Lie algebra: the abelian Lie algebra on the + generators indexed by Partitions over Rational Field """ return "An example of a Lie algebra: the abelian Lie algebra on the" \ " generators indexed by {} over {}".format( @@ -62,9 +62,12 @@ def lie_algebra_generators(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).example() + sage: L = LieAlgebras(QQ).WithBasis().example() sage: L.lie_algebra_generators() - (B['a'], B['b'], B['c']) + Lazy family (Term map from Partitions to + An example of a Lie algebra: the abelian Lie algebra on the + generators indexed by Partitions over Rational + Field(i))_{i in Partitions} """ return self.basis() @@ -74,24 +77,12 @@ def bracket_on_basis(self, x, y): EXAMPLES:: - sage: L = LieAlgebras(QQ).example() - sage: L.bracket_on_basis('a', 'c') + sage: L = LieAlgebras(QQ).WithBasis().example() + sage: L.bracket_on_basis(Partition([4,1]), Partition([2,2,1])) 0 """ return self.zero() - def is_solvable(self): - """ - Return if ``self`` is a solvable Lie algebra. - """ - return True - - def is_nilpotent(self): - """ - Return if ``self`` is a nilpotent Lie algebra. - """ - return True - class Element(CombinatorialFreeModule.Element): def lift(self): """ @@ -99,14 +90,102 @@ def lift(self): EXAMPLES:: - sage: L = LieAlgebras(QQ).example() + sage: L = LieAlgebras(QQ).WithBasis().example() sage: elt = L.an_element() sage: elt.lift() - 2*a + 2*b + 3*c + 3*P[F[2]] + 2*P[F[1]] + 2*P[F[]] """ UEA = self.parent().universal_enveloping_algebra() - gens_dict = UEA.gens_dict() - return UEA.sum(c * gens_dict[t] for t, c in self) + I = UEA._indices + return UEA.sum_of_terms((I.gen(t), c) for t, c in self) Example = AbelianLieAlgebra +############## + +class IndexedPolynomialRing(CombinatorialFreeModule): + """ + Polynomial ring whose generators are indexed by an arbitrary set. + + .. TODO:: + + Currently this is just used as the universal enveloping algebra + for the example of the abelian Lie algebra. This should be + factored out into a more complete class. + """ + def __init__(self, R, indices, **kwds): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).WithBasis().example() + sage: UEA = L.universal_enveloping_algebra() + sage: TestSuite(UEA).run() + """ + if 'category' not in kwds: + kwds['category'] = Algebras(R).WithBasis() + if 'prefix' not in kwds: + kwds['prefix'] = 'P' + # This is a workaround until IndexedFree(Abelian)Monoid elements compare properly + kwds['generator_cmp'] = lambda x,y: -cmp(x.to_word_list(), y.to_word_list()) + M = IndexedFreeAbelianMonoid(indices, bracket='') + CombinatorialFreeModule.__init__(self, R, M, **kwds) + + def _repr_(self): + """ + Return a string represenation of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).WithBasis().example() + sage: L.universal_enveloping_algebra() + Polynomial algebra with generators indexed by Partitions over Rational Field + """ + return "Polynomial algebra with generators indexed by {} over {}".format( + self._indices._indices, self.base_ring()) + + def one_basis(self): + """ + Return the index of element `1`. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).WithBasis().example() + sage: UEA = L.universal_enveloping_algebra() + sage: UEA.one_basis() + 1 + sage: UEA.one_basis().parent() + Free abelian monoid indexed by Partitions + """ + return self._indices.one() + + def product_on_basis(self, x, y): + """ + Return the product of the monomials indexed by ``x`` and ``y``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).WithBasis().example() + sage: UEA = L.universal_enveloping_algebra() + sage: I = UEA._indices + sage: UEA.product_on_basis(I.an_element(), I.an_element()) + P[F[]^4*F[1]^4*F[2]^6] + """ + return self.monomial(x*y) + + def algebra_generators(self): + """ + Return the algebra generators of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).WithBasis().example() + sage: UEA = L.universal_enveloping_algebra() + sage: UEA.algebra_generators() + Lazy family (algebra generator map(i))_{i in Partitions} + """ + I = self._indices + return Family(I._indices, lambda x: self.monomial(I.gen(x)), + name="algebra generator map") + diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index c45f87c9736..45767c3bb3a 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -121,12 +121,16 @@ def example(self, gens=None): EXAMPLES:: sage: LieAlgebras(QQ).example() - An example of a Lie algebra: the abelian Lie algebra on the generators ('a', 'b', 'c') over Rational Field + An example of a Lie algebra: the Lie algebra from the associative algebra + Symmetric group algebra of order 3 over Rational Field + generated by ([2, 1, 3], [2, 3, 1]) Another set of generators can be specified as an optional argument:: sage: LieAlgebras(QQ).example(('x','y','z')) - An example of a Lie algebra: the abelian Lie algebra on the generators ('a', 'b', 'c') over Rational Field + An example of a Lie algebra: the Lie algebra from the associative algebra + Group algebra of Dihedral group of order 8 as a permutation group over Rational Field + generated by (B[(1,2,3,4)], B[(1,4)(2,3)]) """ if gens is None: from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra @@ -202,10 +206,7 @@ def lift(self): Construct the lift morphism from ``self`` to the universal enveloping algebra of ``self``. """ - UEA = self._construct_UEA() - if UEA is NotImplemented: - raise NotImplementedError("no universal enveloping algebra implemented") - M = LiftMorphism(self, UEA) + M = LiftMorphism(self, self._construct_UEA()) M.register_as_coercion() return M diff --git a/src/sage/categories/lie_algebras_with_basis.py b/src/sage/categories/lie_algebras_with_basis.py index 8bda6d9f012..afdff1bcde1 100644 --- a/src/sage/categories/lie_algebras_with_basis.py +++ b/src/sage/categories/lie_algebras_with_basis.py @@ -31,12 +31,15 @@ def example(self, gens=None): EXAMPLES:: sage: LieAlgebras(QQ).WithBasis().example() - An example of a Lie algebra: the abelian Lie algebra on the generators ('a', 'b', 'c') over Rational Field + An example of a Lie algebra: the abelian Lie algebra on the + generators indexed by Partitions over Rational Field Another set of generators can be specified as an optional argument:: sage: LieAlgebras(QQ).WithBasis().example(Compositions()) - An example of a Lie algebra: the abelian Lie algebra on the generators ('a', 'b', 'c') over Rational Field + An example of a Lie algebra: the abelian Lie algebra on the + generators indexed by Compositions of non-negative integers + over Rational Field """ if gens is None: from sage.combinat.partition import Partitions From 1544ff731e194a52a6098d1a1b7fa036957d100f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 15 Aug 2014 13:03:34 +0530 Subject: [PATCH 004/223] Moved lie_algebra_element.py into the example directly. --- src/sage/algebras/lie_algebras/__init__.py | 0 .../lie_algebras/lie_algebra_element.py | 277 ------------------ src/sage/categories/examples/lie_algebras.py | 168 ++++++++++- 3 files changed, 166 insertions(+), 279 deletions(-) delete mode 100644 src/sage/algebras/lie_algebras/__init__.py delete mode 100644 src/sage/algebras/lie_algebras/lie_algebra_element.py diff --git a/src/sage/algebras/lie_algebras/__init__.py b/src/sage/algebras/lie_algebras/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py deleted file mode 100644 index b554acc8ded..00000000000 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ /dev/null @@ -1,277 +0,0 @@ -""" -Lie Algebra Elements - -AUTHORS: - -- Travis Scrimshaw (2005-05-04): Initial implementation -""" - -#***************************************************************************** -# Copyright (C) 2013 Travis Scrimshaw -# -# Distributed under the terms of the GNU General Public License (GPL) -# -# This code is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty -# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -# See the GNU General Public License for more details; the full text -# is available at: -# -# http://www.gnu.org/licenses/ -#***************************************************************************** - -from sage.misc.abstract_method import abstract_method -from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall -from sage.misc.misc import repr_lincomb -from copy import copy -from functools import total_ordering -from sage.structure.element import ModuleElement, RingElement, coerce_binop -from sage.structure.sage_object import SageObject -from sage.combinat.free_module import CombinatorialFreeModuleElement -from sage.structure.element_wrapper import ElementWrapper - -# TODO: Have the other classes inherit from this? -# TODO: Should this be a mixin class (or moved to the category)? -class LieAlgebraElement_generic(ModuleElement): - """ - Generic methods for all Lie algebra elements. - """ - def _mul_(self, other): - """ - If we are multiplying two non-zero elements, automatically - lift up to the universal enveloping algebra. - - EXAMPLES:: - """ - if self == 0 or other == 0: - return self.parent().zero() - # Otherwise we lift to the UEA - return self.lift() * other.lift() - -# TODO: factor out parts of CombinatorialFreeModuleElement into a SparseFreeModuleElement? -# TODO: Call this class LieAlgebraElement_sparse? -# TODO: Inherit from LieAlgebraElement_generic? -class LieAlgebraElement(CombinatorialFreeModuleElement): - """ - A Lie algebra element. - """ - def _repr_(self): - """ - Return a string representation of ``self``. - - EXAMPLES:: - """ - if not self._monomial_coefficients: - return '0' - return repr_lincomb(self.list()) - - # Default implementation - def _latex_monomial(self, m): - """ - Return a `\LaTeX` representation of the monomial ``m``. - - EXAMPLES:: - """ - from sage.misc.latex import latex - return latex(m) - - def _latex_(self): - r""" - Return a `\LaTeX` representation of ``self``. - - EXAMPLES:: - """ - if not self._monomial_coefficients: - return '0' - return repr_lincomb(self.list(), repr_monomial=self._latex_monomial, is_latex=True) - - def _mul_(self, y): - """ - If we are multiplying two non-zero elements, automatically - lift up to the universal enveloping algebra. - - EXAMPLES:: - """ - if self == 0 or y == 0: - return self.parent().zero() - # Otherwise we lift to the UEA - return self.lift() * y.lift() - - def _im_gens_(self, codomain, im_gens): - """ - Return the image of ``self`` in ``codomain`` under the map that sends - the images of the generators of the parent of ``self`` to the - tuple of elements of ``im_gens``. - - EXAMPLES:: - """ - s = codomain.zero() - if not self: # If we are 0 - return s - names = self.parent().variable_names() - return codomain.sum(c * t._im_gens_(codomain, im_gens, names) - for t, c in self._monomial_coefficients.iteritems()) - - # TODO: Move to the category/lift morphism - def lift(self): - """ - Lift ``self`` to the universal enveloping algebra. - - EXAMPLES:: - """ - UEA = self.parent().universal_enveloping_algebra() - gen_dict = UEA.gens_dict() - s = UEA.zero() - if not self: - return s - for t, c in self._monomial_coefficients.iteritems(): - if isinstance(t, LieBracket): - s += c * t.lift(gen_dict) - else: - s += c * gen_dict[t._name] - return s - - def is_constant(self): - """ - Check if ``self`` is a constant (i.e. zero). - - EXAMPLES:: - """ - return notself._monomial_coefficients - - def dict(self): - """ - Return ``self`` as a dictionary mapping monomials to coefficients. - - EXAMPLES:: - """ - return copy(self._monomial_coefficients) - - def list(self): - """ - Return ``self`` as a list of pairs ``(m, c)`` where ``m`` is a - monomial and ``c`` is the coefficient. - - EXAMPLES:: - """ - return sorted(self._monomial_coefficients.items()) - -class LieAlgebraElementWrapper(ElementWrapper): - """ - Wrap an element as a Lie algebra element. - """ - def __eq__(self, rhs): - """ - Check equality. - - EXAMPLES:: - - sage: L = LieAlgebra(QQ, cartan_type=['A',3], representation='matrix') - sage: L.bracket(L.e(2), L.e(1)) == -L.bracket(L.e(1), L.e(2)) - True - """ - if not isinstance(rhs, LieAlgebraElementWrapper): - return self.value == 0 and rhs == 0 - return self.parent() == rhs.parent() and self.value == rhs.value - - def __nonzero__(self): - """ - Check non-zero. - """ - return bool(self.value) - - def _add_(self, rhs): - """ - Add ``self`` and ``rhs``. - - EXAMPLES:: - - sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(QQ, R) - sage: x + y - x + y - """ - return self.__class__(self.parent(), self.value + rhs.value) - - def _sub_(self, rhs): - """ - Subtract ``self`` and ``rhs``. - - EXAMPLES:: - - sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(QQ, R) - sage: x - y - x - y - """ - return self.__class__(self.parent(), self.value - rhs.value) - - # This seems to work with 2 underscores and I don't understand why... - def _mul_(self, x): - """ - If we are multiplying two non-zero elements, automatically - lift up to the universal enveloping algebra. - - EXAMPLES:: - - sage: G = SymmetricGroup(3) - sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(QQ, S) - sage: x*y - y*x - (2,3) - (1,3) - """ - if self.value == 0 or x == 0: - return self.parent().zero() - # Otherwise we lift to the UEA - return self.lift() * x.lift() - - def _acted_upon_(self, scalar, self_on_left=False): - """ - Return the action of a scalar on ``self``. - - EXAMPLES:: - """ - # This was copied and IDK if it still applies: - # 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. - if hasattr( scalar, 'parent' ) and scalar.parent() != self.base_ring(): - # Temporary needed by coercion (see Polynomial/FractionField tests). - if self.base_ring().has_coerce_map_from(scalar.parent()): - scalar = self.base_ring()( scalar ) - else: - return None - if self_on_left: - return self.__class__(self.parent(), self.value * scalar) - return self.__class__(self.parent(), scalar * self.value) - - def __neg__(self): - """ - Return the negation of ``self``. - - EXAMPLES:: - - sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(QQ, R) - sage: -x - -x - """ - return self.__class__(self.parent(), -self.value) - - def __getitem__(self, i): - """ - Redirect the ``__getitem__()`` to the wrapped element. - - EXAMPLES:: - - sage: L = LieAlgebra(QQ, cartan_type=['A',2], representation='matrix') - sage: m = L.e(0) - sage: m[0,0] - 0 - sage: m[0][1] - 1 - """ - return self.value.__getitem__(i) - diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py index 567309a2096..0b1ce914be0 100644 --- a/src/sage/categories/examples/lie_algebras.py +++ b/src/sage/categories/examples/lie_algebras.py @@ -12,14 +12,31 @@ from sage.sets.family import Family from sage.categories.all import LieAlgebras from sage.structure.parent import Parent -from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElementWrapper from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.element_wrapper import ElementWrapper class LieAlgebraFromAssociative(Parent, UniqueRepresentation): r""" An example of a Lie algebra: a Lie algebra from an associative algebra. This class illustrates a minimal implementation of a Lie algebra. + + EXAMPLES: + + We create an example of `\mathfrak{sl}_2` using matrices:: + + + sage: gens = [matrix([[0,1],[0,0]]), matrix([[0,0],[1,0]]), matrix([[1,0],[0,-1]])] + sage: for g in gens: + ....: g.set_immutable() + sage: L = LieAlgebras(QQ).example(gens) + sage: e,f,h = L.lie_algebra_generators() + sage: e.bracket(f) == h + True + sage: h.bracket(e) == 2*e + True + sage: h.bracket(f) == -2*f + True """ @staticmethod def __classcall_private__(cls, gens): @@ -102,7 +119,154 @@ def lie_algebra_generators(self): """ return Family([self.element_class(self, g) for g in self._gens]) - class Element(LieAlgebraElementWrapper): + # TODO: refactor to use LieAlgebraElementWrapper once more of #14901 is added in + class Element(ElementWrapper): + """ + Wrap an element as a Lie algebra element. + """ + def __eq__(self, rhs): + """ + Check equality. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: x,y = L.lie_algebra_generators() + sage: x == x + True + sage: x.bracket(y) == -y.bracket(x) + True + sage: x == y + False + sage: x.bracket(x) == L.zero() + True + sage: x.bracket(x) == 0 + True + """ + if not isinstance(rhs, LieAlgebraFromAssociative.Element): + return self.value == 0 and rhs == 0 + return self.parent() == rhs.parent() and self.value == rhs.value + + def __ne__(self, rhs): + """ + Check not-equals. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: x,y = L.lie_algebra_generators() + sage: x != y + True + sage: x != 0 + True + sage: x != x + False + sage: x.bracket(y) != -y.bracket(x) + False + """ + return not self.__eq__(rhs) + + def __nonzero__(self): + """ + Check non-zero. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: bool(sum(L.lie_algebra_generators())) + True + sage: bool(L.zero()) + False + """ + return bool(self.value) + + def _add_(self, rhs): + """ + Add ``self`` and ``rhs``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: x,y = L.lie_algebra_generators() + sage: x + y + [2, 1, 3] + [2, 3, 1] + """ + return self.__class__(self.parent(), self.value + rhs.value) + + def _sub_(self, rhs): + """ + Subtract ``self`` and ``rhs``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: x,y = L.lie_algebra_generators() + sage: x - y + [2, 1, 3] - [2, 3, 1] + """ + return self.__class__(self.parent(), self.value - rhs.value) + + def _acted_upon_(self, scalar, self_on_left=False): + """ + Return the action of a scalar on ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: x,y = L.lie_algebra_generators() + sage: 3 * x + 3*[2, 1, 3] + sage: y / 4 + 1/4*[2, 3, 1] + """ + # This was copied, but IDK if it still applies: + # 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. + if hasattr( scalar, 'parent' ) and scalar.parent() != self.base_ring(): + # Temporary needed by coercion (see Polynomial/FractionField tests). + if self.base_ring().has_coerce_map_from(scalar.parent()): + scalar = self.base_ring()( scalar ) + else: + return None + if self_on_left: + return self.__class__(self.parent(), self.value * scalar) + return self.__class__(self.parent(), scalar * self.value) + + def __neg__(self): + """ + Return the negation of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: x,y = L.lie_algebra_generators() + sage: -x + -[2, 1, 3] + """ + return self.__class__(self.parent(), -self.value) + + def __getitem__(self, i): + """ + Redirect the ``__getitem__()`` to the wrapped element. + + EXAMPLES:: + + sage: gens = [matrix([[0,1],[0,0]]), matrix([[0,0],[1,0]]), matrix([[1,0],[0,-1]])] + sage: for g in gens: + ....: g.set_immutable() + sage: L = LieAlgebras(QQ).example(gens) + sage: e,f,h = L.lie_algebra_generators() + sage: h[0,0] + 1 + sage: h[1,1] + -1 + sage: h[0,1] + 0 + """ + return self.value.__getitem__(i) + def _bracket_(self, rhs): """ Return the Lie bracket ``[self, rhs]``. From a5d05e493324823d90ead874c060bef09b0f6bd8 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 15 Aug 2014 19:34:08 +0530 Subject: [PATCH 005/223] Started on finite dim lie alg with basis. --- .../examples/finite_dimensional_lie_algebras_with_basis.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index 1748df31e45..218ae4ea9b0 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -76,10 +76,9 @@ def basis(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.basis() """ - d = {} names = self.variable_names() - for i,b in enumerate(self._M.basis()): - d[names[i]] = self.element_class(self, b) + d = {names[i]: self.element_class(self, b) + for i,b in enumerate(self._M.basis())} return Family(d) def lie_algebra_generators(self): From 663e1ae67c87c706afefda4ca3c414a6f10915c6 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 16 Aug 2014 12:07:46 +0530 Subject: [PATCH 006/223] Some more work to FD Lie Alg with basis. --- ...ite_dimensional_lie_algebras_with_basis.py | 79 ++++++++++++++----- 1 file changed, 58 insertions(+), 21 deletions(-) diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index 218ae4ea9b0..b4656c1278c 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -12,9 +12,10 @@ from sage.sets.family import Family from sage.categories.all import LieAlgebras from sage.modules.free_module import FreeModule -from sage.structure.parent import parent +from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element_wrapper import ElementWrapper +from sage.categories.examples.lie_algebras import LieAlgebraFromAssociative as BaseExample class AbelianLieAlgebra(Parent, UniqueRepresentation): r""" @@ -25,13 +26,21 @@ class AbelianLieAlgebra(Parent, UniqueRepresentation): Lie algebra with basis. """ @staticmethod - def __classcall_private__(cls, R, names): + def __classcall_private__(cls, R, names, M=None): """ Normalize input to ensure a unique representation. """ - return super(AbelianLieAlgebra, cls).__classcall__(cls, R, tuple(names)) - - def __init__(self, R, names): + if isinstance(names, str): + names = names.split(',') + if M is None: + M = FreeModule(R, len(names)) + elif len(names) != M.dimension(): + raise ValueError("number of generators is not correct") + else: + M = M.change_ring(R) + return super(AbelianLieAlgebra, cls).__classcall__(cls, R, tuple(names), M) + + def __init__(self, R, names, M): """ EXAMPLES:: @@ -39,9 +48,9 @@ def __init__(self, R, names): An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field sage: TestSuite(L).run() """ - self._M = FreeModule(R, len(names)) + self._M = M cat = LieAlgebras(R).FiniteDimensional().WithBasis() - Parent.__init__(self, names=names, category=cat) + Parent.__init__(self, base=R, names=names, category=cat) def _construct_UEA(self): """ @@ -63,9 +72,24 @@ def _repr_(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field """ - return "An example of a finite dimensional Lie algebra with basis:"\ - " the abelian Lie algebra on the generators "\ - " {} over {}".format(self.lie_algebra_generators(), self.base_ring()) + ret = "An example of a finite dimensional Lie algebra with basis:" \ + " the abelian Lie algebra with generators {!r} over {}".format( + self.variable_names(), self.base_ring()) + B = self._M.basis_matrix() + if not B.is_one(): + ret += " with basis matrix:\n{!r}".format(B) + return ret + + def subalgebra(self, gens, names='x'): + """ + Return a subalgebra of ``self``. + """ + if isinstance(names, str): + names = names.split(',') + if len(names) == 1 and len(gens) != 1: + names = tuple( names[0] + str(i) for i in range(len(gens)) ) + N = self._M.subspace([g.value for g in gens]) + return AbelianLieAlgebra(self.base_ring(), names, N) def basis(self): """ @@ -92,19 +116,26 @@ def lie_algebra_generators(self): """ return self.basis() - def bracket_on_basis(self, x, y): + def gens(self): """ - Return the Lie bracket on basis elements indexed by ``x`` and ``y``. - - EXAMPLES:: + Return the generators of ``self``. + """ + G = self.lie_algebra_generators() + return tuple(G[i] for i in self.variable_names()) - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.bracket_on_basis('a', 'c') - 0 + def free_module(self): """ - return self.zero() + Return ``self`` as a free module. + """ + return self._M + + class Element(BaseExample.Element): + def _bracket_(self, y): + """ + Return the Lie bracket ``[self, y]``. + """ + return self.parent().zero() - class Element(ElementWrapper): def lift(self): """ Return the lift of ``self`` to the universal enveloping algebra. @@ -117,8 +148,14 @@ def lift(self): 2*a + 2*b + 3*c """ UEA = self.parent().universal_enveloping_algebra() - gens_dict = UEA.gens_dict() - return UEA.sum(c * gens_dict[t] for t, c in self) + gens = UEA.gens() + return UEA.sum(c * gens[i] for i, c in self.value.iteritems()) + + def to_vector(self): + """ + Return ``self`` as a vector. + """ + return self.value Example = AbelianLieAlgebra From 8d6084e4dec4e8a9082a2930ede616b6096c9e91 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 16 Aug 2014 21:30:38 +0530 Subject: [PATCH 007/223] Fixes, improvements, and changes to FD Lie algebras with basis. --- ...ite_dimensional_lie_algebras_with_basis.py | 127 ++++++++++++++++-- ...ite_dimensional_lie_algebras_with_basis.py | 18 ++- 2 files changed, 128 insertions(+), 17 deletions(-) diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index b4656c1278c..47d1e3725a6 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -29,6 +29,15 @@ class AbelianLieAlgebra(Parent, UniqueRepresentation): def __classcall_private__(cls, R, names, M=None): """ Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: from sage.categories.examples.finite_dimensional_lie_algebras_with_basis import AbelianLieAlgebra + sage: A1 = AbelianLieAlgebra(QQ, 'x,y,z') + sage: A2 = AbelianLieAlgebra(QQ, ['x','y','z']) + sage: A3 = AbelianLieAlgebra(QQ, ['x','y','z'], FreeModule(QQ, 3)) + sage: A1 is A2 and A2 is A3 + True """ if isinstance(names, str): names = names.split(',') @@ -44,10 +53,10 @@ def __init__(self, R, names, M): """ EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example(); L - An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: TestSuite(L).run() """ + self._ordered_indices = range(M.dimension()) self._M = M cat = LieAlgebras(R).FiniteDimensional().WithBasis() Parent.__init__(self, base=R, names=names, category=cat) @@ -69,8 +78,10 @@ def _repr_(self): """ EXAMPLES:: - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field + sage: LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + An example of a finite dimensional Lie algebra with basis: + the abelian Lie algebra with generators ('a', 'b', 'c') + over Rational Field """ ret = "An example of a finite dimensional Lie algebra with basis:" \ " the abelian Lie algebra with generators {!r} over {}".format( @@ -80,9 +91,63 @@ def _repr_(self): ret += " with basis matrix:\n{!r}".format(B) return ret + def _element_constructor_(self, x): + """ + Construct an element of ``self`` from ``x``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L(0) + (0, 0, 0) + sage: M = FreeModule(ZZ, 3) + sage: L(M([1, -2, 2])) + (1, -2, 2) + """ + return self.element_class(self, self._M(x)) + + @cached_method + def zero(self): + """ + Return the zero element. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.zero() + (0, 0, 0) + """ + return self.element_class(self, self._M.zero()) + + def basis_matrix(self): + """ + Return the basis matrix of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.basis_matrix() + [1 0 0] + [0 1 0] + [0 0 1] + """ + return self._M.basis_matrix() + def subalgebra(self, gens, names='x'): """ Return a subalgebra of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.inject_variables() + Defining a, b, c + sage: L.subalgebra([2*a+b, b + c], 'x,y') + An example of a finite dimensional Lie algebra with basis: + the abelian Lie algebra with generators ('x', 'y') + over Rational Field with basis matrix: + [ 1 0 -1/2] + [ 0 1 1] """ if isinstance(names, str): names = names.split(',') @@ -99,26 +164,24 @@ def basis(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.basis() + Finite family {'a': (1, 0, 0), 'c': (0, 0, 1), 'b': (0, 1, 0)} """ names = self.variable_names() d = {names[i]: self.element_class(self, b) for i,b in enumerate(self._M.basis())} return Family(d) - def lie_algebra_generators(self): + lie_algebra_generators = basis + + def gens(self): """ - Return the generators of ``self`` as a Lie algebra. + Return the generators of ``self``. EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.lie_algebra_generators() - """ - return self.basis() - - def gens(self): - """ - Return the generators of ``self``. + sage: L.gens() + ((1, 0, 0), (0, 1, 0), (0, 0, 1)) """ G = self.lie_algebra_generators() return tuple(G[i] for i in self.variable_names()) @@ -126,6 +189,21 @@ def gens(self): def free_module(self): """ Return ``self`` as a free module. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.free_module() + Vector space of dimension 3 over Rational Field + + sage: L.inject_variables() + Defining a, b, c + sage: S = L.subalgebra([2*a+b, b + c], 'x,y') + sage: S.free_module() + Vector space of degree 3 and dimension 2 over Rational Field + Basis matrix: + [ 1 0 -1/2] + [ 0 1 1] """ return self._M @@ -133,6 +211,16 @@ class Element(BaseExample.Element): def _bracket_(self, y): """ Return the Lie bracket ``[self, y]``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.inject_variables() + Defining a, b, c + sage: a.bracket(c) + (0, 0, 0) + sage: a.bracket(b).bracket(c) + (0, 0, 0) """ return self.parent().zero() @@ -143,7 +231,9 @@ def lift(self): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: elt = L.an_element() + sage: L.inject_variables() + Defining a, b, c + sage: elt = 2*a + 2*b + 3*c sage: elt.lift() 2*a + 2*b + 3*c """ @@ -154,6 +244,15 @@ def lift(self): def to_vector(self): """ Return ``self`` as a vector. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.inject_variables() + Defining a, b, c + sage: elt = 2*a + 2*b + 3*c + sage: elt.to_vector() + (2, 2, 3) """ return self.value 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 92d83605b2a..84748bbf450 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -36,7 +36,9 @@ def example(self, names=('a', 'b', 'c')): sage: C = LieAlgebras(QQ).FiniteDimensional().WithBasis() sage: C.example() - An example of a Lie algebra: the abelian Lie algebra on the generators ('a', 'b', 'c') over Rational Field + An example of a finite dimensional Lie algebra with basis: + the abelian Lie algebra with generators ('a', 'b', 'c') + over Rational Field Other names of generators can be specified as an optional argument:: @@ -128,17 +130,27 @@ def structure_coefficients(self): d = {} B = self.basis() K = self.basis().keys() + zero = self.zero() one = self.base_ring().one() for i,x in enumerate(K): for y in K[i+1:]: bx = B[x] by = B[x] + val = self.bracket(bx, by) + if val == zero: + continue if self._basis_cmp(x, y) > 0: - d[(y, x)] = self.bracket(by, bx) + d[(y, x)] = -val else: - d[(x, y)] = self.bracket(bx, by) + d[(x, y)] = val return Family(d) + @abstract_method + def basis_matrix(self): + """ + Return the basis matrix of ``self``. + """ + def centralizer(self, S): """ Return the centralizer of ``S`` in ``self``. From 78579bd21c6fd4d0f229f77677b66b69f8c1b96c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 17 Aug 2014 12:27:35 +0530 Subject: [PATCH 008/223] Some more fixes and changes to FD Lie algebras with basis. --- ...ite_dimensional_lie_algebras_with_basis.py | 81 +++++++++++++++---- 1 file changed, 67 insertions(+), 14 deletions(-) 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 84748bbf450..8518ade5e9c 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -121,11 +121,29 @@ def killing_form_matrix(self): return m @cached_method - def structure_coefficients(self): + def structure_coefficients(self, include_zeros=False): """ - Return the non-trivial structure coefficients of ``self``. - In particular, if `[x, y] = 0`, then we don't include it in the - output. + Return the structure coefficients of ``self``. + + INPUT: + + - ``include_zeros`` -- (default: ``False``) if ``True``, then + include the `[x, y] = 0` pairs in the output + + OUTPUT: + + A dictionary whose keys are pairs of basis indices `(i, j)` and + whose values are the corresponding *element* of `[b_i, b_j]` + in the Lie algebra. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + Lsage: L.structure_coefficients() + Finite family {} + sage: L.structure_coefficients(True) + Finite family {('b', 'c'): (0, 0, 0), ('a', 'b'): (0, 0, 0), + ('a', 'c'): (0, 0, 0)} """ d = {} B = self.basis() @@ -137,7 +155,7 @@ def structure_coefficients(self): bx = B[x] by = B[x] val = self.bracket(bx, by) - if val == zero: + if not include_zeros and val == zero: continue if self._basis_cmp(x, y) > 0: d[(y, x)] = -val @@ -149,6 +167,14 @@ def structure_coefficients(self): def basis_matrix(self): """ Return the basis matrix of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.basis_matrix() + [1 0 0] + [0 1 0] + [0 0 1] """ def centralizer(self, S): @@ -164,17 +190,31 @@ def centralizer(self, S): m = K.basis_matrix() S = self.structure_coefficients() - sc = {k: S[k].to_vector() for k in S} - X = self.basis() + sc = {k: S[k].to_vector() for k in S.keys()} + X = self.basis().keys() d = self.dimension() - c_mat = matrix([[sum(r[j]*sc[x,X[j]][k] for j in range(d)) for x in X] + K = sc.keys() + c_mat = matrix([[sum(r[j]*sc[x,X[j]][k] for j in range(d) if (x, X[j]) in K) + for x in X] for r in m for k in range(d)]) - C = c_mat.right_kernel() - return self.subalgebra(C) # TODO: convert C back to elements of ``self`` + C = c_mat.right_kernel().basis_matrix() + return self.subalgebra(map(self, C)) def center(self): """ Return the center of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: Z = L.center(); Z + An example of a finite dimensional Lie algebra with basis: + the abelian Lie algebra with generators ('x0', 'x1', 'x2') + over Rational Field + sage: Z.basis_matrix() + [1 0 0] + [0 1 0] + [0 0 1] """ return self.centralizer(self) @@ -198,6 +238,7 @@ def normalizer(self, V): for l,r in enumerate(m.rows()) for k in range(d)]) N = n_mat.right_kernel() # TODO: convert N back to elements of ``self`` by taking the first ``n`` coefficients + return N return self.subalgebra(N) def product_space(self, L): @@ -373,6 +414,12 @@ def is_nilpotent(self): A Lie algebra is nilpotent if the lower central series eventually becomes `0`. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.is_nilpotent() + True """ return not self.lower_central_series()[-1].dimension() @@ -380,9 +427,15 @@ def is_semisimple(self): """ Return if ``self`` if a semisimple Lie algebra. - A Lie algebra is semisimple if the solvable radical is zero. This - is equivalent to saying the Killing form is non-degenerate - (in characteristic 0). + A Lie algebra is semisimple if the solvable radical is zero. In + characteristic 0, this is equivalent to saying the Killing form + is non-degenerate. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.is_semisimple() + True """ return not self.killing_form_matrix().is_singular() @@ -396,7 +449,7 @@ def dimension(self): sage: L.dimension() 2 """ - return ZZ(len(self.basis())) + return self.basis().cardinality() class ElementMethods: def to_vector(self): From 1e1a6a706e7eb99254de586d6702774934c1c4ff Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 21 Aug 2014 09:17:29 +0900 Subject: [PATCH 009/223] Now we are at full coverage and working examples. --- ...ite_dimensional_lie_algebras_with_basis.py | 74 ++++- ...ite_dimensional_lie_algebras_with_basis.py | 219 +++++++++---- src/sage/categories/lie_algebras.py | 287 +++++++++++++++--- .../categories/lie_algebras_with_basis.py | 27 ++ 4 files changed, 492 insertions(+), 115 deletions(-) diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index 47d1e3725a6..5e3b9c4a75c 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -56,24 +56,11 @@ def __init__(self, R, names, M): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: TestSuite(L).run() """ - self._ordered_indices = range(M.dimension()) + self._ordered_indices = names self._M = M cat = LieAlgebras(R).FiniteDimensional().WithBasis() Parent.__init__(self, base=R, names=names, category=cat) - def _construct_UEA(self): - """ - Construct the universal enveloping algebra of ``self``. - - EXAMPLES:: - - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L._construct_UEA() - Multivariate Polynomial Ring in a, b, c over Rational Field - """ - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - return PolynomialRing(self.base_ring(), self.variable_names()) - def _repr_(self): """ EXAMPLES:: @@ -103,7 +90,16 @@ def _element_constructor_(self, x): sage: M = FreeModule(ZZ, 3) sage: L(M([1, -2, 2])) (1, -2, 2) + sage: a,b,c = L.lie_algebra_generators() + sage: X = L.subalgebra([a+b, 2*a+c]) + sage: x,y = X.basis() + sage: L(x) + (1, 0, 1) + sage: L(x+y) + (1, 1, -1) """ + if isinstance(x, AbelianLieAlgebra.Element): + x = x.value return self.element_class(self, self._M(x)) @cached_method @@ -154,7 +150,12 @@ def subalgebra(self, gens, names='x'): if len(names) == 1 and len(gens) != 1: names = tuple( names[0] + str(i) for i in range(len(gens)) ) N = self._M.subspace([g.value for g in gens]) - return AbelianLieAlgebra(self.base_ring(), names, N) + S = AbelianLieAlgebra(self.base_ring(), names, N) + try: + S._ambient = self._ambient + except AttributeError: + S._ambient = self + return S def basis(self): """ @@ -208,6 +209,49 @@ def free_module(self): return self._M class Element(BaseExample.Element): + def __iter__(self): + """ + Iterate over ``self`` by returning pairs ``(i, c)`` where ``i`` + is the index of the basis element and ``c`` is the corresponding + coefficient. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.inject_variables() + Defining a, b, c + sage: elt = 2*a - c + sage: list(elt) + [('a', 2), ('c', -1)] + """ + I = self.parent()._ordered_indices + zero = self.parent().base_ring().zero() + for i, c in self.value.iteritems(): + if c != zero: + yield (I[i], c) + + def __getitem__(self, i): + """ + Redirect the ``__getitem__()`` to the wrapped element unless + ``i`` is a basis index. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.inject_variables() + Defining a, b, c + sage: elt = 2*a + b - c + sage: elt[0] + 2 + sage: elt['a'] + 2 + sage: elt['c'] + -1 + """ + if i in self.parent()._ordered_indices: + i = self.parent()._ordered_indices.index(i) + return self.value.__getitem__(i) + def _bracket_(self, y): """ Return the Lie bracket ``[self, y]``. 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 8518ade5e9c..c39102d7c7e 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -24,6 +24,11 @@ class FiniteDimensionalLieAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ Category of finite dimensional Lie algebras with a basis. + + .. TODO:: + + Many of these tests should use non-abelian Lie algebras and need to + be added after :trac:`16820`. """ _base_category_class_and_axiom = [LieAlgebras.FiniteDimensional, "WithBasis"] @@ -43,7 +48,9 @@ def example(self, names=('a', 'b', 'c')): Other names of generators can be specified as an optional argument:: sage: C.example(('x','y','z')) - An example of a Lie algebra: the abelian Lie algebra on the generators ('a', 'b', 'c') over Rational Field + An example of a finite dimensional Lie algebra with basis: + the abelian Lie algebra with generators ('x', 'y', 'z') + over Rational Field """ from sage.categories.examples.finite_dimensional_lie_algebras_with_basis import Example return Example(self.base_ring(), names) @@ -56,8 +63,17 @@ def _construct_UEA(self): EXAMPLES:: - sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) - sage: L._construct_UEA() + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: UEA = L._construct_UEA(); UEA + Noncommutative Multivariate Polynomial Ring in a, b, c + over Rational Field, nc-relations: {} + sage: UEA.relations(add_commutative=True) + {b*a: a*b, c*a: a*c, c*b: b*c} + + :: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) # todo: not implemented - #16820 + sage: L._construct_UEA() # todo: not implemented - #16820 """ # Create the UEA relations # We need to get names for the basis elements, not just the generators @@ -65,19 +81,19 @@ def _construct_UEA(self): names = self.variable_names() except ValueError: names = tuple('b{}'.format(i) for i in range(self.dimension())) - I = self._indices + I = self._ordered_indices F = FreeAlgebra(self.base_ring(), names) #gens = F.gens() d = F.gens_dict() rels = {} - S = self.structure_coefficients() + S = self.structure_coefficients(True) for k in S.keys(): - g0 = d[names[I.index(k._left)]] - g1 = d[names[I.index(k._right)]] + g0 = d[names[I.index(k[0])]] + g1 = d[names[I.index(k[1])]] if g0 < g1: - rels[g1*g0] = g0*g1 - sum(val*d[g._name] for g, val in S[k]) + rels[g1*g0] = g0*g1 - sum(val*d[names[I.index(g)]] for g, val in S[k]) else: - rels[g0*g1] = g1*g0 + sum(val*d[g._name] for g, val in S[k]) + rels[g0*g1] = g1*g0 + sum(val*d[names[I.index(g)]] for g, val in S[k]) return F.g_algebra(rels) def killing_matrix(self, x, y): @@ -90,8 +106,17 @@ def killing_matrix(self, x, y): EXAMPLES:: - sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) - sage: L.killing_matrix(x, y) + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: a,b,c = L.lie_algebra_generators() + sage: L.killing_matrix(a, b) + [0 0 0] + [0 0 0] + [0 0 0] + + :: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) # todo: not implemented - #16820 + sage: L.killing_matrix(x, y) # todo: not implemented - #16820 [ 0 0] [-1 0] """ @@ -107,6 +132,13 @@ def killing_form(self, x, y): \langle x \mid y \rangle = \mathrm{tr}\left( \mathrm{ad}_x \circ \mathrm{ad}_y \right). + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: a,b,c = L.lie_algebra_generators() + sage: L.killing_form(a, b) + 0 """ return self.killing_matrix(x, y).trace() @@ -114,6 +146,14 @@ def killing_form(self, x, y): def killing_form_matrix(self): """ Return the matrix of the Killing form of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.killing_form_matrix() + [0 0 0] + [0 0 0] + [0 0 0] """ B = self.basis() m = matrix([[self.killing_form(x, y) for x in B] for y in B]) @@ -139,7 +179,7 @@ def structure_coefficients(self, include_zeros=False): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - Lsage: L.structure_coefficients() + sage: L.structure_coefficients() Finite family {} sage: L.structure_coefficients(True) Finite family {('b', 'c'): (0, 0, 0), ('a', 'b'): (0, 0, 0), @@ -180,6 +220,19 @@ def basis_matrix(self): def centralizer(self, S): """ Return the centralizer of ``S`` in ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: a,b,c = L.lie_algebra_generators() + sage: S = L.centralizer([a + b, 2*a + c]); S + An example of a finite dimensional Lie algebra with basis: + the abelian Lie algebra with generators ('x0', 'x1', 'x2') + over Rational Field + sage: S.basis_matrix() + [1 0 0] + [0 1 0] + [0 0 1] """ #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra #if isinstance(S, LieSubalgebra) or S is self: @@ -218,47 +271,41 @@ def center(self): """ return self.centralizer(self) - def normalizer(self, V): - """ - Return the normalizer of ``V`` in ``self``. - """ - #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra - #if not isinstance(V, LieSubalgebra) and V is not self: - if V is not self: - V = self.subalgebra(V) - - m = V.basis_matrix() - S = self.structure_coefficients() - sc = {k: S[k].to_vector() for k in S} - X = self.basis() - d = self.dimension() - t = m.nrows() - n_mat = matrix([[sum(r[j]*sc[x,X[j]][k] for j in range(d)) for x in X] - + [0]*(t*l) + [m[j][k] for j in range(t)] + [0]*(t*(t-l-1)) - for l,r in enumerate(m.rows()) for k in range(d)]) - N = n_mat.right_kernel() - # TODO: convert N back to elements of ``self`` by taking the first ``n`` coefficients - return N - return self.subalgebra(N) - def product_space(self, L): r""" Return the product space ``[self, L]``. EXAMPLES:: - sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) - sage: Lp = L.product_space(L) - sage: Lp + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: a,b,c = L.lie_algebra_generators() + sage: X = L.subalgebra([a, b+c]) + sage: L.product_space(X) + An example of a finite dimensional Lie algebra with basis: + the abelian Lie algebra with generators () + over Rational Field with basis matrix: + [] + sage: Y = L.subalgebra([a, 2*b-c]) + sage: X.product_space(Y) + An example of a finite dimensional Lie algebra with basis: + the abelian Lie algebra with generators () + over Rational Field with basis matrix: + [] + + :: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) # todo: not implemented - #16820 + sage: Lp = L.product_space(L) # todo: not implemented - #16820 + sage: Lp # todo: not implemented - #16820 Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: (x,) - sage: Lp.product_space(L) + sage: Lp.product_space(L) # todo: not implemented - #16820 Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: (x,) - sage: L.product_space(Lp) + sage: L.product_space(Lp) # todo: not implemented - #16820 Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: (x,) - sage: Lp.product_space(Lp) + sage: Lp.product_space(Lp) # todo: not implemented - #16820 Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: () """ @@ -291,6 +338,13 @@ def derived_subalgebra(self): Return the derived subalgebra of ``self``. EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.derived_subalgebra() + An example of a finite dimensional Lie algebra with basis: + the abelian Lie algebra with generators () over + Rational Field with basis matrix: + [] """ return self.product_space(self) @@ -322,11 +376,22 @@ def derived_series(self): \mathfrak{g}] \bigr], \bigl[ [\mathfrak{g}, \mathfrak{g}], [\mathfrak{g}, \mathfrak{g}] \bigr] \biggr] \subseteq \cdots. - EXAMPLES:: - sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.derived_series() + (An example of a finite dimensional Lie algebra with basis: + the abelian Lie algebra with generators ('a', 'b', 'c') + over Rational Field, + An example of a finite dimensional Lie algebra with basis: + the abelian Lie algebra with generators () over + Rational Field with basis matrix: + []) + + :: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) # todo: not implemented - #16820 + sage: L.derived_series() # todo: not implemented - #16820 (Lie algebra on 2 generators (x, y) over Rational Field, Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: (x,), @@ -367,8 +432,20 @@ def lower_central_series(self): EXAMPLES:: - sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) - sage: L.derived_series() + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.lower_central_series() + (An example of a finite dimensional Lie algebra with basis: + the abelian Lie algebra with generators ('a', 'b', 'c') + over Rational Field, + An example of a finite dimensional Lie algebra with basis: + the abelian Lie algebra with generators () over + Rational Field with basis matrix: + []) + + :: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) # todo: not implemented - #16820 + sage: L.lower_central_series() # todo: not implemented - #16820 (Lie algebra on 2 generators (x, y) over Rational Field, Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: (x,)) @@ -387,11 +464,19 @@ def is_abelian(self): EXAMPLES:: - sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.is_abelian() + True + + :: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) # todo: not implemented - #16820 + sage: L.is_abelian() # todo: not implemented - #16820 False """ - return not self.structure_coefficients() + return len(self.structure_coefficients()) == 0 + # TODO: boolean handling of empty family + #return not self.structure_coefficients() def is_solvable(self): r""" @@ -402,8 +487,14 @@ def is_solvable(self): EXAMPLES:: - sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) - sage: L.is_abelian() + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.is_solvable() + True + + :: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) # todo: not implemented - #16820 + sage: L.is_solvable() # todo: not implemented - #16820 False """ return not self.derived_series()[-1].dimension() @@ -435,7 +526,7 @@ def is_semisimple(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.is_semisimple() - True + False """ return not self.killing_form_matrix().is_singular() @@ -445,8 +536,14 @@ def dimension(self): EXAMPLES:: - sage: L = LieAlgebra(QQ, 'x,y', {('x','y'): {'x':1}}) + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.dimension() + 3 + + :: + + sage: L = LieAlgebra(QQ, 'x,y', {('x','y'): {'x':1}}) # todo: not implemented - #16820 + sage: L.dimension() # todo: not implemented - #16820 2 """ return self.basis().cardinality() @@ -455,6 +552,12 @@ class ElementMethods: def to_vector(self): """ Return ``self`` as a vector. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.an_element().to_vector() + (0, 0, 0) """ M = self.parent().free_module() if not self: @@ -468,11 +571,19 @@ def adjoint_matrix(self): # In #11111 (more or less) by using matrix of a mophis EXAMPLES:: - sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) - sage: x.adjoint_matrix() + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.an_element().adjoint_matrix() + [0 0 0] + [0 0 0] + [0 0 0] + + :: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) # todo: not implemented - #16820 + sage: x.adjoint_matrix() # todo: not implemented - #16820 [1 0] [0 0] - sage: y.adjoint_matrix() + sage: y.adjoint_matrix() # todo: not implemented - #16820 [ 0 0] [-1 0] """ diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index 45767c3bb3a..d1af744178a 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -16,6 +16,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.misc.lazy_import import LazyImport +from sage.categories.category import JoinCategory, Category from sage.categories.category_types import Category_over_base_ring from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.distributive_magmas_and_additive_magmas import DistributiveMagmasAndAdditiveMagmas @@ -42,32 +43,34 @@ class LieAlgebras(Category_over_base_ring): computations with it:: sage: A = C.example(); A - An example of a Lie algebra: the abelian Lie algebra on the generators (B['a'], B['b'], B['c']) over Rational Field + An example of a Lie algebra: the Lie algebra from the associative + algebra Symmetric group algebra of order 3 over Rational Field + generated by ([2, 1, 3], [2, 3, 1]) sage: A.category() - Category of Lie algebras with basis over Rational Field + Category of Lie algebras over Rational Field sage: A.base_ring() Rational Field - sage: A.basis().keys() - {'a', 'b', 'c'} - sage: (a,b,c) = A.gens() - sage: a^3, b^2 - (a^3, b^2) - sage: a*c*b - a*b*c + sage: a,b = A.lie_algebra_generators() + sage: a.bracket(b) + -[1, 3, 2] + [3, 2, 1] + sage: b.bracket(2*a + b) + 2*[1, 3, 2] - 2*[3, 2, 1] - sage: A.product - - sage: A.product(a*b,b) - a*b^2 + sage: A.bracket + + sage: A.bracket(a,b) + -[1, 3, 2] + [3, 2, 1] sage: TestSuite(A).run(verbose=True) running ._test_additive_associativity() . . . pass running ._test_an_element() . . . pass running ._test_category() . . . pass - running ._test_characteristic() . . . pass running ._test_distributivity() . . . pass running ._test_elements() . . . Running the test suite of self.an_element() @@ -82,15 +85,15 @@ class LieAlgebras(Category_over_base_ring): running ._test_elements_eq_transitive() . . . pass running ._test_elements_neq() . . . pass running ._test_eq() . . . pass + running ._test_jacobi_identity() . . . pass running ._test_not_implemented_methods() . . . pass running ._test_pickling() . . . pass - running ._test_prod() . . . pass running ._test_some_elements() . . . pass running ._test_zero() . . . pass sage: A.__class__ - + sage: A.element_class - + Please see the source code of `A` (with ``A??``) for how to implement other Lie algebras. @@ -98,6 +101,11 @@ class LieAlgebras(Category_over_base_ring): TESTS:: sage: TestSuite(LieAlgebras(QQ)).run() + + .. TODO:: + + Many of these tests should use Lie algebras which are not the minimal + example and need to be added after :trac:`16820` (and :trac:`16823`). """ @cached_method def super_categories(self): @@ -113,6 +121,28 @@ def super_categories(self): # and Unital, both of which do not make sense for Lie algebras return [Modules(self.base_ring())] + # TODO: Find some way to do this without copying most of the logic. + def _repr_object_names(self): + r""" + Return the name of the objects of this category. + + .. SEEALSO:: :meth:`Category._repr_object_names` + + EXAMPLES:: + + sage: LieAlgebras(QQ)._repr_object_names() + 'Lie algebras over Rational Field' + """ + base = self.base() + if isinstance(base, Category): + if isinstance(base, JoinCategory): + name = '('+' and '.join(C._repr_object_names() for C in base.super_categories())+')' + else: + name = base._repr_object_names() + else: + name = base + return "Lie algebras over {}".format(name) + def example(self, gens=None): """ Return an example of a Lie algebra as per @@ -127,10 +157,11 @@ def example(self, gens=None): Another set of generators can be specified as an optional argument:: - sage: LieAlgebras(QQ).example(('x','y','z')) + sage: F. = FreeAlgebra(QQ) + sage: LieAlgebras(QQ).example(F.gens()) An example of a Lie algebra: the Lie algebra from the associative algebra - Group algebra of Dihedral group of order 8 as a permutation group over Rational Field - generated by (B[(1,2,3,4)], B[(1,4)(2,3)]) + Free Algebra on 3 generators (x, y, z) over Rational Field + generated by (x, y, z) """ if gens is None: from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra @@ -153,13 +184,13 @@ def extra_super_categories(self): EXAMPLES:: - sage: Modules(IntegerModRing(4)).FiniteDimensional().extra_super_categories() + sage: LieAlgebras(IntegerModRing(4)).FiniteDimensional().extra_super_categories() [Category of finite sets] - sage: Modules(ZZ).FiniteDimensional().extra_super_categories() + sage: LieAlgebras(ZZ).FiniteDimensional().extra_super_categories() [] - sage: Modules(GF(5)).FiniteDimensional().is_subcategory(Sets().Finite()) + sage: LieAlgebras(GF(5)).FiniteDimensional().is_subcategory(Sets().Finite()) True - sage: Modules(ZZ).FiniteDimensional().is_subcategory(Sets().Finite()) + sage: LieAlgebras(ZZ).FiniteDimensional().is_subcategory(Sets().Finite()) False """ if self.base_ring() in Sets().Finite(): @@ -171,6 +202,13 @@ def bracket(self, lhs, rhs): """ Return the Lie bracket ``[lhs, rhs]`` after coercing ``lhs`` and ``rhs`` into elements of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: x,y = L.lie_algebra_generators() + sage: L.bracket(x, x + y) + -[1, 3, 2] + [3, 2, 1] """ return self(lhs)._bracket_(self(rhs)) @@ -182,8 +220,15 @@ def universal_enveloping_algebra(self): EXAMPLES:: - sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.universal_enveloping_algebra() + Noncommutative Multivariate Polynomial Ring in a, b, c + over Rational Field, nc-relations: {} + + :: + + sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) # todo: not implemented - #16820 + sage: L.universal_enveloping_algebra() # todo: not implemented - #16820 Multivariate Polynomial Ring in x0, x1, x2 over Rational Field """ return self.lift.codomain() @@ -195,8 +240,15 @@ def _construct_UEA(self): EXAMPLES:: - sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) - sage: L.universal_enveloping_algebra() # indirect doctest + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L._construct_UEA() + Noncommutative Multivariate Polynomial Ring in a, b, c + over Rational Field, nc-relations: {} + + :: + + sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) # todo: not implemented - #16820 + sage: L.universal_enveloping_algebra() # todo: not implemented - #16820 # indirect doctest Multivariate Polynomial Ring in x0, x1, x2 over Rational Field """ @@ -205,6 +257,16 @@ def lift(self): """ Construct the lift morphism from ``self`` to the universal enveloping algebra of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.inject_variables() + Defining a, b, c + sage: lifted = L.lift(2*a + b - c); lifted + 2*a + b - c + sage: lifted.parent() is L.universal_enveloping_algebra() + True """ M = LiftMorphism(self, self._construct_UEA()) M.register_as_coercion() @@ -214,12 +276,32 @@ def lift(self): def subalgebra(self, gens): """ Return the subalgebra of ``self`` generated by ``gens``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.inject_variables() + Defining a, b, c + sage: L.subalgebra([2*a - c, b + c]) + An example of a finite dimensional Lie algebra with basis: + the abelian Lie algebra with generators ('x0', 'x1') + over Rational Field with basis matrix: + [ 1 0 -1/2] + [ 0 1 1] """ @abstract_method(optional=True) def killing_form(self, x, y): """ Return the Killing form of ``x`` and ``y``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.inject_variables() + Defining a, b, c + sage: L.killing_form(a, b+c) + 0 """ def is_abelian(self): @@ -231,11 +313,21 @@ def is_abelian(self): EXAMPLES:: - sage: L. = LieAlgebra(QQ,1) + sage: L = LieAlgebras(QQ).example() sage: L.is_abelian() - True - sage: L. = LieAlgebra(QQ,2) + False + sage: R = QQ['x,y'] + sage: L = LieAlgebras(QQ).example(R.gens()) sage: L.is_abelian() + True + + :: + + sage: L. = LieAlgebra(QQ,1) # todo: not implemented - #16823 + sage: L.is_abelian() # todo: not implemented - #16823 + True + sage: L. = LieAlgebra(QQ,2) # todo: not implemented - #16823 + sage: L.is_abelian() # todo: not implemented - #16823 False """ G = self.lie_algebra_generators() @@ -251,8 +343,14 @@ def is_commutative(self): EXAMPLES:: - sage: L. = LieAlgebra(QQ, 1) + sage: L = LieAlgebras(QQ).example() sage: L.is_commutative() + False + + :: + + sage: L. = LieAlgebra(QQ, 1) # todo: not implemented - #16823 + sage: L.is_commutative() # todo: not implemented - #16823 True """ return self.is_abelian() @@ -264,7 +362,7 @@ def is_field(self, proof=True): EXAMPLES:: - sage: L = LieAlgebra(QQ, 1, 'x', abelian=True) + sage: L = LieAlgebras(QQ).example() sage: L.is_field() False """ @@ -274,20 +372,54 @@ def is_field(self, proof=True): def is_solvable(self): """ Return if ``self`` is a solvable Lie algebra. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.is_solvable() + True """ @abstract_method(optional=True) def is_nilpotent(self): """ Return if ``self`` is a nilpotent Lie algebra. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.is_nilpotent() + True """ def _test_jacobi_identity(self, **options): """ - Test that the Jacobi identity is satisfied. + Test that the Jacobi identity is satisfied on (not + necessarily all) elements of this set. + + INPUT:: + + - ``options`` -- any keyword arguments accepted by :meth:`_tester`. + + EXAMPLES: + + By default, this method runs the tests only on the + elements returned by ``self.some_elements()``:: + + sage: L = LieAlgebras(QQ).example() + sage: L._test_jacobi_identity() + + However, the elements tested can be customized with the + ``elements`` keyword argument:: + + sage: L = LieAlgebras(QQ).example() + sage: x,y = L.lie_algebra_generators() + sage: L._test_jacobi_identity(elements=[x+y, x, 2*y, x.bracket(y)]) + + See the documentation for :class:`TestSuite` for more information. """ tester = self._tester(**options) - elts = self.some_elements() + elts = tester.some_elements() jacobi = lambda x, y, z: self.bracket(x, self.bracket(y, z)) + \ self.bracket(y, self.bracket(z, x)) + \ self.bracket(z, self.bracket(x, y)) @@ -297,8 +429,6 @@ def _test_jacobi_identity(self, **options): if x == y: continue for z in elts: - if x == z or y == z: # Trivial - continue tester.assert_(jacobi(x, y, z) == zero) def _test_distributivity(self, **options): @@ -310,23 +440,28 @@ def _test_distributivity(self, **options): - ``options`` -- any keyword arguments accepted by :meth:`_tester`. + TESTS:: + + sage: L = LieAlgebras(QQ).example() + sage: L._test_distributivity() + EXAMPLES: By default, this method runs the tests only on the elements returned by ``self.some_elements()``:: - sage: LieAlgebra(QQ, 3, 'x,y,z').some_elements() + sage: LieAlgebra(QQ, 3, 'x,y,z').some_elements() # todo: not implemented - #16820 [x] - sage: LieAlgebra(QQ, 3, 'x,y,z')._test_distributivity() + sage: LieAlgebra(QQ, 3, 'x,y,z')._test_distributivity() # todo: not implemented - #16820 However, the elements tested can be customized with the ``elements`` keyword argument:: - sage: L = LieAlgebra(QQ, cartan_type=['A', 2]) - sage: h1 = L.gen(0) - sage: h2 = L.gen(1) - sage: e2 = L.gen(3) - sage: L._test_distributivity(elements=[h1, h2, e2]) + sage: L = LieAlgebra(QQ, cartan_type=['A', 2]) # todo: not implemented - #16821 + sage: h1 = L.gen(0) # todo: not implemented - #16821 + sage: h2 = L.gen(1) # todo: not implemented - #16821 + sage: e2 = L.gen(3) # todo: not implemented - #16821 + sage: L._test_distributivity(elements=[h1, h2, e2]) # todo: not implemented - #16821 See the documentation for :class:`TestSuite` for more information. """ @@ -345,6 +480,13 @@ class ElementMethods: def bracket(self, rhs): """ Return the Lie bracket ``[self, rhs]``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: x,y = L.lie_algebra_generators() + sage: x.bracket(y) + -[1, 3, 2] + [3, 2, 1] """ return self._bracket_(rhs) @@ -355,23 +497,45 @@ def _bracket_(self, y): Return the Lie bracket ``[self, y]``. EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: x,y = L.lie_algebra_generators() + sage: x._bracket_(y) + -[1, 3, 2] + [3, 2, 1] """ + @abstract_method(optional=True) def lift(self): """ Lift ``self`` into an element of the universal enveloping algebra. EXAMPLES:: - sage: L. = LieAlgebra(QQ, abelian=True) - sage: x.lift() + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.inject_variables() + Defining a, b, c + sage: elt = 3*a + b - c + sage: elt.lift() + 3*a + b - c + + :: + + sage: L. = LieAlgebra(QQ, abelian=True) # todo: not implemented - #16820 + sage: x.lift() # todo: not implemented - #16820 x """ - return self.parent().lift(self) def killing_form(self, x): """ Return the Killing form of ``self`` and ``x``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.inject_variables() + Defining a, b, c + sage: a.killing_form(b) + 0 """ return self.parent().killing_form(self, x) @@ -382,18 +546,49 @@ class LiftMorphism(Morphism): def __init__(self, domain, codomain): """ Initialize ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: f = L.lift + + We skip the category test since this is currently not an element of + a homspace:: + + sage: TestSuite(f).run(skip="_test_category") """ Morphism.__init__(self, Hom(domain, codomain)) def _call_(self, x): """ Lift ``x`` to the universal enveloping algebra. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.inject_variables() + Defining a, b, c + sage: L.lift(3*a + b - c) + 3*a + b - c """ return x.lift() def section(self): """ Return the section map of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.lift.section() + Traceback (most recent call last): + ... + NotImplementedError + + .. TODO:: + + Implement the section map from an enveloping algebra to the + corresponding Lie algebra. """ raise NotImplementedError diff --git a/src/sage/categories/lie_algebras_with_basis.py b/src/sage/categories/lie_algebras_with_basis.py index afdff1bcde1..93f460521ca 100644 --- a/src/sage/categories/lie_algebras_with_basis.py +++ b/src/sage/categories/lie_algebras_with_basis.py @@ -51,6 +51,12 @@ class ParentMethods: def _basis_cmp(self, x, y): """ Compare two basis element indices. The default is to call ``cmp``. + + TESTS:: + + sage: L = LieAlgebras(QQ).WithBasis().example() + sage: L._basis_cmp(Partition([3,1]), Partition([2,1,1])) + 1 """ return cmp(x, y) @@ -60,11 +66,23 @@ def bracket_on_basis(self, x, y): Return the bracket of basis elements indexed by ``x`` and ``y`` where ``x < y``. If this is not implemented, then the method ``_bracket_()`` for the elements must be overwritten. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).WithBasis().example() + sage: L.bracket_on_basis(Partition([3,1]), Partition([2,2,1,1])) + 0 """ def free_module(self): """ Return ``self`` as a free module. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).WithBasis().example() + sage: L.free_module() + Free module generated by Partitions over Rational Field """ from sage.combinat.free_module import CombinatorialFreeModule try: @@ -78,6 +96,15 @@ class ElementMethods: def _bracket_(self, y): """ Return the Lie bracket of ``[self, y]``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).WithBasis().example() + sage: G = L.lie_algebra_generators() + sage: x = G[Partition([4,3,3,1])] + sage: y = G[Partition([6,1])] + sage: x.bracket(y) + 0 """ P = self.parent() def term(ml,mr): From f4eab36909748d413704745f137cef42eee0123d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 19 Sep 2014 10:11:50 -0700 Subject: [PATCH 010/223] Initial moving of files. --- src/sage/algebras/lie_algebras/__init__.py | 0 src/sage/algebras/lie_algebras/all.py | 23 + src/sage/algebras/lie_algebras/examples.py | 255 +++++ src/sage/algebras/lie_algebras/heisenberg.py | 507 ++++++++++ src/sage/algebras/lie_algebras/lie_algebra.py | 923 ++++++++++++++++++ .../lie_algebras/lie_algebra_element.py | 485 +++++++++ .../lie_algebras/structure_coefficients.py | 570 +++++++++++ src/sage/algebras/lie_algebras/virasoro.py | 237 +++++ 8 files changed, 3000 insertions(+) create mode 100644 src/sage/algebras/lie_algebras/__init__.py create mode 100644 src/sage/algebras/lie_algebras/all.py create mode 100644 src/sage/algebras/lie_algebras/examples.py create mode 100644 src/sage/algebras/lie_algebras/heisenberg.py create mode 100644 src/sage/algebras/lie_algebras/lie_algebra.py create mode 100644 src/sage/algebras/lie_algebras/lie_algebra_element.py create mode 100644 src/sage/algebras/lie_algebras/structure_coefficients.py create mode 100644 src/sage/algebras/lie_algebras/virasoro.py diff --git a/src/sage/algebras/lie_algebras/__init__.py b/src/sage/algebras/lie_algebras/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/sage/algebras/lie_algebras/all.py b/src/sage/algebras/lie_algebras/all.py new file mode 100644 index 00000000000..490fcea0a8e --- /dev/null +++ b/src/sage/algebras/lie_algebras/all.py @@ -0,0 +1,23 @@ +""" +Lie Algebras +""" + +#***************************************************************************** +# Copyright (C) 2013 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# This code is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# The full text of the GPL is available at: +# +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from lie_algebra import LieAlgebra +#from kac_moody import KacMoodyAlgebra +import examples as lie_algebras + diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py new file mode 100644 index 00000000000..2ca2829fd32 --- /dev/null +++ b/src/sage/algebras/lie_algebras/examples.py @@ -0,0 +1,255 @@ +""" +Examples of Lie Algebras + +There are the following examples of Lie algebras: + +- All 3-dimensional Lie algebras +- The Lie algebra of affine transformations of the line +- All abelian Lie algebras +- The Lie algebra of upper triangular matrices +- The Lie algebra of strictly upper triangular matrices + +AUTHORS: + +- Travis Scrimshaw (07-15-2013): Initial implementation +""" +#***************************************************************************** +# Copyright (C) 2013 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +#from sage.algebras.lie_algebras.classical_lie_algebra import gl, sl, so, sp +from sage.algebras.lie_algebras.virasoro import VirasoroAlgebra + +def three_dimensional(R, a, b, c, d, names=['X', 'Y', 'Z']): + r""" + The 3 dimensional Lie algebra generated by `X, Y, Z` defined by + the relations: + + .. MATH:: + + [X, Y] = aZ + dY, \quad [Y, Z] = bX, \quad [Z, X] = cY - dZ + + where `a,b,c,d \in R`. + + EXAMPLES:: + + sage: L = lie_algebras.three_dimensional(QQ, 4, 1, -1, 2) + sage: L.structure_coefficients() + {[X, Y]: ((Y, 2), (Z, 4)), [X, Z]: ((Y, 1), (Z, 2)), [Y, Z]: ((X, 1),)} + sage: L = lie_algebras.three_dimensional(QQ, 1, 0, 0, 0) + sage: L.structure_coefficients() + {[X, Y]: ((Z, 1),)} + sage: L = lie_algebras.three_dimensional(QQ, 0, 0, -1, -1) + sage: L.structure_coefficients() + {[X, Y]: ((Y, -1),), [X, Z]: ((Y, 1), (Z, -1))} + sage: L = lie_algebras.three_dimensional(QQ, 0, 1, 0, 0) + sage: L.structure_coefficients() + {[Y, Z]: ((X, 1),)} + sage: lie_algebras.three_dimensional(QQ, 0, 0, 0, 0) + Abelian Lie algebra on 3 generators (X, Y, Z) over Rational Field + """ + if isinstance(names, str): + names = names.split(',') + X = names[0] + Y = names[1] + Z = names[2] + from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients + s_coeff = {(X,Y): {Z:a, Y:d}, (Y,Z): {X:b}, (Z,X): {Y:c, Z:-d}} + return LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) + +def cross_product(R, names=['X', 'Y', 'Z']): + r""" + The Lie algebra of `\RR^3` defined by `\times` as the usual cross product. + + EXAMPLES:: + + sage: L = lie_algebras.cross_product(QQ) + sage: L.structure_coefficients() + {[X, Y]: ((Z, 1),), [X, Z]: ((Y, -1),), [Y, Z]: ((X, 1),)} + """ + L = three_dimensional(R, 1, 1, 1, 0, names) + L.rename("Lie algebra of RR^3 under cross product over {}".format(R)) + return L + +def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): + """ + Return the 3-dimensional Lie algebra of rank ``n``. + + INPUT: + + - ``R`` -- the base ring + - ``n`` -- the rank + - ``a`` -- the deformation parameter, if 0 then returns the degenerate case + - ``names`` -- (optional) the generator names + + EXAMPLES:: + + sage: lie_algebras.three_dimensional_by_rank(QQ, 0) + Abelian Lie algebra on 3 generators (X, Y, Z) over Rational Field + sage: L = lie_algebras.three_dimensional_by_rank(QQ, 1) + sage: L.structure_coefficients() + {[Y, Z]: ((X, 1),)} + sage: L = lie_algebras.three_dimensional_by_rank(QQ, 2, 4) + sage: L.structure_coefficients() + {[X, Y]: ((Y, 1),), [X, Z]: ((Y, 1), (Z, 1))} + sage: L = lie_algebras.three_dimensional_by_rank(QQ, 2, 0) + sage: L.structure_coefficients() + {[X, Y]: ((Y, 1),)} + sage: lie_algebras.three_dimensional_by_rank(QQ, 3) + Special linear Lie algebra of rank 2 over Rational Field + """ + if isinstance(names, str): + names = names.split(',') + names = tuple(names) + if n == 0: + from sage.algebras.lie_algebras.structure_coefficients import AbelianLieAlgebra + return AbelianLieAlgebra(R, names) + if n == 1: + L = three_dimensional(R, 0, 1, 0, 0, names) # Strictly upper triangular matrices + L.rename("Lie algebra of 3x3 strictly upper triangular matrices over {}".format(R)) + return L + if n == 2: + if a is None: + raise ValueError("The parameter 'a' must be specified") + X = names[0] + Y = names[1] + Z = names[2] + from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients + if a == 0: + s_coeff = {(X,Y): {Y:R.one()}, (X,Z): {Y:R(a)}} + L = LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) + L.rename("Degenerate Lie algebra of dimension 3 and rank 2 over {}".format(R)) + else: + s_coeff = {(X,Y): {Y:R.one()}, (X,Z): {Y:R.one(), Z:R.one()}} + L = LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) + L.rename("Lie algebra of dimension 3 and rank 2 with parameter {} over {}".format(a, R)) + return L + if n == 3: + return sl(R, 2) + raise ValueError("Invalid rank") + +def affine_transformations_line(R, names=['X', 'Y'], representation='bracket'): + """ + The Lie algebra of affine transformations of the line. + + EXAMPLES:: + + sage: L = lie_algebras.affine_transformations_line(QQ) + sage: L.structure_coefficients() + {[X, Y]: ((Y, 1),)} + """ + if isinstance(names, str): + names = names.split(',') + names = tuple(names) + if representation == 'matrix': + MS = MatrixSpace(R, 2, sparse=True) + one = R.one() + gens = tuple(MS({(0,i):one}) for i in range(2)) + return LieAlgebraFromAssociative(self, R, M, gens, names) + X = names[0] + Y = names[1] + from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients + s_coeff = {(X,Y): {Y:R.one()}} + L = LieAlgebraWithStructureCoefficients(R, s_coeff, names) + L.rename("Lie algebra of affine transformations of a line over {}".format(R)) + return L + +def abelian(R, names): + """ + Return the abelian Lie algebra generated by ``names``. + + EXAMPLES:: + + sage: lie_algebras.abelian(QQ, 'x, y, z') + Abelian Lie algebra on 3 generators (x, y, z) over Rational Field + """ + if isinstance(names, str): + names = names.split(',') + from sage.algebras.lie_algebras.structure_coefficients import AbelianLieAlgebra + return AbelianLieAlgebra(R, tuple(names)) + +def Heisenberg(R, n, representation="structure"): + """ + Return the rank ``n`` Heisenberg algebra in the given representation. + + INPUT: + + - ``R`` -- the base ring + - ``n`` -- the rank + - ``representation`` -- (default: "structure") can be one of the following: + + - ``"structure"`` -- using structure coefficients + - ``"matrix"`` -- using matrices + + EXAMPLES:: + + sage: lie_algebras.Heisenberg(QQ, 3) + Heisenberg algebra of rank 3 over Rational Field + """ + from sage.rings.infinity import infinity + if n == infinity: + from sage.algebras.lie_algebras.heisenberg import InfiniteHeisenbergAlgebra + return InfiniteHeisenbergAlgebra(R) + if representation == "matrix": + from sage.algebras.lie_algebras.heisenberg import HeisenbergAlgebra_matrix + return HeisenbergAlgebra_matrix(R, n) + from sage.algebras.lie_algebras.heisenberg import HeisenbergAlgebra + return HeisenbergAlgebra(R, n) + +def regular_vector_fields(R): + r""" + Return the Lie algebra of regular vector fields of `\CC^{\times}`. + + EXAMPLES:: + + sage: lie_algebras.regular_vector_fields(QQ) + The Lie algebra of regular vector fields over Rational Field + """ + from sage.algebras.lie_algebras.virasoro import LieAlgebraRegularVectorFields + return LieAlgebraRegularVectorFields(R) + +def upper_triangluar_matrices(R, n): + r""" + Return the Lie algebra `\mathfrak{b}_k` of strictly `k \times k` upper + triangular matrices. + + EXAMPLES:: + + sage: lie_algebras.upper_triangluar_matrices(QQ, 4) + Lie algebra of 4-dimensional upper triangular matrices over Rational Field + """ + from sage.matrix.matrix_space import MatrixSpace + from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative + MS = MatrixSpace(R, n, sparse=True) + one = R.one() + names = tuple('n{}'.format(i) for i in range(n-1)) + names = tuple('t{}'.format(i) for i in range(n)) + gens = [MS({(i,i+1):one}) for i in range(n-1)] + gens += [MS({(i,i):one}) for i in range(n)] + L = LieAlgebraFromAssociative(R, MS, gens, names) + L.rename("Lie algebra of {}-dimensional upper triangular matrices over {}".format(n, L.base_ring())) + return L + +def strictly_upper_triangular_matrices(R, n): + r""" + Return the Lie algebra `\mathfrak{n}_k` of strictly `k \times k` upper + triangular matrices. + + EXAMPLES:: + + sage: lie_algebras.strictly_upper_triangular_matrices(QQ, 4) + Lie algebra of 4-dimensional strictly upper triangular matrices over Rational Field + """ + from sage.matrix.matrix_space import MatrixSpace + from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative + MS = MatrixSpace(R, n, sparse=True) + one = R.one() + names = tuple('n{}'.format(i) for i in range(n-1)) + gens = tuple(MS({(i,i+1):one}) for i in range(n-1)) + L = LieAlgebraFromAssociative(R, MS, gens, names) + L.rename("Lie algebra of {}-dimensional strictly upper triangular matrices over {}".format(n, L.base_ring())) + return L + diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py new file mode 100644 index 00000000000..576b17cbe42 --- /dev/null +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -0,0 +1,507 @@ +""" +Heisenberg Algebras + +AUTHORS: + +- Travis Scrimshaw (2013-08-13): Initial version +""" + +#***************************************************************************** +# Copyright (C) 2013 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# This code is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# See the GNU General Public License for more details; the full text +# is available at: +# +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method +from sage.algebras.algebra import Algebra +from sage.algebras.lie_algebras.lie_algebra import InfinitelyGeneratedLieAlgebra, \ + LieAlgebraFromAssociative, FinitelyGeneratedLieAlgebra +from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement, LieGenerator +from sage.categories.lie_algebras import LieAlgebras +from sage.matrix.matrix_space import MatrixSpace +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.infinity import infinity +from sage.sets.family import Family + +class HeisenbergGenerator(LieGenerator): + """ + Generator for the Heisenberg algebra. + """ + def __init__(self, name, i=None): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: from sage.algebras.lie_algebras.heisenberg import HeisenbergGenerator + sage: gen = HeisenbergGenerator('p', 2) + sage: TestSuite(gen).run() + """ + self._i = i + LieGenerator.__init__(self, name) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: from sage.algebras.lie_algebras.heisenberg import HeisenbergGenerator + sage: HeisenbergGenerator('p', 2) + p2 + sage: HeisenbergGenerator('d') + d + """ + if self._i is None: + return self._name + return self._name + repr(self._i) + + def _latex_(self): + r""" + Return a `LaTeX` representation of ``self``. + + EXAMPLES:: + + sage: from sage.algebras.lie_algebras.heisenberg import HeisenbergGenerator + sage: latex(HeisenbergGenerator('p', 2)) + p_{2} + sage: latex(HeisenbergGenerator('d')) + d + """ + if self._i is None: + return self._name + return self._name + "_{{{}}}".format(self._i) + + def __eq__(self, rhs): + """ + Compare equals. + + EXAMPLES:: + + sage: from sage.algebras.lie_algebras.heisenberg import HeisenbergGenerator + sage: p2 = HeisenbergGenerator('p', 2) + sage: p2 == HeisenbergGenerator('p', 2) + True + sage: p2 == HeisenbergGenerator('q', 2) + False + sage: p2 == HeisenbergGenerator('p', 4) + False + """ + return isinstance(rhs, LieGenerator) and self._name == rhs._name \ + and self._i == rhs._i + + def __ne__(self, rhs): + """ + Compare equals. + + EXAMPLES:: + + sage: from sage.algebras.lie_algebras.heisenberg import HeisenbergGenerator + sage: p2 = HeisenbergGenerator('p', 2) + sage: p2 != HeisenbergGenerator('p', 2) + False + sage: p2 != HeisenbergGenerator('q', 2) + True + sage: p2 != HeisenbergGenerator('p', 4) + True + """ + return not self.__eq__(rhs) + + def __lt__(self, rhs): + """ + Compare less than. + + EXAMPLES:: + + sage: from sage.algebras.lie_algebras.heisenberg import HeisenbergGenerator + sage: p2 = HeisenbergGenerator('p', 2) + sage: q2 = HeisenbergGenerator('q', 2) + sage: p3 = HeisenbergGenerator('p', 3) + sage: p2 < p3 + True + sage: p2 < q2 + True + """ + if isinstance(rhs, HeisenbergGenerator): + return self._name < rhs._name or (self._name == rhs._name and self._i < rhs._i) + return False + +class HeisenbergAlgebra_abstract: + """ + The common methods for the (non-matrix) Heisenberg algebras. + """ + def p(self, i): + """ + The generator `p_i`. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, oo) + sage: L.p(2) + p2 + """ + return self.element_class(self, {HeisenbergGenerator('p', i): self.base_ring().one()}) + + def q(self, i): + """ + The generator `q_i`. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, oo) + sage: L.q(2) + q2 + """ + return self.element_class(self, {HeisenbergGenerator('q', i): self.base_ring().one()}) + + def z(self): + """ + The generator `z`. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, oo) + sage: L.z() + z + """ + return self.element_class(self, {HeisenbergGenerator('z'): self.base_ring().one()}) + + def bracket_on_basis(self, x, y): + """ + Return the bracket of basis elements indexed by ``x`` and ``y``. + + EXAMPLES:: + + sage: from sage.algebras.lie_algebras.heisenberg import HeisenbergGenerator + sage: H = lie_algebras.Heisenberg(QQ, 3) + sage: p1 = HeisenbergGenerator('p', 1) + sage: q1 = HeisenbergGenerator('q', 1) + sage: H.bracket_on_basis(p1, q1) + z + """ + if x._name == 'p' and y._name == 'q' and x._i == y._i: + return self.z() + return self.zero() + + Element = LieAlgebraElement + +class HeisenbergAlgebra(HeisenbergAlgebra_abstract, FinitelyGeneratedLieAlgebra): + """ + A Heisenberg algebra defined using structure coefficients. + + The Heisenberg algebra is the Lie algebra generated by `p_i`, `q_i`, and + `z` with the following relations: + + .. MATH:: + + [p_i, q_j] = \delta_{ij} z, \quad [p_i, z] = [q_i, z] = [p_i, p_j] + = [q_i, q_j] = 0. + + .. NOTE:: + + The relations `[p_i, q_j] = \delta_{ij} z`, `[p_i, z] = 0`, and + `[q_i, z] = 0` are known as canonical commutation relations. See + :wikipedia:`Canonical_commutation_relations`. + + INPUT: + + - ``R`` -- the base ring + - ``n`` -- the rank of the Heisenberg algebra + + REFERENCES: + + - :wikipedia:`Heisenberg_algebra` + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, 2) + """ + def __init__(self, R, n): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, 2) + sage: TestSuite(L).run() + """ + self._n = n + names = ['p%s'%i for i in range(1,n+1)] + ['q%s'%i for i in range(1,n+1)] + ['z'] + FinitelyGeneratedLieAlgebra.__init__(self, R, names, + category=LieAlgebras(R).FiniteDimensional().WithBasis()) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: lie_algebras.Heisenberg(QQ, 3) + Heisenberg algebra of rank 3 over Rational Field + """ + return "Heisenberg algebra of rank {0} over {1}".format(self._n, self.base_ring()) + + @cached_method + def gens(self): + """ + Return the generators of ``self``. + + EXAMPLES:: + + sage: H = lie_algebras.Heisenberg(QQ, 2) + sage: H.gens() + (p1, p2, q1, q2, z) + """ + L = [self.p(i) for i in range(1, self._n+1)] + L += [self.q(i) for i in range(1, self._n+1)] + L += [self.z()] + return tuple(L) + + def gen(self, i): + """ + Return the ``i``-th generator of ``self``. + + EXAMPLES:: + + sage: H = lie_algebras.Heisenberg(QQ, 2) + sage: H.gen(2) + q1 + sage: H.gen(4) + z + """ + return self.gens()[i] + + def algebra_generators(self): + """ + Return the algebra generators of ``self``. + + EXAMPLES:: + + sage: H = lie_algebras.Heisenberg(QQ, 1) + sage: H.algebra_generators() + Finite family {'q1': q1, 'p1': p1} + """ + return Family({self.variable_names()[i]: x for i,x in enumerate(self.gens()[:-1])}) + + def basis(self): + """ + Return the basis of ``self``. + + EXAMPLES:: + + sage: H = lie_algebras.Heisenberg(QQ, 1) + sage: H.basis() + Finite family {'q1': q1, 'p1': p1, 'z': z} + """ + return Family({self.variable_names()[i]: x for i,x in enumerate(self.gens())}) + +class InfiniteHeisenbergAlgebra(HeisenbergAlgebra_abstract, InfinitelyGeneratedLieAlgebra): + """ + The infinite Heisenberg algebra. + + This is the Heisenberg algebra on an infinite number of generators. See + :class:`HeisenbergAlgebra` for more information. + """ + def __init__(self, R): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, oo) + sage: TestSuite(L).run() + """ + InfinitelyGeneratedLieAlgebra.__init__(self, R, category=LieAlgebras(R).WithBasis()) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: lie_algebras.Heisenberg(QQ, oo) + The infinite Heisenberg algebra over Rational Field + """ + return "The infinite Heisenberg algebra over {}".format(self.base_ring()) + + def _an_element_(self): + """ + Return an element of ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, oo) + sage: L._an_element_() + p2 - 1/2*q2 + z + """ + c = self.base_ring().an_element() + return self.p(2) - c * self.q(2) + self.z() + + def basis(self): + """ + Return the basis of ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, oo) + sage: L.basis() + Disjoint union of Family + (Lazy family ((i))_{i in Positive integers}, + Lazy family ((i))_{i in Positive integers}, + Family (z,)) + """ + from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets + from sage.sets.positive_integers import PositiveIntegers + from sage.sets.family import Family + p = Family(PositiveIntegers(), self.p) + q = Family(PositiveIntegers(), self.q) + z = Family([self.z()]) + return DisjointUnionEnumeratedSets([p, q, z]) + +####################################################### +## Finite rank Heisenberg algebra using matrices + +class HeisenbergAlgebra_matrix(LieAlgebraFromAssociative, HeisenbergAlgebra): + r""" + A Heisenberg algebra represented using matrices. + + The Heisenberg algebra over `R` is a Lie algebra which is defined as + the Lie algebra of the matrices: + + .. MATH:: + + \begin{bmatrix} + 0 & p^T & z \\ + 0 & 0_n & q \\ + 0 & 0 & 0 + \end{bmatrix} + + where `p, q \in R^n` and `0_n` in the `n \times n` zero matrix. It has a + basis of + + .. MATH:: + + \begin{aligned} + p_i & = \begin{bmatrix} + 0 & e_i^T & 0 \\ + 0 & 0_n & 0 \\ + 0 & 0 & 0 + \end{bmatrix}, + \\ q_i & = \begin{bmatrix} + 0 & 0 & 0 \\ + 0 & 0_n & e_i \\ + 0 & 0 & 0 + \end{bmatrix}, + \\ z & = \begin{bmatrix} + 0 & 0 & z \\ + 0 & 0_n & 0 \\ + 0 & 0 & 0 + \end{bmatrix}, + \end{aligned} + + where `\{e_i\}` is the standard basis. + + INPUT: + + - ``R`` -- the base ring + - ``n`` -- the size of the matrices + """ + def __init__(self, R, n): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, 2, representation="matrix") + sage: TestSuite(L).run() + """ + self._n = n + MS = MatrixSpace(R, n+2, sparse=True) + one = R.one() + p = [MS({(0,i):one}) for i in range(1, n+1)] + q = [MS({(i,n+1):one}) for i in range(1, n+1)] + names = ['p%s'%i for i in range(n)] + ['q%s'%i for i in range(n)] + ['z'] + LieAlgebraFromAssociative.__init__(self, R, MS, tuple(p + q + [MS({(0,n+1):one})]), tuple(names)) + self._p = self.gens()[:n] + self._q = self.gens()[n:2*n] + self._z = self.gen(2*n) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: lie_algebras.Heisenberg(QQ, 3, representation="matrix") + Heisenberg algebra of rank 3 over Rational Field + """ + return "Heisenberg algebra of rank {} over {}".format(self._n, self.base_ring()) + + def p(self, i): + r""" + Return the generator `p_i`. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, 1, representation="matrix") + sage: L.p(0) + [0 1 0] + [0 0 0] + [0 0 0] + """ + return self._p[i] + + def q(self, i): + r""" + Return the generator `q_i`. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, 1, representation="matrix") + sage: L.q(0) + [0 0 0] + [0 0 1] + [0 0 0] + """ + return self._q[i] + + def z(self): + """ + Return the generator `z`. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, 1, representation="matrix") + sage: L.z() + [0 0 1] + [0 0 0] + [0 0 0] + """ + return self._z + + def bracket_on_basis(self, x, y): + """ + Return the bracket of basis elements indexed by ``x`` and ``y``. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, 1, representation="matrix") + sage: p = matrix(QQ, 3, 3, {(0,1):1}) + sage: q = matrix(QQ, 3, 3, {(1,2):1}) + sage: L.bracket_on_basis(p, q) + [0 0 1] + [0 0 0] + [0 0 0] + """ + return self(x*y - y*x) + diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py new file mode 100644 index 00000000000..ecb051050e7 --- /dev/null +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -0,0 +1,923 @@ +""" +Lie Algebras + +AUTHORS: + +- Travis Scrimshaw (2013-05-03): Initial version +""" + +#***************************************************************************** +# Copyright (C) 2013 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# This code is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# See the GNU General Public License for more details; the full text +# is available at: +# +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from copy import copy +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute +from sage.structure.indexed_generators import IndexedGenerators +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.element_wrapper import ElementWrapper + +from sage.categories.algebras import Algebras +from sage.categories.lie_algebras import LieAlgebras +from sage.categories.rings import Rings +from sage.categories.morphism import Morphism, SetMorphism +from sage.categories.map import Map +from sage.categories.homset import Hom + +from sage.algebras.free_algebra import FreeAlgebra +from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, \ + LieBracket, LieAlgebraElement, LieAlgebraElementWrapper +from sage.rings.all import ZZ +from sage.rings.ring import Ring +from sage.rings.integer import Integer +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.infinity import infinity +from sage.matrix.matrix_space import MatrixSpace +from sage.matrix.constructor import matrix +from sage.modules.free_module_element import vector +from sage.modules.free_module import FreeModule, span +from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract +from sage.sets.family import Family +from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + +class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): + r""" + A Lie algebra `L` over a base ring `R`. + + A Lie algebra is an algebra with a bilinear operation called Lie bracket + `[\cdot, \cdot] : L \times L \to L` such that `[x, x] = 0` and + the following relation holds: + + .. MATH:: + + \bigl[x, [y, z] \bigr] + \bigl[ y, [z, x] \bigr] + + \bigl[ z, [x, y] \bigr] = 0. + + This relation is known as the *Jacobi identity* (or sometimes the Jacobi + relation). We note that from `[x, x] = 0`, we have `[x + y, x + y] = 0`. + Next from bilinearity, we see that + + .. MATH:: + + 0 = [x + y, x + y] = [x, x] + [x, y] + [y, x] + [y, y] + = [x, y] + [y, x], + + thus `[x, y] = -[y, x]` and the Lie bracket is antisymmetric. + + Lie algebras are closely related to Lie groups. Let `G` be a Lie group + and fix some `g \in G`, we can construct the Lie algebra `L` of `G` by + considering the tangent space at `g`. We can also (partially) recover `G` + from `L` by using what is known as the exponential map. + + Given any associative algebra `A`, we can construct a Lie algebra `L` by + defining the Lie bracket to be the commutator `[a, b] = ab - ba`. We call + an associative algebra `A` which contains `L` in this fashion an + *enveloping algebra*. We can the embedding which sends the Lie bracket to + the commutator a Lie embedding. Now if we are given a Lie algebra `L`, we + can construct an enveloping algebra `U_L` with Lie embedding `h : L \to + U_L` which has the following universal property: for any enveloping + algebra `A` with Lie embedding `f : L \to A`, there exists a unique unital + algebra homomorphism `g : U_L \to A` such that `f = g \circ h`. The + algebra `U_L` is known as the *universal enveloping algebra*. + + EXAMPLES: + + We can also create abelian Lie algebras using the ``abelian`` keyword:: + + sage: L. = LieAlgebra(QQ, abelian=True); L + Abelian Lie algebra on 3 generators (x, y, z) over Rational Field + + We can also input a set of structure coefficients. For example, we want + to create the Lie algebra of `\QQ^3` under the Lie bracket of `\times` + (cross-product):: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) + sage: L + Lie algebra on 3 generators (x, y, z) over Rational Field + + To compute the Lie backet of two objects, you cannot use the ``*``. + This will automatically lift up to the universal enveloping algebra. + To get elements in the Lie algebra, you must use :meth:`bracket`:: + + sage: L = LieAlgebra(QQ, {('e','h'):{'e':-2}, ('f','h'):{'f':2}, ('e','f'):{'h':1}} + sage: h,e,f = L.gens() + sage: L.bracket(h, e) + 2*e1 + sage: elt = h*e; elt + h1*e1 + sage: elt.parent() + Noncommutative Multivariate Polynomial Ring in h1, e1, f1 over Rational Field, + nc-relations: {f1*e1: e1*f1 - h1, e1*h1: h1*e1 - 2*e1, f1*h1: h1*f1 + 2*f1} + + For convienence, there is are two shorthand notations for computing + Lie backets:: + + sage: h,e,f = L.gens() + sage: L([h,e]) + 2*e1 + sage: L([h,[e,f]]) + 0 + sage: L([[h,e],[e,f]]) + -4*e1 + sage: L[h, e] + 2*e1 + sage: L[h, L[e, f]] + 0 + + .. WARNING:: + + Because this is a modified (abused) version of python syntax, it + does **NOT** work with addition. For example ``L([e + [h, f], h])`` + or ``L[e + [h, f], h]`` will both raise errors. Instead you must + use ``L[e + L[h, f], h]``. + + Now we construct a free Lie algebra in a few different ways. There are + two primary representations, as brackets and as polynomials:: + + sage: L = LieAlgebra(QQ, 'x,y,z'); L # not tested + Free Lie algebra generated by (x, y, z) over Rational Field + sage: P. = LieAlgebra(QQ, representation="polynomial"); P + Lie algebra on 3 generators (a, b, c) over Rational Field + + Using brackets, there are two different bases for the free Lie algebra, + the Hall basis and Lyndon basis. We need to specify which basis we want + to use before being able to construct elements. Each of these can be + accessed as follows:: + + sage: Hall = L.Hall(); Hall # not tested + Free Lie algebra generated by (x, y, z) over Rational Field in the Hall basis + sage: Lyndon = L.Lyndon(); Lyndon # not tested + Free Lie algebra generated by (x, y, z) over Rational Field in the Lyndon basis + + As a convience, we include generators for the Lie algebra as being + elements using the Hall basis. The primary difference between these two + bases is just the canonical form for elements. :: + + sage: L. = LieAlgebra(QQ); L # not tested + Free Lie algebra generated by (x, y, z) over Rational Field + + However this does not hold for the polynomial representation, which we + can think of the variables as being a free algebra and the Lie bracket + is the commutator:: + + sage: P.bracket(a, b) + P.bracket(a - c, b + 3*c) + 2*a*b + 3*a*c - 2*b*a + b*c - 3*c*a - c*b + + REFERENCES: + + .. [deGraaf] Willem A. de Graaf. *Lie Algebras: Theory and Algorithms*. + North-Holland Mathemtaical Library. (2000). Elsevier Science B.V. + + - Victor Kac. *Infinite Dimensional Lie Algebras*. + + - :wikipedia:`Lie_algebra` + """ + @staticmethod + def __classcall_private__(cls, R, arg0=None, arg1=None, names=None, + index_set=None, **kwds): + """ + Select the correct parent based upon input. + """ + # Check if we need to swap the arguments + if arg0 in ZZ or arg1 in Algebras(R): + arg0, arg1 = arg1, arg0 + + # Check if a Cartan type was passed, if so, set that to be the first arg + if "cartan_type" in kwds: + arg0 = CartanType(kwds["cartan_type"]) + + # Parse the first argument + # ----- + + if isinstance(arg0, dict): + if len(arg0) == 0: + from sage.algebras.lie_algebras.structure_coefficients import AbelianLieAlgebra + return AbelianLieAlebra(R, names, index_set) + elif isinstance(arg0.keys()[0], (list,tuple)): + # We assume it is some structure coefficients + arg1, arg0 = arg0, arg1 + else: + # It is generated by elements of an associative algebra + index_set = arg0.keys() + gens = arg0.values() + A = gens[0].parent() + return LieAlgebraFromAssociative(R, A, gens, names, index_set) + + if isinstance(arg0, (Ring, MatrixSpace)) or arg0 in Rings(): + if arg1 is None: + gens = arg0.gens() + if names is None: + names = arg0.variable_names() + elif isinstance(arg1, str): + names = arg1 + gens = arg0.gens() + else: + gens = arg1 + + if names is not None: + if isinstance(names, str): + names = tuple(names.split(',')) + if len(names) != len(gens): + raise ValueError("the number of names must equal the number of generators") + return LieAlgebraFromAssociative(R, arg0, gens, names, index_set) + + if isinstance(arg0, (list, tuple)): + if all(isinstance(x, str) for x in arg0): + # If they are all strings, then it is a list of variables + names = tuple(arg0) + else: + # Otherwise assume they are elements of an assoc alg + A = arg0[0].parent() + if isinstance(arg1, str): + names = tuple(arg1.split(',')) + if len(names) == 1 and len(arg0) != 1: + names = ['{}{}'.format(names[0], i) for i in xrange(len(arg0))] + elif isinstance(arg1, (tuple, list)): + names = tuple(arg1) + if len(names) != len(arg0): + raise ValueError("the number of names must equal the number of generators") + return LieAlgebraFromAssociative(R, A, arg0, names, index_set) + + if isinstance(arg0, str): + names = tuple(arg0.split(',')) + + # Parse the second argument + + if isinstance(arg1, dict): + if isinstance(names, str): + names = tuple(names.split(',')) + # Assume it is some structure coefficients + from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients + return LieAlgebraWithStructureCoefficients(R, arg1, names, index_set) + + # Otherwise it must be either a free or abelian Lie algebra + + if arg1 in ZZ: + if isinstance(arg0, str): + names = arg0 + if names is None: + index_set = range(arg1) + else: + if isinstance(names, str): + names = tuple(names.split(',')) + if arg1 != 1 and len(names) == 1: + names = tuple('{}{}'.format(names[0],i) for i in xrange(arg1)) + if arg1 != len(names): + raise ValueError("the number of names must equal the number of generators") + + if kwds.get("abelian", False): + from sage.algebras.lie_algebras.structure_coefficients import AbelianLieAlgebra + return AbelianLieAlgebra(R, names, index_set) + + rep = kwds.get("representation", "bracket") + if rep == "polynomial": + # Construct the free Lie algebra from polynomials in the + # free (associative unital) algebra + # TODO: Change this to accept an index set once FreeAlgebra accepts one + F = FreeAlgebra(R, names, len(names)) + return LieAlgebraFromAssociative(R, F, F.gens(), names, index_set) + + raise NotImplementedError("the free Lie algebra has not been implemented, see trac ticket #16823") + + # TODO: Should this inherit from IndexedGenerators? + def __init__(self, R, names=None, index_set=None, category=None): + """ + The Lie algebra. + + INPUT: + + - ``R`` -- the base ring + + - ``names`` -- (optional) the names of the generators + + - ``index_set`` -- (optional) the indexing set + + - ``category`` -- the category of the Lie algebra; the default is the + category of Lie algebras over ``R`` + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, abelian=True) + sage: L.category() + Category of finite dimensional lie algebras with basis over Rational Field + """ + category = LieAlgebras(R).or_subcategory(category) + if index_set is None: + if names is None: + raise ValueError("either the names of the generators" + " or the index set must be specified") + index_set = tuple(names) + + if isinstance(index_set, (tuple, list)): + index_set = FiniteEnumeratedSet(index_set) + + #if names is None and index_set.cardinality() < infinity \ + # and all(isinstance(i, str) for i in index_set): + # names = index_set + + self._indices = index_set + Parent.__init__(self, base=R, names=names, category=category) + + def _element_constructor_(self, x): + """ + Convert ``x`` into ``self``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ) + sage: elt = L([x, y]); elt + [x, y] + sage: elt.parent() is L.Hall() + True + """ + if isinstance(x, list) and len(x) == 2: + return self.bracket(self(x[0]), self(x[1])) + if isinstance(x, self.element_class) and x.parent() is self: + return x + if x in self.base_ring(): + if x != 0: + raise ValueError("can only convert the scalar 0 into a Lie algebra element") + return self.zero() + return self.element_class(self, x) + + def __getitem__(self, x): + """ + If `x` is a pair `(a, b)`, return the Lie bracket `(a, b)`. Otherwise + try to return the `x`-th element of ``self``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ) + sage: H = L.Hall() + sage: H[x, [y, x]] + -[x, [x, y]] + """ + if isinstance(x, tuple) and len(x) == 2: + return self(x[0])._bracket_(self(x[1])) + return super(LieAlgebra, self).__getitem__(x) + + def _coerce_map_from_(self, R): + """ + Return ``True`` if there is a coercion from ``R`` into ``self`` and + ``False`` otherwise. + + The things that coerce into ``self`` are: + + - Lie algebras in the same variables over a base with a coercion + map into ``self.base_ring()``. + + - A module which coerces into the base vector space of ``self``. + + TESTS:: + """ + if not isinstance(R, LieAlgebra): + # Should be moved to LieAlgebrasWithBasis somehow since it is a generic coercion + if self.free_module() is not NotImplemented: + return self.free_module().has_coerce_map_from(R) + return False + + # We check if it is a subalgebra of something that can coerce into ``self`` + from sage.algebras.lie_algebras.subalgebra import LieSubalgebra + if isinstance(R, LieSubalgebra) and self.has_coerce_map_from(R._ambient): + return R.ambient_lift + + # Lie algebras in the same indices over any base that coerces in + if R._indices != self._indices: + return False + + return self.base_ring().has_coerce_map_from(R.base_ring()) + + @lazy_attribute + def _ordered_indices(self): + """ + Return the index set of ``self`` in order. + """ + return tuple(sorted(self._indices)) + + def _an_element_(self): + """ + Return an element of ``self``. + """ + return self.sum(self.lie_algebra_generators()) + + @cached_method + def zero(self): + """ + Return the element `0`. + """ + return self.element_class(self, {}) + + zero_element = zero + + @cached_method + def gens(self): + """ + Return a tuple whose entries are the generators for this + object, in some order. + + EXAMPLES:: + """ + return tuple( self.lie_algebra_generators() ) + + def gen(self, i): + """ + The ``i``-th generator of the Lie algebra. + + EXAMPLES:: + """ + G = self.lie_algebra_generators() + return self.element_class(self, G[i]) + + # TODO: find a better place for this method? + def indices(self): + """ + Return the indices of the basis of ``self``. + """ + return self._indices + + # The following methods should belong to LieAlgebrasWithBasis + def _from_dict(self, d, coerce=False, remove_zeros=True): + """ + Construct an element of ``self`` from an ``{index: coefficient}`` + dictionary. + + INPUT: + + - ``d`` -- a dictionary ``{index: coeff}`` where each ``index`` is the + index of a basis element and each ``coeff`` belongs to the + coefficient ring ``self.base_ring()`` + + - ``coerce`` -- a boolean (default: ``False``), whether to coerce the + ``coeff``s to the coefficient ring + + - ``remove_zeros`` -- a boolean (default: ``True``), if some + ``coeff``s may be zero and should therefore be removed + + EXAMPLES:: + + sage: e = SymmetricFunctions(QQ).elementary() + sage: s = SymmetricFunctions(QQ).schur() + sage: a = e([2,1]) + e([1,1,1]); a + e[1, 1, 1] + e[2, 1] + sage: s._from_dict(a.monomial_coefficients()) + s[1, 1, 1] + s[2, 1] + + If the optional argument ``coerce`` is ``True``, then the + coefficients are coerced into the base ring of ``self``:: + + sage: part = Partition([2,1]) + sage: d = {part:1} + sage: a = s._from_dict(d,coerce=True); a + s[2, 1] + sage: a.coefficient(part).parent() + Rational Field + + With ``remove_zeros=True``, zero coefficients are removed:: + + sage: s._from_dict({part:0}) + 0 + + .. WARNING:: + + With ``remove_zeros=False``, it is assumed that no + coefficient of the dictionary is zero. Otherwise, this may + lead to illegal results:: + + sage: list(s._from_dict({part:0}, remove_zeros=False)) + [([2, 1], 0)] + """ + assert isinstance(d, dict) + if coerce: + R = self.base_ring() + d = dict((key, R(coeff)) for key,coeff in d.iteritems()) + if remove_zeros: + d = dict((key, coeff) for key, coeff in d.iteritems() if coeff) + return self.element_class(self, d) + + def monomial(self, i): + """ + Return the monomial indexed by ``i``. + """ + return self.element_class(self, {i: self.base_ring().one()}) + + def term(self, i, c=None): + """ + Return the term indexed by ``i`` with coefficient ``c``. + """ + if c is None: + c = self.base_ring().one() + else: + c = self.base_ring()(c) + return self.element_class(self, {i: c}) + + # TODO: This is essentially an abstract method for Lie algebras without + # a distinguished basis + def lie_algebra_generators(self): + """ + Return the Lie algebra generators of ``self``. + """ + return Family(self._indices, self.monomial, name="monomial map") + +class FinitelyGeneratedLieAlgebra(LieAlgebra): + """ + An fintely generated Lie algebra. + + INPUT: + + - ``R`` -- the base ring + + - ``names`` -- the names of the generators + + - ``index_set`` -- the index set of the generators + + - ``category`` -- the category of the Lie algebra + """ + def __init__(self, R, names=None, index_set=None, category=None): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, abelian=True) + sage: L.category() + Category of finite dimensional lie algebras with basis over Rational Field + """ + LieAlgebra.__init__(self, R, names, index_set, category) + self.__ngens = len(self._indices) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: F. = LieAlgebra(QQ, {('x','y'): {'x': 1}}) + sage: F + Lie algebra on 2 generators (x, y) over Rational Field + """ + if self.__ngens == 1: + return "Lie algebra on the generator {0} over {1}".format( + self.gens()[0], self.base_ring()) + return "Lie algebra on {0} generators {1} over {2}".format( + self.__ngens, self.gens(), self.base_ring()) + +class InfinitelyGeneratedLieAlgebra(LieAlgebra): + r""" + An infinitely generated Lie algebra. + """ + def _an_element_(self): + """ + Return an element of ``self``. + """ + return self.lie_algebra_generators()[self._indices.an_element()] + + def dimension(self): + r""" + Return the dimension of ``self``, which is `\infty`. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, oo) + sage: L.dimension() + +Infinity + """ + return infinity + +class LieAlgebraFromAssociative(LieAlgebra): + """ + A Lie algebra whose elements are from an associative algebra and whose + bracket is the commutator. + + .. WARNING:: + + The returned universal enveloping algebra is too large in general. + To fix this, we need subalgebras implemented. + + .. TODO:: + + Return the subalgebra generated by the basis + elements of ``self`` for the universal enveloping algebra. + + EXAMPLES: + + We create a simple example with a commutative algebra as the base algebra. + Note that the bracket of everything will be 0:: + + sage: R. = PolynomialRing(QQ) + sage: L. = LieAlgebra(QQ, R) + sage: L.bracket(x, y) + 0 + + Next we use a free algebra and do some simple computations:: + + sage: R. = FreeAlgebra(QQ, 2) + sage: L. = LieAlgebra(QQ, R) + sage: x-y + a - b + sage: L.bracket(x-y, x) + a*b - b*a + sage: L.bracket(x-y, L.bracket(x,y)) + a^2*b - 2*a*b*a + a*b^2 + b*a^2 - 2*b*a*b + b^2*a + + We can also use a subset of the generators to use in our Lie algebra:: + + sage: R. = FreeAlgebra(QQ, 3) + sage: L. = LieAlgebra(QQ, R, [a,b]) + + Now for a more complicated example using the group ring of `S_3` as our + base algebra:: + + sage: G = SymmetricGroup(3) + sage: S = GroupAlgebra(G, QQ) + sage: L. = LieAlgebra(QQ, S) + sage: L.bracket(x, y) + (2,3) - (1,3) + sage: L.bracket(x, y-x) + (2,3) - (1,3) + sage: L.bracket(L.bracket(x, y), y) + 2*(1,2,3) - 2*(1,3,2) + sage: L.bracket(x, L.bracket(x, y)) + (2,3) - 2*(1,2) + (1,3) + sage: L.bracket(x, L.bracket(L.bracket(x, y), y)) + 0 + + Here is an example using matrices:: + + sage: MS = MatrixSpace(QQ,2) + sage: m1 = MS([[0, -1], [1, 0]]) + sage: m2 = MS([[-1, 4], [3, 2]]) + sage: L. = LieAlgebra(QQ, MS, [m1, m2]) + sage: x + [ 0 -1] + [ 1 0] + sage: y + [-1 4] + [ 3 2] + sage: L.bracket(x,y) + [-7 -3] + [-3 7] + sage: L.bracket(y,y) + [0 0] + [0 0] + sage: L.bracket(y,x) + [ 7 3] + [ 3 -7] + sage: L.bracket(x, L.bracket(y,x)) + [-6 14] + [14 6] + + If we use a subset of the generators to construct our Lie algebra, + the result of :meth:`universal_enveloping_algebra()` can be too large:: + + sage: R. = FreeAlgebra(QQ, 3) + sage: L = LieAlgebra(QQ, R, [a,b]) + sage: L.universal_enveloping_algebra() is R + True + """ + @staticmethod + def __classcall_private__(cls, R, A, gens, names=None, index_set=None, category=None): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: G = SymmetricGroup(3) + sage: S = GroupAlgebra(G, QQ) + sage: L = LieAlgebra(QQ, S, 'x,y') + sage: L2 = LieAlgebra(QQ, S, [G((1,2,3)), G((1,2))], 'x,y') + sage: L is L2 + True + """ + gens = map(A, gens) + try: + # Try to make things, such as matrices, immutable (since we need to hash them) + gens = map(lambda x: x.set_immutable(), gens) + except AttributeError: + pass + + if names is not None: + names = tuple(names) + + return super(LieAlgebraFromAssociative, cls).__classcall__(cls, + R, A, tuple(gens), names, index_set) + + def __init__(self, R, assoc, gens, names=None, index_set=None, category=None): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: G = SymmetricGroup(3) + sage: S = GroupAlgebra(G, QQ) + sage: L. = LieAlgebra(QQ, S) + sage: TestSuite(L).run() + """ + self._assoc = assoc + # TODO: We should strip axioms from the category of the base ring, + # such as FiniteDimensional, WithBasis + LieAlgebra.__init__(self, R, names, index_set, category) + # We register the coercion here since the UEA already exists + self.lift.register_as_coercion() + if isinstance(gens, dict): + F = Family(self._indices, lambda i: gens[i]) + else: # TODO: Implement a version for infinite set of generators? + F = Family({self._indices[i]: v for i,v in enumerate(gens)}) + self._gens = F + + def _repr_option(self, key): + """ + Metadata about the :meth:`_repr_` output. + + See :meth:`sage.structure.parent._repr_option` for details. + + EXAMPLES:: + + sage: MS = MatrixSpace(QQ,2) + sage: L. = LieAlgebra(QQ, MS, [MS.one()]) + sage: L._repr_option('element_ascii_art') + True + """ + return self._assoc._repr_option(key) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: G = SymmetricGroup(3) + sage: S = GroupAlgebra(G, QQ) + sage: L. = LieAlgebra(QQ, S) + """ + return "Lie algebra from {} generated by {}".format( + self._assoc, tuple(self._gens)) + + def _element_constructor_(self, x): + """ + Convert ``x`` into ``self``. + + EXAMPLES:: + + sage: G = SymmetricGroup(3) + sage: S = GroupAlgebra(G, QQ) + sage: L. = LieAlgebra(QQ, S) + sage: elt = L(x - y); elt + -(1,2) + (1,2,3) + sage: elt.parent() is L + True + """ + if isinstance(x, LieAlgebraElement) and x.parent() is self: + return x + return self.element_class(self, self._assoc(x)) + + def _construct_UEA(self): + """ + Construct the universal enveloping algebra of ``self``. + + EXAMPLES:: + + sage: G = SymmetricGroup(3) + sage: S = GroupAlgebra(G, QQ) + sage: L. = LieAlgebra(QQ, S) + sage: L._construct_UEA() is S + True + """ + return self._assoc + + universal_enveloping_algebra = _construct_UEA + + def lie_algebra_generators(self): + """ + Return the Lie algebra generators of ``self``. + + EXAMPLES:: + + sage: G = SymmetricGroup(3) + sage: S = GroupAlgebra(G, QQ) + sage: L. = LieAlgebra(QQ, S) + """ + return self._gens + + def monomial(self, i): + """ + Return the monomial indexed by ``i``. + """ + if i not in self._indices: + raise ValueError("not an index") + return LieAlgebra.monomial(self, self._gens[i]) + + def term(self, i, c=None): + """ + Return the term indexed by ``i`` with coefficient ``c``. + """ + if i not in self._indices: + raise ValueError("not an index") + return LieAlgebra.term(self, self._gens[i], c) + + @cached_method + def zero_element(self): + """ + Return `0`. + + EXAMPLES:: + + sage: G = SymmetricGroup(3) + sage: S = GroupAlgebra(G, QQ) + sage: L. = LieAlgebra(QQ, S) + sage: L.zero_element() + 0 + """ + return self.element_class(self, self._assoc.zero()) + + zero = zero_element + + def is_abelian(self): + """ + Return ``True`` if ``self`` is abelian. + + EXAMPLES:: + + sage: R = FreeAlgebra(QQ, 2, 'x,y') + sage: L. = LieAlgebra(QQ, R) + sage: L.is_abelian() + False + sage: R = PolynomialRing(QQ, 'x,y') + sage: L. = LieAlgebra(QQ, R) + sage: L.is_abelian() + True + + An example with a Lie algebra from the group algebra:: + + sage: G = SymmetricGroup(3) + sage: S = GroupAlgebra(G, QQ) + sage: L. = LieAlgebra(QQ, S) + sage: L.is_abelian() + False + + Now we construct a Lie algebra from commuting elements in the group + algebra:: + + sage: G = SymmetricGroup(5) + sage: S = GroupAlgebra(G, QQ) + sage: gens = [G((1, 2)), G((3, 4))] + sage: L. = LieAlgebra(QQ, gens, S) + sage: L.is_abelian() + True + """ + if self._assoc.is_commutative(): + return True + return super(LieAlgebraFromAssociative, self).is_abelian() + + class Element(LieAlgebraElementWrapper): + def _bracket_(self, rhs): + """ + Return the bracket ``[self, rhs]``. + + EXAMPLES:: + + sage: R = FreeAlgebra(QQ, 3, 'x,y,z') + sage: L. = LieAlgebra(QQ, R) + sage: L.bracket(x, y) + x*y - y*x + + sage: G = SymmetricGroup(3) + sage: S = GroupAlgebra(G, QQ) + sage: L. = LieAlgebra(QQ, S) + sage: L.bracket(x, y) + (2,3) - (1,3) + + sage: L = LieAlgebra(QQ, cartan_type=['A',2], representation='matrix') + sage: L.bracket(L.gen(0), L.gen(1)) + [0 0 1] + [0 0 0] + [0 0 0] + """ + return self.__class__(self.parent(), self.value*rhs.value - rhs.value*self.value) + + def lift(self): + """ + Lift ``self`` to the universal enveloping algebra. + + EXAMPLES:: + + sage: R = FreeAlgebra(QQ, 3, 'x,y,z') + sage: L. = LieAlgebra(QQ, R) + sage: x.lift() + x + sage: x.lift().parent() + Free Algebra on 3 generators (x, y, z) over Rational Field + """ + return self.value + diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py new file mode 100644 index 00000000000..5a60606df41 --- /dev/null +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -0,0 +1,485 @@ +""" +Lie Algebra Elements + +AUTHORS: + +- Travis Scrimshaw (2005-05-04): Initial implementation +""" + +#***************************************************************************** +# Copyright (C) 2013 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# This code is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# See the GNU General Public License for more details; the full text +# is available at: +# +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.misc.abstract_method import abstract_method +from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall +from sage.misc.misc import repr_lincomb +from copy import copy +from functools import total_ordering +from sage.structure.element import ModuleElement, RingElement, coerce_binop +from sage.structure.sage_object import SageObject +from sage.combinat.free_module import CombinatorialFreeModuleElement +from sage.structure.element_wrapper import ElementWrapper + +@total_ordering +class LieGenerator(SageObject): # Does this need to be SageObject? + """ + A wrapper around an object so it can compare with :class:`LieBracket`. + """ + __metaclass__ = ClasscallMetaclass + + @staticmethod + def __classcall_private__(cls, name): + """ + Return ``name`` if it is a :class:`LieGenerator`, otherwise construct + a new object. + + EXAMPLES:: + """ + if isinstance(name, LieGenerator): + return name + return typecall(cls, name) + + def __init__(self, name): + """ + Initalize ``self``. + + EXAMPLES:: + """ + self._name = name + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + """ + return self._name + + def __eq__(self, rhs): + """ + Compare equals. + + EXAMPLES:: + """ + return isinstance(rhs, LieGenerator) and self._name == rhs._name + + def __lt__(self, rhs): + """ + Compare less than. + + EXAMPLES:: + """ + if isinstance(rhs, LieGenerator): + return self._name < rhs._name + if isinstance(rhs, LieBracket): + return not rhs.__lt__(self) # Clearly self != rhs + return False + + def _im_gens_(self, codomain, im_gens, names): + """ + Return the image of ``self``. + + EXAMPLES:: + """ + x = im_gens[names.index(self._name)] + return im_gens[names.index(self._name)] + + def to_word(self): + """ + Return ``self`` as a word in the variable names. + + EXAMPLES:: + """ + return [self._name] + +@total_ordering +class LieBracket(SageObject): # Does this need to be SageObject? + """ + A Lie bracket. This is the building blocks for Lie algebra elements. + """ + def __init__(self, l, r): + """ + Initialize ``self``. + + EXAMPLES:: + """ + self._left = l + self._right = r + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + """ + return "[{!s}, {!s}]".format(self._left, self._right) + + def _latex_(self): + r""" + Return a `\LaTeX` representation of ``self``. + + EXAMPLES:: + """ + from sage.misc.latex import latex + return "\\left[" + latex(self._left) + "," + latex(self._right) + "\\right]" + + def __getitem__(self, i): + r""" + Return the `i`-th item of ``self``. + + EXAMPLES:: + """ + if i == 0: + return self._left + if i == 1: + return self._right + raise IndexError("i must be either 0 or 1") + + def __eq__(self, rhs): + """ + Check equality. + + EXAMPLES:: + """ + if isinstance(rhs, list): + if len(rhs) != 2: + return False + return self._left == rhs[0] and self._right == rhs[1] + + if not isinstance(rhs, LieBracket): + return False + return self._left == rhs._left and self._right == rhs._right + + def __lt__(self, rhs): + """ + Check less than. + + EXAMPLES:: + """ + if not isinstance(rhs, LieBracket): + return False + if self._left < rhs._left: + return True + elif self._left == rhs._left: + return self._right < rhs._right + return False + + def __hash__(self): + """ + Return the hash value of ``self``. + + EXAMPLES:: + """ + return hash((self._left, self._right)) + + def _im_gens_(self, codomain, im_gens, names): + """ + Return the image of ``self``. + + EXAMPLES:: + """ + return codomain.bracket(self._left._im_gens_(codomain, im_gens, names), + self._right._im_gens_(codomain, im_gens, names)) + + def lift(self, UEA_gens_dict): + """ + Lift ``self`` to the universal enveloping algebra. + + EXAMPLES:: + """ + if isinstance(self._left, LieBracket): + l = self._left.lift(UEA_gens_dict) + else: + l = UEA._gens_dict[self._left] + + if isinstance(self._right, LieBracket): + r = self._right.lift(UEA_gens_dict) + else: + r = UEA_gens_dict[self._right] + + return l*r - r*l + + def to_word(self): + """ + Return ``self`` as a word expressed in the variable names. + + EXAMPLES:: + """ + return self._left.to_word() + self._right.to_word() + +# TODO: Have the other classes inherit from this? +# TODO: Should this be a mixin class (or moved to the category)? +class LieAlgebraElement_generic(ModuleElement): + """ + Generic methods for all Lie algebra elements. + """ + def __mul__(self, other): + """ + If we are multiplying two non-zero elements, automatically + lift up to the universal enveloping algebra. + + EXAMPLES:: + """ + if self == 0 or other == 0: + return self.parent().zero() + # Otherwise we lift to the UEA + return self.lift() * other + +# TODO: Factor out parts of CombinatorialFreeModuleElement into a SparseFreeModuleElement? +# TODO: Do we want a dense version? +class LieAlgebraElement(CombinatorialFreeModuleElement): + """ + A Lie algebra element. + """ + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + """ + if not self._monomial_coefficients: + return '0' + return repr_lincomb(self.list()) + + # Default implementation + def _latex_monomial(self, m): + """ + Return a `\LaTeX` representation of the monomial ``m``. + + EXAMPLES:: + """ + from sage.misc.latex import latex + return latex(m) + + def _latex_(self): + r""" + Return a `\LaTeX` representation of ``self``. + + EXAMPLES:: + """ + if not self._monomial_coefficients: + return '0' + return repr_lincomb(self.list(), repr_monomial=self._latex_monomial, is_latex=True) + + def _mul_(self, y): + """ + If we are multiplying two non-zero elements, automatically + lift up to the universal enveloping algebra. + + EXAMPLES:: + """ + if self == 0 or y == 0: + return self.parent().zero() + # Otherwise we lift to the UEA + return self.lift() * y + + def _im_gens_(self, codomain, im_gens): + """ + Return the image of ``self`` in ``codomain`` under the map that sends + the images of the generators of the parent of ``self`` to the + tuple of elements of ``im_gens``. + + EXAMPLES:: + """ + s = codomain.zero() + if not self: # If we are 0 + return s + names = self.parent().variable_names() + return codomain.sum(c * t._im_gens_(codomain, im_gens, names) + for t, c in self._monomial_coefficients.iteritems()) + + # TODO: Move to the category/lift morphism + def lift(self): + """ + Lift ``self`` to the universal enveloping algebra. + + EXAMPLES:: + """ + UEA = self.parent().universal_enveloping_algebra() + gen_dict = UEA.gens_dict() + s = UEA.zero() + if not self: + return s + for t, c in self._monomial_coefficients.iteritems(): + if isinstance(t, LieBracket): + s += c * t.lift(gen_dict) + else: + s += c * gen_dict[t._name] + return s + + def is_constant(self): + """ + Check if ``self`` is a constant (i.e. zero). + + EXAMPLES:: + """ + return not self._monomial_coefficients + + def dict(self): + """ + Return ``self`` as a dictionary mapping monomials to coefficients. + + EXAMPLES:: + """ + return copy(self._monomial_coefficients) + + def list(self): + """ + Return ``self`` as a list of pairs ``(m, c)`` where ``m`` is a + monomial and ``c`` is the coefficient. + + EXAMPLES:: + """ + return sorted(self._monomial_coefficients.items()) + +class LieAlgebraElementWrapper(ElementWrapper): + """ + Wrap an element as a Lie algebra element. + """ + def __eq__(self, rhs): + """ + Check equality. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, cartan_type=['A',3], representation='matrix') + sage: L.bracket(L.e(2), L.e(1)) == -L.bracket(L.e(1), L.e(2)) + True + """ + if not isinstance(rhs, LieAlgebraElementWrapper): + return self.value == 0 and rhs == 0 + return self.parent() == rhs.parent() and self.value == rhs.value + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, cartan_type=['A',2], representation='matrix') + sage: L.gen(0) + [0 1 0] + [0 0 0] + [0 0 0] + """ + return repr(self.value) + + def _latex_(self): + r""" + Return a `\LaTeX` representation of ``self``. + + EXAMPLES:: + + sage: R = FreeAlgebra(QQ, 3, 'x,y,z') + sage: L. = LieAlgebra(QQ, R) + sage: latex(x + y) + x + y + """ + from sage.misc.latex import latex + return latex(self.value) + + def _add_(self, rhs): + """ + Add ``self`` and ``rhs``. + + EXAMPLES:: + + sage: R = FreeAlgebra(QQ, 3, 'x,y,z') + sage: L. = LieAlgebra(QQ, R) + sage: x + y + x + y + """ + return self.__class__(self.parent(), self.value + rhs.value) + + def _sub_(self, rhs): + """ + Subtract ``self`` and ``rhs``. + + EXAMPLES:: + + sage: R = FreeAlgebra(QQ, 3, 'x,y,z') + sage: L. = LieAlgebra(QQ, R) + sage: x - y + x - y + """ + return self.__class__(self.parent(), self.value - rhs.value) + + # This seems to work with 2 underscores and I don't understand why... + def __mul__(self, x): + """ + If we are multiplying two non-zero elements, automatically + lift up to the universal enveloping algebra. + + EXAMPLES:: + + sage: G = SymmetricGroup(3) + sage: S = GroupAlgebra(G, QQ) + sage: L. = LieAlgebra(QQ, S) + sage: x*y - y*x + (2,3) - (1,3) + """ + if self.value == 0 or x == 0: + return self.parent().zero() + # Otherwise we lift to the UEA + return self.lift() * x + + def _acted_upon_(self, scalar, self_on_left=False): + """ + Return the action of a scalar on ``self``. + + EXAMPLES:: + """ + # This was copied and IDK if it still applies: + # 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. + if hasattr( scalar, 'parent' ) and scalar.parent() != self.base_ring(): + # Temporary needed by coercion (see Polynomial/FractionField tests). + if self.base_ring().has_coerce_map_from(scalar.parent()): + scalar = self.base_ring()( scalar ) + else: + return None + if self_on_left: + return self.__class__(self.parent(), self.value * scalar) + return self.__class__(self.parent(), scalar * self.value) + + def __neg__(self): + """ + Return the negation of ``self``. + + EXAMPLES:: + + sage: R = FreeAlgebra(QQ, 3, 'x,y,z') + sage: L. = LieAlgebra(QQ, R) + sage: -x + -x + """ + return self.__class__(self.parent(), -self.value) + + def __getitem__(self, i): + """ + Redirect the ``__getitem__()`` to the wrapped element. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, cartan_type=['A',2], representation='matrix') + sage: m = L.e(0) + sage: m[0,0] + 0 + sage: m[0][1] + 1 + """ + return self.value.__getitem__(i) + diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py new file mode 100644 index 00000000000..6220a3bc853 --- /dev/null +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -0,0 +1,570 @@ +""" +Lie Algebras Given By Structure Coefficients + +AUTHORS: + +- Travis Scrimshaw (2013-05-03): Initial version +""" + +#***************************************************************************** +# Copyright (C) 2013 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# This code is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# See the GNU General Public License for more details; the full text +# is available at: +# +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from copy import copy +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.misc import repr_lincomb +from sage.structure.indexed_generators import IndexedGenerators +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.element_wrapper import ElementWrapper + +from sage.categories.algebras import Algebras +from sage.categories.lie_algebras import LieAlgebras +from sage.categories.finite_dimensional_lie_algebras_with_basis import FiniteDimensionalLieAlgebrasWithBasis + +from sage.algebras.free_algebra import FreeAlgebra +from sage.algebras.lie_algebras.lie_algebra_element import (LieGenerator, + LieBracket, LieAlgebraElement) +from sage.algebras.lie_algebras.lie_algebra import FinitelyGeneratedLieAlgebra +from sage.algebras.lie_algebras.subalgebra import LieSubalgebra +from sage.algebras.lie_algebras.ideal import LieAlgebraIdeal +from sage.algebras.lie_algebras.quotient import QuotientLieAlgebra +from sage.rings.all import ZZ +from sage.rings.ring import Ring +from sage.rings.integer import Integer +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.infinity import infinity +from sage.matrix.matrix_space import MatrixSpace +from sage.matrix.constructor import matrix +from sage.modules.free_module_element import vector +from sage.modules.free_module import FreeModule, span +from sage.sets.family import Family, AbstractFamily + +# TODO: Much of this could be moved to (FiniteDimensional)LieAlgebrasWithBasis +class LieAlgebraWithStructureCoefficients(FinitelyGeneratedLieAlgebra, IndexedGenerators): + r""" + A Lie algebra with a set of specified structure coefficients. + + The structure coefficients are specified as a dictionary whose keys are + pairs of generators and values are dictionaries of generators mapped + to coefficients. + + EXAMPLES: + + We create the Lie algebra of `\QQ^3` under the Lie bracket defined + by `\times` (cross-product):: + + sage: L = LieAlgebra(QQ, 'x,y,z', {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) + sage: (x,y,z) = L.gens() + sage: L.bracket(x, y) + z + sage: L.bracket(y, x) + -z + """ + @staticmethod + def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, **kwds): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, 'x,y', {('x','y'):{'x':1}}) + sage: L2 = LieAlgebra(QQ, 'x,y', {('y','x'):{'x':-1}}) + sage: L is L2 + True + """ + s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff(s_coeff) + if len(s_coeff) == 0: + return AbelianLieAlgebra(R, names, index_set, **kwds) + + if names is None: + if index_set is None: + raise ValueError("either the names or the index set must be specified") + if len(index_set) <= 1: + return AbelianLieAlgebra(R, names, index_set, **kwds) + elif len(names) <= 1: + return AbelianLieAlgebra(R, names, index_set, **kwds) + + return super(LieAlgebraWithStructureCoefficients, cls).__classcall__( + cls, R, s_coeff, tuple(names), index_set, **kwds) + + @staticmethod + def _standardize_s_coeff(s_coeff): + """ + Helper function to standardize ``s_coeff`` into the appropriate tuple + of tuples. Strips items with coefficients of 0 and duplicate entries. + This does not check the Jacobi relation (nor antisymmetry if the + cardinality is infinite). + """ + # Try to handle infinite basis (once/if supported) + if isinstance(s_coeff, AbstractFamily) and s_coeff.cardinality() == infinity: + return s_coeff + + sc = {} + # Make sure the first gen is smaller than the second in each key + for k in s_coeff.keys(): + v = s_coeff[k] + if isinstance(v, dict): + v = v.items() + + if k[0] > k[1]: + key = LieBracket(k[1], k[0]) + vals = tuple((g, -val) for g, val in v if val != 0) + else: + key = LieBracket(*k) + vals = tuple((g, val) for g, val in v if val != 0) + + if key in sc.keys() and sorted(sc[key]) != sorted(vals): + raise ValueError("non-equal brackets") + + if len(vals) > 0: + sc[key] = vals + return Family(sc) + + def __init__(self, R, s_coeff, names, index_set, category=None, prefix='', + bracket=False, latex_bracket=False, **kwds): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, 'x,y', {('x','y'):{'x':1}}) + sage: TestSuite(L).run() + """ + cat = LieAlgebras(R).WithBasis().or_subcategory(category) + FinitelyGeneratedLieAlgebra.__init__(self, R, names, index_set, cat) + IndexedGenerators.__init__(self, self._indices, prefix=prefix, bracket=bracket, + latex_bracket=latex_bracket, **kwds) + + # Transform the values in the structure coefficients to elements + self._s_coeff = Family({k: self._from_dict(dict(s_coeff[k])) for k in s_coeff.keys()}) + + def basis(self): + """ + Return the basis of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, 'x,y', {('x','y'):{'x':1}}) + sage: L.basis() + Finite family {'y': y, 'x': x} + """ + return Family({i: self.monomial(i) for i in self._indices}) + + def structure_coefficients(self): + """ + Return the dictonary of structure coefficients of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, 'x,y', {('x','y'):{'x':1}}) + sage: L.structure_coefficients() + Finite family {[x, y]: x} + """ + return self._s_coeff + + def dimension(self): + """ + Return the dimension of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, 'x,y', {('x','y'):{'x':1}}) + sage: L.dimension() + 2 + """ + return self.basis().cardinality() + + # Move to FiniteDimensionalLieAlgebrasWithBasis category? + def bracket_on_basis(self, x, y): + """ + Return the Lie bracket of ``[self, y]``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) + sage: L.bracket(x, y) # indirect doctest + z + sage: L.bracket(y, x) + -z + sage: L.bracket(x + y - z, x - y + z) + -2*y - 2*z + """ + comp = self._print_options['generator_cmp'] + ordered = True + if comp(x, y) > 0: # x > y + x,y = y,x + ordered = False + b = LieBracket(x, y) + try: + val = self._s_coeff[b] + except KeyError: + return self.zero() + if ordered: + return val + return -val + + def free_module(self, sparse=True): + """ + Return ``self`` as a free module. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) + sage: L.free_module() + Sparse vector space of dimension 3 over Rational Field + """ + return FreeModule(self.base_ring(), self.dimension(), sparse=sparse) + + def subalgebra(self, gens, names=None, index_set=None, category=None): + """ + Return the subalgebra of ``self`` generated by ``gens``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) + sage: L.subalgebra([x+y]) + Subalgebra generated of Lie algebra on 3 generators (x, y, z) over Rational Field with basis: + (x + y,) + sage: L.subalgebra([x+y, y+z]) + Lie algebra on 3 generators (x, y, z) over Rational Field + + TESTS:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) + sage: L.subalgebra([x+y, x+y]) + Subalgebra generated of Lie algebra on 3 generators (x, y, z) over Rational Field with basis: + (x + y,) + """ + B, s_coeff = LieSubalgebraWithStructureCoefficients._compute_basis_structure_coeff(self, gens) + if len(B) == self.dimension(): + return self + return LieSubalgebraWithStructureCoefficients(self, B, s_coeff, names, index_set, category) + + # TODO: + # - Make a centralizer of a set version + # - Move to FiniteDimensionalLieAlgebrasWithBasis once implemented + # - Return a subalgebra + #@cached_method + #def center(self): + # """ + # Return a list of elements which correspond to a basis for the center + # of ``self``. + # """ + # R = self.base_ring() + # B = self.basis() + # K = list(B.keys()) + # k = len(K) + # d = {} + # for a,i in enumerate(K): + # Bi = B[i] + # for b,j in enumerate(K): + # Bj = B[j] + # for m,c in Bi.bracket(Bj): + # d[(a, K.index(m)+k*b)] = c + # m = Matrix(R, d, nrows=k, ncols=k*k, sparse=True) + # from_vector = lambda x: self.sum_of_terms( ((K[i], c) for i,c in x.iteritems()), + # distinct=True) + # return tuple(map( from_vector, m.kernel().basis() )) + # Dense version + # R = self.base_ring() + # B = self.basis() + # K = list(B.keys()) + # eqns = [[] for dummy in range(k)] + # for a,i in enumerate(K): + # for b,j in enumerate(K): + # v = B[i]*B[j] - B[j]*B[i] + # eqns[a].extend([v[k] for k in K]) + # m = Matrix(R, eqns) + # from_vector = lambda x: self.sum_of_terms(((K[i], c) for i,c in x.iteritems()), + # distinct=True) + # return tuple(map( from_vector, m.kernel().basis() )) + + class Element(LieAlgebraElement): + """ + An element of a Lie algebra given by structure coefficients. + """ + def _repr_(self): + r""" + Return a string representation of ``self``. + """ + prefix = self.parent()._print_options['prefix'] + if self.parent()._names is not None and not prefix: + return LieAlgebraElement._repr_(self) + return repr_lincomb(self._sorted_items_for_printing(), + scalar_mult=self.parent()._print_options['scalar_mult'], + repr_monomial = self.parent()._repr_generator, + strip_one = True) + + def _latex_(self): + r""" + Return a `\LaTeX` representation of ``self``. + """ + prefix = self.parent()._print_options['prefix'] + if self.parent()._names is not None and not prefix: + return LieAlgebraElement._latex_(self) + return repr_lincomb(self._sorted_items_for_printing(), + scalar_mult = self.parent()._print_options['scalar_mult'], + latex_scalar_mult = self.parent()._print_options['latex_scalar_mult'], + repr_monomial = self.parent()._latex_generator, + is_latex=True, strip_one = True) + + def _bracket_(self, y): + """ + Return the Lie bracket ``[self, y]``. + """ + P = self.parent() + return P.sum(cx * cy * P.bracket_on_basis(mx, my) + for mx,cx in self for my,cy in y) + + def to_vector(self): + """ + Return ``self`` as a vector. + """ + V = self.parent().free_module() + return V([self[k] for k in self.parent()._ordered_indices]) + +class LieSubalgebraWithStructureCoefficients(LieSubalgebra): + """ + A Lie subalgebra of a Lie algebra given by structure coefficients. + """ + @staticmethod + def _compute_basis_structure_coeff(A, gens): + """ + Compute an echonalized basis of ``self`` and the corresponding + structure coefficients. + + INPUT: + + - ``A`` -- the ambient Lie algebra + - ``gens`` -- a set of generators as elements in ``A`` + """ + I = A._ordered_indices + R = A.base_ring() + M = A.free_module() + zero = A.zero() + + # Setup the current basis matrix + cur = matrix(R, map(lambda x: x.to_vector(), gens), sparse=M.is_sparse()) + cur.echelonize() + # Remove all zero rows from cur + cur = cur.delete_rows([i for i,row in enumerate(cur.rows()) if row.is_zero()]) + + added = True + while added: + added = False + cur.echelonize() + basis = tuple(A._from_dict({I[i]: c for i,c in row.iteritems()}) for row in cur) + s_coeff = {} + + for i in range(len(basis)): + for j in range(i+1, len(basis)): + b = basis[i].bracket(basis[j]) + if b == zero: + # There is a dependence and no resulting structure + # coefficients, so we don't have to do anything more + continue + + bv = b.to_vector() + dep = M.linear_dependence(cur.rows() + [bv]) + if dep: + # The dependency is the first in the sequence, there's only + # one because the original set is linearly independent + dep = dep[0] + # Rewrite as a linear combination of the current basis + s = -dep[-1] # Guaranteed to be non-zero + d = {k: R(c*~s) for k,c in enumerate(dep[:-1]) if c != 0} + s_coeff[LieBracket(i,j)] = d + else: + added = True + cur = cur.stack(bv) + return (basis, Family(s_coeff)) + + def __init__(self, ambient, basis, s_coeff, names=None, index_set=None, category=None): + r""" + Initialize ``self``. + """ + self._s_coeff = s_coeff # TODO: convert the values to elements of ``self`` + # TODO: make sure the category is in subobjects? + LieSubalgebra.__init__(self, ambient, basis, names, index_set, category) + + def _repr_(self): + """ + Return a string representation of ``self``. + """ + return "Subalgebra generated of {} with basis:\n{}".format(self._ambient, self.gens()) + + def basis(self): + """ + Return a basis of ``self``. + """ + I = self._indices + B = self._gens + return Family({ I[i]: b for i,b in enumerate(B) }) + + def subalgebra(self, gens, names=None, index_set=None, category=None): + """ + Return the subalgebra of ``self`` generated by ``gens``. + """ + gens = map(lambda x: x.value, gens) + B, s_coeff = LieSubalgebraWithStructureCoefficients._compute_basis_structure_coeff(self._ambient, gens) + assert len(B) != self._ambient.dimension() + return LieSubalgebraWithStructureCoefficients(self._ambient, B, s_coeff, + names, index_set, category) + +class LieAlgebraIdealWithStructureCoefficients(LieAlgebraIdeal, + LieSubalgebraWithStructureCoefficients): + """ + A Lie algebra ideal of a Lie algebra given by structure coefficients. + """ + def reduce(self, y): + """ + Return ``y`` modulo ``self``. + """ + M = self._ambient.free_module() + I = M.subspace(map(lambda x: x.to_vector(), self._gens)) + R = I.complement() + ld = M.linear_dependence(R.basis() + I.basis() + [y.to_vector()])[0] + normalizer = -ld[-1] + coeffs = map(lambda x: x / normalizer, ld[:len(R)]) + vec = M(R.linear_combination_of_basis(coeffs)) + return self._ambient(vec) + +# This should either not inherit from QuotientLieAlgebra or refactor out common code +# This should inherit from LieAlgebraWithStructureCoefficients +class QuotientLieAlgebraWithStructureCoefficients(QuotientLieAlgebra): + """ + A quotient Lie algebra of a Lie algebra given by structure coefficients. + + INPUT: + + - ``I`` -- an ideal of a Lie algebra given by structure coefficients + - ``names`` -- the names of the generators + - ``index_set`` -- the indexing set for the generators + - ``category`` -- the category of the quotient Lie algebra + """ + def __init__(self, lie, I, names=None, index_set=None, category=None): + """ + Initialize ``self``. + """ + R = lie.base_ring() + #cat = LieAlgebras(R).FiniteDimensional().WithBasis() + cat = FiniteDimensionalLieAlgebrasWithBasis(R)#.Quotients() + QuotientLieAlgebra.__init__(self, lie, I, names, index_set, cat) + + # Construct the structure coefficients + M = lie.free_module() + IM = M.subspace(map(lambda x: x.to_vector(), I._gens)) + RM = IM.complement() + B = RM.basis() + IM.basis() + dim = len(RM) + self._s_coeff = {} + for i,kl,zl in enumerate(gens): + for kr,zr in gens[i+1:]: + b = LieBracket(zl, zr) + ld = M.linear_dependence(B + [y.to_vector()])[0] + normalizer = -ld[-1] + self._s_coeffs[b] = {indices[j]: val / normalizer + for j,val in enumerate(ld[:dim])} + + Element = LieAlgebraElement + +class AbelianLieAlgebra(LieAlgebraWithStructureCoefficients): + r""" + An abelian Lie algebra. + + A Lie algebra `\mathfrak{g}` is abelian if `[x, y] = 0` for all + `x, y \in \mathfrak{g}`. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, abelian=True) + sage: L.bracket(x, y) + 0 + """ + def __init__(self, R, names=None, index_set=None, **kwds): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) + sage: TestSuite(L).run() + """ + LieAlgebraWithStructureCoefficients.__init__(self, R, Family({}), names, index_set, **kwds) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: LieAlgebra(QQ, 3, 'x', abelian=True) + Abelian Lie algebra on 3 generators (x0, x1, x2) over Rational Field + """ + gens = self.lie_algebra_generators() + if gens.cardinality() == 1: + return "Abelian Lie algebra on generator {} over {}".format(tuple(gens)[0], self.base_ring()) + return "Abelian Lie algebra on {} generators {} over {}".format( + gens.cardinality(), tuple(gens), self.base_ring()) + + def _construct_UEA(self): + """ + Construct the universal enveloping algebra of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) + sage: L._construct_UEA() + Multivariate Polynomial Ring in x0, x1, x2 over Rational Field + """ + return PolynomialRing(self.base_ring(), self.variable_names()) + + def is_abelian(self): + """ + Return ``True`` since this is an abelian Lie algebra. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) + sage: L.is_abelian() + True + """ + return True + + def bracket_on_basis(self, x, y): + """ + Return the Lie bracket of basis elements indexed by ``x`` and ``y``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, abelian=True) + sage: L.bracket_on_basis(x.leading_support(), y.leading_support()) + 0 + """ + return self.zero() + + class Element(LieAlgebraElement): + def _bracket_(self, y): + """ + Return the Lie bracket ``[self, y]``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, abelian=True) + sage: L.bracket(x, y) + 0 + """ + return self.parent().zero() diff --git a/src/sage/algebras/lie_algebras/virasoro.py b/src/sage/algebras/lie_algebras/virasoro.py new file mode 100644 index 00000000000..db313049836 --- /dev/null +++ b/src/sage/algebras/lie_algebras/virasoro.py @@ -0,0 +1,237 @@ +""" +Virasoro Algebras + +AUTHORS: + +- Travis Scrimshaw (2013-05-03): Initial version +""" + +#***************************************************************************** +# Copyright (C) 2013 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# This code is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# See the GNU General Public License for more details; the full text +# is available at: +# +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.categories.lie_algebras import LieAlgebras +from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, LieAlgebraElement +from sage.algebras.lie_algebras.lie_algebra import InfinitelyGeneratedLieAlgebra + +# This is why we should use the repr_term in the parent +class RegVecFieldsGen(LieGenerator): + r""" + Generator class for the Lie algebra of regular vector fields + of `\CC^{\times}`. This is known as the Witt algebra. + + REFERENCES: + + - :wikipedia:`Witt_algebra` + """ + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.regular_vector_fields(QQ) + sage: L.d(2) + d[2] + """ + return "d[" + repr(self._name) + "]" + +class LieAlgebraRegularVectorFields(InfinitelyGeneratedLieAlgebra): + r""" + The Lie algebra of regular vector fields on `C^{\times}`. + + This is the Lie algebra generated by `\{d_i\}_{i \in \ZZ}` and subject + to the relations + + .. MATH:: + + [d_i, d_j] = (j - i) d_{i+j}. + """ + def __init__(self, R): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.regular_vector_fields(QQ) + sage: TestSuite(L).run() + """ + InfinitelyGeneratedLieAlgebra.__init__(self, R, category=LieAlgebras(R).WithBasis()) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: lie_algebras.regular_vector_fields(QQ) + The Lie algebra of regular vector fields over Rational Field + """ + return "The Lie algebra of regular vector fields over {}".format(self.base_ring()) + + def d(self, i): + """ + The generator `d_i`. + + EXAMPLES:: + + sage: L = lie_algebras.regular_vector_fields(QQ) + sage: L.d(4) + d[4] + sage: L.d(-2) + d[-2] + """ + return self.element_class(self, {RegVecFieldsGen(i): self.base_ring().one()}) + + def bracket_on_basis(self, x, y): + """ + Return the bracket of the basis elements indexed by ``x`` and ``y``. + + EXAMPLES:: + + sage: L = lie_algebras.regular_vector_fields(QQ) + sage: d2 = L.d(2) + sage: dm2 = L.d(-2) + sage: d2.bracket(dm2) # indirect doctest + -4*d[0] + sage: d4 = L.d(4) + sage: d2.bracket(d4) + 2*d[6] + sage: L.bracket(d4, d4) + 0 + """ + i = x._name + j = y._name + return self._from_dict({RegVecFieldsGen(i + j): j-i}) + + def _an_element_(self): + """ + Return an element of ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.regular_vector_fields(QQ) + sage: L.an_element() + d[-1] + d[0] - 3*d[1] + """ + return self.d(0) - 3*self.d(1) + self.d(-1) + + def some_elements(self): + """ + Return some elements of ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.regular_vector_fields(QQ) + sage: L.some_elements() + [d[0], d[2], d[-2], d[-1] + d[0] - 3*d[1]] + """ + return [self.d(0), self.d(2), self.d(-2), self.an_element()] + + Element = LieAlgebraElement + +class CentralElement(LieGenerator): + """ + The central element in the Virasoro algebra. + """ + def __init__(self): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: d = lie_algebras.VirasoroAlgebra(QQ) + sage: d.c() + c + """ + return LieGenerator.__init__(self, 'c') + +class VirasoroAlgebra(LieAlgebraRegularVectorFields): + r""" + The Virasoro algebra. + + This is the Lie algebra generated by `\{d_i\}_{i \in \ZZ}` and subject + to the relations + + .. MATH:: + + [d_i, d_j] = (j - i) d_{i+j} + \frac{1}{12}(j^3 - j) \delta_{i,-j} c. + + This is the universal central extension `\widetilde{\mathfrak{d}}` of the + Lie algebra `\mathfrak{d}` of + :class:`regular vector fields ` + on `\CC^{\times}`. + + EXAMPLES:: + + sage: d = lie_algebras.VirasoroAlgebra(QQ) + + TESTS:: + + sage: d = lie_algebras.VirasoroAlgebra(QQ) + sage: TestSuite(d).run() + + REFERENCES: + + - :wikipedia:`Virasoro_algebra` + """ + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: lie_algebras.VirasoroAlgebra(QQ) + The Virasoro algebra over Rational Field + """ + return "The Virasoro algebra over {}".format(self.base_ring()) + + @cached_method + def c(self): + """ + The central element in ``self``. + + EXAMPLES:: + + sage: d = lie_algebras.VirasoroAlgebra(QQ) + sage: d.c() + c + """ + return self.element_class(self, {CentralElement(): self.base_ring().one()}) + + def bracket_on_basis(self, x, y): + """ + Return the bracket of the basis elements indexed by ``x`` and ``y``. + + EXAMPLES:: + + sage: d = lie_algebras.VirasoroAlgebra(QQ) + sage: c = d.c() + sage: d2 = d.d(2) + sage: dm2 = d.d(-2) + sage: c.bracket(d2) # indirect doctest + 0 + sage: d2.bracket(dm2) + -4*d[0] - 1/2*c + """ + i = x._name + j = y._name + if i == 'c' or j == 'c': + return self.zero() + ret = self._from_dict({RegVecFieldsGen(i + j): j-i}) + if i == -j: + ret += (j**3 - j) / 12 * self.c() + return ret + From 2e9f927cd483eee2853c84d9e8cd7cd2d31cba2a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 20 Sep 2014 09:14:39 -0700 Subject: [PATCH 011/223] Starting to make things work again. --- src/sage/algebras/all.py | 2 +- src/sage/algebras/lie_algebras/examples.py | 13 +- src/sage/algebras/lie_algebras/heisenberg.py | 61 +++++-- src/sage/algebras/lie_algebras/lie_algebra.py | 99 ++++++------ .../lie_algebras/lie_algebra_element.py | 38 ++--- .../lie_algebras/structure_coefficients.py | 113 ++++--------- src/sage/algebras/lie_algebras/subalgebra.py | 146 +++++++++++++++++ src/sage/algebras/lie_algebras/virasoro.py | 153 ++++++++++-------- src/sage/categories/lie_algebras.py | 21 ++- 9 files changed, 398 insertions(+), 248 deletions(-) create mode 100644 src/sage/algebras/lie_algebras/subalgebra.py diff --git a/src/sage/algebras/all.py b/src/sage/algebras/all.py index d57f2461623..a035acd434c 100644 --- a/src/sage/algebras/all.py +++ b/src/sage/algebras/all.py @@ -26,11 +26,11 @@ # Ring element base classes from algebra_element import AlgebraElement - from free_algebra import FreeAlgebra from free_algebra_quotient import FreeAlgebraQuotient from steenrod.all import * +from lie_algebras.all import * from finite_dimensional_algebras.all import FiniteDimensionalAlgebra diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index 2ca2829fd32..9e7bbe9e256 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -128,7 +128,14 @@ def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): L.rename("Lie algebra of dimension 3 and rank 2 with parameter {} over {}".format(a, R)) return L if n == 3: - return sl(R, 2) + #return sl(R, 2) + E = names[0] + F = names[1] + H = names[2] + s_coeff = { (E,F): {H:R.one()}, (H,E): {E:R(2)}, (H,F): {E:R(-2)} } + L = LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) + L.rename("sl2 over {}".format(R)) + return L raise ValueError("Invalid rank") def affine_transformations_line(R, names=['X', 'Y'], representation='bracket'): @@ -145,10 +152,12 @@ def affine_transformations_line(R, names=['X', 'Y'], representation='bracket'): names = names.split(',') names = tuple(names) if representation == 'matrix': + from sage.matrix.matrix_space import MatrixSpace MS = MatrixSpace(R, 2, sparse=True) one = R.one() gens = tuple(MS({(0,i):one}) for i in range(2)) - return LieAlgebraFromAssociative(self, R, M, gens, names) + from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative + return LieAlgebraFromAssociative(R, MS, gens, names) X = names[0] Y = names[1] from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index 576b17cbe42..944145228ad 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -23,15 +23,18 @@ from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method +from sage.misc.misc import repr_lincomb from sage.algebras.algebra import Algebra from sage.algebras.lie_algebras.lie_algebra import InfinitelyGeneratedLieAlgebra, \ LieAlgebraFromAssociative, FinitelyGeneratedLieAlgebra from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement, LieGenerator from sage.categories.lie_algebras import LieAlgebras +from sage.combinat.cartesian_product import CartesianProduct from sage.matrix.matrix_space import MatrixSpace from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.infinity import infinity from sage.sets.family import Family +from sage.sets.positive_integers import PositiveIntegers class HeisenbergGenerator(LieGenerator): """ @@ -193,7 +196,19 @@ def bracket_on_basis(self, x, y): return self.z() return self.zero() - Element = LieAlgebraElement + class Element(LieAlgebraElement): + """ + An element in the Heisenberg Lie algebra. + """ + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + """ + if not self._monomial_coefficients: + return '0' + return repr_lincomb(self.list()) class HeisenbergAlgebra(HeisenbergAlgebra_abstract, FinitelyGeneratedLieAlgebra): """ @@ -236,7 +251,7 @@ def __init__(self, R, n): sage: TestSuite(L).run() """ self._n = n - names = ['p%s'%i for i in range(1,n+1)] + ['q%s'%i for i in range(1,n+1)] + ['z'] + names = ['p%s'%i for i in range(1,n+1)] + ['q%s'%i for i in range(1,n+1)] #+ ['z'] FinitelyGeneratedLieAlgebra.__init__(self, R, names, category=LieAlgebras(R).FiniteDimensional().WithBasis()) @@ -260,11 +275,11 @@ def gens(self): sage: H = lie_algebras.Heisenberg(QQ, 2) sage: H.gens() - (p1, p2, q1, q2, z) + (p1, p2, q1, q2) """ L = [self.p(i) for i in range(1, self._n+1)] L += [self.q(i) for i in range(1, self._n+1)] - L += [self.z()] + #L += [self.z()] return tuple(L) def gen(self, i): @@ -281,18 +296,24 @@ def gen(self, i): """ return self.gens()[i] - def algebra_generators(self): + @cached_method + def lie_algebra_generators(self): """ Return the algebra generators of ``self``. EXAMPLES:: sage: H = lie_algebras.Heisenberg(QQ, 1) - sage: H.algebra_generators() + sage: H.lie_algebra_generators() Finite family {'q1': q1, 'p1': p1} """ - return Family({self.variable_names()[i]: x for i,x in enumerate(self.gens()[:-1])}) + d = {} + for i in range(1, self._n+1): + d['p%s'%i] = self.p(i) + d['q%s'%i] = self.q(i) + return Family(d) + @cached_method def basis(self): """ Return the basis of ``self``. @@ -303,7 +324,12 @@ def basis(self): sage: H.basis() Finite family {'q1': q1, 'p1': p1, 'z': z} """ - return Family({self.variable_names()[i]: x for i,x in enumerate(self.gens())}) + d = {} + for i in range(1, self._n+1): + d['p%s'%i] = self.p(i) + d['q%s'%i] = self.q(i) + d['z'] = self.z() + return Family(d) class InfiniteHeisenbergAlgebra(HeisenbergAlgebra_abstract, InfinitelyGeneratedLieAlgebra): """ @@ -342,10 +368,23 @@ def _an_element_(self): sage: L = lie_algebras.Heisenberg(QQ, oo) sage: L._an_element_() - p2 - 1/2*q2 + z + p2 + q2 - 1/2*q3 + z """ c = self.base_ring().an_element() - return self.p(2) - c * self.q(2) + self.z() + return self.p(2) + self.q(2) - c * self.q(3) + self.z() + + def lie_algebra_generators(self): + """ + Return the generators of ``self`` as a Lie algebra. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, oo) + sage: L.lie_algebra_generators() + """ + gen_func = lambda i, l: getattr(self, l)(i) + S = CartesianProduct(PositiveIntegers(), ['p','q']) + return Family(S, gen_func, name='generator map') def basis(self): """ @@ -361,8 +400,6 @@ def basis(self): Family (z,)) """ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets - from sage.sets.positive_integers import PositiveIntegers - from sage.sets.family import Family p = Family(PositiveIntegers(), self.p) q = Family(PositiveIntegers(), self.q) z = Family([self.z()]) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index ecb051050e7..9cdd25e7231 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -146,31 +146,15 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): Now we construct a free Lie algebra in a few different ways. There are two primary representations, as brackets and as polynomials:: - sage: L = LieAlgebra(QQ, 'x,y,z'); L # not tested + sage: L = LieAlgebra(QQ, 'x,y,z'); L # not tested #16823 Free Lie algebra generated by (x, y, z) over Rational Field sage: P. = LieAlgebra(QQ, representation="polynomial"); P Lie algebra on 3 generators (a, b, c) over Rational Field - Using brackets, there are two different bases for the free Lie algebra, - the Hall basis and Lyndon basis. We need to specify which basis we want - to use before being able to construct elements. Each of these can be - accessed as follows:: - - sage: Hall = L.Hall(); Hall # not tested - Free Lie algebra generated by (x, y, z) over Rational Field in the Hall basis - sage: Lyndon = L.Lyndon(); Lyndon # not tested - Free Lie algebra generated by (x, y, z) over Rational Field in the Lyndon basis - - As a convience, we include generators for the Lie algebra as being - elements using the Hall basis. The primary difference between these two - bases is just the canonical form for elements. :: - - sage: L. = LieAlgebra(QQ); L # not tested - Free Lie algebra generated by (x, y, z) over Rational Field - - However this does not hold for the polynomial representation, which we - can think of the variables as being a free algebra and the Lie bracket - is the commutator:: + We currently (:trac:`16823`) have the free Lie algebra given in the + polynomial representation, which is the Lie algebra of the Free algebra. + So the generators of the free Lie algebra are the generators of the + free algebra and the Lie bracket is the commutator:: sage: P.bracket(a, b) + P.bracket(a - c, b + 3*c) 2*a*b + 3*a*c - 2*b*a + b*c - 3*c*a - c*b @@ -204,7 +188,7 @@ def __classcall_private__(cls, R, arg0=None, arg1=None, names=None, if isinstance(arg0, dict): if len(arg0) == 0: from sage.algebras.lie_algebras.structure_coefficients import AbelianLieAlgebra - return AbelianLieAlebra(R, names, index_set) + return AbelianLieAlgebra(R, names, index_set) elif isinstance(arg0.keys()[0], (list,tuple)): # We assume it is some structure coefficients arg1, arg0 = arg0, arg1 @@ -399,19 +383,6 @@ def _coerce_map_from_(self, R): return self.base_ring().has_coerce_map_from(R.base_ring()) - @lazy_attribute - def _ordered_indices(self): - """ - Return the index set of ``self`` in order. - """ - return tuple(sorted(self._indices)) - - def _an_element_(self): - """ - Return an element of ``self``. - """ - return self.sum(self.lie_algebra_generators()) - @cached_method def zero(self): """ @@ -421,16 +392,6 @@ def zero(self): zero_element = zero - @cached_method - def gens(self): - """ - Return a tuple whose entries are the generators for this - object, in some order. - - EXAMPLES:: - """ - return tuple( self.lie_algebra_generators() ) - def gen(self, i): """ The ``i``-th generator of the Lie algebra. @@ -438,16 +399,17 @@ def gen(self, i): EXAMPLES:: """ G = self.lie_algebra_generators() - return self.element_class(self, G[i]) + return G[i] - # TODO: find a better place for this method? + # TODO: Find a better place for this method? + # TODO: Use IndexedGenerators? def indices(self): """ Return the indices of the basis of ``self``. """ return self._indices - # The following methods should belong to LieAlgebrasWithBasis + # The following methods should belong to ModulesWithBasis? def _from_dict(self, d, coerce=False, remove_zeros=True): """ Construct an element of ``self`` from an ``{index: coefficient}`` @@ -522,11 +484,10 @@ def term(self, i, c=None): c = self.base_ring()(c) return self.element_class(self, {i: c}) - # TODO: This is essentially an abstract method for Lie algebras without - # a distinguished basis + # TODO: This is essentially an abstract method for Lie algebras def lie_algebra_generators(self): """ - Return the Lie algebra generators of ``self``. + Return the generators of ``self`` as a Lie algebra. """ return Family(self._indices, self.monomial, name="monomial map") @@ -573,6 +534,35 @@ def _repr_(self): return "Lie algebra on {0} generators {1} over {2}".format( self.__ngens, self.gens(), self.base_ring()) + @cached_method + def gens(self): + """ + Return a tuple whose entries are the generators for this + object, in some order. + + EXAMPLES:: + """ + G = self.lie_algebra_generators() + try: + return tuple(G[i] for i in self.variable_names()) + except IndexError: + return tuple(G[i] for i in self.indices()) + except ValueError: + return tuple(G) + + @lazy_attribute + def _ordered_indices(self): + """ + Return the index set of ``self`` in order. + """ + return tuple(sorted(self._indices)) + + def _an_element_(self): + """ + Return an element of ``self``. + """ + return self.sum(self.lie_algebra_generators()) + class InfinitelyGeneratedLieAlgebra(LieAlgebra): r""" An infinitely generated Lie algebra. @@ -595,7 +585,8 @@ def dimension(self): """ return infinity -class LieAlgebraFromAssociative(LieAlgebra): +# TODO: Implement a version for infinite set of generators? +class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): """ A Lie algebra whose elements are from an associative algebra and whose bracket is the commutator. @@ -727,12 +718,12 @@ def __init__(self, R, assoc, gens, names=None, index_set=None, category=None): self._assoc = assoc # TODO: We should strip axioms from the category of the base ring, # such as FiniteDimensional, WithBasis - LieAlgebra.__init__(self, R, names, index_set, category) + FinitelyGeneratedLieAlgebra.__init__(self, R, names, index_set, category) # We register the coercion here since the UEA already exists self.lift.register_as_coercion() if isinstance(gens, dict): F = Family(self._indices, lambda i: gens[i]) - else: # TODO: Implement a version for infinite set of generators? + else: F = Family({self._indices[i]: v for i,v in enumerate(gens)}) self._gens = F diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index 5a60606df41..2a538fff83f 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -242,15 +242,15 @@ class LieAlgebraElement(CombinatorialFreeModuleElement): """ A Lie algebra element. """ - def _repr_(self): - """ - Return a string representation of ``self``. - - EXAMPLES:: - """ - if not self._monomial_coefficients: - return '0' - return repr_lincomb(self.list()) + #def _repr_(self): + # """ + # Return a string representation of ``self``. + # + # EXAMPLES:: + # """ + # if not self._monomial_coefficients: + # return '0' + # return repr_lincomb(self.list()) # Default implementation def _latex_monomial(self, m): @@ -262,15 +262,15 @@ def _latex_monomial(self, m): from sage.misc.latex import latex return latex(m) - def _latex_(self): - r""" - Return a `\LaTeX` representation of ``self``. - - EXAMPLES:: - """ - if not self._monomial_coefficients: - return '0' - return repr_lincomb(self.list(), repr_monomial=self._latex_monomial, is_latex=True) + #def _latex_(self): + # r""" + # Return a `\LaTeX` representation of ``self``. + # + # EXAMPLES:: + # """ + # if not self._monomial_coefficients: + # return '0' + # return repr_lincomb(self.list(), repr_monomial=self._latex_monomial, is_latex=True) def _mul_(self, y): """ @@ -299,7 +299,7 @@ def _im_gens_(self, codomain, im_gens): return codomain.sum(c * t._im_gens_(codomain, im_gens, names) for t, c in self._monomial_coefficients.iteritems()) - # TODO: Move to the category/lift morphism + # TODO: Move to the category/lift morphism? def lift(self): """ Lift ``self`` to the universal enveloping algebra. diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 6220a3bc853..4bd211b47a7 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -35,12 +35,11 @@ from sage.categories.finite_dimensional_lie_algebras_with_basis import FiniteDimensionalLieAlgebrasWithBasis from sage.algebras.free_algebra import FreeAlgebra -from sage.algebras.lie_algebras.lie_algebra_element import (LieGenerator, - LieBracket, LieAlgebraElement) +from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement from sage.algebras.lie_algebras.lie_algebra import FinitelyGeneratedLieAlgebra from sage.algebras.lie_algebras.subalgebra import LieSubalgebra -from sage.algebras.lie_algebras.ideal import LieAlgebraIdeal -from sage.algebras.lie_algebras.quotient import QuotientLieAlgebra +#from sage.algebras.lie_algebras.ideal import LieAlgebraIdeal +#from sage.algebras.lie_algebras.quotient import QuotientLieAlgebra from sage.rings.all import ZZ from sage.rings.ring import Ring from sage.rings.integer import Integer @@ -80,9 +79,9 @@ def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, **kwds): EXAMPLES:: - sage: L = LieAlgebra(QQ, 'x,y', {('x','y'):{'x':1}}) + sage: L1 = LieAlgebra(QQ, 'x,y', {('x','y'):{'x':1}}) sage: L2 = LieAlgebra(QQ, 'x,y', {('y','x'):{'x':-1}}) - sage: L is L2 + sage: L1 is L2 True """ s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff(s_coeff) @@ -109,8 +108,8 @@ def _standardize_s_coeff(s_coeff): cardinality is infinite). """ # Try to handle infinite basis (once/if supported) - if isinstance(s_coeff, AbstractFamily) and s_coeff.cardinality() == infinity: - return s_coeff + #if isinstance(s_coeff, AbstractFamily) and s_coeff.cardinality() == infinity: + # return s_coeff sc = {} # Make sure the first gen is smaller than the second in each key @@ -120,10 +119,10 @@ def _standardize_s_coeff(s_coeff): v = v.items() if k[0] > k[1]: - key = LieBracket(k[1], k[0]) + key = (k[1], k[0]) vals = tuple((g, -val) for g, val in v if val != 0) else: - key = LieBracket(*k) + key = tuple(k) vals = tuple((g, val) for g, val in v if val != 0) if key in sc.keys() and sorted(sc[key]) != sorted(vals): @@ -143,13 +142,14 @@ def __init__(self, R, s_coeff, names, index_set, category=None, prefix='', sage: L = LieAlgebra(QQ, 'x,y', {('x','y'):{'x':1}}) sage: TestSuite(L).run() """ - cat = LieAlgebras(R).WithBasis().or_subcategory(category) + cat = LieAlgebras(R).WithBasis().FiniteDimensional().or_subcategory(category) FinitelyGeneratedLieAlgebra.__init__(self, R, names, index_set, cat) IndexedGenerators.__init__(self, self._indices, prefix=prefix, bracket=bracket, latex_bracket=latex_bracket, **kwds) # Transform the values in the structure coefficients to elements - self._s_coeff = Family({k: self._from_dict(dict(s_coeff[k])) for k in s_coeff.keys()}) + self._s_coeff = Family({k: self._from_dict(dict(s_coeff[k])) + for k in s_coeff.keys()}) def basis(self): """ @@ -171,7 +171,7 @@ def structure_coefficients(self): sage: L = LieAlgebra(QQ, 'x,y', {('x','y'):{'x':1}}) sage: L.structure_coefficients() - Finite family {[x, y]: x} + Finite family {('x', 'y'): x} """ return self._s_coeff @@ -187,17 +187,16 @@ def dimension(self): """ return self.basis().cardinality() - # Move to FiniteDimensionalLieAlgebrasWithBasis category? def bracket_on_basis(self, x, y): """ - Return the Lie bracket of ``[self, y]``. + Return the Lie bracket of ``[x, y]``. EXAMPLES:: sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) - sage: L.bracket(x, y) # indirect doctest + sage: L.bracket_on_basis('x', 'y') z - sage: L.bracket(y, x) + sage: L.bracket_on_basis('y', 'x') -z sage: L.bracket(x + y - z, x - y + z) -2*y - 2*z @@ -207,7 +206,7 @@ def bracket_on_basis(self, x, y): if comp(x, y) > 0: # x > y x,y = y,x ordered = False - b = LieBracket(x, y) + b = (x, y) try: val = self._s_coeff[b] except KeyError: @@ -321,13 +320,13 @@ def _latex_(self): repr_monomial = self.parent()._latex_generator, is_latex=True, strip_one = True) - def _bracket_(self, y): - """ - Return the Lie bracket ``[self, y]``. - """ - P = self.parent() - return P.sum(cx * cy * P.bracket_on_basis(mx, my) - for mx,cx in self for my,cy in y) + #def _bracket_(self, y): + # """ + # Return the Lie bracket ``[self, y]``. + # """ + # P = self.parent() + # return P.sum(cx * cy * P.bracket_on_basis(mx, my) + # for mx,cx in self for my,cy in y) def to_vector(self): """ @@ -386,7 +385,7 @@ def _compute_basis_structure_coeff(A, gens): # Rewrite as a linear combination of the current basis s = -dep[-1] # Guaranteed to be non-zero d = {k: R(c*~s) for k,c in enumerate(dep[:-1]) if c != 0} - s_coeff[LieBracket(i,j)] = d + s_coeff[(i,j)] = d else: added = True cur = cur.stack(bv) @@ -396,15 +395,15 @@ def __init__(self, ambient, basis, s_coeff, names=None, index_set=None, category r""" Initialize ``self``. """ - self._s_coeff = s_coeff # TODO: convert the values to elements of ``self`` # TODO: make sure the category is in subobjects? LieSubalgebra.__init__(self, ambient, basis, names, index_set, category) + self._s_coeff = s_coeff # TODO: convert the values to elements of ``self`` def _repr_(self): """ Return a string representation of ``self``. """ - return "Subalgebra generated of {} with basis:\n{}".format(self._ambient, self.gens()) + return "Subalgebra of {} with basis:\n{}".format(self._ambient, self.gens()) def basis(self): """ @@ -424,63 +423,6 @@ def subalgebra(self, gens, names=None, index_set=None, category=None): return LieSubalgebraWithStructureCoefficients(self._ambient, B, s_coeff, names, index_set, category) -class LieAlgebraIdealWithStructureCoefficients(LieAlgebraIdeal, - LieSubalgebraWithStructureCoefficients): - """ - A Lie algebra ideal of a Lie algebra given by structure coefficients. - """ - def reduce(self, y): - """ - Return ``y`` modulo ``self``. - """ - M = self._ambient.free_module() - I = M.subspace(map(lambda x: x.to_vector(), self._gens)) - R = I.complement() - ld = M.linear_dependence(R.basis() + I.basis() + [y.to_vector()])[0] - normalizer = -ld[-1] - coeffs = map(lambda x: x / normalizer, ld[:len(R)]) - vec = M(R.linear_combination_of_basis(coeffs)) - return self._ambient(vec) - -# This should either not inherit from QuotientLieAlgebra or refactor out common code -# This should inherit from LieAlgebraWithStructureCoefficients -class QuotientLieAlgebraWithStructureCoefficients(QuotientLieAlgebra): - """ - A quotient Lie algebra of a Lie algebra given by structure coefficients. - - INPUT: - - - ``I`` -- an ideal of a Lie algebra given by structure coefficients - - ``names`` -- the names of the generators - - ``index_set`` -- the indexing set for the generators - - ``category`` -- the category of the quotient Lie algebra - """ - def __init__(self, lie, I, names=None, index_set=None, category=None): - """ - Initialize ``self``. - """ - R = lie.base_ring() - #cat = LieAlgebras(R).FiniteDimensional().WithBasis() - cat = FiniteDimensionalLieAlgebrasWithBasis(R)#.Quotients() - QuotientLieAlgebra.__init__(self, lie, I, names, index_set, cat) - - # Construct the structure coefficients - M = lie.free_module() - IM = M.subspace(map(lambda x: x.to_vector(), I._gens)) - RM = IM.complement() - B = RM.basis() + IM.basis() - dim = len(RM) - self._s_coeff = {} - for i,kl,zl in enumerate(gens): - for kr,zr in gens[i+1:]: - b = LieBracket(zl, zr) - ld = M.linear_dependence(B + [y.to_vector()])[0] - normalizer = -ld[-1] - self._s_coeffs[b] = {indices[j]: val / normalizer - for j,val in enumerate(ld[:dim])} - - Element = LieAlgebraElement - class AbelianLieAlgebra(LieAlgebraWithStructureCoefficients): r""" An abelian Lie algebra. @@ -568,3 +510,4 @@ def _bracket_(self, y): 0 """ return self.parent().zero() + diff --git a/src/sage/algebras/lie_algebras/subalgebra.py b/src/sage/algebras/lie_algebras/subalgebra.py new file mode 100644 index 00000000000..4bdd44aa591 --- /dev/null +++ b/src/sage/algebras/lie_algebras/subalgebra.py @@ -0,0 +1,146 @@ +""" +(Lie) Subalgebras of Lie Algebras + +AUTHORS: + +- Travis Scrimshaw (2013-05-03): Initial version +""" + +#***************************************************************************** +# Copyright (C) 2013 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# This code is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# See the GNU General Public License for more details; the full text +# is available at: +# +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.categories.homset import Hom +from sage.categories.morphism import Morphism +from sage.algebras.lie_algebras.lie_algebra import LieAlgebra +from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElementWrapper +from sage.rings.all import ZZ + +# TODO: A class for finite dimensional subalgebras so we can give an echonized basis +class LieSubalgebra(LieAlgebra): + r""" + The Lie subalgebra `\mathfrak{h}` of a Lie algebra `\mathfrak{g}`. + """ + def __init__(self, ambient, gens, names=None, index_set=None, category=None): + """ + Initialize ``self``. + + INPUT: + + - ``ambient`` -- the ambient Lie algebra + + - ``gens`` -- the generators for this subalgebra + + - ``names`` -- (optional) the names for the generators + + - ``index_set`` -- (optional) the index set for the generators + + - ``category`` -- (optional) the category + + EXAMPLES:: + """ + self._ambient = ambient + self._gens = gens + category = ambient.category().or_subcategory(category) + if names is None and index_set is None: + index_set = range(len(gens)) + LieAlgebra.__init__(self, ambient.base_ring(), names, index_set, category) + + def _repr_(self): + """ + Return a string representation of ``self``. + """ + return "Subalgebra generated by {} of {}".format(self.gens(), self._ambient) + + @cached_method + def lie_algebra_generators(self): + """ + Return the generators of ``self`` as a Lie algebra. + """ + return tuple(self.element_class(self, g) for g in self._gens) + + def subalgebra(self, gens, names=None, index_set=None, category=None): + r""" + Return the subalgebra of ``self`` generated by ``gens``. + """ + return LieSubalgebra(self._ambient, map(lambda x: x.value, gens), + names, index_set, category) + + def free_module(self): + r""" + Return ``self`` as (a subspace of) a free module. + """ + return self._ambient.free_module().subspace(map(lambda x: x.to_vector(), self.basis())) + + @lazy_attribute + def ambient_lift(self): + r""" + Return the morphism which lifts an element of ``self`` to + the ambient Lie algebra. + """ + return AmbientLiftMorphism(self, self._ambient) + + class Element(LieAlgebraElementWrapper): + r""" + An element in a Lie subalgebra. + """ + def _bracket_(self, rhs): + r""" + Return the bracket ``[self, rhs]``. + + EXAMPLES:: + """ + return self.__class__(self.parent(), self.value.bracket(rhs.value)) + + def __iter__(self): + r""" + Iterate over ``self``. + + EXAMPLES:: + """ + return iter(self.value) + +class AmbientLiftMorphism(Morphism): + r""" + The natural lifting morphism from a Lie subalgebra to its + ambient Lie algebra. + """ + def __init__(self, domain, codomain): + r""" + Initialize ``self``. + + EXAMPLES:: + """ + Morphism.__init__(self, Hom(domain, codomain)) + + def _repr_type(self): + r""" + Return a string representation of the type of ``self``. + + EXAMPLES:: + """ + return "Lift" + + def _call_(self, x): + r""" + Lift ``x`` to the ambient Lie algebra. + + EXAMPLES:: + """ + return x.value + diff --git a/src/sage/algebras/lie_algebras/virasoro.py b/src/sage/algebras/lie_algebras/virasoro.py index db313049836..31361e12606 100644 --- a/src/sage/algebras/lie_algebras/virasoro.py +++ b/src/sage/algebras/lie_algebras/virasoro.py @@ -23,32 +23,15 @@ from sage.misc.cachefunc import cached_method from sage.categories.lie_algebras import LieAlgebras +from sage.rings.all import ZZ +from sage.sets.family import Family +from sage.sets.set import Set +from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets +from sage.structure.indexed_generators import IndexedGenerators from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, LieAlgebraElement from sage.algebras.lie_algebras.lie_algebra import InfinitelyGeneratedLieAlgebra -# This is why we should use the repr_term in the parent -class RegVecFieldsGen(LieGenerator): - r""" - Generator class for the Lie algebra of regular vector fields - of `\CC^{\times}`. This is known as the Witt algebra. - - REFERENCES: - - - :wikipedia:`Witt_algebra` - """ - def _repr_(self): - """ - Return a string representation of ``self``. - - EXAMPLES:: - - sage: L = lie_algebras.regular_vector_fields(QQ) - sage: L.d(2) - d[2] - """ - return "d[" + repr(self._name) + "]" - -class LieAlgebraRegularVectorFields(InfinitelyGeneratedLieAlgebra): +class LieAlgebraRegularVectorFields(InfinitelyGeneratedLieAlgebra, IndexedGenerators): r""" The Lie algebra of regular vector fields on `C^{\times}`. @@ -58,6 +41,12 @@ class LieAlgebraRegularVectorFields(InfinitelyGeneratedLieAlgebra): .. MATH:: [d_i, d_j] = (j - i) d_{i+j}. + + This is known as the Witt (Lie) algebra. + + REFERENCES: + + - :wikipedia:`Witt_algebra` """ def __init__(self, R): """ @@ -68,7 +57,9 @@ def __init__(self, R): sage: L = lie_algebras.regular_vector_fields(QQ) sage: TestSuite(L).run() """ - InfinitelyGeneratedLieAlgebra.__init__(self, R, category=LieAlgebras(R).WithBasis()) + cat = LieAlgebras(R).WithBasis() + InfinitelyGeneratedLieAlgebra.__init__(self, R, index_set=ZZ, category=cat) + IndexedGenerators.__init__(self, ZZ, prefix='d', bracket='[') def _repr_(self): """ @@ -81,40 +72,35 @@ def _repr_(self): """ return "The Lie algebra of regular vector fields over {}".format(self.base_ring()) - def d(self, i): + @cached_method + def lie_algebra_generators(self): """ - The generator `d_i`. + Return the generators of ``self`` as a Lie algebra. EXAMPLES:: sage: L = lie_algebras.regular_vector_fields(QQ) - sage: L.d(4) - d[4] - sage: L.d(-2) - d[-2] + sage: L.lie_algebra_generators() """ - return self.element_class(self, {RegVecFieldsGen(i): self.base_ring().one()}) + return Family(self._indices, self.monomial, name='generator map') - def bracket_on_basis(self, x, y): + def bracket_on_basis(self, i, j): """ - Return the bracket of the basis elements indexed by ``x`` and ``y``. + Return the bracket of the basis elements indexed by ``i`` and ``j``. EXAMPLES:: sage: L = lie_algebras.regular_vector_fields(QQ) - sage: d2 = L.d(2) - sage: dm2 = L.d(-2) - sage: d2.bracket(dm2) # indirect doctest + sage: L.bracket_on_basis(2, -2) -4*d[0] + sage: d2 = L.d(2) sage: d4 = L.d(4) sage: d2.bracket(d4) 2*d[6] sage: L.bracket(d4, d4) 0 """ - i = x._name - j = y._name - return self._from_dict({RegVecFieldsGen(i + j): j-i}) + return self.term(i + j, j - i) def _an_element_(self): """ @@ -126,7 +112,7 @@ def _an_element_(self): sage: L.an_element() d[-1] + d[0] - 3*d[1] """ - return self.d(0) - 3*self.d(1) + self.d(-1) + return self.monomial(0) - 3*self.monomial(1) + self.monomial(-1) def some_elements(self): """ @@ -138,27 +124,11 @@ def some_elements(self): sage: L.some_elements() [d[0], d[2], d[-2], d[-1] + d[0] - 3*d[1]] """ - return [self.d(0), self.d(2), self.d(-2), self.an_element()] + return [self.monomial(0), self.monomial(2), self.monomial(-2), self.an_element()] Element = LieAlgebraElement -class CentralElement(LieGenerator): - """ - The central element in the Virasoro algebra. - """ - def __init__(self): - """ - Initialize ``self``. - - EXAMPLES:: - - sage: d = lie_algebras.VirasoroAlgebra(QQ) - sage: d.c() - c - """ - return LieGenerator.__init__(self, 'c') - -class VirasoroAlgebra(LieAlgebraRegularVectorFields): +class VirasoroAlgebra(InfinitelyGeneratedLieAlgebra, IndexedGenerators): r""" The Virasoro algebra. @@ -187,6 +157,20 @@ class VirasoroAlgebra(LieAlgebraRegularVectorFields): - :wikipedia:`Virasoro_algebra` """ + def __init__(self, R): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.regular_vector_fields(QQ) + sage: TestSuite(L).run() + """ + cat = LieAlgebras(R).WithBasis() + I = DisjointUnionEnumeratedSets([Set(['c']), ZZ]) + InfinitelyGeneratedLieAlgebra.__init__(self, R, index_set=I, category=cat) + IndexedGenerators.__init__(self, I, prefix='d', bracket='[') + def _repr_(self): """ Return a string representation of ``self``. @@ -199,6 +183,23 @@ def _repr_(self): return "The Virasoro algebra over {}".format(self.base_ring()) @cached_method + def lie_algebra_generators(self): + """ + Return the generators of ``self`` as a Lie algebra. + + EXAMPLES:: + + sage: L = lie_algebras.regular_vector_fields(QQ) + sage: L.lie_algebra_generators() + """ + return Family(self._indices, self.monomial, name='generator map') + + def d(self, i): + """ + Return the element `d_i` in ``self``. + """ + return self.monomial(i) + def c(self): """ The central element in ``self``. @@ -209,11 +210,11 @@ def c(self): sage: d.c() c """ - return self.element_class(self, {CentralElement(): self.base_ring().one()}) + return self.monomial(c) - def bracket_on_basis(self, x, y): + def bracket_on_basis(self, i, j): """ - Return the bracket of the basis elements indexed by ``x`` and ``y``. + Return the bracket of the basis elements indexed by ``i`` and ``j``. EXAMPLES:: @@ -226,8 +227,6 @@ def bracket_on_basis(self, x, y): sage: d2.bracket(dm2) -4*d[0] - 1/2*c """ - i = x._name - j = y._name if i == 'c' or j == 'c': return self.zero() ret = self._from_dict({RegVecFieldsGen(i + j): j-i}) @@ -235,3 +234,31 @@ def bracket_on_basis(self, x, y): ret += (j**3 - j) / 12 * self.c() return ret + def _an_element_(self): + """ + Return an element of ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.VirasoroAlgebra(QQ) + sage: L.an_element() + d[-1] + d[0] - 3*d[1] + """ + d = self.monomial + return d(0) - self.base_ring().an_element()*d(1) + d(-1) + d('c') + + def some_elements(self): + """ + Return some elements of ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.VirasoroAlgebra(QQ) + sage: L.some_elements() + [d[0], d[2], d[-2], d[-1] + d[0] - 3*d[1]] + """ + d = self.monomial + return [d(0), d(2), d(-2), d('c'), self.an_element()] + + Element = LieAlgebraElement + diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index d1af744178a..7f2b2e465ca 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -198,6 +198,12 @@ def extra_super_categories(self): return [] class ParentMethods: + #@abstract_method + #def lie_algebra_generators(self): + # """ + # Return the generators of ``self`` as a Lie algebra. + # """ + def bracket(self, lhs, rhs): """ Return the Lie bracket ``[lhs, rhs]`` after coercing ``lhs`` and @@ -272,23 +278,14 @@ def lift(self): M.register_as_coercion() return M - @abstract_method(optional=True) - def subalgebra(self, gens): + def subalgebra(self, gens, names=None, index_set=None, category=None): """ Return the subalgebra of ``self`` generated by ``gens``. EXAMPLES:: - - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.inject_variables() - Defining a, b, c - sage: L.subalgebra([2*a - c, b + c]) - An example of a finite dimensional Lie algebra with basis: - the abelian Lie algebra with generators ('x0', 'x1') - over Rational Field with basis matrix: - [ 1 0 -1/2] - [ 0 1 1] """ + from sage.algebras.lie_algebras.subalgebra import LieSubalgebra + return LieSubalgebra(gens, names, index_set, category) @abstract_method(optional=True) def killing_form(self, x, y): From c3992022fe80fbcea65e9a6a12f4296f6180f23d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 23 Sep 2014 01:56:37 -0700 Subject: [PATCH 012/223] Split off subalgebras into another ticket. --- .../lie_algebras/structure_coefficients.py | 193 ++---------------- src/sage/algebras/lie_algebras/subalgebra.py | 146 ------------- 2 files changed, 12 insertions(+), 327 deletions(-) delete mode 100644 src/sage/algebras/lie_algebras/subalgebra.py diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 4bd211b47a7..6893b869f60 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -37,7 +37,7 @@ from sage.algebras.free_algebra import FreeAlgebra from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement from sage.algebras.lie_algebras.lie_algebra import FinitelyGeneratedLieAlgebra -from sage.algebras.lie_algebras.subalgebra import LieSubalgebra +#from sage.algebras.lie_algebras.subalgebra import LieSubalgebra #from sage.algebras.lie_algebras.ideal import LieAlgebraIdeal #from sage.algebras.lie_algebras.quotient import QuotientLieAlgebra from sage.rings.all import ZZ @@ -122,6 +122,7 @@ def _standardize_s_coeff(s_coeff): key = (k[1], k[0]) vals = tuple((g, -val) for g, val in v if val != 0) else: + assert k[0] < k[1], "elements {} not ordered".format(k) key = tuple(k) vals = tuple((g, val) for g, val in v if val != 0) @@ -133,24 +134,29 @@ def _standardize_s_coeff(s_coeff): return Family(sc) def __init__(self, R, s_coeff, names, index_set, category=None, prefix='', - bracket=False, latex_bracket=False, **kwds): + bracket=False, latex_bracket=False, string_quotes=False, **kwds): """ Initialize ``self``. EXAMPLES:: - sage: L = LieAlgebra(QQ, 'x,y', {('x','y'):{'x':1}}) + sage: L = LieAlgebra(QQ, 'x,y', {('x','y'): {'x':1}}) sage: TestSuite(L).run() """ cat = LieAlgebras(R).WithBasis().FiniteDimensional().or_subcategory(category) FinitelyGeneratedLieAlgebra.__init__(self, R, names, index_set, cat) - IndexedGenerators.__init__(self, self._indices, prefix=prefix, bracket=bracket, - latex_bracket=latex_bracket, **kwds) + IndexedGenerators.__init__(self, self._indices, prefix=prefix, + bracket=bracket, latex_bracket=latex_bracket, + string_quotes=string_quotes, **kwds) # Transform the values in the structure coefficients to elements self._s_coeff = Family({k: self._from_dict(dict(s_coeff[k])) for k in s_coeff.keys()}) + # For compatibility with CombinatorialFreeModuleElement + _repr_term = IndexedGenerators._repr_generator + _latex_term = IndexedGenerators._latex_generator + def basis(self): """ Return the basis of ``self``. @@ -225,100 +231,13 @@ def free_module(self, sparse=True): sage: L.free_module() Sparse vector space of dimension 3 over Rational Field """ + # TODO: Make this return a free module with the same index set as ``self`` return FreeModule(self.base_ring(), self.dimension(), sparse=sparse) - def subalgebra(self, gens, names=None, index_set=None, category=None): - """ - Return the subalgebra of ``self`` generated by ``gens``. - - EXAMPLES:: - - sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) - sage: L.subalgebra([x+y]) - Subalgebra generated of Lie algebra on 3 generators (x, y, z) over Rational Field with basis: - (x + y,) - sage: L.subalgebra([x+y, y+z]) - Lie algebra on 3 generators (x, y, z) over Rational Field - - TESTS:: - - sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) - sage: L.subalgebra([x+y, x+y]) - Subalgebra generated of Lie algebra on 3 generators (x, y, z) over Rational Field with basis: - (x + y,) - """ - B, s_coeff = LieSubalgebraWithStructureCoefficients._compute_basis_structure_coeff(self, gens) - if len(B) == self.dimension(): - return self - return LieSubalgebraWithStructureCoefficients(self, B, s_coeff, names, index_set, category) - - # TODO: - # - Make a centralizer of a set version - # - Move to FiniteDimensionalLieAlgebrasWithBasis once implemented - # - Return a subalgebra - #@cached_method - #def center(self): - # """ - # Return a list of elements which correspond to a basis for the center - # of ``self``. - # """ - # R = self.base_ring() - # B = self.basis() - # K = list(B.keys()) - # k = len(K) - # d = {} - # for a,i in enumerate(K): - # Bi = B[i] - # for b,j in enumerate(K): - # Bj = B[j] - # for m,c in Bi.bracket(Bj): - # d[(a, K.index(m)+k*b)] = c - # m = Matrix(R, d, nrows=k, ncols=k*k, sparse=True) - # from_vector = lambda x: self.sum_of_terms( ((K[i], c) for i,c in x.iteritems()), - # distinct=True) - # return tuple(map( from_vector, m.kernel().basis() )) - # Dense version - # R = self.base_ring() - # B = self.basis() - # K = list(B.keys()) - # eqns = [[] for dummy in range(k)] - # for a,i in enumerate(K): - # for b,j in enumerate(K): - # v = B[i]*B[j] - B[j]*B[i] - # eqns[a].extend([v[k] for k in K]) - # m = Matrix(R, eqns) - # from_vector = lambda x: self.sum_of_terms(((K[i], c) for i,c in x.iteritems()), - # distinct=True) - # return tuple(map( from_vector, m.kernel().basis() )) - class Element(LieAlgebraElement): """ An element of a Lie algebra given by structure coefficients. """ - def _repr_(self): - r""" - Return a string representation of ``self``. - """ - prefix = self.parent()._print_options['prefix'] - if self.parent()._names is not None and not prefix: - return LieAlgebraElement._repr_(self) - return repr_lincomb(self._sorted_items_for_printing(), - scalar_mult=self.parent()._print_options['scalar_mult'], - repr_monomial = self.parent()._repr_generator, - strip_one = True) - - def _latex_(self): - r""" - Return a `\LaTeX` representation of ``self``. - """ - prefix = self.parent()._print_options['prefix'] - if self.parent()._names is not None and not prefix: - return LieAlgebraElement._latex_(self) - return repr_lincomb(self._sorted_items_for_printing(), - scalar_mult = self.parent()._print_options['scalar_mult'], - latex_scalar_mult = self.parent()._print_options['latex_scalar_mult'], - repr_monomial = self.parent()._latex_generator, - is_latex=True, strip_one = True) #def _bracket_(self, y): # """ @@ -335,94 +254,6 @@ def to_vector(self): V = self.parent().free_module() return V([self[k] for k in self.parent()._ordered_indices]) -class LieSubalgebraWithStructureCoefficients(LieSubalgebra): - """ - A Lie subalgebra of a Lie algebra given by structure coefficients. - """ - @staticmethod - def _compute_basis_structure_coeff(A, gens): - """ - Compute an echonalized basis of ``self`` and the corresponding - structure coefficients. - - INPUT: - - - ``A`` -- the ambient Lie algebra - - ``gens`` -- a set of generators as elements in ``A`` - """ - I = A._ordered_indices - R = A.base_ring() - M = A.free_module() - zero = A.zero() - - # Setup the current basis matrix - cur = matrix(R, map(lambda x: x.to_vector(), gens), sparse=M.is_sparse()) - cur.echelonize() - # Remove all zero rows from cur - cur = cur.delete_rows([i for i,row in enumerate(cur.rows()) if row.is_zero()]) - - added = True - while added: - added = False - cur.echelonize() - basis = tuple(A._from_dict({I[i]: c for i,c in row.iteritems()}) for row in cur) - s_coeff = {} - - for i in range(len(basis)): - for j in range(i+1, len(basis)): - b = basis[i].bracket(basis[j]) - if b == zero: - # There is a dependence and no resulting structure - # coefficients, so we don't have to do anything more - continue - - bv = b.to_vector() - dep = M.linear_dependence(cur.rows() + [bv]) - if dep: - # The dependency is the first in the sequence, there's only - # one because the original set is linearly independent - dep = dep[0] - # Rewrite as a linear combination of the current basis - s = -dep[-1] # Guaranteed to be non-zero - d = {k: R(c*~s) for k,c in enumerate(dep[:-1]) if c != 0} - s_coeff[(i,j)] = d - else: - added = True - cur = cur.stack(bv) - return (basis, Family(s_coeff)) - - def __init__(self, ambient, basis, s_coeff, names=None, index_set=None, category=None): - r""" - Initialize ``self``. - """ - # TODO: make sure the category is in subobjects? - LieSubalgebra.__init__(self, ambient, basis, names, index_set, category) - self._s_coeff = s_coeff # TODO: convert the values to elements of ``self`` - - def _repr_(self): - """ - Return a string representation of ``self``. - """ - return "Subalgebra of {} with basis:\n{}".format(self._ambient, self.gens()) - - def basis(self): - """ - Return a basis of ``self``. - """ - I = self._indices - B = self._gens - return Family({ I[i]: b for i,b in enumerate(B) }) - - def subalgebra(self, gens, names=None, index_set=None, category=None): - """ - Return the subalgebra of ``self`` generated by ``gens``. - """ - gens = map(lambda x: x.value, gens) - B, s_coeff = LieSubalgebraWithStructureCoefficients._compute_basis_structure_coeff(self._ambient, gens) - assert len(B) != self._ambient.dimension() - return LieSubalgebraWithStructureCoefficients(self._ambient, B, s_coeff, - names, index_set, category) - class AbelianLieAlgebra(LieAlgebraWithStructureCoefficients): r""" An abelian Lie algebra. diff --git a/src/sage/algebras/lie_algebras/subalgebra.py b/src/sage/algebras/lie_algebras/subalgebra.py deleted file mode 100644 index 4bdd44aa591..00000000000 --- a/src/sage/algebras/lie_algebras/subalgebra.py +++ /dev/null @@ -1,146 +0,0 @@ -""" -(Lie) Subalgebras of Lie Algebras - -AUTHORS: - -- Travis Scrimshaw (2013-05-03): Initial version -""" - -#***************************************************************************** -# Copyright (C) 2013 Travis Scrimshaw -# -# Distributed under the terms of the GNU General Public License (GPL) -# -# This code is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty -# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -# See the GNU General Public License for more details; the full text -# is available at: -# -# http://www.gnu.org/licenses/ -#***************************************************************************** - -from sage.misc.cachefunc import cached_method -from sage.misc.lazy_attribute import lazy_attribute -from sage.structure.parent import Parent -from sage.structure.unique_representation import UniqueRepresentation -from sage.categories.homset import Hom -from sage.categories.morphism import Morphism -from sage.algebras.lie_algebras.lie_algebra import LieAlgebra -from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElementWrapper -from sage.rings.all import ZZ - -# TODO: A class for finite dimensional subalgebras so we can give an echonized basis -class LieSubalgebra(LieAlgebra): - r""" - The Lie subalgebra `\mathfrak{h}` of a Lie algebra `\mathfrak{g}`. - """ - def __init__(self, ambient, gens, names=None, index_set=None, category=None): - """ - Initialize ``self``. - - INPUT: - - - ``ambient`` -- the ambient Lie algebra - - - ``gens`` -- the generators for this subalgebra - - - ``names`` -- (optional) the names for the generators - - - ``index_set`` -- (optional) the index set for the generators - - - ``category`` -- (optional) the category - - EXAMPLES:: - """ - self._ambient = ambient - self._gens = gens - category = ambient.category().or_subcategory(category) - if names is None and index_set is None: - index_set = range(len(gens)) - LieAlgebra.__init__(self, ambient.base_ring(), names, index_set, category) - - def _repr_(self): - """ - Return a string representation of ``self``. - """ - return "Subalgebra generated by {} of {}".format(self.gens(), self._ambient) - - @cached_method - def lie_algebra_generators(self): - """ - Return the generators of ``self`` as a Lie algebra. - """ - return tuple(self.element_class(self, g) for g in self._gens) - - def subalgebra(self, gens, names=None, index_set=None, category=None): - r""" - Return the subalgebra of ``self`` generated by ``gens``. - """ - return LieSubalgebra(self._ambient, map(lambda x: x.value, gens), - names, index_set, category) - - def free_module(self): - r""" - Return ``self`` as (a subspace of) a free module. - """ - return self._ambient.free_module().subspace(map(lambda x: x.to_vector(), self.basis())) - - @lazy_attribute - def ambient_lift(self): - r""" - Return the morphism which lifts an element of ``self`` to - the ambient Lie algebra. - """ - return AmbientLiftMorphism(self, self._ambient) - - class Element(LieAlgebraElementWrapper): - r""" - An element in a Lie subalgebra. - """ - def _bracket_(self, rhs): - r""" - Return the bracket ``[self, rhs]``. - - EXAMPLES:: - """ - return self.__class__(self.parent(), self.value.bracket(rhs.value)) - - def __iter__(self): - r""" - Iterate over ``self``. - - EXAMPLES:: - """ - return iter(self.value) - -class AmbientLiftMorphism(Morphism): - r""" - The natural lifting morphism from a Lie subalgebra to its - ambient Lie algebra. - """ - def __init__(self, domain, codomain): - r""" - Initialize ``self``. - - EXAMPLES:: - """ - Morphism.__init__(self, Hom(domain, codomain)) - - def _repr_type(self): - r""" - Return a string representation of the type of ``self``. - - EXAMPLES:: - """ - return "Lift" - - def _call_(self, x): - r""" - Lift ``x`` to the ambient Lie algebra. - - EXAMPLES:: - """ - return x.value - From 96c8163bb55c376c423d1e39cd0a32131247ba4e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 23 Sep 2014 03:13:29 -0700 Subject: [PATCH 013/223] eisenberg and Virasoro passing doctests. Removed unnecessary classes. --- src/sage/algebras/lie_algebras/heisenberg.py | 363 ++++++++---------- src/sage/algebras/lie_algebras/lie_algebra.py | 11 +- .../lie_algebras/lie_algebra_element.py | 192 +-------- src/sage/algebras/lie_algebras/virasoro.py | 112 ++++-- 4 files changed, 240 insertions(+), 438 deletions(-) diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index 944145228ad..fd9adf74c6a 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -24,125 +24,36 @@ from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method from sage.misc.misc import repr_lincomb +from sage.structure.indexed_generators import IndexedGenerators + from sage.algebras.algebra import Algebra from sage.algebras.lie_algebras.lie_algebra import InfinitelyGeneratedLieAlgebra, \ LieAlgebraFromAssociative, FinitelyGeneratedLieAlgebra -from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement, LieGenerator +from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement from sage.categories.lie_algebras import LieAlgebras from sage.combinat.cartesian_product import CartesianProduct from sage.matrix.matrix_space import MatrixSpace from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.infinity import infinity +from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family from sage.sets.positive_integers import PositiveIntegers +from sage.sets.set import Set -class HeisenbergGenerator(LieGenerator): +class HeisenbergAlgebra_abstract(IndexedGenerators): """ - Generator for the Heisenberg algebra. + The common methods for the (non-matrix) Heisenberg algebras. """ - def __init__(self, name, i=None): + def __init__(self, I): """ Initialize ``self``. EXAMPLES:: - sage: from sage.algebras.lie_algebras.heisenberg import HeisenbergGenerator - sage: gen = HeisenbergGenerator('p', 2) - sage: TestSuite(gen).run() - """ - self._i = i - LieGenerator.__init__(self, name) - - def _repr_(self): - """ - Return a string representation of ``self``. - - EXAMPLES:: - - sage: from sage.algebras.lie_algebras.heisenberg import HeisenbergGenerator - sage: HeisenbergGenerator('p', 2) - p2 - sage: HeisenbergGenerator('d') - d - """ - if self._i is None: - return self._name - return self._name + repr(self._i) - - def _latex_(self): - r""" - Return a `LaTeX` representation of ``self``. - - EXAMPLES:: - - sage: from sage.algebras.lie_algebras.heisenberg import HeisenbergGenerator - sage: latex(HeisenbergGenerator('p', 2)) - p_{2} - sage: latex(HeisenbergGenerator('d')) - d - """ - if self._i is None: - return self._name - return self._name + "_{{{}}}".format(self._i) - - def __eq__(self, rhs): - """ - Compare equals. - - EXAMPLES:: - - sage: from sage.algebras.lie_algebras.heisenberg import HeisenbergGenerator - sage: p2 = HeisenbergGenerator('p', 2) - sage: p2 == HeisenbergGenerator('p', 2) - True - sage: p2 == HeisenbergGenerator('q', 2) - False - sage: p2 == HeisenbergGenerator('p', 4) - False - """ - return isinstance(rhs, LieGenerator) and self._name == rhs._name \ - and self._i == rhs._i - - def __ne__(self, rhs): + sage: L = lie_algebras.Heisenberg(QQ, oo) # indirect doctest """ - Compare equals. - - EXAMPLES:: - - sage: from sage.algebras.lie_algebras.heisenberg import HeisenbergGenerator - sage: p2 = HeisenbergGenerator('p', 2) - sage: p2 != HeisenbergGenerator('p', 2) - False - sage: p2 != HeisenbergGenerator('q', 2) - True - sage: p2 != HeisenbergGenerator('p', 4) - True - """ - return not self.__eq__(rhs) - - def __lt__(self, rhs): - """ - Compare less than. - - EXAMPLES:: - - sage: from sage.algebras.lie_algebras.heisenberg import HeisenbergGenerator - sage: p2 = HeisenbergGenerator('p', 2) - sage: q2 = HeisenbergGenerator('q', 2) - sage: p3 = HeisenbergGenerator('p', 3) - sage: p2 < p3 - True - sage: p2 < q2 - True - """ - if isinstance(rhs, HeisenbergGenerator): - return self._name < rhs._name or (self._name == rhs._name and self._i < rhs._i) - return False - -class HeisenbergAlgebra_abstract: - """ - The common methods for the (non-matrix) Heisenberg algebras. - """ + IndexedGenerators.__init__(self, I, prefix='', bracket=False, + latex_bracket=False, string_quotes=False) def p(self, i): """ The generator `p_i`. @@ -153,7 +64,7 @@ def p(self, i): sage: L.p(2) p2 """ - return self.element_class(self, {HeisenbergGenerator('p', i): self.base_ring().one()}) + return self.element_class(self, {('p', i): self.base_ring().one()}) def q(self, i): """ @@ -165,7 +76,7 @@ def q(self, i): sage: L.q(2) q2 """ - return self.element_class(self, {HeisenbergGenerator('q', i): self.base_ring().one()}) + return self.element_class(self, {('q', i): self.base_ring().one()}) def z(self): """ @@ -177,7 +88,7 @@ def z(self): sage: L.z() z """ - return self.element_class(self, {HeisenbergGenerator('z'): self.base_ring().one()}) + return self.element_class(self, {'z': self.base_ring().one()}) def bracket_on_basis(self, x, y): """ @@ -185,86 +96,67 @@ def bracket_on_basis(self, x, y): EXAMPLES:: - sage: from sage.algebras.lie_algebras.heisenberg import HeisenbergGenerator sage: H = lie_algebras.Heisenberg(QQ, 3) - sage: p1 = HeisenbergGenerator('p', 1) - sage: q1 = HeisenbergGenerator('q', 1) + sage: p1 = ('p', 1) + sage: q1 = ('q', 1) sage: H.bracket_on_basis(p1, q1) z """ - if x._name == 'p' and y._name == 'q' and x._i == y._i: + if x == 'z' or y == 'z': + return self.zero() + if x[0] == 'p' and y[0] == 'q' and x[1] == y[1]: return self.z() return self.zero() - class Element(LieAlgebraElement): - """ - An element in the Heisenberg Lie algebra. - """ - def _repr_(self): - """ - Return a string representation of ``self``. - - EXAMPLES:: - """ - if not self._monomial_coefficients: - return '0' - return repr_lincomb(self.list()) - -class HeisenbergAlgebra(HeisenbergAlgebra_abstract, FinitelyGeneratedLieAlgebra): - """ - A Heisenberg algebra defined using structure coefficients. - - The Heisenberg algebra is the Lie algebra generated by `p_i`, `q_i`, and - `z` with the following relations: - - .. MATH:: - - [p_i, q_j] = \delta_{ij} z, \quad [p_i, z] = [q_i, z] = [p_i, p_j] - = [q_i, q_j] = 0. - - .. NOTE:: - - The relations `[p_i, q_j] = \delta_{ij} z`, `[p_i, z] = 0`, and - `[q_i, z] = 0` are known as canonical commutation relations. See - :wikipedia:`Canonical_commutation_relations`. + def _repr_term(self, m): + r""" + Return a string representation of the term indexed by ``m``. - INPUT: + EXAMPLES:: - - ``R`` -- the base ring - - ``n`` -- the rank of the Heisenberg algebra + sage: H = lie_algebras.Heisenberg(QQ, 3) + sage: H._repr_term(('p', 1)) + 'p1' + sage: H._repr_term('z') + 'z' + """ + if isinstance(m, str): + return m + return m[0] + str(m[1]) - REFERENCES: + def _latex_term(self, m): + r""" + Return a string representation of the term indexed by ``m``. - - :wikipedia:`Heisenberg_algebra` + EXAMPLES:: - EXAMPLES:: + sage: H = lie_algebras.Heisenberg(QQ, 3) + sage: H._latex_term(('p', 1)) + 'p_{1}' + sage: H._latex_term('z') + 'z' + """ + if isinstance(m, str): + return m + return "%s_{%s}" % m # else it is a tuple of length 2 - sage: L = lie_algebras.Heisenberg(QQ, 2) +class HeisenbergAlgebra_fd: """ - def __init__(self, R, n): + Common methods for finite-dimensional Heisenberg algebras. + """ + def __init__(self, n): """ Initialize ``self``. - EXAMPLES:: + INPUT: - sage: L = lie_algebras.Heisenberg(QQ, 2) - sage: TestSuite(L).run() - """ - self._n = n - names = ['p%s'%i for i in range(1,n+1)] + ['q%s'%i for i in range(1,n+1)] #+ ['z'] - FinitelyGeneratedLieAlgebra.__init__(self, R, names, - category=LieAlgebras(R).FiniteDimensional().WithBasis()) + - ``n`` -- the rank - def _repr_(self): - """ - Return a string representation of ``self``. + TESTS:: - EXAMPLES:: - - sage: lie_algebras.Heisenberg(QQ, 3) - Heisenberg algebra of rank 3 over Rational Field + sage: H = lie_algebras.Heisenberg(QQ, 3) # indirect doctest """ - return "Heisenberg algebra of rank {0} over {1}".format(self._n, self.base_ring()) + self._n = n @cached_method def gens(self): @@ -289,10 +181,10 @@ def gen(self, i): EXAMPLES:: sage: H = lie_algebras.Heisenberg(QQ, 2) - sage: H.gen(2) - q1 - sage: H.gen(4) - z + sage: H.gen(0) + p1 + sage: H.gen(3) + q2 """ return self.gens()[i] @@ -331,6 +223,63 @@ def basis(self): d['z'] = self.z() return Family(d) +class HeisenbergAlgebra(HeisenbergAlgebra_fd, HeisenbergAlgebra_abstract, FinitelyGeneratedLieAlgebra): + """ + A Heisenberg algebra defined using structure coefficients. + + The Heisenberg algebra is the Lie algebra generated by `p_i`, `q_i`, and + `z` with the following relations: + + .. MATH:: + + [p_i, q_j] = \delta_{ij} z, \quad [p_i, z] = [q_i, z] = [p_i, p_j] + = [q_i, q_j] = 0. + + .. NOTE:: + + The relations `[p_i, q_j] = \delta_{ij} z`, `[p_i, z] = 0`, and + `[q_i, z] = 0` are known as canonical commutation relations. See + :wikipedia:`Canonical_commutation_relations`. + + INPUT: + + - ``R`` -- the base ring + - ``n`` -- the rank of the Heisenberg algebra + + REFERENCES: + + - :wikipedia:`Heisenberg_algebra` + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, 2) + """ + def __init__(self, R, n): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, 2) + sage: TestSuite(L).run() + """ + HeisenbergAlgebra_fd.__init__(self, n) + names = ['p%s'%i for i in range(1,n+1)] + ['q%s'%i for i in range(1,n+1)] #+ ['z'] + FinitelyGeneratedLieAlgebra.__init__(self, R, names, + category=LieAlgebras(R).FiniteDimensional().WithBasis()) + HeisenbergAlgebra_abstract.__init__(self, names) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: lie_algebras.Heisenberg(QQ, 3) + Heisenberg algebra of rank 3 over Rational Field + """ + return "Heisenberg algebra of rank {0} over {1}".format(self._n, self.base_ring()) + class InfiniteHeisenbergAlgebra(HeisenbergAlgebra_abstract, InfinitelyGeneratedLieAlgebra): """ The infinite Heisenberg algebra. @@ -347,7 +296,10 @@ def __init__(self, R): sage: L = lie_algebras.Heisenberg(QQ, oo) sage: TestSuite(L).run() """ - InfinitelyGeneratedLieAlgebra.__init__(self, R, category=LieAlgebras(R).WithBasis()) + S = CartesianProduct(PositiveIntegers(), ['p','q']) + cat = LieAlgebras(R).WithBasis() + InfinitelyGeneratedLieAlgebra.__init__(self, R, index_set=S, category=cat) + HeisenbergAlgebra_abstract.__init__(self, S) def _repr_(self): """ @@ -368,7 +320,7 @@ def _an_element_(self): sage: L = lie_algebras.Heisenberg(QQ, oo) sage: L._an_element_() - p2 + q2 - 1/2*q3 + z + z + p2 + q2 - 1/2*q3 """ c = self.base_ring().an_element() return self.p(2) + self.q(2) - c * self.q(3) + self.z() @@ -381,10 +333,11 @@ def lie_algebra_generators(self): sage: L = lie_algebras.Heisenberg(QQ, oo) sage: L.lie_algebra_generators() + Lazy family (generator map(i))_{i in Cartesian product of + Positive integers, ['p', 'q']} """ - gen_func = lambda i, l: getattr(self, l)(i) S = CartesianProduct(PositiveIntegers(), ['p','q']) - return Family(S, gen_func, name='generator map') + return Family(S, self.monomial, name='generator map') def basis(self): """ @@ -394,21 +347,17 @@ def basis(self): sage: L = lie_algebras.Heisenberg(QQ, oo) sage: L.basis() - Disjoint union of Family - (Lazy family ((i))_{i in Positive integers}, - Lazy family ((i))_{i in Positive integers}, - Family (z,)) + Lazy family (basis map(i))_{i in Disjoint union of + Family ({'z'}, Cartesian product of Positive integers, ['p', 'q'])} """ - from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets - p = Family(PositiveIntegers(), self.p) - q = Family(PositiveIntegers(), self.q) - z = Family([self.z()]) - return DisjointUnionEnumeratedSets([p, q, z]) + S = CartesianProduct(PositiveIntegers(), ['p','q']) + I = DisjointUnionEnumeratedSets([Set(['z']), S]) + return Family(I, self.monomial, name="basis map") ####################################################### ## Finite rank Heisenberg algebra using matrices -class HeisenbergAlgebra_matrix(LieAlgebraFromAssociative, HeisenbergAlgebra): +class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): r""" A Heisenberg algebra represented using matrices. @@ -452,6 +401,18 @@ class HeisenbergAlgebra_matrix(LieAlgebraFromAssociative, HeisenbergAlgebra): - ``R`` -- the base ring - ``n`` -- the size of the matrices + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, 1, representation="matrix") + sage: p = L.p(1) + sage: q = L.q(1) + sage: z = L.bracket(p, q); z + [0 0 1] + [0 0 0] + [0 0 0] + sage: z == L.z() + True """ def __init__(self, R, n): """ @@ -462,16 +423,16 @@ def __init__(self, R, n): sage: L = lie_algebras.Heisenberg(QQ, 2, representation="matrix") sage: TestSuite(L).run() """ - self._n = n + HeisenbergAlgebra_fd.__init__(self, n) MS = MatrixSpace(R, n+2, sparse=True) one = R.one() - p = [MS({(0,i):one}) for i in range(1, n+1)] - q = [MS({(i,n+1):one}) for i in range(1, n+1)] - names = ['p%s'%i for i in range(n)] + ['q%s'%i for i in range(n)] + ['z'] - LieAlgebraFromAssociative.__init__(self, R, MS, tuple(p + q + [MS({(0,n+1):one})]), tuple(names)) - self._p = self.gens()[:n] - self._q = self.gens()[n:2*n] - self._z = self.gen(2*n) + p = tuple(MS({(0,i):one}) for i in range(1, n+1)) + q = tuple(MS({(i,n+1):one}) for i in range(1, n+1)) + names = tuple('p%s'%i for i in range(1,n+1)) + names = names + tuple('q%s'%i for i in range(1,n+1)) + ('z',) + cat = LieAlgebras(R).FiniteDimensional().WithBasis() + LieAlgebraFromAssociative.__init__(self, R, MS, p + q + (MS({(0,n+1):one}),), + names=names, category=cat) def _repr_(self): """ @@ -491,12 +452,12 @@ def p(self, i): EXAMPLES:: sage: L = lie_algebras.Heisenberg(QQ, 1, representation="matrix") - sage: L.p(0) + sage: L.p(1) [0 1 0] [0 0 0] [0 0 0] """ - return self._p[i] + return self._gens['p%s'%i] def q(self, i): r""" @@ -505,12 +466,12 @@ def q(self, i): EXAMPLES:: sage: L = lie_algebras.Heisenberg(QQ, 1, representation="matrix") - sage: L.q(0) + sage: L.q(1) [0 0 0] [0 0 1] [0 0 0] """ - return self._q[i] + return self._gens['q%s'%i] def z(self): """ @@ -524,21 +485,5 @@ def z(self): [0 0 0] [0 0 0] """ - return self._z - - def bracket_on_basis(self, x, y): - """ - Return the bracket of basis elements indexed by ``x`` and ``y``. - - EXAMPLES:: - - sage: L = lie_algebras.Heisenberg(QQ, 1, representation="matrix") - sage: p = matrix(QQ, 3, 3, {(0,1):1}) - sage: q = matrix(QQ, 3, 3, {(1,2):1}) - sage: L.bracket_on_basis(p, q) - [0 0 1] - [0 0 0] - [0 0 0] - """ - return self(x*y - y*x) + return self._gens['z'] diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 9cdd25e7231..cfd71d3f489 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -37,8 +37,8 @@ from sage.categories.homset import Hom from sage.algebras.free_algebra import FreeAlgebra -from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, \ - LieBracket, LieAlgebraElement, LieAlgebraElementWrapper +from sage.algebras.lie_algebras.lie_algebra_element import (LieAlgebraElement, + LieAlgebraElementWrapper) from sage.rings.all import ZZ from sage.rings.ring import Ring from sage.rings.integer import Integer @@ -491,6 +491,8 @@ def lie_algebra_generators(self): """ return Family(self._indices, self.monomial, name="monomial map") + Element = LieAlgebraElement # Default for all Lie algebras + class FinitelyGeneratedLieAlgebra(LieAlgebra): """ An fintely generated Lie algebra. @@ -722,9 +724,10 @@ def __init__(self, R, assoc, gens, names=None, index_set=None, category=None): # We register the coercion here since the UEA already exists self.lift.register_as_coercion() if isinstance(gens, dict): - F = Family(self._indices, lambda i: gens[i]) + F = Family(self._indices, lambda i: self.element_class(self, gens[i])) else: - F = Family({self._indices[i]: v for i,v in enumerate(gens)}) + F = Family({self._indices[i]: self.element_class(self, v) + for i,v in enumerate(gens)}) self._gens = F def _repr_option(self, key): diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index 2a538fff83f..2c4347a3e14 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -31,193 +31,6 @@ from sage.combinat.free_module import CombinatorialFreeModuleElement from sage.structure.element_wrapper import ElementWrapper -@total_ordering -class LieGenerator(SageObject): # Does this need to be SageObject? - """ - A wrapper around an object so it can compare with :class:`LieBracket`. - """ - __metaclass__ = ClasscallMetaclass - - @staticmethod - def __classcall_private__(cls, name): - """ - Return ``name`` if it is a :class:`LieGenerator`, otherwise construct - a new object. - - EXAMPLES:: - """ - if isinstance(name, LieGenerator): - return name - return typecall(cls, name) - - def __init__(self, name): - """ - Initalize ``self``. - - EXAMPLES:: - """ - self._name = name - - def _repr_(self): - """ - Return a string representation of ``self``. - - EXAMPLES:: - """ - return self._name - - def __eq__(self, rhs): - """ - Compare equals. - - EXAMPLES:: - """ - return isinstance(rhs, LieGenerator) and self._name == rhs._name - - def __lt__(self, rhs): - """ - Compare less than. - - EXAMPLES:: - """ - if isinstance(rhs, LieGenerator): - return self._name < rhs._name - if isinstance(rhs, LieBracket): - return not rhs.__lt__(self) # Clearly self != rhs - return False - - def _im_gens_(self, codomain, im_gens, names): - """ - Return the image of ``self``. - - EXAMPLES:: - """ - x = im_gens[names.index(self._name)] - return im_gens[names.index(self._name)] - - def to_word(self): - """ - Return ``self`` as a word in the variable names. - - EXAMPLES:: - """ - return [self._name] - -@total_ordering -class LieBracket(SageObject): # Does this need to be SageObject? - """ - A Lie bracket. This is the building blocks for Lie algebra elements. - """ - def __init__(self, l, r): - """ - Initialize ``self``. - - EXAMPLES:: - """ - self._left = l - self._right = r - - def _repr_(self): - """ - Return a string representation of ``self``. - - EXAMPLES:: - """ - return "[{!s}, {!s}]".format(self._left, self._right) - - def _latex_(self): - r""" - Return a `\LaTeX` representation of ``self``. - - EXAMPLES:: - """ - from sage.misc.latex import latex - return "\\left[" + latex(self._left) + "," + latex(self._right) + "\\right]" - - def __getitem__(self, i): - r""" - Return the `i`-th item of ``self``. - - EXAMPLES:: - """ - if i == 0: - return self._left - if i == 1: - return self._right - raise IndexError("i must be either 0 or 1") - - def __eq__(self, rhs): - """ - Check equality. - - EXAMPLES:: - """ - if isinstance(rhs, list): - if len(rhs) != 2: - return False - return self._left == rhs[0] and self._right == rhs[1] - - if not isinstance(rhs, LieBracket): - return False - return self._left == rhs._left and self._right == rhs._right - - def __lt__(self, rhs): - """ - Check less than. - - EXAMPLES:: - """ - if not isinstance(rhs, LieBracket): - return False - if self._left < rhs._left: - return True - elif self._left == rhs._left: - return self._right < rhs._right - return False - - def __hash__(self): - """ - Return the hash value of ``self``. - - EXAMPLES:: - """ - return hash((self._left, self._right)) - - def _im_gens_(self, codomain, im_gens, names): - """ - Return the image of ``self``. - - EXAMPLES:: - """ - return codomain.bracket(self._left._im_gens_(codomain, im_gens, names), - self._right._im_gens_(codomain, im_gens, names)) - - def lift(self, UEA_gens_dict): - """ - Lift ``self`` to the universal enveloping algebra. - - EXAMPLES:: - """ - if isinstance(self._left, LieBracket): - l = self._left.lift(UEA_gens_dict) - else: - l = UEA._gens_dict[self._left] - - if isinstance(self._right, LieBracket): - r = self._right.lift(UEA_gens_dict) - else: - r = UEA_gens_dict[self._right] - - return l*r - r*l - - def to_word(self): - """ - Return ``self`` as a word expressed in the variable names. - - EXAMPLES:: - """ - return self._left.to_word() + self._right.to_word() - # TODO: Have the other classes inherit from this? # TODO: Should this be a mixin class (or moved to the category)? class LieAlgebraElement_generic(ModuleElement): @@ -312,10 +125,7 @@ def lift(self): if not self: return s for t, c in self._monomial_coefficients.iteritems(): - if isinstance(t, LieBracket): - s += c * t.lift(gen_dict) - else: - s += c * gen_dict[t._name] + s += c * gen_dict[t._name] return s def is_constant(self): diff --git a/src/sage/algebras/lie_algebras/virasoro.py b/src/sage/algebras/lie_algebras/virasoro.py index 31361e12606..ba8ec8d44ed 100644 --- a/src/sage/algebras/lie_algebras/virasoro.py +++ b/src/sage/algebras/lie_algebras/virasoro.py @@ -28,7 +28,7 @@ from sage.sets.set import Set from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.structure.indexed_generators import IndexedGenerators -from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, LieAlgebraElement +from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement from sage.algebras.lie_algebras.lie_algebra import InfinitelyGeneratedLieAlgebra class LieAlgebraRegularVectorFields(InfinitelyGeneratedLieAlgebra, IndexedGenerators): @@ -72,6 +72,10 @@ def _repr_(self): """ return "The Lie algebra of regular vector fields over {}".format(self.base_ring()) + # For compatibility with CombinatorialFreeModuleElement + _repr_term = IndexedGenerators._repr_generator + _latex_term = IndexedGenerators._latex_generator + @cached_method def lie_algebra_generators(self): """ @@ -81,6 +85,7 @@ def lie_algebra_generators(self): sage: L = lie_algebras.regular_vector_fields(QQ) sage: L.lie_algebra_generators() + Lazy family (generator map(i))_{i in Integer Ring} """ return Family(self._indices, self.monomial, name='generator map') @@ -93,11 +98,9 @@ def bracket_on_basis(self, i, j): sage: L = lie_algebras.regular_vector_fields(QQ) sage: L.bracket_on_basis(2, -2) -4*d[0] - sage: d2 = L.d(2) - sage: d4 = L.d(4) - sage: d2.bracket(d4) + sage: L.bracket_on_basis(2, 4) 2*d[6] - sage: L.bracket(d4, d4) + sage: L.bracket_on_basis(4, 4) 0 """ return self.term(i + j, j - i) @@ -126,8 +129,6 @@ def some_elements(self): """ return [self.monomial(0), self.monomial(2), self.monomial(-2), self.an_element()] - Element = LieAlgebraElement - class VirasoroAlgebra(InfinitelyGeneratedLieAlgebra, IndexedGenerators): r""" The Virasoro algebra. @@ -148,11 +149,6 @@ class VirasoroAlgebra(InfinitelyGeneratedLieAlgebra, IndexedGenerators): sage: d = lie_algebras.VirasoroAlgebra(QQ) - TESTS:: - - sage: d = lie_algebras.VirasoroAlgebra(QQ) - sage: TestSuite(d).run() - REFERENCES: - :wikipedia:`Virasoro_algebra` @@ -163,13 +159,44 @@ def __init__(self, R): EXAMPLES:: - sage: L = lie_algebras.regular_vector_fields(QQ) - sage: TestSuite(L).run() + sage: d = lie_algebras.VirasoroAlgebra(QQ) + sage: TestSuite(d).run() """ cat = LieAlgebras(R).WithBasis() - I = DisjointUnionEnumeratedSets([Set(['c']), ZZ]) - InfinitelyGeneratedLieAlgebra.__init__(self, R, index_set=I, category=cat) - IndexedGenerators.__init__(self, I, prefix='d', bracket='[') + InfinitelyGeneratedLieAlgebra.__init__(self, R, index_set=ZZ, category=cat) + IndexedGenerators.__init__(self, ZZ, prefix='d', bracket='[') + + def _repr_term(self, m): + """ + Return a string representation of the term indexed by ``m``. + + EXAMPLES:: + + sage: d = lie_algebras.VirasoroAlgebra(QQ) + sage: d._repr_term('c') + 'c' + sage: d._repr_term(2) + 'd[2]' + """ + if isinstance(m, str): + return m + return IndexedGenerators._repr_generator(self, m) + + def _latex_term(self, m): + r""" + Return a `\LaTeX` representation of the term indexed by ``m``. + + EXAMPLES:: + + sage: d = lie_algebras.VirasoroAlgebra(QQ) + sage: d._latex_term('c') + 'c' + sage: d._latex_term(2) + 'd_{2}' + """ + if isinstance(m, str): + return m + return IndexedGenerators._latex_generator(self, m) def _repr_(self): """ @@ -189,14 +216,36 @@ def lie_algebra_generators(self): EXAMPLES:: - sage: L = lie_algebras.regular_vector_fields(QQ) - sage: L.lie_algebra_generators() + sage: d = lie_algebras.VirasoroAlgebra(QQ) + sage: d.lie_algebra_generators() + Lazy family (generator map(i))_{i in Integer Ring} """ return Family(self._indices, self.monomial, name='generator map') + @cached_method + def basis(self): + """ + Return a basis of ``self``. + + EXAMPLES:: + + sage: d = lie_algebras.VirasoroAlgebra(QQ) + sage: d.basis() + Lazy family (basis map(i))_{i in Disjoint union of + Family ({'c'}, Integer Ring)} + """ + I = DisjointUnionEnumeratedSets([Set(['c']), ZZ]) + return Family(I, self.monomial, name='basis map') + def d(self, i): """ Return the element `d_i` in ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.VirasoroAlgebra(QQ) + sage: L.d(2) + d[2] """ return self.monomial(i) @@ -210,7 +259,7 @@ def c(self): sage: d.c() c """ - return self.monomial(c) + return self.monomial('c') def bracket_on_basis(self, i, j): """ @@ -219,17 +268,14 @@ def bracket_on_basis(self, i, j): EXAMPLES:: sage: d = lie_algebras.VirasoroAlgebra(QQ) - sage: c = d.c() - sage: d2 = d.d(2) - sage: dm2 = d.d(-2) - sage: c.bracket(d2) # indirect doctest + sage: d.bracket_on_basis('c', 2) 0 - sage: d2.bracket(dm2) + sage: d.bracket_on_basis(2, -2) -4*d[0] - 1/2*c """ if i == 'c' or j == 'c': return self.zero() - ret = self._from_dict({RegVecFieldsGen(i + j): j-i}) + ret = self._from_dict({i + j: j-i}) if i == -j: ret += (j**3 - j) / 12 * self.c() return ret @@ -240,9 +286,9 @@ def _an_element_(self): EXAMPLES:: - sage: L = lie_algebras.VirasoroAlgebra(QQ) - sage: L.an_element() - d[-1] + d[0] - 3*d[1] + sage: d = lie_algebras.VirasoroAlgebra(QQ) + sage: d.an_element() + d[-1] + d[0] - 1/2*d[1] + c """ d = self.monomial return d(0) - self.base_ring().an_element()*d(1) + d(-1) + d('c') @@ -253,12 +299,10 @@ def some_elements(self): EXAMPLES:: - sage: L = lie_algebras.VirasoroAlgebra(QQ) - sage: L.some_elements() - [d[0], d[2], d[-2], d[-1] + d[0] - 3*d[1]] + sage: d = lie_algebras.VirasoroAlgebra(QQ) + sage: d.some_elements() + [d[0], d[2], d[-2], c, d[-1] + d[0] - 1/2*d[1] + c] """ d = self.monomial return [d(0), d(2), d(-2), d('c'), self.an_element()] - Element = LieAlgebraElement - From 913e95f287b4318a606e3aa8078e86846906cdd8 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 24 Sep 2014 09:30:24 -0500 Subject: [PATCH 014/223] Some cleanup on lie_algebra.py. --- src/sage/algebras/lie_algebras/lie_algebra.py | 138 +++++++++--------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index cfd71d3f489..ebd8480ac3e 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -103,7 +103,9 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): to create the Lie algebra of `\QQ^3` under the Lie bracket of `\times` (cross-product):: - sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) + sage: L. = LieAlgebra(QQ, {('x','y'): {'z':1}, + ....: ('y','z'): {'x':1}, + ....: ('z','x'): {'y':1}}) sage: L Lie algebra on 3 generators (x, y, z) over Rational Field @@ -111,12 +113,13 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): This will automatically lift up to the universal enveloping algebra. To get elements in the Lie algebra, you must use :meth:`bracket`:: - sage: L = LieAlgebra(QQ, {('e','h'):{'e':-2}, ('f','h'):{'f':2}, ('e','f'):{'h':1}} + sage: L = LieAlgebra(QQ, {('e','h'): {'e':-2}, ('f','h'): {'f':2}, + ....: ('e','f'): {'h':1}}) sage: h,e,f = L.gens() sage: L.bracket(h, e) - 2*e1 + 2*e sage: elt = h*e; elt - h1*e1 + h*e sage: elt.parent() Noncommutative Multivariate Polynomial Ring in h1, e1, f1 over Rational Field, nc-relations: {f1*e1: e1*f1 - h1, e1*h1: h1*e1 - 2*e1, f1*h1: h1*f1 + 2*f1} @@ -149,7 +152,8 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): sage: L = LieAlgebra(QQ, 'x,y,z'); L # not tested #16823 Free Lie algebra generated by (x, y, z) over Rational Field sage: P. = LieAlgebra(QQ, representation="polynomial"); P - Lie algebra on 3 generators (a, b, c) over Rational Field + Lie algebra generated by (a, c, b) from + Free Algebra on 3 generators (a, b, c) over Rational Field We currently (:trac:`16823`) have the free Lie algebra given in the polynomial representation, which is the Lie algebra of the Free algebra. @@ -170,23 +174,22 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): """ @staticmethod def __classcall_private__(cls, R, arg0=None, arg1=None, names=None, - index_set=None, **kwds): + index_set=None, abelian=False, **kwds): """ Select the correct parent based upon input. """ + check_assoc = lambda A: (isinstance(A, (Ring, MatrixSpace)) + or A in Rings() + or A in Algebras(R).Associative()) # Check if we need to swap the arguments - if arg0 in ZZ or arg1 in Algebras(R): + if arg0 in ZZ or check_assoc(arg1): arg0, arg1 = arg1, arg0 - # Check if a Cartan type was passed, if so, set that to be the first arg - if "cartan_type" in kwds: - arg0 = CartanType(kwds["cartan_type"]) - # Parse the first argument # ----- if isinstance(arg0, dict): - if len(arg0) == 0: + if not arg0: from sage.algebras.lie_algebras.structure_coefficients import AbelianLieAlgebra return AbelianLieAlgebra(R, names, index_set) elif isinstance(arg0.keys()[0], (list,tuple)): @@ -199,7 +202,7 @@ def __classcall_private__(cls, R, arg0=None, arg1=None, names=None, A = gens[0].parent() return LieAlgebraFromAssociative(R, A, gens, names, index_set) - if isinstance(arg0, (Ring, MatrixSpace)) or arg0 in Rings(): + if check_assoc(arg0): if arg1 is None: gens = arg0.gens() if names is None: @@ -244,7 +247,7 @@ def __classcall_private__(cls, R, arg0=None, arg1=None, names=None, names = tuple(names.split(',')) # Assume it is some structure coefficients from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients - return LieAlgebraWithStructureCoefficients(R, arg1, names, index_set) + return LieAlgebraWithStructureCoefficients(R, arg1, names, index_set, **kwds) # Otherwise it must be either a free or abelian Lie algebra @@ -261,10 +264,11 @@ def __classcall_private__(cls, R, arg0=None, arg1=None, names=None, if arg1 != len(names): raise ValueError("the number of names must equal the number of generators") - if kwds.get("abelian", False): + if abelian: from sage.algebras.lie_algebras.structure_coefficients import AbelianLieAlgebra return AbelianLieAlgebra(R, names, index_set) + # Otherwise it is the free Lie algebra rep = kwds.get("representation", "bracket") if rep == "polynomial": # Construct the free Lie algebra from polynomials in the @@ -320,10 +324,10 @@ def _element_constructor_(self, x): EXAMPLES:: - sage: L. = LieAlgebra(QQ) + sage: L. = LieAlgebra(QQ, representation="polynomial") sage: elt = L([x, y]); elt - [x, y] - sage: elt.parent() is L.Hall() + x*y - y*x + sage: elt.parent() is L True """ if isinstance(x, list) and len(x) == 2: @@ -343,10 +347,9 @@ def __getitem__(self, x): EXAMPLES:: - sage: L. = LieAlgebra(QQ) - sage: H = L.Hall() - sage: H[x, [y, x]] - -[x, [x, y]] + sage: L. = LieAlgebra(QQ, representation="polynomial") + sage: L[x, [y, x]] + -x^2*y + 2*x*y*x - y*x^2 """ if isinstance(x, tuple) and len(x) == 2: return self(x[0])._bracket_(self(x[1])) @@ -387,25 +390,28 @@ def _coerce_map_from_(self, R): def zero(self): """ Return the element `0`. - """ - return self.element_class(self, {}) - zero_element = zero + EXAMPLES:: - def gen(self, i): + sage: L. = LieAlgebra(QQ, representation="polynomial") + sage: L.zero() + 0 """ - The ``i``-th generator of the Lie algebra. + return self.element_class(self, {}) - EXAMPLES:: - """ - G = self.lie_algebra_generators() - return G[i] + zero_element = zero # TODO: Find a better place for this method? # TODO: Use IndexedGenerators? def indices(self): """ Return the indices of the basis of ``self``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, representation="polynomial") + sage: L.indices() + {'x', 'y'} """ return self._indices @@ -428,37 +434,6 @@ def _from_dict(self, d, coerce=False, remove_zeros=True): ``coeff``s may be zero and should therefore be removed EXAMPLES:: - - sage: e = SymmetricFunctions(QQ).elementary() - sage: s = SymmetricFunctions(QQ).schur() - sage: a = e([2,1]) + e([1,1,1]); a - e[1, 1, 1] + e[2, 1] - sage: s._from_dict(a.monomial_coefficients()) - s[1, 1, 1] + s[2, 1] - - If the optional argument ``coerce`` is ``True``, then the - coefficients are coerced into the base ring of ``self``:: - - sage: part = Partition([2,1]) - sage: d = {part:1} - sage: a = s._from_dict(d,coerce=True); a - s[2, 1] - sage: a.coefficient(part).parent() - Rational Field - - With ``remove_zeros=True``, zero coefficients are removed:: - - sage: s._from_dict({part:0}) - 0 - - .. WARNING:: - - With ``remove_zeros=False``, it is assumed that no - coefficient of the dictionary is zero. Otherwise, this may - lead to illegal results:: - - sage: list(s._from_dict({part:0}, remove_zeros=False)) - [([2, 1], 0)] """ assert isinstance(d, dict) if coerce: @@ -471,12 +446,16 @@ def _from_dict(self, d, coerce=False, remove_zeros=True): def monomial(self, i): """ Return the monomial indexed by ``i``. + + EXAMPLES:: """ return self.element_class(self, {i: self.base_ring().one()}) def term(self, i, c=None): """ Return the term indexed by ``i`` with coefficient ``c``. + + EXAMPLES:: """ if c is None: c = self.base_ring().one() @@ -488,9 +467,15 @@ def term(self, i, c=None): def lie_algebra_generators(self): """ Return the generators of ``self`` as a Lie algebra. + + EXAMPLES:: """ return Family(self._indices, self.monomial, name="monomial map") + # FIXME: Placeholder -- Should this be in the category? + def free_module(self): + return NotImplemented + Element = LieAlgebraElement # Default for all Lie algebras class FinitelyGeneratedLieAlgebra(LieAlgebra): @@ -675,7 +660,7 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): the result of :meth:`universal_enveloping_algebra()` can be too large:: sage: R. = FreeAlgebra(QQ, 3) - sage: L = LieAlgebra(QQ, R, [a,b]) + sage: L = LieAlgebra(QQ, R, [a,b], names='x,y') sage: L.universal_enveloping_algebra() is R True """ @@ -696,7 +681,8 @@ def __classcall_private__(cls, R, A, gens, names=None, index_set=None, category= gens = map(A, gens) try: # Try to make things, such as matrices, immutable (since we need to hash them) - gens = map(lambda x: x.set_immutable(), gens) + for g in gens: + g.set_immutable() except AttributeError: pass @@ -729,6 +715,7 @@ def __init__(self, R, assoc, gens, names=None, index_set=None, category=None): F = Family({self._indices[i]: self.element_class(self, v) for i,v in enumerate(gens)}) self._gens = F + # TODO: Do we want to store the original generators? def _repr_option(self, key): """ @@ -755,8 +742,8 @@ def _repr_(self): sage: S = GroupAlgebra(G, QQ) sage: L. = LieAlgebra(QQ, S) """ - return "Lie algebra from {} generated by {}".format( - self._assoc, tuple(self._gens)) + return "Lie algebra generated by {} from {}".format( + tuple(self._gens), self._assoc) def _element_constructor_(self, x): """ @@ -771,9 +758,13 @@ def _element_constructor_(self, x): -(1,2) + (1,2,3) sage: elt.parent() is L True + sage: L([x, y]) + (2,3) - (1,3) """ if isinstance(x, LieAlgebraElement) and x.parent() is self: return x + if isinstance(x, list) and len(x) == 2: + return LieAlgebra._element_constructor_(self, x) return self.element_class(self, self._assoc(x)) def _construct_UEA(self): @@ -801,16 +792,24 @@ def lie_algebra_generators(self): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) sage: L. = LieAlgebra(QQ, S) + sage: L.lie_algebra_generators() + Finite family {'y': (1,2), 'x': (1,2,3)} """ return self._gens def monomial(self, i): """ Return the monomial indexed by ``i``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, representation="polynomial") + sage: L.monomial('x') + x """ if i not in self._indices: raise ValueError("not an index") - return LieAlgebra.monomial(self, self._gens[i]) + return self._gens[i] def term(self, i, c=None): """ @@ -818,7 +817,7 @@ def term(self, i, c=None): """ if i not in self._indices: raise ValueError("not an index") - return LieAlgebra.term(self, self._gens[i], c) + return c * self._gens[i] @cached_method def zero_element(self): @@ -898,7 +897,8 @@ def _bracket_(self, rhs): [0 0 0] [0 0 0] """ - return self.__class__(self.parent(), self.value*rhs.value - rhs.value*self.value) + ret = self.value * rhs.value - rhs.value * self.value + return self.__class__(self.parent(), ret) def lift(self): """ From cbe4363d7cdf9aace16ebfc4d7513dbbe4b8b7a8 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 22 Oct 2014 14:38:50 -0700 Subject: [PATCH 015/223] Fixing some more things. --- src/sage/algebras/lie_algebras/examples.py | 36 +++++++++++++++++++ src/sage/algebras/lie_algebras/lie_algebra.py | 27 ++++++++------ .../lie_algebras/lie_algebra_element.py | 28 +++++++-------- .../lie_algebras/structure_coefficients.py | 20 +++++++++-- 4 files changed, 83 insertions(+), 28 deletions(-) diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index 9e7bbe9e256..4a0bf34ddcb 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -104,13 +104,16 @@ def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): if isinstance(names, str): names = names.split(',') names = tuple(names) + if n == 0: from sage.algebras.lie_algebras.structure_coefficients import AbelianLieAlgebra return AbelianLieAlgebra(R, names) + if n == 1: L = three_dimensional(R, 0, 1, 0, 0, names) # Strictly upper triangular matrices L.rename("Lie algebra of 3x3 strictly upper triangular matrices over {}".format(R)) return L + if n == 2: if a is None: raise ValueError("The parameter 'a' must be specified") @@ -127,8 +130,10 @@ def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): L = LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) L.rename("Lie algebra of dimension 3 and rank 2 with parameter {} over {}".format(a, R)) return L + if n == 3: #return sl(R, 2) + from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients E = names[0] F = names[1] H = names[2] @@ -136,8 +141,39 @@ def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): L = LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) L.rename("sl2 over {}".format(R)) return L + raise ValueError("Invalid rank") +# This can probably be replaced (removed) by sl once the classical Lie +# algebras are implemented +def sl(R, n, representation='bracket'): + r""" + Return the Lie algebra `\mathfrak{sl}_n`. + + EXAMPLES:: + + sage: lie_algebras.sl(QQ, 2) + sl2 over Rational Field + """ + if n != 2: + raise NotImplementedError("only n=2 is implemented") + + if representation == 'matrix': + from sage.matrix.matrix_space import MatrixSpace + from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative + MS = MatrixSpace(R, 2) + E = MS([[0,1],[0,0]]) + F = MS([[0,0],[1,0]]) + H = MS([[1,0],[-1,0]]) + L = LieAlgebraFromAssociative(R, MS, [E, F, H], ['E', 'F', 'H']) + L.rename("sl2 as a matrix Lie algebra over {}".format(R)) + elif representation == 'bracket': + L = three_dimensional_by_rank(R, 3) + else: + raise ValueError("invalid representation") + + return L + def affine_transformations_line(R, names=['X', 'Y'], representation='bracket'): """ The Lie algebra of affine transformations of the line. diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index ebd8480ac3e..de1a6fdc7fd 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -103,9 +103,8 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): to create the Lie algebra of `\QQ^3` under the Lie bracket of `\times` (cross-product):: - sage: L. = LieAlgebra(QQ, {('x','y'): {'z':1}, - ....: ('y','z'): {'x':1}, - ....: ('z','x'): {'y':1}}) + sage: d = {('x','y'): {'z':1}, ('y','z'): {'x':1}, ('z','x'): {'y':1}} + sage: L. = LieAlgebra(QQ, d) sage: L Lie algebra on 3 generators (x, y, z) over Rational Field @@ -114,8 +113,8 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): To get elements in the Lie algebra, you must use :meth:`bracket`:: sage: L = LieAlgebra(QQ, {('e','h'): {'e':-2}, ('f','h'): {'f':2}, - ....: ('e','f'): {'h':1}}) - sage: h,e,f = L.gens() + ....: ('e','f'): {'h':1}}, names='e,f,h') + sage: e,f,h = L.gens() sage: L.bracket(h, e) 2*e sage: elt = h*e; elt @@ -537,6 +536,12 @@ def gens(self): except ValueError: return tuple(G) + def gen(self, i): + """ + Return the ``i``-th generator of ``self``. + """ + return self.gens()[i] + @lazy_attribute def _ordered_indices(self): """ @@ -707,8 +712,6 @@ def __init__(self, R, assoc, gens, names=None, index_set=None, category=None): # TODO: We should strip axioms from the category of the base ring, # such as FiniteDimensional, WithBasis FinitelyGeneratedLieAlgebra.__init__(self, R, names, index_set, category) - # We register the coercion here since the UEA already exists - self.lift.register_as_coercion() if isinstance(gens, dict): F = Family(self._indices, lambda i: self.element_class(self, gens[i])) else: @@ -717,6 +720,9 @@ def __init__(self, R, assoc, gens, names=None, index_set=None, category=None): self._gens = F # TODO: Do we want to store the original generators? + # We register the coercion here since the UEA already exists + self.lift.register_as_coercion() + def _repr_option(self, key): """ Metadata about the :meth:`_repr_` output. @@ -891,11 +897,10 @@ def _bracket_(self, rhs): sage: L.bracket(x, y) (2,3) - (1,3) - sage: L = LieAlgebra(QQ, cartan_type=['A',2], representation='matrix') + sage: L = lie_algebras.sl(QQ, 2, representation='matrix') sage: L.bracket(L.gen(0), L.gen(1)) - [0 0 1] - [0 0 0] - [0 0 0] + [ 1 0] + [ 0 -1] """ ret = self.value * rhs.value - rhs.value * self.value return self.__class__(self.parent(), ret) diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index 2c4347a3e14..692a5b68953 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -85,7 +85,8 @@ def _latex_monomial(self, m): # return '0' # return repr_lincomb(self.list(), repr_monomial=self._latex_monomial, is_latex=True) - def _mul_(self, y): + # Need to bypass the coercion model + def __mul__(self, y): """ If we are multiplying two non-zero elements, automatically lift up to the universal enveloping algebra. @@ -163,8 +164,8 @@ def __eq__(self, rhs): EXAMPLES:: - sage: L = LieAlgebra(QQ, cartan_type=['A',3], representation='matrix') - sage: L.bracket(L.e(2), L.e(1)) == -L.bracket(L.e(1), L.e(2)) + 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 """ if not isinstance(rhs, LieAlgebraElementWrapper): @@ -177,11 +178,10 @@ def _repr_(self): EXAMPLES:: - sage: L = LieAlgebra(QQ, cartan_type=['A',2], representation='matrix') - sage: L.gen(0) - [0 1 0] - [0 0 0] - [0 0 0] + sage: R = FreeAlgebra(QQ, 3, 'x,y,z') + sage: L. = LieAlgebra(QQ, R) + sage: x + y + x + y """ return repr(self.value) @@ -191,10 +191,10 @@ def _latex_(self): EXAMPLES:: - sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(QQ, R) - sage: latex(x + y) - x + y + sage: R = FreeAlgebra(QQ, 3, 'x') + sage: L. = LieAlgebra(QQ, R) + sage: latex(x0 + x1) + x_{0} + x_{1} """ from sage.misc.latex import latex return latex(self.value) @@ -284,8 +284,8 @@ def __getitem__(self, i): EXAMPLES:: - sage: L = LieAlgebra(QQ, cartan_type=['A',2], representation='matrix') - sage: m = L.e(0) + sage: L = lie_algebras.sl(QQ, 2, representation='matrix') + sage: m = L.gen(0) sage: m[0,0] 0 sage: m[0][1] diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 6893b869f60..b7f82b43e4f 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -169,17 +169,31 @@ def basis(self): """ return Family({i: self.monomial(i) for i in self._indices}) - def structure_coefficients(self): + def structure_coefficients(self, include_zeros=False): """ Return the dictonary of structure coefficients of ``self``. EXAMPLES:: - sage: L = LieAlgebra(QQ, 'x,y', {('x','y'):{'x':1}}) + sage: L = LieAlgebra(QQ, 'x,y,z', {('x','y'):{'x':1}}) sage: L.structure_coefficients() Finite family {('x', 'y'): x} + sage: L.structure_coefficients(True) + Finite family {('x', 'y'): x, ('x', 'z'): 0, ('y', 'z'): 0} """ - return self._s_coeff + if not include_zeros: + return self._s_coeff + ret = {} + zero = self.base_ring().zero() + S = dict(self._s_coeff) + for i,x in enumerate(self._indices): + for y in self._indices[i+1:]: + if x < y: + b = (x, y) + else: + b = (y, x) + ret[b] = S.get(b, zero) + return Family(ret) def dimension(self): """ From ed93f29b3abedf59d156b96bb49b297fd21969c4 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 28 Nov 2014 11:50:57 -0800 Subject: [PATCH 016/223] Created category for subalgebras of FD Lie algebras with basis. --- ...ite_dimensional_lie_algebras_with_basis.py | 33 ++++++++---- ...ite_dimensional_lie_algebras_with_basis.py | 52 ++++++++++++++----- 2 files changed, 62 insertions(+), 23 deletions(-) diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index 5e3b9c4a75c..114937b161c 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -26,7 +26,7 @@ class AbelianLieAlgebra(Parent, UniqueRepresentation): Lie algebra with basis. """ @staticmethod - def __classcall_private__(cls, R, names, M=None): + def __classcall_private__(cls, R, names, M=None, ambient=None): """ Normalize input to ensure a unique representation. @@ -47,9 +47,9 @@ def __classcall_private__(cls, R, names, M=None): raise ValueError("number of generators is not correct") else: M = M.change_ring(R) - return super(AbelianLieAlgebra, cls).__classcall__(cls, R, tuple(names), M) + return super(AbelianLieAlgebra, cls).__classcall__(cls, R, tuple(names), M, ambient) - def __init__(self, R, names, M): + def __init__(self, R, names, M, ambient): """ EXAMPLES:: @@ -59,6 +59,11 @@ def __init__(self, R, names, M): self._ordered_indices = names self._M = M cat = LieAlgebras(R).FiniteDimensional().WithBasis() + if ambient is None: + ambient = self + else: + cat = cat.Subobjects() + self._ambient = ambient Parent.__init__(self, base=R, names=names, category=cat) def _repr_(self): @@ -129,6 +134,21 @@ def basis_matrix(self): """ return self._M.basis_matrix() + def ambient(self): + """ + Return the ambient Lie algebra of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.inject_variables() + Defining a, b, c + sage: S = L.subalgebra([2*a+b, b + c], 'x,y') + sage: S.ambient() == L + True + """ + return self._ambient + def subalgebra(self, gens, names='x'): """ Return a subalgebra of ``self``. @@ -150,12 +170,7 @@ def subalgebra(self, gens, names='x'): if len(names) == 1 and len(gens) != 1: names = tuple( names[0] + str(i) for i in range(len(gens)) ) N = self._M.subspace([g.value for g in gens]) - S = AbelianLieAlgebra(self.base_ring(), names, N) - try: - S._ambient = self._ambient - except AttributeError: - S._ambient = self - return S + return AbelianLieAlgebra(self.base_ring(), names, N, self._ambient) def basis(self): """ 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 c39102d7c7e..d61cdaa581d 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -16,6 +16,7 @@ from sage.misc.cachefunc import cached_method from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.lie_algebras import LieAlgebras +from sage.categories.subobjects import SubobjectsCategory from sage.rings.all import ZZ from sage.algebras.free_algebra import FreeAlgebra from sage.sets.family import Family @@ -203,20 +204,6 @@ def structure_coefficients(self, include_zeros=False): d[(x, y)] = val return Family(d) - @abstract_method - def basis_matrix(self): - """ - Return the basis matrix of ``self``. - - EXAMPLES:: - - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.basis_matrix() - [1 0 0] - [0 1 0] - [0 0 1] - """ - def centralizer(self, S): """ Return the centralizer of ``S`` in ``self``. @@ -591,3 +578,40 @@ def adjoint_matrix(self): # In #11111 (more or less) by using matrix of a mophis basis = P.basis() return matrix([P.bracket(self, b).to_vector() for b in basis]) + class Subobjects(SubobjectsCategory): + """ + A category for subalgebras of a finite dimensional Lie algebra + with basis. + """ + class ParentMethods: + @abstract_method + def ambient(self): + """ + Return the ambient Lie algebra of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.inject_variables() + Defining a, b, c + sage: S = L.subalgebra([2*a+b, b + c], 'x,y') + sage: S.ambient() == L + True + """ + + @abstract_method + def basis_matrix(self): + """ + Return the basis matrix of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.inject_variables() + Defining a, b, c + sage: S = L.subalgebra([2*a+b, b + c], 'x,y') + sage: S.basis_matrix() + [ 1 0 -1/2] + [ 0 1 1] + """ + From b302cc1c9ebc9466b6cabc6f6e95cd1461de0855 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 28 Nov 2014 13:23:06 -0800 Subject: [PATCH 017/223] Added free_module abstract method. --- src/sage/categories/lie_algebras.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index d1af744178a..d343dae3295 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -252,6 +252,18 @@ def _construct_UEA(self): Multivariate Polynomial Ring in x0, x1, x2 over Rational Field """ + @abstract_method(optional=True) + def free_module(self): + """ + Construct the universal enveloping algebra of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.free_module() + Vector space of dimension 3 over Rational Field + """ + @lazy_attribute def lift(self): """ From c2a3a982e419c0839f1fba68bf71b1014f243547 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 28 Nov 2014 20:50:53 -0800 Subject: [PATCH 018/223] Many changes, fixes, and adding full doctest coverage. --- src/sage/algebras/catalog.py | 2 + src/sage/algebras/lie_algebras/examples.py | 30 +-- src/sage/algebras/lie_algebras/heisenberg.py | 6 +- src/sage/algebras/lie_algebras/lie_algebra.py | 253 +++++++++++------- .../lie_algebras/lie_algebra_element.py | 136 +++++----- .../lie_algebras/structure_coefficients.py | 38 +-- ...ite_dimensional_lie_algebras_with_basis.py | 52 ++-- src/sage/categories/lie_algebras.py | 45 +++- 8 files changed, 329 insertions(+), 233 deletions(-) diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index 58d7f8e5715..ccbe117587e 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -22,6 +22,7 @@ - :class:`algebras.Hall ` - :class:`algebras.IwahoriHecke ` +- :class:`algebras.Lie ` - :class:`algebras.NilCoxeter ` - :func:`algebras.Quaternion @@ -40,6 +41,7 @@ from sage.algebras.clifford_algebra import CliffordAlgebra as Clifford from sage.algebras.clifford_algebra import ExteriorAlgebra as Exterior from sage.algebras.weyl_algebra import DifferentialWeylAlgebra as DifferentialWeyl +from sage.algebras.lie_algebras.lie_algebra import LieAlgebra as Lie from sage.misc.lazy_import import lazy_import lazy_import('sage.algebras.nil_coxeter_algebra', 'NilCoxeterAlgebra', 'NilCoxeter') diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index 4a0bf34ddcb..e66280a6a9b 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -38,16 +38,16 @@ def three_dimensional(R, a, b, c, d, names=['X', 'Y', 'Z']): sage: L = lie_algebras.three_dimensional(QQ, 4, 1, -1, 2) sage: L.structure_coefficients() - {[X, Y]: ((Y, 2), (Z, 4)), [X, Z]: ((Y, 1), (Z, 2)), [Y, Z]: ((X, 1),)} + Finite family {('X', 'Y'): 2*Y + 4*Z, ('X', 'Z'): Y + 2*Z, ('Y', 'Z'): X} sage: L = lie_algebras.three_dimensional(QQ, 1, 0, 0, 0) sage: L.structure_coefficients() - {[X, Y]: ((Z, 1),)} + Finite family {('X', 'Y'): Z} sage: L = lie_algebras.three_dimensional(QQ, 0, 0, -1, -1) sage: L.structure_coefficients() - {[X, Y]: ((Y, -1),), [X, Z]: ((Y, 1), (Z, -1))} + Finite family {('X', 'Y'): -Y, ('X', 'Z'): Y - Z} sage: L = lie_algebras.three_dimensional(QQ, 0, 1, 0, 0) sage: L.structure_coefficients() - {[Y, Z]: ((X, 1),)} + Finite family {('Y', 'Z'): X} sage: lie_algebras.three_dimensional(QQ, 0, 0, 0, 0) Abelian Lie algebra on 3 generators (X, Y, Z) over Rational Field """ @@ -68,7 +68,7 @@ def cross_product(R, names=['X', 'Y', 'Z']): sage: L = lie_algebras.cross_product(QQ) sage: L.structure_coefficients() - {[X, Y]: ((Z, 1),), [X, Z]: ((Y, -1),), [Y, Z]: ((X, 1),)} + Finite family {('X', 'Y'): Z, ('X', 'Z'): -Y, ('Y', 'Z'): X} """ L = three_dimensional(R, 1, 1, 1, 0, names) L.rename("Lie algebra of RR^3 under cross product over {}".format(R)) @@ -91,15 +91,15 @@ def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): Abelian Lie algebra on 3 generators (X, Y, Z) over Rational Field sage: L = lie_algebras.three_dimensional_by_rank(QQ, 1) sage: L.structure_coefficients() - {[Y, Z]: ((X, 1),)} + Finite family {('Y', 'Z'): X} sage: L = lie_algebras.three_dimensional_by_rank(QQ, 2, 4) sage: L.structure_coefficients() - {[X, Y]: ((Y, 1),), [X, Z]: ((Y, 1), (Z, 1))} + Finite family {('X', 'Y'): Y, ('X', 'Z'): Y + Z} sage: L = lie_algebras.three_dimensional_by_rank(QQ, 2, 0) sage: L.structure_coefficients() - {[X, Y]: ((Y, 1),)} + Finite family {('X', 'Y'): Y} sage: lie_algebras.three_dimensional_by_rank(QQ, 3) - Special linear Lie algebra of rank 2 over Rational Field + sl2 over Rational Field """ if isinstance(names, str): names = names.split(',') @@ -165,7 +165,7 @@ def sl(R, n, representation='bracket'): E = MS([[0,1],[0,0]]) F = MS([[0,0],[1,0]]) H = MS([[1,0],[-1,0]]) - L = LieAlgebraFromAssociative(R, MS, [E, F, H], ['E', 'F', 'H']) + L = LieAlgebraFromAssociative([E, F, H], ['E', 'F', 'H']) L.rename("sl2 as a matrix Lie algebra over {}".format(R)) elif representation == 'bracket': L = three_dimensional_by_rank(R, 3) @@ -182,7 +182,7 @@ def affine_transformations_line(R, names=['X', 'Y'], representation='bracket'): sage: L = lie_algebras.affine_transformations_line(QQ) sage: L.structure_coefficients() - {[X, Y]: ((Y, 1),)} + Finite family {('X', 'Y'): Y} """ if isinstance(names, str): names = names.split(',') @@ -193,7 +193,7 @@ def affine_transformations_line(R, names=['X', 'Y'], representation='bracket'): one = R.one() gens = tuple(MS({(0,i):one}) for i in range(2)) from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative - return LieAlgebraFromAssociative(R, MS, gens, names) + return LieAlgebraFromAssociative(gens, names) X = names[0] Y = names[1] from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients @@ -271,10 +271,10 @@ def upper_triangluar_matrices(R, n): MS = MatrixSpace(R, n, sparse=True) one = R.one() names = tuple('n{}'.format(i) for i in range(n-1)) - names = tuple('t{}'.format(i) for i in range(n)) + names += tuple('t{}'.format(i) for i in range(n)) gens = [MS({(i,i+1):one}) for i in range(n-1)] gens += [MS({(i,i):one}) for i in range(n)] - L = LieAlgebraFromAssociative(R, MS, gens, names) + L = LieAlgebraFromAssociative(gens, names) L.rename("Lie algebra of {}-dimensional upper triangular matrices over {}".format(n, L.base_ring())) return L @@ -294,7 +294,7 @@ def strictly_upper_triangular_matrices(R, n): one = R.one() names = tuple('n{}'.format(i) for i in range(n-1)) gens = tuple(MS({(i,i+1):one}) for i in range(n-1)) - L = LieAlgebraFromAssociative(R, MS, gens, names) + L = LieAlgebraFromAssociative(gens, names) L.rename("Lie algebra of {}-dimensional strictly upper triangular matrices over {}".format(n, L.base_ring())) return L diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index fd9adf74c6a..6a5d1989ae1 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -336,8 +336,8 @@ def lie_algebra_generators(self): Lazy family (generator map(i))_{i in Cartesian product of Positive integers, ['p', 'q']} """ - S = CartesianProduct(PositiveIntegers(), ['p','q']) - return Family(S, self.monomial, name='generator map') + return Family(self._indices, lambda x: self.monomial(tuple(x)), + name='generator map') def basis(self): """ @@ -431,7 +431,7 @@ def __init__(self, R, n): names = tuple('p%s'%i for i in range(1,n+1)) names = names + tuple('q%s'%i for i in range(1,n+1)) + ('z',) cat = LieAlgebras(R).FiniteDimensional().WithBasis() - LieAlgebraFromAssociative.__init__(self, R, MS, p + q + (MS({(0,n+1):one}),), + LieAlgebraFromAssociative.__init__(self, p + q + (MS({(0,n+1):one}),), names=names, category=cat) def _repr_(self): diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index de1a6fdc7fd..91774c7f14d 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -114,27 +114,26 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): sage: L = LieAlgebra(QQ, {('e','h'): {'e':-2}, ('f','h'): {'f':2}, ....: ('e','f'): {'h':1}}, names='e,f,h') - sage: e,f,h = L.gens() + sage: e,f,h = L.lie_algebra_generators() sage: L.bracket(h, e) 2*e sage: elt = h*e; elt - h*e + e*h + 2*e sage: elt.parent() - Noncommutative Multivariate Polynomial Ring in h1, e1, f1 over Rational Field, - nc-relations: {f1*e1: e1*f1 - h1, e1*h1: h1*e1 - 2*e1, f1*h1: h1*f1 + 2*f1} + Noncommutative Multivariate Polynomial Ring in e, f, h over Rational Field, + nc-relations: {f*e: e*f - h, h*f: f*h - 2*f, h*e: e*h + 2*e} For convienence, there is are two shorthand notations for computing Lie backets:: - sage: h,e,f = L.gens() sage: L([h,e]) - 2*e1 + 2*e sage: L([h,[e,f]]) 0 sage: L([[h,e],[e,f]]) - -4*e1 + -4*e sage: L[h, e] - 2*e1 + 2*e sage: L[h, L[e, f]] 0 @@ -172,16 +171,37 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): - :wikipedia:`Lie_algebra` """ @staticmethod - def __classcall_private__(cls, R, arg0=None, arg1=None, names=None, + def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, index_set=None, abelian=False, **kwds): """ Select the correct parent based upon input. + + TESTS:: + + sage: LieAlgebra(QQ, abelian=True, names='x,y,z') + Abelian Lie algebra on 3 generators (x, y, z) over Rational Field + sage: LieAlgebra(QQ, {('e','h'): {'e':-2}, ('f','h'): {'f':2}, + ....: ('e','f'): {'h':1}}, names='e,f,h') + Lie algebra on 3 generators (e, f, h) over Rational Field """ + # Parse associative algebra input + # ----- + + assoc = kwds.get("associative", None) + if assoc is not None: + return LieAlgebraFromAssociative(assoc, names, index_set) + + # Parse the remaining arguments + # ----- + + if R is None: + raise ValueError("invalid arguments") + check_assoc = lambda A: (isinstance(A, (Ring, MatrixSpace)) or A in Rings() or A in Algebras(R).Associative()) - # Check if we need to swap the arguments if arg0 in ZZ or check_assoc(arg1): + # Check if we need to swap the arguments arg0, arg1 = arg1, arg0 # Parse the first argument @@ -194,56 +214,20 @@ def __classcall_private__(cls, R, arg0=None, arg1=None, names=None, elif isinstance(arg0.keys()[0], (list,tuple)): # We assume it is some structure coefficients arg1, arg0 = arg0, arg1 - else: - # It is generated by elements of an associative algebra - index_set = arg0.keys() - gens = arg0.values() - A = gens[0].parent() - return LieAlgebraFromAssociative(R, A, gens, names, index_set) - - if check_assoc(arg0): - if arg1 is None: - gens = arg0.gens() - if names is None: - names = arg0.variable_names() - elif isinstance(arg1, str): - names = arg1 - gens = arg0.gens() - else: - gens = arg1 - - if names is not None: - if isinstance(names, str): - names = tuple(names.split(',')) - if len(names) != len(gens): - raise ValueError("the number of names must equal the number of generators") - return LieAlgebraFromAssociative(R, arg0, gens, names, index_set) if isinstance(arg0, (list, tuple)): if all(isinstance(x, str) for x in arg0): # If they are all strings, then it is a list of variables names = tuple(arg0) - else: - # Otherwise assume they are elements of an assoc alg - A = arg0[0].parent() - if isinstance(arg1, str): - names = tuple(arg1.split(',')) - if len(names) == 1 and len(arg0) != 1: - names = ['{}{}'.format(names[0], i) for i in xrange(len(arg0))] - elif isinstance(arg1, (tuple, list)): - names = tuple(arg1) - if len(names) != len(arg0): - raise ValueError("the number of names must equal the number of generators") - return LieAlgebraFromAssociative(R, A, arg0, names, index_set) if isinstance(arg0, str): names = tuple(arg0.split(',')) + elif isinstance(names, str): + names = tuple(names.split(',')) # Parse the second argument if isinstance(arg1, dict): - if isinstance(names, str): - names = tuple(names.split(',')) # Assume it is some structure coefficients from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients return LieAlgebraWithStructureCoefficients(R, arg1, names, index_set, **kwds) @@ -261,7 +245,8 @@ def __classcall_private__(cls, R, arg0=None, arg1=None, names=None, if arg1 != 1 and len(names) == 1: names = tuple('{}{}'.format(names[0],i) for i in xrange(arg1)) if arg1 != len(names): - raise ValueError("the number of names must equal the number of generators") + raise ValueError("the number of names must equal the" + " number of generators") if abelian: from sage.algebras.lie_algebras.structure_coefficients import AbelianLieAlgebra @@ -274,7 +259,7 @@ def __classcall_private__(cls, R, arg0=None, arg1=None, names=None, # free (associative unital) algebra # TODO: Change this to accept an index set once FreeAlgebra accepts one F = FreeAlgebra(R, names, len(names)) - return LieAlgebraFromAssociative(R, F, F.gens(), names, index_set) + return LieAlgebraFromAssociative(F.gens(), names, index_set) raise NotImplementedError("the free Lie algebra has not been implemented, see trac ticket #16823") @@ -310,6 +295,9 @@ def __init__(self, R, names=None, index_set=None, category=None): if isinstance(index_set, (tuple, list)): index_set = FiniteEnumeratedSet(index_set) + if isinstance(names, str): + names = tuple(names.split(',')) + #if names is None and index_set.cardinality() < infinity \ # and all(isinstance(i, str) for i in index_set): # names = index_set @@ -367,17 +355,23 @@ def _coerce_map_from_(self, R): - A module which coerces into the base vector space of ``self``. TESTS:: + + sage: L. = LieAlgebra(QQ, abelian=True) + sage: L._coerce_map_from_(L.free_module()) + True + sage: L._coerce_map_from_(FreeModule(ZZ, 2)) + True """ if not isinstance(R, LieAlgebra): # Should be moved to LieAlgebrasWithBasis somehow since it is a generic coercion - if self.free_module() is not NotImplemented: + if self.free_module is not NotImplemented: return self.free_module().has_coerce_map_from(R) return False # We check if it is a subalgebra of something that can coerce into ``self`` - from sage.algebras.lie_algebras.subalgebra import LieSubalgebra - if isinstance(R, LieSubalgebra) and self.has_coerce_map_from(R._ambient): - return R.ambient_lift + #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra + #if isinstance(R, LieSubalgebra) and self.has_coerce_map_from(R._ambient): + # return R.ambient_lift # Lie algebras in the same indices over any base that coerces in if R._indices != self._indices: @@ -433,6 +427,11 @@ def _from_dict(self, d, coerce=False, remove_zeros=True): ``coeff``s may be zero and should therefore be removed EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, oo) + sage: d = {('p', 1): 4, ('q', 3): 1/2, 'z': -2} + sage: L._from_dict(d) + -2*z + 4*p1 + 1/2*q3 """ assert isinstance(d, dict) if coerce: @@ -447,6 +446,10 @@ def monomial(self, i): Return the monomial indexed by ``i``. EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, oo) + sage: L.monomial(('p', 1)) + p1 """ return self.element_class(self, {i: self.base_ring().one()}) @@ -455,6 +458,10 @@ def term(self, i, c=None): Return the term indexed by ``i`` with coefficient ``c``. EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, oo) + sage: L.term(('p', 1), 4) + 4*p1 """ if c is None: c = self.base_ring().one() @@ -462,19 +469,18 @@ def term(self, i, c=None): c = self.base_ring()(c) return self.element_class(self, {i: c}) - # TODO: This is essentially an abstract method for Lie algebras def lie_algebra_generators(self): """ Return the generators of ``self`` as a Lie algebra. EXAMPLES:: + + sage: L. = LieAlgebra(QQ, representation="polynomial") + sage: L.lie_algebra_generators() + Finite family {'y': y, 'x': x} """ return Family(self._indices, self.monomial, name="monomial map") - # FIXME: Placeholder -- Should this be in the category? - def free_module(self): - return NotImplemented - Element = LieAlgebraElement # Default for all Lie algebras class FinitelyGeneratedLieAlgebra(LieAlgebra): @@ -527,6 +533,10 @@ def gens(self): object, in some order. EXAMPLES:: + + sage: L. = LieAlgebra(QQ, abelian=True) + sage: L.gens() + (x, y) """ G = self.lie_algebra_generators() try: @@ -539,6 +549,12 @@ def gens(self): def gen(self, i): """ Return the ``i``-th generator of ``self``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, abelian=True) + sage: L.gen(0) + x """ return self.gens()[i] @@ -546,12 +562,24 @@ def gen(self, i): def _ordered_indices(self): """ Return the index set of ``self`` in order. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, abelian=True) + sage: L._ordered_indices + ('x', 'y') """ - return tuple(sorted(self._indices)) + return tuple(self._indices) def _an_element_(self): """ Return an element of ``self``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, abelian=True) + sage: L.an_element() + x + y """ return self.sum(self.lie_algebra_generators()) @@ -562,6 +590,12 @@ class InfinitelyGeneratedLieAlgebra(LieAlgebra): def _an_element_(self): """ Return an element of ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, oo) + sage: L._an_element_() + z + p2 + q2 - 1/2*q3 """ return self.lie_algebra_generators()[self._indices.an_element()] @@ -599,14 +633,14 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): Note that the bracket of everything will be 0:: sage: R. = PolynomialRing(QQ) - sage: L. = LieAlgebra(QQ, R) + sage: L. = LieAlgebra(associative=R) sage: L.bracket(x, y) 0 Next we use a free algebra and do some simple computations:: sage: R. = FreeAlgebra(QQ, 2) - sage: L. = LieAlgebra(QQ, R) + sage: L. = LieAlgebra(associative=R) sage: x-y a - b sage: L.bracket(x-y, x) @@ -617,14 +651,14 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): We can also use a subset of the generators to use in our Lie algebra:: sage: R. = FreeAlgebra(QQ, 3) - sage: L. = LieAlgebra(QQ, R, [a,b]) + sage: L. = LieAlgebra(associative=[a,b]) Now for a more complicated example using the group ring of `S_3` as our base algebra:: sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(QQ, S) + sage: L. = LieAlgebra(associative=S) sage: L.bracket(x, y) (2,3) - (1,3) sage: L.bracket(x, y-x) @@ -641,7 +675,7 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): sage: MS = MatrixSpace(QQ,2) sage: m1 = MS([[0, -1], [1, 0]]) sage: m2 = MS([[-1, 4], [3, 2]]) - sage: L. = LieAlgebra(QQ, MS, [m1, m2]) + sage: L. = LieAlgebra(associative=[m1, m2]) sage: x [ 0 -1] [ 1 0] @@ -665,12 +699,12 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): the result of :meth:`universal_enveloping_algebra()` can be too large:: sage: R. = FreeAlgebra(QQ, 3) - sage: L = LieAlgebra(QQ, R, [a,b], names='x,y') + sage: L = LieAlgebra(associative=[a,b], names='x,y') sage: L.universal_enveloping_algebra() is R True """ @staticmethod - def __classcall_private__(cls, R, A, gens, names=None, index_set=None, category=None): + def __classcall_private__(cls, gens, names=None, index_set=None, category=None): """ Normalize input to ensure a unique representation. @@ -678,12 +712,33 @@ def __classcall_private__(cls, R, A, gens, names=None, index_set=None, category= sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L = LieAlgebra(QQ, S, 'x,y') - sage: L2 = LieAlgebra(QQ, S, [G((1,2,3)), G((1,2))], 'x,y') + sage: L = LieAlgebra(associative=S, names='x,y') + sage: L2 = LieAlgebra(associative=map(S, [G((1,2,3)), G((1,2))]), names='x,y') sage: L is L2 True """ - gens = map(A, gens) + if isinstance(gens, Parent): + A = gens + gens = gens.gens() + elif isinstance(gens, dict): + if index_set is None: + index_set = gens.keys() + gens = gens.values() + else: # Assume it is list-like + A = gens[0].parent() + gens = tuple(gens) + + if isinstance(names, str): + names = tuple(names.split(',')) + elif isinstance(names, (tuple, list)): + names = tuple(names) + + if names is not None and len(names) != len(gens): + raise ValueError("the number of names must equal the number of generators") + if index_set is not None and len(index_set) != len(gens): + raise ValueError("the number of names must equal the number of generators") + + gens = tuple(map(A, gens)) # Make sure all the generators have the same parent try: # Try to make things, such as matrices, immutable (since we need to hash them) for g in gens: @@ -691,13 +746,13 @@ def __classcall_private__(cls, R, A, gens, names=None, index_set=None, category= except AttributeError: pass - if names is not None: - names = tuple(names) + # TODO: We should strip axioms from the category of the base ring, + # such as FiniteDimensional, WithBasis and standardize return super(LieAlgebraFromAssociative, cls).__classcall__(cls, - R, A, tuple(gens), names, index_set) + gens, names, index_set) - def __init__(self, R, assoc, gens, names=None, index_set=None, category=None): + def __init__(self, gens, names=None, index_set=None, category=None): """ Initialize ``self``. @@ -705,13 +760,12 @@ def __init__(self, R, assoc, gens, names=None, index_set=None, category=None): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(QQ, S) + sage: L. = LieAlgebra(associative=S) sage: TestSuite(L).run() """ - self._assoc = assoc - # TODO: We should strip axioms from the category of the base ring, - # such as FiniteDimensional, WithBasis - FinitelyGeneratedLieAlgebra.__init__(self, R, names, index_set, category) + self._assoc = gens[0].parent() + FinitelyGeneratedLieAlgebra.__init__(self, self._assoc.base_ring(), + names, index_set, category) if isinstance(gens, dict): F = Family(self._indices, lambda i: self.element_class(self, gens[i])) else: @@ -720,8 +774,9 @@ def __init__(self, R, assoc, gens, names=None, index_set=None, category=None): self._gens = F # TODO: Do we want to store the original generators? - # We register the coercion here since the UEA already exists - self.lift.register_as_coercion() + # We construct the lift map in order to register the coercion + # here since the UEA already exists + self.lift def _repr_option(self, key): """ @@ -732,7 +787,7 @@ def _repr_option(self, key): EXAMPLES:: sage: MS = MatrixSpace(QQ,2) - sage: L. = LieAlgebra(QQ, MS, [MS.one()]) + sage: L. = LieAlgebra(associative=[MS.one()]) sage: L._repr_option('element_ascii_art') True """ @@ -746,7 +801,7 @@ def _repr_(self): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(QQ, S) + sage: L. = LieAlgebra(associative=S) """ return "Lie algebra generated by {} from {}".format( tuple(self._gens), self._assoc) @@ -759,7 +814,7 @@ def _element_constructor_(self, x): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(QQ, S) + sage: L. = LieAlgebra(associative=S) sage: elt = L(x - y); elt -(1,2) + (1,2,3) sage: elt.parent() is L @@ -781,14 +836,12 @@ def _construct_UEA(self): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(QQ, S) + sage: L. = LieAlgebra(associative=S) sage: L._construct_UEA() is S True """ return self._assoc - universal_enveloping_algebra = _construct_UEA - def lie_algebra_generators(self): """ Return the Lie algebra generators of ``self``. @@ -797,7 +850,7 @@ def lie_algebra_generators(self): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(QQ, S) + sage: L. = LieAlgebra(associative=S) sage: L.lie_algebra_generators() Finite family {'y': (1,2), 'x': (1,2,3)} """ @@ -820,6 +873,12 @@ def monomial(self, i): def term(self, i, c=None): """ Return the term indexed by ``i`` with coefficient ``c``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, representation="polynomial") + sage: L.term('x', 4) + 4*x """ if i not in self._indices: raise ValueError("not an index") @@ -834,7 +893,7 @@ def zero_element(self): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(QQ, S) + sage: L. = LieAlgebra(associative=S) sage: L.zero_element() 0 """ @@ -849,11 +908,11 @@ def is_abelian(self): EXAMPLES:: sage: R = FreeAlgebra(QQ, 2, 'x,y') - sage: L. = LieAlgebra(QQ, R) + sage: L. = LieAlgebra(associative=R) sage: L.is_abelian() False sage: R = PolynomialRing(QQ, 'x,y') - sage: L. = LieAlgebra(QQ, R) + sage: L. = LieAlgebra(associative=R) sage: L.is_abelian() True @@ -861,7 +920,7 @@ def is_abelian(self): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(QQ, S) + sage: L. = LieAlgebra(associative=S) sage: L.is_abelian() False @@ -870,8 +929,8 @@ def is_abelian(self): sage: G = SymmetricGroup(5) sage: S = GroupAlgebra(G, QQ) - sage: gens = [G((1, 2)), G((3, 4))] - sage: L. = LieAlgebra(QQ, gens, S) + sage: gens = map(S, [G((1, 2)), G((3, 4))]) + sage: L. = LieAlgebra(associative=gens) sage: L.is_abelian() True """ @@ -887,13 +946,13 @@ def _bracket_(self, rhs): EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(QQ, R) + sage: L. = LieAlgebra(associative=R) sage: L.bracket(x, y) x*y - y*x sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(QQ, S) + sage: L. = LieAlgebra(associative=S) sage: L.bracket(x, y) (2,3) - (1,3) @@ -912,7 +971,7 @@ def lift(self): EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(QQ, R) + sage: L. = LieAlgebra(associative=R) sage: x.lift() x sage: x.lift().parent() diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index 692a5b68953..b222972c089 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -33,21 +33,21 @@ # TODO: Have the other classes inherit from this? # TODO: Should this be a mixin class (or moved to the category)? -class LieAlgebraElement_generic(ModuleElement): - """ - Generic methods for all Lie algebra elements. - """ - def __mul__(self, other): - """ - If we are multiplying two non-zero elements, automatically - lift up to the universal enveloping algebra. - - EXAMPLES:: - """ - if self == 0 or other == 0: - return self.parent().zero() - # Otherwise we lift to the UEA - return self.lift() * other +#class LieAlgebraElement_generic(ModuleElement): +# """ +# Generic methods for all Lie algebra elements. +# """ +# def __mul__(self, other): +# """ +# If we are multiplying two non-zero elements, automatically +# lift up to the universal enveloping algebra. +# +# EXAMPLES:: +# """ +# if self == 0 or other == 0: +# return self.parent().zero() +# # Otherwise we lift to the UEA +# return self.lift() * other # TODO: Factor out parts of CombinatorialFreeModuleElement into a SparseFreeModuleElement? # TODO: Do we want a dense version? @@ -55,36 +55,6 @@ class LieAlgebraElement(CombinatorialFreeModuleElement): """ A Lie algebra element. """ - #def _repr_(self): - # """ - # Return a string representation of ``self``. - # - # EXAMPLES:: - # """ - # if not self._monomial_coefficients: - # return '0' - # return repr_lincomb(self.list()) - - # Default implementation - def _latex_monomial(self, m): - """ - Return a `\LaTeX` representation of the monomial ``m``. - - EXAMPLES:: - """ - from sage.misc.latex import latex - return latex(m) - - #def _latex_(self): - # r""" - # Return a `\LaTeX` representation of ``self``. - # - # EXAMPLES:: - # """ - # if not self._monomial_coefficients: - # return '0' - # return repr_lincomb(self.list(), repr_monomial=self._latex_monomial, is_latex=True) - # Need to bypass the coercion model def __mul__(self, y): """ @@ -92,26 +62,30 @@ def __mul__(self, y): lift up to the universal enveloping algebra. EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}}) + sage: y*x + x*y - z """ if self == 0 or y == 0: return self.parent().zero() # Otherwise we lift to the UEA return self.lift() * y - def _im_gens_(self, codomain, im_gens): - """ - Return the image of ``self`` in ``codomain`` under the map that sends - the images of the generators of the parent of ``self`` to the - tuple of elements of ``im_gens``. - - EXAMPLES:: - """ - s = codomain.zero() - if not self: # If we are 0 - return s - names = self.parent().variable_names() - return codomain.sum(c * t._im_gens_(codomain, im_gens, names) - for t, c in self._monomial_coefficients.iteritems()) + #def _im_gens_(self, codomain, im_gens): + # """ + # Return the image of ``self`` in ``codomain`` under the map that sends + # the images of the generators of the parent of ``self`` to the + # tuple of elements of ``im_gens``. + # + # EXAMPLES:: + # """ + # s = codomain.zero() + # if not self: # If we are 0 + # return s + # names = self.parent().variable_names() + # return codomain.sum(c * t._im_gens_(codomain, im_gens, names) + # for t, c in self._monomial_coefficients.iteritems()) # TODO: Move to the category/lift morphism? def lift(self): @@ -119,6 +93,10 @@ def lift(self): Lift ``self`` to the universal enveloping algebra. EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}}) + sage: x.lift().parent() == L.universal_enveloping_algebra() + True """ UEA = self.parent().universal_enveloping_algebra() gen_dict = UEA.gens_dict() @@ -126,7 +104,7 @@ def lift(self): if not self: return s for t, c in self._monomial_coefficients.iteritems(): - s += c * gen_dict[t._name] + s += c * gen_dict[t] return s def is_constant(self): @@ -134,6 +112,13 @@ def is_constant(self): Check if ``self`` is a constant (i.e. zero). EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}}) + sage: a = x + y + sage: a.is_constant() + False + sage: L.zero().is_constant() + True """ return not self._monomial_coefficients @@ -142,6 +127,11 @@ def dict(self): Return ``self`` as a dictionary mapping monomials to coefficients. EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}}) + sage: a = 3*x - 1/2*z + sage: a.dict() + {'x': 3, 'z': -1/2} """ return copy(self._monomial_coefficients) @@ -151,6 +141,11 @@ def list(self): monomial and ``c`` is the coefficient. EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}}) + sage: a = 3*x - 1/2*z + sage: a.list() + [('x', 3), ('z', -1/2)] """ return sorted(self._monomial_coefficients.items()) @@ -179,7 +174,7 @@ def _repr_(self): EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(QQ, R) + sage: L. = LieAlgebra(associative=R) sage: x + y x + y """ @@ -192,7 +187,7 @@ def _latex_(self): EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x') - sage: L. = LieAlgebra(QQ, R) + sage: L. = LieAlgebra(associative=R) sage: latex(x0 + x1) x_{0} + x_{1} """ @@ -206,7 +201,7 @@ def _add_(self, rhs): EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(QQ, R) + sage: L. = LieAlgebra(associative=R) sage: x + y x + y """ @@ -219,7 +214,7 @@ def _sub_(self, rhs): EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(QQ, R) + sage: L. = LieAlgebra(associative=R) sage: x - y x - y """ @@ -235,7 +230,7 @@ def __mul__(self, x): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(QQ, S) + sage: L. = LieAlgebra(associative=S) sage: x*y - y*x (2,3) - (1,3) """ @@ -249,6 +244,15 @@ def _acted_upon_(self, scalar, self_on_left=False): Return the action of a scalar on ``self``. EXAMPLES:: + + sage: R = FreeAlgebra(QQ, 3, 'x,y,z') + sage: L. = LieAlgebra(associative=R) + sage: 3*x + 3*x + sage: x / 2 + 1/2*x + sage: y * 1/2 + 1/2*y """ # This was copied and IDK if it still applies: # With the current design, the coercion model does not have @@ -272,7 +276,7 @@ def __neg__(self): EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(QQ, R) + sage: L. = LieAlgebra(associative=R) sage: -x -x """ diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index b7f82b43e4f..64a5d99e7ec 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -51,7 +51,6 @@ from sage.modules.free_module import FreeModule, span from sage.sets.family import Family, AbstractFamily -# TODO: Much of this could be moved to (FiniteDimensional)LieAlgebrasWithBasis class LieAlgebraWithStructureCoefficients(FinitelyGeneratedLieAlgebra, IndexedGenerators): r""" A Lie algebra with a set of specified structure coefficients. @@ -84,6 +83,9 @@ def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, **kwds): sage: L1 is L2 True """ + if isinstance(names, str): + names = tuple(names.split(',')) + s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff(s_coeff) if len(s_coeff) == 0: return AbelianLieAlgebra(R, names, index_set, **kwds) @@ -106,6 +108,13 @@ def _standardize_s_coeff(s_coeff): of tuples. Strips items with coefficients of 0 and duplicate entries. This does not check the Jacobi relation (nor antisymmetry if the cardinality is infinite). + + EXAMPLES:: + + sage: from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients + sage: d = {('y','x'): {'x':-1}} + sage: LieAlgebraWithStructureCoefficients._standardize_s_coeff(d) + Finite family {('x', 'y'): (('x', 1),)} """ # Try to handle infinite basis (once/if supported) #if isinstance(s_coeff, AbstractFamily) and s_coeff.cardinality() == infinity: @@ -167,7 +176,7 @@ def basis(self): sage: L.basis() Finite family {'y': y, 'x': x} """ - return Family({i: self.monomial(i) for i in self._indices}) + return Family(self._indices, self.monomial) def structure_coefficients(self, include_zeros=False): """ @@ -178,13 +187,15 @@ def structure_coefficients(self, include_zeros=False): sage: L = LieAlgebra(QQ, 'x,y,z', {('x','y'):{'x':1}}) sage: L.structure_coefficients() Finite family {('x', 'y'): x} - sage: L.structure_coefficients(True) + sage: S = L.structure_coefficients(True); S Finite family {('x', 'y'): x, ('x', 'z'): 0, ('y', 'z'): 0} + sage: S['x','z'].parent() is L + True """ if not include_zeros: return self._s_coeff ret = {} - zero = self.base_ring().zero() + zero = self.zero() S = dict(self._s_coeff) for i,x in enumerate(self._indices): for y in self._indices[i+1:]: @@ -241,29 +252,26 @@ def free_module(self, sparse=True): EXAMPLES:: - sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) + sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}}) sage: L.free_module() Sparse vector space of dimension 3 over Rational Field """ - # TODO: Make this return a free module with the same index set as ``self`` return FreeModule(self.base_ring(), self.dimension(), sparse=sparse) class Element(LieAlgebraElement): """ An element of a Lie algebra given by structure coefficients. """ - - #def _bracket_(self, y): - # """ - # Return the Lie bracket ``[self, y]``. - # """ - # P = self.parent() - # return P.sum(cx * cy * P.bracket_on_basis(mx, my) - # for mx,cx in self for my,cy in y) - def to_vector(self): """ Return ``self`` as a vector. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'z':1}}) + sage: a = x + 3*y - z/2 + sage: a.to_vector() + (1, 3, -1/2) """ V = self.parent().free_module() return V([self[k] for k in self.parent()._ordered_indices]) 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 d61cdaa581d..e2b49dfcfb8 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -73,8 +73,10 @@ def _construct_UEA(self): :: - sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) # todo: not implemented - #16820 - sage: L._construct_UEA() # todo: not implemented - #16820 + sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) + sage: L._construct_UEA() + Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, + nc-relations: {z*x: x*z + y, z*y: y*z - x, y*x: x*y - z} """ # Create the UEA relations # We need to get names for the basis elements, not just the generators @@ -116,8 +118,8 @@ def killing_matrix(self, x, y): :: - sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) # todo: not implemented - #16820 - sage: L.killing_matrix(x, y) # todo: not implemented - #16820 + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: L.killing_matrix(x, y) [ 0 0] [-1 0] """ @@ -281,18 +283,18 @@ def product_space(self, L): :: - sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) # todo: not implemented - #16820 - sage: Lp = L.product_space(L) # todo: not implemented - #16820 - sage: Lp # todo: not implemented - #16820 + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: Lp = L.product_space(L) # todo: not implemented - #17416 + sage: Lp # todo: not implemented - #17416 Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: (x,) - sage: Lp.product_space(L) # todo: not implemented - #16820 + sage: Lp.product_space(L) # todo: not implemented - #17416 Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: (x,) - sage: L.product_space(Lp) # todo: not implemented - #16820 + sage: L.product_space(Lp) # todo: not implemented - #17416 Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: (x,) - sage: Lp.product_space(Lp) # todo: not implemented - #16820 + sage: Lp.product_space(Lp) # todo: not implemented - #17416 Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: () """ @@ -377,8 +379,8 @@ def derived_series(self): :: - sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) # todo: not implemented - #16820 - sage: L.derived_series() # todo: not implemented - #16820 + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: L.derived_series() # todo: not implemented - #17416 (Lie algebra on 2 generators (x, y) over Rational Field, Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: (x,), @@ -431,8 +433,8 @@ def lower_central_series(self): :: - sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) # todo: not implemented - #16820 - sage: L.lower_central_series() # todo: not implemented - #16820 + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: L.lower_central_series() # todo: not implemented - #17416 (Lie algebra on 2 generators (x, y) over Rational Field, Subalgebra generated of Lie algebra on 2 generators (x, y) over Rational Field with basis: (x,)) @@ -457,8 +459,8 @@ def is_abelian(self): :: - sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) # todo: not implemented - #16820 - sage: L.is_abelian() # todo: not implemented - #16820 + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: L.is_abelian() False """ return len(self.structure_coefficients()) == 0 @@ -480,8 +482,8 @@ def is_solvable(self): :: - sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) # todo: not implemented - #16820 - sage: L.is_solvable() # todo: not implemented - #16820 + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: L.is_solvable() # todo: not implemented - #17416 False """ return not self.derived_series()[-1].dimension() @@ -529,8 +531,8 @@ def dimension(self): :: - sage: L = LieAlgebra(QQ, 'x,y', {('x','y'): {'x':1}}) # todo: not implemented - #16820 - sage: L.dimension() # todo: not implemented - #16820 + sage: L = LieAlgebra(QQ, 'x,y', {('x','y'): {'x':1}}) + sage: L.dimension() 2 """ return self.basis().cardinality() @@ -566,13 +568,13 @@ def adjoint_matrix(self): # In #11111 (more or less) by using matrix of a mophis :: - sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) # todo: not implemented - #16820 - sage: x.adjoint_matrix() # todo: not implemented - #16820 - [1 0] + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: x.adjoint_matrix() [0 0] - sage: y.adjoint_matrix() # todo: not implemented - #16820 - [ 0 0] + [1 0] + sage: y.adjoint_matrix() [-1 0] + [ 0 0] """ P = self.parent() basis = P.basis() diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index e9d2148f9a3..b0baa6bc482 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -233,8 +233,8 @@ def universal_enveloping_algebra(self): :: - sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) # todo: not implemented - #16820 - sage: L.universal_enveloping_algebra() # todo: not implemented - #16820 + sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) + sage: L.universal_enveloping_algebra() Multivariate Polynomial Ring in x0, x1, x2 over Rational Field """ return self.lift.codomain() @@ -253,8 +253,8 @@ def _construct_UEA(self): :: - sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) # todo: not implemented - #16820 - sage: L.universal_enveloping_algebra() # todo: not implemented - #16820 # indirect doctest + sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) + sage: L.universal_enveloping_algebra() # indirect doctest Multivariate Polynomial Ring in x0, x1, x2 over Rational Field """ @@ -291,13 +291,33 @@ def lift(self): return M def subalgebra(self, gens, names=None, index_set=None, category=None): - """ + r""" Return the subalgebra of ``self`` generated by ``gens``. EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.inject_variables() + Defining a, b, c + sage: L.subalgebra([2*a - c, b + c]) + An example of a finite dimensional Lie algebra with basis: + the abelian Lie algebra with generators ('x0', 'x1') + over Rational Field with basis matrix: + [ 1 0 -1/2] + [ 0 1 1] + + :: + + sage: L = LieAlgebras(QQ).example() + sage: x,y = L.lie_algebra_generators() + sage: L.subalgebra([x + y]) + Traceback (most recent call last): + ... + NotImplementedError: subalgebras not yet implemented: see #17416 """ - from sage.algebras.lie_algebras.subalgebra import LieSubalgebra - return LieSubalgebra(gens, names, index_set, category) + raise NotImplementedError("subalgebras not yet implemented: see #17416") + #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra + #return LieSubalgebra(gens, names, index_set, category) @abstract_method(optional=True) def killing_form(self, x, y): @@ -459,9 +479,10 @@ def _test_distributivity(self, **options): By default, this method runs the tests only on the elements returned by ``self.some_elements()``:: - sage: LieAlgebra(QQ, 3, 'x,y,z').some_elements() # todo: not implemented - #16820 - [x] - sage: LieAlgebra(QQ, 3, 'x,y,z')._test_distributivity() # todo: not implemented - #16820 + sage: L = LieAlgebra(QQ, 3, 'x,y,z', representation="polynomial") + sage: L.some_elements() + [x + y + z] + sage: L._test_distributivity() However, the elements tested can be customized with the ``elements`` keyword argument:: @@ -529,8 +550,8 @@ def lift(self): :: - sage: L. = LieAlgebra(QQ, abelian=True) # todo: not implemented - #16820 - sage: x.lift() # todo: not implemented - #16820 + sage: L. = LieAlgebra(QQ, abelian=True) + sage: x.lift() x """ From e5c1703bc6c958566a5f2a91d909e45b52b3c2b0 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 24 Dec 2014 22:56:19 -0800 Subject: [PATCH 019/223] Fixed typos with sl2 construction. --- src/sage/algebras/lie_algebras/examples.py | 26 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index e66280a6a9b..86e8c9d79a2 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -137,7 +137,7 @@ def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): E = names[0] F = names[1] H = names[2] - s_coeff = { (E,F): {H:R.one()}, (H,E): {E:R(2)}, (H,F): {E:R(-2)} } + s_coeff = { (E,F): {H:R.one()}, (H,E): {E:R(2)}, (H,F): {F:R(-2)} } L = LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) L.rename("sl2 over {}".format(R)) return L @@ -152,8 +152,26 @@ def sl(R, n, representation='bracket'): EXAMPLES:: - sage: lie_algebras.sl(QQ, 2) + sage: sl2 = lie_algebras.sl(QQ, 2); sl2 sl2 over Rational Field + sage: E,F,H = sl2.gens() + sage: E.bracket(F) == H + True + sage: H.bracket(E) == 2*E + True + sage: H.bracket(F) == -2*F + True + + TESTS:: + + sage: sl2 = lie_algebras.sl(QQ, 2, representation='matrix') + sage: E,F,H = sl2.gens() + sage: E.bracket(F) == H + True + sage: H.bracket(E) == 2*E + True + sage: H.bracket(F) == -2*F + True """ if n != 2: raise NotImplementedError("only n=2 is implemented") @@ -164,11 +182,11 @@ def sl(R, n, representation='bracket'): MS = MatrixSpace(R, 2) E = MS([[0,1],[0,0]]) F = MS([[0,0],[1,0]]) - H = MS([[1,0],[-1,0]]) + H = MS([[1,0],[0,-1]]) L = LieAlgebraFromAssociative([E, F, H], ['E', 'F', 'H']) L.rename("sl2 as a matrix Lie algebra over {}".format(R)) elif representation == 'bracket': - L = three_dimensional_by_rank(R, 3) + L = three_dimensional_by_rank(R, 3, names=['E', 'F', 'H']) else: raise ValueError("invalid representation") From 036995f21ad58e1fc9486bc3431d4c5a1c411bad Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 14 Feb 2015 00:34:14 -0800 Subject: [PATCH 020/223] Cleaning up/Fixing some logic, in particular for FromAssociative. --- src/sage/algebras/lie_algebras/lie_algebra.py | 195 ++++++++++++------ .../lie_algebras/lie_algebra_element.py | 4 +- .../lie_algebras/structure_coefficients.py | 12 +- 3 files changed, 135 insertions(+), 76 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 91774c7f14d..58ee14480fa 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -49,7 +49,7 @@ from sage.modules.free_module_element import vector from sage.modules.free_module import FreeModule, span from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract -from sage.sets.family import Family +from sage.sets.family import Family, AbstractFamily from sage.sets.finite_enumerated_set import FiniteEnumeratedSet class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): @@ -170,6 +170,8 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): - :wikipedia:`Lie_algebra` """ + # This works because it is an abstract base class and this + # __classcall_private__ will only be called when calling LieAlgebra @staticmethod def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, index_set=None, abelian=False, **kwds): @@ -189,7 +191,7 @@ def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, assoc = kwds.get("associative", None) if assoc is not None: - return LieAlgebraFromAssociative(assoc, names, index_set) + return LieAlgebraFromAssociative(assoc, names=names, index_set=index_set) # Parse the remaining arguments # ----- @@ -258,12 +260,54 @@ def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, # Construct the free Lie algebra from polynomials in the # free (associative unital) algebra # TODO: Change this to accept an index set once FreeAlgebra accepts one - F = FreeAlgebra(R, names, len(names)) - return LieAlgebraFromAssociative(F.gens(), names, index_set) + F = FreeAlgebra(R, names) + return LieAlgebraFromAssociative(list(F.algebra_generators()), + names, index_set) - raise NotImplementedError("the free Lie algebra has not been implemented, see trac ticket #16823") + raise NotImplementedError("the free Lie algebra has only been implemented using polynomials in the free algebra, see trac ticket #16823") - # TODO: Should this inherit from IndexedGenerators? + @staticmethod + def _standardize_names_index_set(names=None, index_set=None, ngens=None): + """ + Standardize the ``names`` and ``index_set`` for a Lie algebra. + + .. TODO:: + + This function could likely be generalized for any parent + inheriting from :class:`IndexedGenerators` and (potentially) + having ``names``. Should this method be moved to + :class:`IndexedGenerators`? + """ + if index_set is None: + if names is None: + raise ValueError("either the names of the generators" + " or the index set must be specified") + # If only the names are specified, then we make the indexing set + # be the names + index_set = tuple(names) + + if isinstance(names, str): + names = tuple(names.split(',')) + elif names is not None: + names = tuple(names) + + if isinstance(index_set, (tuple, list)): + index_set = FiniteEnumeratedSet(index_set) + + if names is not None: + if index_set is not None and len(names) != index_set.cardinality(): + raise ValueError("the number of names must equal" + " the size of the indexing set") + if ngens is not None and len(names) != ngens: + raise ValueError("the number of names must equal the number of generators") + elif ngens is not None and index_set.cardinality() != ngens: + raise ValueError("the size of the indexing set must equal" + " the number of generators") + + return names, index_set + + # TODO: Should this inherit from IndexedGenerators or should this + # be a subclass? def __init__(self, R, names=None, index_set=None, category=None): """ The Lie algebra. @@ -286,21 +330,6 @@ def __init__(self, R, names=None, index_set=None, category=None): Category of finite dimensional lie algebras with basis over Rational Field """ category = LieAlgebras(R).or_subcategory(category) - if index_set is None: - if names is None: - raise ValueError("either the names of the generators" - " or the index set must be specified") - index_set = tuple(names) - - if isinstance(index_set, (tuple, list)): - index_set = FiniteEnumeratedSet(index_set) - - if isinstance(names, str): - names = tuple(names.split(',')) - - #if names is None and index_set.cardinality() < infinity \ - # and all(isinstance(i, str) for i in index_set): - # names = index_set self._indices = index_set Parent.__init__(self, base=R, names=names, category=category) @@ -318,13 +347,13 @@ def _element_constructor_(self, x): True """ if isinstance(x, list) and len(x) == 2: - return self.bracket(self(x[0]), self(x[1])) - if isinstance(x, self.element_class) and x.parent() is self: - return x + return self(x[0])._bracket_(self(x[1])) + if x in self.base_ring(): if x != 0: raise ValueError("can only convert the scalar 0 into a Lie algebra element") return self.zero() + return self.element_class(self, x) def __getitem__(self, x): @@ -392,8 +421,6 @@ def zero(self): """ return self.element_class(self, {}) - zero_element = zero - # TODO: Find a better place for this method? # TODO: Use IndexedGenerators? def indices(self): @@ -611,7 +638,6 @@ def dimension(self): """ return infinity -# TODO: Implement a version for infinite set of generators? class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): """ A Lie algebra whose elements are from an associative algebra and whose @@ -704,7 +730,7 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): True """ @staticmethod - def __classcall_private__(cls, gens, names=None, index_set=None, category=None): + def __classcall_private__(cls, gens, names=None, index_set=None): """ Normalize input to ensure a unique representation. @@ -719,38 +745,58 @@ def __classcall_private__(cls, gens, names=None, index_set=None, category=None): """ if isinstance(gens, Parent): A = gens - gens = gens.gens() + ngens = None + # Parse possible generators (i.e., a basis) from the parent + try: + gens = A.basis() + + if index_set is None: + try: + index_set = gens.keys() + except (AttributeError, ValueError): + pass + if names is None: + try: + names = A.variable_names() + except ValueError: + pass + except (AttributeError, NotImplementedError): + pass + + elif isinstance(gens, AbstractFamily): + if index_set is None: + index_set = gens.keys() + if gens.cardinality() < float('inf'): + gens = tuple([gens[i] for i in gens.keys()]) + ngens = len(gens) + elif isinstance(gens, dict): if index_set is None: index_set = gens.keys() gens = gens.values() + ngens = len(gens) else: # Assume it is list-like A = gens[0].parent() gens = tuple(gens) + ngens = len(gens) - if isinstance(names, str): - names = tuple(names.split(',')) - elif isinstance(names, (tuple, list)): - names = tuple(names) + names, index_set = _standardize_names_index_set(names, index_set, ngens) - if names is not None and len(names) != len(gens): - raise ValueError("the number of names must equal the number of generators") - if index_set is not None and len(index_set) != len(gens): - raise ValueError("the number of names must equal the number of generators") + if gens is not A: # If we have a generating set + # Make sure all the generators have the same parent of A + gens = tuple(map(A, gens)) - gens = tuple(map(A, gens)) # Make sure all the generators have the same parent - try: - # Try to make things, such as matrices, immutable (since we need to hash them) - for g in gens: - g.set_immutable() - except AttributeError: - pass - - # TODO: We should strip axioms from the category of the base ring, - # such as FiniteDimensional, WithBasis and standardize + if ngens: + try: + # Try to make things, such as matrices, immutable + # since we need to hash them + for g in gens: + g.set_immutable() + except AttributeError: + pass return super(LieAlgebraFromAssociative, cls).__classcall__(cls, - gens, names, index_set) + gens, names=names, index_set=index_set) def __init__(self, gens, names=None, index_set=None, category=None): """ @@ -760,19 +806,35 @@ def __init__(self, gens, names=None, index_set=None, category=None): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(associative=S) + sage: L = LieAlgebra(associative=S) sage: TestSuite(L).run() """ - self._assoc = gens[0].parent() - FinitelyGeneratedLieAlgebra.__init__(self, self._assoc.base_ring(), - names, index_set, category) - if isinstance(gens, dict): - F = Family(self._indices, lambda i: self.element_class(self, gens[i])) + if isinstance(gens, Parent): + gens = None + self._assoc = gens else: + self._assoc = gens[0].parent() + R = self._assoc.base_ring() + + # We strip the following axioms from the category of the assoc. algebra: + # FiniteDimensional and WithBasis + category = LieAlgebras(R).or_subcategory(category) + if 'FiniteDimensional' in self._assoc.category().axioms(): + category = category.FiniteDimensional() + if 'WithBasis' in self._assoc.category().axioms(): + category = category.WithBasis() + + FinitelyGeneratedLieAlgebra.__init__(self, R, names, index_set, category) + + if isinstance(gens, tuple): F = Family({self._indices[i]: self.element_class(self, v) for i,v in enumerate(gens)}) + elif gens is not None: # It is a family + F = Family(self._indices, lambda i: self.element_class(self, gens[i]), + name="generator map") self._gens = F - # TODO: Do we want to store the original generators? + # We don't need to store the original generators because we can + # get them from lifting this object's generators # We construct the lift map in order to register the coercion # here since the UEA already exists @@ -813,19 +875,20 @@ def _element_constructor_(self, x): EXAMPLES:: sage: G = SymmetricGroup(3) - sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(associative=S) + sage: A = G.group_algebra(QQ) + sage: L = LieAlgebra(associative=S) + sage: x,y = S.algebra_generators() sage: elt = L(x - y); elt -(1,2) + (1,2,3) sage: elt.parent() is L True + sage: elt == L(x) - L(y) + True sage: L([x, y]) (2,3) - (1,3) """ - if isinstance(x, LieAlgebraElement) and x.parent() is self: - return x if isinstance(x, list) and len(x) == 2: - return LieAlgebra._element_constructor_(self, x) + return self(x[0])._bracket_(self(x[1])) return self.element_class(self, self._assoc(x)) def _construct_UEA(self): @@ -836,7 +899,7 @@ def _construct_UEA(self): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(associative=S) + sage: L = LieAlgebra(associative=S) sage: L._construct_UEA() is S True """ @@ -850,7 +913,7 @@ def lie_algebra_generators(self): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(associative=S) + sage: L = LieAlgebra(associative=S) sage: L.lie_algebra_generators() Finite family {'y': (1,2), 'x': (1,2,3)} """ @@ -867,6 +930,7 @@ def monomial(self, i): x """ if i not in self._indices: + #return self(self._assoc.monomial(i)) raise ValueError("not an index") return self._gens[i] @@ -881,11 +945,12 @@ def term(self, i, c=None): 4*x """ if i not in self._indices: + #return self(self._assoc.term(i, c)) raise ValueError("not an index") return c * self._gens[i] @cached_method - def zero_element(self): + def zero(self): """ Return `0`. @@ -894,13 +959,11 @@ def zero_element(self): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) sage: L. = LieAlgebra(associative=S) - sage: L.zero_element() + sage: L.zero() 0 """ return self.element_class(self, self._assoc.zero()) - zero = zero_element - def is_abelian(self): """ Return ``True`` if ``self`` is abelian. diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index b222972c089..34bb1d91d9b 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -221,6 +221,8 @@ def _sub_(self, rhs): return self.__class__(self.parent(), self.value - rhs.value) # This seems to work with 2 underscores and I don't understand why... + # We let the universal enveloping algebra handle the rest if both + # arguments are non-zero def __mul__(self, x): """ If we are multiplying two non-zero elements, automatically @@ -254,7 +256,7 @@ def _acted_upon_(self, scalar, self_on_left=False): sage: y * 1/2 1/2*y """ - # This was copied and IDK if it still applies: + # 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 diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 64a5d99e7ec..293317ebc2e 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -83,23 +83,17 @@ def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, **kwds): sage: L1 is L2 True """ - if isinstance(names, str): - names = tuple(names.split(',')) + names, index_set = _standardize_names_index_set(names, index_set) s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff(s_coeff) if len(s_coeff) == 0: return AbelianLieAlgebra(R, names, index_set, **kwds) - if names is None: - if index_set is None: - raise ValueError("either the names or the index set must be specified") - if len(index_set) <= 1: - return AbelianLieAlgebra(R, names, index_set, **kwds) - elif len(names) <= 1: + if (names is None and len(index_set) <= 1) or len(names) <= 1: return AbelianLieAlgebra(R, names, index_set, **kwds) return super(LieAlgebraWithStructureCoefficients, cls).__classcall__( - cls, R, s_coeff, tuple(names), index_set, **kwds) + cls, R, s_coeff, names, index_set, **kwds) @staticmethod def _standardize_s_coeff(s_coeff): From b4b89da6c3c02ecd95091b7d2cceb0b8347a58b7 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 15 Feb 2015 02:58:18 -0800 Subject: [PATCH 021/223] Fixing errors introduced by logic changes. --- src/sage/algebras/lie_algebras/examples.py | 16 +- src/sage/algebras/lie_algebras/lie_algebra.py | 177 +++++++++++------- .../lie_algebras/structure_coefficients.py | 16 +- 3 files changed, 126 insertions(+), 83 deletions(-) diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index 86e8c9d79a2..c0beaaa00a1 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -70,7 +70,7 @@ def cross_product(R, names=['X', 'Y', 'Z']): sage: L.structure_coefficients() Finite family {('X', 'Y'): Z, ('X', 'Z'): -Y, ('Y', 'Z'): X} """ - L = three_dimensional(R, 1, 1, 1, 0, names) + L = three_dimensional(R, 1, 1, 1, 0, names=names) L.rename("Lie algebra of RR^3 under cross product over {}".format(R)) return L @@ -107,10 +107,10 @@ def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): if n == 0: from sage.algebras.lie_algebras.structure_coefficients import AbelianLieAlgebra - return AbelianLieAlgebra(R, names) + return AbelianLieAlgebra(R, names=names) if n == 1: - L = three_dimensional(R, 0, 1, 0, 0, names) # Strictly upper triangular matrices + L = three_dimensional(R, 0, 1, 0, 0, names=names) # Strictly upper triangular matrices L.rename("Lie algebra of 3x3 strictly upper triangular matrices over {}".format(R)) return L @@ -183,7 +183,7 @@ def sl(R, n, representation='bracket'): E = MS([[0,1],[0,0]]) F = MS([[0,0],[1,0]]) H = MS([[1,0],[0,-1]]) - L = LieAlgebraFromAssociative([E, F, H], ['E', 'F', 'H']) + L = LieAlgebraFromAssociative(MS, [E, F, H], ['E', 'F', 'H']) L.rename("sl2 as a matrix Lie algebra over {}".format(R)) elif representation == 'bracket': L = three_dimensional_by_rank(R, 3, names=['E', 'F', 'H']) @@ -211,12 +211,12 @@ def affine_transformations_line(R, names=['X', 'Y'], representation='bracket'): one = R.one() gens = tuple(MS({(0,i):one}) for i in range(2)) from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative - return LieAlgebraFromAssociative(gens, names) + return LieAlgebraFromAssociative(MS, gens, names=names) X = names[0] Y = names[1] from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients s_coeff = {(X,Y): {Y:R.one()}} - L = LieAlgebraWithStructureCoefficients(R, s_coeff, names) + L = LieAlgebraWithStructureCoefficients(R, s_coeff, names=names) L.rename("Lie algebra of affine transformations of a line over {}".format(R)) return L @@ -292,7 +292,7 @@ def upper_triangluar_matrices(R, n): names += tuple('t{}'.format(i) for i in range(n)) gens = [MS({(i,i+1):one}) for i in range(n-1)] gens += [MS({(i,i):one}) for i in range(n)] - L = LieAlgebraFromAssociative(gens, names) + L = LieAlgebraFromAssociative(MS, gens, names=names) L.rename("Lie algebra of {}-dimensional upper triangular matrices over {}".format(n, L.base_ring())) return L @@ -312,7 +312,7 @@ def strictly_upper_triangular_matrices(R, n): one = R.one() names = tuple('n{}'.format(i) for i in range(n-1)) gens = tuple(MS({(i,i+1):one}) for i in range(n-1)) - L = LieAlgebraFromAssociative(gens, names) + L = LieAlgebraFromAssociative(MS, gens, names=names) L.rename("Lie algebra of {}-dimensional strictly upper triangular matrices over {}".format(n, L.base_ring())) return L diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 58ee14480fa..d6d97e8a0e8 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -36,7 +36,7 @@ from sage.categories.map import Map from sage.categories.homset import Hom -from sage.algebras.free_algebra import FreeAlgebra +from sage.algebras.free_algebra import FreeAlgebra, is_FreeAlgebra from sage.algebras.lie_algebras.lie_algebra_element import (LieAlgebraElement, LieAlgebraElementWrapper) from sage.rings.all import ZZ @@ -150,7 +150,7 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): sage: L = LieAlgebra(QQ, 'x,y,z'); L # not tested #16823 Free Lie algebra generated by (x, y, z) over Rational Field sage: P. = LieAlgebra(QQ, representation="polynomial"); P - Lie algebra generated by (a, c, b) from + Lie algebra generated by (a, c, b) in Free Algebra on 3 generators (a, b, c) over Rational Field We currently (:trac:`16823`) have the free Lie algebra given in the @@ -261,8 +261,7 @@ def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, # free (associative unital) algebra # TODO: Change this to accept an index set once FreeAlgebra accepts one F = FreeAlgebra(R, names) - return LieAlgebraFromAssociative(list(F.algebra_generators()), - names, index_set) + return LieAlgebraFromAssociative(F, F.gens(), names=names, index_set=index_set) raise NotImplementedError("the free Lie algebra has only been implemented using polynomials in the free algebra, see trac ticket #16823") @@ -295,7 +294,9 @@ def _standardize_names_index_set(names=None, index_set=None, ngens=None): index_set = FiniteEnumeratedSet(index_set) if names is not None: - if index_set is not None and len(names) != index_set.cardinality(): + if index_set is None: + index_set = names + elif len(names) != index_set.cardinality(): raise ValueError("the number of names must equal" " the size of the indexing set") if ngens is not None and len(names) != ngens: @@ -568,9 +569,9 @@ def gens(self): G = self.lie_algebra_generators() try: return tuple(G[i] for i in self.variable_names()) - except IndexError: + except (KeyError, IndexError): return tuple(G[i] for i in self.indices()) - except ValueError: + except (KeyError, ValueError): return tuple(G) def gen(self, i): @@ -659,7 +660,7 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): Note that the bracket of everything will be 0:: sage: R. = PolynomialRing(QQ) - sage: L. = LieAlgebra(associative=R) + sage: L = LieAlgebra(associative=R) sage: L.bracket(x, y) 0 @@ -684,7 +685,7 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(associative=S) + sage: L. = LieAlgebra(associative=S.gens()) sage: L.bracket(x, y) (2,3) - (1,3) sage: L.bracket(x, y-x) @@ -730,59 +731,82 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): True """ @staticmethod - def __classcall_private__(cls, gens, names=None, index_set=None): + def __classcall_private__(cls, A, gens=None, names=None, index_set=None): """ Normalize input to ensure a unique representation. - EXAMPLES:: + TESTS:: sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L = LieAlgebra(associative=S, names='x,y') - sage: L2 = LieAlgebra(associative=map(S, [G((1,2,3)), G((1,2))]), names='x,y') - sage: L is L2 + sage: L1 = LieAlgebra(associative=S.gens(), names='x,y') + sage: L2 = LieAlgebra(associative=[ S(G((1,2,3))), S(G((1,2))) ], names='x,y') + sage: L1 is L2 True - """ - if isinstance(gens, Parent): - A = gens - ngens = None - # Parse possible generators (i.e., a basis) from the parent - try: - gens = A.basis() + sage: F. = FreeAlgebra(QQ) + sage: L1 = LieAlgebra(associative=F) + sage: L2. = LieAlgebra(associative=F.gens()) + sage: L3. = LieAlgebra(QQ, representation="polynomial") + sage: L1 is L2 + True + """ + # If A is not a ring, then we treat it as a set of generators + if isinstance(A, Parent) and A.category().is_subcategory(Rings()): + # TODO: As part of #16823, this should instead construct a + # subclass with specialized methods for the free Lie algebra + if is_FreeAlgebra(A): + if gens is None: + gens = A.gens() if index_set is None: - try: - index_set = gens.keys() - except (AttributeError, ValueError): - pass - if names is None: - try: - names = A.variable_names() - except ValueError: - pass - except (AttributeError, NotImplementedError): - pass + index_set = A.variable_names() + elif gens is None: + # Parse possible generators (i.e., a basis) from the parent + try: + gens = A.basis() + except (AttributeError, NotImplementedError): + pass + if names is None: + try: + names = A.variable_names() + except ValueError: + pass + else: + gens = A + A = None - elif isinstance(gens, AbstractFamily): - if index_set is None: + if index_set is None: + # See if we can get an index set from the generators + try: index_set = gens.keys() + except (AttributeError, ValueError): + pass + try: + ngens = len(gens) + except (TypeError, NotImplementedError): + ngens = None + + names, index_set = LieAlgebra._standardize_names_index_set(names, index_set, ngens) + + is_fg = False # Is finitely generated + if isinstance(gens, AbstractFamily): if gens.cardinality() < float('inf'): - gens = tuple([gens[i] for i in gens.keys()]) - ngens = len(gens) + is_fg = True + try: + gens = tuple([gens[i] for i in index_set]) + except KeyError: + gens = tuple(gens) elif isinstance(gens, dict): - if index_set is None: - index_set = gens.keys() + is_fg = True gens = gens.values() - ngens = len(gens) - else: # Assume it is list-like - A = gens[0].parent() + elif gens: # Assume it is list-like + is_fg = True gens = tuple(gens) - ngens = len(gens) - - names, index_set = _standardize_names_index_set(names, index_set, ngens) - if gens is not A: # If we have a generating set + if is_fg: # If we have a finite generating set + if A is None: + A = gens[0].parent() # Make sure all the generators have the same parent of A gens = tuple(map(A, gens)) @@ -796,9 +820,9 @@ def __classcall_private__(cls, gens, names=None, index_set=None): pass return super(LieAlgebraFromAssociative, cls).__classcall__(cls, - gens, names=names, index_set=index_set) + A, gens, names=names, index_set=index_set) - def __init__(self, gens, names=None, index_set=None, category=None): + def __init__(self, A, gens, names=None, index_set=None, category=None): """ Initialize ``self``. @@ -809,11 +833,7 @@ def __init__(self, gens, names=None, index_set=None, category=None): sage: L = LieAlgebra(associative=S) sage: TestSuite(L).run() """ - if isinstance(gens, Parent): - gens = None - self._assoc = gens - else: - self._assoc = gens[0].parent() + self._assoc = A R = self._assoc.base_ring() # We strip the following axioms from the category of the assoc. algebra: @@ -827,12 +847,12 @@ def __init__(self, gens, names=None, index_set=None, category=None): FinitelyGeneratedLieAlgebra.__init__(self, R, names, index_set, category) if isinstance(gens, tuple): - F = Family({self._indices[i]: self.element_class(self, v) - for i,v in enumerate(gens)}) + gens = Family({self._indices[i]: self.element_class(self, v) + for i,v in enumerate(gens)}) elif gens is not None: # It is a family - F = Family(self._indices, lambda i: self.element_class(self, gens[i]), - name="generator map") - self._gens = F + gens = Family(self._indices, lambda i: self.element_class(self, gens[i]), + name="generator map") + self._gens = gens # We don't need to store the original generators because we can # get them from lifting this object's generators @@ -863,10 +883,20 @@ def _repr_(self): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(associative=S) + sage: LieAlgebra(associative=S) + Lie algebra generated by ((2,3), (1,3), (1,2), (1,3,2), (), (1,2,3)) + in Group algebra of group + "Symmetric group of order 3! as a permutation group" + over base ring Rational Field + sage: LieAlgebra(associative=S.gens()) + Lie algebra generated by ((1,2,3), (1,2)) + in Group algebra of group + "Symmetric group of order 3! as a permutation group" + over base ring Rational Field """ - return "Lie algebra generated by {} from {}".format( - tuple(self._gens), self._assoc) + if self._gens is not None: + return "Lie algebra generated by {} in {}".format(tuple(self._gens), self._assoc) + return "Lie algebra of {}".format(self._assoc) def _element_constructor_(self, x): """ @@ -875,7 +905,7 @@ def _element_constructor_(self, x): EXAMPLES:: sage: G = SymmetricGroup(3) - sage: A = G.group_algebra(QQ) + sage: S = GroupAlgebra(G, QQ) sage: L = LieAlgebra(associative=S) sage: x,y = S.algebra_generators() sage: elt = L(x - y); elt @@ -915,7 +945,8 @@ def lie_algebra_generators(self): sage: S = GroupAlgebra(G, QQ) sage: L = LieAlgebra(associative=S) sage: L.lie_algebra_generators() - Finite family {'y': (1,2), 'x': (1,2,3)} + Finite family {(2,3): (2,3), (1,3): (1,3), (1,2,3): (1,2,3), + (): (), (1,2): (1,2), (1,3,2): (1,3,2)} """ return self._gens @@ -925,7 +956,8 @@ def monomial(self, i): EXAMPLES:: - sage: L. = LieAlgebra(QQ, representation="polynomial") + sage: F. = FreeAlgebra(QQ) + sage: L = LieAlgebra(associative=F) sage: L.monomial('x') x """ @@ -940,7 +972,8 @@ def term(self, i, c=None): EXAMPLES:: - sage: L. = LieAlgebra(QQ, representation="polynomial") + sage: F. = FreeAlgebra(QQ) + sage: L = LieAlgebra(associative=F) sage: L.term('x', 4) 4*x """ @@ -958,7 +991,7 @@ def zero(self): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(associative=S) + sage: L = LieAlgebra(associative=S) sage: L.zero() 0 """ @@ -971,11 +1004,12 @@ def is_abelian(self): EXAMPLES:: sage: R = FreeAlgebra(QQ, 2, 'x,y') - sage: L. = LieAlgebra(associative=R) + sage: L = LieAlgebra(associative=R) sage: L.is_abelian() False + sage: R = PolynomialRing(QQ, 'x,y') - sage: L. = LieAlgebra(associative=R) + sage: L = LieAlgebra(associative=R) sage: L.is_abelian() True @@ -983,7 +1017,7 @@ def is_abelian(self): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(associative=S) + sage: L = LieAlgebra(associative=S) sage: L.is_abelian() False @@ -1008,14 +1042,13 @@ def _bracket_(self, rhs): EXAMPLES:: - sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(associative=R) + sage: L. = LieAlgebra(QQ, representation="polynomial") sage: L.bracket(x, y) x*y - y*x sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(associative=S) + sage: L. = LieAlgebra(associative=S.gens()) sage: L.bracket(x, y) (2,3) - (1,3) @@ -1034,7 +1067,7 @@ def lift(self): EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(associative=R) + sage: L. = LieAlgebra(associative=R.gens()) sage: x.lift() x sage: x.lift().parent() diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 293317ebc2e..263bcd5ddb3 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -36,7 +36,7 @@ from sage.algebras.free_algebra import FreeAlgebra from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement -from sage.algebras.lie_algebras.lie_algebra import FinitelyGeneratedLieAlgebra +from sage.algebras.lie_algebras.lie_algebra import LieAlgebra, FinitelyGeneratedLieAlgebra #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra #from sage.algebras.lie_algebras.ideal import LieAlgebraIdeal #from sage.algebras.lie_algebras.quotient import QuotientLieAlgebra @@ -83,7 +83,7 @@ def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, **kwds): sage: L1 is L2 True """ - names, index_set = _standardize_names_index_set(names, index_set) + names, index_set = LieAlgebra._standardize_names_index_set(names, index_set) s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff(s_coeff) if len(s_coeff) == 0: @@ -283,7 +283,17 @@ class AbelianLieAlgebra(LieAlgebraWithStructureCoefficients): sage: L.bracket(x, y) 0 """ - def __init__(self, R, names=None, index_set=None, **kwds): + @staticmethod + def __classcall_private__(cls, R, names=None, index_set=None, **kwds): + """ + Normalize input to ensure a unique representation. + + TESTS:: + """ + names, index_set = LieAlgebra._standardize_names_index_set(names, index_set) + return super(AbelianLieAlgebra, cls).__classcall__(cls, R, names, index_set, **kwds) + + def __init__(self, R, names, index_set, **kwds): """ Initialize ``self``. From e9587d79b19f7dd096c32e3f05282457665e6099 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 17 Feb 2015 16:05:51 -0800 Subject: [PATCH 022/223] Added a custom lift morphism for Lie alg from assoc. --- src/sage/algebras/lie_algebras/lie_algebra.py | 49 ++++++++++++++----- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index d6d97e8a0e8..2d83da5ce12 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -30,7 +30,7 @@ from sage.structure.element_wrapper import ElementWrapper from sage.categories.algebras import Algebras -from sage.categories.lie_algebras import LieAlgebras +from sage.categories.lie_algebras import LieAlgebras, LiftMorphism from sage.categories.rings import Rings from sage.categories.morphism import Morphism, SetMorphism from sage.categories.map import Map @@ -277,6 +277,11 @@ def _standardize_names_index_set(names=None, index_set=None, ngens=None): having ``names``. Should this method be moved to :class:`IndexedGenerators`? """ + if isinstance(names, str): + names = tuple(names.split(',')) + elif names is not None: + names = tuple(names) + if index_set is None: if names is None: raise ValueError("either the names of the generators" @@ -285,11 +290,6 @@ def _standardize_names_index_set(names=None, index_set=None, ngens=None): # be the names index_set = tuple(names) - if isinstance(names, str): - names = tuple(names.split(',')) - elif names is not None: - names = tuple(names) - if isinstance(index_set, (tuple, list)): index_set = FiniteEnumeratedSet(index_set) @@ -661,6 +661,7 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): sage: R. = PolynomialRing(QQ) sage: L = LieAlgebra(associative=R) + sage: x, y = L(a), L(b) sage: L.bracket(x, y) 0 @@ -675,7 +676,8 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): sage: L.bracket(x-y, L.bracket(x,y)) a^2*b - 2*a*b*a + a*b^2 + b*a^2 - 2*b*a*b + b^2*a - We can also use a subset of the generators to use in our Lie algebra:: + We can also use a subset of the generators to use as a generating set + of the Lie algebra:: sage: R. = FreeAlgebra(QQ, 3) sage: L. = LieAlgebra(associative=[a,b]) @@ -739,7 +741,7 @@ def __classcall_private__(cls, A, gens=None, names=None, index_set=None): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L1 = LieAlgebra(associative=S.gens(), names='x,y') + sage: L1 = LieAlgebra(associative=tuple(S.gens()), names=['x','y']) sage: L2 = LieAlgebra(associative=[ S(G((1,2,3))), S(G((1,2))) ], names='x,y') sage: L1 is L2 True @@ -856,9 +858,10 @@ def __init__(self, A, gens, names=None, index_set=None, category=None): # We don't need to store the original generators because we can # get them from lifting this object's generators - # We construct the lift map in order to register the coercion - # here since the UEA already exists - self.lift + # We construct the (custom) lift map in order to register the + # coercion here since the UEA already exists + self.lift = LiftMorphismFromAssociative(self, self._assoc) + self.lift.register_as_coercion() def _repr_option(self, key): """ @@ -1075,3 +1078,27 @@ def lift(self): """ return self.value +class LiftMorphismFromAssociative(LiftMorphism): + """ + The natural lifting morphism from a Lie algebra constructed from + an associative algebra `A` to `A`. + """ + def preimage(self, x): + """ + Return the preimage of ``x`` under ``self``. + """ + return self.domain().element_class(self.domain(), x) + + def _call_(self, x): + """ + Return the image of ``x`` under ``self``. + """ + return x.value + + def section(self): + """ + Return the section map of ``self``. + """ + return SetMorphism(Hom(self.codomain(), self.domain()), + self.preimage) + From 65c1f5451f4f496fa0f52d66606de806dda60a43 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 17 Feb 2015 16:09:09 -0800 Subject: [PATCH 023/223] Removed the LiftMorphism.section map. --- src/sage/categories/lie_algebras.py | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index d343dae3295..d88ceea9276 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -585,22 +585,3 @@ def _call_(self, x): """ return x.lift() - def section(self): - """ - Return the section map of ``self``. - - EXAMPLES:: - - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.lift.section() - Traceback (most recent call last): - ... - NotImplementedError - - .. TODO:: - - Implement the section map from an enveloping algebra to the - corresponding Lie algebra. - """ - raise NotImplementedError - From 87bba39ede0cfea37bb5e92b81aa851a2420863e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 17 Feb 2015 16:26:43 -0800 Subject: [PATCH 024/223] Fixing the last issues from the changes. --- src/sage/algebras/lie_algebras/heisenberg.py | 10 +++--- src/sage/algebras/lie_algebras/lie_algebra.py | 31 +++++++++++++++++++ .../lie_algebras/lie_algebra_element.py | 2 +- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index 6a5d1989ae1..0129944ff30 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -223,7 +223,8 @@ def basis(self): d['z'] = self.z() return Family(d) -class HeisenbergAlgebra(HeisenbergAlgebra_fd, HeisenbergAlgebra_abstract, FinitelyGeneratedLieAlgebra): +class HeisenbergAlgebra(HeisenbergAlgebra_fd, HeisenbergAlgebra_abstract, + FinitelyGeneratedLieAlgebra): """ A Heisenberg algebra defined using structure coefficients. @@ -265,7 +266,8 @@ def __init__(self, R, n): """ HeisenbergAlgebra_fd.__init__(self, n) names = ['p%s'%i for i in range(1,n+1)] + ['q%s'%i for i in range(1,n+1)] #+ ['z'] - FinitelyGeneratedLieAlgebra.__init__(self, R, names, + names = tuple(names) + FinitelyGeneratedLieAlgebra.__init__(self, R, names=names, index_set=names, category=LieAlgebras(R).FiniteDimensional().WithBasis()) HeisenbergAlgebra_abstract.__init__(self, names) @@ -431,8 +433,8 @@ def __init__(self, R, n): names = tuple('p%s'%i for i in range(1,n+1)) names = names + tuple('q%s'%i for i in range(1,n+1)) + ('z',) cat = LieAlgebras(R).FiniteDimensional().WithBasis() - LieAlgebraFromAssociative.__init__(self, p + q + (MS({(0,n+1):one}),), - names=names, category=cat) + LieAlgebraFromAssociative.__init__(self, MS, p + q + (MS({(0,n+1):one}),), + names=names, index_set=names, category=cat) def _repr_(self): """ diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 2d83da5ce12..048ff3c738e 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -1086,18 +1086,49 @@ class LiftMorphismFromAssociative(LiftMorphism): def preimage(self, x): """ Return the preimage of ``x`` under ``self``. + + EXAMPLES:: + + sage: R = FreeAlgebra(QQ, 3, 'a,b,c') + sage: L = LieAlgebra(associative=R) + sage: x,y,z = R.gens() + sage: f = L.lift + sage: p = f.preimage(x*y - z); p + -c + a*b + sage: p.parent() is L + True """ return self.domain().element_class(self.domain(), x) def _call_(self, x): """ Return the image of ``x`` under ``self``. + + EXAMPLES:: + + sage: R = FreeAlgebra(QQ, 3, 'x,y,z') + sage: L. = LieAlgebra(associative=R) + sage: f = L.lift + sage: a = f(L([x,y]) + z); a + z + x*y - y*x + sage: a.parent() is R + True """ return x.value def section(self): """ Return the section map of ``self``. + + EXAMPLES:: + + sage: R = FreeAlgebra(QQ, 3, 'x,y,z') + sage: L. = LieAlgebra(associative=R) + sage: f = L.lift + sage: f.section() + Generic morphism: + From: Free Algebra on 3 generators (x, y, z) over Rational Field + To: Lie algebra generated by (y, x, z) in Free Algebra on 3 generators (x, y, z) over Rational Field """ return SetMorphism(Hom(self.codomain(), self.domain()), self.preimage) diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index 34bb1d91d9b..e736817eb09 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -232,7 +232,7 @@ def __mul__(self, x): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) - sage: L. = LieAlgebra(associative=S) + sage: L. = LieAlgebra(associative=S.gens()) sage: x*y - y*x (2,3) - (1,3) """ From 980545eafb913863a66a06f1e4d5d2e61141490a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 27 Feb 2015 23:00:49 -0800 Subject: [PATCH 025/223] Fixed the doc. --- .../finite_dimensional_lie_algebras_with_basis.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 d61cdaa581d..687b9a964fa 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -101,9 +101,9 @@ def killing_matrix(self, x, y): r""" Return the Killing matrix of ``x`` and ``y``. - The Killing form is defined as the matrix corresponding to the - action of `\mathrm{ad}_x \circ \mathrm{ad}_y` in the basis - of ``self``. + The Killing matrix is defined as the matrix corresponding + to the action of `\mathrm{ad}_x \circ \mathrm{ad}_y` in + the basis of ``self``. EXAMPLES:: From 9b08311a7902b9c3d7d62518b2b52d38743b81a8 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Mon, 9 Mar 2015 15:39:29 -0400 Subject: [PATCH 026/223] a few questions to boot --- ...ite_dimensional_lie_algebras_with_basis.py | 48 ++++++++++++++++++- src/sage/categories/examples/lie_algebras.py | 30 ++++++++++-- ...ite_dimensional_lie_algebras_with_basis.py | 22 +++++---- .../categories/lie_algebras_with_basis.py | 2 +- 4 files changed, 88 insertions(+), 14 deletions(-) diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index 114937b161c..a9443c83455 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -22,8 +22,51 @@ class AbelianLieAlgebra(Parent, UniqueRepresentation): An example of a finite dimensional Lie algebra with basis: the abelian Lie algebra. + Let `R` be a commutative ring, and `M` an `R`-module. The + *abelian Lie algebra* on `M` is the `R`-Lie algebra + obtained by endowing `M` with the trivial Lie bracket + (`[a, b] = 0` for all `a, b \in M`). + This class illustrates a minimal implementation of a finite dimensional Lie algebra with basis. + + INPUT: + + - ``R`` -- base ring + + - ``names`` -- list of strings, to be used as identifiers for + the basis elements of `M` + + - ``M`` -- an `R`-module (default: the free `R`-module of + rank ``len(names)``) to serve as the ground space for the + Lie algebra + + - ``ambient`` -- (optional) a Lie algebra; if this is set, + then the resulting Lie algebra is declared a Lie subalgebra + of ``ambient`` + + OUTPUT: + + The abelian Lie algebra on `M`. + + .. TODO:: + + Have I correctly explained these? + + .. TODO:: + + Why am I required to specify ``names`` if the actual + elements of the Lie algebra end up being anonymous + vectors anyway? + + sage: from sage.categories.examples.finite_dimensional_lie_algebras_with_basis import * + sage: AbelianLieAlgebra(QQ, ['x','y']) + An example of a finite dimensional Lie algebra with + basis: the abelian Lie algebra with generators + ('x', 'y') over Rational Field + sage: _.gens() + ((1, 0), (0, 1)) + """ @staticmethod def __classcall_private__(cls, R, names, M=None, ambient=None): @@ -151,7 +194,10 @@ def ambient(self): def subalgebra(self, gens, names='x'): """ - Return a subalgebra of ``self``. + Return the Lie subalgebra of ``self`` generated by the + elements of the iterable ``gens``. + + This currently requires the ground ring `R` to be a field. EXAMPLES:: diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py index 0b1ce914be0..774152a2e45 100644 --- a/src/sage/categories/examples/lie_algebras.py +++ b/src/sage/categories/examples/lie_algebras.py @@ -17,14 +17,32 @@ class LieAlgebraFromAssociative(Parent, UniqueRepresentation): r""" - An example of a Lie algebra: a Lie algebra from an associative algebra. + An example of a Lie algebra: a Lie algebra from an associative + algebra. + + Let `R` be a commutative ring, and `A` an associative + `R`-algebra. The Lie algebra `A` (sometimes denoted `A^-`) + is defined to be the `R`-module `A` with Lie bracket given by + the commutator in `A`: that is, `[a, b] := ab - ba` for all + `a, b \in A`. This class illustrates a minimal implementation of a Lie algebra. - EXAMPLES: + INPUT: + + - ``R`` -- base ring + + .. TODO:: - We create an example of `\mathfrak{sl}_2` using matrices:: + I don't see how this class is supposed to be + instantiated. Apparently I am supposed to pass it a + nonempty (bad requirement if you ask me) list of + generators. Shouldn't I rather be asked for the + associative algebra `A` ? + EXAMPLES: + + We create a model of `\mathfrak{sl}_2` using matrices:: sage: gens = [matrix([[0,1],[0,0]]), matrix([[0,0],[1,0]]), matrix([[1,0],[0,-1]])] sage: for g in gens: @@ -111,6 +129,12 @@ def lie_algebra_generators(self): """ Return the generators of ``self`` as a Lie algebra. + .. TODO:: + + This is false (including the doctest). The generators + of an algebra seldom generate its Lie algebra. I'd + rather use the basis. + EXAMPLES:: sage: L = LieAlgebras(QQ).example() 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 687b9a964fa..f1fc2141830 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -208,6 +208,10 @@ def centralizer(self, S): """ Return the centralizer of ``S`` in ``self``. + .. TODO:: + + What is S? + EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() @@ -351,17 +355,17 @@ def derived_series(self): [\mathfrak{g}^{(k)}, \mathfrak{g}^{(k)}] and recall that - `\mathfrak{g}^{(k)} \subseteq \mathfrak{g}^{(k+1)}`. - Alternatively we canexpress this as + `\mathfrak{g}^{(k)} \supseteq \mathfrak{g}^{(k+1)}`. + Alternatively we can express this as .. MATH:: - \mathfrak{g} \subseteq [\mathfrak{g}, \mathfrak{g}] \subseteq + \mathfrak{g} \supseteq [\mathfrak{g}, \mathfrak{g}] \supseteq \bigl[ [\mathfrak{g}, \mathfrak{g}], [\mathfrak{g}, - \mathfrak{g}] \bigr] \subseteq + \mathfrak{g}] \bigr] \supseteq \biggl[ \bigl[ [\mathfrak{g}, \mathfrak{g}], [\mathfrak{g}, \mathfrak{g}] \bigr], \bigl[ [\mathfrak{g}, \mathfrak{g}], - [\mathfrak{g}, \mathfrak{g}] \bigr] \biggr] \subseteq \cdots. + [\mathfrak{g}, \mathfrak{g}] \bigr] \biggr] \supseteq \cdots. EXAMPLES:: @@ -407,15 +411,15 @@ def lower_central_series(self): \mathfrak{g}_{k+1} = [\mathfrak{g}, \mathfrak{g}_{k}] - and recall that `\mathfrak{g}_k} \subseteq \mathfrak{g}_{k+1}`. + and recall that `\mathfrak{g}_k} \supseteq \mathfrak{g}_{k+1}`. Alternatively we can express this as .. MATH:: - \mathfrak{g} \subseteq [\mathfrak{g}, \mathfrak{g}] \subseteq + \mathfrak{g} \supseteq [\mathfrak{g}, \mathfrak{g}] \supseteq \bigl[ [\mathfrak{g}, \mathfrak{g}], \mathfrak{g} \bigr] - \subseteq\biggl[\bigl[ [\mathfrak{g}, \mathfrak{g}], - \mathfrak{g} \bigr], \mathfrak{g}\biggr] \subseteq \cdots. + \supseteq\biggl[\bigl[ [\mathfrak{g}, \mathfrak{g}], + \mathfrak{g} \bigr], \mathfrak{g}\biggr] \supseteq \cdots. EXAMPLES:: diff --git a/src/sage/categories/lie_algebras_with_basis.py b/src/sage/categories/lie_algebras_with_basis.py index 93f460521ca..51856eefe2d 100644 --- a/src/sage/categories/lie_algebras_with_basis.py +++ b/src/sage/categories/lie_algebras_with_basis.py @@ -95,7 +95,7 @@ def free_module(self): class ElementMethods: def _bracket_(self, y): """ - Return the Lie bracket of ``[self, y]``. + Return the Lie bracket ``[self, y]``. EXAMPLES:: From 5a0bc7df31648bbde2ab8f5181f4930ea74feee5 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 12 Mar 2015 17:54:16 -0700 Subject: [PATCH 027/223] Answering some questions. --- ...ite_dimensional_lie_algebras_with_basis.py | 12 ++++++---- src/sage/categories/examples/lie_algebras.py | 22 ++++--------------- ...ite_dimensional_lie_algebras_with_basis.py | 5 +++-- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index a9443c83455..e5abb7c0f57 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -11,6 +11,7 @@ from sage.misc.cachefunc import cached_method from sage.sets.family import Family from sage.categories.all import LieAlgebras +from sage.rings.all import ZZ from sage.modules.free_module import FreeModule from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -49,10 +50,6 @@ class AbelianLieAlgebra(Parent, UniqueRepresentation): The abelian Lie algebra on `M`. - .. TODO:: - - Have I correctly explained these? - .. TODO:: Why am I required to specify ``names`` if the actual @@ -81,9 +78,16 @@ def __classcall_private__(cls, R, names, M=None, ambient=None): sage: A3 = AbelianLieAlgebra(QQ, ['x','y','z'], FreeModule(QQ, 3)) sage: A1 is A2 and A2 is A3 True + + sage: A1 = AbelianLieAlgebra(QQ, 'x0,x1') + sage: A2 = AbelianLieAlgebra(QQ, 2) + sage: A1 is A2 + True """ if isinstance(names, str): names = names.split(',') + elif names in ZZ: + names = ['x%s'%i for i in range(names)] if M is None: M = FreeModule(R, len(names)) elif len(names) != M.dimension(): diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py index 774152a2e45..79b6cbf7fd3 100644 --- a/src/sage/categories/examples/lie_algebras.py +++ b/src/sage/categories/examples/lie_algebras.py @@ -17,8 +17,10 @@ class LieAlgebraFromAssociative(Parent, UniqueRepresentation): r""" - An example of a Lie algebra: a Lie algebra from an associative - algebra. + An example of a Lie algebra: a Lie algebra generated by + a set of elements of an associative algebra. + + This class illustrates a minimal implementation of a Lie algebra. Let `R` be a commutative ring, and `A` an associative `R`-algebra. The Lie algebra `A` (sometimes denoted `A^-`) @@ -26,20 +28,10 @@ class LieAlgebraFromAssociative(Parent, UniqueRepresentation): the commutator in `A`: that is, `[a, b] := ab - ba` for all `a, b \in A`. - This class illustrates a minimal implementation of a Lie algebra. - INPUT: - ``R`` -- base ring - .. TODO:: - - I don't see how this class is supposed to be - instantiated. Apparently I am supposed to pass it a - nonempty (bad requirement if you ask me) list of - generators. Shouldn't I rather be asked for the - associative algebra `A` ? - EXAMPLES: We create a model of `\mathfrak{sl}_2` using matrices:: @@ -129,12 +121,6 @@ def lie_algebra_generators(self): """ Return the generators of ``self`` as a Lie algebra. - .. TODO:: - - This is false (including the doctest). The generators - of an algebra seldom generate its Lie algebra. I'd - rather use the basis. - EXAMPLES:: sage: L = LieAlgebras(QQ).example() 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 f1fc2141830..4bbdea327cd 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -208,9 +208,10 @@ def centralizer(self, S): """ Return the centralizer of ``S`` in ``self``. - .. TODO:: + INPUT: - What is S? + - ``S`` -- a subalgebra of ``self`` or a set of elements which + represent generators for a subalgebra EXAMPLES:: From 144a5a5e6432062279a8600f8acd24f7083051f9 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 12 Mar 2015 17:57:28 -0700 Subject: [PATCH 028/223] Small fix for the doc. --- src/sage/categories/examples/lie_algebras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py index 79b6cbf7fd3..a5da1500cf1 100644 --- a/src/sage/categories/examples/lie_algebras.py +++ b/src/sage/categories/examples/lie_algebras.py @@ -30,7 +30,7 @@ class LieAlgebraFromAssociative(Parent, UniqueRepresentation): INPUT: - - ``R`` -- base ring + - ``gens`` -- a set of elements of an associative algebra EXAMPLES: From 198f8a8db695921d8f7ae5fdabc4a6bdd7388f7b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 12 Mar 2015 18:45:24 -0700 Subject: [PATCH 029/223] Added new categories to documentation. --- src/doc/en/reference/categories/index.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/doc/en/reference/categories/index.rst b/src/doc/en/reference/categories/index.rst index ef69b30335e..4f59fd21d2d 100644 --- a/src/doc/en/reference/categories/index.rst +++ b/src/doc/en/reference/categories/index.rst @@ -81,6 +81,7 @@ Categories sage/categories/finite_dimensional_bialgebras_with_basis sage/categories/finite_dimensional_coalgebras_with_basis sage/categories/finite_dimensional_hopf_algebras_with_basis + sage/categories/finite_dimensional_lie_algebras_with_basis.py sage/categories/finite_dimensional_modules_with_basis sage/categories/finite_enumerated_sets sage/categories/finite_fields @@ -116,6 +117,8 @@ Categories sage/categories/integral_domains sage/categories/lattice_posets sage/categories/left_modules + sage/categories/lie_algebras.py + sage/categories/lie_algebras_with_basis.py sage/categories/magmas sage/categories/magmas_and_additive_magmas sage/categories/magmatic_algebras @@ -172,11 +175,14 @@ Examples of parents using categories sage/categories/examples/facade_sets sage/categories/examples/finite_coxeter_groups sage/categories/examples/finite_enumerated_sets + sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py sage/categories/examples/finite_monoids sage/categories/examples/finite_semigroups sage/categories/examples/finite_weyl_groups sage/categories/examples/hopf_algebras_with_basis sage/categories/examples/infinite_enumerated_sets + sage/categories/examples/lie_algebras.py + sage/categories/examples/lie_algebras_with_basis.py sage/categories/examples/monoids sage/categories/examples/posets sage/categories/examples/semigroups_cython From ece3cd9d8ae826f28b82935d638de1f5df9d90a9 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 12 Mar 2015 18:50:24 -0700 Subject: [PATCH 030/223] Added files to the documentation. --- src/doc/en/reference/algebras/index.rst | 4 ++++ src/doc/en/reference/algebras/lie_algebras.rst | 13 +++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/doc/en/reference/algebras/lie_algebras.rst diff --git a/src/doc/en/reference/algebras/index.rst b/src/doc/en/reference/algebras/index.rst index 4e5792d031b..bdec3e106bd 100644 --- a/src/doc/en/reference/algebras/index.rst +++ b/src/doc/en/reference/algebras/index.rst @@ -33,6 +33,9 @@ Algebras sage/algebras/affine_nil_temperley_lieb sage/algebras/hall_algebra + + lie_algebras + sage/algebras/jordan_algebra sage/algebras/quatalg/quaternion_algebra @@ -47,3 +50,4 @@ Algebras sage/algebras/weyl_algebra .. include:: ../footer.txt + diff --git a/src/doc/en/reference/algebras/lie_algebras.rst b/src/doc/en/reference/algebras/lie_algebras.rst new file mode 100644 index 00000000000..23a49b8f498 --- /dev/null +++ b/src/doc/en/reference/algebras/lie_algebras.rst @@ -0,0 +1,13 @@ +Lie Algebras +============ + +.. toctree:: + :maxdepth: 2 + + sage/algebras/lie_algebras/examples.py + sage/algebras/lie_algebras/heisenberg.py + sage/algebras/lie_algebras/lie_algebra.py + sage/algebras/lie_algebras/lie_algebra_element.py + sage/algebras/lie_algebras/structure_coefficients.py + sage/algebras/lie_algebras/virasoro.py + From 845e5aa14b7c97edeb04859fc92ebc63a78be1cb Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 17 Mar 2015 11:10:18 -0700 Subject: [PATCH 031/223] Some last tweaks and getting full coverage. --- src/sage/algebras/lie_algebras/lie_algebra.py | 51 ++++++++++++++++--- .../lie_algebras/structure_coefficients.py | 5 ++ 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 048ff3c738e..e0bda89ad2d 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -276,6 +276,40 @@ def _standardize_names_index_set(names=None, index_set=None, ngens=None): inheriting from :class:`IndexedGenerators` and (potentially) having ``names``. Should this method be moved to :class:`IndexedGenerators`? + + TESTS:: + + sage: LieAlgebra._standardize_names_index_set('x,y') + (('x', 'y'), {'x', 'y'}) + sage: LieAlgebra._standardize_names_index_set(['x','y']) + (('x', 'y'), {'x', 'y'}) + sage: LieAlgebra._standardize_names_index_set(['x','y'], ['a','b']) + (('x', 'y'), {'a', 'b'}) + sage: LieAlgebra._standardize_names_index_set('x,y', ngens=2) + (('x', 'y'), {'x', 'y'}) + sage: LieAlgebra._standardize_names_index_set(index_set=['a','b'], ngens=2) + (None, {'a', 'b'}) + + sage: LieAlgebra._standardize_names_index_set() + Traceback (most recent call last): + ... + ValueError: either the names of the generators or the index set must be specified + sage: LieAlgebra._standardize_names_index_set(['x'], ['a', 'b']) + Traceback (most recent call last): + ... + ValueError: the number of names must equal the size of the indexing set + sage: LieAlgebra._standardize_names_index_set('x,y', ['a']) + Traceback (most recent call last): + ... + ValueError: the number of names must equal the size of the indexing set + sage: LieAlgebra._standardize_names_index_set('x,y,z', ngens=2) + Traceback (most recent call last): + ... + ValueError: the number of names must equal the number of generators + sage: LieAlgebra._standardize_names_index_set(index_set=['a'], ngens=2) + Traceback (most recent call last): + ... + ValueError: the size of the indexing set must equal the number of generators """ if isinstance(names, str): names = tuple(names.split(',')) @@ -644,10 +678,12 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): A Lie algebra whose elements are from an associative algebra and whose bracket is the commutator. - .. WARNING:: + .. TODO:: - The returned universal enveloping algebra is too large in general. - To fix this, we need subalgebras implemented. + Split this class into 2 classes, the base class for the Lie + algebra corresponding to the full associative algebra and a + subclass for the Lie subalgebra (of the full algebra) + generated by a generating set. .. TODO:: @@ -858,8 +894,7 @@ def __init__(self, A, gens, names=None, index_set=None, category=None): # We don't need to store the original generators because we can # get them from lifting this object's generators - # We construct the (custom) lift map in order to register the - # coercion here since the UEA already exists + # We construct the lift map to the associative algebra self.lift = LiftMorphismFromAssociative(self, self._assoc) self.lift.register_as_coercion() @@ -924,16 +959,16 @@ def _element_constructor_(self, x): return self(x[0])._bracket_(self(x[1])) return self.element_class(self, self._assoc(x)) - def _construct_UEA(self): + def associative_algebra(self): """ - Construct the universal enveloping algebra of ``self``. + Construct the associative algebra used to construct ``self``. EXAMPLES:: sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) sage: L = LieAlgebra(associative=S) - sage: L._construct_UEA() is S + sage: L.associative_algebra() is S True """ return self._assoc diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 263bcd5ddb3..de0ce75de2d 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -289,6 +289,11 @@ def __classcall_private__(cls, R, names=None, index_set=None, **kwds): Normalize input to ensure a unique representation. TESTS:: + + sage: L1 = LieAlgebra(QQ, 'x,y', {}) + sage: L2. = LieAlgebra(QQ, abelian=True) + sage: L1 is L2 + True """ names, index_set = LieAlgebra._standardize_names_index_set(names, index_set) return super(AbelianLieAlgebra, cls).__classcall__(cls, R, names, index_set, **kwds) From 6b3a6233c67b044d9a1787aef1085fea4d645358 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 18 Mar 2015 06:01:38 +0100 Subject: [PATCH 032/223] review of src/sage/categories/examples/lie_algebras.py --- src/sage/categories/category.py | 2 +- src/sage/categories/examples/lie_algebras.py | 23 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index 66d10edf186..5d77bf381db 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -2625,7 +2625,7 @@ def category_graph(categories = None): Graphics object consisting of 20 graphics primitives sage: sage.categories.category.category_graph().plot() - Graphics object consisting of 312 graphics primitives + Graphics object consisting of 314 graphics primitives """ from sage import graphs if categories is None: diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py index a5da1500cf1..60da4865a0f 100644 --- a/src/sage/categories/examples/lie_algebras.py +++ b/src/sage/categories/examples/lie_algebras.py @@ -28,9 +28,22 @@ class LieAlgebraFromAssociative(Parent, UniqueRepresentation): the commutator in `A`: that is, `[a, b] := ab - ba` for all `a, b \in A`. + What this class implements is not precisely `A^-`, however; + it is the Lie subalgebra of `A^-` generated by the elements + of the iterable ``gens``. This specific implementation does not + provide a reasonable containment test (i.e., it does not allow + you to check if a given element `a` of `A^-` belongs to this + Lie subalgebra); it, however, allows computing inside it. + INPUT: - - ``gens`` -- a set of elements of an associative algebra + - ``gens`` -- a nonempty iterable consisting of elements of an + associative algebra `A` + + OUTPUT: + + The Lie subalgebra of `A^-` generated by the elements of + ``gens`` EXAMPLES: @@ -138,6 +151,10 @@ def __eq__(self, rhs): """ Check equality. + This check is rather restrictive: ``self`` and ``rhs`` are only + revealed as equal if they are equal *and* have the same parent + (or both are zero). + EXAMPLES:: sage: L = LieAlgebras(QQ).example() @@ -226,7 +243,9 @@ def _acted_upon_(self, scalar, self_on_left=False): sage: x,y = L.lie_algebra_generators() sage: 3 * x 3*[2, 1, 3] - sage: y / 4 + sage: y / QQ(4) + 1/4*[2, 3, 1] + sage: y / 4 # not tested: todo 1/4*[2, 3, 1] """ # This was copied, but IDK if it still applies: From 3f07d055c8fb0a7da1d1ef7d2eaddb7d177fa6b8 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 18 Mar 2015 06:08:43 +0100 Subject: [PATCH 033/223] fixing another doctest --- src/sage/categories/category.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index 5d77bf381db..d60d8ac2faf 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -2583,13 +2583,14 @@ def category_sample(): sage: sorted(category_sample(), key=str) [Category of G-sets for Symmetric group of order 8! as a permutation group, Category of Hecke modules over Rational Field, + Category of Lie algebras over Rational Field, Category of additive magmas, ..., Category of fields, ..., Category of graded hopf algebras with basis over Rational Field, ..., Category of modular abelian varieties over Rational Field, ..., Category of simplicial complexes, ..., Category of vector spaces over Rational Field, ..., - Category of weyl groups,... + Category of weyl groups, ... """ import sage.categories.all abstract_classes_for_categories = [Category] From 898b24a46b1064369fdef931a09f9b7f8b22fbed Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 18 Mar 2015 06:05:27 +0100 Subject: [PATCH 034/223] anonymizing AbelianLieAlgebra example --- ...ite_dimensional_lie_algebras_with_basis.py | 131 +++++++----------- ...ite_dimensional_lie_algebras_with_basis.py | 10 +- 2 files changed, 51 insertions(+), 90 deletions(-) diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index e5abb7c0f57..cdd0d85183c 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -15,7 +15,6 @@ from sage.modules.free_module import FreeModule from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.element_wrapper import ElementWrapper from sage.categories.examples.lie_algebras import LieAlgebraFromAssociative as BaseExample class AbelianLieAlgebra(Parent, UniqueRepresentation): @@ -35,12 +34,10 @@ class AbelianLieAlgebra(Parent, UniqueRepresentation): - ``R`` -- base ring - - ``names`` -- list of strings, to be used as identifiers for - the basis elements of `M` + - ``n`` -- (optional) a nonnegative integer (default: ``None``) - ``M`` -- an `R`-module (default: the free `R`-module of - rank ``len(names)``) to serve as the ground space for the - Lie algebra + rank ``n``) to serve as the ground space for the Lie algebra - ``ambient`` -- (optional) a Lie algebra; if this is set, then the resulting Lie algebra is declared a Lie subalgebra @@ -49,61 +46,44 @@ class AbelianLieAlgebra(Parent, UniqueRepresentation): OUTPUT: The abelian Lie algebra on `M`. - - .. TODO:: - - Why am I required to specify ``names`` if the actual - elements of the Lie algebra end up being anonymous - vectors anyway? - - sage: from sage.categories.examples.finite_dimensional_lie_algebras_with_basis import * - sage: AbelianLieAlgebra(QQ, ['x','y']) - An example of a finite dimensional Lie algebra with - basis: the abelian Lie algebra with generators - ('x', 'y') over Rational Field - sage: _.gens() - ((1, 0), (0, 1)) - """ @staticmethod - def __classcall_private__(cls, R, names, M=None, ambient=None): + def __classcall_private__(cls, R, n=None, M=None, ambient=None): """ Normalize input to ensure a unique representation. EXAMPLES:: sage: from sage.categories.examples.finite_dimensional_lie_algebras_with_basis import AbelianLieAlgebra - sage: A1 = AbelianLieAlgebra(QQ, 'x,y,z') - sage: A2 = AbelianLieAlgebra(QQ, ['x','y','z']) - sage: A3 = AbelianLieAlgebra(QQ, ['x','y','z'], FreeModule(QQ, 3)) + sage: A1 = AbelianLieAlgebra(QQ, n=3) + sage: A2 = AbelianLieAlgebra(QQ, M=FreeModule(QQ, 3)) + sage: A3 = AbelianLieAlgebra(QQ, 3, FreeModule(QQ, 3)) sage: A1 is A2 and A2 is A3 True - sage: A1 = AbelianLieAlgebra(QQ, 'x0,x1') - sage: A2 = AbelianLieAlgebra(QQ, 2) + sage: A1 = AbelianLieAlgebra(QQ, 2) + sage: A2 = AbelianLieAlgebra(ZZ, 2) sage: A1 is A2 - True + False + + sage: A1 = AbelianLieAlgebra(QQ, 0) + sage: A2 = AbelianLieAlgebra(QQ, 1) + sage: A1 is A2 + False """ - if isinstance(names, str): - names = names.split(',') - elif names in ZZ: - names = ['x%s'%i for i in range(names)] if M is None: - M = FreeModule(R, len(names)) - elif len(names) != M.dimension(): - raise ValueError("number of generators is not correct") + M = FreeModule(R, n) else: M = M.change_ring(R) - return super(AbelianLieAlgebra, cls).__classcall__(cls, R, tuple(names), M, ambient) + return super(AbelianLieAlgebra, cls).__classcall__(cls, R, n=None, M=M, ambient=ambient) - def __init__(self, R, names, M, ambient): + def __init__(self, R, n=None, M=None, ambient=None): """ EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: TestSuite(L).run() """ - self._ordered_indices = names self._M = M cat = LieAlgebras(R).FiniteDimensional().WithBasis() if ambient is None: @@ -111,7 +91,7 @@ def __init__(self, R, names, M, ambient): else: cat = cat.Subobjects() self._ambient = ambient - Parent.__init__(self, base=R, names=names, category=cat) + Parent.__init__(self, base=R, category=cat) def _repr_(self): """ @@ -119,17 +99,19 @@ def _repr_(self): sage: LieAlgebras(QQ).FiniteDimensional().WithBasis().example() An example of a finite dimensional Lie algebra with basis: - the abelian Lie algebra with generators ('a', 'b', 'c') - over Rational Field + the 3-dimensional abelian Lie algebra over Rational Field """ ret = "An example of a finite dimensional Lie algebra with basis:" \ - " the abelian Lie algebra with generators {!r} over {}".format( - self.variable_names(), self.base_ring()) + " the {}-dimensional abelian Lie algebra over {}".format( + self.n(), self.base_ring()) B = self._M.basis_matrix() if not B.is_one(): ret += " with basis matrix:\n{!r}".format(B) return ret + def n(self): + return self._M.rank() + def _element_constructor_(self, x): """ Construct an element of ``self`` from ``x``. @@ -146,9 +128,9 @@ def _element_constructor_(self, x): sage: X = L.subalgebra([a+b, 2*a+c]) sage: x,y = X.basis() sage: L(x) - (1, 0, 1) + (1, 0, 1/2) sage: L(x+y) - (1, 1, -1) + (1, 1, 0) """ if isinstance(x, AbelianLieAlgebra.Element): x = x.value @@ -188,15 +170,14 @@ def ambient(self): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.inject_variables() - Defining a, b, c - sage: S = L.subalgebra([2*a+b, b + c], 'x,y') + sage: a, b, c = L.lie_algebra_generators() + sage: S = L.subalgebra([2*a+b, b + c]) sage: S.ambient() == L True """ return self._ambient - def subalgebra(self, gens, names='x'): + def subalgebra(self, gens): """ Return the Lie subalgebra of ``self`` generated by the elements of the iterable ``gens``. @@ -206,21 +187,16 @@ def subalgebra(self, gens, names='x'): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.inject_variables() - Defining a, b, c - sage: L.subalgebra([2*a+b, b + c], 'x,y') + sage: a, b, c = L.lie_algebra_generators() + sage: L.subalgebra([2*a+b, b + c]) An example of a finite dimensional Lie algebra with basis: - the abelian Lie algebra with generators ('x', 'y') - over Rational Field with basis matrix: + the 2-dimensional abelian Lie algebra over Rational Field with + basis matrix: [ 1 0 -1/2] [ 0 1 1] """ - if isinstance(names, str): - names = names.split(',') - if len(names) == 1 and len(gens) != 1: - names = tuple( names[0] + str(i) for i in range(len(gens)) ) N = self._M.subspace([g.value for g in gens]) - return AbelianLieAlgebra(self.base_ring(), names, N, self._ambient) + return AbelianLieAlgebra(self.base_ring(), M=N, ambient=self._ambient) def basis(self): """ @@ -230,10 +206,9 @@ def basis(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.basis() - Finite family {'a': (1, 0, 0), 'c': (0, 0, 1), 'b': (0, 1, 0)} + Finite family {0: (1, 0, 0), 1: (0, 1, 0), 2: (0, 0, 1)} """ - names = self.variable_names() - d = {names[i]: self.element_class(self, b) + d = {i: self.element_class(self, b) for i,b in enumerate(self._M.basis())} return Family(d) @@ -249,8 +224,7 @@ def gens(self): sage: L.gens() ((1, 0, 0), (0, 1, 0), (0, 0, 1)) """ - G = self.lie_algebra_generators() - return tuple(G[i] for i in self.variable_names()) + return tuple(self._M.basis()) def free_module(self): """ @@ -262,9 +236,8 @@ def free_module(self): sage: L.free_module() Vector space of dimension 3 over Rational Field - sage: L.inject_variables() - Defining a, b, c - sage: S = L.subalgebra([2*a+b, b + c], 'x,y') + sage: a, b, c = L.lie_algebra_generators() + sage: S = L.subalgebra([2*a+b, b + c]) sage: S.free_module() Vector space of degree 3 and dimension 2 over Rational Field Basis matrix: @@ -283,17 +256,15 @@ def __iter__(self): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.inject_variables() - Defining a, b, c + sage: a, b, c = L.lie_algebra_generators() sage: elt = 2*a - c sage: list(elt) - [('a', 2), ('c', -1)] + [(0, 2), (2, -1)] """ - I = self.parent()._ordered_indices zero = self.parent().base_ring().zero() for i, c in self.value.iteritems(): if c != zero: - yield (I[i], c) + yield (i, c) def __getitem__(self, i): """ @@ -303,18 +274,13 @@ def __getitem__(self, i): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.inject_variables() - Defining a, b, c + sage: a, b, c = L.lie_algebra_generators() sage: elt = 2*a + b - c sage: elt[0] 2 - sage: elt['a'] - 2 - sage: elt['c'] + sage: elt[2] -1 """ - if i in self.parent()._ordered_indices: - i = self.parent()._ordered_indices.index(i) return self.value.__getitem__(i) def _bracket_(self, y): @@ -324,8 +290,7 @@ def _bracket_(self, y): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.inject_variables() - Defining a, b, c + sage: a, b, c = L.lie_algebra_generators() sage: a.bracket(c) (0, 0, 0) sage: a.bracket(b).bracket(c) @@ -340,8 +305,7 @@ def lift(self): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.inject_variables() - Defining a, b, c + sage: a, b, c = L.lie_algebra_generators() sage: elt = 2*a + 2*b + 3*c sage: elt.lift() 2*a + 2*b + 3*c @@ -357,8 +321,7 @@ def to_vector(self): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.inject_variables() - Defining a, b, c + sage: a, b, c = L.lie_algebra_generators() sage: elt = 2*a + 2*b + 3*c sage: elt.to_vector() (2, 2, 3) 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 4bbdea327cd..11a3ae48391 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -33,7 +33,7 @@ class FiniteDimensionalLieAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ _base_category_class_and_axiom = [LieAlgebras.FiniteDimensional, "WithBasis"] - def example(self, names=('a', 'b', 'c')): + def example(self, n=3): """ Return an example of a finite dimensional Lie algebra with basis as per :meth:`Category.example `. @@ -43,18 +43,16 @@ def example(self, names=('a', 'b', 'c')): sage: C = LieAlgebras(QQ).FiniteDimensional().WithBasis() sage: C.example() An example of a finite dimensional Lie algebra with basis: - the abelian Lie algebra with generators ('a', 'b', 'c') - over Rational Field + the abelian 3-dimensional Lie algebra over Rational Field Other names of generators can be specified as an optional argument:: sage: C.example(('x','y','z')) An example of a finite dimensional Lie algebra with basis: - the abelian Lie algebra with generators ('x', 'y', 'z') - over Rational Field + the abelian 3-dimensional Lie algebra over Rational Field """ from sage.categories.examples.finite_dimensional_lie_algebras_with_basis import Example - return Example(self.base_ring(), names) + return Example(self.base_ring(), n) class ParentMethods: @cached_method From b0abe90e740a849113871306f7275ba376aa17aa Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 18 Mar 2015 18:06:45 +0100 Subject: [PATCH 035/223] a few more fixes(?) --- .../finite_dimensional_lie_algebras_with_basis.py | 3 --- .../finite_dimensional_lie_algebras_with_basis.py | 13 ++++++------- src/sage/categories/lie_algebras.py | 12 ++++++------ 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index cdd0d85183c..31b5931ac70 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -109,9 +109,6 @@ def _repr_(self): ret += " with basis matrix:\n{!r}".format(B) return ret - def n(self): - return self._M.rank() - def _element_constructor_(self, x): """ Construct an element of ``self`` from ``x``. 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 11a3ae48391..aaa5b93686f 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -80,19 +80,18 @@ def _construct_UEA(self): names = self.variable_names() except ValueError: names = tuple('b{}'.format(i) for i in range(self.dimension())) - I = self._ordered_indices F = FreeAlgebra(self.base_ring(), names) #gens = F.gens() d = F.gens_dict() rels = {} S = self.structure_coefficients(True) for k in S.keys(): - g0 = d[names[I.index(k[0])]] - g1 = d[names[I.index(k[1])]] + g0 = d[names[k[0]]] + g1 = d[names[k[1]]] if g0 < g1: - rels[g1*g0] = g0*g1 - sum(val*d[names[I.index(g)]] for g, val in S[k]) + rels[g1*g0] = g0*g1 - sum(val*d[names[g]] for g, val in S[k]) else: - rels[g0*g1] = g1*g0 + sum(val*d[names[I.index(g)]] for g, val in S[k]) + rels[g0*g1] = g1*g0 + sum(val*d[names[g]] for g, val in S[k]) return F.g_algebra(rels) def killing_matrix(self, x, y): @@ -595,7 +594,7 @@ def ambient(self): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.inject_variables() + sage: a, b, c = L.lie_algebra_generators() Defining a, b, c sage: S = L.subalgebra([2*a+b, b + c], 'x,y') sage: S.ambient() == L @@ -610,7 +609,7 @@ def basis_matrix(self): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.inject_variables() + sage: a, b, c = L.lie_algebra_generators() Defining a, b, c sage: S = L.subalgebra([2*a+b, b + c], 'x,y') sage: S.basis_matrix() diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index d88ceea9276..aa96416d218 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -273,7 +273,7 @@ def lift(self): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.inject_variables() + sage: a, b, c = L.lie_algebra_generators() Defining a, b, c sage: lifted = L.lift(2*a + b - c); lifted 2*a + b - c @@ -292,7 +292,7 @@ def subalgebra(self, gens): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.inject_variables() + sage: a, b, c = L.lie_algebra_generators() Defining a, b, c sage: L.subalgebra([2*a - c, b + c]) An example of a finite dimensional Lie algebra with basis: @@ -310,7 +310,7 @@ def killing_form(self, x, y): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.inject_variables() + sage: a, b, c = L.lie_algebra_generators() Defining a, b, c sage: L.killing_form(a, b+c) 0 @@ -524,7 +524,7 @@ def lift(self): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.inject_variables() + sage: a, b, c = L.lie_algebra_generators() Defining a, b, c sage: elt = 3*a + b - c sage: elt.lift() @@ -544,7 +544,7 @@ def killing_form(self, x): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.inject_variables() + sage: a, b, c = L.lie_algebra_generators() Defining a, b, c sage: a.killing_form(b) 0 @@ -578,7 +578,7 @@ def _call_(self, x): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.inject_variables() + sage: a, b, c = L.lie_algebra_generators() Defining a, b, c sage: L.lift(3*a + b - c) 3*a + b - c From ee7b9cd107a53be39b4660c146332be157abea69 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 22 Mar 2015 16:08:37 +0100 Subject: [PATCH 036/223] cleaning fallout from removing the names in abelian Lie algebra example --- ...ite_dimensional_lie_algebras_with_basis.py | 5 +- ...ite_dimensional_lie_algebras_with_basis.py | 68 ++++++++----------- src/sage/categories/lie_algebras.py | 20 ++---- 3 files changed, 38 insertions(+), 55 deletions(-) diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index 31b5931ac70..5471ad96d0b 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -11,7 +11,6 @@ from sage.misc.cachefunc import cached_method from sage.sets.family import Family from sage.categories.all import LieAlgebras -from sage.rings.all import ZZ from sage.modules.free_module import FreeModule from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -103,7 +102,7 @@ def _repr_(self): """ ret = "An example of a finite dimensional Lie algebra with basis:" \ " the {}-dimensional abelian Lie algebra over {}".format( - self.n(), self.base_ring()) + self.dimension(), self.base_ring()) B = self._M.basis_matrix() if not B.is_one(): ret += " with basis matrix:\n{!r}".format(B) @@ -305,7 +304,7 @@ def lift(self): sage: a, b, c = L.lie_algebra_generators() sage: elt = 2*a + 2*b + 3*c sage: elt.lift() - 2*a + 2*b + 3*c + 2*b0 + 2*b1 + 3*b2 """ UEA = self.parent().universal_enveloping_algebra() gens = UEA.gens() 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 aaa5b93686f..4aa14160dc4 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -17,7 +17,6 @@ from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.lie_algebras import LieAlgebras from sage.categories.subobjects import SubobjectsCategory -from sage.rings.all import ZZ from sage.algebras.free_algebra import FreeAlgebra from sage.sets.family import Family from sage.matrix.constructor import matrix @@ -43,13 +42,13 @@ def example(self, n=3): sage: C = LieAlgebras(QQ).FiniteDimensional().WithBasis() sage: C.example() An example of a finite dimensional Lie algebra with basis: - the abelian 3-dimensional Lie algebra over Rational Field + the 3-dimensional abelian Lie algebra over Rational Field - Other names of generators can be specified as an optional argument:: + Other dimensions can be specified as an optional argument:: - sage: C.example(('x','y','z')) + sage: C.example(5) An example of a finite dimensional Lie algebra with basis: - the abelian 3-dimensional Lie algebra over Rational Field + the 5-dimensional abelian Lie algebra over Rational Field """ from sage.categories.examples.finite_dimensional_lie_algebras_with_basis import Example return Example(self.base_ring(), n) @@ -64,10 +63,10 @@ def _construct_UEA(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: UEA = L._construct_UEA(); UEA - Noncommutative Multivariate Polynomial Ring in a, b, c + Noncommutative Multivariate Polynomial Ring in b0, b1, b2 over Rational Field, nc-relations: {} sage: UEA.relations(add_commutative=True) - {b*a: a*b, c*a: a*c, c*b: b*c} + {b1*b0: b0*b1, b2*b0: b0*b2, b2*b1: b1*b2} :: @@ -180,14 +179,12 @@ def structure_coefficients(self, include_zeros=False): sage: L.structure_coefficients() Finite family {} sage: L.structure_coefficients(True) - Finite family {('b', 'c'): (0, 0, 0), ('a', 'b'): (0, 0, 0), - ('a', 'c'): (0, 0, 0)} + Finite family {(0, 1): (0, 0, 0), (1, 2): (0, 0, 0), (0, 2): (0, 0, 0)} """ d = {} B = self.basis() K = self.basis().keys() zero = self.zero() - one = self.base_ring().one() for i,x in enumerate(K): for y in K[i+1:]: bx = B[x] @@ -216,8 +213,7 @@ def centralizer(self, S): sage: a,b,c = L.lie_algebra_generators() sage: S = L.centralizer([a + b, 2*a + c]); S An example of a finite dimensional Lie algebra with basis: - the abelian Lie algebra with generators ('x0', 'x1', 'x2') - over Rational Field + the 3-dimensional abelian Lie algebra over Rational Field sage: S.basis_matrix() [1 0 0] [0 1 0] @@ -250,9 +246,8 @@ def center(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: Z = L.center(); Z - An example of a finite dimensional Lie algebra with basis: - the abelian Lie algebra with generators ('x0', 'x1', 'x2') - over Rational Field + An example of a finite dimensional Lie algebra with basis: the + 3-dimensional abelian Lie algebra over Rational Field sage: Z.basis_matrix() [1 0 0] [0 1 0] @@ -271,15 +266,15 @@ def product_space(self, L): sage: X = L.subalgebra([a, b+c]) sage: L.product_space(X) An example of a finite dimensional Lie algebra with basis: - the abelian Lie algebra with generators () - over Rational Field with basis matrix: - [] + the 0-dimensional abelian Lie algebra over Rational Field + with basis matrix: + [] sage: Y = L.subalgebra([a, 2*b-c]) sage: X.product_space(Y) An example of a finite dimensional Lie algebra with basis: - the abelian Lie algebra with generators () - over Rational Field with basis matrix: - [] + the 0-dimensional abelian Lie algebra over Rational + Field with basis matrix: + [] :: @@ -316,8 +311,7 @@ def product_space(self, L): for a in K for b in LK]) b_mat.echelonize() r = b_mat.rank() - I = A._ordered_indices - gens = [A.element_class(A, {I[i]: v for i,v in row.iteritems()}) + gens = [A.element_class(A, {i: v for i,v in row.iteritems()}) for row in b_mat.rows()[:r]] return A.subalgebra(gens) @@ -331,9 +325,9 @@ def derived_subalgebra(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.derived_subalgebra() An example of a finite dimensional Lie algebra with basis: - the abelian Lie algebra with generators () over - Rational Field with basis matrix: - [] + the 0-dimensional abelian Lie algebra over Rational Field + with basis matrix: + [] """ return self.product_space(self) @@ -370,11 +364,10 @@ def derived_series(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.derived_series() (An example of a finite dimensional Lie algebra with basis: - the abelian Lie algebra with generators ('a', 'b', 'c') - over Rational Field, + the 3-dimensional abelian Lie algebra over Rational Field, An example of a finite dimensional Lie algebra with basis: - the abelian Lie algebra with generators () over - Rational Field with basis matrix: + the 0-dimensional abelian Lie algebra over Rational Field + with basis matrix: []) :: @@ -422,13 +415,12 @@ def lower_central_series(self): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.lower_central_series() + sage: L.derived_series() (An example of a finite dimensional Lie algebra with basis: - the abelian Lie algebra with generators ('a', 'b', 'c') - over Rational Field, + the 3-dimensional abelian Lie algebra over Rational Field, An example of a finite dimensional Lie algebra with basis: - the abelian Lie algebra with generators () over - Rational Field with basis matrix: + the 0-dimensional abelian Lie algebra over Rational Field + with basis matrix: []) :: @@ -595,8 +587,7 @@ def ambient(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: a, b, c = L.lie_algebra_generators() - Defining a, b, c - sage: S = L.subalgebra([2*a+b, b + c], 'x,y') + sage: S = L.subalgebra([2*a+b, b + c]) sage: S.ambient() == L True """ @@ -610,8 +601,7 @@ def basis_matrix(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: a, b, c = L.lie_algebra_generators() - Defining a, b, c - sage: S = L.subalgebra([2*a+b, b + c], 'x,y') + sage: S = L.subalgebra([2*a+b, b + c]) sage: S.basis_matrix() [ 1 0 -1/2] [ 0 1 1] diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index aa96416d218..f4ffdf524e6 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -222,7 +222,7 @@ def universal_enveloping_algebra(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.universal_enveloping_algebra() - Noncommutative Multivariate Polynomial Ring in a, b, c + Noncommutative Multivariate Polynomial Ring in b0, b1, b2 over Rational Field, nc-relations: {} :: @@ -242,7 +242,7 @@ def _construct_UEA(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L._construct_UEA() - Noncommutative Multivariate Polynomial Ring in a, b, c + Noncommutative Multivariate Polynomial Ring in b0, b1, b2 over Rational Field, nc-relations: {} :: @@ -274,9 +274,8 @@ def lift(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: a, b, c = L.lie_algebra_generators() - Defining a, b, c sage: lifted = L.lift(2*a + b - c); lifted - 2*a + b - c + 2*b0 + b1 - b2 sage: lifted.parent() is L.universal_enveloping_algebra() True """ @@ -293,11 +292,10 @@ def subalgebra(self, gens): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: a, b, c = L.lie_algebra_generators() - Defining a, b, c sage: L.subalgebra([2*a - c, b + c]) An example of a finite dimensional Lie algebra with basis: - the abelian Lie algebra with generators ('x0', 'x1') - over Rational Field with basis matrix: + the 2-dimensional abelian Lie algebra over Rational Field + with basis matrix: [ 1 0 -1/2] [ 0 1 1] """ @@ -311,7 +309,6 @@ def killing_form(self, x, y): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: a, b, c = L.lie_algebra_generators() - Defining a, b, c sage: L.killing_form(a, b+c) 0 """ @@ -525,10 +522,9 @@ def lift(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: a, b, c = L.lie_algebra_generators() - Defining a, b, c sage: elt = 3*a + b - c sage: elt.lift() - 3*a + b - c + 3*b0 + b1 - b2 :: @@ -545,7 +541,6 @@ def killing_form(self, x): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: a, b, c = L.lie_algebra_generators() - Defining a, b, c sage: a.killing_form(b) 0 """ @@ -579,9 +574,8 @@ def _call_(self, x): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: a, b, c = L.lie_algebra_generators() - Defining a, b, c sage: L.lift(3*a + b - c) - 3*a + b - c + 3*b0 + b1 - b2 """ return x.lift() From 7ad90c037c5b22d96383ffbf480079e13ac6e300 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Mon, 23 Mar 2015 01:35:00 +0100 Subject: [PATCH 037/223] trivial doc correction --- .../finite_dimensional_lie_algebras_with_basis.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 4aa14160dc4..c03730314cf 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -169,9 +169,9 @@ def structure_coefficients(self, include_zeros=False): OUTPUT: - A dictionary whose keys are pairs of basis indices `(i, j)` and - whose values are the corresponding *element* of `[b_i, b_j]` - in the Lie algebra. + A dictionary whose keys are pairs of basis indices `(i, j)` + with `i < j`, and whose values are the corresponding + *elements* `[b_i, b_j]` in the Lie algebra. EXAMPLES:: From 3084981752c2869399b05fd91705178f1101329b Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Mon, 23 Mar 2015 23:46:38 +0100 Subject: [PATCH 038/223] making _bracket_ required and bracket optional (was the other way round, which could lead to attributeerrors) --- src/sage/categories/lie_algebras.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index f4ffdf524e6..98248f755cf 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -19,14 +19,12 @@ from sage.categories.category import JoinCategory, Category from sage.categories.category_types import Category_over_base_ring from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring -from sage.categories.distributive_magmas_and_additive_magmas import DistributiveMagmasAndAdditiveMagmas from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.modules import Modules from sage.categories.sets_cat import Sets from sage.categories.homset import Hom from sage.categories.morphism import Morphism -from sage.structure.sage_object import have_same_parent -from sage.structure.element import get_coercion_model, coerce_binop +from sage.structure.element import coerce_binop class LieAlgebras(Category_over_base_ring): """ @@ -209,6 +207,10 @@ def bracket(self, lhs, rhs): sage: x,y = L.lie_algebra_generators() sage: L.bracket(x, x + y) -[1, 3, 2] + [3, 2, 1] + sage: L.bracket(x, 0) + 0 + sage: L.bracket(0, x) + 0 """ return self(lhs)._bracket_(self(rhs)) @@ -496,14 +498,18 @@ def bracket(self, rhs): sage: x,y = L.lie_algebra_generators() sage: x.bracket(y) -[1, 3, 2] + [3, 2, 1] + sage: x.bracket(0) + 0 """ return self._bracket_(rhs) - # Implement this in order to avoid having to deal with the coercions - @abstract_method(optional=True) + # Implement this method to define the Lie bracket. You do not + # need to deal with the coercions here. + @abstract_method def _bracket_(self, y): """ - Return the Lie bracket ``[self, y]``. + Return the Lie bracket ``[self, y]``, where ``y`` is an + element of the same Lie algebra as ``self``. EXAMPLES:: @@ -511,6 +517,10 @@ def _bracket_(self, y): sage: x,y = L.lie_algebra_generators() sage: x._bracket_(y) -[1, 3, 2] + [3, 2, 1] + sage: y._bracket_(x) + [1, 3, 2] - [3, 2, 1] + sage: x._bracket_(x) + 0 """ @abstract_method(optional=True) From 3c8325bd31355335d752ef1297c420b68307748d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 24 Mar 2015 11:44:12 -0700 Subject: [PATCH 039/223] Fixing some things with the Heisenberg algebra, but broke pickling. --- src/sage/algebras/lie_algebras/heisenberg.py | 27 ++++++++++++++++--- src/sage/algebras/lie_algebras/lie_algebra.py | 4 +-- .../lie_algebras/lie_algebra_element.py | 6 +++++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index 0129944ff30..93f717dd01c 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -27,8 +27,9 @@ from sage.structure.indexed_generators import IndexedGenerators from sage.algebras.algebra import Algebra -from sage.algebras.lie_algebras.lie_algebra import InfinitelyGeneratedLieAlgebra, \ - LieAlgebraFromAssociative, FinitelyGeneratedLieAlgebra +from sage.algebras.lie_algebras.lie_algebra import (LieAlgebra, + InfinitelyGeneratedLieAlgebra, LieAlgebraFromAssociative, + FinitelyGeneratedLieAlgebra) from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement from sage.categories.lie_algebras import LieAlgebras from sage.combinat.cartesian_product import CartesianProduct @@ -39,6 +40,7 @@ from sage.sets.family import Family from sage.sets.positive_integers import PositiveIntegers from sage.sets.set import Set +from sage.rings.all import ZZ class HeisenbergAlgebra_abstract(IndexedGenerators): """ @@ -140,6 +142,25 @@ def _latex_term(self, m): return m return "%s_{%s}" % m # else it is a tuple of length 2 + class Element(LieAlgebra.Element): + def __getitem__(self, m): + """ + Return the element indexed by ``m``. + + We include a shortcut for strings such as `p1` and `q8`. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, 3) + sage: x = L.an_element(); x + p1 + p2 + p3 + q1 + q2 + q3 + sage: x['p1'] + 1 + """ + if isinstance(m, str) and len(m) != 1: + m = (m[0], ZZ(m[1])) + return super(HeisenbergAlgebra.Element, self).__getitem__(m) + class HeisenbergAlgebra_fd: """ Common methods for finite-dimensional Heisenberg algebras. @@ -203,7 +224,7 @@ def lie_algebra_generators(self): for i in range(1, self._n+1): d['p%s'%i] = self.p(i) d['q%s'%i] = self.q(i) - return Family(d) + return Family(self._indices, lambda i: d[i]) @cached_method def basis(self): diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index e0bda89ad2d..fff13245376 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -623,7 +623,7 @@ def gen(self, i): @lazy_attribute def _ordered_indices(self): """ - Return the index set of ``self`` in order. + Return the index set of the basis of ``self`` in (some) order. EXAMPLES:: @@ -631,7 +631,7 @@ def _ordered_indices(self): sage: L._ordered_indices ('x', 'y') """ - return tuple(self._indices) + return tuple(self.basis().keys()) def _an_element_(self): """ diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index e736817eb09..0262dbb977b 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -30,6 +30,7 @@ from sage.structure.sage_object import SageObject from sage.combinat.free_module import CombinatorialFreeModuleElement from sage.structure.element_wrapper import ElementWrapper +from sage.categories.finite_dimensional_lie_algebras_with_basis import FiniteDimensionalLieAlgebrasWithBasis # TODO: Have the other classes inherit from this? # TODO: Should this be a mixin class (or moved to the category)? @@ -149,6 +150,11 @@ def list(self): """ return sorted(self._monomial_coefficients.items()) + # FIXME: Use the methods defined in the category instead of + # those given by CombinatorialFreeModuleElement + _vector_ = FiniteDimensionalLieAlgebrasWithBasis.ElementMethods.__dict__['to_vector'] + to_vector = _vector_ + class LieAlgebraElementWrapper(ElementWrapper): """ Wrap an element as a Lie algebra element. From 896028a55410950242a3a818b6d90dd7898d800c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 24 Mar 2015 14:10:49 -0700 Subject: [PATCH 040/223] A y for an x. --- .../categories/finite_dimensional_lie_algebras_with_basis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c03730314cf..2ba168de838 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -188,7 +188,7 @@ def structure_coefficients(self, include_zeros=False): for i,x in enumerate(K): for y in K[i+1:]: bx = B[x] - by = B[x] + by = B[y] val = self.bracket(bx, by) if not include_zeros and val == zero: continue From 6ca7aca066e0f28f47c3bd065cc9583497803514 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 24 Mar 2015 14:25:03 -0700 Subject: [PATCH 041/223] Fixing some parts of _construct_UEA. --- ...nite_dimensional_lie_algebras_with_basis.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) 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 2ba168de838..fd1344455d7 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -75,22 +75,24 @@ def _construct_UEA(self): """ # Create the UEA relations # We need to get names for the basis elements, not just the generators + I = self._basis_ordering try: - names = self.variable_names() + names = [str(x) for x in I] + F = FreeAlgebra(self.base_ring(), names) except ValueError: - names = tuple('b{}'.format(i) for i in range(self.dimension())) - F = FreeAlgebra(self.base_ring(), names) - #gens = F.gens() + names = ['b{}'.format(i) for i in range(self.dimension())] + F = FreeAlgebra(self.base_ring(), names) d = F.gens_dict() rels = {} S = self.structure_coefficients(True) + get_var = lambda g: d[names[I.index(g)]] for k in S.keys(): - g0 = d[names[k[0]]] - g1 = d[names[k[1]]] + g0 = get_var(k[0]) + g1 = get_var(k[1]) if g0 < g1: - rels[g1*g0] = g0*g1 - sum(val*d[names[g]] for g, val in S[k]) + rels[g1*g0] = g0*g1 - sum(val*get_var(g) for g, val in S[k]) else: - rels[g0*g1] = g1*g0 + sum(val*d[names[g]] for g, val in S[k]) + rels[g0*g1] = g1*g0 + sum(val*get_var(g) for g, val in S[k]) return F.g_algebra(rels) def killing_matrix(self, x, y): From d35b756e3fee08c6ced786cefc0a09aac17a7456 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 24 Mar 2015 14:27:06 -0700 Subject: [PATCH 042/223] Adding a default _basis_ordering and _dense_free_module --- ...ite_dimensional_lie_algebras_with_basis.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) 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 fd1344455d7..3694261680e 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -14,6 +14,7 @@ from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.lie_algebras import LieAlgebras from sage.categories.subobjects import SubobjectsCategory @@ -95,6 +96,35 @@ def _construct_UEA(self): rels[g0*g1] = g1*g0 + sum(val*get_var(g) for g, val in S[k]) return F.g_algebra(rels) + @lazy_attribute + def _basis_ordering(self): + """ + Return an order of the indices of the basis. + + Override this attribute to get a specific ordering of the basis. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {}) + sage: L._basis_ordering + ('x', 'y', 'z') + """ + return tuple(self.basis().keys()) + + @lazy_attribute + def _dense_free_module(self): + """ + Return a dense free module associated to ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, 3) + sage: L._dense_free_module + Vector space of dimension 7 over Rational Field + """ + from sage.modules.free_module import FreeModule + return FreeModule(self.base_ring(), len(self._basis_ordering)) + def killing_matrix(self, x, y): r""" Return the Killing matrix of ``x`` and ``y``. From e95d67cbdda81ca0dc127bb10c1175fb0535dfa4 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 24 Mar 2015 14:43:08 -0700 Subject: [PATCH 043/223] More fixes to fin-dim w/ basis category. --- ...ite_dimensional_lie_algebras_with_basis.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) 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 3694261680e..f6fdefd5960 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -105,25 +105,27 @@ def _basis_ordering(self): EXAMPLES:: - sage: L. = LieAlgebra(QQ, {}) + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L._basis_ordering - ('x', 'y', 'z') + (0, 1, 2) """ return tuple(self.basis().keys()) - @lazy_attribute - def _dense_free_module(self): + @cached_method + def _dense_free_module(self, R=None): """ - Return a dense free module associated to ``self``. + Return a dense free module associated to ``self`` over ``R``. EXAMPLES:: - sage: L = lie_algebras.Heisenberg(QQ, 3) - sage: L._dense_free_module - Vector space of dimension 7 over Rational Field + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L._dense_free_module() + Vector space of dimension 3 over Rational Field """ + if R is None: + R = self.base_ring() from sage.modules.free_module import FreeModule - return FreeModule(self.base_ring(), len(self._basis_ordering)) + return FreeModule(R, self.dimension()) def killing_matrix(self, x, y): r""" From a491bb07db52cc51a790dda75de9cccbe8746bfa Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 24 Mar 2015 15:17:20 -0700 Subject: [PATCH 044/223] Some more cleanup and fixes. --- src/sage/algebras/lie_algebras/heisenberg.py | 64 +++++++------------ src/sage/algebras/lie_algebras/lie_algebra.py | 30 +++++++-- .../lie_algebras/lie_algebra_element.py | 22 +++++-- ...ite_dimensional_lie_algebras_with_basis.py | 19 +----- 4 files changed, 68 insertions(+), 67 deletions(-) diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index 93f717dd01c..dd2b9fc8c65 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -27,9 +27,8 @@ from sage.structure.indexed_generators import IndexedGenerators from sage.algebras.algebra import Algebra -from sage.algebras.lie_algebras.lie_algebra import (LieAlgebra, - InfinitelyGeneratedLieAlgebra, LieAlgebraFromAssociative, - FinitelyGeneratedLieAlgebra) +from sage.algebras.lie_algebras.lie_algebra import (InfinitelyGeneratedLieAlgebra, + LieAlgebraFromAssociative, FinitelyGeneratedLieAlgebra) from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement from sage.categories.lie_algebras import LieAlgebras from sage.combinat.cartesian_product import CartesianProduct @@ -66,7 +65,7 @@ def p(self, i): sage: L.p(2) p2 """ - return self.element_class(self, {('p', i): self.base_ring().one()}) + return self.element_class(self, {'p%i'%i: self.base_ring().one()}) def q(self, i): """ @@ -78,7 +77,7 @@ def q(self, i): sage: L.q(2) q2 """ - return self.element_class(self, {('q', i): self.base_ring().one()}) + return self.element_class(self, {'q%i'%i: self.base_ring().one()}) def z(self): """ @@ -117,14 +116,12 @@ def _repr_term(self, m): EXAMPLES:: sage: H = lie_algebras.Heisenberg(QQ, 3) - sage: H._repr_term(('p', 1)) + sage: H._repr_term('p1') 'p1' sage: H._repr_term('z') 'z' """ - if isinstance(m, str): - return m - return m[0] + str(m[1]) + return m def _latex_term(self, m): r""" @@ -138,28 +135,9 @@ def _latex_term(self, m): sage: H._latex_term('z') 'z' """ - if isinstance(m, str): + if len(m) == 1: return m - return "%s_{%s}" % m # else it is a tuple of length 2 - - class Element(LieAlgebra.Element): - def __getitem__(self, m): - """ - Return the element indexed by ``m``. - - We include a shortcut for strings such as `p1` and `q8`. - - EXAMPLES:: - - sage: L = lie_algebras.Heisenberg(QQ, 3) - sage: x = L.an_element(); x - p1 + p2 + p3 + q1 + q2 + q3 - sage: x['p1'] - 1 - """ - if isinstance(m, str) and len(m) != 1: - m = (m[0], ZZ(m[1])) - return super(HeisenbergAlgebra.Element, self).__getitem__(m) + return "%s_{%s}"%(m[0], m[1]) # else it is of length 2 class HeisenbergAlgebra_fd: """ @@ -242,7 +220,7 @@ def basis(self): d['p%s'%i] = self.p(i) d['q%s'%i] = self.q(i) d['z'] = self.z() - return Family(d) + return Family(self._indices + ('z',), lambda i: d[i]) class HeisenbergAlgebra(HeisenbergAlgebra_fd, HeisenbergAlgebra_abstract, FinitelyGeneratedLieAlgebra): @@ -331,9 +309,9 @@ def _repr_(self): EXAMPLES:: sage: lie_algebras.Heisenberg(QQ, oo) - The infinite Heisenberg algebra over Rational Field + Infinite Heisenberg algebra over Rational Field """ - return "The infinite Heisenberg algebra over {}".format(self.base_ring()) + return "Infinite Heisenberg algebra over {}".format(self.base_ring()) def _an_element_(self): """ @@ -343,7 +321,7 @@ def _an_element_(self): sage: L = lie_algebras.Heisenberg(QQ, oo) sage: L._an_element_() - z + p2 + q2 - 1/2*q3 + p2 + q2 - 1/2*q3 + z """ c = self.base_ring().an_element() return self.p(2) + self.q(2) - c * self.q(3) + self.z() @@ -359,7 +337,7 @@ def lie_algebra_generators(self): Lazy family (generator map(i))_{i in Cartesian product of Positive integers, ['p', 'q']} """ - return Family(self._indices, lambda x: self.monomial(tuple(x)), + return Family(self._indices, lambda x: self.monomial(x[1] + str(x[0])), name='generator map') def basis(self): @@ -375,7 +353,11 @@ def basis(self): """ S = CartesianProduct(PositiveIntegers(), ['p','q']) I = DisjointUnionEnumeratedSets([Set(['z']), S]) - return Family(I, self.monomial, name="basis map") + def basis_elt(x): + if isinstance(x, str): + return self.monomial(x) + return self.monomial(x[1] + str(x[0])) + return Family(I, basis_elt, name="basis map") ####################################################### ## Finite rank Heisenberg algebra using matrices @@ -452,10 +434,10 @@ def __init__(self, R, n): p = tuple(MS({(0,i):one}) for i in range(1, n+1)) q = tuple(MS({(i,n+1):one}) for i in range(1, n+1)) names = tuple('p%s'%i for i in range(1,n+1)) - names = names + tuple('q%s'%i for i in range(1,n+1)) + ('z',) + names = names + tuple('q%s'%i for i in range(1,n+1)) cat = LieAlgebras(R).FiniteDimensional().WithBasis() - LieAlgebraFromAssociative.__init__(self, MS, p + q + (MS({(0,n+1):one}),), - names=names, index_set=names, category=cat) + LieAlgebraFromAssociative.__init__(self, MS, p + q, names=names, + index_set=names, category=cat) def _repr_(self): """ @@ -496,6 +478,7 @@ def q(self, i): """ return self._gens['q%s'%i] + @cached_method def z(self): """ Return the generator `z`. @@ -508,5 +491,6 @@ def z(self): [0 0 0] [0 0 0] """ - return self._gens['z'] + d = {(0,self._n+1): self.base_ring().one()} + return self.element_class( self, self._assoc(d) ) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index fff13245376..76c89ef6511 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -491,7 +491,7 @@ def _from_dict(self, d, coerce=False, remove_zeros=True): EXAMPLES:: sage: L = lie_algebras.Heisenberg(QQ, oo) - sage: d = {('p', 1): 4, ('q', 3): 1/2, 'z': -2} + sage: d = {'p1': 4, 'q3': 1/2, 'z': -2} sage: L._from_dict(d) -2*z + 4*p1 + 1/2*q3 """ @@ -510,7 +510,7 @@ def monomial(self, i): EXAMPLES:: sage: L = lie_algebras.Heisenberg(QQ, oo) - sage: L.monomial(('p', 1)) + sage: L.monomial('p1') p1 """ return self.element_class(self, {i: self.base_ring().one()}) @@ -522,7 +522,7 @@ def term(self, i, c=None): EXAMPLES:: sage: L = lie_algebras.Heisenberg(QQ, oo) - sage: L.term(('p', 1), 4) + sage: L.term('p1', 4) 4*p1 """ if c is None: @@ -543,6 +543,28 @@ def lie_algebra_generators(self): """ return Family(self._indices, self.monomial, name="monomial map") + def get_order(self): + """ + Return an ordering of the basis indices. + + .. TODO:: + + Remove this method and in :class:`CombinatorialFreeModule` + in favor of a method in the category of (finite dimensional) + modules with basis. + + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {}) + sage: L.get_order() + ('x', 'y') + """ + try: + return self._basis_ordering + except AttributeError: + raise ValueError("the Lie algebra is not finite dimensional with a basis") + Element = LieAlgebraElement # Default for all Lie algebras class FinitelyGeneratedLieAlgebra(LieAlgebra): @@ -657,7 +679,7 @@ def _an_element_(self): sage: L = lie_algebras.Heisenberg(QQ, oo) sage: L._an_element_() - z + p2 + q2 - 1/2*q3 + p2 + q2 - 1/2*q3 + z """ return self.lie_algebra_generators()[self._indices.an_element()] diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index 0262dbb977b..78e82b40a50 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -30,7 +30,6 @@ from sage.structure.sage_object import SageObject from sage.combinat.free_module import CombinatorialFreeModuleElement from sage.structure.element_wrapper import ElementWrapper -from sage.categories.finite_dimensional_lie_algebras_with_basis import FiniteDimensionalLieAlgebrasWithBasis # TODO: Have the other classes inherit from this? # TODO: Should this be a mixin class (or moved to the category)? @@ -150,11 +149,6 @@ def list(self): """ return sorted(self._monomial_coefficients.items()) - # FIXME: Use the methods defined in the category instead of - # those given by CombinatorialFreeModuleElement - _vector_ = FiniteDimensionalLieAlgebrasWithBasis.ElementMethods.__dict__['to_vector'] - to_vector = _vector_ - class LieAlgebraElementWrapper(ElementWrapper): """ Wrap an element as a Lie algebra element. @@ -247,6 +241,22 @@ def __mul__(self, x): # Otherwise we lift to the UEA return self.lift() * x + def __div__(self, x, self_on_left=False ): + """ + Division by coefficients. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, 3) + sage: x = L.an_element(); x + p1 + p2 + p3 + q1 + q2 + q3 + sage: x / 2 + 1/2*p1 + 1/2*p2 + 1/2*p3 + 1/2*q1 + 1/2*q2 + 1/2*q3 + """ + if self_on_left: + return self * (~x) + return (~x) * self + def _acted_upon_(self, scalar, self_on_left=False): """ Return the action of a scalar on ``self``. 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 096ac63a91a..9188cd69a62 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -347,7 +347,8 @@ def product_space(self, L): for a in K for b in LK]) b_mat.echelonize() r = b_mat.rank() - gens = [A.element_class(A, {i: v for i,v in row.iteritems()}) + I = A._basis_ordering + gens = [A.element_class(A, {I[i]: v for i,v in row.iteritems()}) for row in b_mat.rows()[:r]] return A.subalgebra(gens) @@ -566,22 +567,6 @@ def dimension(self): return self.basis().cardinality() class ElementMethods: - def to_vector(self): - """ - Return ``self`` as a vector. - - EXAMPLES:: - - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.an_element().to_vector() - (0, 0, 0) - """ - M = self.parent().free_module() - if not self: - return M.zero() - B = M.basis() - return M.sum(B[k]*self[k] for k in self.parent()._ordered_indices) - def adjoint_matrix(self): # In #11111 (more or less) by using matrix of a mophism """ Return the matrix of the adjoint action of ``self``. From aabf5405d5472a0fad8782e506e96e382596f96f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 24 Mar 2015 15:20:54 -0700 Subject: [PATCH 045/223] Fixing coefficient division. --- src/sage/categories/examples/lie_algebras.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py index 60da4865a0f..db3cb9d95d2 100644 --- a/src/sage/categories/examples/lie_algebras.py +++ b/src/sage/categories/examples/lie_algebras.py @@ -243,10 +243,6 @@ def _acted_upon_(self, scalar, self_on_left=False): sage: x,y = L.lie_algebra_generators() sage: 3 * x 3*[2, 1, 3] - sage: y / QQ(4) - 1/4*[2, 3, 1] - sage: y / 4 # not tested: todo - 1/4*[2, 3, 1] """ # This was copied, but IDK if it still applies: # With the current design, the coercion model does not have @@ -263,6 +259,21 @@ def _acted_upon_(self, scalar, self_on_left=False): return self.__class__(self.parent(), self.value * scalar) return self.__class__(self.parent(), scalar * self.value) + def __div__(self, x, self_on_left=False ): + """ + Division by coefficients. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: x,y = L.lie_algebra_generators() + sage: y / 4 + 1/4*[2, 3, 1] + """ + if self_on_left: + return self * (~x) + return (~x) * self + def __neg__(self): """ Return the negation of ``self``. From 2128184c6460fa03b8d4a90e97792315202d9805 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 27 Mar 2015 09:27:10 +0100 Subject: [PATCH 046/223] yet another stupid question --- src/sage/categories/examples/lie_algebras.py | 2 +- src/sage/categories/lie_algebras.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py index db3cb9d95d2..eddbb400294 100644 --- a/src/sage/categories/examples/lie_algebras.py +++ b/src/sage/categories/examples/lie_algebras.py @@ -259,7 +259,7 @@ def _acted_upon_(self, scalar, self_on_left=False): return self.__class__(self.parent(), self.value * scalar) return self.__class__(self.parent(), scalar * self.value) - def __div__(self, x, self_on_left=False ): + def __div__(self, x, self_on_left=False): """ Division by coefficients. diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index 98248f755cf..a6baf908137 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -130,6 +130,12 @@ def _repr_object_names(self): sage: LieAlgebras(QQ)._repr_object_names() 'Lie algebras over Rational Field' + sage: LieAlgebras(Fields())._repr_object_names() + 'Lie algebras over fields' + sage: from sage.categories.category import JoinCategory + sage: from sage.categories.category_with_axiom import Blahs + sage: LieAlgebras(JoinCategory((Blahs().Flying(), Fields()))) + Category of Lie algebras over (flying unital blahs and fields) """ base = self.base() if isinstance(base, Category): @@ -240,6 +246,11 @@ def _construct_UEA(self): """ Construct the universal enveloping algebra of ``self``. + .. TODO:: + + What is the difference between this and + :meth:`universal_enveloping_algebra`? + EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() From 8eda1040915249308c40dd286dd6436fefb3408c Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 28 Mar 2015 08:19:46 +0100 Subject: [PATCH 047/223] some more changes --- src/sage/categories/lie_algebras.py | 44 ++++++++++++++----- .../categories/lie_algebras_with_basis.py | 3 +- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index a6baf908137..37df46840de 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -196,6 +196,8 @@ def extra_super_categories(self): True sage: LieAlgebras(ZZ).FiniteDimensional().is_subcategory(Sets().Finite()) False + sage: LieAlgebras(GF(5)).WithBasis().FiniteDimensional().is_subcategory(Sets().Finite()) + True """ if self.base_ring() in Sets().Finite(): return [Sets().Finite()] @@ -220,8 +222,9 @@ def bracket(self, lhs, rhs): """ return self(lhs)._bracket_(self(rhs)) - # Do not override this, instead implement _construct_UEA() in order - # to automatically setup the coercion + # Do not override this. Instead implement :meth:`_construct_UEA`; + # then, :meth:`lift` and :meth:`universal_enveloping_algebra` + # will automatically setup the coercion def universal_enveloping_algebra(self): """ Return the universal enveloping algebra of ``self``. @@ -238,18 +241,22 @@ def universal_enveloping_algebra(self): sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) # todo: not implemented - #16820 sage: L.universal_enveloping_algebra() # todo: not implemented - #16820 Multivariate Polynomial Ring in x0, x1, x2 over Rational Field + + .. SEEALSO:: + + :meth:`lift` """ return self.lift.codomain() @abstract_method(optional=True) def _construct_UEA(self): """ - Construct the universal enveloping algebra of ``self``. - - .. TODO:: + Return the universal enveloping algebra of ``self``. - What is the difference between this and - :meth:`universal_enveloping_algebra`? + Unlike :meth:`universal_enveloping_algebra`, this method does not + (usually) construct the canonical lift morphism from ``self`` + to the universal enveloping algebra (let alone register it + as a coercion). EXAMPLES:: @@ -268,7 +275,15 @@ def _construct_UEA(self): @abstract_method(optional=True) def free_module(self): """ - Construct the universal enveloping algebra of ``self``. + Construct the underlying (free) `R`-module of ``self``. + + This is an optional method, since Lie algebras are not + necessarily free as `R`-modules. + + .. TODO:: + + Why :meth:`free_module` instead of a more general + and probably more useful ``module``? EXAMPLES:: @@ -281,7 +296,12 @@ def free_module(self): def lift(self): """ Construct the lift morphism from ``self`` to the universal - enveloping algebra of ``self``. + enveloping algebra of ``self`` (the latter is implemented + as :meth:`universal_enveloping_algebra`). + + This is a Lie algebra homomorphism. It is injective if + ``self`` is a free module over its base ring, or if the + base ring is a `\QQ`-algebra. EXAMPLES:: @@ -537,7 +557,8 @@ def _bracket_(self, y): @abstract_method(optional=True) def lift(self): """ - Lift ``self`` into an element of the universal enveloping algebra. + Lift the element ``self`` to an element of the universal + enveloping algebra. EXAMPLES:: @@ -569,7 +590,8 @@ def killing_form(self, x): class LiftMorphism(Morphism): """ - The natural lifting morphism from a Lie algebra to an enveloping algebra. + The natural lifting morphism from a Lie algebra to its + enveloping algebra. """ def __init__(self, domain, codomain): """ diff --git a/src/sage/categories/lie_algebras_with_basis.py b/src/sage/categories/lie_algebras_with_basis.py index 51856eefe2d..375ece622c3 100644 --- a/src/sage/categories/lie_algebras_with_basis.py +++ b/src/sage/categories/lie_algebras_with_basis.py @@ -95,7 +95,8 @@ def free_module(self): class ElementMethods: def _bracket_(self, y): """ - Return the Lie bracket ``[self, y]``. + Return the Lie bracket ``[self, y]``, where ``y`` is an + element of the same Lie algebra as ``self``. EXAMPLES:: From 6c18d0734fbda11cb64318d79256bd390d3cb549 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 28 Mar 2015 17:29:40 +0100 Subject: [PATCH 048/223] rename free_module as module --- .../finite_dimensional_lie_algebras_with_basis.py | 8 ++++---- src/sage/categories/lie_algebras.py | 12 ++++-------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index 5471ad96d0b..72d1d4e540f 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -222,19 +222,19 @@ def gens(self): """ return tuple(self._M.basis()) - def free_module(self): + def module(self): """ - Return ``self`` as a free module. + Return the underlying free module of ``self``. EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.free_module() + sage: L.module() Vector space of dimension 3 over Rational Field sage: a, b, c = L.lie_algebra_generators() sage: S = L.subalgebra([2*a+b, b + c]) - sage: S.free_module() + sage: S.module() Vector space of degree 3 and dimension 2 over Rational Field Basis matrix: [ 1 0 -1/2] diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index 37df46840de..acce23ba482 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -273,22 +273,18 @@ def _construct_UEA(self): """ @abstract_method(optional=True) - def free_module(self): + def module(self): """ - Construct the underlying (free) `R`-module of ``self``. - - This is an optional method, since Lie algebras are not - necessarily free as `R`-modules. + Construct the underlying `R`-module of ``self``. .. TODO:: - Why :meth:`free_module` instead of a more general - and probably more useful ``module``? + Why optional? EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.free_module() + sage: L.module() Vector space of dimension 3 over Rational Field """ From c893945b300c3157485d4094fd2e72eadb65935d Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 28 Mar 2015 18:00:08 +0100 Subject: [PATCH 049/223] review sage/categories/lie_algebras.py --- src/sage/categories/lie_algebras.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index acce23ba482..5d033c67ebc 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -275,11 +275,7 @@ def _construct_UEA(self): @abstract_method(optional=True) def module(self): """ - Construct the underlying `R`-module of ``self``. - - .. TODO:: - - Why optional? + Return the underlying `R`-module of ``self``. EXAMPLES:: @@ -398,6 +394,13 @@ def is_field(self, proof=True): Return ``False`` since Lie algebras are never a field since they are not associative and antisymmetric. + .. TODO:: + + Do we need this method? It is confusing (some would misinterpret + it as checking for equality with the base field as an abelian + Lie algebra), and I don't see any contract that would require + it (our Lie algebras do not inherit from magmatic algebras). + EXAMPLES:: sage: L = LieAlgebras(QQ).example() @@ -432,8 +435,9 @@ def is_nilpotent(self): def _test_jacobi_identity(self, **options): """ - Test that the Jacobi identity is satisfied on (not - necessarily all) elements of this set. + Test that the Jacobi identity and the antisymmetry axiom + (`[x, x] = 0`) are satisfied on (not necessarily all) + elements of this set. INPUT:: @@ -461,11 +465,12 @@ def _test_jacobi_identity(self, **options): jacobi = lambda x, y, z: self.bracket(x, self.bracket(y, z)) + \ self.bracket(y, self.bracket(z, x)) + \ self.bracket(z, self.bracket(x, y)) + antisym = lambda x: self.bracket(x, x) zero = self.zero() for x in elts: for y in elts: if x == y: - continue + tester.assert_(antisym(x) == zero) for z in elts: tester.assert_(jacobi(x, y, z) == zero) @@ -553,8 +558,8 @@ def _bracket_(self, y): @abstract_method(optional=True) def lift(self): """ - Lift the element ``self`` to an element of the universal - enveloping algebra. + Return the image of ``self`` under the canonical lift from the Lie + algebra to its universal enveloping algebra. EXAMPLES:: From 37a1ece719c7de6fff56bcbbf88679e8d23763fd Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 28 Mar 2015 18:35:54 +0100 Subject: [PATCH 050/223] a few more changes --- ...ite_dimensional_lie_algebras_with_basis.py | 11 +++- src/sage/categories/lie_algebras.py | 61 +++++++++++-------- 2 files changed, 44 insertions(+), 28 deletions(-) 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 f6fdefd5960..b009d5818fa 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -83,23 +83,28 @@ def _construct_UEA(self): except ValueError: names = ['b{}'.format(i) for i in range(self.dimension())] F = FreeAlgebra(self.base_ring(), names) + # ``F`` is the free algebra over the basis of ``self``. The + # universal enveloping algebra of ``self`` will be constructed + # as a quotient of ``F``. d = F.gens_dict() rels = {} S = self.structure_coefficients(True) get_var = lambda g: d[names[I.index(g)]] + # The function ``get_var`` sends an element of the basis of + # ``self`` to the corresponding element of ``F``. for k in S.keys(): g0 = get_var(k[0]) g1 = get_var(k[1]) if g0 < g1: - rels[g1*g0] = g0*g1 - sum(val*get_var(g) for g, val in S[k]) + rels[g1*g0] = g0*g1 - F.sum(val*get_var(g) for g, val in S[k]) else: - rels[g0*g1] = g1*g0 + sum(val*get_var(g) for g, val in S[k]) + rels[g0*g1] = g1*g0 + F.sum(val*get_var(g) for g, val in S[k]) return F.g_algebra(rels) @lazy_attribute def _basis_ordering(self): """ - Return an order of the indices of the basis. + Return a (fixed) order of the indices of the basis. Override this attribute to get a specific ordering of the basis. diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index 5d033c67ebc..cf6b448d130 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -68,6 +68,7 @@ class LieAlgebras(Category_over_base_ring): sage: TestSuite(A).run(verbose=True) running ._test_additive_associativity() . . . pass running ._test_an_element() . . . pass + running ._test_antisymmetry() . . . pass running ._test_category() . . . pass running ._test_distributivity() . . . pass running ._test_elements() . . . @@ -389,26 +390,6 @@ def is_commutative(self): """ return self.is_abelian() - def is_field(self, proof=True): - """ - Return ``False`` since Lie algebras are never a field since - they are not associative and antisymmetric. - - .. TODO:: - - Do we need this method? It is confusing (some would misinterpret - it as checking for equality with the base field as an abelian - Lie algebra), and I don't see any contract that would require - it (our Lie algebras do not inherit from magmatic algebras). - - EXAMPLES:: - - sage: L = LieAlgebras(QQ).example() - sage: L.is_field() - False - """ - return False - @abstract_method(optional=True) def is_solvable(self): """ @@ -435,9 +416,8 @@ def is_nilpotent(self): def _test_jacobi_identity(self, **options): """ - Test that the Jacobi identity and the antisymmetry axiom - (`[x, x] = 0`) are satisfied on (not necessarily all) - elements of this set. + Test that the Jacobi identity is satisfied on (not + necessarily all) elements of this set. INPUT:: @@ -465,15 +445,46 @@ def _test_jacobi_identity(self, **options): jacobi = lambda x, y, z: self.bracket(x, self.bracket(y, z)) + \ self.bracket(y, self.bracket(z, x)) + \ self.bracket(z, self.bracket(x, y)) - antisym = lambda x: self.bracket(x, x) zero = self.zero() for x in elts: for y in elts: if x == y: - tester.assert_(antisym(x) == zero) + continue for z in elts: tester.assert_(jacobi(x, y, z) == zero) + def _test_antisymmetry(self, **options): + """ + Test that the antisymmetry axiom is satisfied on (not + necessarily all) elements of this set. + + INPUT:: + + - ``options`` -- any keyword arguments accepted by :meth:`_tester`. + + EXAMPLES: + + By default, this method runs the tests only on the + elements returned by ``self.some_elements()``:: + + sage: L = LieAlgebras(QQ).example() + sage: L._test_antisymmetry() + + However, the elements tested can be customized with the + ``elements`` keyword argument:: + + sage: L = LieAlgebras(QQ).example() + sage: x,y = L.lie_algebra_generators() + sage: L._test_antisymmetry(elements=[x+y, x, 2*y, x.bracket(y)]) + + See the documentation for :class:`TestSuite` for more information. + """ + tester = self._tester(**options) + elts = tester.some_elements() + zero = self.zero() + for x in elts: + tester.assert_(self.bracket(x, x) == zero) + def _test_distributivity(self, **options): r""" Test the distributivity of the Lie bracket `[,]` on `+` on (not From 464c131fcfa33e4e6a2172ee7e1fdf4144b0425d Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 28 Mar 2015 23:24:07 +0100 Subject: [PATCH 051/223] another appearance of free_module --- .../finite_dimensional_lie_algebras_with_basis.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) 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 b009d5818fa..20ee37e41a8 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -104,7 +104,8 @@ def _construct_UEA(self): @lazy_attribute def _basis_ordering(self): """ - Return a (fixed) order of the indices of the basis. + Return the indices of the basis of ``self`` as a tuple in + a fixed order. Override this attribute to get a specific ordering of the basis. @@ -137,8 +138,9 @@ def killing_matrix(self, x, y): Return the Killing matrix of ``x`` and ``y``. The Killing matrix is defined as the matrix corresponding - to the action of `\mathrm{ad}_x \circ \mathrm{ad}_y` in - the basis of ``self``. + to the action of + `\operatorname{ad}_x \circ \operatorname{ad}_y` in the + basis of ``self``. EXAMPLES:: @@ -578,8 +580,12 @@ def to_vector(self): sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: L.an_element().to_vector() (0, 0, 0) + + .. TODO:: + + Doctest this implementation on an example not overshadowed. """ - M = self.parent().free_module() + M = self.parent().module() if not self: return M.zero() B = M.basis() From 6608a1805869afd139d6c1c6361caf2542363b25 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 29 Mar 2015 01:03:16 +0100 Subject: [PATCH 052/223] .module and .to_vector: I still don't get them --- .../categories/finite_dimensional_lie_algebras_with_basis.py | 2 ++ 1 file changed, 2 insertions(+) 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 20ee37e41a8..8b6b1e70015 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -585,6 +585,8 @@ def to_vector(self): Doctest this implementation on an example not overshadowed. """ + # TODO: + # Why do we have this method? Shouldn't it just return ``self``? M = self.parent().module() if not self: return M.zero() From 6201720759c9f35cb0349a3c71d7b178686ef346 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 29 Mar 2015 17:02:18 -0400 Subject: [PATCH 053/223] does this make sense? --- ...ite_dimensional_lie_algebras_with_basis.py | 26 ++++++++++++++-- ...ite_dimensional_lie_algebras_with_basis.py | 5 ++- src/sage/categories/lie_algebras.py | 31 ++++++++++++++++++- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index 72d1d4e540f..6eac51341e7 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -224,7 +224,25 @@ def gens(self): def module(self): """ - Return the underlying free module of ``self``. + Return the underlying `R`-module of ``self`` as an + unindexed free `R`-module (i.e., as an `R`-module + of column vectors). + + For instance, if ``self`` has ordered basis + `(e, f, h)`, then ``self.module()`` will be the + `R`-module `R^3`, and the elements `e`, `f` and + `h` of ``self`` will correspond to the basis + vectors `(1, 0, 0)`, `(0, 1, 0)` and `(0, 0, 1)` + of ``self.module()``. + + This method :meth:`module` needs to be set whenever + a finite-dimensional Lie algebra with basis is + intended to support linear algebra (which is, e.g., + used in the computation of centralizers and lower + central series). One then needs to also implement + a ``to_vector`` ElementMethod which sends every + element of ``self`` to the corresponding element of + ``self.to_module()``. EXAMPLES:: @@ -312,7 +330,11 @@ def lift(self): def to_vector(self): """ - Return ``self`` as a vector. + Return ``self`` as a vector in + ``self.parent().module()``. + + See the docstring of the latter method for the meaning + of this. EXAMPLES:: 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 8b6b1e70015..9a3e22c493f 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -573,7 +573,10 @@ def dimension(self): class ElementMethods: def to_vector(self): """ - Return ``self`` as a vector. + Return ``self`` as a vector in ``self.parent().module()``. + + See the docstring of the latter method for the meaning + of this. EXAMPLES:: diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index cf6b448d130..e0a346bffa4 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -276,7 +276,36 @@ def _construct_UEA(self): @abstract_method(optional=True) def module(self): """ - Return the underlying `R`-module of ``self``. + Return the underlying `R`-module of ``self`` as an + unindexed free `R`-module (i.e., as an `R`-module + of column vectors). + + For instance, if ``self`` has ordered basis + `(e, f, h)`, then ``self.module()`` will be the + `R`-module `R^3`, and the elements `e`, `f` and + `h` of ``self`` will correspond to the basis + vectors `(1, 0, 0)`, `(0, 1, 0)` and `(0, 0, 1)` + of ``self.module()``. + + This method :meth:`module` needs to be set whenever + a finite-dimensional Lie algebra with basis is + intended to support linear algebra (which is, e.g., + used in the computation of centralizers and lower + central series). One then needs to also implement + a ``to_vector`` ElementMethod which sends every + element of ``self`` to the corresponding element of + ``self.to_module()``. + + .. TODO:: + + Why is this method here and not in + :class:`FiniteDimensionalLieAlgebrasWithBasis` ? + + .. TODO:: + + I see no ``from_vector`` method. How is one + supposed to take an element of ``self.module()`` + back to ``self``? Via coercion/constructor? EXAMPLES:: From b0e36fe84ece0690d7298cd913ec8b77a3c4f38b Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Mon, 13 Apr 2015 23:41:09 +0200 Subject: [PATCH 054/223] changes I forgot to commit a few weeks ago --- ...ite_dimensional_lie_algebras_with_basis.py | 26 ++++++++++++++----- .../categories/lie_algebras_with_basis.py | 10 ++++--- 2 files changed, 27 insertions(+), 9 deletions(-) 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 9a3e22c493f..2d29e79ed55 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -135,7 +135,8 @@ def _dense_free_module(self, R=None): def killing_matrix(self, x, y): r""" - Return the Killing matrix of ``x`` and ``y``. + Return the Killing matrix of ``x`` and ``y``, where ``x`` + and ``y`` are two elements of ``self``. The Killing matrix is defined as the matrix corresponding to the action of @@ -162,14 +163,16 @@ def killing_matrix(self, x, y): def killing_form(self, x, y): r""" - Return the Killing form on ``x`` and ``y``. + Return the Killing form on ``x`` and ``y``, where ``x`` + and ``y`` are two elements of ``self``. The Killing form is defined as .. MATH:: - \langle x \mid y \rangle = \mathrm{tr}\left( \mathrm{ad}_x - \circ \mathrm{ad}_y \right). + \langle x \mid y \rangle + = \operatorname{tr}\left( \operatorname{ad}_x + \circ \operatorname{ad}_y \right). EXAMPLES:: @@ -185,6 +188,10 @@ def killing_form_matrix(self): """ Return the matrix of the Killing form of ``self``. + The rows and the columns of this matrix are indexed by the + elements of the basis of ``self`` (in the order provided by + :meth:`basis`). + EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() @@ -192,9 +199,16 @@ def killing_form_matrix(self): [0 0 0] [0 0 0] [0 0 0] + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example(0) + sage: m = L.killing_form_matrix() + [] + sage: parent(m) + Full MatrixSpace of 0 by 0 dense matrices over Rational Field """ B = self.basis() - m = matrix([[self.killing_form(x, y) for x in B] for y in B]) + m = matrix(self.base_ring(), + [[self.killing_form(x, y) for x in B] for y in B]) m.set_immutable() return m @@ -224,7 +238,7 @@ def structure_coefficients(self, include_zeros=False): """ d = {} B = self.basis() - K = self.basis().keys() + K = B.keys() zero = self.zero() for i,x in enumerate(K): for y in K[i+1:]: diff --git a/src/sage/categories/lie_algebras_with_basis.py b/src/sage/categories/lie_algebras_with_basis.py index 375ece622c3..f33f30f6776 100644 --- a/src/sage/categories/lie_algebras_with_basis.py +++ b/src/sage/categories/lie_algebras_with_basis.py @@ -74,14 +74,18 @@ def bracket_on_basis(self, x, y): 0 """ - def free_module(self): + def module(self): """ - Return ``self`` as a free module. + Return the underlying free `R`-module of ``self``. + + This method becomes useful when ``self`` does not belong to + the :class:`FreeModules` category and thus does not + natively support linear-algebra methods. EXAMPLES:: sage: L = LieAlgebras(QQ).WithBasis().example() - sage: L.free_module() + sage: L.module() Free module generated by Partitions over Rational Field """ from sage.combinat.free_module import CombinatorialFreeModule From de608491bf98ce8209b719e2a1052e2f13f917f3 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 15 Apr 2015 17:10:32 +0200 Subject: [PATCH 055/223] I have no idea what I'm doing --- ...ite_dimensional_lie_algebras_with_basis.py | 48 +++++++----- ...ite_dimensional_lie_algebras_with_basis.py | 49 +++++++++--- src/sage/categories/lie_algebras.py | 77 ++++++++++++++++--- .../categories/lie_algebras_with_basis.py | 49 +++++++++++- 4 files changed, 178 insertions(+), 45 deletions(-) diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index 6eac51341e7..0160911baab 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -224,25 +224,15 @@ def gens(self): def module(self): """ - Return the underlying `R`-module of ``self`` as an - unindexed free `R`-module (i.e., as an `R`-module - of column vectors). - - For instance, if ``self`` has ordered basis - `(e, f, h)`, then ``self.module()`` will be the - `R`-module `R^3`, and the elements `e`, `f` and - `h` of ``self`` will correspond to the basis - vectors `(1, 0, 0)`, `(0, 1, 0)` and `(0, 0, 1)` - of ``self.module()``. - - This method :meth:`module` needs to be set whenever - a finite-dimensional Lie algebra with basis is - intended to support linear algebra (which is, e.g., - used in the computation of centralizers and lower - central series). One then needs to also implement - a ``to_vector`` ElementMethod which sends every - element of ``self`` to the corresponding element of - ``self.to_module()``. + Return an `R`-module which is isomorphic to the + underlying `R`-module of ``self``. + + See + :meth:`sage.categories.lie_algebras.LieAlgebras.module` for + an explanation. + + In this particular example, this returns the module `M` + that was used to construct ``self``. EXAMPLES:: @@ -260,6 +250,26 @@ def module(self): """ return self._M + def from_vector(self, v): + """ + Return the element of ``self`` corresponding to the + vector ``v`` in ``self.module()``. + + Implement this if you implement :meth:`module`; see the + documentation of + :meth:`sage.categories.lie_algebras.LieAlgebras.module` + for how this is to be done. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: u = L.from_vector(vector(QQ, (1, 0, 0))); u + (1, 0, 0) + sage: parent(u) is L + True + """ + return self.element_class(self, self._M(v)) + class Element(BaseExample.Element): def __iter__(self): """ 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 2d29e79ed55..d5271356ece 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -21,6 +21,7 @@ from sage.algebras.free_algebra import FreeAlgebra from sage.sets.family import Family from sage.matrix.constructor import matrix +from sage.modules.free_module_element import vector class FiniteDimensionalLieAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ @@ -133,6 +134,31 @@ def _dense_free_module(self, R=None): from sage.modules.free_module import FreeModule return FreeModule(R, self.dimension()) + def from_vector(self, v): + """ + Return the element of ``self`` corresponding to the + vector ``v`` in ``self.module()``. + + Implement this if you implement :meth:`module`; see the + documentation of + :meth:`sage.categories.lie_algebras.LieAlgebras.module` + for how this is to be done. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: u = L.from_vector(vector(QQ, (1, 0, 0))); u + (1, 0, 0) + sage: parent(u) is L + True + """ + M = self.module() + if not v: + return self.zero() + B = M.basis() + selfB = self.basis() + return self.sum(v[k]*selfB[k] for k in self._basis_ordering) + def killing_matrix(self, x, y): r""" Return the Killing matrix of ``x`` and ``y``, where ``x`` @@ -201,7 +227,7 @@ def killing_form_matrix(self): [0 0 0] sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example(0) - sage: m = L.killing_form_matrix() + sage: m = L.killing_form_matrix(); m [] sage: parent(m) Full MatrixSpace of 0 by 0 dense matrices over Rational Field @@ -287,11 +313,12 @@ def centralizer(self, S): X = self.basis().keys() d = self.dimension() K = sc.keys() - c_mat = matrix([[sum(r[j]*sc[x,X[j]][k] for j in range(d) if (x, X[j]) in K) + c_mat = matrix(self.base_ring(), + [[sum(r[j]*sc[x,X[j]][k] for j in range(d) if (x, X[j]) in K) for x in X] for r in m for k in range(d)]) C = c_mat.right_kernel().basis_matrix() - return self.subalgebra(map(self, C)) + return self.subalgebra([self.from_vector(v) for v in C]) def center(self): """ @@ -587,10 +614,13 @@ def dimension(self): class ElementMethods: def to_vector(self): """ - Return ``self`` as a vector in ``self.parent().module()``. + Return the vector in ``g.module()`` corresponding to the + element ``self`` of ``g`` (where ``g`` is the parent of + ``self``). - See the docstring of the latter method for the meaning - of this. + Implement this if you implement ``g.module()``. + See :meth:`sage.categories.lie_algebras.LieAlgebras.module` + for how this is to be done. EXAMPLES:: @@ -602,13 +632,11 @@ def to_vector(self): Doctest this implementation on an example not overshadowed. """ - # TODO: - # Why do we have this method? Shouldn't it just return ``self``? M = self.parent().module() if not self: return M.zero() B = M.basis() - return M.sum(B[k]*self[k] for k in self.parent()._ordered_indices) + return M.sum(Bk*self[k] for k, Bk in B.iteritems()) def adjoint_matrix(self): # In #11111 (more or less) by using matrix of a mophism """ @@ -634,7 +662,8 @@ def adjoint_matrix(self): # In #11111 (more or less) by using matrix of a mophis """ P = self.parent() basis = P.basis() - return matrix([P.bracket(self, b).to_vector() for b in basis]) + return matrix(self.base_ring(), + [vector(P.bracket(self, b).to_vector()) for b in basis]) class Subobjects(SubobjectsCategory): """ diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index e0a346bffa4..169edeb16db 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -276,9 +276,19 @@ def _construct_UEA(self): @abstract_method(optional=True) def module(self): """ - Return the underlying `R`-module of ``self`` as an - unindexed free `R`-module (i.e., as an `R`-module - of column vectors). + Return an `R`-module which is isomorphic to the + underlying `R`-module of ``self``. + + The rationale behind this method is to enable linear + algebraic functionality on ``self`` (such as + computing the span of a list of vectors in ``self``) + via an isomorphism from ``self`` to an `R`-module + (typically, although not always, an `R`-module of + the form `R^n` for an `n \in \NN`) on which such + functionality already exists. For this method to be + of any use, it should return an `R`-module which has + linear algebraic functionality that ``self`` does + not have. For instance, if ``self`` has ordered basis `(e, f, h)`, then ``self.module()`` will be the @@ -292,20 +302,26 @@ def module(self): intended to support linear algebra (which is, e.g., used in the computation of centralizers and lower central series). One then needs to also implement - a ``to_vector`` ElementMethod which sends every - element of ``self`` to the corresponding element of - ``self.to_module()``. + the `R`-module isomorphism from ``self`` to + ``self.module()`` in both directions; that is, + implement: - .. TODO:: + * a ``to_vector`` ElementMethod which sends every + element of ``self`` to the corresponding element of + ``self.module()``; + + * a ``from_vector`` ParentMethod which sends every + element of ``self.module()`` to an element + of ``self``. - Why is this method here and not in - :class:`FiniteDimensionalLieAlgebrasWithBasis` ? + The ``from_vector`` method will automatically serve + as an element constructor of ``self`` (that is, + ``self(v)`` for any ``v`` in ``self.module()`` will + return ``self.from_vector(v)``). .. TODO:: - I see no ``from_vector`` method. How is one - supposed to take an element of ``self.module()`` - back to ``self``? Via coercion/constructor? + Ensure that this is actually so. EXAMPLES:: @@ -314,6 +330,24 @@ def module(self): Vector space of dimension 3 over Rational Field """ + @abstract_method(optional=True) + def from_vector(self, v): + """ + Return the element of ``self`` corresponding to the + vector ``v`` in ``self.module()``. + + Implement this if you implement :meth:`module`; see the + documentation of the latter for how this is to be done. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: u = L.from_vector(vector(QQ, (1, 0, 0))); u + (1, 0, 0) + sage: parent(u) is L + True + """ + @lazy_attribute def lift(self): """ @@ -595,6 +629,25 @@ def _bracket_(self, y): 0 """ + @abstract_method(optional=True) + def to_vector(self): + """ + Return the vector in ``g.module()`` corresponding to the + element ``self`` of ``g`` (where ``g`` is the parent of + ``self``). + + Implement this if you implement ``g.module()``. + See :meth:`LieAlgebras.module` for how this is to be done. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: u = L((1, 0, 0)).to_vector(); u + (1, 0, 0) + sage: parent(u) + Vector space of dimension 3 over Rational Field + """ + @abstract_method(optional=True) def lift(self): """ diff --git a/src/sage/categories/lie_algebras_with_basis.py b/src/sage/categories/lie_algebras_with_basis.py index f33f30f6776..3bc24ca5bcd 100644 --- a/src/sage/categories/lie_algebras_with_basis.py +++ b/src/sage/categories/lie_algebras_with_basis.py @@ -76,11 +76,12 @@ def bracket_on_basis(self, x, y): def module(self): """ - Return the underlying free `R`-module of ``self``. + Return an `R`-module which is isomorphic to the + underlying `R`-module of ``self``. - This method becomes useful when ``self`` does not belong to - the :class:`FreeModules` category and thus does not - natively support linear-algebra methods. + See + :meth:`sage.categories.lie_algebras.LieAlgebras.module` for + an explanation. EXAMPLES:: @@ -96,6 +97,26 @@ def module(self): # Otherwise just index by the basis of ``self`` as a fallback return CombinatorialFreeModule(self.base_ring(), self.basis()) + def from_vector(self, v): + """ + Return the element of ``self`` corresponding to the + vector ``v`` in ``self.module()``. + + Implement this if you implement :meth:`module`; see the + documentation of + :meth:`sage.categories.lie_algebras.LieAlgebras.module` + for how this is to be done. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: u = L.from_vector(vector(QQ, (1, 0, 0))); u + (1, 0, 0) + sage: parent(u) is L + True + """ + return self(v) + class ElementMethods: def _bracket_(self, y): """ @@ -121,3 +142,23 @@ def term(ml,mr): return -P.bracket_on_basis(mr, ml) return P.sum(cl*cr * term(ml,mr) for ml,cl in self for mr,cr in y) + def to_vector(self): + """ + Return the vector in ``g.module()`` corresponding to the + element ``self`` of ``g`` (where ``g`` is the parent of + ``self``). + + Implement this if you implement ``g.module()``. + See :meth:`sage.categories.lie_algebras.LieAlgebras.module` + for how this is to be done. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: u = L((1, 0, 0)).to_vector(); u + (1, 0, 0) + sage: parent(u) + Vector space of dimension 3 over Rational Field + """ + return self.parent().module(self) + From 0c28f5fce7c81cdaaa177eff1672e6382803a615 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 15 Apr 2015 22:57:24 +0200 Subject: [PATCH 056/223] reverting parts of previous commit with fire --- ...ite_dimensional_lie_algebras_with_basis.py | 51 ------------------- .../categories/lie_algebras_with_basis.py | 17 ++++--- 2 files changed, 11 insertions(+), 57 deletions(-) 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 d5271356ece..a8b81cbc774 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -134,31 +134,6 @@ def _dense_free_module(self, R=None): from sage.modules.free_module import FreeModule return FreeModule(R, self.dimension()) - def from_vector(self, v): - """ - Return the element of ``self`` corresponding to the - vector ``v`` in ``self.module()``. - - Implement this if you implement :meth:`module`; see the - documentation of - :meth:`sage.categories.lie_algebras.LieAlgebras.module` - for how this is to be done. - - EXAMPLES:: - - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: u = L.from_vector(vector(QQ, (1, 0, 0))); u - (1, 0, 0) - sage: parent(u) is L - True - """ - M = self.module() - if not v: - return self.zero() - B = M.basis() - selfB = self.basis() - return self.sum(v[k]*selfB[k] for k in self._basis_ordering) - def killing_matrix(self, x, y): r""" Return the Killing matrix of ``x`` and ``y``, where ``x`` @@ -612,32 +587,6 @@ def dimension(self): return self.basis().cardinality() class ElementMethods: - def to_vector(self): - """ - Return the vector in ``g.module()`` corresponding to the - element ``self`` of ``g`` (where ``g`` is the parent of - ``self``). - - Implement this if you implement ``g.module()``. - See :meth:`sage.categories.lie_algebras.LieAlgebras.module` - for how this is to be done. - - EXAMPLES:: - - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.an_element().to_vector() - (0, 0, 0) - - .. TODO:: - - Doctest this implementation on an example not overshadowed. - """ - M = self.parent().module() - if not self: - return M.zero() - B = M.basis() - return M.sum(Bk*self[k] for k, Bk in B.iteritems()) - def adjoint_matrix(self): # In #11111 (more or less) by using matrix of a mophism """ Return the matrix of the adjoint action of ``self``. diff --git a/src/sage/categories/lie_algebras_with_basis.py b/src/sage/categories/lie_algebras_with_basis.py index 3bc24ca5bcd..e87b0060aba 100644 --- a/src/sage/categories/lie_algebras_with_basis.py +++ b/src/sage/categories/lie_algebras_with_basis.py @@ -115,7 +115,8 @@ def from_vector(self, v): sage: parent(u) is L True """ - return self(v) + B = self.basis() + return self.sum(v[i] * B[i] for i in v.support()) class ElementMethods: def _bracket_(self, y): @@ -155,10 +156,14 @@ def to_vector(self): EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: u = L((1, 0, 0)).to_vector(); u - (1, 0, 0) - sage: parent(u) - Vector space of dimension 3 over Rational Field + sage: L.an_element().to_vector() + (0, 0, 0) + + .. TODO:: + + Doctest this implementation on an example not overshadowed. """ - return self.parent().module(self) + M = self.parent().module() + B = M.basis() + return M.sum(self[i] * B[i] for i in self.support()) From 6c5fe38ffdc537cce65e26a3753a7220b58cbef5 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 16 Apr 2015 07:06:24 +0200 Subject: [PATCH 057/223] minor changes --- src/sage/algebras/lie_algebras/examples.py | 8 +++++++- src/sage/algebras/lie_algebras/virasoro.py | 18 +++++++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index c0beaaa00a1..50fc7061aa5 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -9,6 +9,12 @@ - The Lie algebra of upper triangular matrices - The Lie algebra of strictly upper triangular matrices +See also +:class:`sage.algebras.lie_algebras.virasoro.LieAlgebraRegularVectorFields` +and +:class:`sage.algebras.lie_algebras.virasoro.VirasoroAlgebra` for +other examples. + AUTHORS: - Travis Scrimshaw (07-15-2013): Initial implementation @@ -21,7 +27,7 @@ #****************************************************************************** #from sage.algebras.lie_algebras.classical_lie_algebra import gl, sl, so, sp -from sage.algebras.lie_algebras.virasoro import VirasoroAlgebra +#from sage.algebras.lie_algebras.virasoro import VirasoroAlgebra def three_dimensional(R, a, b, c, d, names=['X', 'Y', 'Z']): r""" diff --git a/src/sage/algebras/lie_algebras/virasoro.py b/src/sage/algebras/lie_algebras/virasoro.py index ba8ec8d44ed..f3237e44114 100644 --- a/src/sage/algebras/lie_algebras/virasoro.py +++ b/src/sage/algebras/lie_algebras/virasoro.py @@ -28,7 +28,7 @@ from sage.sets.set import Set from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.structure.indexed_generators import IndexedGenerators -from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement +#from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement from sage.algebras.lie_algebras.lie_algebra import InfinitelyGeneratedLieAlgebra class LieAlgebraRegularVectorFields(InfinitelyGeneratedLieAlgebra, IndexedGenerators): @@ -133,12 +133,20 @@ class VirasoroAlgebra(InfinitelyGeneratedLieAlgebra, IndexedGenerators): r""" The Virasoro algebra. - This is the Lie algebra generated by `\{d_i\}_{i \in \ZZ}` and subject - to the relations + This is the Lie algebra generated by `\{d_i\}_{i \in \ZZ} \cup \{c\}` + and subject to the relations .. MATH:: - [d_i, d_j] = (j - i) d_{i+j} + \frac{1}{12}(j^3 - j) \delta_{i,-j} c. + [d_i, d_j] = (j - i) d_{i+j} + \frac{1}{12}(j^3 - j) \delta_{i,-j} c + + and + + .. MATH:: + + [d_i, c] = 0. + + (Here, it is assumed that the base ring `R` has `2` invertible.) This is the universal central extension `\widetilde{\mathfrak{d}}` of the Lie algebra `\mathfrak{d}` of @@ -251,7 +259,7 @@ def d(self, i): def c(self): """ - The central element in ``self``. + The central element `c` in ``self``. EXAMPLES:: From 3d450840695003e8e410e0d0e3b926d7a00abe23 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 16 Apr 2015 07:12:25 +0200 Subject: [PATCH 058/223] fixing Jacobi identity for 3d example (unless Iam wrong? please add tests) --- src/sage/algebras/lie_algebras/examples.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index 50fc7061aa5..45532e6cad7 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -31,26 +31,29 @@ def three_dimensional(R, a, b, c, d, names=['X', 'Y', 'Z']): r""" - The 3 dimensional Lie algebra generated by `X, Y, Z` defined by - the relations: + The 3 dimensional Lie algebra over a given commutative ring `R` + generated by `X, Y, Z` subject to the relations: .. MATH:: - [X, Y] = aZ + dY, \quad [Y, Z] = bX, \quad [Z, X] = cY - dZ + [X, Y] = aZ + dY, \quad [Y, Z] = bX, \quad [Z, X] = cY + dZ where `a,b,c,d \in R`. + This is always a well-defined 3-dimensional Lie algebra, as can + be easily proven by computation. + EXAMPLES:: sage: L = lie_algebras.three_dimensional(QQ, 4, 1, -1, 2) sage: L.structure_coefficients() - Finite family {('X', 'Y'): 2*Y + 4*Z, ('X', 'Z'): Y + 2*Z, ('Y', 'Z'): X} + Finite family {('X', 'Y'): 2*Y + 4*Z, ('X', 'Z'): Y - 2*Z, ('Y', 'Z'): X} sage: L = lie_algebras.three_dimensional(QQ, 1, 0, 0, 0) sage: L.structure_coefficients() Finite family {('X', 'Y'): Z} sage: L = lie_algebras.three_dimensional(QQ, 0, 0, -1, -1) sage: L.structure_coefficients() - Finite family {('X', 'Y'): -Y, ('X', 'Z'): Y - Z} + Finite family {('X', 'Y'): -Y, ('X', 'Z'): Y + Z} sage: L = lie_algebras.three_dimensional(QQ, 0, 1, 0, 0) sage: L.structure_coefficients() Finite family {('Y', 'Z'): X} @@ -63,7 +66,7 @@ def three_dimensional(R, a, b, c, d, names=['X', 'Y', 'Z']): Y = names[1] Z = names[2] from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients - s_coeff = {(X,Y): {Z:a, Y:d}, (Y,Z): {X:b}, (Z,X): {Y:c, Z:-d}} + s_coeff = {(X,Y): {Z:a, Y:d}, (Y,Z): {X:b}, (Z,X): {Y:c, Z:d}} return LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) def cross_product(R, names=['X', 'Y', 'Z']): From dfad36c9deb5a0b35b72dbefee3ac5290e9fd838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 16 Apr 2015 13:30:00 +0200 Subject: [PATCH 059/223] trac #16819 wrong inclusion into doc is corrected --- src/doc/en/reference/categories/index.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/en/reference/categories/index.rst b/src/doc/en/reference/categories/index.rst index a53167444bc..155a111cdcb 100644 --- a/src/doc/en/reference/categories/index.rst +++ b/src/doc/en/reference/categories/index.rst @@ -86,7 +86,7 @@ Categories sage/categories/finite_dimensional_bialgebras_with_basis sage/categories/finite_dimensional_coalgebras_with_basis sage/categories/finite_dimensional_hopf_algebras_with_basis - sage/categories/finite_dimensional_lie_algebras_with_basis.py + sage/categories/finite_dimensional_lie_algebras_with_basis sage/categories/finite_dimensional_modules_with_basis sage/categories/finite_enumerated_sets sage/categories/finite_fields @@ -122,8 +122,8 @@ Categories sage/categories/integral_domains sage/categories/lattice_posets sage/categories/left_modules - sage/categories/lie_algebras.py - sage/categories/lie_algebras_with_basis.py + sage/categories/lie_algebras + sage/categories/lie_algebras_with_basis sage/categories/magmas sage/categories/magmas_and_additive_magmas sage/categories/magmatic_algebras @@ -180,15 +180,15 @@ Examples of parents using categories sage/categories/examples/facade_sets sage/categories/examples/finite_coxeter_groups sage/categories/examples/finite_enumerated_sets - sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py + sage/categories/examples/finite_dimensional_lie_algebras_with_basis sage/categories/examples/finite_monoids sage/categories/examples/finite_semigroups sage/categories/examples/finite_weyl_groups sage/categories/examples/graded_modules_with_basis sage/categories/examples/hopf_algebras_with_basis sage/categories/examples/infinite_enumerated_sets - sage/categories/examples/lie_algebras.py - sage/categories/examples/lie_algebras_with_basis.py + sage/categories/examples/lie_algebras + sage/categories/examples/lie_algebras_with_basis sage/categories/examples/monoids sage/categories/examples/posets sage/categories/examples/semigroups_cython From eb3b058689ffe114ef62c8b4389e784fad8d176c Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 16 Apr 2015 16:07:58 +0200 Subject: [PATCH 060/223] hopefully fix doc bug --- src/sage/categories/groups.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 785d81afc12..9df00c49a4f 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -91,9 +91,9 @@ class ParentMethods: def group_generators(self): """ - Returns group generators for self. + Return group generators for ``self``. - This default implementation calls :meth:`.gens`, for + This default implementation calls :meth:`gens`, for backward compatibility. EXAMPLES:: From 5e9a839618ae034d04c13340603a8b62d4bbf2f8 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 16 Apr 2015 16:33:06 +0200 Subject: [PATCH 061/223] Jacobi identity now tested --- src/sage/algebras/lie_algebras/examples.py | 5 ++++- .../algebras/lie_algebras/structure_coefficients.py | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index 45532e6cad7..5681bb7abc5 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -48,6 +48,7 @@ def three_dimensional(R, a, b, c, d, names=['X', 'Y', 'Z']): sage: L = lie_algebras.three_dimensional(QQ, 4, 1, -1, 2) sage: L.structure_coefficients() Finite family {('X', 'Y'): 2*Y + 4*Z, ('X', 'Z'): Y - 2*Z, ('Y', 'Z'): X} + sage: TestSuite(L).run() sage: L = lie_algebras.three_dimensional(QQ, 1, 0, 0, 0) sage: L.structure_coefficients() Finite family {('X', 'Y'): Z} @@ -71,13 +72,15 @@ def three_dimensional(R, a, b, c, d, names=['X', 'Y', 'Z']): def cross_product(R, names=['X', 'Y', 'Z']): r""" - The Lie algebra of `\RR^3` defined by `\times` as the usual cross product. + The Lie algebra of `\RR^3` defined by the usual cross product + `\times`. EXAMPLES:: sage: L = lie_algebras.cross_product(QQ) sage: L.structure_coefficients() Finite family {('X', 'Y'): Z, ('X', 'Z'): -Y, ('Y', 'Z'): X} + sage: TestSuite(L).run() """ L = three_dimensional(R, 1, 1, 1, 0, names=names) L.rename("Lie algebra of RR^3 under cross product over {}".format(R)) diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index de0ce75de2d..51884e4c0f3 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -252,6 +252,18 @@ def free_module(self, sparse=True): """ return FreeModule(self.base_ring(), self.dimension(), sparse=sparse) + def some_elements(self): + """ + Return some elements of ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.three_dimensional(QQ, 4, 1, -1, 2) + sage: L.some_elements() + [X, Y, Z, X + Y + Z] + """ + return list(self.basis()) + [self.sum(self.basis())] + class Element(LieAlgebraElement): """ An element of a Lie algebra given by structure coefficients. From 005984dfd1e329136db896a7dd29c1a2153dcff6 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 16 Apr 2015 17:07:28 +0200 Subject: [PATCH 062/223] document the broken multiplication by base ring --- src/sage/algebras/lie_algebras/examples.py | 2 +- src/sage/algebras/lie_algebras/lie_algebra.py | 8 ++++---- src/sage/algebras/lie_algebras/lie_algebra_element.py | 8 ++++++-- src/sage/algebras/lie_algebras/structure_coefficients.py | 6 +++--- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index 5681bb7abc5..49088424722 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -27,7 +27,7 @@ #****************************************************************************** #from sage.algebras.lie_algebras.classical_lie_algebra import gl, sl, so, sp -#from sage.algebras.lie_algebras.virasoro import VirasoroAlgebra +from sage.algebras.lie_algebras.virasoro import VirasoroAlgebra def three_dimensional(R, a, b, c, d, names=['X', 'Y', 'Z']): r""" diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 76c89ef6511..eab9a91ec72 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -421,15 +421,15 @@ def _coerce_map_from_(self, R): TESTS:: sage: L. = LieAlgebra(QQ, abelian=True) - sage: L._coerce_map_from_(L.free_module()) + sage: L._coerce_map_from_(L.module()) True sage: L._coerce_map_from_(FreeModule(ZZ, 2)) True """ if not isinstance(R, LieAlgebra): # Should be moved to LieAlgebrasWithBasis somehow since it is a generic coercion - if self.free_module is not NotImplemented: - return self.free_module().has_coerce_map_from(R) + if self.module is not NotImplemented: + return self.module().has_coerce_map_from(R) return False # We check if it is a subalgebra of something that can coerce into ``self`` @@ -493,7 +493,7 @@ def _from_dict(self, d, coerce=False, remove_zeros=True): sage: L = lie_algebras.Heisenberg(QQ, oo) sage: d = {'p1': 4, 'q3': 1/2, 'z': -2} sage: L._from_dict(d) - -2*z + 4*p1 + 1/2*q3 + 4*p1 + 1/2*q3 - 2*z """ assert isinstance(d, dict) if coerce: diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index 78e82b40a50..dc85c55f1ec 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -267,9 +267,13 @@ def _acted_upon_(self, scalar, self_on_left=False): sage: L. = LieAlgebra(associative=R) sage: 3*x 3*x - sage: x / 2 + sage: parent(3*x) == parent(x) # this is broken + False + sage: x / 2 # not tested -- :trac:`18221` 1/2*x - sage: y * 1/2 + sage: y * (1/2) + 1/2*y + sage: y * 1/2 # not tested -- :trac:`18221` 1/2*y """ # This was copied and IDK if it still applies (TCS): diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 51884e4c0f3..08de20b3068 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -240,14 +240,14 @@ def bracket_on_basis(self, x, y): return val return -val - def free_module(self, sparse=True): + def module(self, sparse=True): """ Return ``self`` as a free module. EXAMPLES:: sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}}) - sage: L.free_module() + sage: L.module() Sparse vector space of dimension 3 over Rational Field """ return FreeModule(self.base_ring(), self.dimension(), sparse=sparse) @@ -279,7 +279,7 @@ def to_vector(self): sage: a.to_vector() (1, 3, -1/2) """ - V = self.parent().free_module() + V = self.parent().module() return V([self[k] for k in self.parent()._ordered_indices]) class AbelianLieAlgebra(LieAlgebraWithStructureCoefficients): From 5bf7cf7b377985c6374e1a907f517cae62c063ea Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 16 Apr 2015 17:37:40 +0200 Subject: [PATCH 063/223] documenting LieAlgebraWithStructureCoefficients (mostly scaffolding for myself) --- src/sage/algebras/lie_algebras/lie_algebra.py | 4 +- .../lie_algebras/structure_coefficients.py | 43 ++++++++++++++++--- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index eab9a91ec72..1fac2cccf92 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -393,8 +393,8 @@ def _element_constructor_(self, x): def __getitem__(self, x): """ - If `x` is a pair `(a, b)`, return the Lie bracket `(a, b)`. Otherwise - try to return the `x`-th element of ``self``. + If `x` is a pair `(a, b)`, return the Lie bracket `[a, b]`. + Otherwise try to return the `x`-th element of ``self``. EXAMPLES:: diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 08de20b3068..3ac2a865164 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -55,9 +55,38 @@ class LieAlgebraWithStructureCoefficients(FinitelyGeneratedLieAlgebra, IndexedGe r""" A Lie algebra with a set of specified structure coefficients. - The structure coefficients are specified as a dictionary whose keys are - pairs of generators and values are dictionaries of generators mapped - to coefficients. + The structure coefficients are specified as a dictionary `d` whose + keys are pairs of basis indices, and whose values are + dictionaries which in turn are indexed by basis indices. The value + of `d` at a pair `(u, v)` of basis indices is the dictionary whose + `w`-th entry (for `w` a basis index) is the coefficient of `b_w` + in the Lie bracket `[b_u, b_v]` (where `b_x` means the basis + element with index `x`). + + INPUT: + + - ``R`` -- a ring, to be used as the base ring + + - ``s_coeff`` -- a dictionary, indexed by pairs of basis indices + (see below), and whose values are dictionaries which are + indexed by (single) basis indices and whose values are elements + of `R` + + - ``names`` -- list or tuple of strings + + - ``index_set`` -- list or tuple of hashable and comparable + elements + + OUTPUT: + + A Lie algebra over ``R`` which (as an `R`-module) is free with + a basis indexed by the elements of ``index_set``. The `i`-th + basis element is displayed using the name ``names[i]``. + If we let `b_i` denote this `i`-th basis element, then the Lie + bracket is given by the requirement that the `b_k`-coefficient + of `[b_i, b_j]` is ``s_coeff[(i, j)][k]`` if + ``s_coeff[(i, j)]`` exists, otherwise ``-s_coeff[(j, i)][k]`` + if ``s_coeff[(j, i)]`` exists, otherwise `0`. EXAMPLES: @@ -125,12 +154,16 @@ def _standardize_s_coeff(s_coeff): key = (k[1], k[0]) vals = tuple((g, -val) for g, val in v if val != 0) else: - assert k[0] < k[1], "elements {} not ordered".format(k) + if not k[0] < k[1]: + if k[0] == k[1] and not all(val = 0 for g, val in v): + raise "elements {} are equal but their bracket is not set to 0".format(k) + if not k[0] <= k[1]: + raise "elements {} are not comparable".format(k) key = tuple(k) vals = tuple((g, val) for g, val in v if val != 0) if key in sc.keys() and sorted(sc[key]) != sorted(vals): - raise ValueError("non-equal brackets") + raise ValueError("two distinct values given for one and the same bracket") if len(vals) > 0: sc[key] = vals From 4e8469da080ac7d303b74a8c697c6687b28e4dc3 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 16 Apr 2015 17:54:54 +0200 Subject: [PATCH 064/223] fixing own bugs, and heeding pyflakes --- src/sage/algebras/lie_algebras/examples.py | 2 +- src/sage/algebras/lie_algebras/heisenberg.py | 13 +++-- src/sage/algebras/lie_algebras/lie_algebra.py | 23 +++++---- .../lie_algebras/lie_algebra_element.py | 12 ++--- .../lie_algebras/structure_coefficients.py | 50 ++++++++++--------- src/sage/categories/examples/lie_algebras.py | 2 +- .../examples/lie_algebras_with_basis.py | 2 +- .../categories/lie_algebras_with_basis.py | 2 +- 8 files changed, 54 insertions(+), 52 deletions(-) diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index 49088424722..1d0a3e62736 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -27,7 +27,7 @@ #****************************************************************************** #from sage.algebras.lie_algebras.classical_lie_algebra import gl, sl, so, sp -from sage.algebras.lie_algebras.virasoro import VirasoroAlgebra +from sage.algebras.lie_algebras.virasoro import VirasoroAlgebra # this is used, just not in this file def three_dimensional(R, a, b, c, d, names=['X', 'Y', 'Z']): r""" diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index dd2b9fc8c65..f98f2a2a6df 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -21,25 +21,24 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method -from sage.misc.misc import repr_lincomb +#from sage.misc.misc import repr_lincomb from sage.structure.indexed_generators import IndexedGenerators -from sage.algebras.algebra import Algebra +#from sage.algebras.algebra import Algebra from sage.algebras.lie_algebras.lie_algebra import (InfinitelyGeneratedLieAlgebra, LieAlgebraFromAssociative, FinitelyGeneratedLieAlgebra) -from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement +#from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement from sage.categories.lie_algebras import LieAlgebras from sage.combinat.cartesian_product import CartesianProduct from sage.matrix.matrix_space import MatrixSpace -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.infinity import infinity +#from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +#from sage.rings.infinity import infinity from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family from sage.sets.positive_integers import PositiveIntegers from sage.sets.set import Set -from sage.rings.all import ZZ +#from sage.rings.all import ZZ class HeisenbergAlgebra_abstract(IndexedGenerators): """ diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 1fac2cccf92..3de2e2d0551 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -21,19 +21,20 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from copy import copy +#from copy import copy from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute -from sage.structure.indexed_generators import IndexedGenerators +#from sage.structure.indexed_generators import IndexedGenerators from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.element_wrapper import ElementWrapper +#from sage.structure.element_wrapper import ElementWrapper from sage.categories.algebras import Algebras from sage.categories.lie_algebras import LieAlgebras, LiftMorphism from sage.categories.rings import Rings -from sage.categories.morphism import Morphism, SetMorphism -from sage.categories.map import Map +#from sage.categories.morphism import Morphism +from sage.categories.morphism import SetMorphism +#from sage.categories.map import Map from sage.categories.homset import Hom from sage.algebras.free_algebra import FreeAlgebra, is_FreeAlgebra @@ -41,14 +42,14 @@ LieAlgebraElementWrapper) from sage.rings.all import ZZ from sage.rings.ring import Ring -from sage.rings.integer import Integer -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +#from sage.rings.integer import Integer +#from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.infinity import infinity from sage.matrix.matrix_space import MatrixSpace -from sage.matrix.constructor import matrix -from sage.modules.free_module_element import vector -from sage.modules.free_module import FreeModule, span -from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract +#from sage.matrix.constructor import matrix +#from sage.modules.free_module_element import vector +#from sage.modules.free_module import FreeModule, span +#from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract from sage.sets.family import Family, AbstractFamily from sage.sets.finite_enumerated_set import FiniteEnumeratedSet diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index dc85c55f1ec..c0311ebbcb9 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -21,13 +21,13 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.abstract_method import abstract_method -from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall -from sage.misc.misc import repr_lincomb +#from sage.misc.abstract_method import abstract_method +#from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall +#from sage.misc.misc import repr_lincomb from copy import copy -from functools import total_ordering -from sage.structure.element import ModuleElement, RingElement, coerce_binop -from sage.structure.sage_object import SageObject +#from functools import total_ordering +#from sage.structure.element import ModuleElement, RingElement, coerce_binop +#from sage.structure.sage_object import SageObject from sage.combinat.free_module import CombinatorialFreeModuleElement from sage.structure.element_wrapper import ElementWrapper diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 3ac2a865164..cfa103ae8bf 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -21,35 +21,34 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from copy import copy -from sage.misc.cachefunc import cached_method -from sage.misc.lazy_attribute import lazy_attribute -from sage.misc.misc import repr_lincomb +#from copy import copy +#from sage.misc.cachefunc import cached_method +#from sage.misc.lazy_attribute import lazy_attribute +#from sage.misc.misc import repr_lincomb from sage.structure.indexed_generators import IndexedGenerators -from sage.structure.parent import Parent -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.element_wrapper import ElementWrapper +#from sage.structure.parent import Parent +#from sage.structure.unique_representation import UniqueRepresentation +#from sage.structure.element_wrapper import ElementWrapper -from sage.categories.algebras import Algebras +#from sage.categories.algebras import Algebras from sage.categories.lie_algebras import LieAlgebras -from sage.categories.finite_dimensional_lie_algebras_with_basis import FiniteDimensionalLieAlgebrasWithBasis -from sage.algebras.free_algebra import FreeAlgebra +#from sage.algebras.free_algebra import FreeAlgebra from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement from sage.algebras.lie_algebras.lie_algebra import LieAlgebra, FinitelyGeneratedLieAlgebra #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra #from sage.algebras.lie_algebras.ideal import LieAlgebraIdeal #from sage.algebras.lie_algebras.quotient import QuotientLieAlgebra -from sage.rings.all import ZZ -from sage.rings.ring import Ring -from sage.rings.integer import Integer +#from sage.rings.all import ZZ +#from sage.rings.ring import Ring +#from sage.rings.integer import Integer from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.infinity import infinity -from sage.matrix.matrix_space import MatrixSpace -from sage.matrix.constructor import matrix -from sage.modules.free_module_element import vector -from sage.modules.free_module import FreeModule, span -from sage.sets.family import Family, AbstractFamily +#from sage.rings.infinity import infinity +#from sage.matrix.matrix_space import MatrixSpace +#from sage.matrix.constructor import matrix +#from sage.modules.free_module_element import vector +from sage.modules.free_module import FreeModule #, span +from sage.sets.family import Family #, AbstractFamily class LieAlgebraWithStructureCoefficients(FinitelyGeneratedLieAlgebra, IndexedGenerators): r""" @@ -127,8 +126,9 @@ def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, **kwds): @staticmethod def _standardize_s_coeff(s_coeff): """ - Helper function to standardize ``s_coeff`` into the appropriate tuple - of tuples. Strips items with coefficients of 0 and duplicate entries. + Helper function to standardize ``s_coeff`` into the appropriate form + (dictionary indexed by pairs, whose values are dictionaries). + Strips items with coefficients of 0 and duplicate entries. This does not check the Jacobi relation (nor antisymmetry if the cardinality is infinite). @@ -155,10 +155,12 @@ def _standardize_s_coeff(s_coeff): vals = tuple((g, -val) for g, val in v if val != 0) else: if not k[0] < k[1]: - if k[0] == k[1] and not all(val = 0 for g, val in v): - raise "elements {} are equal but their bracket is not set to 0".format(k) + if k[0] == k[1]: + if not all(val == 0 for g, val in v): + raise ValueError("elements {} are equal but their bracket is not set to 0".format(k)) + continue if not k[0] <= k[1]: - raise "elements {} are not comparable".format(k) + raise ValueError("elements {} are not comparable".format(k)) key = tuple(k) vals = tuple((g, val) for g, val in v if val != 0) diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py index eddbb400294..e1503583496 100644 --- a/src/sage/categories/examples/lie_algebras.py +++ b/src/sage/categories/examples/lie_algebras.py @@ -8,7 +8,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.cachefunc import cached_method +#from sage.misc.cachefunc import cached_method from sage.sets.family import Family from sage.categories.all import LieAlgebras from sage.structure.parent import Parent diff --git a/src/sage/categories/examples/lie_algebras_with_basis.py b/src/sage/categories/examples/lie_algebras_with_basis.py index 55737b473a1..e35e5efc062 100644 --- a/src/sage/categories/examples/lie_algebras_with_basis.py +++ b/src/sage/categories/examples/lie_algebras_with_basis.py @@ -8,7 +8,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.cachefunc import cached_method +#from sage.misc.cachefunc import cached_method from sage.sets.family import Family from sage.categories.lie_algebras import LieAlgebras from sage.categories.algebras import Algebras diff --git a/src/sage/categories/lie_algebras_with_basis.py b/src/sage/categories/lie_algebras_with_basis.py index e87b0060aba..f0199419301 100644 --- a/src/sage/categories/lie_algebras_with_basis.py +++ b/src/sage/categories/lie_algebras_with_basis.py @@ -13,7 +13,7 @@ #****************************************************************************** from sage.misc.abstract_method import abstract_method -from sage.misc.cachefunc import cached_method +#from sage.misc.cachefunc import cached_method from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.lie_algebras import LieAlgebras From 878ab1d0ed5dc2b0e27f1257caccb3747009bfb1 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 16 Apr 2015 18:17:43 +0200 Subject: [PATCH 065/223] make generators work correctly for rank0 Heisenberg algebra --- src/sage/algebras/lie_algebras/heisenberg.py | 17 ++++++++++++----- .../lie_algebras/lie_algebra_element.py | 6 +++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index f98f2a2a6df..ab3b89da8bf 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -169,7 +169,8 @@ def gens(self): """ L = [self.p(i) for i in range(1, self._n+1)] L += [self.q(i) for i in range(1, self._n+1)] - #L += [self.z()] + if self._n == 0: + L += [self.z()] return tuple(L) def gen(self, i): @@ -189,18 +190,22 @@ def gen(self, i): @cached_method def lie_algebra_generators(self): """ - Return the algebra generators of ``self``. + Return the Lie algebra generators of ``self``. EXAMPLES:: sage: H = lie_algebras.Heisenberg(QQ, 1) sage: H.lie_algebra_generators() - Finite family {'q1': q1, 'p1': p1} + Finite family {'q1': q1, 'p1': p1, 'z': z} + sage: H = lie_algebras.Heisenberg(QQ, 0) + sage: H.lie_algebra_generators() + Finite family {'z': z} """ d = {} for i in range(1, self._n+1): d['p%s'%i] = self.p(i) d['q%s'%i] = self.q(i) + d['z'] = self.z() return Family(self._indices, lambda i: d[i]) @cached_method @@ -219,7 +224,7 @@ def basis(self): d['p%s'%i] = self.p(i) d['q%s'%i] = self.q(i) d['z'] = self.z() - return Family(self._indices + ('z',), lambda i: d[i]) + return Family(self._indices, lambda i: d[i]) class HeisenbergAlgebra(HeisenbergAlgebra_fd, HeisenbergAlgebra_abstract, FinitelyGeneratedLieAlgebra): @@ -261,9 +266,11 @@ def __init__(self, R, n): sage: L = lie_algebras.Heisenberg(QQ, 2) sage: TestSuite(L).run() + sage: L = lie_algebras.Heisenberg(QQ, 0) # not tested -- :trac:`18224` + sage: TestSuite(L).run() """ HeisenbergAlgebra_fd.__init__(self, n) - names = ['p%s'%i for i in range(1,n+1)] + ['q%s'%i for i in range(1,n+1)] #+ ['z'] + names = ['p%s'%i for i in range(1,n+1)] + ['q%s'%i for i in range(1,n+1)] + ['z'] names = tuple(names) FinitelyGeneratedLieAlgebra.__init__(self, R, names=names, index_set=names, category=LieAlgebras(R).FiniteDimensional().WithBasis()) diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index c0311ebbcb9..2116eb9bc3d 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -249,9 +249,9 @@ def __div__(self, x, self_on_left=False ): sage: L = lie_algebras.Heisenberg(QQ, 3) sage: x = L.an_element(); x - p1 + p2 + p3 + q1 + q2 + q3 + p1 + p2 + p3 + q1 + q2 + q3 + z sage: x / 2 - 1/2*p1 + 1/2*p2 + 1/2*p3 + 1/2*q1 + 1/2*q2 + 1/2*q3 + 1/2*p1 + 1/2*p2 + 1/2*p3 + 1/2*q1 + 1/2*q2 + 1/2*q3 + 1/2*z """ if self_on_left: return self * (~x) @@ -267,7 +267,7 @@ def _acted_upon_(self, scalar, self_on_left=False): sage: L. = LieAlgebra(associative=R) sage: 3*x 3*x - sage: parent(3*x) == parent(x) # this is broken + sage: parent(3*x) == parent(x) # this is broken in this particular ticket False sage: x / 2 # not tested -- :trac:`18221` 1/2*x From 6f6c529b753631bde338b7225968619e193db794 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 16 Apr 2015 18:48:10 +0200 Subject: [PATCH 066/223] p-Witt algebras, so that we have a characteristic-p example --- src/sage/algebras/lie_algebras/examples.py | 17 +++ src/sage/algebras/lie_algebras/virasoro.py | 117 ++++++++++++++++++++- 2 files changed, 132 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index 1d0a3e62736..951540b15c6 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -60,6 +60,11 @@ def three_dimensional(R, a, b, c, d, names=['X', 'Y', 'Z']): Finite family {('Y', 'Z'): X} sage: lie_algebras.three_dimensional(QQ, 0, 0, 0, 0) Abelian Lie algebra on 3 generators (X, Y, Z) over Rational Field + sage: Q. = PolynomialRing(QQ) + sage: L = lie_algebras.three_dimensional(Q, a, b, c, d) + sage: L.structure_coefficients() + Finite family {('X', 'Y'): d*Y + a*Z, ('X', 'Z'): (-c)*Y + (-d)*Z, ('Y', 'Z'): b*X} + sage: TestSuite(L).run() """ if isinstance(names, str): names = names.split(',') @@ -286,6 +291,18 @@ def regular_vector_fields(R): from sage.algebras.lie_algebras.virasoro import LieAlgebraRegularVectorFields return LieAlgebraRegularVectorFields(R) +def pwitt(R, p): + r""" + Return the `p`-Witt Lie algebra over `R`. + + EXAMPLES:: + + sage: lie_algebras.pwitt(GF(5), 5) + The 5-Witt Lie algebra over Finite Field of size 5 + """ + from sage.algebras.lie_algebras.virasoro import WittLieAlgebra_charp + return WittLieAlgebra_charp(R, p) + def upper_triangluar_matrices(R, n): r""" Return the Lie algebra `\mathfrak{b}_k` of strictly `k \times k` upper diff --git a/src/sage/algebras/lie_algebras/virasoro.py b/src/sage/algebras/lie_algebras/virasoro.py index f3237e44114..c0744e741a7 100644 --- a/src/sage/algebras/lie_algebras/virasoro.py +++ b/src/sage/algebras/lie_algebras/virasoro.py @@ -29,11 +29,11 @@ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.structure.indexed_generators import IndexedGenerators #from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement -from sage.algebras.lie_algebras.lie_algebra import InfinitelyGeneratedLieAlgebra +from sage.algebras.lie_algebras.lie_algebra import InfinitelyGeneratedLieAlgebra, FinitelyGeneratedLieAlgebra class LieAlgebraRegularVectorFields(InfinitelyGeneratedLieAlgebra, IndexedGenerators): r""" - The Lie algebra of regular vector fields on `C^{\times}`. + The Lie algebra of regular vector fields on `\CC^{\times}`. This is the Lie algebra generated by `\{d_i\}_{i \in \ZZ}` and subject to the relations @@ -47,6 +47,10 @@ class LieAlgebraRegularVectorFields(InfinitelyGeneratedLieAlgebra, IndexedGenera REFERENCES: - :wikipedia:`Witt_algebra` + + .. SEEALSO:: + + :class:`WittLieAlgebra_charp` """ def __init__(self, R): """ @@ -129,6 +133,115 @@ def some_elements(self): """ return [self.monomial(0), self.monomial(2), self.monomial(-2), self.an_element()] +class WittLieAlgebra_charp(FinitelyGeneratedLieAlgebra, IndexedGenerators): + r""" + The `p`-Witt Lie algebra over a ring `R` in which + `p \cdot 1_R = 0`. + + Let `R` be a ring and `p` be a positive integer such that + `p \cdot 1_R = 0`. The `p`-Witt Lie algebra over `R` is + the Lie algebra with basis `\{d_0, d_1, \ldots, d_{p-1}\}` + and subject to the relations + + .. MATH:: + + [d_i, d_j] = (j - i) d_{i+j}, + + where the `i+j` on the right hand side is identified with its + remainder modulo `p`. + + .. SEEALSO:: + + :class:`LieAlgebraRegularVectorFields` + """ + def __init__(self, R, p): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.pwitt(GF(5), 5); L + The 5-Witt Lie algebra over Finite Field of size 5 + sage: TestSuite(L).run() + sage: L = lie_algebras.pwitt(Zmod(6), 6) + sage: TestSuite(L).run() # not tested -- universal envelope doesn't work + sage: L._test_jacobi_identity() + """ + cat = LieAlgebras(R).FiniteDimensional().WithBasis() + FinitelyGeneratedLieAlgebra.__init__(self, R, index_set=range(p), category=cat) + IndexedGenerators.__init__(self, range(p), prefix='d', bracket='[') + self._p = p + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: lie_algebras.pwitt(Zmod(5), 5) + The 5-Witt Lie algebra over Ring of integers modulo 5 + """ + return "The {}-Witt Lie algebra over {}".format(self._p, self.base_ring()) + + # For compatibility with CombinatorialFreeModuleElement + _repr_term = IndexedGenerators._repr_generator + _latex_term = IndexedGenerators._latex_generator + + @cached_method + def lie_algebra_generators(self): + """ + Return the generators of ``self`` as a Lie algebra. + + EXAMPLES:: + + sage: L = lie_algebras.pwitt(Zmod(5), 5) + sage: L.lie_algebra_generators() + Finite family {0: d[0], 1: d[1], 2: d[2], 3: d[3], 4: d[4]} + """ + return Family(self._indices, self.monomial, name='generator map') + + def bracket_on_basis(self, i, j): + """ + Return the bracket of the basis elements indexed by ``i`` and ``j``. + + EXAMPLES:: + + sage: L = lie_algebras.pwitt(Zmod(5), 5) + sage: L.bracket_on_basis(2, 3) + d[0] + sage: L.bracket_on_basis(3, 2) + 4*d[0] + sage: L.bracket_on_basis(2, 2) + 0 + sage: L.bracket_on_basis(1, 3) + 2*d[4] + """ + return self.term((i + j) % self._p, j - i) + + def _an_element_(self): + """ + Return an element of ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.pwitt(Zmod(5), 5) + sage: L.an_element() + d[0] + 2*d[1] + d[4] + """ + return self.monomial(0) - 3*self.monomial(1 % self._p) + self.monomial((-1) % self._p) + + def some_elements(self): + """ + Return some elements of ``self``. + + EXAMPLES:: + + sage: L = lie_algebras.pwitt(Zmod(5), 5) + sage: L.some_elements() + [d[0], d[2], d[3], d[0] + 2*d[1] + d[4]] + """ + return [self.monomial(0), self.monomial(2 % self._p), self.monomial((-2) % self._p), self.an_element()] + class VirasoroAlgebra(InfinitelyGeneratedLieAlgebra, IndexedGenerators): r""" The Virasoro algebra. From 052721a72568247cafc5abff310ad3478f999961 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 16 Apr 2015 20:55:42 +0200 Subject: [PATCH 067/223] I don't know why (and in what sense) three_dimensional covers "all 3-dim Lie algebras", so I weakened that claim. (Maybe it does over fields, but I somehow doubt that it works in general.) Also, corrected a bordercase failure for empty gens. --- src/sage/algebras/lie_algebras/examples.py | 45 ++++++++++++++++--- src/sage/algebras/lie_algebras/lie_algebra.py | 8 +++- .../lie_algebras/lie_algebra_element.py | 16 +++++++ 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index 951540b15c6..ac019e65973 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -3,9 +3,10 @@ There are the following examples of Lie algebras: -- All 3-dimensional Lie algebras +- A rather comprehensive family of 3-dimensional Lie + algebras - The Lie algebra of affine transformations of the line -- All abelian Lie algebras +- All abelian Lie algebras on free modules - The Lie algebra of upper triangular matrices - The Lie algebra of strictly upper triangular matrices @@ -31,8 +32,8 @@ def three_dimensional(R, a, b, c, d, names=['X', 'Y', 'Z']): r""" - The 3 dimensional Lie algebra over a given commutative ring `R` - generated by `X, Y, Z` subject to the relations: + The 3-dimensional Lie algebra over a given commutative ring `R` + with basis `\{X, Y, Z\}` subject to the relations: .. MATH:: @@ -93,7 +94,7 @@ def cross_product(R, names=['X', 'Y', 'Z']): def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): """ - Return the 3-dimensional Lie algebra of rank ``n``. + Return a 3-dimensional Lie algebra of rank ``n``, where `0 \leq n \leq 3`. INPUT: @@ -308,10 +309,25 @@ def upper_triangluar_matrices(R, n): Return the Lie algebra `\mathfrak{b}_k` of strictly `k \times k` upper triangular matrices. + .. TODO:: + + This implementation does not know it is finite-dimensional and + does not know its basis. + EXAMPLES:: - sage: lie_algebras.upper_triangluar_matrices(QQ, 4) + sage: L = lie_algebras.upper_triangluar_matrices(QQ, 4); L Lie algebra of 4-dimensional upper triangular matrices over Rational Field + sage: TestSuite(L).run() + + TESTS:: + + sage: L = lie_algebras.upper_triangluar_matrices(QQ, 1); L + Lie algebra of 1-dimensional upper triangular matrices over Rational Field + sage: TestSuite(L).run() + sage: L = lie_algebras.upper_triangluar_matrices(QQ, 0); L + Lie algebra of 0-dimensional upper triangular matrices over Rational Field + sage: TestSuite(L).run() """ from sage.matrix.matrix_space import MatrixSpace from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative @@ -330,10 +346,25 @@ def strictly_upper_triangular_matrices(R, n): Return the Lie algebra `\mathfrak{n}_k` of strictly `k \times k` upper triangular matrices. + .. TODO:: + + This implementation does not know it is finite-dimensional and + does not know its basis. + EXAMPLES:: - sage: lie_algebras.strictly_upper_triangular_matrices(QQ, 4) + sage: L = lie_algebras.strictly_upper_triangular_matrices(QQ, 4); L Lie algebra of 4-dimensional strictly upper triangular matrices over Rational Field + sage: TestSuite(L).run() + + TESTS:: + + sage: L = lie_algebras.strictly_upper_triangular_matrices(QQ, 1); L + Lie algebra of 1-dimensional strictly upper triangular matrices over Rational Field + sage: TestSuite(L).run() + sage: L = lie_algebras.strictly_upper_triangular_matrices(QQ, 0); L + Lie algebra of 0-dimensional strictly upper triangular matrices over Rational Field + sage: TestSuite(L).run() """ from sage.matrix.matrix_space import MatrixSpace from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 3de2e2d0551..8db62f18b5f 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -790,6 +790,12 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): sage: L = LieAlgebra(associative=[a,b], names='x,y') sage: L.universal_enveloping_algebra() is R True + + TESTS:: + + sage: from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative as LAFA + sage: LAFA(MatrixSpace(QQ, 0, sparse=True), [], names=()) + Lie algebra generated by () in Full MatrixSpace of 0 by 0 sparse matrices over Rational Field """ @staticmethod def __classcall_private__(cls, A, gens=None, names=None, index_set=None): @@ -861,7 +867,7 @@ def __classcall_private__(cls, A, gens=None, names=None, index_set=None): elif isinstance(gens, dict): is_fg = True gens = gens.values() - elif gens: # Assume it is list-like + elif gens is not None: # Assume it is list-like is_fg = True gens = tuple(gens) diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index 2116eb9bc3d..3f5e8c7fd5e 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -167,6 +167,22 @@ def __eq__(self, rhs): return self.value == 0 and rhs == 0 return self.parent() == rhs.parent() and self.value == rhs.value + def __ne__(self, rhs): + """ + Check non-equality. + + EXAMPLES:: + + 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.zero() == 0 + True + sage: L.zero() != 0 + False + """ + return not (self == rhs) + def _repr_(self): """ Return a string representation of ``self``. From 4dd721a971b8606497cc046cf19e2706666cdf37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 16 Apr 2015 21:27:34 +0200 Subject: [PATCH 068/223] trac #16820 fixing doc inclusion once again (no .py) --- src/doc/en/reference/algebras/lie_algebras.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/en/reference/algebras/lie_algebras.rst b/src/doc/en/reference/algebras/lie_algebras.rst index 23a49b8f498..19b56d3fc9b 100644 --- a/src/doc/en/reference/algebras/lie_algebras.rst +++ b/src/doc/en/reference/algebras/lie_algebras.rst @@ -4,10 +4,10 @@ Lie Algebras .. toctree:: :maxdepth: 2 - sage/algebras/lie_algebras/examples.py - sage/algebras/lie_algebras/heisenberg.py - sage/algebras/lie_algebras/lie_algebra.py - sage/algebras/lie_algebras/lie_algebra_element.py - sage/algebras/lie_algebras/structure_coefficients.py - sage/algebras/lie_algebras/virasoro.py + sage/algebras/lie_algebras/examples. + sage/algebras/lie_algebras/heisenberg + sage/algebras/lie_algebras/lie_algebra + sage/algebras/lie_algebras/lie_algebra_element + sage/algebras/lie_algebras/structure_coefficients + sage/algebras/lie_algebras/virasoro From ee3edc49855a1dd98bca0fad32f38897c5d9a3df Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 16 Apr 2015 21:33:16 +0200 Subject: [PATCH 069/223] attempt at using from_vector in _element_constructor_; this causes weird errors I have yet to understand --- src/sage/algebras/lie_algebras/lie_algebra.py | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 8db62f18b5f..0421c9c990a 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -57,9 +57,9 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): r""" A Lie algebra `L` over a base ring `R`. - A Lie algebra is an algebra with a bilinear operation called Lie bracket - `[\cdot, \cdot] : L \times L \to L` such that `[x, x] = 0` and - the following relation holds: + A Lie algebra is an `R`-module `L` with a bilinear operation called + Lie bracket `[\cdot, \cdot] : L \times L \to L` such that + `[x, x] = 0` and the following relation holds: .. MATH:: @@ -124,7 +124,7 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): Noncommutative Multivariate Polynomial Ring in e, f, h over Rational Field, nc-relations: {f*e: e*f - h, h*f: f*h - 2*f, h*e: e*h + 2*e} - For convienence, there is are two shorthand notations for computing + For convienence, there are two shorthand notations for computing Lie backets:: sage: L([h,e]) @@ -385,6 +385,9 @@ def _element_constructor_(self, x): if isinstance(x, list) and len(x) == 2: return self(x[0])._bracket_(self(x[1])) + if hasattr(self, "module") and x in self.module(): + return self.from_vector(x) + if x in self.base_ring(): if x != 0: raise ValueError("can only convert the scalar 0 into a Lie algebra element") @@ -990,7 +993,7 @@ def _element_constructor_(self, x): def associative_algebra(self): """ - Construct the associative algebra used to construct ``self``. + Return the associative algebra used to construct ``self``. EXAMPLES:: @@ -1131,6 +1134,13 @@ def lift(self): """ Lift ``self`` to the universal enveloping algebra. + .. TODO:: + + Something seems off about this method. The universal + enveloping algebra of ``self`` does not have to be + the algebra from which ``self`` was constructed; it + is usually larger. + EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x,y,z') From eb81ce8a62555f2157475b4190190feaaaa86e6a Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 16 Apr 2015 21:42:47 +0200 Subject: [PATCH 070/223] document brokenness --- .../algebras/lie_algebras/lie_algebra_element.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index 3f5e8c7fd5e..2eea659bcb3 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -157,6 +157,12 @@ def __eq__(self, rhs): """ Check equality. + .. TODO:: + + The doctest is not legit, as the elements it acts on are not + instances of LieAlgebraElementWrapper. It should be moved + somewhere and we need a real test. + EXAMPLES:: sage: L = lie_algebras.three_dimensional_by_rank(QQ, 3) @@ -171,6 +177,16 @@ def __ne__(self, rhs): """ Check non-equality. + .. TODO:: + + The doctest is not legit, as the elements it acts on are not + instances of LieAlgebraElementWrapper. It should be moved + somewhere and we need a real test. + + .. TODO:: + + The doctest fails, although not on this class's fault. + EXAMPLES:: sage: L = lie_algebras.three_dimensional_by_rank(QQ, 3) From e37e0c7b2dfb12a073fa030fb18d384a4bce7b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 16 Apr 2015 21:43:14 +0200 Subject: [PATCH 071/223] trac #16820 oops, forgot one dot --- src/doc/en/reference/algebras/lie_algebras.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/en/reference/algebras/lie_algebras.rst b/src/doc/en/reference/algebras/lie_algebras.rst index 19b56d3fc9b..7e1276edc8e 100644 --- a/src/doc/en/reference/algebras/lie_algebras.rst +++ b/src/doc/en/reference/algebras/lie_algebras.rst @@ -4,7 +4,7 @@ Lie Algebras .. toctree:: :maxdepth: 2 - sage/algebras/lie_algebras/examples. + sage/algebras/lie_algebras/examples sage/algebras/lie_algebras/heisenberg sage/algebras/lie_algebras/lie_algebra sage/algebras/lie_algebras/lie_algebra_element From 8c5361b202dd68b31be6eb414b437badceb3fa76 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 16 Apr 2015 21:51:03 +0200 Subject: [PATCH 072/223] meanwhile, fix _acted_upon_ bug --- src/sage/algebras/lie_algebras/lie_algebra_element.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index 2eea659bcb3..dffa3d1c616 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -69,6 +69,8 @@ def __mul__(self, y): """ if self == 0 or y == 0: return self.parent().zero() + if y in self.base_ring(): + return y * self # Otherwise we lift to the UEA return self.lift() * y @@ -299,8 +301,8 @@ def _acted_upon_(self, scalar, self_on_left=False): sage: L. = LieAlgebra(associative=R) sage: 3*x 3*x - sage: parent(3*x) == parent(x) # this is broken in this particular ticket - False + sage: parent(3*x) == parent(x) + True sage: x / 2 # not tested -- :trac:`18221` 1/2*x sage: y * (1/2) From 021ed1e344f8a30bc08407ac9069cb950429ff6d Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 16 Apr 2015 21:59:59 +0200 Subject: [PATCH 073/223] more tests --- .../lie_algebras/lie_algebra_element.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index dffa3d1c616..91181020286 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -170,6 +170,10 @@ def __eq__(self, rhs): 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 """ if not isinstance(rhs, LieAlgebraElementWrapper): return self.value == 0 and rhs == 0 @@ -198,6 +202,14 @@ def __ne__(self, rhs): True sage: L.zero() != 0 False + + 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 """ return not (self == rhs) @@ -309,6 +321,13 @@ def _acted_upon_(self, scalar, self_on_left=False): 1/2*y sage: y * 1/2 # not tested -- :trac:`18221` 1/2*y + + .. TODO:: + + Do we want to fix this? + + sage: parent(x*(1/3)) + Free Algebra on 3 generators (x, y, z) over Rational Field """ # This was copied and IDK if it still applies (TCS): # With the current design, the coercion model does not have From c1838221b369f47e407ffcd95fd53bd4f239e21d Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 16 Apr 2015 22:22:29 +0200 Subject: [PATCH 074/223] all doctests pass again :) --- src/sage/algebras/lie_algebras/lie_algebra.py | 7 +++++-- .../algebras/lie_algebras/lie_algebra_element.py | 12 ++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 0421c9c990a..60d9803661d 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -385,8 +385,11 @@ def _element_constructor_(self, x): if isinstance(x, list) and len(x) == 2: return self(x[0])._bracket_(self(x[1])) - if hasattr(self, "module") and x in self.module(): - return self.from_vector(x) + try: + if x in self.module(): + return self.from_vector(x) + except AttributeError: + pass if x in self.base_ring(): if x != 0: diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index 91181020286..8947aab9bf3 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -167,6 +167,10 @@ def __eq__(self, rhs): EXAMPLES:: + 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 + 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 @@ -195,6 +199,14 @@ def __ne__(self, rhs): EXAMPLES:: + 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 + 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 From c75e37bbdc5a9208f04bd4b09a1f049aacf0bb32 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 17 Apr 2015 00:09:22 +0200 Subject: [PATCH 075/223] with trac 18221 merged in, some stopgaps removed --- src/sage/algebras/lie_algebras/lie_algebra_element.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index 8947aab9bf3..039e019ed3b 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -327,11 +327,15 @@ def _acted_upon_(self, scalar, self_on_left=False): 3*x sage: parent(3*x) == parent(x) True - sage: x / 2 # not tested -- :trac:`18221` + sage: x / 2 1/2*x sage: y * (1/2) 1/2*y - sage: y * 1/2 # not tested -- :trac:`18221` + sage: y * 1/2 + 1/2*y + sage: 1/2 * y + 1/2*y + sage: QQ(1/2) * y 1/2*y .. TODO:: From 3032fc09f15c90b61a3cf9b146e90b000c15fa4c Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 17 Apr 2015 00:17:25 +0200 Subject: [PATCH 076/223] product of Lie algebra elements with base ring elements now doesn't lift into the universal envelope --- .../lie_algebras/lie_algebra_element.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index 039e019ed3b..35261d1c6c1 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -293,9 +293,19 @@ def __mul__(self, x): sage: L. = LieAlgebra(associative=S.gens()) sage: x*y - y*x (2,3) - (1,3) + 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 """ if self.value == 0 or x == 0: return self.parent().zero() + if x in self.base_ring(): + return x * self # Otherwise we lift to the UEA return self.lift() * x @@ -337,13 +347,6 @@ def _acted_upon_(self, scalar, self_on_left=False): 1/2*y sage: QQ(1/2) * y 1/2*y - - .. TODO:: - - Do we want to fix this? - - sage: parent(x*(1/3)) - Free Algebra on 3 generators (x, y, z) over Rational Field """ # This was copied and IDK if it still applies (TCS): # With the current design, the coercion model does not have From bf2eb372d2135972a1e646d1120772da33dc8013 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 17 Apr 2015 00:41:29 +0200 Subject: [PATCH 077/223] same optimization as in trac 17098, plus getting rid of todos --- src/sage/algebras/lie_algebras/lie_algebra.py | 10 +++++---- .../lie_algebras/lie_algebra_element.py | 22 +++++-------------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 60d9803661d..bfbdab41d6e 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -155,7 +155,8 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): Free Algebra on 3 generators (a, b, c) over Rational Field We currently (:trac:`16823`) have the free Lie algebra given in the - polynomial representation, which is the Lie algebra of the Free algebra. + polynomial representation, which is the Lie subalgebra of the Free + algebra generated by the degree-`1` component. So the generators of the free Lie algebra are the generators of the free algebra and the Lie bracket is the commutator:: @@ -167,7 +168,8 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): .. [deGraaf] Willem A. de Graaf. *Lie Algebras: Theory and Algorithms*. North-Holland Mathemtaical Library. (2000). Elsevier Science B.V. - - Victor Kac. *Infinite Dimensional Lie Algebras*. + - Victor G. Kac. *Infinite Dimensional Lie Algebras*. 3rd edition + 1995, Cambridge University Press. - :wikipedia:`Lie_algebra` """ @@ -505,9 +507,9 @@ def _from_dict(self, d, coerce=False, remove_zeros=True): assert isinstance(d, dict) if coerce: R = self.base_ring() - d = dict((key, R(coeff)) for key,coeff in d.iteritems()) + d = {key: R(coeff) for key,coeff in d.iteritems()} if remove_zeros: - d = dict((key, coeff) for key, coeff in d.iteritems() if coeff) + d = {key: coeff for key, coeff in d.iteritems() if coeff} return self.element_class(self, d) def monomial(self, i): diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index 35261d1c6c1..ed657e457af 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -159,18 +159,15 @@ def __eq__(self, rhs): """ Check equality. - .. TODO:: - - The doctest is not legit, as the elements it acts on are not - instances of LieAlgebraElementWrapper. It should be moved - somewhere and we need a real test. - EXAMPLES:: 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 @@ -187,16 +184,6 @@ def __ne__(self, rhs): """ Check non-equality. - .. TODO:: - - The doctest is not legit, as the elements it acts on are not - instances of LieAlgebraElementWrapper. It should be moved - somewhere and we need a real test. - - .. TODO:: - - The doctest fails, although not on this class's fault. - EXAMPLES:: sage: L = lie_algebras.sl(QQ, 2, representation='matrix') @@ -207,6 +194,9 @@ def __ne__(self, rhs): 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 From 09281457c8cf34a075be3b72ae88296a75c54d93 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 17 Apr 2015 01:30:52 +0200 Subject: [PATCH 078/223] trivial edit --- src/sage/algebras/lie_algebras/lie_algebra.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index bfbdab41d6e..16c17c047fc 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -743,7 +743,7 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): sage: L.bracket(x-y, L.bracket(x,y)) a^2*b - 2*a*b*a + a*b^2 + b*a^2 - 2*b*a*b + b^2*a - We can also use a subset of the generators to use as a generating set + We can also use a subset of the generators as a generating set of the Lie algebra:: sage: R. = FreeAlgebra(QQ, 3) @@ -991,6 +991,8 @@ def _element_constructor_(self, x): True sage: L([x, y]) (2,3) - (1,3) + sage: L(2) + 2*() """ if isinstance(x, list) and len(x) == 2: return self(x[0])._bracket_(self(x[1])) From 301ddb58fcbe191708c915f11985c37b73667922 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 22 Apr 2015 05:29:30 +0200 Subject: [PATCH 079/223] updating some doctests to recent changes in permutation groups (I guess) --- src/sage/algebras/lie_algebras/lie_algebra.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 16c17c047fc..f7a5f68bae0 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -959,12 +959,12 @@ def _repr_(self): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) sage: LieAlgebra(associative=S) - Lie algebra generated by ((2,3), (1,3), (1,2), (1,3,2), (), (1,2,3)) + Lie algebra generated by ((2,3), (1,2,3), (), (1,2), (1,3), (1,3,2)) in Group algebra of group "Symmetric group of order 3! as a permutation group" over base ring Rational Field sage: LieAlgebra(associative=S.gens()) - Lie algebra generated by ((1,2,3), (1,2)) + Lie algebra generated by ((1,2), (1,2,3)) in Group algebra of group "Symmetric group of order 3! as a permutation group" over base ring Rational Field @@ -1022,8 +1022,8 @@ def lie_algebra_generators(self): sage: S = GroupAlgebra(G, QQ) sage: L = LieAlgebra(associative=S) sage: L.lie_algebra_generators() - Finite family {(2,3): (2,3), (1,3): (1,3), (1,2,3): (1,2,3), - (): (), (1,2): (1,2), (1,3,2): (1,3,2)} + Finite family {(2,3): (2,3), (1,2): (1,2), (1,3): (1,3), + (1,2,3): (1,2,3), (1,3,2): (1,3,2), (): ()} """ return self._gens From 53aec590880cab86cac50165e3d66291f99d9241 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 24 Aug 2015 23:11:25 +0000 Subject: [PATCH 080/223] Fixed trivial doctest failure. --- src/sage/categories/lie_algebras.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index 36b9b378d23..a6cd5279b62 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -69,6 +69,7 @@ class LieAlgebras(Category_over_base_ring): running ._test_additive_associativity() . . . pass running ._test_an_element() . . . pass running ._test_antisymmetry() . . . pass + running ._test_cardinality() . . . pass running ._test_category() . . . pass running ._test_distributivity() . . . pass running ._test_elements() . . . From 7a768e82f1eb1ccacf04169f8aadcbb4505eaae8 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 24 Aug 2015 23:56:57 +0000 Subject: [PATCH 081/223] Reworking the UEA for LieAlgebraFromAssociative. --- src/sage/algebras/lie_algebras/lie_algebra.py | 64 ++++++++----------- .../lie_algebras/lie_algebra_element.py | 12 +++- 2 files changed, 34 insertions(+), 42 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index f7a5f68bae0..08467806f2c 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -151,7 +151,7 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): sage: L = LieAlgebra(QQ, 'x,y,z'); L # not tested #16823 Free Lie algebra generated by (x, y, z) over Rational Field sage: P. = LieAlgebra(QQ, representation="polynomial"); P - Lie algebra generated by (a, c, b) in + Lie algebra generated by (a, b, c) in Free Algebra on 3 generators (a, b, c) over Rational Field We currently (:trac:`16823`) have the free Lie algebra given in the @@ -168,8 +168,7 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): .. [deGraaf] Willem A. de Graaf. *Lie Algebras: Theory and Algorithms*. North-Holland Mathemtaical Library. (2000). Elsevier Science B.V. - - Victor G. Kac. *Infinite Dimensional Lie Algebras*. 3rd edition - 1995, Cambridge University Press. + - [Kac]_ - :wikipedia:`Lie_algebra` """ @@ -626,7 +625,7 @@ def gens(self): object, in some order. EXAMPLES:: - + sage: L. = LieAlgebra(QQ, abelian=True) sage: L.gens() (x, y) @@ -657,7 +656,7 @@ def _ordered_indices(self): Return the index set of the basis of ``self`` in (some) order. EXAMPLES:: - + sage: L. = LieAlgebra(QQ, abelian=True) sage: L._ordered_indices ('x', 'y') @@ -669,7 +668,7 @@ def _an_element_(self): Return an element of ``self``. EXAMPLES:: - + sage: L. = LieAlgebra(QQ, abelian=True) sage: L.an_element() x + y @@ -791,14 +790,6 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): [-6 14] [14 6] - If we use a subset of the generators to construct our Lie algebra, - the result of :meth:`universal_enveloping_algebra()` can be too large:: - - sage: R. = FreeAlgebra(QQ, 3) - sage: L = LieAlgebra(associative=[a,b], names='x,y') - sage: L.universal_enveloping_algebra() is R - True - TESTS:: sage: from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative as LAFA @@ -883,7 +874,7 @@ def __classcall_private__(cls, A, gens=None, names=None, index_set=None): if A is None: A = gens[0].parent() # Make sure all the generators have the same parent of A - gens = tuple(map(A, gens)) + gens = tuple([A(g) for g in gens]) if ngens: try: @@ -922,8 +913,10 @@ def __init__(self, A, gens, names=None, index_set=None, category=None): FinitelyGeneratedLieAlgebra.__init__(self, R, names, index_set, category) if isinstance(gens, tuple): - gens = Family({self._indices[i]: self.element_class(self, v) - for i,v in enumerate(gens)}) + # This guarantees that the generators have a specified ordering + d = {self._indices[i]: self.element_class(self, v) + for i,v in enumerate(gens)} + gens = Family(list(self._indices), lambda i: d[i]) elif gens is not None: # It is a family gens = Family(self._indices, lambda i: self.element_class(self, gens[i]), name="generator map") @@ -931,9 +924,8 @@ def __init__(self, A, gens, names=None, index_set=None, category=None): # We don't need to store the original generators because we can # get them from lifting this object's generators - # We construct the lift map to the associative algebra - self.lift = LiftMorphismFromAssociative(self, self._assoc) - self.lift.register_as_coercion() + # We construct the lift map to the ambient associative algebra + LiftMorphismToAssociative(self, self._assoc).register_as_coercion() def _repr_option(self, key): """ @@ -959,12 +951,12 @@ def _repr_(self): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) sage: LieAlgebra(associative=S) - Lie algebra generated by ((2,3), (1,2,3), (), (1,2), (1,3), (1,3,2)) + Lie algebra generated by ((), (1,2), (1,2,3), (1,3,2), (2,3), (1,3)) in Group algebra of group "Symmetric group of order 3! as a permutation group" over base ring Rational Field sage: LieAlgebra(associative=S.gens()) - Lie algebra generated by ((1,2), (1,2,3)) + Lie algebra generated by ((1,2,3), (1,2)) in Group algebra of group "Symmetric group of order 3! as a permutation group" over base ring Rational Field @@ -1062,7 +1054,7 @@ def term(self, i, c=None): @cached_method def zero(self): """ - Return `0`. + Return the element `0` in ``self``. EXAMPLES:: @@ -1137,29 +1129,23 @@ def _bracket_(self, rhs): ret = self.value * rhs.value - rhs.value * self.value return self.__class__(self.parent(), ret) - def lift(self): + def lift_associative(self): """ - Lift ``self`` to the universal enveloping algebra. - - .. TODO:: - - Something seems off about this method. The universal - enveloping algebra of ``self`` does not have to be - the algebra from which ``self`` was constructed; it - is usually larger. + Lift ``self`` to the ambient associative algebra (which + might be larger than the universal envelopting algebra). EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x,y,z') sage: L. = LieAlgebra(associative=R.gens()) - sage: x.lift() + sage: x.lift_associative() x - sage: x.lift().parent() + sage: x.lift_associative().parent() Free Algebra on 3 generators (x, y, z) over Rational Field """ return self.value -class LiftMorphismFromAssociative(LiftMorphism): +class LiftMorphismToAssociative(LiftMorphism): """ The natural lifting morphism from a Lie algebra constructed from an associative algebra `A` to `A`. @@ -1173,7 +1159,7 @@ def preimage(self, x): sage: R = FreeAlgebra(QQ, 3, 'a,b,c') sage: L = LieAlgebra(associative=R) sage: x,y,z = R.gens() - sage: f = L.lift + sage: f = R.coerce_map_from(L) sage: p = f.preimage(x*y - z); p -c + a*b sage: p.parent() is L @@ -1189,7 +1175,7 @@ def _call_(self, x): sage: R = FreeAlgebra(QQ, 3, 'x,y,z') sage: L. = LieAlgebra(associative=R) - sage: f = L.lift + sage: f = R.coerce_map_from(L) sage: a = f(L([x,y]) + z); a z + x*y - y*x sage: a.parent() is R @@ -1205,11 +1191,11 @@ def section(self): sage: R = FreeAlgebra(QQ, 3, 'x,y,z') sage: L. = LieAlgebra(associative=R) - sage: f = L.lift + sage: f = R.coerce_map_from(L) sage: f.section() Generic morphism: From: Free Algebra on 3 generators (x, y, z) over Rational Field - To: Lie algebra generated by (y, x, z) in Free Algebra on 3 generators (x, y, z) over Rational Field + To: Lie algebra generated by (x, y, z) in Free Algebra on 3 generators (x, y, z) over Rational Field """ return SetMorphism(Hom(self.codomain(), self.domain()), self.preimage) diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index ed657e457af..bf87556b759 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -268,7 +268,7 @@ def _sub_(self, rhs): """ return self.__class__(self.parent(), self.value - rhs.value) - # This seems to work with 2 underscores and I don't understand why... + # We need to bypass the coercion framework # We let the universal enveloping algebra handle the rest if both # arguments are non-zero def __mul__(self, x): @@ -276,13 +276,16 @@ def __mul__(self, x): If we are multiplying two non-zero elements, automatically lift up to the universal enveloping algebra. + .. TODO:: + + Write tests for this method once :trac:`16822` is + implemented. + EXAMPLES:: sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) sage: L. = LieAlgebra(associative=S.gens()) - sage: x*y - y*x - (2,3) - (1,3) sage: u = x*3; u 3*(1,2,3) sage: parent(u) == L @@ -291,6 +294,9 @@ def __mul__(self, x): 3/2*(1,2,3) sage: parent(u) == L True + sage: elt = x*y - y*x; elt # not tested: needs #16822 + sage: S(elt) # not tested: needs #16822 + (2,3) - (1,3) """ if self.value == 0 or x == 0: return self.parent().zero() From 2f6b1e40e53f0039e5786a9390bdad1c9d2a7217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 31 Aug 2015 17:25:10 +0200 Subject: [PATCH 082/223] trac #16820 correct syntax for input --- src/sage/categories/lie_algebras.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index a6cd5279b62..261228c8ebf 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -500,7 +500,7 @@ def _test_jacobi_identity(self, **options): Test that the Jacobi identity is satisfied on (not necessarily all) elements of this set. - INPUT:: + INPUT: - ``options`` -- any keyword arguments accepted by :meth:`_tester`. @@ -539,7 +539,7 @@ def _test_antisymmetry(self, **options): Test that the antisymmetry axiom is satisfied on (not necessarily all) elements of this set. - INPUT:: + INPUT: - ``options`` -- any keyword arguments accepted by :meth:`_tester`. @@ -571,7 +571,7 @@ def _test_distributivity(self, **options): Test the distributivity of the Lie bracket `[,]` on `+` on (not necessarily all) elements of this set. - INPUT:: + INPUT: - ``options`` -- any keyword arguments accepted by :meth:`_tester`. From 15e231797c8028a56d66eb19b067df90f2822822 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 23 Oct 2015 11:30:53 -0500 Subject: [PATCH 083/223] Fixing doctests due to output order. --- src/sage/algebras/lie_algebras/lie_algebra.py | 9 +++++++-- .../finite_dimensional_lie_algebras_with_basis.py | 6 ++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 08467806f2c..0d6aaa3adc1 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -120,9 +120,14 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): 2*e sage: elt = h*e; elt e*h + 2*e - sage: elt.parent() + sage: P = elt.parent(); P Noncommutative Multivariate Polynomial Ring in e, f, h over Rational Field, - nc-relations: {f*e: e*f - h, h*f: f*h - 2*f, h*e: e*h + 2*e} + nc-relations: {...} + sage: R = P.relations() + sage: for rhs in R: print("{} = {}".format(rhs, R[rhs])) + h*f = f*h - 2*f + f*e = e*f - h + h*e = e*h + 2*e For convienence, there are two shorthand notations for computing Lie backets:: 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 fbf48320c90..762b6d2dc4b 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -73,9 +73,11 @@ def _construct_UEA(self): :: sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) - sage: L._construct_UEA() + sage: UEA = L._construct_UEA(); UEA Noncommutative Multivariate Polynomial Ring in x, y, z over Rational Field, - nc-relations: {z*x: x*z + y, z*y: y*z - x, y*x: x*y - z} + nc-relations: {...} + sage: sorted(UEA.relations().items(), key=str) + [(y*x, x*y - z), (z*x, x*z + y), (z*y, y*z - x)] """ # Create the UEA relations # We need to get names for the basis elements, not just the generators From b38f9838d5ebfcd120587543d60333c46ad3865a Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 24 Oct 2015 03:48:22 +0200 Subject: [PATCH 084/223] documentation improvements --- src/sage/algebras/lie_algebras/lie_algebra.py | 116 +++++++++++++++--- .../lie_algebras/structure_coefficients.py | 13 ++ 2 files changed, 110 insertions(+), 19 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 0d6aaa3adc1..dcc1927e215 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -63,7 +63,7 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): .. MATH:: - \bigl[x, [y, z] \bigr] + \bigl[ y, [z, x] \bigr] + \bigl[ x, [y, z] \bigr] + \bigl[ y, [z, x] \bigr] + \bigl[ z, [x, y] \bigr] = 0. This relation is known as the *Jacobi identity* (or sometimes the Jacobi @@ -78,39 +78,117 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): thus `[x, y] = -[y, x]` and the Lie bracket is antisymmetric. Lie algebras are closely related to Lie groups. Let `G` be a Lie group - and fix some `g \in G`, we can construct the Lie algebra `L` of `G` by + and fix some `g \in G`. We can construct the Lie algebra `L` of `G` by considering the tangent space at `g`. We can also (partially) recover `G` from `L` by using what is known as the exponential map. - Given any associative algebra `A`, we can construct a Lie algebra `L` by - defining the Lie bracket to be the commutator `[a, b] = ab - ba`. We call - an associative algebra `A` which contains `L` in this fashion an - *enveloping algebra*. We can the embedding which sends the Lie bracket to - the commutator a Lie embedding. Now if we are given a Lie algebra `L`, we + Given any associative algebra `A`, we can construct a Lie algebra `L` + on the `R`-module `A` by defining the Lie bracket to be the commutator + `[a, b] = ab - ba`. We call an associative algebra `A` which contains + `L` in this fashion an *enveloping algebra* of `L`. The embedding + `L \to A` which sends the Lie bracket to the commutator will be called + a Lie embedding. Now if we are given a Lie algebra `L`, we can construct an enveloping algebra `U_L` with Lie embedding `h : L \to U_L` which has the following universal property: for any enveloping algebra `A` with Lie embedding `f : L \to A`, there exists a unique unital algebra homomorphism `g : U_L \to A` such that `f = g \circ h`. The - algebra `U_L` is known as the *universal enveloping algebra*. + algebra `U_L` is known as the *universal enveloping algebra* of `L`. EXAMPLES: - We can also create abelian Lie algebras using the ``abelian`` keyword:: + **1.** The simplest examples of Lie algebras are *abelian Lie + algebras*. These are Lie algebras whose Lie bracket is (identically) + zero. We can create them using the ``abelian`` keyword:: sage: L. = LieAlgebra(QQ, abelian=True); L Abelian Lie algebra on 3 generators (x, y, z) over Rational Field - We can also input a set of structure coefficients. For example, we want - to create the Lie algebra of `\QQ^3` under the Lie bracket of `\times` - (cross-product):: + **2.** A Lie algebra can be built from any associative algebra by + defining the Lie bracket to be the commutator. For example, we can + start with the descent algebra: + + sage: D = DescentAlgebra(QQ, 4).D() + sage: L = LieAlgebra(associative=D); L + Lie algebra generated by (D{}, D{1}, D{2}, D{3}, D{1, 2}, D{1, 3}, D{2, 3}, D{1, 2, 3}) + in Descent algebra of 4 over Rational Field in the standard basis + sage: L(D[2]).bracket(L(D[3])) + D{1, 2} - D{1, 3} + D{2} - D{3} + + Next we use a free algebra and do some simple computations:: + + sage: R. = FreeAlgebra(QQ, 3) + sage: L. = LieAlgebra(associative=R) + sage: x-y+z + a - b + c + sage: L.bracket(x-y, x-z) + a*b - a*c - b*a + b*c + c*a - c*b + sage: L.bracket(x-y, L.bracket(x,y)) + a^2*b - 2*a*b*a + a*b^2 + b*a^2 - 2*b*a*b + b^2*a + + We can also use a subset of the elements as a generating set + of the Lie algebra:: + + sage: R. = FreeAlgebra(QQ, 3) + sage: L. = LieAlgebra(associative=[a,b+c]) + sage: L.bracket(x, y) + a*b + a*c - b*a - c*a + + Now for a more complicated example using the group ring of `S_3` as our + base algebra:: + + sage: G = SymmetricGroup(3) + sage: S = GroupAlgebra(G, QQ) + sage: L. = LieAlgebra(associative=S.gens()) + sage: L.bracket(x, y) + (2,3) - (1,3) + sage: L.bracket(x, y-x) + (2,3) - (1,3) + sage: L.bracket(L.bracket(x, y), y) + 2*(1,2,3) - 2*(1,3,2) + sage: L.bracket(x, L.bracket(x, y)) + (2,3) - 2*(1,2) + (1,3) + sage: L.bracket(x, L.bracket(L.bracket(x, y), y)) + 0 + + Here is an example using matrices:: + + sage: MS = MatrixSpace(QQ,2) + sage: m1 = MS([[0, -1], [1, 0]]) + sage: m2 = MS([[-1, 4], [3, 2]]) + sage: L. = LieAlgebra(associative=[m1, m2]) + sage: x + [ 0 -1] + [ 1 0] + sage: y + [-1 4] + [ 3 2] + sage: L.bracket(x,y) + [-7 -3] + [-3 7] + sage: L.bracket(y,y) + [0 0] + [0 0] + sage: L.bracket(y,x) + [ 7 3] + [ 3 -7] + sage: L.bracket(x, L.bracket(y,x)) + [-6 14] + [14 6] + + (See :class:`LieAlgebraFromAssociative` for other examples.) + + **3.** We can also creating a Lie algebra by inputting a set of + structure coefficients. For example, we can create the Lie algebra + of `\QQ^3` under the Lie bracket `\times` (cross-product):: sage: d = {('x','y'): {'z':1}, ('y','z'): {'x':1}, ('z','x'): {'y':1}} sage: L. = LieAlgebra(QQ, d) sage: L Lie algebra on 3 generators (x, y, z) over Rational Field - To compute the Lie backet of two objects, you cannot use the ``*``. - This will automatically lift up to the universal enveloping algebra. + To compute the Lie bracket of two elements, you cannot use the ``*`` + operator. Indeed, this automatically lifts up to the universal + enveloping algebra and takes the (associative) product there. To get elements in the Lie algebra, you must use :meth:`bracket`:: sage: L = LieAlgebra(QQ, {('e','h'): {'e':-2}, ('f','h'): {'f':2}, @@ -124,13 +202,13 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): Noncommutative Multivariate Polynomial Ring in e, f, h over Rational Field, nc-relations: {...} sage: R = P.relations() - sage: for rhs in R: print("{} = {}".format(rhs, R[rhs])) - h*f = f*h - 2*f + sage: for rhs in sorted(R, key=str): print("{} = {}".format(rhs, R[rhs])) f*e = e*f - h h*e = e*h + 2*e + h*f = f*h - 2*f For convienence, there are two shorthand notations for computing - Lie backets:: + Lie brackets:: sage: L([h,e]) 2*e @@ -147,7 +225,7 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): Because this is a modified (abused) version of python syntax, it does **NOT** work with addition. For example ``L([e + [h, f], h])`` - or ``L[e + [h, f], h]`` will both raise errors. Instead you must + and ``L[e + [h, f], h]`` will both raise errors. Instead you must use ``L[e + L[h, f], h]``. Now we construct a free Lie algebra in a few different ways. There are @@ -727,7 +805,7 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): EXAMPLES: - We create a simple example with a commutative algebra as the base algebra. + For the first example, we start with a commutative algebra. Note that the bracket of everything will be 0:: sage: R. = PolynomialRing(QQ) diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index cfa103ae8bf..54da97149bf 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -98,6 +98,19 @@ class LieAlgebraWithStructureCoefficients(FinitelyGeneratedLieAlgebra, IndexedGe z sage: L.bracket(y, x) -z + + TESTS: + + We can input structure coefficients that fail the Jacobi + identity, but the test suite will call us out on it:: + + We create the Lie algebra of `\QQ^3` under the Lie bracket defined + by `\times` (cross-product):: + + sage: Fake = LieAlgebra(QQ, 'x,y,z', {('x','y'):{'z':3}, ('y','z'):{'z':1}, ('z','x'):{'y':1}}) + sage: TestSuite(Fake).run() + Failure in _test_jacobi_identity: + ... """ @staticmethod def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, **kwds): From 090d308cd47fb5dfec0acc935972af18e2164ded Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 24 Oct 2015 03:50:56 +0200 Subject: [PATCH 085/223] oops --- src/sage/algebras/lie_algebras/structure_coefficients.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 54da97149bf..b026ab5ecf0 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -104,9 +104,6 @@ class LieAlgebraWithStructureCoefficients(FinitelyGeneratedLieAlgebra, IndexedGe We can input structure coefficients that fail the Jacobi identity, but the test suite will call us out on it:: - We create the Lie algebra of `\QQ^3` under the Lie bracket defined - by `\times` (cross-product):: - sage: Fake = LieAlgebra(QQ, 'x,y,z', {('x','y'):{'z':3}, ('y','z'):{'z':1}, ('z','x'):{'y':1}}) sage: TestSuite(Fake).run() Failure in _test_jacobi_identity: From a84a4ba3f43f3925847ecfab05d9a7a3793a5e43 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 24 Oct 2015 11:24:58 -0500 Subject: [PATCH 086/223] Fixes for LieAlgebraFromAssociative. --- src/sage/algebras/free_algebra.py | 2 +- src/sage/algebras/lie_algebras/lie_algebra.py | 193 +++++++++--------- .../lie_algebras/lie_algebra_element.py | 12 +- 3 files changed, 107 insertions(+), 100 deletions(-) diff --git a/src/sage/algebras/free_algebra.py b/src/sage/algebras/free_algebra.py index c37143097a7..9483f0d9756 100644 --- a/src/sage/algebras/free_algebra.py +++ b/src/sage/algebras/free_algebra.py @@ -723,7 +723,7 @@ def algebra_generators(self): x = self.gen(i) ret[str(x)] = x from sage.sets.family import Family - return Family(ret) + return Family(self.variable_names(), lambda i: ret[i]) @cached_method def gens(self): diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index dcc1927e215..68ef3c351e3 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -109,15 +109,15 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): sage: D = DescentAlgebra(QQ, 4).D() sage: L = LieAlgebra(associative=D); L - Lie algebra generated by (D{}, D{1}, D{2}, D{3}, D{1, 2}, D{1, 3}, D{2, 3}, D{1, 2, 3}) - in Descent algebra of 4 over Rational Field in the standard basis + Lie algebra of Descent algebra of 4 over Rational Field + in the standard basis sage: L(D[2]).bracket(L(D[3])) D{1, 2} - D{1, 3} + D{2} - D{3} Next we use a free algebra and do some simple computations:: sage: R. = FreeAlgebra(QQ, 3) - sage: L. = LieAlgebra(associative=R) + sage: L. = LieAlgebra(associative=R.gens()) sage: x-y+z a - b + c sage: L.bracket(x-y, x-z) @@ -346,6 +346,10 @@ def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, # free (associative unital) algebra # TODO: Change this to accept an index set once FreeAlgebra accepts one F = FreeAlgebra(R, names) + if index_set is None: + index_set = F.variable_names() + # TODO: As part of #16823, this should instead construct a + # subclass with specialized methods for the free Lie algebra return LieAlgebraFromAssociative(F, F.gens(), names=names, index_set=index_set) raise NotImplementedError("the free Lie algebra has only been implemented using polynomials in the free algebra, see trac ticket #16823") @@ -634,6 +638,40 @@ def lie_algebra_generators(self): """ return Family(self._indices, self.monomial, name="monomial map") + @cached_method + def gens(self): + """ + Return a tuple whose entries are the generators for this + object, in some order. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, abelian=True) + sage: L.gens() + (x, y) + """ + G = self.lie_algebra_generators() + if G.cardinality() == float('inf'): + return G + try: + return tuple(G[i] for i in self.variable_names()) + except (KeyError, IndexError): + return tuple(G[i] for i in self.indices()) + except (KeyError, ValueError): + return tuple(G) + + def gen(self, i): + """ + Return the ``i``-th generator of ``self``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, abelian=True) + sage: L.gen(0) + x + """ + return tuple(self.gens())[i] + def get_order(self): """ Return an ordering of the basis indices. @@ -701,38 +739,6 @@ def _repr_(self): return "Lie algebra on {0} generators {1} over {2}".format( self.__ngens, self.gens(), self.base_ring()) - @cached_method - def gens(self): - """ - Return a tuple whose entries are the generators for this - object, in some order. - - EXAMPLES:: - - sage: L. = LieAlgebra(QQ, abelian=True) - sage: L.gens() - (x, y) - """ - G = self.lie_algebra_generators() - try: - return tuple(G[i] for i in self.variable_names()) - except (KeyError, IndexError): - return tuple(G[i] for i in self.indices()) - except (KeyError, ValueError): - return tuple(G) - - def gen(self, i): - """ - Return the ``i``-th generator of ``self``. - - EXAMPLES:: - - sage: L. = LieAlgebra(QQ, abelian=True) - sage: L.gen(0) - x - """ - return self.gens()[i] - @lazy_attribute def _ordered_indices(self): """ @@ -786,7 +792,7 @@ def dimension(self): """ return infinity -class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): +class LieAlgebraFromAssociative(LieAlgebra): """ A Lie algebra whose elements are from an associative algebra and whose bracket is the commutator. @@ -796,7 +802,7 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): Split this class into 2 classes, the base class for the Lie algebra corresponding to the full associative algebra and a subclass for the Lie subalgebra (of the full algebra) - generated by a generating set. + generated by a generating set? .. TODO:: @@ -808,16 +814,17 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): For the first example, we start with a commutative algebra. Note that the bracket of everything will be 0:: - sage: R. = PolynomialRing(QQ) + sage: R = SymmetricGroupAlgebra(QQ, 2) sage: L = LieAlgebra(associative=R) - sage: x, y = L(a), L(b) + sage: x, y = L.basis() sage: L.bracket(x, y) 0 Next we use a free algebra and do some simple computations:: sage: R. = FreeAlgebra(QQ, 2) - sage: L. = LieAlgebra(associative=R) + sage: L = LieAlgebra(associative=R) + sage: x,y = L(a), L(b) sage: x-y a - b sage: L.bracket(x-y, x) @@ -880,7 +887,8 @@ class LieAlgebraFromAssociative(FinitelyGeneratedLieAlgebra): Lie algebra generated by () in Full MatrixSpace of 0 by 0 sparse matrices over Rational Field """ @staticmethod - def __classcall_private__(cls, A, gens=None, names=None, index_set=None): + def __classcall_private__(cls, A, gens=None, names=None, index_set=None, + free_lie_algebra=False): """ Normalize input to ensure a unique representation. @@ -894,32 +902,19 @@ def __classcall_private__(cls, A, gens=None, names=None, index_set=None): True sage: F. = FreeAlgebra(QQ) - sage: L1 = LieAlgebra(associative=F) + sage: L1 = LieAlgebra(associative=F.algebra_generators(), names='x,y,z') sage: L2. = LieAlgebra(associative=F.gens()) - sage: L3. = LieAlgebra(QQ, representation="polynomial") sage: L1 is L2 True """ # If A is not a ring, then we treat it as a set of generators if isinstance(A, Parent) and A.category().is_subcategory(Rings()): - # TODO: As part of #16823, this should instead construct a - # subclass with specialized methods for the free Lie algebra - if is_FreeAlgebra(A): - if gens is None: - gens = A.gens() - if index_set is None: - index_set = A.variable_names() - elif gens is None: - # Parse possible generators (i.e., a basis) from the parent + if gens is None and index_set is None: + # Use the indexing set of the basis try: - gens = A.basis() + index_set = A.basis().keys() except (AttributeError, NotImplementedError): pass - if names is None: - try: - names = A.variable_names() - except ValueError: - pass else: gens = A A = None @@ -930,36 +925,38 @@ def __classcall_private__(cls, A, gens=None, names=None, index_set=None): index_set = gens.keys() except (AttributeError, ValueError): pass - try: - ngens = len(gens) - except (TypeError, NotImplementedError): - ngens = None - - names, index_set = LieAlgebra._standardize_names_index_set(names, index_set, ngens) - is_fg = False # Is finitely generated + ngens = None if isinstance(gens, AbstractFamily): + if index_set is None and names is None: + index_set = gens.keys() if gens.cardinality() < float('inf'): - is_fg = True + # TODO: This makes the generators of a finitely generated + # Lie algebra into an ordered list for uniqueness and then + # reconstructs the family. Instead create a key for the + # cache this way and then pass the family. try: gens = tuple([gens[i] for i in index_set]) except KeyError: gens = tuple(gens) + ngens = len(gens) elif isinstance(gens, dict): - is_fg = True + if index_set is None and names is None: + index_set = gens.keys() gens = gens.values() + ngens = len(gens) elif gens is not None: # Assume it is list-like - is_fg = True gens = tuple(gens) + ngens = len(gens) + if index_set is None and names is None: + index_set = range(ngens) - if is_fg: # If we have a finite generating set + if ngens is not None: if A is None: A = gens[0].parent() # Make sure all the generators have the same parent of A gens = tuple([A(g) for g in gens]) - - if ngens: try: # Try to make things, such as matrices, immutable # since we need to hash them @@ -968,10 +965,12 @@ def __classcall_private__(cls, A, gens=None, names=None, index_set=None): except AttributeError: pass + names, index_set = LieAlgebra._standardize_names_index_set(names, index_set, ngens) + return super(LieAlgebraFromAssociative, cls).__classcall__(cls, A, gens, names=names, index_set=index_set) - def __init__(self, A, gens, names=None, index_set=None, category=None): + def __init__(self, A, gens=None, names=None, index_set=None, category=None): """ Initialize ``self``. @@ -990,10 +989,10 @@ def __init__(self, A, gens, names=None, index_set=None, category=None): category = LieAlgebras(R).or_subcategory(category) if 'FiniteDimensional' in self._assoc.category().axioms(): category = category.FiniteDimensional() - if 'WithBasis' in self._assoc.category().axioms(): + if 'WithBasis' in self._assoc.category().axioms() and gens is None: category = category.WithBasis() - FinitelyGeneratedLieAlgebra.__init__(self, R, names, index_set, category) + LieAlgebra.__init__(self, R, names, index_set, category) if isinstance(gens, tuple): # This guarantees that the generators have a specified ordering @@ -1001,9 +1000,11 @@ def __init__(self, A, gens, names=None, index_set=None, category=None): for i,v in enumerate(gens)} gens = Family(list(self._indices), lambda i: d[i]) elif gens is not None: # It is a family - gens = Family(self._indices, lambda i: self.element_class(self, gens[i]), + gens = Family(self._indices, + lambda i: self.element_class(self, gens[i]), name="generator map") self._gens = gens + # We don't need to store the original generators because we can # get them from lifting this object's generators @@ -1034,8 +1035,7 @@ def _repr_(self): sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) sage: LieAlgebra(associative=S) - Lie algebra generated by ((), (1,2), (1,2,3), (1,3,2), (2,3), (1,3)) - in Group algebra of group + Lie algebra of Group algebra of group "Symmetric group of order 3! as a permutation group" over base ring Rational Field sage: LieAlgebra(associative=S.gens()) @@ -1054,20 +1054,19 @@ def _element_constructor_(self, x): EXAMPLES:: - sage: G = SymmetricGroup(3) - sage: S = GroupAlgebra(G, QQ) + sage: S = SymmetricGroupAlgebra(QQ, 3) sage: L = LieAlgebra(associative=S) sage: x,y = S.algebra_generators() sage: elt = L(x - y); elt - -(1,2) + (1,2,3) + [2, 1, 3] - [2, 3, 1] sage: elt.parent() is L True sage: elt == L(x) - L(y) True sage: L([x, y]) - (2,3) - (1,3) + -[1, 3, 2] + [3, 2, 1] sage: L(2) - 2*() + 2*[1, 2, 3] """ if isinstance(x, list) and len(x) == 2: return self(x[0])._bracket_(self(x[1])) @@ -1100,7 +1099,15 @@ def lie_algebra_generators(self): Finite family {(2,3): (2,3), (1,2): (1,2), (1,3): (1,3), (1,2,3): (1,2,3), (1,3,2): (1,3,2), (): ()} """ - return self._gens + if self._gens is not None: + return self._gens + try: + ngens = self._indices.cardinality() + except AttributeError: + ngens = len(self._indices) + if ngens < float('inf'): + return Family(list(self._indices), self.monomial) + return Family(self._indices, self.monomial, name="generator map") def monomial(self, i): """ @@ -1110,13 +1117,13 @@ def monomial(self, i): sage: F. = FreeAlgebra(QQ) sage: L = LieAlgebra(associative=F) - sage: L.monomial('x') + sage: L.monomial(x.leading_support()) x """ - if i not in self._indices: + if i not in self.basis().keys(): #return self(self._assoc.monomial(i)) raise ValueError("not an index") - return self._gens[i] + return self.element_class(self, self._assoc.monomial(i)) def term(self, i, c=None): """ @@ -1126,13 +1133,13 @@ def term(self, i, c=None): sage: F. = FreeAlgebra(QQ) sage: L = LieAlgebra(associative=F) - sage: L.term('x', 4) + sage: L.term(x.leading_support(), 4) 4*x """ - if i not in self._indices: + if i not in self.basis().keys(): #return self(self._assoc.term(i, c)) raise ValueError("not an index") - return c * self._gens[i] + return self.element_class(self, self._assoc.term(i, c)) @cached_method def zero(self): @@ -1156,12 +1163,12 @@ def is_abelian(self): EXAMPLES:: sage: R = FreeAlgebra(QQ, 2, 'x,y') - sage: L = LieAlgebra(associative=R) + sage: L = LieAlgebra(associative=R.gens()) sage: L.is_abelian() False sage: R = PolynomialRing(QQ, 'x,y') - sage: L = LieAlgebra(associative=R) + sage: L = LieAlgebra(associative=R.gens()) sage: L.is_abelian() True @@ -1257,7 +1264,7 @@ def _call_(self, x): EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(associative=R) + sage: L. = LieAlgebra(associative=R.gens()) sage: f = R.coerce_map_from(L) sage: a = f(L([x,y]) + z); a z + x*y - y*x @@ -1273,7 +1280,7 @@ def section(self): EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(associative=R) + sage: L. = LieAlgebra(associative=R.gens()) sage: f = R.coerce_map_from(L) sage: f.section() Generic morphism: diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index bf87556b759..e677ff662be 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -222,7 +222,7 @@ def _repr_(self): EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(associative=R) + sage: L. = LieAlgebra(associative=R.gens()) sage: x + y x + y """ @@ -235,7 +235,7 @@ def _latex_(self): EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x') - sage: L. = LieAlgebra(associative=R) + sage: L. = LieAlgebra(associative=R.gens()) sage: latex(x0 + x1) x_{0} + x_{1} """ @@ -249,7 +249,7 @@ def _add_(self, rhs): EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(associative=R) + sage: L. = LieAlgebra(associative=R.gens()) sage: x + y x + y """ @@ -262,7 +262,7 @@ def _sub_(self, rhs): EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(associative=R) + sage: L. = LieAlgebra(associative=R.gens()) sage: x - y x - y """ @@ -328,7 +328,7 @@ def _acted_upon_(self, scalar, self_on_left=False): EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(associative=R) + sage: L. = LieAlgebra(associative=R.gens()) sage: 3*x 3*x sage: parent(3*x) == parent(x) @@ -366,7 +366,7 @@ def __neg__(self): EXAMPLES:: sage: R = FreeAlgebra(QQ, 3, 'x,y,z') - sage: L. = LieAlgebra(associative=R) + sage: L. = LieAlgebra(associative=R.gens()) sage: -x -x """ From eedbb63c2964f52cb513666e67d73b56adcb1752 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 24 Oct 2015 18:26:17 +0200 Subject: [PATCH 087/223] review of examples.py --- src/sage/algebras/lie_algebras/examples.py | 50 ++++++-- src/sage/algebras/lie_algebras/heisenberg.py | 114 +++++++++++++++++- .../lie_algebras/structure_coefficients.py | 7 +- src/sage/algebras/lie_algebras/virasoro.py | 2 +- 4 files changed, 158 insertions(+), 15 deletions(-) diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index ac019e65973..272b8ecd586 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -96,11 +96,21 @@ def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): """ Return a 3-dimensional Lie algebra of rank ``n``, where `0 \leq n \leq 3`. + Here, the *rank* of a Lie algebra `L` is defined as the dimension + of its derived subalgebra `[L, L]`. (We are assuming that `R` is + a field of characteristic `0`; otherwise the Lie algebras + constructed by this function are still well-defined but no longer + might have the correct ranks.) This is not to be confused with + the other standard definition of a rank (namely, as the + dimension of a Cartan subalgebra, when `L` is semisimple). + INPUT: - ``R`` -- the base ring - ``n`` -- the rank - - ``a`` -- the deformation parameter, if 0 then returns the degenerate case + - ``a`` -- the deformation parameter (used for `n = 2`); this should + be a nonzero element of `R` in order for the resulting Lie + algebra to actually have the right rank(?) - ``names`` -- (optional) the generator names EXAMPLES:: @@ -141,10 +151,12 @@ def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients if a == 0: s_coeff = {(X,Y): {Y:R.one()}, (X,Z): {Y:R(a)}} + # Why use R(a) here if R == 0 ? Also this has rank 1. L = LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) L.rename("Degenerate Lie algebra of dimension 3 and rank 2 over {}".format(R)) else: s_coeff = {(X,Y): {Y:R.one()}, (X,Z): {Y:R.one(), Z:R.one()}} + # a doesn't appear here :/ L = LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) L.rename("Lie algebra of dimension 3 and rank 2 with parameter {} over {}".format(a, R)) return L @@ -219,6 +231,15 @@ def affine_transformations_line(R, names=['X', 'Y'], representation='bracket'): sage: L = lie_algebras.affine_transformations_line(QQ) sage: L.structure_coefficients() Finite family {('X', 'Y'): Y} + sage: X, Y = L.lie_algebra_generators() + sage: L[X, Y] == Y + True + sage: TestSuite(L).run() + sage: L = lie_algebras.affine_transformations_line(QQ, representation="matrix") + sage: X, Y = L.lie_algebra_generators() + sage: L[X, Y] == Y + True + sage: TestSuite(L).run() """ if isinstance(names, str): names = names.split(',') @@ -259,7 +280,7 @@ def Heisenberg(R, n, representation="structure"): INPUT: - ``R`` -- the base ring - - ``n`` -- the rank + - ``n`` -- the rank (a nonnegative integer or infinity) - ``representation`` -- (default: "structure") can be one of the following: - ``"structure"`` -- using structure coefficients @@ -282,7 +303,11 @@ def Heisenberg(R, n, representation="structure"): def regular_vector_fields(R): r""" - Return the Lie algebra of regular vector fields of `\CC^{\times}`. + Return the Lie algebra of regular vector fields on `\CC^{\times}`. + + .. SEEALSO:: + + :class:`~sage.algebras.lie_algebras.virasoro.LieAlgebraRegularVectorFields` EXAMPLES:: @@ -304,9 +329,9 @@ def pwitt(R, p): from sage.algebras.lie_algebras.virasoro import WittLieAlgebra_charp return WittLieAlgebra_charp(R, p) -def upper_triangluar_matrices(R, n): +def upper_triangular_matrices(R, n): r""" - Return the Lie algebra `\mathfrak{b}_k` of strictly `k \times k` upper + Return the Lie algebra `\mathfrak{b}_k` of `k \times k` upper triangular matrices. .. TODO:: @@ -316,16 +341,19 @@ def upper_triangluar_matrices(R, n): EXAMPLES:: - sage: L = lie_algebras.upper_triangluar_matrices(QQ, 4); L + sage: L = lie_algebras.upper_triangular_matrices(QQ, 4); L Lie algebra of 4-dimensional upper triangular matrices over Rational Field sage: TestSuite(L).run() + sage: n0, n1, n2, t0, t1, t2, t3 = L.lie_algebra_generators() + sage: L[n2, t2] == -n2 + True TESTS:: - sage: L = lie_algebras.upper_triangluar_matrices(QQ, 1); L + sage: L = lie_algebras.upper_triangular_matrices(QQ, 1); L Lie algebra of 1-dimensional upper triangular matrices over Rational Field sage: TestSuite(L).run() - sage: L = lie_algebras.upper_triangluar_matrices(QQ, 0); L + sage: L = lie_algebras.upper_triangular_matrices(QQ, 0); L Lie algebra of 0-dimensional upper triangular matrices over Rational Field sage: TestSuite(L).run() """ @@ -356,6 +384,12 @@ def strictly_upper_triangular_matrices(R, n): sage: L = lie_algebras.strictly_upper_triangular_matrices(QQ, 4); L Lie algebra of 4-dimensional strictly upper triangular matrices over Rational Field sage: TestSuite(L).run() + sage: n0, n1, n2 = L.lie_algebra_generators() + sage: L[n2, n1] + [ 0 0 0 0] + [ 0 0 0 -1] + [ 0 0 0 0] + [ 0 0 0 0] TESTS:: diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index ab3b89da8bf..29cd0f7b257 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -156,6 +156,24 @@ def __init__(self, n): """ self._n = n + def n(self): + """ + Return the rank of the Heisenberg algebra ``self``. + + This is the ``n`` such that ``self`` is the `n`-th Heisenberg + algebra. + + EXAMPLES:: + + sage: H = lie_algebras.Heisenberg(QQ, 3) + sage: H.n() + 3 + sage: H = lie_algebras.Heisenberg(QQ, 3, representation="matrix") + sage: H.n() + 3 + """ + return self._n + @cached_method def gens(self): """ @@ -378,7 +396,7 @@ class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): .. MATH:: \begin{bmatrix} - 0 & p^T & z \\ + 0 & p^T & k \\ 0 & 0_n & q \\ 0 & 0 & 0 \end{bmatrix} @@ -400,13 +418,13 @@ class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): 0 & 0 & 0 \end{bmatrix}, \\ z & = \begin{bmatrix} - 0 & 0 & z \\ + 0 & 0 & 1 \\ 0 & 0_n & 0 \\ 0 & 0 & 0 \end{bmatrix}, \end{aligned} - where `\{e_i\}` is the standard basis. + where `\{e_i\}` is the standard basis of `R^n`. INPUT: @@ -424,6 +442,8 @@ class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): [0 0 0] sage: z == L.z() True + sage: L.dimension() + 3 """ def __init__(self, R, n): """ @@ -442,9 +462,60 @@ def __init__(self, R, n): names = tuple('p%s'%i for i in range(1,n+1)) names = names + tuple('q%s'%i for i in range(1,n+1)) cat = LieAlgebras(R).FiniteDimensional().WithBasis() + # We are allowed to do this, since we override ``basis``. LieAlgebraFromAssociative.__init__(self, MS, p + q, names=names, index_set=names, category=cat) + def basis(self): + """ + Return the standard basis of ``self``. + + This is the basis + `(p_1, p_2, \ldots, p_n, q_1, q_2, \ldots, q_n, z)`, where + `p_i = E_{1, i+1}`, `q_i = E_{i+1, n+1}` and `z = E_{1, n+1}`. + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, 2, representation="matrix") + sage: sorted(dict(L.basis()).items()) + [( + [0 1 0 0] + [0 0 0 0] + [0 0 0 0] + 'p1', [0 0 0 0] + ), + ( + [0 0 1 0] + [0 0 0 0] + [0 0 0 0] + 'p2', [0 0 0 0] + ), + ( + [0 0 0 0] + [0 0 0 1] + [0 0 0 0] + 'q1', [0 0 0 0] + ), + ( + [0 0 0 0] + [0 0 0 0] + [0 0 0 1] + 'q2', [0 0 0 0] + ), + ( + [0 0 0 1] + [0 0 0 0] + [0 0 0 0] + 'z', [0 0 0 0] + )] + """ + pq = self.lie_algebra_generators() + def monomial(i): + if i == 'z': + return self.z() + return pq[i] + return Family(self.variable_names() + ('z',), monomial) + def _repr_(self): """ Return a string representation of ``self``. @@ -500,3 +571,40 @@ def z(self): d = {(0,self._n+1): self.base_ring().one()} return self.element_class( self, self._assoc(d) ) + class Element(LieAlgebraFromAssociative.Element): + def monomial_coefficients(self, copy=True): + """ + Return a dictionary whose keys are indices of basis elements in + the support of ``self`` and whose values are the corresponding + coefficients. + + INPUT: + + - ``copy`` -- ignored + + EXAMPLES:: + + sage: L = lie_algebras.Heisenberg(QQ, 3, representation="matrix") + sage: elt = L(Matrix(QQ, [[0, 1, 3, 0, 3], [0, 0, 0, 0, 0], [0, 0, 0, 0, -3], + ....: [0, 0, 0, 0, 7], [0, 0, 0, 0, 0]])) + sage: elt + [ 0 1 3 0 3] + [ 0 0 0 0 0] + [ 0 0 0 0 -3] + [ 0 0 0 0 7] + [ 0 0 0 0 0] + sage: sorted(elt.monomial_coefficients().items()) + [('p1', 1), ('p2', 3), ('q2', -3), ('q3', 7), ('z', 3)] + """ + d = {} + n = self.parent()._n + for i, mon in enumerate(self.parent().basis().keys()): + if i < n: + entry = self[0, i+1] + elif i < 2 * n: + entry = self[i-n+1, n+1] + else: + entry = self[0, n+1] + if entry: + d[mon] = entry + return d diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index b026ab5ecf0..a66b11b2795 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -73,8 +73,8 @@ class LieAlgebraWithStructureCoefficients(FinitelyGeneratedLieAlgebra, IndexedGe - ``names`` -- list or tuple of strings - - ``index_set`` -- list or tuple of hashable and comparable - elements + - ``index_set`` -- (default: ``names``) list or tuple of hashable + and comparable elements OUTPUT: @@ -259,7 +259,8 @@ def dimension(self): def bracket_on_basis(self, x, y): """ - Return the Lie bracket of ``[x, y]``. + Return the Lie bracket ``[x, y]`` of two basis elements + (indexed by) ``x`` and ``y``. EXAMPLES:: diff --git a/src/sage/algebras/lie_algebras/virasoro.py b/src/sage/algebras/lie_algebras/virasoro.py index c0744e741a7..36250a51d7e 100644 --- a/src/sage/algebras/lie_algebras/virasoro.py +++ b/src/sage/algebras/lie_algebras/virasoro.py @@ -35,7 +35,7 @@ class LieAlgebraRegularVectorFields(InfinitelyGeneratedLieAlgebra, IndexedGenera r""" The Lie algebra of regular vector fields on `\CC^{\times}`. - This is the Lie algebra generated by `\{d_i\}_{i \in \ZZ}` and subject + This is the Lie algebra with basis `\{d_i\}_{i \in \ZZ}` and subject to the relations .. MATH:: From 773ffdba4088f5d40b1598adc873fe002339b646 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 24 Oct 2015 12:23:48 -0500 Subject: [PATCH 088/223] Adding a monomial_coefficients method. --- src/sage/algebras/lie_algebras/lie_algebra.py | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 68ef3c351e3..68ff79a9d72 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -1194,6 +1194,31 @@ def is_abelian(self): return True return super(LieAlgebraFromAssociative, self).is_abelian() + def _an_element_(self): + """ + Return an element of ``self``. + + EXAMPLES:: + + sage: F. = FreeAlgebra(QQ) + + An infinitely generated example:: + + sage: L = LieAlgebra(associative=F) + sage: L.an_element() + x + + A finitely generated example:: + + sage: L = LieAlgebra(associative=F.gens()) + sage: L.an_element() + x + y + """ + G = self.lie_algebra_generators() + if G.cardinality() < float('inf'): + return self.sum(G) + return G[self._indices.an_element()] + class Element(LieAlgebraElementWrapper): def _bracket_(self, rhs): """ @@ -1235,6 +1260,32 @@ def lift_associative(self): """ return self.value + def monomial_coefficients(self, copy=True): + """ + Return the monomial coefficients of ``self`` (if this + notion makes sense for ``self.parent()``). + + EXAMPLES:: + + sage: R. = FreeAlgebra(QQ) + sage: L = LieAlgebra(associative=R) + sage: elt = L(x) + 2*L(y) - L(z) + sage: sorted(elt.monomial_coefficients().items()) + [(x, 1), (y, 2), (z, -1)] + + sage: L = LieAlgebra(associative=[x,y]) + sage: elt = L(x) + 2*L(y) + sage: elt.monomial_coefficients() + Traceback (most recent call last): + ... + NotImplementedError: the basis is not defined + """ + if self.parent()._gens is not None: + raise NotImplementedError("the basis is not defined") + # Copy is ignored until #18066 is merged or a dependency + #return self.value.monomial_coefficients(copy) + return self.value.monomial_coefficients() + class LiftMorphismToAssociative(LiftMorphism): """ The natural lifting morphism from a Lie algebra constructed from From 10ce8ff4c84248795e99f807aac2772c33e03cd6 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 25 Oct 2015 00:21:34 -0500 Subject: [PATCH 089/223] Fixing some things from recent positive review/merges. --- src/sage/algebras/lie_algebras/heisenberg.py | 25 ++++++-------- src/sage/algebras/lie_algebras/lie_algebra.py | 34 +++++++------------ .../lie_algebras/lie_algebra_element.py | 15 ++++++++ src/sage/categories/lie_algebras.py | 4 +-- 4 files changed, 41 insertions(+), 37 deletions(-) diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index 29cd0f7b257..f7d2d2a21c1 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -22,23 +22,18 @@ #***************************************************************************** from sage.misc.cachefunc import cached_method -#from sage.misc.misc import repr_lincomb from sage.structure.indexed_generators import IndexedGenerators -#from sage.algebras.algebra import Algebra from sage.algebras.lie_algebras.lie_algebra import (InfinitelyGeneratedLieAlgebra, LieAlgebraFromAssociative, FinitelyGeneratedLieAlgebra) -#from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement +from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraMatrixWrapper from sage.categories.lie_algebras import LieAlgebras -from sage.combinat.cartesian_product import CartesianProduct +from sage.categories.cartesian_product import cartesian_product from sage.matrix.matrix_space import MatrixSpace -#from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -#from sage.rings.infinity import infinity from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family from sage.sets.positive_integers import PositiveIntegers from sage.sets.set import Set -#from sage.rings.all import ZZ class HeisenbergAlgebra_abstract(IndexedGenerators): """ @@ -321,7 +316,7 @@ def __init__(self, R): sage: L = lie_algebras.Heisenberg(QQ, oo) sage: TestSuite(L).run() """ - S = CartesianProduct(PositiveIntegers(), ['p','q']) + S = cartesian_product([PositiveIntegers(), ['p','q']]) cat = LieAlgebras(R).WithBasis() InfinitelyGeneratedLieAlgebra.__init__(self, R, index_set=S, category=cat) HeisenbergAlgebra_abstract.__init__(self, S) @@ -358,8 +353,9 @@ def lie_algebra_generators(self): sage: L = lie_algebras.Heisenberg(QQ, oo) sage: L.lie_algebra_generators() - Lazy family (generator map(i))_{i in Cartesian product of - Positive integers, ['p', 'q']} + Lazy family (generator map(i))_{i in The cartesian product of + (Positive integers, {'p', 'q'})} + """ return Family(self._indices, lambda x: self.monomial(x[1] + str(x[0])), name='generator map') @@ -372,10 +368,10 @@ def basis(self): sage: L = lie_algebras.Heisenberg(QQ, oo) sage: L.basis() - Lazy family (basis map(i))_{i in Disjoint union of - Family ({'z'}, Cartesian product of Positive integers, ['p', 'q'])} + Lazy family (basis map(i))_{i in Disjoint union of Family ({'z'}, + The cartesian product of (Positive integers, {'p', 'q'}))} """ - S = CartesianProduct(PositiveIntegers(), ['p','q']) + S = cartesian_product([PositiveIntegers(), ['p','q']]) I = DisjointUnionEnumeratedSets([Set(['z']), S]) def basis_elt(x): if isinstance(x, str): @@ -571,7 +567,7 @@ def z(self): d = {(0,self._n+1): self.base_ring().one()} return self.element_class( self, self._assoc(d) ) - class Element(LieAlgebraFromAssociative.Element): + class Element(LieAlgebraMatrixWrapper, LieAlgebraFromAssociative.Element): def monomial_coefficients(self, copy=True): """ Return a dictionary whose keys are indices of basis elements in @@ -608,3 +604,4 @@ def monomial_coefficients(self, copy=True): if entry: d[mon] = entry return d + diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 68ff79a9d72..c52c6c115b8 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -21,35 +21,25 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -#from copy import copy from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute #from sage.structure.indexed_generators import IndexedGenerators from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -#from sage.structure.element_wrapper import ElementWrapper from sage.categories.algebras import Algebras from sage.categories.lie_algebras import LieAlgebras, LiftMorphism from sage.categories.rings import Rings -#from sage.categories.morphism import Morphism from sage.categories.morphism import SetMorphism -#from sage.categories.map import Map from sage.categories.homset import Hom from sage.algebras.free_algebra import FreeAlgebra, is_FreeAlgebra from sage.algebras.lie_algebras.lie_algebra_element import (LieAlgebraElement, - LieAlgebraElementWrapper) + LieAlgebraElementWrapper, LieAlgebraMatrixWrapper) from sage.rings.all import ZZ from sage.rings.ring import Ring -#from sage.rings.integer import Integer -#from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.infinity import infinity from sage.matrix.matrix_space import MatrixSpace -#from sage.matrix.constructor import matrix -#from sage.modules.free_module_element import vector -#from sage.modules.free_module import FreeModule, span -#from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract from sage.sets.family import Family, AbstractFamily from sage.sets.finite_enumerated_set import FiniteEnumeratedSet @@ -682,7 +672,6 @@ def get_order(self): in favor of a method in the category of (finite dimensional) modules with basis. - EXAMPLES:: sage: L. = LieAlgebra(QQ, {}) @@ -957,16 +946,16 @@ def __classcall_private__(cls, A, gens=None, names=None, index_set=None, A = gens[0].parent() # Make sure all the generators have the same parent of A gens = tuple([A(g) for g in gens]) - try: - # Try to make things, such as matrices, immutable - # since we need to hash them - for g in gens: - g.set_immutable() - except AttributeError: - pass names, index_set = LieAlgebra._standardize_names_index_set(names, index_set, ngens) + if isinstance(A, MatrixSpace): + if gens is not None: + for g in gens: + g.set_immutable() + return MatrixLieAlgebraFromAssociative(A, gens, names=names, + index_set=index_set) + return super(LieAlgebraFromAssociative, cls).__classcall__(cls, A, gens, names=names, index_set=index_set) @@ -1283,8 +1272,7 @@ def monomial_coefficients(self, copy=True): if self.parent()._gens is not None: raise NotImplementedError("the basis is not defined") # Copy is ignored until #18066 is merged or a dependency - #return self.value.monomial_coefficients(copy) - return self.value.monomial_coefficients() + return self.value.monomial_coefficients(copy) class LiftMorphismToAssociative(LiftMorphism): """ @@ -1341,3 +1329,7 @@ def section(self): return SetMorphism(Hom(self.codomain(), self.domain()), self.preimage) +class MatrixLieAlgebraFromAssociative(LieAlgebraFromAssociative): + class Element(LieAlgebraMatrixWrapper, LieAlgebraFromAssociative.Element): + pass + diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index e677ff662be..9b5bf0c93fe 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -387,3 +387,18 @@ def __getitem__(self, i): """ return self.value.__getitem__(i) +class LieAlgebraMatrixWrapper(LieAlgebraElementWrapper): + 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 + """ + value.set_immutable() # Make the matrix immutable for hashing + LieAlgebraElementWrapper.__init__(self, parent, value) + diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index 261228c8ebf..0651359438f 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -604,8 +604,8 @@ def _test_distributivity(self, **options): tester = self._tester(**options) S = tester.some_elements() P = S[0].parent() - from sage.combinat.cartesian_product import CartesianProduct - for x,y,z in tester.some_elements(CartesianProduct(S,S,S)): + from sage.categories.cartesian_product import cartesian_product + for x,y,z in tester.some_elements(cartesian_product([S,S,S])): # left distributivity tester.assert_(P.bracket(x, (y + z)) == P.bracket(x, y) + P.bracket(x, z)) # right distributivity From cdb2e5b9476356aa9f91d372a51aa802921f0e62 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 25 Oct 2015 17:58:29 +0100 Subject: [PATCH 090/223] review heisenberg.py --- src/sage/algebras/lie_algebras/heisenberg.py | 85 +++++++++++++------ src/sage/algebras/lie_algebras/lie_algebra.py | 2 +- .../lie_algebras/structure_coefficients.py | 8 +- src/sage/algebras/lie_algebras/virasoro.py | 24 ++++-- 4 files changed, 83 insertions(+), 36 deletions(-) diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index f7d2d2a21c1..bdf8e76e7e7 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -49,9 +49,10 @@ def __init__(self, I): """ IndexedGenerators.__init__(self, I, prefix='', bracket=False, latex_bracket=False, string_quotes=False) + def p(self, i): """ - The generator `p_i`. + The generator `p_i` of the Heisenberg algebra. EXAMPLES:: @@ -63,7 +64,7 @@ def p(self, i): def q(self, i): """ - The generator `q_i`. + The generator `q_i` of the Heisenberg algebra. EXAMPLES:: @@ -75,7 +76,7 @@ def q(self, i): def z(self): """ - The generator `z`. + The generator `z` of the Heisenberg algebra. EXAMPLES:: @@ -87,7 +88,11 @@ def z(self): def bracket_on_basis(self, x, y): """ - Return the bracket of basis elements indexed by ``x`` and ``y``. + Return the bracket of basis elements indexed by ``x`` and ``y`` + where ``x < y``. + + The basis of a Heisenberg algebra is ordered in such a way that + the `p_i` come first, the `q_i` come next, and the `z` comes last. EXAMPLES:: @@ -97,7 +102,7 @@ def bracket_on_basis(self, x, y): sage: H.bracket_on_basis(p1, q1) z """ - if x == 'z' or y == 'z': + if y == 'z': # No need to test for x == 'z' since x < y is assumed. return self.zero() if x[0] == 'p' and y[0] == 'q' and x[1] == y[1]: return self.z() @@ -156,7 +161,8 @@ def n(self): Return the rank of the Heisenberg algebra ``self``. This is the ``n`` such that ``self`` is the `n`-th Heisenberg - algebra. + algebra. The dimension of this Heisenberg algebra is then + `2n + 1`. EXAMPLES:: @@ -172,18 +178,21 @@ def n(self): @cached_method def gens(self): """ - Return the generators of ``self``. + Return the Lie algebra generators of ``self``. EXAMPLES:: sage: H = lie_algebras.Heisenberg(QQ, 2) sage: H.gens() (p1, p2, q1, q2) + sage: H = lie_algebras.Heisenberg(QQ, 0) + sage: H.gens() + (z,) """ + if self._n == 0: + return (self.z(),) L = [self.p(i) for i in range(1, self._n+1)] L += [self.q(i) for i in range(1, self._n+1)] - if self._n == 0: - L += [self.z()] return tuple(L) def gen(self, i): @@ -244,20 +253,30 @@ class HeisenbergAlgebra(HeisenbergAlgebra_fd, HeisenbergAlgebra_abstract, """ A Heisenberg algebra defined using structure coefficients. - The Heisenberg algebra is the Lie algebra generated by `p_i`, `q_i`, and - `z` with the following relations: + The `n`-th Heisenberg algebra (where `n` is a nonnegative + integer or infinity) is the Lie algebra with basis + `\{p_i\}_{1 \leq i \leq n} \cup \{q_i\}_{1 \leq i \leq n} \cup \{z\}` + with the following relations: .. MATH:: [p_i, q_j] = \delta_{ij} z, \quad [p_i, z] = [q_i, z] = [p_i, p_j] = [q_i, q_j] = 0. + This Lie algebra is also known as the Heisenberg algebra of rank `n`. + .. NOTE:: The relations `[p_i, q_j] = \delta_{ij} z`, `[p_i, z] = 0`, and `[q_i, z] = 0` are known as canonical commutation relations. See :wikipedia:`Canonical_commutation_relations`. + .. WARNING:: + + The `n` in the above definition is called the "rank" of the + Heisenberg algebra; it is not, however, a rank in any of the usual + meanings that this word has in the theory of Lie algebras. + INPUT: - ``R`` -- the base ring @@ -283,8 +302,9 @@ def __init__(self, R, n): sage: TestSuite(L).run() """ HeisenbergAlgebra_fd.__init__(self, n) - names = ['p%s'%i for i in range(1,n+1)] + ['q%s'%i for i in range(1,n+1)] + ['z'] - names = tuple(names) + names = tuple(['p%s'%i for i in range(1,n+1)] + + ['q%s'%i for i in range(1,n+1)] + + ['z']) FinitelyGeneratedLieAlgebra.__init__(self, R, names=names, index_set=names, category=LieAlgebras(R).FiniteDimensional().WithBasis()) HeisenbergAlgebra_abstract.__init__(self, names) @@ -301,10 +321,11 @@ def _repr_(self): return "Heisenberg algebra of rank {0} over {1}".format(self._n, self.base_ring()) class InfiniteHeisenbergAlgebra(HeisenbergAlgebra_abstract, InfinitelyGeneratedLieAlgebra): - """ + r""" The infinite Heisenberg algebra. - This is the Heisenberg algebra on an infinite number of generators. See + This is the Heisenberg algebra on an infinite number of generators. In + other words, this is the Heisenberg algebra of rank `\infty`. See :class:`HeisenbergAlgebra` for more information. """ def __init__(self, R): @@ -315,6 +336,10 @@ def __init__(self, R): sage: L = lie_algebras.Heisenberg(QQ, oo) sage: TestSuite(L).run() + sage: L.p(1).bracket(L.q(1)) == L.z() + True + sage: L.q(1).bracket(L.p(1)) == -L.z() + True """ S = cartesian_product([PositiveIntegers(), ['p','q']]) cat = LieAlgebras(R).WithBasis() @@ -370,6 +395,10 @@ def basis(self): sage: L.basis() Lazy family (basis map(i))_{i in Disjoint union of Family ({'z'}, The cartesian product of (Positive integers, {'p', 'q'}))} + sage: L.basis()['z'] + z + sage: L.basis()[(12, 'p')] + p12 """ S = cartesian_product([PositiveIntegers(), ['p','q']]) I = DisjointUnionEnumeratedSets([Set(['z']), S]) @@ -386,8 +415,8 @@ class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): r""" A Heisenberg algebra represented using matrices. - The Heisenberg algebra over `R` is a Lie algebra which is defined as - the Lie algebra of the matrices: + The `n`-th Heisenberg algebra over `R` is a Lie algebra which is + defined as the Lie algebra of the `(n+2) \times (n+2)`-matrices: .. MATH:: @@ -397,8 +426,8 @@ class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): 0 & 0 & 0 \end{bmatrix} - where `p, q \in R^n` and `0_n` in the `n \times n` zero matrix. It has a - basis of + where `p, q \in R^n` and `0_n` in the `n \times n` zero matrix. It has + a basis consisting of of .. MATH:: @@ -407,12 +436,12 @@ class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): 0 & e_i^T & 0 \\ 0 & 0_n & 0 \\ 0 & 0 & 0 - \end{bmatrix}, + \end{bmatrix} \qquad \text{for } 1 \leq i \leq n , \\ q_i & = \begin{bmatrix} 0 & 0 & 0 \\ 0 & 0_n & e_i \\ 0 & 0 & 0 - \end{bmatrix}, + \end{bmatrix} \qquad \text{for } 1 \leq i \leq n , \\ z & = \begin{bmatrix} 0 & 0 & 1 \\ 0 & 0_n & 0 \\ @@ -422,10 +451,14 @@ class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): where `\{e_i\}` is the standard basis of `R^n`. + This Lie algebra is isomorphic to the `n`-th Heisenberg algebra + cosnstructed in :class:`HeisenbergAlgebra`; the bases correspond to + each other. + INPUT: - ``R`` -- the base ring - - ``n`` -- the size of the matrices + - ``n`` -- the nonnegative integer `n` EXAMPLES:: @@ -468,7 +501,7 @@ def basis(self): This is the basis `(p_1, p_2, \ldots, p_n, q_1, q_2, \ldots, q_n, z)`, where - `p_i = E_{1, i+1}`, `q_i = E_{i+1, n+1}` and `z = E_{1, n+1}`. + `p_i = E_{1, i+1}`, `q_i = E_{i+1, n+2}` and `z = E_{1, n+2}`. EXAMPLES:: @@ -525,7 +558,7 @@ def _repr_(self): def p(self, i): r""" - Return the generator `p_i`. + Return the generator `p_i` of the Heisenberg algebra. EXAMPLES:: @@ -539,7 +572,7 @@ def p(self, i): def q(self, i): r""" - Return the generator `q_i`. + Return the generator `q_i` of the Heisenberg algebra. EXAMPLES:: @@ -554,7 +587,7 @@ def q(self, i): @cached_method def z(self): """ - Return the generator `z`. + Return the generator `z` of the Heisenberg algebra. EXAMPLES:: diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index c52c6c115b8..3bb10275faf 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -33,7 +33,7 @@ from sage.categories.morphism import SetMorphism from sage.categories.homset import Hom -from sage.algebras.free_algebra import FreeAlgebra, is_FreeAlgebra +from sage.algebras.free_algebra import FreeAlgebra from sage.algebras.lie_algebras.lie_algebra_element import (LieAlgebraElement, LieAlgebraElementWrapper, LieAlgebraMatrixWrapper) from sage.rings.all import ZZ diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index a66b11b2795..f65dcae8903 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -260,7 +260,10 @@ def dimension(self): def bracket_on_basis(self, x, y): """ Return the Lie bracket ``[x, y]`` of two basis elements - (indexed by) ``x`` and ``y``. + (indexed by) ``x`` and ``y`` where ``x < y``. + + (This particular implementation actually does not require + ``x < y``.) EXAMPLES:: @@ -272,9 +275,8 @@ def bracket_on_basis(self, x, y): sage: L.bracket(x + y - z, x - y + z) -2*y - 2*z """ - comp = self._print_options['generator_cmp'] ordered = True - if comp(x, y) > 0: # x > y + if x > y: x,y = y,x ordered = False b = (x, y) diff --git a/src/sage/algebras/lie_algebras/virasoro.py b/src/sage/algebras/lie_algebras/virasoro.py index 36250a51d7e..21eb442195b 100644 --- a/src/sage/algebras/lie_algebras/virasoro.py +++ b/src/sage/algebras/lie_algebras/virasoro.py @@ -95,7 +95,11 @@ def lie_algebra_generators(self): def bracket_on_basis(self, i, j): """ - Return the bracket of the basis elements indexed by ``i`` and ``j``. + Return the bracket of basis elements indexed by ``x`` and ``y`` + where ``x < y``. + + (This particular implementation actually does not require + ``x < y``.) EXAMPLES:: @@ -202,7 +206,11 @@ def lie_algebra_generators(self): def bracket_on_basis(self, i, j): """ - Return the bracket of the basis elements indexed by ``i`` and ``j``. + Return the bracket of basis elements indexed by ``x`` and ``y`` + where ``x < y``. + + (This particular implementation actually does not require + ``x < y``.) EXAMPLES:: @@ -246,7 +254,7 @@ class VirasoroAlgebra(InfinitelyGeneratedLieAlgebra, IndexedGenerators): r""" The Virasoro algebra. - This is the Lie algebra generated by `\{d_i\}_{i \in \ZZ} \cup \{c\}` + This is the Lie algebra with basis `\{d_i\}_{i \in \ZZ} \cup \{c\}` and subject to the relations .. MATH:: @@ -261,8 +269,8 @@ class VirasoroAlgebra(InfinitelyGeneratedLieAlgebra, IndexedGenerators): (Here, it is assumed that the base ring `R` has `2` invertible.) - This is the universal central extension `\widetilde{\mathfrak{d}}` of the - Lie algebra `\mathfrak{d}` of + This is the universal central extension `\widetilde{\mathfrak{d}}` of + the Lie algebra `\mathfrak{d}` of :class:`regular vector fields ` on `\CC^{\times}`. @@ -384,7 +392,11 @@ def c(self): def bracket_on_basis(self, i, j): """ - Return the bracket of the basis elements indexed by ``i`` and ``j``. + Return the bracket of basis elements indexed by ``x`` and ``y`` + where ``x < y``. + + (This particular implementation actually does not require + ``x < y``.) EXAMPLES:: From eda8d898c413e6244f515d72f6cbdca4aa2a763e Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 25 Oct 2015 18:20:26 +0100 Subject: [PATCH 091/223] review virasoro.py --- src/sage/algebras/lie_algebras/virasoro.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/sage/algebras/lie_algebras/virasoro.py b/src/sage/algebras/lie_algebras/virasoro.py index 21eb442195b..457bc12306d 100644 --- a/src/sage/algebras/lie_algebras/virasoro.py +++ b/src/sage/algebras/lie_algebras/virasoro.py @@ -1,5 +1,5 @@ """ -Virasoro Algebras +Virasoro Algebra and Related Lie Algebras AUTHORS: @@ -42,7 +42,7 @@ class LieAlgebraRegularVectorFields(InfinitelyGeneratedLieAlgebra, IndexedGenera [d_i, d_j] = (j - i) d_{i+j}. - This is known as the Witt (Lie) algebra. + This is also known as the Witt (Lie) algebra. REFERENCES: @@ -184,6 +184,8 @@ def _repr_(self): sage: lie_algebras.pwitt(Zmod(5), 5) The 5-Witt Lie algebra over Ring of integers modulo 5 + sage: lie_algebras.pwitt(Zmod(5), 15) + The 15-Witt Lie algebra over Ring of integers modulo 5 """ return "The {}-Witt Lie algebra over {}".format(self._p, self.base_ring()) @@ -322,6 +324,8 @@ def _latex_term(self, m): 'c' sage: d._latex_term(2) 'd_{2}' + sage: d._latex_term(-13) + 'd_{-13}' """ if isinstance(m, str): return m @@ -359,9 +363,15 @@ def basis(self): EXAMPLES:: sage: d = lie_algebras.VirasoroAlgebra(QQ) - sage: d.basis() + sage: B = d.basis(); B Lazy family (basis map(i))_{i in Disjoint union of Family ({'c'}, Integer Ring)} + sage: B['c'] + c + sage: B[3] + d[3] + sage: B[-15] + d[-15] """ I = DisjointUnionEnumeratedSets([Set(['c']), ZZ]) return Family(I, self.monomial, name='basis map') From 0fc61b37f2c6539c25419fa8e910abf49b012f3e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 25 Oct 2015 12:27:09 -0500 Subject: [PATCH 092/223] Adding coercions for the Heisenberg algebra. --- src/sage/algebras/lie_algebras/heisenberg.py | 175 ++++++++++++------- 1 file changed, 115 insertions(+), 60 deletions(-) diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index bdf8e76e7e7..9cba3317efa 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -30,6 +30,7 @@ from sage.categories.lie_algebras import LieAlgebras from sage.categories.cartesian_product import cartesian_product from sage.matrix.matrix_space import MatrixSpace +from sage.rings.integer import Integer from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family from sage.sets.positive_integers import PositiveIntegers @@ -138,7 +139,7 @@ def _latex_term(self, m): return m return "%s_{%s}"%(m[0], m[1]) # else it is of length 2 -class HeisenbergAlgebra_fd: +class HeisenbergAlgebra_fd(object): """ Common methods for finite-dimensional Heisenberg algebras. """ @@ -241,12 +242,38 @@ def basis(self): sage: H.basis() Finite family {'q1': q1, 'p1': p1, 'z': z} """ + k = ['p%s'%i for i in range(1, self._n+1)] + k += ['q%s'%i for i in range(1, self._n+1)] + k += ['z'] d = {} for i in range(1, self._n+1): d['p%s'%i] = self.p(i) d['q%s'%i] = self.q(i) d['z'] = self.z() - return Family(self._indices, lambda i: d[i]) + return Family(k, lambda i: d[i]) + + def _coerce_map_from_(self, H): + """ + Return the coercion map from ``H`` to ``self`` if one exists, + otherwise return ``None``. + + EXAMPLES:: + + sage: HB = lie_algebras.Heisenberg(QQ, 3) + sage: HM = lie_algebras.Heisenberg(QQ, 3, representation="matrix") + sage: HB.has_coerce_map_from(HM) + True + sage: HM.has_coerce_map_from(HB) + True + sage: HZ = lie_algebras.Heisenberg(ZZ, 2, representation="matrix") + sage: HB.has_coerce_map_from(HM) + True + """ + if isinstance(H, HeisenbergAlgebra_fd): + if H._n <= self._n and self.base_ring().has_coerce_map_from(H.base_ring()): + return H.module_morphism(lambda i: self.basis()[i], codomain=self) + return None # Otherwise no coercion + return super(HeisenbergAlgebra_fd, self)._coerce_map_from_(H) class HeisenbergAlgebra(HeisenbergAlgebra_fd, HeisenbergAlgebra_abstract, FinitelyGeneratedLieAlgebra): @@ -408,6 +435,53 @@ def basis_elt(x): return self.monomial(x[1] + str(x[0])) return Family(I, basis_elt, name="basis map") + def _from_fd_on_basis(self, i): + """ + Return the monomial in ``self`` corresponding to the + finite-dimensional basis element indexed by ``i``. + + EXAMPLES:: + + sage: H = lie_algebras.Heisenberg(QQ, oo) + sage: H._from_fd_on_basis('p2') + p2 + sage: H._from_fd_on_basis('q3') + q3 + sage: H._from_fd_on_basis('z') + z + """ + if i == 'z': + return self.z() + if i[0] == 'p': + return self.p(Integer(i[1:])) + return self.q(Integer(i[1:])) + + def _coerce_map_from_(self, H): + """ + Return the coercion map from ``H`` to ``self`` if one exists, + otherwise return ``None``. + + EXAMPLES:: + + sage: H = lie_algebras.Heisenberg(QQ, oo) + sage: HZ = lie_algebras.Heisenberg(ZZ, oo) + sage: phi = H.coerce_map_from(HZ) + sage: phi(HZ.p(3)).leading_coefficient().parent() + Rational Field + sage: HF = lie_algebras.Heisenberg(QQ, 3, representation="matrix") + sage: H.has_coerce_map_from(HF) + True + """ + if isinstance(H, HeisenbergAlgebra_fd): + if self.base_ring().has_coerce_map_from(H.base_ring()): + return H.module_morphism(self._from_fd_on_basis, codomain=self) + return None # Otherwise no coercion + if isinstance(H, InfiniteHeisenbergAlgebra): + if self.base_ring().has_coerce_map_from(H.base_ring()): + return lambda C,x: self._from_dict(x._monomial_coefficients, coerce=True) + return None # Otherwise no coercion + return super(InfiniteHeisenbergAlgebra, self)._coerce_map_from_(H) + ####################################################### ## Finite rank Heisenberg algebra using matrices @@ -473,6 +547,39 @@ class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): True sage: L.dimension() 3 + + sage: L = lie_algebras.Heisenberg(QQ, 2, representation="matrix") + sage: sorted(dict(L.basis()).items()) + [( + [0 1 0 0] + [0 0 0 0] + [0 0 0 0] + 'p1', [0 0 0 0] + ), + ( + [0 0 1 0] + [0 0 0 0] + [0 0 0 0] + 'p2', [0 0 0 0] + ), + ( + [0 0 0 0] + [0 0 0 1] + [0 0 0 0] + 'q1', [0 0 0 0] + ), + ( + [0 0 0 0] + [0 0 0 0] + [0 0 0 1] + 'q2', [0 0 0 0] + ), + ( + [0 0 0 1] + [0 0 0 0] + [0 0 0 0] + 'z', [0 0 0 0] + )] """ def __init__(self, R, n): """ @@ -486,65 +593,15 @@ def __init__(self, R, n): HeisenbergAlgebra_fd.__init__(self, n) MS = MatrixSpace(R, n+2, sparse=True) one = R.one() - p = tuple(MS({(0,i):one}) for i in range(1, n+1)) - q = tuple(MS({(i,n+1):one}) for i in range(1, n+1)) + p = tuple(MS({(0,i): one}) for i in range(1, n+1)) + q = tuple(MS({(i,n+1): one}) for i in range(1, n+1)) + z = (MS({(0,self._n+1): one}),) names = tuple('p%s'%i for i in range(1,n+1)) - names = names + tuple('q%s'%i for i in range(1,n+1)) + names = names + tuple('q%s'%i for i in range(1,n+1)) + ('z',) cat = LieAlgebras(R).FiniteDimensional().WithBasis() - # We are allowed to do this, since we override ``basis``. - LieAlgebraFromAssociative.__init__(self, MS, p + q, names=names, + LieAlgebraFromAssociative.__init__(self, MS, p + q + z, names=names, index_set=names, category=cat) - def basis(self): - """ - Return the standard basis of ``self``. - - This is the basis - `(p_1, p_2, \ldots, p_n, q_1, q_2, \ldots, q_n, z)`, where - `p_i = E_{1, i+1}`, `q_i = E_{i+1, n+2}` and `z = E_{1, n+2}`. - - EXAMPLES:: - - sage: L = lie_algebras.Heisenberg(QQ, 2, representation="matrix") - sage: sorted(dict(L.basis()).items()) - [( - [0 1 0 0] - [0 0 0 0] - [0 0 0 0] - 'p1', [0 0 0 0] - ), - ( - [0 0 1 0] - [0 0 0 0] - [0 0 0 0] - 'p2', [0 0 0 0] - ), - ( - [0 0 0 0] - [0 0 0 1] - [0 0 0 0] - 'q1', [0 0 0 0] - ), - ( - [0 0 0 0] - [0 0 0 0] - [0 0 0 1] - 'q2', [0 0 0 0] - ), - ( - [0 0 0 1] - [0 0 0 0] - [0 0 0 0] - 'z', [0 0 0 0] - )] - """ - pq = self.lie_algebra_generators() - def monomial(i): - if i == 'z': - return self.z() - return pq[i] - return Family(self.variable_names() + ('z',), monomial) - def _repr_(self): """ Return a string representation of ``self``. @@ -584,7 +641,6 @@ def q(self, i): """ return self._gens['q%s'%i] - @cached_method def z(self): """ Return the generator `z` of the Heisenberg algebra. @@ -597,8 +653,7 @@ def z(self): [0 0 0] [0 0 0] """ - d = {(0,self._n+1): self.base_ring().one()} - return self.element_class( self, self._assoc(d) ) + return self._gens['z'] class Element(LieAlgebraMatrixWrapper, LieAlgebraFromAssociative.Element): def monomial_coefficients(self, copy=True): From b8be3f4298913132df18d3230186f93686561223 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 25 Oct 2015 18:53:50 +0100 Subject: [PATCH 093/223] review heisenberg.py again; coercion still relies on unstaged changes to module morphisms --- src/sage/algebras/lie_algebras/heisenberg.py | 64 ++++++++++++++++++-- src/sage/modules/with_basis/morphism.py | 10 ++- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index 9cba3317efa..ee6f5fa0269 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -265,9 +265,29 @@ def _coerce_map_from_(self, H): True sage: HM.has_coerce_map_from(HB) True + sage: HB(HM.p(2)) + p2 + sage: HM(-HB.q(3)) == -HM.q(3) + True + sage: HB(HM.z()) + z + sage: HM(HB.z()) == HM.z() + True + sage: HQ = lie_algebras.Heisenberg(QQ, 2) + sage: HB.has_coerce_map_from(HQ) + True + sage: HB(HQ.p(2)) + p2 + sage: HZ = lie_algebras.Heisenberg(ZZ, 2) + sage: HB.has_coerce_map_from(HZ) + True + sage: HB(HZ.p(2)) + p2 sage: HZ = lie_algebras.Heisenberg(ZZ, 2, representation="matrix") - sage: HB.has_coerce_map_from(HM) + sage: HB.has_coerce_map_from(HZ) True + sage: HB(HZ.p(2)) + p2 """ if isinstance(H, HeisenbergAlgebra_fd): if H._n <= self._n and self.base_ring().has_coerce_map_from(H.base_ring()): @@ -438,7 +458,10 @@ def basis_elt(x): def _from_fd_on_basis(self, i): """ Return the monomial in ``self`` corresponding to the - finite-dimensional basis element indexed by ``i``. + basis element indexed by ``i``, where ``i`` is a basis index for + a *finite-dimensional* Heisenberg algebra. + + This is used for coercion. EXAMPLES:: @@ -466,11 +489,24 @@ def _coerce_map_from_(self, H): sage: H = lie_algebras.Heisenberg(QQ, oo) sage: HZ = lie_algebras.Heisenberg(ZZ, oo) sage: phi = H.coerce_map_from(HZ) + sage: phi(HZ.p(3)) == H.p(3) + True sage: phi(HZ.p(3)).leading_coefficient().parent() Rational Field sage: HF = lie_algebras.Heisenberg(QQ, 3, representation="matrix") sage: H.has_coerce_map_from(HF) True + sage: H(HF.p(2)) + p2 + sage: H(HF.z()) + z + sage: HF = lie_algebras.Heisenberg(QQ, 3) + sage: H.has_coerce_map_from(HF) + True + sage: H(HF.p(2)) + p2 + sage: H(HF.z()) + z """ if isinstance(H, HeisenbergAlgebra_fd): if self.base_ring().has_coerce_map_from(H.base_ring()): @@ -501,7 +537,7 @@ class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): \end{bmatrix} where `p, q \in R^n` and `0_n` in the `n \times n` zero matrix. It has - a basis consisting of of + a basis consisting of .. MATH:: @@ -523,7 +559,10 @@ class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): \end{bmatrix}, \end{aligned} - where `\{e_i\}` is the standard basis of `R^n`. + where `\{e_i\}` is the standard basis of `R^n`. In other words, it has + the basis `(p_1, p_2, \ldots, p_n, q_1, q_2, \ldots, q_n, z)`, where + `p_i = E_{1, i+1}`, `q_i = E_{i+1, n+2}` and `z = E_{1, n+2}` are + elementary matrices. This Lie algebra is isomorphic to the `n`-th Heisenberg algebra cosnstructed in :class:`HeisenbergAlgebra`; the bases correspond to @@ -580,6 +619,21 @@ class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): [0 0 0 0] 'z', [0 0 0 0] )] + + sage: L = lie_algebras.Heisenberg(QQ, 0, representation="matrix") + sage: sorted(dict(L.basis()).items()) + [( + [0 1] + 'z', [0 0] + )] + sage: L.gens() + ( + [0 1] + [0 0] + ) + sage: L.lie_algebra_generators() + Finite family {'z': [0 1] + [0 0]} """ def __init__(self, R, n): """ @@ -595,7 +649,7 @@ def __init__(self, R, n): one = R.one() p = tuple(MS({(0,i): one}) for i in range(1, n+1)) q = tuple(MS({(i,n+1): one}) for i in range(1, n+1)) - z = (MS({(0,self._n+1): one}),) + z = (MS({(0,n+1): one}),) names = tuple('p%s'%i for i in range(1,n+1)) names = names + tuple('q%s'%i for i in range(1,n+1)) + ('z',) cat = LieAlgebras(R).FiniteDimensional().WithBasis() diff --git a/src/sage/modules/with_basis/morphism.py b/src/sage/modules/with_basis/morphism.py index 4fb91391cc0..3f1c94cda04 100644 --- a/src/sage/modules/with_basis/morphism.py +++ b/src/sage/modules/with_basis/morphism.py @@ -381,9 +381,15 @@ def __call__(self, *args): assert(x.parent() is self.domain()) if self._is_module_with_basis_over_same_base_ring: - return self.codomain().linear_combination( (self._on_basis(*(before+(index,)+after)), coeff ) for (index, coeff) in args[self._position] ) + return self.codomain().linear_combination( + ( self._on_basis(*(before+(index,)+after)), coeff ) + for (index, coeff) + in args[self._position].monomial_coefficients().iteritems() ) else: - return sum(( coeff * self._on_basis(*(before+(index,)+after)) for (index, coeff) in args[self._position]), self._zero) + return sum(( coeff * self._on_basis(*(before+(index,)+after)) + for (index, coeff) + in args[self._position].monomial_coefficients().iteritems() ), + self._zero) # As per the specs of Map, we should in fact implement _call_. # However we currently need to abuse Map.__call__ (which strict From 6815f1c02c6a13cef96d542328d3248e06ca9fb9 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 25 Oct 2015 18:56:51 +0100 Subject: [PATCH 094/223] review heisenberg.py again; coercion still relies on unstaged changes to module morphisms --- src/sage/algebras/lie_algebras/heisenberg.py | 64 ++++++++++++++++++-- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index 9cba3317efa..ee6f5fa0269 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -265,9 +265,29 @@ def _coerce_map_from_(self, H): True sage: HM.has_coerce_map_from(HB) True + sage: HB(HM.p(2)) + p2 + sage: HM(-HB.q(3)) == -HM.q(3) + True + sage: HB(HM.z()) + z + sage: HM(HB.z()) == HM.z() + True + sage: HQ = lie_algebras.Heisenberg(QQ, 2) + sage: HB.has_coerce_map_from(HQ) + True + sage: HB(HQ.p(2)) + p2 + sage: HZ = lie_algebras.Heisenberg(ZZ, 2) + sage: HB.has_coerce_map_from(HZ) + True + sage: HB(HZ.p(2)) + p2 sage: HZ = lie_algebras.Heisenberg(ZZ, 2, representation="matrix") - sage: HB.has_coerce_map_from(HM) + sage: HB.has_coerce_map_from(HZ) True + sage: HB(HZ.p(2)) + p2 """ if isinstance(H, HeisenbergAlgebra_fd): if H._n <= self._n and self.base_ring().has_coerce_map_from(H.base_ring()): @@ -438,7 +458,10 @@ def basis_elt(x): def _from_fd_on_basis(self, i): """ Return the monomial in ``self`` corresponding to the - finite-dimensional basis element indexed by ``i``. + basis element indexed by ``i``, where ``i`` is a basis index for + a *finite-dimensional* Heisenberg algebra. + + This is used for coercion. EXAMPLES:: @@ -466,11 +489,24 @@ def _coerce_map_from_(self, H): sage: H = lie_algebras.Heisenberg(QQ, oo) sage: HZ = lie_algebras.Heisenberg(ZZ, oo) sage: phi = H.coerce_map_from(HZ) + sage: phi(HZ.p(3)) == H.p(3) + True sage: phi(HZ.p(3)).leading_coefficient().parent() Rational Field sage: HF = lie_algebras.Heisenberg(QQ, 3, representation="matrix") sage: H.has_coerce_map_from(HF) True + sage: H(HF.p(2)) + p2 + sage: H(HF.z()) + z + sage: HF = lie_algebras.Heisenberg(QQ, 3) + sage: H.has_coerce_map_from(HF) + True + sage: H(HF.p(2)) + p2 + sage: H(HF.z()) + z """ if isinstance(H, HeisenbergAlgebra_fd): if self.base_ring().has_coerce_map_from(H.base_ring()): @@ -501,7 +537,7 @@ class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): \end{bmatrix} where `p, q \in R^n` and `0_n` in the `n \times n` zero matrix. It has - a basis consisting of of + a basis consisting of .. MATH:: @@ -523,7 +559,10 @@ class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): \end{bmatrix}, \end{aligned} - where `\{e_i\}` is the standard basis of `R^n`. + where `\{e_i\}` is the standard basis of `R^n`. In other words, it has + the basis `(p_1, p_2, \ldots, p_n, q_1, q_2, \ldots, q_n, z)`, where + `p_i = E_{1, i+1}`, `q_i = E_{i+1, n+2}` and `z = E_{1, n+2}` are + elementary matrices. This Lie algebra is isomorphic to the `n`-th Heisenberg algebra cosnstructed in :class:`HeisenbergAlgebra`; the bases correspond to @@ -580,6 +619,21 @@ class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): [0 0 0 0] 'z', [0 0 0 0] )] + + sage: L = lie_algebras.Heisenberg(QQ, 0, representation="matrix") + sage: sorted(dict(L.basis()).items()) + [( + [0 1] + 'z', [0 0] + )] + sage: L.gens() + ( + [0 1] + [0 0] + ) + sage: L.lie_algebra_generators() + Finite family {'z': [0 1] + [0 0]} """ def __init__(self, R, n): """ @@ -595,7 +649,7 @@ def __init__(self, R, n): one = R.one() p = tuple(MS({(0,i): one}) for i in range(1, n+1)) q = tuple(MS({(i,n+1): one}) for i in range(1, n+1)) - z = (MS({(0,self._n+1): one}),) + z = (MS({(0,n+1): one}),) names = tuple('p%s'%i for i in range(1,n+1)) names = names + tuple('q%s'%i for i in range(1,n+1)) + ('z',) cat = LieAlgebras(R).FiniteDimensional().WithBasis() From 3f9a4a19a30d6749ab046160bc43988958c9490f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 26 Oct 2015 17:33:53 -0500 Subject: [PATCH 095/223] Fixing the failing doctests and making the doc build. --- src/sage/algebras/lie_algebras/lie_algebra.py | 38 +++++++++---------- ...ite_dimensional_lie_algebras_with_basis.py | 18 ++++++++- src/sage/categories/lie_algebras.py | 11 +++--- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 3bb10275faf..e4970adf4e3 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -95,7 +95,7 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): **2.** A Lie algebra can be built from any associative algebra by defining the Lie bracket to be the commutator. For example, we can - start with the descent algebra: + start with the descent algebra:: sage: D = DescentAlgebra(QQ, 4).D() sage: L = LieAlgebra(associative=D); L @@ -686,22 +686,22 @@ def get_order(self): Element = LieAlgebraElement # Default for all Lie algebras class FinitelyGeneratedLieAlgebra(LieAlgebra): + r""" + An finitely generated Lie algebra. """ - An fintely generated Lie algebra. + def __init__(self, R, names=None, index_set=None, category=None): + """ + Initialize ``self``. - INPUT: + INPUT: - - ``R`` -- the base ring + - ``R`` -- the base ring - - ``names`` -- the names of the generators + - ``names`` -- the names of the generators - - ``index_set`` -- the index set of the generators + - ``index_set`` -- the index set of the generators - - ``category`` -- the category of the Lie algebra - """ - def __init__(self, R, names=None, index_set=None, category=None): - """ - Initialize ``self``. + - ``category`` -- the category of the Lie algebra EXAMPLES:: @@ -827,8 +827,8 @@ class LieAlgebraFromAssociative(LieAlgebra): sage: R. = FreeAlgebra(QQ, 3) sage: L. = LieAlgebra(associative=[a,b]) - Now for a more complicated example using the group ring of `S_3` as our - base algebra:: + Now for a more complicated example using the group ring of `S_3` + as our base algebra:: sage: G = SymmetricGroup(3) sage: S = GroupAlgebra(G, QQ) @@ -868,12 +868,6 @@ class LieAlgebraFromAssociative(LieAlgebra): sage: L.bracket(x, L.bracket(y,x)) [-6 14] [14 6] - - TESTS:: - - sage: from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative as LAFA - sage: LAFA(MatrixSpace(QQ, 0, sparse=True), [], names=()) - Lie algebra generated by () in Full MatrixSpace of 0 by 0 sparse matrices over Rational Field """ @staticmethod def __classcall_private__(cls, A, gens=None, names=None, index_set=None, @@ -969,6 +963,12 @@ def __init__(self, A, gens=None, names=None, index_set=None, category=None): sage: S = GroupAlgebra(G, QQ) sage: L = LieAlgebra(associative=S) sage: TestSuite(L).run() + + TESTS:: + + sage: from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative as LAFA + sage: LAFA(MatrixSpace(QQ, 0, sparse=True), [], names=()) + Lie algebra generated by () in Full MatrixSpace of 0 by 0 sparse matrices over Rational Field """ self._assoc = A R = self._assoc.base_ring() diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index 0160911baab..f6729d6679d 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -74,7 +74,9 @@ def __classcall_private__(cls, R, n=None, M=None, ambient=None): M = FreeModule(R, n) else: M = M.change_ring(R) - return super(AbelianLieAlgebra, cls).__classcall__(cls, R, n=None, M=M, ambient=ambient) + n = M.dimension() + return super(AbelianLieAlgebra, cls).__classcall__(cls, R, n=n, M=M, + ambient=ambient) def __init__(self, R, n=None, M=None, ambient=None): """ @@ -356,5 +358,19 @@ def to_vector(self): """ return self.value + def monomial_coefficients(self, copy=True): + """ + Return the monomial coefficients of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: a, b, c = L.lie_algebra_generators() + sage: elt = 2*a + 2*b + 3*c + sage: elt.monomial_coefficients() + {0: 2, 1: 2, 2: 3} + """ + return self.value.monomial_coefficients(copy) + Example = AbelianLieAlgebra diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index 0651359438f..76d64202150 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -603,13 +603,14 @@ def _test_distributivity(self, **options): """ tester = self._tester(**options) S = tester.some_elements() - P = S[0].parent() - from sage.categories.cartesian_product import cartesian_product - for x,y,z in tester.some_elements(cartesian_product([S,S,S])): + from sage.misc.misc import some_tuples + for x,y,z in some_tuples(S, 3, tester._max_runs): # left distributivity - tester.assert_(P.bracket(x, (y + z)) == P.bracket(x, y) + P.bracket(x, z)) + tester.assert_(self.bracket(x, (y + z)) + == self.bracket(x, y) + self.bracket(x, z)) # right distributivity - tester.assert_(P.bracket((x + y), z) == P.bracket(x, z) + P.bracket(y, z)) + tester.assert_(self.bracket((x + y), z) + == self.bracket(x, z) + self.bracket(y, z)) class ElementMethods: @coerce_binop From b9930e6c4f3f099baf341b58dc81d50a00df4986 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Tue, 27 Oct 2015 14:16:55 -0400 Subject: [PATCH 096/223] some changes to standardization of names --- src/sage/algebras/lie_algebras/lie_algebra.py | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index e4970adf4e3..0917824dc2b 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -349,6 +349,24 @@ def _standardize_names_index_set(names=None, index_set=None, ngens=None): """ Standardize the ``names`` and ``index_set`` for a Lie algebra. + The method is supposed to return a pair + ``(names', index_set')``, where ``names'`` is either + ``None`` or a tuple of strings, and where ``index_set'`` + is a finite enumerated set. (The purpose of + ``index_set'`` is to index the basis elements or the + generators of some Lie algebra; the strings in + ``names'``, when they exist, are used for printing these + indices.) + + .. TODO:: + + As far as I understand, the optional parameter ``ngens`` + is only used to raise errors when it is wrong. There is + no automatic numbering like "if ``names`` is a string + with no commas and ``ngens`` is not ``None``, then set + ``names = [names + str(i) for i in range(ngens)]``". Do + we need this parameter then? + .. TODO:: This function could likely be generalized for any parent @@ -407,9 +425,7 @@ def _standardize_names_index_set(names=None, index_set=None, ngens=None): index_set = FiniteEnumeratedSet(index_set) if names is not None: - if index_set is None: - index_set = names - elif len(names) != index_set.cardinality(): + if len(names) != index_set.cardinality(): raise ValueError("the number of names must equal" " the size of the indexing set") if ngens is not None and len(names) != ngens: From 60f743a2d8f8d684e4e636d6bdf329fae9967cb2 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 27 Oct 2015 13:58:41 -0500 Subject: [PATCH 097/223] Parsing the input so that it uses the indexing set. --- .../lie_algebras/structure_coefficients.py | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index f65dcae8903..6aadfc2ea1f 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -120,11 +120,25 @@ def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, **kwds): sage: L2 = LieAlgebra(QQ, 'x,y', {('y','x'):{'x':-1}}) sage: L1 is L2 True + + Check that we convert names to the indexing set:: + + sage: L = LieAlgebra(QQ, 'x,y,z', {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}, index_set=range(3)) + sage: (x,y,z) = L.gens() + sage: L[x,y] + L[2] """ names, index_set = LieAlgebra._standardize_names_index_set(names, index_set) + # Make sure the structure coefficients are given by the indexing set + if names is not None and names != tuple(index_set): + d = {x: index_set[i] for i,x in enumerate(names)} + get_pairs = lambda X: X.items() if isinstance(X, dict) else X + s_coeff = {(d[k[0]], d[k[1]]): [(d[x], y) for x,y in get_pairs(s_coeff[k])] + for k in s_coeff} + s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff(s_coeff) - if len(s_coeff) == 0: + if s_coeff.cardinality() == 0: return AbelianLieAlgebra(R, names, index_set, **kwds) if (names is None and len(index_set) <= 1) or len(names) <= 1: @@ -181,8 +195,8 @@ def _standardize_s_coeff(s_coeff): sc[key] = vals return Family(sc) - def __init__(self, R, s_coeff, names, index_set, category=None, prefix='', - bracket=False, latex_bracket=False, string_quotes=False, **kwds): + def __init__(self, R, s_coeff, names, index_set, category=None, prefix=None, + bracket=None, latex_bracket=None, string_quotes=None, **kwds): """ Initialize ``self``. @@ -191,6 +205,19 @@ def __init__(self, R, s_coeff, names, index_set, category=None, prefix='', sage: L = LieAlgebra(QQ, 'x,y', {('x','y'): {'x':1}}) sage: TestSuite(L).run() """ + default = (names != tuple(index_set)) + if prefix is None: + if default: + prefix = 'L' + else: + prefix = '' + if bracket is None: + bracket = default + if latex_bracket is None: + latex_bracket = default + if string_quotes is None: + string_quotes = default + cat = LieAlgebras(R).WithBasis().FiniteDimensional().or_subcategory(category) FinitelyGeneratedLieAlgebra.__init__(self, R, names, index_set, cat) IndexedGenerators.__init__(self, self._indices, prefix=prefix, From 50f4441019eeb080c7e700e2853f9b6aa564cf7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 19 Jan 2016 09:46:43 +0100 Subject: [PATCH 098/223] trac #16820 correct the spelling of Cartesian --- src/sage/algebras/lie_algebras/heisenberg.py | 4 ++-- src/sage/algebras/lie_algebras/virasoro.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index ee6f5fa0269..07e24e5381e 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -425,7 +425,7 @@ def lie_algebra_generators(self): sage: L = lie_algebras.Heisenberg(QQ, oo) sage: L.lie_algebra_generators() - Lazy family (generator map(i))_{i in The cartesian product of + Lazy family (generator map(i))_{i in The Cartesian product of (Positive integers, {'p', 'q'})} """ @@ -441,7 +441,7 @@ def basis(self): sage: L = lie_algebras.Heisenberg(QQ, oo) sage: L.basis() Lazy family (basis map(i))_{i in Disjoint union of Family ({'z'}, - The cartesian product of (Positive integers, {'p', 'q'}))} + The Cartesian product of (Positive integers, {'p', 'q'}))} sage: L.basis()['z'] z sage: L.basis()[(12, 'p')] diff --git a/src/sage/algebras/lie_algebras/virasoro.py b/src/sage/algebras/lie_algebras/virasoro.py index 457bc12306d..2cc73a9b384 100644 --- a/src/sage/algebras/lie_algebras/virasoro.py +++ b/src/sage/algebras/lie_algebras/virasoro.py @@ -414,13 +414,13 @@ def bracket_on_basis(self, i, j): sage: d.bracket_on_basis('c', 2) 0 sage: d.bracket_on_basis(2, -2) - -4*d[0] - 1/2*c + -1/2*c - 4*d[0] """ if i == 'c' or j == 'c': return self.zero() ret = self._from_dict({i + j: j-i}) if i == -j: - ret += (j**3 - j) / 12 * self.c() + ret += (j ** 3 - j) / 12 * self.c() return ret def _an_element_(self): From 7d155ecae295b68d22eee62f07438af2111641fb Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 2 Jun 2016 08:06:10 -0500 Subject: [PATCH 099/223] Fixing trivial doctest failures. --- src/sage/algebras/lie_algebras/lie_algebra.py | 2 +- src/sage/algebras/lie_algebras/virasoro.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 0917824dc2b..f4e516057b4 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -1211,7 +1211,7 @@ def _an_element_(self): sage: L = LieAlgebra(associative=F) sage: L.an_element() - x + 1 A finitely generated example:: diff --git a/src/sage/algebras/lie_algebras/virasoro.py b/src/sage/algebras/lie_algebras/virasoro.py index 2cc73a9b384..d4410c6a3ab 100644 --- a/src/sage/algebras/lie_algebras/virasoro.py +++ b/src/sage/algebras/lie_algebras/virasoro.py @@ -414,7 +414,7 @@ def bracket_on_basis(self, i, j): sage: d.bracket_on_basis('c', 2) 0 sage: d.bracket_on_basis(2, -2) - -1/2*c - 4*d[0] + -4*d[0] - 1/2*c """ if i == 'c' or j == 'c': return self.zero() From a016182b1fcb8dcb4b29840be98436dda8531464 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 2 Jun 2016 10:08:08 -0500 Subject: [PATCH 100/223] Implementing a better way to compare indices. --- .../lie_algebras/structure_coefficients.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 6aadfc2ea1f..ca45806cf33 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -302,18 +302,15 @@ def bracket_on_basis(self, x, y): sage: L.bracket(x + y - z, x - y + z) -2*y - 2*z """ - ordered = True - if x > y: - x,y = y,x - ordered = False - b = (x, y) try: - val = self._s_coeff[b] + return self._s_coeff[x,y] + except KeyError: + pass + + try: + return -self._s_coeff[y,x] except KeyError: return self.zero() - if ordered: - return val - return -val def module(self, sparse=True): """ From 6fcb3726142ab68451acc682d523b264bc1e319f Mon Sep 17 00:00:00 2001 From: Aram Dermenjian Date: Fri, 1 Jul 2016 13:17:33 -0400 Subject: [PATCH 101/223] Travis' fix for documentation --- src/doc/en/reference/algebras/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/en/reference/algebras/index.rst b/src/doc/en/reference/algebras/index.rst index 56e15772a22..d07bb22dd97 100644 --- a/src/doc/en/reference/algebras/index.rst +++ b/src/doc/en/reference/algebras/index.rst @@ -75,7 +75,7 @@ Non-associative algebras .. toctree:: :maxdepth: 2 - sage/algebras/lie_algebras + lie_algebras sage/algebras/jordan_algebra sage/combinat/free_prelie_algebra sage/algebras/shuffle_algebra From d5e618b4517c8766181a276da80f4e34080f60b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 12 Jul 2016 19:17:29 +0200 Subject: [PATCH 102/223] abc of Lie algebras, use key rather than cmp to sort ; and sorting_key --- .../examples/lie_algebras_with_basis.py | 3 ++- ...ite_dimensional_lie_algebras_with_basis.py | 6 ++--- .../categories/lie_algebras_with_basis.py | 26 ++++++++++++------- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/sage/categories/examples/lie_algebras_with_basis.py b/src/sage/categories/examples/lie_algebras_with_basis.py index e35e5efc062..6c122daa56e 100644 --- a/src/sage/categories/examples/lie_algebras_with_basis.py +++ b/src/sage/categories/examples/lie_algebras_with_basis.py @@ -128,7 +128,8 @@ def __init__(self, R, indices, **kwds): if 'prefix' not in kwds: kwds['prefix'] = 'P' # This is a workaround until IndexedFree(Abelian)Monoid elements compare properly - kwds['generator_cmp'] = lambda x,y: -cmp(x.to_word_list(), y.to_word_list()) + kwds['sorting_key'] = lambda x: x.to_word_list() + kwds['sorting_reverse'] = True M = IndexedFreeAbelianMonoid(indices, bracket='') CombinatorialFreeModule.__init__(self, R, M, **kwds) 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 762b6d2dc4b..4e123ddf8ab 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -245,14 +245,14 @@ def structure_coefficients(self, include_zeros=False): B = self.basis() K = B.keys() zero = self.zero() - for i,x in enumerate(K): - for y in K[i+1:]: + for i, x in enumerate(K): + for y in K[i + 1:]: bx = B[x] by = B[y] val = self.bracket(bx, by) if not include_zeros and val == zero: continue - if self._basis_cmp(x, y) > 0: + if self._basis_key(x) > self._basis_key(y): d[(y, x)] = -val else: d[(x, y)] = val diff --git a/src/sage/categories/lie_algebras_with_basis.py b/src/sage/categories/lie_algebras_with_basis.py index f0199419301..119360d36d1 100644 --- a/src/sage/categories/lie_algebras_with_basis.py +++ b/src/sage/categories/lie_algebras_with_basis.py @@ -48,17 +48,19 @@ def example(self, gens=None): return Example(self.base_ring(), gens) class ParentMethods: - def _basis_cmp(self, x, y): + def _basis_key(self, x): """ - Compare two basis element indices. The default is to call ``cmp``. + Return the key used to compare two basis element indices. + + The default is to call the element itself. TESTS:: sage: L = LieAlgebras(QQ).WithBasis().example() - sage: L._basis_cmp(Partition([3,1]), Partition([2,1,1])) - 1 + sage: L._basis_key(Partition([3,1])) + [3, 1] """ - return cmp(x, y) + return x @abstract_method(optional=True) def bracket_on_basis(self, x, y): @@ -134,14 +136,18 @@ def _bracket_(self, y): 0 """ P = self.parent() - def term(ml,mr): - comp = P._basis_cmp(ml,mr) - if comp == 0: + + def term(ml, mr): + key_ml = P._basis_key(ml) + key_mr = P._basis_key(mr) + if key_ml == key_mr: return P.zero() - if comp < 0: + if key_ml < key_mr: return P.bracket_on_basis(ml, mr) return -P.bracket_on_basis(mr, ml) - return P.sum(cl*cr * term(ml,mr) for ml,cl in self for mr,cr in y) + + return P.sum(cl * cr * term(ml, mr) + for ml, cl in self for mr, cr in y) def to_vector(self): """ From e7f2cf054153cf20f6aae410ba0541b68ea4e6f3 Mon Sep 17 00:00:00 2001 From: jhs Date: Thu, 28 Jul 2016 15:21:39 -0400 Subject: [PATCH 103/223] "21118: created function to list degrees of iterates of a function" --- .../schemes/projective/projective_morphism.py | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 4992b08531a..d2960a2c1f0 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -25,7 +25,6 @@ - Ben Hutz (2015-11): iteration of subschemes - """ #***************************************************************************** @@ -1172,6 +1171,57 @@ def degree(self): """ return(self._polys[0].degree()) + def degree_sequence(self, iterates=2): + r""" + Return sequence of degrees of normalized iterates + + INPUT: ``iterates`` -- positive integer (optional - default: 2) + + OUTPUT: List + + EXAMPLES:: + + sage: P2. = ProjectiveSpace(QQ, 2) + sage: H = End(P2) + sage: f = H([Z^2, X*Y, Y^2]) + sage: f.degree_sequence(15) + [1, 2, 3, 5, 8, 11, 17, 24, 31, 45, 56, 68, 91, 93, 184, 275] + + :: + + sage: F. = PolynomialRing(QQ) + sage: P2. = ProjectiveSpace(F, 2) + sage: H = End(P2) + sage: f = H([Y*Z, X*Y, Y^2 + t*X*Z]) + sage: f.degree_sequence(5) + [1, 2, 3, 5, 8, 13] + + :: + + sage: P2. = ProjectiveSpace(QQ, 2) + sage: H = End(P2) + sage: f = H([X^2, Y^2, Z^2]) + sage: f.degree_sequence(10) + [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] + + """ + if int(iterates) < 1: + raise TypeError("iteration number must be a positive integer") + if not self.is_endomorphism(): + raise TypeError("map is not an endomorphism") + + if self.is_morphism(): + D = [1,self.degree()] + for n in range(2, iterates+1): + D.append(D[1]**n) + else: + D = [] + for n in range(0, iterates+1): + fn = self.nth_iterate_map(n) + fn.normalize_coordinates() + D.append(fn.degree()) + return D + def dehomogenize(self, n): r""" Returns the standard dehomogenization at the ``n[0]`` coordinate for the domain From 16e36a91adfe1c65dc053fea62e58f5447ba8386 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 8 Aug 2016 12:10:44 -0500 Subject: [PATCH 104/223] Refactor to use free modules for fin-dim Lie algebras w/ structure coeffs; a bit more work needed still. --- src/sage/algebras/lie_algebras/abelian.py | 180 ++++++++++ src/sage/algebras/lie_algebras/examples.py | 21 +- src/sage/algebras/lie_algebras/heisenberg.py | 17 +- src/sage/algebras/lie_algebras/lie_algebra.py | 244 +++++-------- .../lie_algebras/lie_algebra_element.py | 17 +- .../lie_algebras/structure_coefficients.py | 333 +++++++++--------- src/sage/algebras/lie_algebras/virasoro.py | 15 +- ...ite_dimensional_lie_algebras_with_basis.py | 4 +- src/sage/categories/lie_algebras.py | 2 + src/sage/structure/indexed_generators.py | 86 +++++ 10 files changed, 571 insertions(+), 348 deletions(-) create mode 100644 src/sage/algebras/lie_algebras/abelian.py diff --git a/src/sage/algebras/lie_algebras/abelian.py b/src/sage/algebras/lie_algebras/abelian.py new file mode 100644 index 00000000000..1d24a39a738 --- /dev/null +++ b/src/sage/algebras/lie_algebras/abelian.py @@ -0,0 +1,180 @@ +""" +Abelian Lie Algebras + +AUTHORS: + +- Travis Scrimshaw (2016-06-07): Initial version +""" + +#***************************************************************************** +# Copyright (C) 2016 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. +# http://www.gnu.org/licenses/ +#***************************************************************************** + +#from copy import copy +from sage.misc.cachefunc import cached_method +#from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.misc import repr_lincomb +from sage.structure.indexed_generators import (IndexedGenerators, + standardize_names_index_set) +#from sage.structure.parent import Parent +#from sage.structure.unique_representation import UniqueRepresentation + +#from sage.categories.algebras import Algebras +from sage.categories.lie_algebras import LieAlgebras + +#from sage.algebras.free_algebra import FreeAlgebra +from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement +from sage.algebras.lie_algebras.lie_algebra import LieAlgebra, FinitelyGeneratedLieAlgebra +from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients +#from sage.algebras.lie_algebras.ideal import LieAlgebraIdeal +#from sage.algebras.lie_algebras.quotient import QuotientLieAlgebra +#from sage.rings.all import ZZ +#from sage.rings.ring import Ring +#from sage.rings.integer import Integer +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.infinity import infinity +#from sage.matrix.matrix_space import MatrixSpace +#from sage.matrix.constructor import matrix +#from sage.modules.free_module_element import vector +from sage.modules.free_module import FreeModule #, span +from sage.sets.family import Family #, AbstractFamily + +class AbelianLieAlgebra(LieAlgebraWithStructureCoefficients): + r""" + An abelian Lie algebra. + + A Lie algebra `\mathfrak{g}` is abelian if `[x, y] = 0` for all + `x, y \in \mathfrak{g}`. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, abelian=True) + sage: L.bracket(x, y) + 0 + """ + @staticmethod + def __classcall_private__(cls, R, names=None, index_set=None, **kwds): + """ + Normalize input to ensure a unique representation. + + TESTS:: + + sage: L1 = LieAlgebra(QQ, 'x,y', {}) + sage: L2. = LieAlgebra(QQ, abelian=True) + sage: L1 is L2 + True + """ + names, index_set = standardize_names_index_set(names, index_set) + if index_set.cardinality() == infinity: + return InfiniteDimensionalAbelianLieAlgebra(R, index_set, **kwds) + return super(AbelianLieAlgebra, cls).__classcall__(cls, R, names, index_set, **kwds) + + def __init__(self, R, names, index_set, **kwds): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) + sage: TestSuite(L).run() + """ + LieAlgebraWithStructureCoefficients.__init__(self, R, Family({}), names, index_set, **kwds) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: LieAlgebra(QQ, 3, 'x', abelian=True) + Abelian Lie algebra on 3 generators (x0, x1, x2) over Rational Field + """ + gens = self.lie_algebra_generators() + if gens.cardinality() == 1: + return "Abelian Lie algebra on generator {} over {}".format(tuple(gens)[0], self.base_ring()) + return "Abelian Lie algebra on {} generators {} over {}".format( + gens.cardinality(), tuple(gens), self.base_ring()) + + def _construct_UEA(self): + """ + Construct the universal enveloping algebra of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) + sage: L._construct_UEA() + Multivariate Polynomial Ring in x0, x1, x2 over Rational Field + """ + return PolynomialRing(self.base_ring(), self.variable_names()) + + def is_abelian(self): + """ + Return ``True`` since this is an abelian Lie algebra. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) + sage: L.is_abelian() + True + """ + return True + + # abelian => nilpotent => solvable + is_nilpotent = is_solvable = is_abelian + + class Element(LieAlgebraWithStructureCoefficients.Element): + def _bracket_(self, y): + """ + Return the Lie bracket ``[self, y]``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, abelian=True) + sage: L.bracket(x, y) + 0 + """ + return self.parent().zero() + +class InfiniteDimensionalAbelianLieAlgebra(LieAlgebra, IndexedGenerators): + r""" + An infinite dimensional abelian Lie algebra. + + A Lie algebra `\mathfrak{g}` is abelian if `[x, y] = 0` for all + `x, y \in \mathfrak{g}`. + """ + def __init__(self, R, index_set, prefix='L', **kwds): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: L = LieAlgebra(QQ, index_set=ZZ, abelian=True) + sage: TestSuite(L).run() + """ + cat = LieAlgebras(R).WithBasis() + LieAlgebra.__init__(self, R, category=cat) + IndexedGenerators.__init__(self, index_set, prefix=prefix, **kwds) + + def dimension(self): + r""" + Return the dimension of ``self``, which is `\infty`. + + EXAMPLES:: + + sage: L = lie_algebras.abelian(QQ, index_set=ZZ) + sage: L.dimension() + +Infinity + """ + return infinity + + class Element(LieAlgebraElement): + def _bracket_(self, other): + return self.parent().zero() + + diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index 272b8ecd586..1f67b65083b 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -134,7 +134,7 @@ def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): names = tuple(names) if n == 0: - from sage.algebras.lie_algebras.structure_coefficients import AbelianLieAlgebra + from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra return AbelianLieAlgebra(R, names=names) if n == 1: @@ -259,7 +259,7 @@ def affine_transformations_line(R, names=['X', 'Y'], representation='bracket'): L.rename("Lie algebra of affine transformations of a line over {}".format(R)) return L -def abelian(R, names): +def abelian(R, names=None, index_set=None): """ Return the abelian Lie algebra generated by ``names``. @@ -270,8 +270,21 @@ def abelian(R, names): """ if isinstance(names, str): names = names.split(',') - from sage.algebras.lie_algebras.structure_coefficients import AbelianLieAlgebra - return AbelianLieAlgebra(R, tuple(names)) + elif isinstance(names, (list, tuple)): + names = tuple(names) + elif names is not None: + if index_set is not None: + raise ValueError("invalid generator names") + index_set = names + names = None + from sage.rings.infinity import infinity + if (index_set is not None + and not isinstance(index_set, (list, tuple)) + and index_set.cardinality() == infinity): + from sage.algebras.lie_algebras.abelian import InfiniteDimensionalAbelianLieAlgebra + return InfiniteDimensionalAbelianLieAlgebra(R, index_set=index_set) + from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra + return AbelianLieAlgebra(R, names=names, index_set=index_set) def Heisenberg(R, n, representation="structure"): """ diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index 07e24e5381e..83ff50fed5d 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -24,9 +24,10 @@ from sage.misc.cachefunc import cached_method from sage.structure.indexed_generators import IndexedGenerators -from sage.algebras.lie_algebras.lie_algebra import (InfinitelyGeneratedLieAlgebra, - LieAlgebraFromAssociative, FinitelyGeneratedLieAlgebra) -from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraMatrixWrapper +from sage.algebras.lie_algebras.lie_algebra import (LieAlgebraFromAssociative, + LieAlgebraWithGenerators) +from sage.algebras.lie_algebras.lie_algebra_element import (LieAlgebraElement, + LieAlgebraMatrixWrapper) from sage.categories.lie_algebras import LieAlgebras from sage.categories.cartesian_product import cartesian_product from sage.matrix.matrix_space import MatrixSpace @@ -139,6 +140,8 @@ def _latex_term(self, m): return m return "%s_{%s}"%(m[0], m[1]) # else it is of length 2 + Element = LieAlgebraElement + class HeisenbergAlgebra_fd(object): """ Common methods for finite-dimensional Heisenberg algebras. @@ -296,7 +299,7 @@ def _coerce_map_from_(self, H): return super(HeisenbergAlgebra_fd, self)._coerce_map_from_(H) class HeisenbergAlgebra(HeisenbergAlgebra_fd, HeisenbergAlgebra_abstract, - FinitelyGeneratedLieAlgebra): + LieAlgebraWithGenerators): """ A Heisenberg algebra defined using structure coefficients. @@ -352,7 +355,7 @@ def __init__(self, R, n): names = tuple(['p%s'%i for i in range(1,n+1)] + ['q%s'%i for i in range(1,n+1)] + ['z']) - FinitelyGeneratedLieAlgebra.__init__(self, R, names=names, index_set=names, + LieAlgebraWithGenerators.__init__(self, R, names=names, index_set=names, category=LieAlgebras(R).FiniteDimensional().WithBasis()) HeisenbergAlgebra_abstract.__init__(self, names) @@ -367,7 +370,7 @@ def _repr_(self): """ return "Heisenberg algebra of rank {0} over {1}".format(self._n, self.base_ring()) -class InfiniteHeisenbergAlgebra(HeisenbergAlgebra_abstract, InfinitelyGeneratedLieAlgebra): +class InfiniteHeisenbergAlgebra(HeisenbergAlgebra_abstract, LieAlgebraWithGenerators): r""" The infinite Heisenberg algebra. @@ -390,7 +393,7 @@ def __init__(self, R): """ S = cartesian_product([PositiveIntegers(), ['p','q']]) cat = LieAlgebras(R).WithBasis() - InfinitelyGeneratedLieAlgebra.__init__(self, R, index_set=S, category=cat) + LieAlgebraWithGenerators.__init__(self, R, index_set=S, category=cat) HeisenbergAlgebra_abstract.__init__(self, S) def _repr_(self): diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index f4e516057b4..19a7c03c2d0 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -23,7 +23,8 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute -#from sage.structure.indexed_generators import IndexedGenerators +from sage.structure.indexed_generators import (IndexedGenerators, + standardize_names_index_set) from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -41,7 +42,6 @@ from sage.rings.infinity import infinity from sage.matrix.matrix_space import MatrixSpace from sage.sets.family import Family, AbstractFamily -from sage.sets.finite_enumerated_set import FiniteEnumeratedSet class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): r""" @@ -241,7 +241,7 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): .. [deGraaf] Willem A. de Graaf. *Lie Algebras: Theory and Algorithms*. North-Holland Mathemtaical Library. (2000). Elsevier Science B.V. - - [Kac]_ + - [Kac]_ Victor Kac, *Infinite dimensional Lie algebras*. - :wikipedia:`Lie_algebra` """ @@ -286,7 +286,7 @@ def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, if isinstance(arg0, dict): if not arg0: - from sage.algebras.lie_algebras.structure_coefficients import AbelianLieAlgebra + from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra return AbelianLieAlgebra(R, names, index_set) elif isinstance(arg0.keys()[0], (list,tuple)): # We assume it is some structure coefficients @@ -326,7 +326,7 @@ def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, " number of generators") if abelian: - from sage.algebras.lie_algebras.structure_coefficients import AbelianLieAlgebra + from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra return AbelianLieAlgebra(R, names, index_set) # Otherwise it is the free Lie algebra @@ -344,101 +344,7 @@ def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, raise NotImplementedError("the free Lie algebra has only been implemented using polynomials in the free algebra, see trac ticket #16823") - @staticmethod - def _standardize_names_index_set(names=None, index_set=None, ngens=None): - """ - Standardize the ``names`` and ``index_set`` for a Lie algebra. - - The method is supposed to return a pair - ``(names', index_set')``, where ``names'`` is either - ``None`` or a tuple of strings, and where ``index_set'`` - is a finite enumerated set. (The purpose of - ``index_set'`` is to index the basis elements or the - generators of some Lie algebra; the strings in - ``names'``, when they exist, are used for printing these - indices.) - - .. TODO:: - - As far as I understand, the optional parameter ``ngens`` - is only used to raise errors when it is wrong. There is - no automatic numbering like "if ``names`` is a string - with no commas and ``ngens`` is not ``None``, then set - ``names = [names + str(i) for i in range(ngens)]``". Do - we need this parameter then? - - .. TODO:: - - This function could likely be generalized for any parent - inheriting from :class:`IndexedGenerators` and (potentially) - having ``names``. Should this method be moved to - :class:`IndexedGenerators`? - - TESTS:: - - sage: LieAlgebra._standardize_names_index_set('x,y') - (('x', 'y'), {'x', 'y'}) - sage: LieAlgebra._standardize_names_index_set(['x','y']) - (('x', 'y'), {'x', 'y'}) - sage: LieAlgebra._standardize_names_index_set(['x','y'], ['a','b']) - (('x', 'y'), {'a', 'b'}) - sage: LieAlgebra._standardize_names_index_set('x,y', ngens=2) - (('x', 'y'), {'x', 'y'}) - sage: LieAlgebra._standardize_names_index_set(index_set=['a','b'], ngens=2) - (None, {'a', 'b'}) - - sage: LieAlgebra._standardize_names_index_set() - Traceback (most recent call last): - ... - ValueError: either the names of the generators or the index set must be specified - sage: LieAlgebra._standardize_names_index_set(['x'], ['a', 'b']) - Traceback (most recent call last): - ... - ValueError: the number of names must equal the size of the indexing set - sage: LieAlgebra._standardize_names_index_set('x,y', ['a']) - Traceback (most recent call last): - ... - ValueError: the number of names must equal the size of the indexing set - sage: LieAlgebra._standardize_names_index_set('x,y,z', ngens=2) - Traceback (most recent call last): - ... - ValueError: the number of names must equal the number of generators - sage: LieAlgebra._standardize_names_index_set(index_set=['a'], ngens=2) - Traceback (most recent call last): - ... - ValueError: the size of the indexing set must equal the number of generators - """ - if isinstance(names, str): - names = tuple(names.split(',')) - elif names is not None: - names = tuple(names) - - if index_set is None: - if names is None: - raise ValueError("either the names of the generators" - " or the index set must be specified") - # If only the names are specified, then we make the indexing set - # be the names - index_set = tuple(names) - - if isinstance(index_set, (tuple, list)): - index_set = FiniteEnumeratedSet(index_set) - - if names is not None: - if len(names) != index_set.cardinality(): - raise ValueError("the number of names must equal" - " the size of the indexing set") - if ngens is not None and len(names) != ngens: - raise ValueError("the number of names must equal the number of generators") - elif ngens is not None and index_set.cardinality() != ngens: - raise ValueError("the size of the indexing set must equal" - " the number of generators") - - return names, index_set - - # TODO: Should this inherit from IndexedGenerators or should this - # be a subclass? - def __init__(self, R, names=None, index_set=None, category=None): + def __init__(self, R, names=None, category=None): """ The Lie algebra. @@ -448,8 +354,6 @@ def __init__(self, R, names=None, index_set=None, category=None): - ``names`` -- (optional) the names of the generators - - ``index_set`` -- (optional) the indexing set - - ``category`` -- the category of the Lie algebra; the default is the category of Lie algebras over ``R`` @@ -460,8 +364,6 @@ def __init__(self, R, names=None, index_set=None, category=None): Category of finite dimensional lie algebras with basis over Rational Field """ category = LieAlgebras(R).or_subcategory(category) - - self._indices = index_set Parent.__init__(self, base=R, names=names, category=category) def _element_constructor_(self, x): @@ -557,20 +459,6 @@ def zero(self): """ return self.element_class(self, {}) - # TODO: Find a better place for this method? - # TODO: Use IndexedGenerators? - def indices(self): - """ - Return the indices of the basis of ``self``. - - EXAMPLES:: - - sage: L. = LieAlgebra(QQ, representation="polynomial") - sage: L.indices() - {'x', 'y'} - """ - return self._indices - # The following methods should belong to ModulesWithBasis? def _from_dict(self, d, coerce=False, remove_zeros=True): """ @@ -632,6 +520,58 @@ def term(self, i, c=None): c = self.base_ring()(c) return self.element_class(self, {i: c}) + def get_order(self): + """ + Return an ordering of the basis indices. + + .. TODO:: + + Remove this method and in :class:`CombinatorialFreeModule` + in favor of a method in the category of (finite dimensional) + modules with basis. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {}) + sage: L.get_order() + ('x', 'y') + """ + try: + return self._basis_ordering + except AttributeError: + raise ValueError("the Lie algebra is not finite dimensional with a basis") + + #Element = LieAlgebraElement # Default for all Lie algebras + +class LieAlgebraWithGenerators(LieAlgebra): + """ + A Lie algebra with distinguished generators. + """ + def __init__(self, R, names=None, index_set=None, category=None, prefix='L', **kwds): + """ + The Lie algebra. + + INPUT: + + - ``R`` -- the base ring + - ``names`` -- (optional) the names of the generators + - ``index_set`` -- (optional) the indexing set + - ``category`` -- the category of the Lie algebra; the default is the + category of Lie algebras over ``R`` + - ``prefix`` -- (optional) the prefix for the generator representation + - any keyword accepted by + :class:`~sage.structure.indexed_generators.IndexedGenerators` + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, abelian=True) + sage: L.category() + Category of finite dimensional lie algebras with basis over Rational Field + """ + self._indices = index_set + LieAlgebra.__init__(self, R, names, category) + + @cached_method def lie_algebra_generators(self): """ Return the generators of ``self`` as a Lie algebra. @@ -657,8 +597,6 @@ def gens(self): (x, y) """ G = self.lie_algebra_generators() - if G.cardinality() == float('inf'): - return G try: return tuple(G[i] for i in self.variable_names()) except (KeyError, IndexError): @@ -676,34 +614,23 @@ def gen(self, i): sage: L.gen(0) x """ - return tuple(self.gens())[i] + return self.gens()[i] - def get_order(self): + def indices(self): """ - Return an ordering of the basis indices. - - .. TODO:: - - Remove this method and in :class:`CombinatorialFreeModule` - in favor of a method in the category of (finite dimensional) - modules with basis. + Return the indices of ``self``. EXAMPLES:: - sage: L. = LieAlgebra(QQ, {}) - sage: L.get_order() - ('x', 'y') + sage: L. = LieAlgebra(QQ, representation="polynomial") + sage: F.indices() + {'x', 'y'} """ - try: - return self._basis_ordering - except AttributeError: - raise ValueError("the Lie algebra is not finite dimensional with a basis") - - Element = LieAlgebraElement # Default for all Lie algebras + return self._indices -class FinitelyGeneratedLieAlgebra(LieAlgebra): +class FinitelyGeneratedLieAlgebra(LieAlgebraWithGenerators): r""" - An finitely generated Lie algebra. + A finitely generated Lie algebra. """ def __init__(self, R, names=None, index_set=None, category=None): """ @@ -725,7 +652,7 @@ def __init__(self, R, names=None, index_set=None, category=None): sage: L.category() Category of finite dimensional lie algebras with basis over Rational Field """ - LieAlgebra.__init__(self, R, names, index_set, category) + LieAlgebraWithGenerators.__init__(self, R, names, index_set, category) self.__ngens = len(self._indices) def _repr_(self): @@ -769,7 +696,7 @@ def _an_element_(self): """ return self.sum(self.lie_algebra_generators()) -class InfinitelyGeneratedLieAlgebra(LieAlgebra): +class InfinitelyGeneratedLieAlgebra(LieAlgebraWithGenerators): r""" An infinitely generated Lie algebra. """ @@ -785,19 +712,21 @@ def _an_element_(self): """ return self.lie_algebra_generators()[self._indices.an_element()] - def dimension(self): - r""" - Return the dimension of ``self``, which is `\infty`. - - EXAMPLES:: - - sage: L = lie_algebras.Heisenberg(QQ, oo) - sage: L.dimension() - +Infinity - """ - return infinity +# Do we want this to return lie_algebra_generators()? Perhaps in the category? +# def gens(self): +# """ +# Return a tuple whose entries are the generators for this +# object, in some order. +# +# EXAMPLES:: +# +# sage: L. = LieAlgebra(QQ, abelian=True) +# sage: L.gens() +# (x, y) +# """ +# return self.lie_algebra_generators() -class LieAlgebraFromAssociative(LieAlgebra): +class LieAlgebraFromAssociative(LieAlgebraWithGenerators): """ A Lie algebra whose elements are from an associative algebra and whose bracket is the commutator. @@ -957,7 +886,7 @@ def __classcall_private__(cls, A, gens=None, names=None, index_set=None, # Make sure all the generators have the same parent of A gens = tuple([A(g) for g in gens]) - names, index_set = LieAlgebra._standardize_names_index_set(names, index_set, ngens) + names, index_set = standardize_names_index_set(names, index_set, ngens) if isinstance(A, MatrixSpace): if gens is not None: @@ -997,7 +926,7 @@ def __init__(self, A, gens=None, names=None, index_set=None, category=None): if 'WithBasis' in self._assoc.category().axioms() and gens is None: category = category.WithBasis() - LieAlgebra.__init__(self, R, names, index_set, category) + LieAlgebraWithGenerators.__init__(self, R, names, index_set, category) if isinstance(gens, tuple): # This guarantees that the generators have a specified ordering @@ -1252,7 +1181,7 @@ def _bracket_(self, rhs): def lift_associative(self): """ Lift ``self`` to the ambient associative algebra (which - might be larger than the universal envelopting algebra). + might be smaller than the universal enveloping algebra). EXAMPLES:: @@ -1287,7 +1216,6 @@ def monomial_coefficients(self, copy=True): """ if self.parent()._gens is not None: raise NotImplementedError("the basis is not defined") - # Copy is ignored until #18066 is merged or a dependency return self.value.monomial_coefficients(copy) class LiftMorphismToAssociative(LiftMorphism): diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.py index 9b5bf0c93fe..fcbf6840653 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.py @@ -63,7 +63,7 @@ def __mul__(self, y): EXAMPLES:: - sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}}) + sage: L. = LieAlgebra(QQ, {('x','y'): {'z':1}}) sage: y*x x*y - z """ @@ -242,6 +242,20 @@ def _latex_(self): from sage.misc.latex import latex return latex(self.value) + def _ascii_art_(self): + """ + Return an ascii art representation of ``self``. + """ + from sage.typeset.ascii_art import ascii_art + return ascii_art(self.value) + + def _unicode_art_(self): + """ + Return a unicode art representation of ``self``. + """ + from sage.typeset.unicode_art import unicode_art + return unicode_art(self.value) + def _add_(self, rhs): """ Add ``self`` and ``rhs``. @@ -387,6 +401,7 @@ def __getitem__(self, i): """ return self.value.__getitem__(i) +# TODO: Also used for vectors, find a better name class LieAlgebraMatrixWrapper(LieAlgebraElementWrapper): def __init__(self, parent, value): """ diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index ca45806cf33..13fdaab0ebd 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -22,19 +22,19 @@ #***************************************************************************** #from copy import copy -#from sage.misc.cachefunc import cached_method +from sage.misc.cachefunc import cached_method #from sage.misc.lazy_attribute import lazy_attribute -#from sage.misc.misc import repr_lincomb -from sage.structure.indexed_generators import IndexedGenerators +from sage.misc.misc import repr_lincomb +from sage.structure.indexed_generators import (IndexedGenerators, + standardize_names_index_set) #from sage.structure.parent import Parent #from sage.structure.unique_representation import UniqueRepresentation -#from sage.structure.element_wrapper import ElementWrapper #from sage.categories.algebras import Algebras from sage.categories.lie_algebras import LieAlgebras #from sage.algebras.free_algebra import FreeAlgebra -from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement +from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraMatrixWrapper from sage.algebras.lie_algebras.lie_algebra import LieAlgebra, FinitelyGeneratedLieAlgebra #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra #from sage.algebras.lie_algebras.ideal import LieAlgebraIdeal @@ -92,7 +92,7 @@ class LieAlgebraWithStructureCoefficients(FinitelyGeneratedLieAlgebra, IndexedGe We create the Lie algebra of `\QQ^3` under the Lie bracket defined by `\times` (cross-product):: - sage: L = LieAlgebra(QQ, 'x,y,z', {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) + sage: L = LieAlgebra(QQ, 'x,y,z', {('x','y'): {'z':1}, ('y','z'): {'x':1}, ('z','x'): {'y':1}}) sage: (x,y,z) = L.gens() sage: L.bracket(x, y) z @@ -108,6 +108,12 @@ class LieAlgebraWithStructureCoefficients(FinitelyGeneratedLieAlgebra, IndexedGe sage: TestSuite(Fake).run() Failure in _test_jacobi_identity: ... + + Old tests !!!!!placeholder for now!!!!!:: + + sage: L = LieAlgebra(QQ, 'x,y', {('x','y'):{'x':1}}) + sage: L.basis() + Finite family {'y': y, 'x': x} """ @staticmethod def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, **kwds): @@ -116,39 +122,45 @@ def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, **kwds): EXAMPLES:: - sage: L1 = LieAlgebra(QQ, 'x,y', {('x','y'):{'x':1}}) - sage: L2 = LieAlgebra(QQ, 'x,y', {('y','x'):{'x':-1}}) + sage: L1 = LieAlgebra(QQ, 'x,y', {('x','y'): {'x':1}}) + sage: L2 = LieAlgebra(QQ, 'x,y', {('y','x'): {'x':-1}}) sage: L1 is L2 True Check that we convert names to the indexing set:: - sage: L = LieAlgebra(QQ, 'x,y,z', {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}, index_set=range(3)) + sage: L = LieAlgebra(QQ, 'x,y,z', {('x','y'): {'z':1}, ('y','z'): {'x':1}, ('z','x'): {'y':1}}, index_set=range(3)) sage: (x,y,z) = L.gens() sage: L[x,y] L[2] """ - names, index_set = LieAlgebra._standardize_names_index_set(names, index_set) + names, index_set = standardize_names_index_set(names, index_set) - # Make sure the structure coefficients are given by the indexing set + # Make sure the structure coefficients are given by the index set if names is not None and names != tuple(index_set): d = {x: index_set[i] for i,x in enumerate(names)} get_pairs = lambda X: X.items() if isinstance(X, dict) else X - s_coeff = {(d[k[0]], d[k[1]]): [(d[x], y) for x,y in get_pairs(s_coeff[k])] - for k in s_coeff} - - s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff(s_coeff) + try: + s_coeff = {(d[k[0]], d[k[1]]): [(d[x], y) for x,y in get_pairs(s_coeff[k])] + for k in s_coeff} + except KeyError: + # At this point we assume they are given by the index set + pass + + s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff(s_coeff, index_set) if s_coeff.cardinality() == 0: + from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra return AbelianLieAlgebra(R, names, index_set, **kwds) if (names is None and len(index_set) <= 1) or len(names) <= 1: + from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra return AbelianLieAlgebra(R, names, index_set, **kwds) return super(LieAlgebraWithStructureCoefficients, cls).__classcall__( cls, R, s_coeff, names, index_set, **kwds) @staticmethod - def _standardize_s_coeff(s_coeff): + def _standardize_s_coeff(s_coeff, index_set): """ Helper function to standardize ``s_coeff`` into the appropriate form (dictionary indexed by pairs, whose values are dictionaries). @@ -160,13 +172,15 @@ def _standardize_s_coeff(s_coeff): sage: from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients sage: d = {('y','x'): {'x':-1}} - sage: LieAlgebraWithStructureCoefficients._standardize_s_coeff(d) + sage: LieAlgebraWithStructureCoefficients._standardize_s_coeff(d, ('x', 'y')) Finite family {('x', 'y'): (('x', 1),)} """ # Try to handle infinite basis (once/if supported) #if isinstance(s_coeff, AbstractFamily) and s_coeff.cardinality() == infinity: # return s_coeff + index_to_pos = {k: i for i,k in enumerate(index_set)} + sc = {} # Make sure the first gen is smaller than the second in each key for k in s_coeff.keys(): @@ -174,24 +188,22 @@ def _standardize_s_coeff(s_coeff): if isinstance(v, dict): v = v.items() - if k[0] > k[1]: + if index_to_pos[k[0]] > index_to_pos[k[1]]: key = (k[1], k[0]) vals = tuple((g, -val) for g, val in v if val != 0) else: - if not k[0] < k[1]: + if not index_to_pos[k[0]] < index_to_pos[k[1]]: if k[0] == k[1]: if not all(val == 0 for g, val in v): raise ValueError("elements {} are equal but their bracket is not set to 0".format(k)) continue - if not k[0] <= k[1]: - raise ValueError("elements {} are not comparable".format(k)) key = tuple(k) vals = tuple((g, val) for g, val in v if val != 0) if key in sc.keys() and sorted(sc[key]) != sorted(vals): raise ValueError("two distinct values given for one and the same bracket") - if len(vals) > 0: + if vals: sc[key] = vals return Family(sc) @@ -218,39 +230,42 @@ def __init__(self, R, s_coeff, names, index_set, category=None, prefix=None, if string_quotes is None: string_quotes = default + #self._pos_to_index = dict(enumerate(index_set)) + self._index_to_pos = {k: i for i,k in enumerate(index_set)} + if "sorting_key" not in kwds: + kwds["sorting_key"] = self._index_to_pos.__getitem__ + cat = LieAlgebras(R).WithBasis().FiniteDimensional().or_subcategory(category) FinitelyGeneratedLieAlgebra.__init__(self, R, names, index_set, cat) IndexedGenerators.__init__(self, self._indices, prefix=prefix, bracket=bracket, latex_bracket=latex_bracket, string_quotes=string_quotes, **kwds) + self._M = FreeModule(R, len(index_set)) + # Transform the values in the structure coefficients to elements - self._s_coeff = Family({k: self._from_dict(dict(s_coeff[k])) - for k in s_coeff.keys()}) + def to_vector(tuples): + vec = [R.zero()]*len(index_set) + for k,c in tuples: + vec[self._index_to_pos[k]] = c + vec = self._M(vec) + vec.set_immutable() + return vec + self._s_coeff = {(self._index_to_pos[k[0]], self._index_to_pos[k[1]]): + to_vector(s_coeff[k]) + for k in s_coeff.keys()} # For compatibility with CombinatorialFreeModuleElement _repr_term = IndexedGenerators._repr_generator _latex_term = IndexedGenerators._latex_generator - def basis(self): - """ - Return the basis of ``self``. - - EXAMPLES:: - - sage: L = LieAlgebra(QQ, 'x,y', {('x','y'):{'x':1}}) - sage: L.basis() - Finite family {'y': y, 'x': x} - """ - return Family(self._indices, self.monomial) - def structure_coefficients(self, include_zeros=False): """ Return the dictonary of structure coefficients of ``self``. EXAMPLES:: - sage: L = LieAlgebra(QQ, 'x,y,z', {('x','y'):{'x':1}}) + sage: L = LieAlgebra(QQ, 'x,y,z', {('x','y'): {'x':1}}) sage: L.structure_coefficients() Finite family {('x', 'y'): x} sage: S = L.structure_coefficients(True); S @@ -259,17 +274,16 @@ def structure_coefficients(self, include_zeros=False): True """ if not include_zeros: - return self._s_coeff + pos_to_index = dict(enumerate(self._indices)) + return Family({(pos_to_index[k[0]], pos_to_index[k[1]]): + self.element_class(self, self._s_coeff[k]) + for k in self._s_coeff}) ret = {} - zero = self.zero() - S = dict(self._s_coeff) + zero = self._M.zero() for i,x in enumerate(self._indices): - for y in self._indices[i+1:]: - if x < y: - b = (x, y) - else: - b = (y, x) - ret[b] = S.get(b, zero) + for j, y in enumerate(self._indices[i+1:]): + elt = self._s_coeff.get((i, j+i+1), zero) + ret[x,y] = self.element_class(self, elt) # +i+1 for offset return Family(ret) def dimension(self): @@ -284,34 +298,6 @@ def dimension(self): """ return self.basis().cardinality() - def bracket_on_basis(self, x, y): - """ - Return the Lie bracket ``[x, y]`` of two basis elements - (indexed by) ``x`` and ``y`` where ``x < y``. - - (This particular implementation actually does not require - ``x < y``.) - - EXAMPLES:: - - sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}, ('y','z'):{'x':1}, ('z','x'):{'y':1}}) - sage: L.bracket_on_basis('x', 'y') - z - sage: L.bracket_on_basis('y', 'x') - -z - sage: L.bracket(x + y - z, x - y + z) - -2*y - 2*z - """ - try: - return self._s_coeff[x,y] - except KeyError: - pass - - try: - return -self._s_coeff[y,x] - except KeyError: - return self.zero() - def module(self, sparse=True): """ Return ``self`` as a free module. @@ -324,6 +310,25 @@ def module(self, sparse=True): """ return FreeModule(self.base_ring(), self.dimension(), sparse=sparse) + @cached_method + def zero(self): + """ + Return the element `0` in ``self``. + """ + return self.element_class(self, self._M.zero()) + + def monomial(self, k): + """ + Return the monomial indexed by ``k``. + """ + return self.element_class(self, self._M.basis()[self._index_to_pos[k]]) + + def from_vector(self, v): + """ + Return an element of ``self`` from the vector ``v``. + """ + return self.element_class(self, self._M(v)) + def some_elements(self): """ Return some elements of ``self``. @@ -336,10 +341,78 @@ def some_elements(self): """ return list(self.basis()) + [self.sum(self.basis())] - class Element(LieAlgebraElement): + class Element(LieAlgebraMatrixWrapper): """ An element of a Lie algebra given by structure coefficients. """ + def _sorted_items_for_printing(self): + """ + Return a list of pairs ``(k, c)`` used in printing. + + .. WARNING:: + + The internal representation order is fixed, whereas this + depends on ``"sorting_key"`` print option as it is used + only for printing. + """ + print_options = self.parent().print_options() + pos_to_index = dict(enumerate(self.parent()._indices)) + v = [(pos_to_index[k], c) for k,c in self.value.iteritems()] + try: + v.sort(key=lambda monomial_coeff: + print_options['sorting_key'](monomial_coeff[0]), + reverse=print_options['sorting_reverse']) + except Exception: # Sorting the output is a plus, but if we can't, no big deal + pass + return v + + def _repr_(self): + """ + EXAMPLES:: + """ + return repr_lincomb(self._sorted_items_for_printing(), + scalar_mult=self.parent()._print_options['scalar_mult'], + repr_monomial=self.parent()._repr_generator, + strip_one=True) + + def _latex_(self): + """ + EXAMPLES:: + """ + return repr_lincomb(self._sorted_items_for_printing(), + scalar_mult=self.parent()._print_options['scalar_mult'], + latex_scalar_mult=self.parent()._print_options['latex_scalar_mult'], + repr_monomial=self.parent()._latex_term, + is_latex=True, strip_one=True) + + def _bracket_(self, other): + """ + Return the Lie bracket ``[self, other]``. + + sage: L. = LieAlgebra(QQ, {('x','y'): {'z':1}, ('y','z'): {'x':1}, ('z','x'): {'y':1}}) + sage: L.bracket(x, y) + z + sage: L.bracket(y, x) + -z + sage: L.bracket(x + y - z, x - y + z) + -2*y - 2*z + """ + P = self.parent() + s_coeff = P._s_coeff + d = P.dimension() + ret = P._M.zero() + for i1,c1 in enumerate(self.value): + if not c1: + pass + for i2,c2 in enumerate(other.value): + if not c2: + pass + if (i1, i2) in s_coeff: + ret += c1 * c2 * s_coeff[i1, i2] + elif (i2, i1) in s_coeff: + ret -= c1 * c2 * s_coeff[i2, i1] + return type(self)(P, ret) + def to_vector(self): """ Return ``self`` as a vector. @@ -351,109 +424,23 @@ def to_vector(self): sage: a.to_vector() (1, 3, -1/2) """ - V = self.parent().module() - return V([self[k] for k in self.parent()._ordered_indices]) - -class AbelianLieAlgebra(LieAlgebraWithStructureCoefficients): - r""" - An abelian Lie algebra. - - A Lie algebra `\mathfrak{g}` is abelian if `[x, y] = 0` for all - `x, y \in \mathfrak{g}`. - - EXAMPLES:: - - sage: L. = LieAlgebra(QQ, abelian=True) - sage: L.bracket(x, y) - 0 - """ - @staticmethod - def __classcall_private__(cls, R, names=None, index_set=None, **kwds): - """ - Normalize input to ensure a unique representation. - - TESTS:: - - sage: L1 = LieAlgebra(QQ, 'x,y', {}) - sage: L2. = LieAlgebra(QQ, abelian=True) - sage: L1 is L2 - True - """ - names, index_set = LieAlgebra._standardize_names_index_set(names, index_set) - return super(AbelianLieAlgebra, cls).__classcall__(cls, R, names, index_set, **kwds) - - def __init__(self, R, names, index_set, **kwds): - """ - Initialize ``self``. - - EXAMPLES:: - - sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) - sage: TestSuite(L).run() - """ - LieAlgebraWithStructureCoefficients.__init__(self, R, Family({}), names, index_set, **kwds) - - def _repr_(self): - """ - Return a string representation of ``self``. - - EXAMPLES:: - - sage: LieAlgebra(QQ, 3, 'x', abelian=True) - Abelian Lie algebra on 3 generators (x0, x1, x2) over Rational Field - """ - gens = self.lie_algebra_generators() - if gens.cardinality() == 1: - return "Abelian Lie algebra on generator {} over {}".format(tuple(gens)[0], self.base_ring()) - return "Abelian Lie algebra on {} generators {} over {}".format( - gens.cardinality(), tuple(gens), self.base_ring()) - - def _construct_UEA(self): - """ - Construct the universal enveloping algebra of ``self``. - - EXAMPLES:: - - sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) - sage: L._construct_UEA() - Multivariate Polynomial Ring in x0, x1, x2 over Rational Field - """ - return PolynomialRing(self.base_ring(), self.variable_names()) - - def is_abelian(self): - """ - Return ``True`` since this is an abelian Lie algebra. + return self.value - EXAMPLES:: - - sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) - sage: L.is_abelian() - True - """ - return True - - def bracket_on_basis(self, x, y): - """ - Return the Lie bracket of basis elements indexed by ``x`` and ``y``. - - EXAMPLES:: + def lift(self): + """ + Return the lift of ``self`` to the universal enveloping algebra. - sage: L. = LieAlgebra(QQ, abelian=True) - sage: L.bracket_on_basis(x.leading_support(), y.leading_support()) - 0 - """ - return self.zero() + EXAMPLES:: + """ + UEA = self.parent().universal_enveloping_algebra() + gens = UEA.gens() + return UEA.sum(c * gens[i] for i, c in self.value.iteritems()) - class Element(LieAlgebraElement): - def _bracket_(self, y): + def monomial_coefficients(self, copy=True): """ - Return the Lie bracket ``[self, y]``. + Return the monomial coefficients of ``self``. EXAMPLES:: - - sage: L. = LieAlgebra(QQ, abelian=True) - sage: L.bracket(x, y) - 0 """ - return self.parent().zero() + return self.value.monomial_coefficients(copy) diff --git a/src/sage/algebras/lie_algebras/virasoro.py b/src/sage/algebras/lie_algebras/virasoro.py index d4410c6a3ab..e6fbd65cf36 100644 --- a/src/sage/algebras/lie_algebras/virasoro.py +++ b/src/sage/algebras/lie_algebras/virasoro.py @@ -28,8 +28,9 @@ from sage.sets.set import Set from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.structure.indexed_generators import IndexedGenerators -#from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement -from sage.algebras.lie_algebras.lie_algebra import InfinitelyGeneratedLieAlgebra, FinitelyGeneratedLieAlgebra +from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement +from sage.algebras.lie_algebras.lie_algebra import (InfinitelyGeneratedLieAlgebra, + FinitelyGeneratedLieAlgebra) class LieAlgebraRegularVectorFields(InfinitelyGeneratedLieAlgebra, IndexedGenerators): r""" @@ -137,6 +138,8 @@ def some_elements(self): """ return [self.monomial(0), self.monomial(2), self.monomial(-2), self.an_element()] + Element = LieAlgebraElement + class WittLieAlgebra_charp(FinitelyGeneratedLieAlgebra, IndexedGenerators): r""" The `p`-Witt Lie algebra over a ring `R` in which @@ -250,7 +253,11 @@ def some_elements(self): sage: L.some_elements() [d[0], d[2], d[3], d[0] + 2*d[1] + d[4]] """ - return [self.monomial(0), self.monomial(2 % self._p), self.monomial((-2) % self._p), self.an_element()] + return [self.monomial(0), self.monomial(2 % self._p), + self.monomial((-2) % self._p), + self.an_element()] + + Element = LieAlgebraElement class VirasoroAlgebra(InfinitelyGeneratedLieAlgebra, IndexedGenerators): r""" @@ -449,3 +456,5 @@ def some_elements(self): d = self.monomial return [d(0), d(2), d(-2), d('c'), self.an_element()] + Element = LieAlgebraElement + 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 4e123ddf8ab..f6261088025 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -368,13 +368,13 @@ def product_space(self, L): K = B.keys() LK = LB.keys() # We echelonize the matrix here + # TODO: Do we want to? b_mat = matrix(A.base_ring(), [A.bracket(B[a], LB[b]).to_vector() for a in K for b in LK]) b_mat.echelonize() r = b_mat.rank() I = A._basis_ordering - gens = [A.element_class(A, {I[i]: v for i,v in row.iteritems()}) - for row in b_mat.rows()[:r]] + gens = [A.from_vector(row) for row in b_mat.rows()[:r]] return A.subalgebra(gens) @cached_method diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index 76d64202150..d1c52dfe25f 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -212,6 +212,8 @@ class ParentMethods: # Return the generators of ``self`` as a Lie algebra. # """ + # TODO: Move this to LieAlgebraElement, cythonize, and use more standard + # coercion framework test (i.e., have_same_parent) def bracket(self, lhs, rhs): """ Return the Lie bracket ``[lhs, rhs]`` after coercing ``lhs`` and diff --git a/src/sage/structure/indexed_generators.py b/src/sage/structure/indexed_generators.py index c61f7c57d99..d127a30e3c0 100644 --- a/src/sage/structure/indexed_generators.py +++ b/src/sage/structure/indexed_generators.py @@ -497,3 +497,89 @@ def _latex_generator(self, m): return left + s + right return "%s_{%s}" % (prefix, s) +def standardize_names_index_set(names=None, index_set=None, ngens=None): + """ + Standardize the ``names`` and ``index_set`` for a Lie algebra. + + OUTPUT: + + A pair ``(names', index_set')``, where ``names'`` is either ``None`` + or a tuple of strings, and where ``index_set'`` is a finite + enumerated set. (The purpose of ``index_set'`` is to index the + generators of some object (e.g., the basis of a module); the strings + in ``names'``, when they exist, are used for printing these indices.) + + TESTS:: + + sage: from sage.structure.indexed_generators import standardize_names_index_set + sage: standardize_names_index_set('x,y') + (('x', 'y'), {'x', 'y'}) + sage: standardize_names_index_set(['x','y']) + (('x', 'y'), {'x', 'y'}) + sage: standardize_names_index_set(['x','y'], ['a','b']) + (('x', 'y'), {'a', 'b'}) + sage: standardize_names_index_set('x,y', ngens=2) + (('x', 'y'), {'x', 'y'}) + sage: standardize_names_index_set(index_set=['a','b'], ngens=2) + (None, {'a', 'b'}) + sage: standardize_names_index_set('x', ngens=3) + (('x0', 'x1', 'x2'), {'x0', 'x1', 'x2'}) + + sage: standardize_names_index_set() + Traceback (most recent call last): + ... + ValueError: either the names of the generators or the index set must be specified + sage: standardize_names_index_set(['x'], ['a', 'b']) + Traceback (most recent call last): + ... + ValueError: the number of names must equal the size of the indexing set + sage: standardize_names_index_set('x,y', ['a']) + Traceback (most recent call last): + ... + ValueError: the number of names must equal the size of the indexing set + sage: standardize_names_index_set('x,y,z', ngens=2) + Traceback (most recent call last): + ... + ValueError: the number of names must equal the number of generators + sage: standardize_names_index_set(index_set=['a'], ngens=2) + Traceback (most recent call last): + ... + ValueError: the size of the indexing set must equal the number of generators + """ + if isinstance(names, str): + names = tuple(names.split(',')) + elif names is not None: + names = tuple(names) + + if names is not None and len(names) == 1 and ngens > 1: + letter = names[0] + names = tuple([letter + str(i) for i in range(ngens)]) + + if index_set is None: + if names is None: + # If neither is specified, we make range(ngens) the index set + if ngens is None: + raise ValueError("the index_set, names, or number of" + " generators must be specified") + index_set = tuple(range(ngens)) + else: + # If only the names are specified, then we make the indexing set + # be the names + index_set = tuple(names) + + if isinstance(index_set, (tuple, list)): + from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + index_set = FiniteEnumeratedSet(index_set) + + if names is not None: + if len(names) != index_set.cardinality(): + raise ValueError("the number of names must equal" + " the size of the indexing set") + if ngens is not None and len(names) != ngens: + raise ValueError("the number of names must equal the number of generators") + elif ngens is not None and index_set.cardinality() != ngens: + raise ValueError("the size of the indexing set must equal" + " the number of generators") + + return (names, index_set) + From cd730d0d851fab88389b89c06719b62cc4129424 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 9 Aug 2016 07:31:55 -0500 Subject: [PATCH 105/223] Fixing universal enveloping algebra code. --- .../lie_algebras/structure_coefficients.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 13fdaab0ebd..65c240eb883 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -413,6 +413,16 @@ def _bracket_(self, other): ret -= c1 * c2 * s_coeff[i2, i1] return type(self)(P, ret) + def __iter__(self): + """ + Iterate over ``self``. + """ + zero = self.base_ring().zero() + I = self.parent()._indices + for i,v in enumerate(self.value): + if v != zero: + yield (I[i], v) + def to_vector(self): """ Return ``self`` as a vector. @@ -441,6 +451,14 @@ def monomial_coefficients(self, copy=True): Return the monomial coefficients of ``self``. EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'z':1}}) + sage: a = 2*x - 3/2*y + z + sage: list(a) + [('x', 2), ('y', -3/2), ('z', 1)] + sage: a = 2*x - 3/2*z + sage: list(a) + [('x', 2), ('z', -3/2)] """ - return self.value.monomial_coefficients(copy) + return {self._indices[i]: v for i,v in self.value.monomial_coefficients()} From 023856768842280d6102ac006b95ca1091c8a7f2 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 9 Aug 2016 09:18:42 -0500 Subject: [PATCH 106/223] Cythonizing the element class. --- src/module_list.py | 3 + .../lie_algebras/lie_algebra_element.pxd | 16 ++ ...bra_element.py => lie_algebra_element.pyx} | 203 +++++++++++++++--- .../lie_algebras/structure_coefficients.py | 104 +-------- 4 files changed, 197 insertions(+), 129 deletions(-) create mode 100644 src/sage/algebras/lie_algebras/lie_algebra_element.pxd rename src/sage/algebras/lie_algebras/{lie_algebra_element.py => lie_algebra_element.pyx} (67%) diff --git a/src/module_list.py b/src/module_list.py index cee71b8978a..da7a5c92ddf 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -190,6 +190,9 @@ def uname_specific(name, value, alternative): language='c++', libraries = ["flint", "gmp", "gmpxx", "m", "ntl"]), + Extension('sage.algebras.lie_algebras.lie_algebra_element', + sources = ["sage/algebras/lie_algebras/lie_algebra_element.pyx"]), + ################################ ## ## sage.arith diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.pxd b/src/sage/algebras/lie_algebras/lie_algebra_element.pxd new file mode 100644 index 00000000000..47c46336c51 --- /dev/null +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.pxd @@ -0,0 +1,16 @@ +from sage.structure.element_wrapper cimport ElementWrapper + +cdef class LieAlgebraElementWrapper(ElementWrapper): + cpdef _add_(self, right) + cpdef _sub_(self, right) + +cdef class LieAlgebraMatrixWrapper(LieAlgebraElementWrapper): + pass + +cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): + cpdef bracket(self, right) + cpdef _bracket_(self, right) + cpdef to_vector(self) + cpdef dict monomial_coefficients(self, bint copy=*) + #cpdef lift(self) + diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.py b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx similarity index 67% rename from src/sage/algebras/lie_algebras/lie_algebra_element.py rename to src/sage/algebras/lie_algebras/lie_algebra_element.pyx index fcbf6840653..aed4d085016 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.py +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx @@ -23,13 +23,14 @@ #from sage.misc.abstract_method import abstract_method #from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall -#from sage.misc.misc import repr_lincomb +from sage.misc.misc import repr_lincomb from copy import copy #from functools import total_ordering #from sage.structure.element import ModuleElement, RingElement, coerce_binop #from sage.structure.sage_object import SageObject from sage.combinat.free_module import CombinatorialFreeModuleElement -from sage.structure.element_wrapper import ElementWrapper +from sage.structure.element cimport have_same_parent, coercion_model +from sage.structure.element_wrapper cimport ElementWrapper # TODO: Have the other classes inherit from this? # TODO: Should this be a mixin class (or moved to the category)? @@ -151,13 +152,14 @@ def list(self): """ return sorted(self._monomial_coefficients.items()) -class LieAlgebraElementWrapper(ElementWrapper): +cdef class LieAlgebraElementWrapper(ElementWrapper): """ Wrap an element as a Lie algebra element. """ - def __eq__(self, rhs): + + def __richcmp__(self, right, int op): """ - Check equality. + Perform a rich comparison. EXAMPLES:: @@ -175,16 +177,8 @@ def __eq__(self, rhs): 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 - """ - if not isinstance(rhs, LieAlgebraElementWrapper): - return self.value == 0 and rhs == 0 - return self.parent() == rhs.parent() and self.value == rhs.value - - def __ne__(self, rhs): - """ - Check non-equality. - EXAMPLES:: + 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)) @@ -200,10 +194,11 @@ def __ne__(self, rhs): 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.zero() == 0 - True - sage: L.zero() != 0 + sage: L.an_element() + 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)) @@ -212,8 +207,27 @@ def __ne__(self, rhs): True sage: L.zero() != 0 False + sage: L.zero() >= 0 + True + sage: L.zero() < 0 + False """ - return not (self == rhs) + if right == self.parent().base_ring().zero(): + if op == 3: # != + return self.__nonzero__() + if op in [1,2,5]: # <=, ==, >= + return not self.__nonzero__() + return False # <, > + if not have_same_parent(self, right): + try: + self, right = coercion_model.canonical_coercion(self, right) + except (TypeError, ValueError): + return op == 3 + if op == 3: # != + return self.value != right.value + if op in [1,2,5]: # <=, ==, >= + return self.value == right.value + return False # <, > def _repr_(self): """ @@ -256,7 +270,13 @@ def _unicode_art_(self): from sage.typeset.unicode_art import unicode_art return unicode_art(self.value) - def _add_(self, rhs): + def __nonzero__(self): + """ + Return if ``self`` is non-zero. + """ + return bool(self.value) + + cpdef _add_(self, right): """ Add ``self`` and ``rhs``. @@ -267,9 +287,9 @@ def _add_(self, rhs): sage: x + y x + y """ - return self.__class__(self.parent(), self.value + rhs.value) + return self.__class__(self.parent(), self.value + right.value) - def _sub_(self, rhs): + cpdef _sub_(self, right): """ Subtract ``self`` and ``rhs``. @@ -280,7 +300,7 @@ def _sub_(self, rhs): sage: x - y x - y """ - return self.__class__(self.parent(), self.value - rhs.value) + return self.__class__(self.parent(), self.value - right.value) # We need to bypass the coercion framework # We let the universal enveloping algebra handle the rest if both @@ -319,7 +339,7 @@ def __mul__(self, x): # Otherwise we lift to the UEA return self.lift() * x - def __div__(self, x, self_on_left=False ): + def __div__(self, x): """ Division by coefficients. @@ -331,9 +351,7 @@ def __div__(self, x, self_on_left=False ): sage: x / 2 1/2*p1 + 1/2*p2 + 1/2*p3 + 1/2*q1 + 1/2*q2 + 1/2*q3 + 1/2*z """ - if self_on_left: - return self * (~x) - return (~x) * self + return self * (~x) def _acted_upon_(self, scalar, self_on_left=False): """ @@ -402,7 +420,7 @@ def __getitem__(self, i): return self.value.__getitem__(i) # TODO: Also used for vectors, find a better name -class LieAlgebraMatrixWrapper(LieAlgebraElementWrapper): +cdef class LieAlgebraMatrixWrapper(LieAlgebraElementWrapper): def __init__(self, parent, value): """ Initialize ``self``. @@ -417,3 +435,134 @@ def __init__(self, parent, value): value.set_immutable() # Make the matrix immutable for hashing LieAlgebraElementWrapper.__init__(self, parent, value) +cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): + """ + An element of a Lie algebra given by structure coefficients. + """ + def _repr_(self): + """ + EXAMPLES:: + """ + return repr_lincomb(self._sorted_items_for_printing(), + scalar_mult=self.parent()._print_options['scalar_mult'], + repr_monomial=self.parent()._repr_generator, + strip_one=True) + + def _latex_(self): + """ + EXAMPLES:: + """ + return repr_lincomb(self._sorted_items_for_printing(), + scalar_mult=self.parent()._print_options['scalar_mult'], + latex_scalar_mult=self.parent()._print_options['latex_scalar_mult'], + repr_monomial=self.parent()._latex_term, + is_latex=True, strip_one=True) + + cpdef bracket(self, right): + """ + Return the Lie bracket ``[self, right]``. + + EXAMPLES:: + + sage: L. = 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 + """ + if not have_same_parent(self, right): + self, right = coercion_model.canonical_coercion(self, right) + return self._bracket_(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. = LieAlgebra(QQ, {('x','y'): {'z':1}, ('y','z'): {'x':1}, ('z','x'): {'y':1}}) + sage: x._bracket_(y) + z + sage: y._bracket_(x) + -z + """ + P = self.parent() + cdef dict s_coeff = P._s_coeff + d = P.dimension() + ret = P._M.zero() + cdef int i1, i2 + for i1,c1 in enumerate(self.value): + if not c1: + pass + for i2,c2 in enumerate(right.value): + if not c2: + pass + if (i1, i2) in s_coeff: + ret += c1 * c2 * s_coeff[i1, i2] + elif (i2, i1) in s_coeff: + ret -= c1 * c2 * s_coeff[i2, i1] + return self.__class__(P, ret) + + def __iter__(self): + """ + Iterate over ``self``. + """ + zero = self.base_ring().zero() + I = self.parent()._indices + cdef int i + for i,v in enumerate(self.value): + if v != zero: + yield (I[i], v) + + cpdef to_vector(self): + """ + Return ``self`` as a vector. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'z':1}}) + sage: a = x + 3*y - z/2 + sage: a.to_vector() + (1, 3, -1/2) + """ + return self.value + + def lift(self): + """ + Return the lift of ``self`` to the universal enveloping algebra. + + EXAMPLES:: + """ + UEA = self.parent().universal_enveloping_algebra() + gens = UEA.gens() + return UEA.sum(c * gens[i] for i, c in self.value.iteritems()) + + cpdef dict monomial_coefficients(self, bint copy=True): + """ + Return the monomial coefficients of ``self``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'z':1}}) + sage: a = 2*x - 3/2*y + z + sage: list(a) + [('x', 2), ('y', -3/2), ('z', 1)] + sage: a = 2*x - 3/2*z + sage: list(a) + [('x', 2), ('z', -3/2)] + """ + I = self.parent()._indices + return {I[i]: v for i,v in self.value.monomial_coefficients()} + + def __getitem__(self, i): + """ + Return the coefficient of the basis element indexed by ``i``. + + EXAMPLES:: + """ + return self.value[self.parent()._indices.index(i)] + diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 65c240eb883..ee748cf8039 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -24,7 +24,6 @@ #from copy import copy from sage.misc.cachefunc import cached_method #from sage.misc.lazy_attribute import lazy_attribute -from sage.misc.misc import repr_lincomb from sage.structure.indexed_generators import (IndexedGenerators, standardize_names_index_set) #from sage.structure.parent import Parent @@ -34,7 +33,7 @@ from sage.categories.lie_algebras import LieAlgebras #from sage.algebras.free_algebra import FreeAlgebra -from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraMatrixWrapper +from sage.algebras.lie_algebras.lie_algebra_element import StructureCoefficientsElement from sage.algebras.lie_algebras.lie_algebra import LieAlgebra, FinitelyGeneratedLieAlgebra #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra #from sage.algebras.lie_algebras.ideal import LieAlgebraIdeal @@ -341,10 +340,7 @@ def some_elements(self): """ return list(self.basis()) + [self.sum(self.basis())] - class Element(LieAlgebraMatrixWrapper): - """ - An element of a Lie algebra given by structure coefficients. - """ + class Element(StructureCoefficientsElement): def _sorted_items_for_printing(self): """ Return a list of pairs ``(k, c)`` used in printing. @@ -366,99 +362,3 @@ def _sorted_items_for_printing(self): pass return v - def _repr_(self): - """ - EXAMPLES:: - """ - return repr_lincomb(self._sorted_items_for_printing(), - scalar_mult=self.parent()._print_options['scalar_mult'], - repr_monomial=self.parent()._repr_generator, - strip_one=True) - - def _latex_(self): - """ - EXAMPLES:: - """ - return repr_lincomb(self._sorted_items_for_printing(), - scalar_mult=self.parent()._print_options['scalar_mult'], - latex_scalar_mult=self.parent()._print_options['latex_scalar_mult'], - repr_monomial=self.parent()._latex_term, - is_latex=True, strip_one=True) - - def _bracket_(self, other): - """ - Return the Lie bracket ``[self, other]``. - - sage: L. = LieAlgebra(QQ, {('x','y'): {'z':1}, ('y','z'): {'x':1}, ('z','x'): {'y':1}}) - sage: L.bracket(x, y) - z - sage: L.bracket(y, x) - -z - sage: L.bracket(x + y - z, x - y + z) - -2*y - 2*z - """ - P = self.parent() - s_coeff = P._s_coeff - d = P.dimension() - ret = P._M.zero() - for i1,c1 in enumerate(self.value): - if not c1: - pass - for i2,c2 in enumerate(other.value): - if not c2: - pass - if (i1, i2) in s_coeff: - ret += c1 * c2 * s_coeff[i1, i2] - elif (i2, i1) in s_coeff: - ret -= c1 * c2 * s_coeff[i2, i1] - return type(self)(P, ret) - - def __iter__(self): - """ - Iterate over ``self``. - """ - zero = self.base_ring().zero() - I = self.parent()._indices - for i,v in enumerate(self.value): - if v != zero: - yield (I[i], v) - - def to_vector(self): - """ - Return ``self`` as a vector. - - EXAMPLES:: - - sage: L. = LieAlgebra(QQ, {('x','y'): {'z':1}}) - sage: a = x + 3*y - z/2 - sage: a.to_vector() - (1, 3, -1/2) - """ - return self.value - - def lift(self): - """ - Return the lift of ``self`` to the universal enveloping algebra. - - EXAMPLES:: - """ - UEA = self.parent().universal_enveloping_algebra() - gens = UEA.gens() - return UEA.sum(c * gens[i] for i, c in self.value.iteritems()) - - def monomial_coefficients(self, copy=True): - """ - Return the monomial coefficients of ``self``. - - EXAMPLES:: - - sage: L. = LieAlgebra(QQ, {('x','y'): {'z':1}}) - sage: a = 2*x - 3/2*y + z - sage: list(a) - [('x', 2), ('y', -3/2), ('z', 1)] - sage: a = 2*x - 3/2*z - sage: list(a) - [('x', 2), ('z', -3/2)] - """ - return {self._indices[i]: v for i,v in self.value.monomial_coefficients()} - From 9f33f5d2da42d3c8619a1690d655579884418f2c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 9 Aug 2016 09:23:18 -0500 Subject: [PATCH 107/223] Fixing TestSuite for infinite-dimensional abelian Lie algebras. --- src/sage/algebras/lie_algebras/abelian.py | 8 ++++---- src/sage/algebras/lie_algebras/lie_algebra.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/lie_algebras/abelian.py b/src/sage/algebras/lie_algebras/abelian.py index 1d24a39a738..e5a71f27305 100644 --- a/src/sage/algebras/lie_algebras/abelian.py +++ b/src/sage/algebras/lie_algebras/abelian.py @@ -30,7 +30,8 @@ #from sage.algebras.free_algebra import FreeAlgebra from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement -from sage.algebras.lie_algebras.lie_algebra import LieAlgebra, FinitelyGeneratedLieAlgebra +from sage.algebras.lie_algebras.lie_algebra import (LieAlgebra, FinitelyGeneratedLieAlgebra, + InfinitelyGeneratedLieAlgebra) from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients #from sage.algebras.lie_algebras.ideal import LieAlgebraIdeal #from sage.algebras.lie_algebras.quotient import QuotientLieAlgebra @@ -141,7 +142,7 @@ def _bracket_(self, y): """ return self.parent().zero() -class InfiniteDimensionalAbelianLieAlgebra(LieAlgebra, IndexedGenerators): +class InfiniteDimensionalAbelianLieAlgebra(InfinitelyGeneratedLieAlgebra, IndexedGenerators): r""" An infinite dimensional abelian Lie algebra. @@ -158,7 +159,7 @@ def __init__(self, R, index_set, prefix='L', **kwds): sage: TestSuite(L).run() """ cat = LieAlgebras(R).WithBasis() - LieAlgebra.__init__(self, R, category=cat) + InfinitelyGeneratedLieAlgebra.__init__(self, R, category=cat) IndexedGenerators.__init__(self, index_set, prefix=prefix, **kwds) def dimension(self): @@ -177,4 +178,3 @@ class Element(LieAlgebraElement): def _bracket_(self, other): return self.parent().zero() - diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 19a7c03c2d0..56d39a85f38 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -623,7 +623,7 @@ def indices(self): EXAMPLES:: sage: L. = LieAlgebra(QQ, representation="polynomial") - sage: F.indices() + sage: L.indices() {'x', 'y'} """ return self._indices From 394c3f0eee14dc17129930c459d914c6252e5961 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 9 Aug 2016 09:35:44 -0500 Subject: [PATCH 108/223] Not creating a new vector at every step in _bracket_. --- .../lie_algebras/lie_algebra_element.pyx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx index aed4d085016..c70900ec0b2 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx @@ -156,7 +156,6 @@ cdef class LieAlgebraElementWrapper(ElementWrapper): """ Wrap an element as a Lie algebra element. """ - def __richcmp__(self, right, int op): """ Perform a rich comparison. @@ -493,19 +492,23 @@ cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): P = self.parent() cdef dict s_coeff = P._s_coeff d = P.dimension() - ret = P._M.zero() - cdef int i1, i2 - for i1,c1 in enumerate(self.value): + cdef list ret = [P.base_ring().zero()]*d + cdef int i1, i2, i3 + for i1 in range(d): + c1 = self.value[i1] if not c1: pass - for i2,c2 in enumerate(right.value): + for i2 in range(d): + c2 = right.value[i2] if not c2: pass if (i1, i2) in s_coeff: - ret += c1 * c2 * s_coeff[i1, i2] + for i3 in range(d): + ret[i3] += c1 * c2 * s_coeff[i1, i2][i3] elif (i2, i1) in s_coeff: - ret -= c1 * c2 * s_coeff[i2, i1] - return self.__class__(P, ret) + for i3 in range(d): + ret[i3] -= c1 * c2 * s_coeff[i2, i1][i3] + return self.__class__(P, P._M(ret)) def __iter__(self): """ From 2e6692c257dbcf9b48252adc78adb41feb86de41 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 23 Nov 2016 04:09:48 -0600 Subject: [PATCH 109/223] Doing some fixes and bringing it up to full coverage. --- src/doc/en/reference/references/index.rst | 4 + src/sage/algebras/lie_algebras/abelian.py | 33 ++- src/sage/algebras/lie_algebras/lie_algebra.py | 15 +- .../lie_algebras/lie_algebra_element.pyx | 260 +++++++++--------- .../lie_algebras/structure_coefficients.py | 32 +++ ...ite_dimensional_lie_algebras_with_basis.py | 20 +- src/sage/categories/lie_algebras.py | 43 +-- 7 files changed, 232 insertions(+), 175 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 09cb94087f7..d5133b94ac3 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -467,6 +467,10 @@ REFERENCES: Leçons mathématiques de Bordeaux, vol. 4, pages 259-300, Cassini (2011). +.. [deGraaf2000] Willem A. de Graaf. *Lie Algebras: Theory and Algorithms*. + North-Holland Mathemtaical Library. (2000). + Elsevier Science B.V. + .. [Deo1987a] \V. Deodhar, A splitting criterion for the Bruhat orderings on Coxeter groups. Comm. Algebra, 15:1889-1894, 1987. diff --git a/src/sage/algebras/lie_algebras/abelian.py b/src/sage/algebras/lie_algebras/abelian.py index e5a71f27305..183dfe1268f 100644 --- a/src/sage/algebras/lie_algebras/abelian.py +++ b/src/sage/algebras/lie_algebras/abelian.py @@ -116,7 +116,7 @@ def _construct_UEA(self): def is_abelian(self): """ - Return ``True`` since this is an abelian Lie algebra. + Return ``True`` since ``self`` is an abelian Lie algebra. EXAMPLES:: @@ -174,7 +174,38 @@ def dimension(self): """ return infinity + def is_abelian(self): + """ + Return ``True`` since ``self`` is an abelian Lie algebra. + + EXAMPLES:: + + sage: L = lie_algebras.abelian(QQ, index_set=ZZ) + sage: L.is_abelian() + True + """ + return True + + # abelian => nilpotent => solvable + is_nilpotent = is_solvable = is_abelian + + # For compatibility with CombinatorialFreeModuleElement + _repr_term = IndexedGenerators._repr_generator + _latex_term = IndexedGenerators._latex_generator + class Element(LieAlgebraElement): def _bracket_(self, other): + """ + Return the Lie bracket ``[self, y]``. + + EXAMPLES:: + + sage: L = lie_algebras.abelian(QQ, index_set=ZZ) + sage: B = L.basis() + sage: l1 = B[1] + sage: l5 = B[5] + sage: l1.bracket(l5) + 0 + """ return self.parent().zero() diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 56d39a85f38..115a6516d07 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -36,7 +36,7 @@ from sage.algebras.free_algebra import FreeAlgebra from sage.algebras.lie_algebras.lie_algebra_element import (LieAlgebraElement, - LieAlgebraElementWrapper, LieAlgebraMatrixWrapper) + LieAlgebraElementWrapper, LieAlgebraMatrixWrapper) from sage.rings.all import ZZ from sage.rings.ring import Ring from sage.rings.infinity import infinity @@ -238,11 +238,8 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): REFERENCES: - .. [deGraaf] Willem A. de Graaf. *Lie Algebras: Theory and Algorithms*. - North-Holland Mathemtaical Library. (2000). Elsevier Science B.V. - - - [Kac]_ Victor Kac, *Infinite dimensional Lie algebras*. - + - [deGraaf2000]_ Willem A. de Graaf. *Lie Algebras: Theory and Algorithms*. + - [Kac1990]_ Victor Kac, *Infinite dimensional Lie algebras*. - :wikipedia:`Lie_algebra` """ # This works because it is an abstract base class and this @@ -342,7 +339,9 @@ def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, # subclass with specialized methods for the free Lie algebra return LieAlgebraFromAssociative(F, F.gens(), names=names, index_set=index_set) - raise NotImplementedError("the free Lie algebra has only been implemented using polynomials in the free algebra, see trac ticket #16823") + raise NotImplementedError("the free Lie algebra has only been" + " implemented using polynomials in the" + " free algebra, see trac ticket #16823") def __init__(self, R, names=None, category=None): """ @@ -667,7 +666,7 @@ def _repr_(self): """ if self.__ngens == 1: return "Lie algebra on the generator {0} over {1}".format( - self.gens()[0], self.base_ring()) + self.gen(0), self.base_ring()) return "Lie algebra on {0} generators {1} over {2}".format( self.__ngens, self.gens(), self.base_ring()) diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx index c70900ec0b2..26819867b65 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx @@ -1,13 +1,14 @@ +# -*- coding: utf-8 -*- """ Lie Algebra Elements AUTHORS: -- Travis Scrimshaw (2005-05-04): Initial implementation +- Travis Scrimshaw (2013-05-04): Initial implementation """ #***************************************************************************** -# Copyright (C) 2013 Travis Scrimshaw +# Copyright (C) 2013 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # @@ -21,10 +22,11 @@ AUTHORS: # http://www.gnu.org/licenses/ #***************************************************************************** +from copy import copy + #from sage.misc.abstract_method import abstract_method #from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall from sage.misc.misc import repr_lincomb -from copy import copy #from functools import total_ordering #from sage.structure.element import ModuleElement, RingElement, coerce_binop #from sage.structure.sage_object import SageObject @@ -106,127 +108,68 @@ class LieAlgebraElement(CombinatorialFreeModuleElement): s = UEA.zero() if not self: return s - for t, c in self._monomial_coefficients.iteritems(): + for t, c in self.monomial_coefficients(copy=False).iteritems(): s += c * gen_dict[t] return s - def is_constant(self): - """ - Check if ``self`` is a constant (i.e. zero). - - EXAMPLES:: - - sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}}) - sage: a = x + y - sage: a.is_constant() - False - sage: L.zero().is_constant() - True - """ - return not self._monomial_coefficients - - def dict(self): - """ - Return ``self`` as a dictionary mapping monomials to coefficients. - - EXAMPLES:: - - sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}}) - sage: a = 3*x - 1/2*z - sage: a.dict() - {'x': 3, 'z': -1/2} - """ - return copy(self._monomial_coefficients) - - def list(self): - """ - Return ``self`` as a list of pairs ``(m, c)`` where ``m`` is a - monomial and ``c`` is the coefficient. - - EXAMPLES:: - - sage: L. = LieAlgebra(QQ, {('x','y'):{'z':1}}) - sage: a = 3*x - 1/2*z - sage: a.list() - [('x', 3), ('z', -1/2)] - """ - return sorted(self._monomial_coefficients.items()) - cdef class LieAlgebraElementWrapper(ElementWrapper): """ Wrap an element as a Lie algebra element. - """ - def __richcmp__(self, right, int op): - """ - Perform a rich comparison. - - EXAMPLES:: - 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() - 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 - """ - if right == self.parent().base_ring().zero(): - if op == 3: # != - return self.__nonzero__() - if op in [1,2,5]: # <=, ==, >= - return not self.__nonzero__() - return False # <, > - if not have_same_parent(self, right): - try: - self, right = coercion_model.canonical_coercion(self, right) - except (TypeError, ValueError): - return op == 3 - if op == 3: # != - return self.value != right.value - if op in [1,2,5]: # <=, ==, >= - return self.value == right.value - return False # <, > + 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): """ @@ -258,6 +201,19 @@ cdef class LieAlgebraElementWrapper(ElementWrapper): 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 + **** + ** + ** + * """ from sage.typeset.ascii_art import ascii_art return ascii_art(self.value) @@ -265,6 +221,20 @@ cdef class LieAlgebraElementWrapper(ElementWrapper): 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 + ┌┬┬┬┐ + ├┼┼┴┘ + ├┼┤ + ├┼┘ + └┘ """ from sage.typeset.unicode_art import unicode_art return unicode_art(self.value) @@ -272,6 +242,15 @@ cdef class LieAlgebraElementWrapper(ElementWrapper): def __nonzero__(self): """ Return if ``self`` is non-zero. + + EXAMPLES:: + + sage: R = FreeAlgebra(QQ, 3, 'x,y,z') + sage: L. = LieAlgebra(associative=R.gens()) + sage: bool(L.zero()) + False + sage: bool(x + y) + True """ return bool(self.value) @@ -346,9 +325,9 @@ cdef class LieAlgebraElementWrapper(ElementWrapper): sage: L = lie_algebras.Heisenberg(QQ, 3) sage: x = L.an_element(); x - p1 + p2 + p3 + q1 + q2 + q3 + z + p1 sage: x / 2 - 1/2*p1 + 1/2*p2 + 1/2*p3 + 1/2*q1 + 1/2*q2 + 1/2*q3 + 1/2*z + 1/2*p1 """ return self * (~x) @@ -441,6 +420,10 @@ cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): def _repr_(self): """ EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'x':1}}) + sage: x - 3/2 * y + x - 3/2*y """ return repr_lincomb(self._sorted_items_for_printing(), scalar_mult=self.parent()._print_options['scalar_mult'], @@ -448,8 +431,13 @@ cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): strip_one=True) def _latex_(self): - """ + r""" EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'x':1}}) + sage: elt = x - 3/2 * y + sage: latex(elt) + x - \frac{3}{2}y """ return repr_lincomb(self._sorted_items_for_printing(), scalar_mult=self.parent()._print_options['scalar_mult'], @@ -513,6 +501,13 @@ cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): def __iter__(self): """ Iterate over ``self``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'x':1}}) + sage: elt = x - 3/2 * y + sage: list(elt) + [('x', 1), ('y', -3/2)] """ zero = self.base_ring().zero() I = self.parent()._indices @@ -539,6 +534,14 @@ cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): Return the lift of ``self`` to the universal enveloping algebra. EXAMPLES:: + + sage: L. = 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} """ UEA = self.parent().universal_enveloping_algebra() gens = UEA.gens() @@ -546,26 +549,31 @@ cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): cpdef dict monomial_coefficients(self, bint copy=True): """ - Return the monomial coefficients of ``self``. + Return the monomial coefficients of ``self`` as a dictionary. EXAMPLES:: sage: L. = LieAlgebra(QQ, {('x','y'): {'z':1}}) sage: a = 2*x - 3/2*y + z - sage: list(a) - [('x', 2), ('y', -3/2), ('z', 1)] + sage: a.monomial_coefficients() + {'x': 2, 'y': -3/2, 'z': 1} sage: a = 2*x - 3/2*z - sage: list(a) - [('x', 2), ('z', -3/2)] + sage: a.monomial_coefficients() + {'x': 2, 'z': -3/2} """ I = self.parent()._indices - return {I[i]: v for i,v in self.value.monomial_coefficients()} + return {I[i]: v for i,v in self.value.monomial_coefficients(copy=False).items()} def __getitem__(self, i): """ Return the coefficient of the basis element indexed by ``i``. EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'x':1}}) + sage: elt = x - 3/2 * y + sage: elt['y'] + -3/2 """ return self.value[self.parent()._indices.index(i)] diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index ee748cf8039..97592bf951c 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -313,18 +313,36 @@ def module(self, sparse=True): def zero(self): """ Return the element `0` in ``self``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'z':1}}) + sage: L.zero() + 0 """ return self.element_class(self, self._M.zero()) def monomial(self, k): """ Return the monomial indexed by ``k``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'z':1}}) + sage: L.monomial('x') + x """ return self.element_class(self, self._M.basis()[self._index_to_pos[k]]) def from_vector(self, v): """ Return an element of ``self`` from the vector ``v``. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'z':1}}) + sage: L.from_vector([1, 2, -2]) + x + 2*y - 2*z """ return self.element_class(self, self._M(v)) @@ -350,6 +368,20 @@ def _sorted_items_for_printing(self): The internal representation order is fixed, whereas this depends on ``"sorting_key"`` print option as it is used only for printing. + + EXAMPLES:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'z':1}}) + sage: elt = x + y/2 - z; elt + x + 1/2*y - z + sage: elt._sorted_items_for_printing() + [('x', 1), ('y', 1/2), ('z', -1)] + sage: key = {'x': 2, 'y': 1, 'z': 0} + sage: L.print_options(sorting_key=key.__getitem__) + sage: elt._sorted_items_for_printing() + [('z', -1), ('y', 1/2), ('x', 1)] + sage: elt + -z + 1/2*y + x """ print_options = self.parent().print_options() pos_to_index = dict(enumerate(self.parent()._indices)) 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 f6261088025..b7d59be9f9d 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -240,10 +240,26 @@ def structure_coefficients(self, include_zeros=False): Finite family {} sage: L.structure_coefficients(True) Finite family {(0, 1): (0, 0, 0), (1, 2): (0, 0, 0), (0, 2): (0, 0, 0)} + + :: + + sage: G = SymmetricGroup(3) + sage: S = GroupAlgebra(G, QQ) + sage: L = LieAlgebra(associative=S) + sage: L.structure_coefficients() + Finite family {((1,3,2), (1,3)): (2,3) - (1,2), + ((1,2), (1,2,3)): -(2,3) + (1,3), + ((1,2,3), (1,3)): -(2,3) + (1,2), + ((2,3), (1,3,2)): -(1,2) + (1,3), + ((2,3), (1,3)): -(1,2,3) + (1,3,2), + ((2,3), (1,2)): (1,2,3) - (1,3,2), + ((2,3), (1,2,3)): (1,2) - (1,3), + ((1,2), (1,3,2)): (2,3) - (1,3), + ((1,2), (1,3)): (1,2,3) - (1,3,2)} """ d = {} B = self.basis() - K = B.keys() + K = list(B.keys()) zero = self.zero() for i, x in enumerate(K): for y in K[i + 1:]: @@ -513,7 +529,7 @@ def is_abelian(self): :: - sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: L. = LieAlgebra(QQ, {('x','y'): {'x':1}}) sage: L.is_abelian() False """ diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index d1c52dfe25f..6168486f628 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -57,54 +57,21 @@ class LieAlgebras(Category_over_base_ring): sage: b.bracket(2*a + b) 2*[1, 3, 2] - 2*[3, 2, 1] - sage: A.bracket - - sage: A.bracket(a,b) + sage: A.bracket(a, b) -[1, 3, 2] + [3, 2, 1] - sage: TestSuite(A).run(verbose=True) - running ._test_additive_associativity() . . . pass - running ._test_an_element() . . . pass - running ._test_antisymmetry() . . . pass - running ._test_cardinality() . . . pass - running ._test_category() . . . pass - running ._test_distributivity() . . . pass - running ._test_elements() . . . - Running the test suite of self.an_element() - running ._test_category() . . . pass - running ._test_eq() . . . pass - running ._test_nonzero_equal() . . . pass - running ._test_not_implemented_methods() . . . pass - running ._test_pickling() . . . pass - pass - running ._test_elements_eq_reflexive() . . . pass - running ._test_elements_eq_symmetric() . . . pass - running ._test_elements_eq_transitive() . . . pass - running ._test_elements_neq() . . . pass - running ._test_eq() . . . pass - running ._test_jacobi_identity() . . . pass - running ._test_not_implemented_methods() . . . pass - running ._test_pickling() . . . pass - running ._test_some_elements() . . . pass - running ._test_zero() . . . pass - sage: A.__class__ - - sage: A.element_class - - Please see the source code of `A` (with ``A??``) for how to implement other Lie algebras. TESTS:: - sage: TestSuite(LieAlgebras(QQ)).run() + sage: C = LieAlgebras(QQ) + sage: TestSuite(C).run() + sage: TestSuite(C.example()).run() .. TODO:: - Many of these tests should use Lie algebras which are not the minimal + Many of these tests should use Lie algebras that are not the minimal example and need to be added after :trac:`16820` (and :trac:`16823`). """ @cached_method From af54ea281be2afdd7ddcc47527900ae152c111d3 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 23 Nov 2016 04:17:47 -0600 Subject: [PATCH 110/223] Cleaning up some (currently) unused imports. --- src/sage/algebras/lie_algebras/abelian.py | 24 ++----------------- src/sage/algebras/lie_algebras/lie_algebra.py | 8 +++---- .../lie_algebras/lie_algebra_element.pyx | 5 ---- .../lie_algebras/structure_coefficients.py | 19 +++------------ 4 files changed, 8 insertions(+), 48 deletions(-) diff --git a/src/sage/algebras/lie_algebras/abelian.py b/src/sage/algebras/lie_algebras/abelian.py index 183dfe1268f..32066e25388 100644 --- a/src/sage/algebras/lie_algebras/abelian.py +++ b/src/sage/algebras/lie_algebras/abelian.py @@ -16,35 +16,15 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -#from copy import copy -from sage.misc.cachefunc import cached_method -#from sage.misc.lazy_attribute import lazy_attribute -from sage.misc.misc import repr_lincomb from sage.structure.indexed_generators import (IndexedGenerators, standardize_names_index_set) -#from sage.structure.parent import Parent -#from sage.structure.unique_representation import UniqueRepresentation - -#from sage.categories.algebras import Algebras from sage.categories.lie_algebras import LieAlgebras - -#from sage.algebras.free_algebra import FreeAlgebra from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement -from sage.algebras.lie_algebras.lie_algebra import (LieAlgebra, FinitelyGeneratedLieAlgebra, - InfinitelyGeneratedLieAlgebra) +from sage.algebras.lie_algebras.lie_algebra import InfinitelyGeneratedLieAlgebra from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients -#from sage.algebras.lie_algebras.ideal import LieAlgebraIdeal -#from sage.algebras.lie_algebras.quotient import QuotientLieAlgebra -#from sage.rings.all import ZZ -#from sage.rings.ring import Ring -#from sage.rings.integer import Integer from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.infinity import infinity -#from sage.matrix.matrix_space import MatrixSpace -#from sage.matrix.constructor import matrix -#from sage.modules.free_module_element import vector -from sage.modules.free_module import FreeModule #, span -from sage.sets.family import Family #, AbstractFamily +from sage.sets.family import Family class AbelianLieAlgebra(LieAlgebraWithStructureCoefficients): r""" diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 115a6516d07..f0cbb06fa52 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -23,8 +23,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute -from sage.structure.indexed_generators import (IndexedGenerators, - standardize_names_index_set) +from sage.structure.indexed_generators import standardize_names_index_set from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -35,11 +34,10 @@ from sage.categories.homset import Hom from sage.algebras.free_algebra import FreeAlgebra -from sage.algebras.lie_algebras.lie_algebra_element import (LieAlgebraElement, - LieAlgebraElementWrapper, LieAlgebraMatrixWrapper) +from sage.algebras.lie_algebras.lie_algebra_element import (LieAlgebraElementWrapper, + LieAlgebraMatrixWrapper) from sage.rings.all import ZZ from sage.rings.ring import Ring -from sage.rings.infinity import infinity from sage.matrix.matrix_space import MatrixSpace from sage.sets.family import Family, AbstractFamily diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx index 26819867b65..8db779be8e8 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx @@ -24,12 +24,7 @@ AUTHORS: from copy import copy -#from sage.misc.abstract_method import abstract_method -#from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall from sage.misc.misc import repr_lincomb -#from functools import total_ordering -#from sage.structure.element import ModuleElement, RingElement, coerce_binop -#from sage.structure.sage_object import SageObject from sage.combinat.free_module import CombinatorialFreeModuleElement from sage.structure.element cimport have_same_parent, coercion_model from sage.structure.element_wrapper cimport ElementWrapper diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 97592bf951c..481b309e469 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -21,33 +21,20 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -#from copy import copy from sage.misc.cachefunc import cached_method #from sage.misc.lazy_attribute import lazy_attribute from sage.structure.indexed_generators import (IndexedGenerators, standardize_names_index_set) -#from sage.structure.parent import Parent -#from sage.structure.unique_representation import UniqueRepresentation -#from sage.categories.algebras import Algebras from sage.categories.lie_algebras import LieAlgebras -#from sage.algebras.free_algebra import FreeAlgebra from sage.algebras.lie_algebras.lie_algebra_element import StructureCoefficientsElement -from sage.algebras.lie_algebras.lie_algebra import LieAlgebra, FinitelyGeneratedLieAlgebra +from sage.algebras.lie_algebras.lie_algebra import FinitelyGeneratedLieAlgebra #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra #from sage.algebras.lie_algebras.ideal import LieAlgebraIdeal #from sage.algebras.lie_algebras.quotient import QuotientLieAlgebra -#from sage.rings.all import ZZ -#from sage.rings.ring import Ring -#from sage.rings.integer import Integer -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -#from sage.rings.infinity import infinity -#from sage.matrix.matrix_space import MatrixSpace -#from sage.matrix.constructor import matrix -#from sage.modules.free_module_element import vector -from sage.modules.free_module import FreeModule #, span -from sage.sets.family import Family #, AbstractFamily +from sage.modules.free_module import FreeModule +from sage.sets.family import Family class LieAlgebraWithStructureCoefficients(FinitelyGeneratedLieAlgebra, IndexedGenerators): r""" From d333710a1c9322000b5ae338ca037d3beb647a3e Mon Sep 17 00:00:00 2001 From: TB Date: Wed, 23 Nov 2016 15:51:57 +0200 Subject: [PATCH 111/223] Omission of abelian Lie algebras from doc index, and citation fix. --- src/doc/en/reference/algebras/lie_algebras.rst | 1 + src/sage/algebras/lie_algebras/lie_algebra.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/en/reference/algebras/lie_algebras.rst b/src/doc/en/reference/algebras/lie_algebras.rst index 7e1276edc8e..79bc38bc8a6 100644 --- a/src/doc/en/reference/algebras/lie_algebras.rst +++ b/src/doc/en/reference/algebras/lie_algebras.rst @@ -4,6 +4,7 @@ Lie Algebras .. toctree:: :maxdepth: 2 + sage/algebras/lie_algebras/abelian sage/algebras/lie_algebras/examples sage/algebras/lie_algebras/heisenberg sage/algebras/lie_algebras/lie_algebra diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index f0cbb06fa52..3f767ec477c 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -237,7 +237,7 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): REFERENCES: - [deGraaf2000]_ Willem A. de Graaf. *Lie Algebras: Theory and Algorithms*. - - [Kac1990]_ Victor Kac, *Infinite dimensional Lie algebras*. + - [Ka1990]_ Victor Kac, *Infinite dimensional Lie algebras*. - :wikipedia:`Lie_algebra` """ # This works because it is an abstract base class and this From eff47f6b34d6b9e987912cf8236a895b77596413 Mon Sep 17 00:00:00 2001 From: TB Date: Thu, 24 Nov 2016 11:15:18 +0200 Subject: [PATCH 112/223] standardize_names_index_set: Fix doctest and better documentation --- src/sage/structure/indexed_generators.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sage/structure/indexed_generators.py b/src/sage/structure/indexed_generators.py index d127a30e3c0..3881b634288 100644 --- a/src/sage/structure/indexed_generators.py +++ b/src/sage/structure/indexed_generators.py @@ -503,11 +503,15 @@ def standardize_names_index_set(names=None, index_set=None, ngens=None): OUTPUT: - A pair ``(names', index_set')``, where ``names'`` is either ``None`` - or a tuple of strings, and where ``index_set'`` is a finite - enumerated set. (The purpose of ``index_set'`` is to index the - generators of some object (e.g., the basis of a module); the strings - in ``names'``, when they exist, are used for printing these indices.) + A pair ``(names_std, index_set_std)``, where ``names_std`` is either + ``None`` or a tuple of strings, and where ``index_set_std`` is a finite + enumerated set. + The purpose of ``index_set_std`` is to index the generators of some object + (e.g., the basis of a module); the strings in ``names_std``, when they + exist, are used for printing these indices. The ``ngens`` + + If ``names`` contains exactly one name ``X`` and ``ngens`` is greater than + 1, then ``names_std`` are ``Xi`` for ``i`` in ``range(ngens)``. TESTS:: @@ -528,7 +532,7 @@ def standardize_names_index_set(names=None, index_set=None, ngens=None): sage: standardize_names_index_set() Traceback (most recent call last): ... - ValueError: either the names of the generators or the index set must be specified + ValueError: the index_set, names, or number of generators must be specified sage: standardize_names_index_set(['x'], ['a', 'b']) Traceback (most recent call last): ... From 965c70b1ef515c23bf6ca3be3ff6bf8a9d03c94b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 11 Dec 2016 15:53:37 +0100 Subject: [PATCH 113/223] trac 16820 no more xrange --- src/sage/algebras/lie_algebras/lie_algebra.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 3f767ec477c..dd104910347 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -20,6 +20,7 @@ # # http://www.gnu.org/licenses/ #***************************************************************************** +from six.moves import range from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute @@ -310,12 +311,13 @@ def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, if isinstance(arg0, str): names = arg0 if names is None: - index_set = range(arg1) + index_set = list(range(arg1)) else: if isinstance(names, str): names = tuple(names.split(',')) if arg1 != 1 and len(names) == 1: - names = tuple('{}{}'.format(names[0],i) for i in xrange(arg1)) + names = tuple('{}{}'.format(names[0], i) + for i in range(arg1)) if arg1 != len(names): raise ValueError("the number of names must equal the" " number of generators") @@ -875,7 +877,7 @@ def __classcall_private__(cls, A, gens=None, names=None, index_set=None, gens = tuple(gens) ngens = len(gens) if index_set is None and names is None: - index_set = range(ngens) + index_set = list(range(ngens)) if ngens is not None: if A is None: From 7c92fd10fd6a4557c98e908d5d8051d57c9ac630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 3 Jan 2017 20:25:40 +0100 Subject: [PATCH 114/223] trac 16820 nonzero -> bool --- src/sage/categories/examples/lie_algebras.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py index e1503583496..695bd7c1b1e 100644 --- a/src/sage/categories/examples/lie_algebras.py +++ b/src/sage/categories/examples/lie_algebras.py @@ -193,7 +193,7 @@ def __ne__(self, rhs): """ return not self.__eq__(rhs) - def __nonzero__(self): + def __bool__(self): """ Check non-zero. @@ -207,6 +207,8 @@ def __nonzero__(self): """ return bool(self.value) + __nonzero__ = __bool__ + def _add_(self, rhs): """ Add ``self`` and ``rhs``. From 6a919fa0cb113b648fd79001cd4ef1afbf30a40b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 25 Jan 2017 15:23:58 +0100 Subject: [PATCH 115/223] py3 : removal of cmp() in real_lazy --- src/sage/rings/real_lazy.pyx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/real_lazy.pyx b/src/sage/rings/real_lazy.pyx index 26542878f33..53a033886be 100644 --- a/src/sage/rings/real_lazy.pyx +++ b/src/sage/rings/real_lazy.pyx @@ -29,6 +29,7 @@ from operator import add, sub, mul, div, pow, neg, inv cdef canonical_coercion from sage.structure.element import canonical_coercion from sage.structure.all import parent +from sage.structure.sage_object cimport richcmp import sage.categories.map from sage.categories.morphism cimport Morphism @@ -657,7 +658,7 @@ cdef class LazyFieldElement(FieldElement): """ return self._new_unop(self, inv) - cpdef int _cmp_(self, other) except -2: + cpdef _richcmp_(self, other, int op): """ If things are being wrapped, tries to compare values. That failing, it tries to compare intervals, which may return a false negative. @@ -693,11 +694,11 @@ cdef class LazyFieldElement(FieldElement): try: if isinstance(self, LazyWrapper) and isinstance(other, LazyWrapper): left, right = canonical_coercion((self)._value, (other)._value) - return cmp(left, right) + return richcmp(left, right, op) except TypeError: pass left, right = self.approx(), other.approx() - return cmp(left, right) + return richcmp(left, right, op) def __hash__(self): """ From 7fbcc38dd109416c645e1ed0fee63758c096c208 Mon Sep 17 00:00:00 2001 From: John Cremona Date: Tue, 14 Feb 2017 09:52:50 +0000 Subject: [PATCH 116/223] added a few new polynomial utility methods including symmetric power --- .../rings/polynomial/polynomial_element.pyx | 199 +++++++++++++++++- 1 file changed, 196 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 0d5abf1121f..61e158a4609 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -6162,9 +6162,9 @@ cdef class Polynomial(CommutativeAlgebraElement): ....: for p2 in [5*y^2 - 7, -3*y - 1]: ....: for monic in [True,False]: ....: for op in [operator.add, operator.sub, operator.mul, operator.div]: - ....: pr = p1.composed_op(p2, operator.add, "resultant", monic=monic) - ....: pb = p1.composed_op(p2, operator.add, "BFSS", monic=monic) - ....: assert pr == pb and parent(pr) is parent(pb) + ....: pr = p1.composed_op(p2, op, "resultant", monic=monic) + ....: pb = p1.composed_op(p2, op, "BFSS", monic=monic) + ....: assert ((pr == pb) or ((not monic) and pr == -pb) and (parent(pr) is parent(pb))) REFERENCES: @@ -6279,6 +6279,199 @@ cdef class Polynomial(CommutativeAlgebraElement): else: raise ValueError('algorithm must be "resultant" or "BFSS"') + def compose_power(self, k, algorithm=None, monic=False): + r""" + Return the k'th iterate of the composed product of this + polynomial with itself. + + INPUT: + + - ``k`` - a non-negative integer + + - ``algorithm`` - None (default), "resultant" or "BFSS". See :meth:`.composed_op` + + - ``monic`` - False (default) or True. See :meth:`.composed_op` + + OUTPUT: + + The polynomial of degree $d^k$ where $d$ is the degree, whose + roots are all $k$-fold products of roots of this polynomial. + That is, $f*f*\dots*f$ where this is $f$ and + $f*f=$f.composed_op(f,operator.mul). + + TESTS: + + sage: R. = ZZ[] + sage: x = polygen(R) + sage: f = (x-a)*(x-b)*(x-c) + sage: f.compose_power(2).factor() + (x - c^2) * (x - b^2) * (x - a^2) * (x - b*c)^2 * (x - a*c)^2 * (x - a*b)^2 + + sage: x = polygen(QQ) + sage: f = x^2-2*x+2 + sage: f2 = f.compose_power(2); f2 + x^4 - 4*x^3 + 8*x^2 - 16*x + 16 + sage: f2 == f.composed_op(f,operator.mul) + True + sage: f3 = f.compose_power(3); f3 + x^8 - 8*x^7 + 32*x^6 - 64*x^5 + 128*x^4 - 512*x^3 + 2048*x^2 - 4096*x + 4096 + sage: f3 == f2.composed_op(f,operator.mul) + True + sage: f4 = f.compose_power(4) + sage: f4 == f3.composed_op(f,operator.mul) + True + """ + try: + k = ZZ(k) + except ValueError("Cannot iterate {} times".format(k)): + return self + if k<0: + raise ValueError("Cannot iterate a negative number {} of times".format(k)) + if k==0: + return self.variables()[0]-1 + if k==1: + return self + if k==2: + return self.composed_op(self, operator.mul, algorithm=algorithm, monic=monic) + k2, k1 = k.quo_rem(2) + # recurse to get the k/2 -iterate where k=2*k2+k1: + R = self.compose_power(k2, algorithm=algorithm, monic=monic) + # square: + R = R.composed_op(R, operator.mul, algorithm=algorithm, monic=monic) + # one more factor if k odd: + if k1: + R = R.composed_op(self, operator.mul) + return R + + def power_roots(self, n, monic=False): + r""" + Returns the polynomial whose roots are the $n$th power of the roots of this. + + TESTS:: + + sage: f = cyclotomic_polynomial(30) + sage: f.power_roots(7)==f + True + sage: f.power_roots(6) == cyclotomic_polynomial(5)**2 + True + sage: f.power_roots(10) == cyclotomic_polynomial(3)**4 + True + sage: f.power_roots(15) == cyclotomic_polynomial(2)**8 + True + sage: f.power_roots(30) == cyclotomic_polynomial(1)**8 + True + + sage: x = polygen(QQ) + sage: f = x^2-2*x+2 + sage: f.power_roots(10) + x^2 + 1024 + + When f is monic the output will have leading coefficient + $\pm1$ depending on the degree, but we can force it to be + monic:: + + sage: R. = ZZ[] + sage: x = polygen(R) + sage: f = (x-a)*(x-b)*(x-c) + sage: f.power_roots(3).factor() + (-1) * (x - c^3) * (x - b^3) * (x - a^3) + sage: f.power_roots(3,monic=True).factor() + (x - c^3) * (x - b^3) * (x - a^3) + + """ + u,v = PolynomialRing(self.parent().base_ring(),['u','v']).gens() + R = (u-v**n).resultant(self(v),v) + R = R([self.variables()[0],0]) + if monic: + R = R.monic() + return R + + def symmetric_power(self, k, monic=False): + r""" + Returns the polynomial whose roots are products of $k$th distinct roots of this. + + TESTS:: + + sage: x = polygen(QQ) + sage: f=x^4-x+2 + sage: [f.symmetric_power(k) for k in range(5)] + [x - 1, x^4 - x + 2, x^6 - 2*x^4 - x^3 - 4*x^2 + 8, x^4 - x^3 + 8, x - 2] + + sage: f = x^5-2*x+2 + sage: [f.symmetric_power(k) for k in range(6)] + [x - 1, + x^5 - 2*x + 2, + x^10 + 2*x^8 - 4*x^6 - 8*x^5 - 8*x^4 - 8*x^3 + 16, + x^10 + 4*x^7 - 8*x^6 + 16*x^5 - 16*x^4 + 32*x^2 + 64, + x^5 + 2*x^4 - 16, + x + 2] + + sage: R. = ZZ[] + sage: x = polygen(R) + sage: f = (x-a)*(x-b)*(x-c)*(x-d) + sage: [f.symmetric_power(k).factor() for k in range(5)] + [x - 1, + (-x + d) * (-x + c) * (-x + b) * (-x + a), + (x - c*d) * (x - b*d) * (x - a*d) * (x - b*c) * (x - a*c) * (x - a*b), + (x - b*c*d) * (x - a*c*d) * (x - a*b*d) * (x - a*b*c), + x - a*b*c*d] + """ + try: + k = ZZ(k) + except (ValueError, TypeError): + raise ValueError("Cannot compute k'th symmetric power for k={}".format(k)) + n = self.degree() + if k<0 or k>n: + raise ValueError("Cannot compute k'th symmetric power for k={}".format(k)) + x = self.variables()[0] + if k==0: + return x-1 + if k==1: + if monic: + return self.monic() + return self + c = (-1)**n * self(0) + if k==n: + return x-c + if k>n-k: # use (n-k)'th symmetric power + g = self.symmetric_power(n-k, monic=monic) + from sage.arith.all import binomial + g = ((-x)**binomial(n,k) * g(c/x) / c**binomial(n-1,k)).numerator() + if monic: + g = g.monic() + return g + def star(g,h): + return g.composed_op(h, operator.mul, monic=True) + def rpow(g,n): + return g.power_roots(n, monic=True) + if k==2: + g = (star(self, self) // rpow(self,2)).nth_root(2) + if monic: + g = g.monic() + return g + if k==3: + g = star(self.symmetric_power(2, monic=monic), self) * rpow(self,3) + h = star(rpow(self,2),self) + g = (g // h).nth_root(3) + if monic: + g = g.monic() + return g + + fkn = fkd = self.parent().one() + for j in range(1,k+1): + g = star(rpow(self,j), self.symmetric_power(k-j)) + if j%2: + fkn *= g + else: + fkd *= g + + fk = fkn//fkd + assert fk*fkd==fkn + g = fk.nth_root(k) + if monic: + g = g.monic() + return g + def discriminant(self): r""" Returns the discriminant of self. From bf3ac90966d76545148063063040fa5b8540c04d Mon Sep 17 00:00:00 2001 From: John Cremona Date: Tue, 21 Feb 2017 09:43:39 +0000 Subject: [PATCH 117/223] renamed power_roots() method to adams_operator() --- .../rings/polynomial/polynomial_element.pyx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 61e158a4609..2238de17ead 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -6343,27 +6343,27 @@ cdef class Polynomial(CommutativeAlgebraElement): R = R.composed_op(self, operator.mul) return R - def power_roots(self, n, monic=False): + def adams_operator(self, n, monic=False): r""" Returns the polynomial whose roots are the $n$th power of the roots of this. TESTS:: sage: f = cyclotomic_polynomial(30) - sage: f.power_roots(7)==f + sage: f.adams_operator(7)==f True - sage: f.power_roots(6) == cyclotomic_polynomial(5)**2 + sage: f.adams_operator(6) == cyclotomic_polynomial(5)**2 True - sage: f.power_roots(10) == cyclotomic_polynomial(3)**4 + sage: f.adams_operator(10) == cyclotomic_polynomial(3)**4 True - sage: f.power_roots(15) == cyclotomic_polynomial(2)**8 + sage: f.adams_operator(15) == cyclotomic_polynomial(2)**8 True - sage: f.power_roots(30) == cyclotomic_polynomial(1)**8 + sage: f.adams_operator(30) == cyclotomic_polynomial(1)**8 True sage: x = polygen(QQ) sage: f = x^2-2*x+2 - sage: f.power_roots(10) + sage: f.adams_operator(10) x^2 + 1024 When f is monic the output will have leading coefficient @@ -6373,9 +6373,9 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R. = ZZ[] sage: x = polygen(R) sage: f = (x-a)*(x-b)*(x-c) - sage: f.power_roots(3).factor() + sage: f.adams_operator(3).factor() (-1) * (x - c^3) * (x - b^3) * (x - a^3) - sage: f.power_roots(3,monic=True).factor() + sage: f.adams_operator(3,monic=True).factor() (x - c^3) * (x - b^3) * (x - a^3) """ @@ -6443,7 +6443,7 @@ cdef class Polynomial(CommutativeAlgebraElement): def star(g,h): return g.composed_op(h, operator.mul, monic=True) def rpow(g,n): - return g.power_roots(n, monic=True) + return g.adams_operator(n, monic=True) if k==2: g = (star(self, self) // rpow(self,2)).nth_root(2) if monic: From 904e6ff46367761f4a968c3ccd1f301a2ed3a6ae Mon Sep 17 00:00:00 2001 From: John Cremona Date: Wed, 22 Feb 2017 13:35:49 +0000 Subject: [PATCH 118/223] #22343 changes to _semistable_reducible_primes() for elliptic curves over number fields --- .../elliptic_curves/gal_reps_number_field.py | 234 ++++++++---------- 1 file changed, 103 insertions(+), 131 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py index faf6f8d6dff..af136ad36fd 100644 --- a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py +++ b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py @@ -28,6 +28,7 @@ - Eric Larson (2012-05-28): initial version. - Eric Larson (2014-08-13): added isogeny_bound function. +- John Cremona (2016, 2017): various efficiency improvements to _semistable_reducible_primes REFERENCES: @@ -53,13 +54,12 @@ from sage.structure.sage_object import SageObject from sage.rings.number_field.number_field import NumberField, QuadraticField from sage.schemes.elliptic_curves.cm import cm_j_invariants -from sage.rings.rational_field import QQ from sage.modules.free_module import VectorSpace from sage.rings.finite_rings.finite_field_constructor import GF -from sage.rings.integer import Integer from sage.misc.functional import cyclotomic_polynomial -from sage.arith.all import legendre_symbol +from sage.arith.all import legendre_symbol, primes from sage.sets.set import Set +from sage.rings.all import PolynomialRing, Integer, ZZ, QQ, Infinity class GaloisRepresentation(SageObject): r""" @@ -751,28 +751,6 @@ def _over_numberfield(E): return E -def _tr12(tr, det): - r"""Compute `X^{12} + Y^{12}` given `X + Y` and `X * Y`. - - INPUT: - - - ``tr`` - The value of `X + Y`. - - - ``det`` - The value of `X * Y`. - - OUTPUT: The value of `X^{12} + Y^{12}`. - - EXAMPLES:: - - sage: from sage.schemes.elliptic_curves.gal_reps_number_field import * - sage: X, Y = QQ['X, Y'].gens() - sage: sage.schemes.elliptic_curves.gal_reps_number_field._tr12(X + Y, X * Y) - X^12 + Y^12 - """ - - det3 = det**3 - return ((tr * (tr**2 - 3 * det))**2 - 2 * det3)**2 - 2 * det3**2 - def deg_one_primes_iter(K, principal_only=False): r""" Return an iterator over degree 1 primes of ``K``. @@ -811,14 +789,18 @@ def deg_one_primes_iter(K, principal_only=False): # imaginary quadratic fields have no principal primes of norm < disc / 4 start = K.discriminant().abs() // 4 if principal_only and K.signature() == (0,1) else 2 + K_is_Q = (K==QQ) from sage.arith.misc import primes from sage.rings.infinity import infinity for p in primes(start=start, stop=infinity): - for P in K.primes_above(p, degree=1): - if not principal_only or P.is_principal(): - yield P + if K_is_Q: + yield ZZ.ideal(p) + else: + for P in K.primes_above(p, degree=1): + if not principal_only or P.is_principal(): + yield P -def _semistable_reducible_primes(E): +def _semistable_reducible_primes(E, verbose=False): r"""Find a list containing all semistable primes l unramified in K/QQ for which the Galois image for E could be reducible. @@ -839,9 +821,9 @@ def _semistable_reducible_primes(E): sage: 5 in sage.schemes.elliptic_curves.gal_reps_number_field._semistable_reducible_primes(E) True """ - - E = _over_numberfield(E) + if verbose: print("In _semistable_reducible_primes with E={}".format(E.ainvs())) K = E.base_field() + d = K.degree() deg_one_primes = deg_one_primes_iter(K, principal_only=True) @@ -849,132 +831,123 @@ def _semistable_reducible_primes(E): # We find two primes (of distinct residue characteristics) which are # of degree 1, unramified in K/Q, and at which E has good reduction. - # Both of these primes will give us a nontrivial divisibility constraint + # Each of these primes will give us a nontrivial divisibility constraint # on the exceptional primes l. For both of these primes P, we precompute - # a generator and the trace of Frob_P^12. + # a generator and the characteristic polynomial of Frob_P^12. precomp = [] - last_char = 0 # The residue characteristic of the most recent prime. + last_p = 0 # The residue characteristic of the most recent prime. while len(precomp) < 2: P = next(deg_one_primes) - - # the iterator tests this already - # if not P.is_principal(): - # continue - - det = P.norm() - if det == last_char: - continue - - if P.ramification_index() != 1: - continue - - if E.has_bad_reduction(P): + p = P.norm() + if p != last_p and (d==1 or P.ramification_index() == 1) and E.has_good_reduction(P): + precomp.append(P) + last_p = p + + Px, Py = precomp + x, y = [P.gens_reduced()[0] for P in precomp] + EmodPx = E.reduction(Px) if d>1 else E.reduction(x) + EmodPy = E.reduction(Py) if d>1 else E.reduction(y) + fxpol = EmodPx.frobenius_polynomial() + fypol = EmodPy.frobenius_polynomial() + fx12pol = fxpol.adams_operator(12) # roots are 12th powers of those of fxpol + fy12pol = fypol.adams_operator(12) + px = x.norm() if d>1 else x + py = y.norm() if d>1 else x + Zx = fxpol.parent() + xpol = x.charpoly() if d>1 else Zx([-x,1]) + ypol = y.charpoly() if d>1 else Zx([-y,1]) + + if verbose: print("Finished precomp, x={} (p={}), y={} (p={})".format(x,px,y,py)) + + for w in range(1+d/2): + if verbose: print("w = {}".format(w)) + gx = xpol.symmetric_power(w).adams_operator(12).resultant(fx12pol) + gy = ypol.symmetric_power(w).adams_operator(12).resultant(fy12pol) + if verbose: print("computed gx and gy") + + gxn = Integer(gx.absolute_norm()) if d>1 else gx + gyn = Integer(gy.absolute_norm()) if d>1 else gy + gxyn = gxn.gcd(gyn) + if gxyn: + xprimes = gxyn.prime_factors() + if verbose: print("adding prime factors {} of {} to {}".format(xprimes, gxyn, sorted(bad_primes))) + bad_primes.update(xprimes) + if verbose: print("...done, bad_primes now {}".format(sorted(bad_primes))) continue + else: + if verbose: print("gx and gy both 0!") - tr = E.reduction(P).trace_of_frobenius() - x = P.gens_reduced()[0] - - precomp.append((x, _tr12(tr, det))) - last_char = det - - x, tx = precomp[0] - y, ty = precomp[1] - - Kgal = K.galois_closure('b') - maps = K.embeddings(Kgal) - - for i in range(2 ** (K.degree() - 1)): - ## We iterate through all possible characters. ## - - # Here, if i = i_{l-1} i_{l-2} cdots i_1 i_0 in binary, then i - # corresponds to the character prod sigma_j^{i_j}. - - phi1x = 1 - phi2x = 1 - phi1y = 1 - phi2y = 1 - - # We compute the two algebraic characters at x and y: - for j in range(K.degree()): - if i % 2 == 1: - phi1x *= maps[j](x) - phi1y *= maps[j](y) - else: - phi2x *= maps[j](x) - phi2y *= maps[j](y) - i = int(i/2) - - # Any prime with reducible image must divide both of: - gx = phi1x**12 + phi2x**12 - tx - gy = phi1y**12 + phi2y**12 - ty - - if (gx != 0) or (gy != 0): - for prime in Integer(Kgal.ideal([gx, gy]).norm()).prime_factors(): - bad_primes.add(prime) - - continue ## It is possible that our curve has CM. ## # Our character must be of the form Nm^K_F for an imaginary # quadratic subfield F of K (which is the CM field if E has CM). - # We compute F: - a = (Integer(phi1x + phi2x)**2 - 4 * x.norm()).squarefree_part() + # Note that this can only happen when d is even, w=d/2, and K + # contains (or the Galois closure of K contains?) the + # imaginary quadratic field F = Q(sqrt(a)) which is the + # splitting field of both fx12pol and fy12pol. We compute a + # and relativise K over F: - # See #19229: the name given here, which is not used, should - # not be the name of the generator of the base field. - F = QuadraticField(a, 'gal_rep_nf_sqrt_a') + a = fx12pol.discriminant().squarefree_part() + + # Construct a field isomorphic to K but a relative extension over QQ(sqrt(a)). - # Next, we turn K into relative number field over F. + # See #19229: the names given here, which are not used, should + # not be the name of the generator of the base field. - K = K.relativize(F.embeddings(K)[0], K.variable_name()+'0') - E = E.change_ring(K.structure()[1]) + rootsa = K(a).sqrt(all=True) # otherwise if a is not a square the + # returned result is in the symbolic ring! + try: + roota = rootsa[0] + except IndexError: + raise RuntimeError("error in _semistable_reducible_primes: K={} does not contain sqrt({})".format(K,a)) + K_rel = K.relativize(roota, ['name1','name2']) + iso = K_rel.structure()[1] # an isomorphism from K to K_rel + E_rel = E.change_ring(iso) # same as E but over K_rel - ## We try to find a nontrivial divisibility condition. ## + ## We try again to find a nontrivial divisibility condition. ## + div = 0 patience = 5 * K.absolute_degree() # Number of Frobenius elements to check before suspecting that E # has CM and computing the set of CM j-invariants of K to check. # TODO: Is this the best value for this parameter? - while True: - P = next(deg_one_primes) - - # the iterator tests this already - # if not P.is_principal(): - # continue - - try: - tr = E.change_ring(P.residue_field()).trace_of_frobenius() - except ArithmeticError: # Bad reduction at P. - continue - - x = P.gens_reduced()[0].norm(F) - div = (x**12).trace() - _tr12(tr, x.norm()) - - patience -= 1 - - if div != 0: - # We found our divisibility constraint. - - for prime in Integer(div).prime_factors(): - bad_primes.add(prime) - - # Turn K back into an absolute number field. + while div==0 and patience>0: + P = next(deg_one_primes) # a prime of K not K_rel + while E.has_bad_reduction(P): + P = next(deg_one_primes) + + if verbose: print("trying P = {}...".format(P)) + EmodP = E.reduction(P) + fpol = EmodP.frobenius_polynomial() + if verbose: print("...good reduction, frobenius poly = {}".format(fpol)) + x = iso(P.gens_reduced()[0]).relative_norm() + xpol = x.charpoly().adams_operator(12) + div2 = Integer(xpol.resultant(fpol.adams_operator(12)) // x.norm()**12) + if div2: + div = div2.isqrt() + assert div2==div**2 + if verbose: print("...div = {}".format(div)) + else: + if verbose: print("...div = 0, continuing") + patience -= 1 - E = E.change_ring(K.structure()[0]) - K = K.structure()[0].codomain() + if patience == 0: + # We suspect that E has CM, so we check: + if E.has_cm(): + raise ValueError("In _semistable_reducible_primes, the curve E should not have CM.") - break + assert div != 0 + # We found our divisibility constraint. - if patience == 0: - # We suspect that E has CM, so we check: - f = K.structure()[0] - if f(E.j_invariant()) in cm_j_invariants(f.codomain()): - raise ValueError("The curve E should not have CM.") + xprimes = div.prime_factors() + if verbose: print("...adding prime factors {} of {} to {}...".format(xprimes,div, sorted(bad_primes))) + bad_primes.update(xprimes) + if verbose: print("...done, bad_primes now {}".format(sorted(bad_primes))) L = sorted(bad_primes) return L @@ -1128,4 +1101,3 @@ def _possible_normalizers(E, SA): bad_primes = sorted(bad_primes) return bad_primes - From 533dd93f556d70b92118c1bc04aa2e48d7922805 Mon Sep 17 00:00:00 2001 From: John Cremona Date: Wed, 22 Feb 2017 13:48:44 +0000 Subject: [PATCH 119/223] #22343 new doctest added --- .../schemes/elliptic_curves/gal_reps_number_field.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py index af136ad36fd..6a3d218d92b 100644 --- a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py +++ b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py @@ -820,6 +820,15 @@ def _semistable_reducible_primes(E, verbose=False): sage: E = EllipticCurve([0, -1, 1, -10, -20]) # X_0(11) sage: 5 in sage.schemes.elliptic_curves.gal_reps_number_field._semistable_reducible_primes(E) True + + This example, over a quintic field with Galois group $S_5$, took a + very long time before :trac:`22343`:: + + sage: K. = NumberField(x^5 - 6*x^3 + 8*x - 1) + sage: E = EllipticCurve(K, [a^3 - 2*a, a^4 - 2*a^3 - 4*a^2 + 6*a + 1, a + 1, -a^3 + a + 1, -a]) + sage: from sage.schemes.elliptic_curves.gal_reps_number_field import _semistable_reducible_primes + sage: _semistable_reducible_primes(E) + [2, 5, 53, 1117] """ if verbose: print("In _semistable_reducible_primes with E={}".format(E.ainvs())) K = E.base_field() From 1817af4493beeb4e7af010950dd29d9f1cce7b36 Mon Sep 17 00:00:00 2001 From: John Cremona Date: Sun, 26 Feb 2017 15:16:11 +0000 Subject: [PATCH 120/223] #22343 fix syntax errors in docstrings --- src/sage/rings/polynomial/polynomial_element.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 2238de17ead..8c6c221c3c6 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -6297,9 +6297,9 @@ cdef class Polynomial(CommutativeAlgebraElement): The polynomial of degree $d^k$ where $d$ is the degree, whose roots are all $k$-fold products of roots of this polynomial. That is, $f*f*\dots*f$ where this is $f$ and - $f*f=$f.composed_op(f,operator.mul). + $f*f=$ f.composed_op(f,operator.mul). - TESTS: + TESTS:: sage: R. = ZZ[] sage: x = polygen(R) @@ -6345,7 +6345,7 @@ cdef class Polynomial(CommutativeAlgebraElement): def adams_operator(self, n, monic=False): r""" - Returns the polynomial whose roots are the $n$th power of the roots of this. + Returns the polynomial whose roots are the $n$-th power of the roots of this. TESTS:: @@ -6388,7 +6388,7 @@ cdef class Polynomial(CommutativeAlgebraElement): def symmetric_power(self, k, monic=False): r""" - Returns the polynomial whose roots are products of $k$th distinct roots of this. + Returns the polynomial whose roots are products of $k$-th distinct roots of this. TESTS:: From 20963880dfbc18035cea6159eb13d5c71b0fda59 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Mon, 27 Feb 2017 05:29:49 +0100 Subject: [PATCH 121/223] Added algorithm='sympy' (needs work) and algorithm='giac' (needs info). === Remarks === - replicating the ideas from symbolic_sum in /calculus/calculus.py. - contrary to my comment in the ticket description, giac interface does allow conversion into/back from SR, though instead of `SR(res)`, it is `res = giac(ex)` and `res.sage()`. - however, giac conversion heaviside -> Heaviside does not seem to work (see below). === Done === - corrected (swapped) the s <-> t inside inverse_laplace. Nothing changes from the outside, but now the inverse_laplace? "Signature" corresponds to the expected use, as in `inverse_laplace(1/(s^3+1), s, t)` instead of the (wrong), `inverse_laplace(1/(s^3+1), t, s)`. - added sympy algorithm for the inverse laplace transform, as in: sage: inverse_laplace(exp(-s)/s, s, t, algorithm='sympy') heaviside(t - 1) - added sympy algorithm for the direct laplace transform, as in: sage: laplace(heaviside(t-1), t, s, algorithm='sympy') (e^(-s)/s, 0, True) - added giac algorithm for the inverse/direct laplace transform, but this needs info/work (see below). === Needs work === - the behaviour of algorithm=`sympy` with unevaluated expressions is not the same as with maxima. for instance, sage: inverse_laplace(1, s, t, algorithm='maxima') ilt(1, s, t) but sage: inverse_laplace(1, s, t, algorithm='sympy') raises an AttributeError. - add new examples to the documentation of `laplace` and `inverse_laplace`. - notice that laplace algorithm in sympy returns a tuple (F, a, cond), with F being the Laplace transform, Re(s) > a is the half-plane of convergence, and cond being additional convergence conditions. In this commit, the full tuple is being returned. decide if we want to keep this behaviour. === Needs info === - with algorithm='giac', the Heaviside is not transformed properly. See: sage: inverse_laplace(exp(-s)/s, s, t, algorithm='giac') Heaviside(t-1) notice the upper case in Heaviside, it should be lower case (for instance, we cannot evaluate/doesn't plot). - conversely, sage: laplace(heaviside(t-1), t, s, algorithm='giac') integrate(e^(-s*t)*heaviside(t - 1), t, 0, +Infinity) and this is probably for the same reason (conversion heaviside -> Heaviside). Notice that: sage: giac('laplace(Heaviside(t-1), t, s)') exp(-s)/s does work. --- src/sage/calculus/calculus.py | 69 ++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 5fedf2e850b..1e3e4285273 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -1259,7 +1259,7 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): ################################################################### # Laplace transform ################################################################### -def laplace(ex, t, s): +def laplace(ex, t, s, algorithm='maxima'): r""" Attempts to compute and return the Laplace transform of ``self`` with respect to the variable `t` and @@ -1361,9 +1361,37 @@ def laplace(ex, t, s): """ if not isinstance(ex, (Expression, Function)): ex = SR(ex) - return ex.parent()(ex._maxima_().laplace(var(t), var(s))) -def inverse_laplace(ex, t, s): + if algorithm == 'maxima': + return ex.parent()(ex._maxima_().laplace(var(t), var(s))) + + elif algorithm == 'sympy': + ex, t, s = [expr._sympy_() for expr in (ex, t, s)] + from sympy import laplace_transform + result = laplace_transform(ex, t, s) + if isinstance(result, tuple): + try: + (result, a, cond) = result + return result._sage_(), a, cond + except AttributeError: + raise AttributeError("Unable to convert SymPy result (={}) into" + " Sage".format(result)) + else: + return result + + elif algorithm == 'giac': + ex = "laplace(%s, %s, %s)" % tuple([repr(expr._giac_()) for expr in (ex, t, s)]) + from sage.interfaces.giac import giac + try: + result = giac(ex) + except TypeError: + raise ValueError("Giac cannot make sense of: %s" % ex) + return result.sage() + + else: + raise ValueError("Unknown algorithm: %s" % algorithm) + +def inverse_laplace(ex, s, t, algorithm='maxima'): r""" Attempts to compute the inverse Laplace transform of ``self`` with respect to the variable `t` and @@ -1409,7 +1437,31 @@ def inverse_laplace(ex, t, s): """ if not isinstance(ex, Expression): ex = SR(ex) - return ex.parent()(ex._maxima_().ilt(var(t), var(s))) + + if algorithm == 'maxima': + return ex.parent()(ex._maxima_().ilt(var(s), var(t))) + + elif algorithm == 'sympy': + ex, s, t = [expr._sympy_() for expr in (ex, s, t)] + from sympy import inverse_laplace_transform + result = inverse_laplace_transform(ex, s, t) + try: + return result._sage_() + except AttributeError: + raise AttributeError("Unable to convert SymPy result (={}) into" + " Sage".format(result)) + + elif algorithm == 'giac': + ex = "invlaplace(%s, %s, %s)" % tuple([repr(expr._giac_()) for expr in (ex, s, t)]) + from sage.interfaces.giac import giac + try: + result = giac(ex) + except TypeError: + raise ValueError("Giac cannot make sense of: %s" % ex) + return result.sage() + + else: + raise ValueError("Unknown algorithm: %s" % algorithm) ################################################################### # symbolic evaluation "at" a point @@ -1776,15 +1828,15 @@ def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima): 2 sage: var('my_new_var').full_simplify() my_new_var - + ODE solution constants are treated differently (:trac:`16007`):: - + sage: from sage.calculus.calculus import symbolic_expression_from_maxima_string as sefms sage: sefms('%k1*x + %k2*y + %c') _K1*x + _K2*y + _C Check that some hypothetical variables don't end up as special constants (:trac:`6882`):: - + sage: from sage.calculus.calculus import symbolic_expression_from_maxima_string as sefms sage: sefms('%i')^2 -1 @@ -1848,7 +1900,7 @@ def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima): #we apply the square-bracket replacing patterns repeatedly #to ensure that nested brackets get handled (from inside to out) while True: - olds = s + olds = s s = polylog_ex.sub('polylog(\\1,', s) s = maxima_polygamma.sub('psi(\g<1>,', s) # this replaces psi[n](foo) with psi(n,foo), ensuring that derivatives of the digamma function are parsed properly below if s == olds: break @@ -2108,4 +2160,3 @@ def _find_Mvar(name): make_float = lambda x: SR(RealDoubleElement(x)), make_var = _find_Mvar, make_function = _find_func) - From 7bda1a49c73c19c3b18eb9fb0b07ece5f6323f65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 2 Mar 2017 17:33:13 +0100 Subject: [PATCH 122/223] trac 16820 get rid of some .iteritems in py files --- src/sage/algebras/lie_algebras/lie_algebra.py | 5 +++-- src/sage/algebras/lie_algebras/structure_coefficients.py | 3 ++- .../examples/finite_dimensional_lie_algebras_with_basis.py | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index dd104910347..aba527e6383 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -21,6 +21,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** from six.moves import range +from six import iteritems from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute @@ -486,9 +487,9 @@ def _from_dict(self, d, coerce=False, remove_zeros=True): assert isinstance(d, dict) if coerce: R = self.base_ring() - d = {key: R(coeff) for key,coeff in d.iteritems()} + d = {key: R(coeff) for key,coeff in iteritems(d)} if remove_zeros: - d = {key: coeff for key, coeff in d.iteritems() if coeff} + d = {key: coeff for key, coeff in iteritems(d) if coeff} return self.element_class(self, d) def monomial(self, i): diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 481b309e469..203e14d4df0 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -20,6 +20,7 @@ # # http://www.gnu.org/licenses/ #***************************************************************************** +from six import iteritems from sage.misc.cachefunc import cached_method #from sage.misc.lazy_attribute import lazy_attribute @@ -372,7 +373,7 @@ def _sorted_items_for_printing(self): """ print_options = self.parent().print_options() pos_to_index = dict(enumerate(self.parent()._indices)) - v = [(pos_to_index[k], c) for k,c in self.value.iteritems()] + v = [(pos_to_index[k], c) for k, c in iteritems(self.value)] try: v.sort(key=lambda monomial_coeff: print_options['sorting_key'](monomial_coeff[0]), diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index f6729d6679d..72499180287 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -7,6 +7,7 @@ # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ #***************************************************************************** +from six import iteritems from sage.misc.cachefunc import cached_method from sage.sets.family import Family @@ -288,7 +289,7 @@ def __iter__(self): [(0, 2), (2, -1)] """ zero = self.parent().base_ring().zero() - for i, c in self.value.iteritems(): + for i, c in iteritems(self.value): if c != zero: yield (i, c) @@ -338,7 +339,7 @@ def lift(self): """ UEA = self.parent().universal_enveloping_algebra() gens = UEA.gens() - return UEA.sum(c * gens[i] for i, c in self.value.iteritems()) + return UEA.sum(c * gens[i] for i, c in iteritems(self.value)) def to_vector(self): """ From efa77ed34e7c6dd33701b2d378db556e7fa27b82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 8 Mar 2017 16:59:17 +0100 Subject: [PATCH 123/223] trac 22257 fixing doctests --- src/sage/rings/number_field/number_field.py | 10 +++++----- .../number_field/number_field_element_quadratic.pyx | 2 +- src/sage/rings/real_lazy.pyx | 5 ++++- src/sage/schemes/elliptic_curves/heegner.py | 7 +++++-- src/sage/symbolic/expression.pyx | 2 +- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 9321a9f7a5e..68a6341fa52 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -1948,12 +1948,12 @@ def subfield(self, alpha, name=None, names=None): Generic morphism: From: Number Field in z0 with defining polynomial x^2 - 5 To: Complex Lazy Field - Defn: z0 -> 2.236067977499790? + Defn: z0 -> 2.23606797749979? + 0.?e-14*I Check transitivity:: sage: CLF_from_L(L.gen()) - 2.236067977499790? + 2.23606797749979? + 0.?e-14*I sage: CLF_from_K(K_from_L(L.gen())) 2.23606797749979? + 0.?e-14*I @@ -4332,7 +4332,7 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin sage: F, L1_into_F, L2_into_F, k = L1.composite_fields(L2, both_maps=True)[0] sage: [CDF(L1_into_F(L1.gen())), CDF(L2_into_F(L2.gen()))] - [-0.6293842454258952, -0.7708351267200303] + [-0.6293842454258959, -0.7708351267200312] Let's check that if only one field has an embedding, the resulting fields do not have embeddings:: @@ -7233,14 +7233,14 @@ def _subfields_helper(self, degree=0, name=None, both_maps=True, optimize=False) True sage: L1, _, _ = K.subfields(2)[0]; L1, CDF(L1.gen()) # indirect doctest - (Number Field in a0 with defining polynomial x^2 - 23, -4.795831523312719) + (Number Field in a0 with defining polynomial x^2 - 23, -4.795831523312721) If we take a different embedding of the large field, we get a different embedding of the degree 2 subfield:: sage: K. = NumberField(x^4 - 23, embedding=-50) sage: L2, _, _ = K.subfields(2)[0]; L2, CDF(L2.gen()) # indirect doctest - (Number Field in a0 with defining polynomial x^2 - 23, -4.795831523312719) + (Number Field in a0 with defining polynomial x^2 - 23, -4.795831523312721) Test for :trac:`7695`:: diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pyx b/src/sage/rings/number_field/number_field_element_quadratic.pyx index a23c8588dbd..0e3392afa25 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -978,7 +978,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: cf.n() 1.41421356237310 sage: sqrt2.n() - 1.41421356237309 + 1.41421356237310 sage: cf.value() sqrt2 diff --git a/src/sage/rings/real_lazy.pyx b/src/sage/rings/real_lazy.pyx index a56e5f8d186..1637e03abf4 100644 --- a/src/sage/rings/real_lazy.pyx +++ b/src/sage/rings/real_lazy.pyx @@ -25,6 +25,7 @@ import math cdef add, sub, mul, div, pow, neg, inv from operator import add, sub, mul, div, pow, neg, inv +from cpython.object cimport Py_EQ cdef canonical_coercion from sage.structure.element import canonical_coercion @@ -698,6 +699,8 @@ cdef class LazyFieldElement(FieldElement): except TypeError: pass left, right = self.approx(), other.approx() + if op == Py_EQ and left.endpoints() == right.endpoints(): + return True return richcmp(left, right, op) def __hash__(self): @@ -916,7 +919,7 @@ def make_element(parent, *args): EXAMPLES:: sage: a = RLF(pi) + RLF(sqrt(1/2)) # indirect doctest - sage: loads(dumps(a)) == a + sage: bool(loads(dumps(a)) == a) True """ return parent(*args) diff --git a/src/sage/schemes/elliptic_curves/heegner.py b/src/sage/schemes/elliptic_curves/heegner.py index d2612489125..04b2b54cf69 100644 --- a/src/sage/schemes/elliptic_curves/heegner.py +++ b/src/sage/schemes/elliptic_curves/heegner.py @@ -3171,7 +3171,7 @@ def numerical_approx(self, prec=53, algorithm=None): 8.4...e-31 + 6.0...e-31*I sage: E = EllipticCurve('37a'); P = E.heegner_point(-40); P Heegner point of discriminant -40 on elliptic curve of conductor 37 - sage: P.numerical_approx() # abs tol 1e-15 + sage: P.numerical_approx() # abs tol 1e-14 (-3.15940603400359e-16 + 1.41421356237309*I : 1.00000000000000 - 1.41421356237309*I : 1.00000000000000) A rank 2 curve, where all Heegner points of conductor 1 are 0:: @@ -6250,8 +6250,11 @@ def kolyvagin_point(self, D, c=ZZ(1), check=True): sage: E = EllipticCurve('37a1') sage: P = E.kolyvagin_point(-67); P Kolyvagin point of discriminant -67 on elliptic curve of conductor 37 - sage: P.numerical_approx() + sage: xyz = P.numerical_approx(); xyz # random digits (6.00000000000000 : -15.0000000000000 : 1.00000000000000) + sage: x, y = xyz.xy() + sage: max(abs(x - 6), abs(y + 15)) < 1e-14 + True sage: P.index() 6 sage: g = E((0,-1,1)) # a generator diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index a65c34d569b..2cfc6a6301a 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -3527,7 +3527,7 @@ cdef class Expression(CommutativeRingElement): -1 sage: cmp(log(8), 3*log(2)) 0 - sage: RLF(1) < RLF(sqrt(2)) + sage: bool(RLF(1) < RLF(sqrt(2))) True sage: RealSet((0, pi),[pi, pi],(pi,4)) (0, 4) From e1f07ca74416008e8280700152ec90e6e6f6329e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 8 Mar 2017 21:57:39 +0100 Subject: [PATCH 124/223] trac 22257 fixing back doctests --- src/sage/rings/number_field/number_field.py | 10 +++++----- .../number_field/number_field_element_quadratic.pyx | 2 +- src/sage/rings/real_lazy.pyx | 4 +--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 68a6341fa52..9321a9f7a5e 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -1948,12 +1948,12 @@ def subfield(self, alpha, name=None, names=None): Generic morphism: From: Number Field in z0 with defining polynomial x^2 - 5 To: Complex Lazy Field - Defn: z0 -> 2.23606797749979? + 0.?e-14*I + Defn: z0 -> 2.236067977499790? Check transitivity:: sage: CLF_from_L(L.gen()) - 2.23606797749979? + 0.?e-14*I + 2.236067977499790? sage: CLF_from_K(K_from_L(L.gen())) 2.23606797749979? + 0.?e-14*I @@ -4332,7 +4332,7 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin sage: F, L1_into_F, L2_into_F, k = L1.composite_fields(L2, both_maps=True)[0] sage: [CDF(L1_into_F(L1.gen())), CDF(L2_into_F(L2.gen()))] - [-0.6293842454258959, -0.7708351267200312] + [-0.6293842454258952, -0.7708351267200303] Let's check that if only one field has an embedding, the resulting fields do not have embeddings:: @@ -7233,14 +7233,14 @@ def _subfields_helper(self, degree=0, name=None, both_maps=True, optimize=False) True sage: L1, _, _ = K.subfields(2)[0]; L1, CDF(L1.gen()) # indirect doctest - (Number Field in a0 with defining polynomial x^2 - 23, -4.795831523312721) + (Number Field in a0 with defining polynomial x^2 - 23, -4.795831523312719) If we take a different embedding of the large field, we get a different embedding of the degree 2 subfield:: sage: K. = NumberField(x^4 - 23, embedding=-50) sage: L2, _, _ = K.subfields(2)[0]; L2, CDF(L2.gen()) # indirect doctest - (Number Field in a0 with defining polynomial x^2 - 23, -4.795831523312721) + (Number Field in a0 with defining polynomial x^2 - 23, -4.795831523312719) Test for :trac:`7695`:: diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pyx b/src/sage/rings/number_field/number_field_element_quadratic.pyx index 0e3392afa25..a23c8588dbd 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -978,7 +978,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: cf.n() 1.41421356237310 sage: sqrt2.n() - 1.41421356237310 + 1.41421356237309 sage: cf.value() sqrt2 diff --git a/src/sage/rings/real_lazy.pyx b/src/sage/rings/real_lazy.pyx index 1637e03abf4..c020789c75a 100644 --- a/src/sage/rings/real_lazy.pyx +++ b/src/sage/rings/real_lazy.pyx @@ -699,9 +699,7 @@ cdef class LazyFieldElement(FieldElement): except TypeError: pass left, right = self.approx(), other.approx() - if op == Py_EQ and left.endpoints() == right.endpoints(): - return True - return richcmp(left, right, op) + return richcmp(left.endpoints(), right.endpoints(), op) def __hash__(self): """ From a93ded97cb0210c094a361f671b315f9c8cc7615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 9 Mar 2017 17:03:54 +0100 Subject: [PATCH 125/223] trac 22257 details --- src/sage/rings/real_lazy.pyx | 1 - src/sage/schemes/elliptic_curves/heegner.py | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/sage/rings/real_lazy.pyx b/src/sage/rings/real_lazy.pyx index c020789c75a..2eeff8ee879 100644 --- a/src/sage/rings/real_lazy.pyx +++ b/src/sage/rings/real_lazy.pyx @@ -25,7 +25,6 @@ import math cdef add, sub, mul, div, pow, neg, inv from operator import add, sub, mul, div, pow, neg, inv -from cpython.object cimport Py_EQ cdef canonical_coercion from sage.structure.element import canonical_coercion diff --git a/src/sage/schemes/elliptic_curves/heegner.py b/src/sage/schemes/elliptic_curves/heegner.py index 04b2b54cf69..c7fcfc7632c 100644 --- a/src/sage/schemes/elliptic_curves/heegner.py +++ b/src/sage/schemes/elliptic_curves/heegner.py @@ -6250,11 +6250,8 @@ def kolyvagin_point(self, D, c=ZZ(1), check=True): sage: E = EllipticCurve('37a1') sage: P = E.kolyvagin_point(-67); P Kolyvagin point of discriminant -67 on elliptic curve of conductor 37 - sage: xyz = P.numerical_approx(); xyz # random digits + sage: P.numerical_approx() # abs tol 1e-14 (6.00000000000000 : -15.0000000000000 : 1.00000000000000) - sage: x, y = xyz.xy() - sage: max(abs(x - 6), abs(y + 15)) < 1e-14 - True sage: P.index() 6 sage: g = E((0,-1,1)) # a generator From 084f6aacc77b539528469fda643bf687c49b3008 Mon Sep 17 00:00:00 2001 From: Ben Hutz Date: Thu, 9 Mar 2017 10:35:26 -0600 Subject: [PATCH 126/223] 22556: implement periodic points for rational maps --- .../schemes/projective/projective_morphism.py | 185 ++++++++++++------ 1 file changed, 124 insertions(+), 61 deletions(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 40a70ef1a9d..605aef55caf 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -3127,7 +3127,7 @@ def critical_height(self, **kwds): ch += P.canonical_height(F, **kwds) return(ch) - def periodic_points(self, n, minimal=True, R=None, algorithm='variety'): + def periodic_points(self, n, minimal=True, R=None, algorithm='variety', return_scheme=False): r""" Computes the periodic points of period ``n`` of this map defined over the ring ``R`` or the base ring of the map. @@ -3141,7 +3141,9 @@ def periodic_points(self, n, minimal=True, R=None, algorithm='variety'): but is slow as the defining equations of the variety get more complicated. - The map must be a projective morphism. + For rational map, where there are potentially infinitely many peiodic points + of a given period, you must use the ``return_scheme`` option. Note + that this scheme will include the indeterminacy locus. INPUT: @@ -3156,9 +3158,12 @@ def periodic_points(self, n, minimal=True, R=None, algorithm='variety'): on the appropriate variety or ``cyclegraph`` to find the cycles from the cycle graph. Default: ``variety``. + - ``return_scheme`` - return a subscheme of the ambient space which defines the + ``n``th periodic points. + OUTPUT: - - a list of periodic points of this map. + - a list of periodic points of this map or the subscheme defining the periodic points EXAMPLES:: @@ -3256,9 +3261,46 @@ def periodic_points(self, n, minimal=True, R=None, algorithm='variety'): sage: H = End(P) sage: f = H([3*x^2+5*y^2,y^2]) sage: f.periodic_points(2, R=GF(3), minimal=False) + [(2 : 1)] + + :: + + sage: P. = ProjectiveSpace(QQ, 2) + sage: H = End(P) + sage: f = H([x^2, x*y, z^2]) + sage: f.periodic_points(1) + Traceback (most recent call last): + ... + TypeError: use return_scheme=True + + :: + + sage: R. = QQ[] + sage: K. = NumberField(x^2 - x + 3) + sage: P. = ProjectiveSpace(K,2) + sage: X = P.subscheme(2*x-y) + sage: H = End(X) + sage: f = H([x^2-y^2, 2*(x^2-y^2), y^2-z^2]) + sage: f.periodic_points(2) + [(-1/5*u - 1/5 : -2/5*u - 2/5 : 1), (1/5*u - 2/5 : 2/5*u - 4/5 : 1)] + + :: + + sage: P. = ProjectiveSpace(QQ,2) + sage: H = End(P) + sage: f = H([x^2-y^2, x^2-z^2, y^2-z^2]) + sage: f.periodic_points(1) + [(-1 : 0 : 1)] + sage: f.periodic_points(1, return_scheme=True) + Closed subscheme of Projective Space of dimension 2 over Rational Field + defined by: + -x^3 + x^2*y - y^3 + x*z^2, + -x*y^2 + x^2*z - y^2*z + x*z^2, + -y^3 + x^2*z + y*z^2 - z^3 + sage: f.periodic_points(2, minimal=True, return_scheme=True) Traceback (most recent call last): ... - NotImplementedError: must be a projective morphism + NotImplementedError: return_subscheme only implemented for minimal=False """ if n <= 0: raise ValueError("a positive integer period must be specified") @@ -3269,54 +3311,66 @@ def periodic_points(self, n, minimal=True, R=None, algorithm='variety'): R = self.base_ring() else: f = self.change_ring(R) - if not f.is_morphism(): - # if not, the variety is not dimension 0 and - # can cannot construct the cyclegraph due to - #indeterminacies - raise NotImplementedError("must be a projective morphism") - PS = f.codomain() - if algorithm == 'variety': - if R in NumberFields() or R is QQbar or R in FiniteFields(): - N = PS.dimension_relative() + 1 - R = PS.coordinate_ring() - F = f.nth_iterate_map(n) - L = [F[i]*R.gen(j) - F[j]*R.gen(i) for i in range(0,N) for j in range(i+1, N)] - X = PS.subscheme(L) - points = [PS(Q) for Q in X.rational_points()] - - if not minimal: - return points + CR = f.coordinate_ring() + dom = f.domain() + PS = f.codomain().ambient_space() + N = PS.dimension_relative() + 1 + if algorithm == 'cyclegraph': + if R in FiniteFields(): + g = f.cyclegraph() + points = [] + for cycle in g.all_simple_cycles(): + m = len(cycle)-1 + if minimal: + if m == n: + points = points + cycle[:-1] + else: + if n % m == 0: + points = points + cycle[:-1] + return(points) else: - #we want only the points with minimal period n - #so we go through the list and remove any that - #have smaller period by checking the iterates - rem_indices = [] - for i in range(len(points)-1,-1,-1): - # iterate points to check if minimal - P = points[i] - for j in range(1,n): - P = f(P) - if P == points[i]: - points.pop(i) - break - return points - else: - raise NotImplementedError("ring must a number field or finite field") - elif algorithm == 'cyclegraph': - if R in FiniteFields(): - g = f.cyclegraph() - points = [] - for cycle in g.all_simple_cycles(): - m = len(cycle)-1 - if minimal: - if m == n: - points = points + cycle[:-1] + raise TypeError("ring must be finite to generate cyclegraph") + elif algorithm == 'variety': + F = f.nth_iterate_map(n) + L = [F[i]*CR.gen(j) - F[j]*CR.gen(i) for i in range(0,N) for j in range(i+1, N)] + L = [t for t in L if t != 0] + X = PS.subscheme(L + list(dom.defining_polynomials())) + if return_scheme: #this includes the indeterminancy locus points! + if minimal and n != 1: + raise NotImplementedError("return_subscheme only implemented for minimal=False") + return X + if X.dimension() == 0: + if R in NumberFields() or R is QQbar or R in FiniteFields(): + Z = f.indeterminacy_locus() + points = [dom(Q) for Q in X.rational_points()] + good_points = [] + for Q in points: + try: + Z(list(Q)) + except TypeError: + good_points.append(Q) + points = good_points + + if not minimal: + return points else: - if n % m == 0: - points = points + cycle[:-1] - return(points) - else: - raise TypeError("ring must be finite to generate cyclegraph") + #we want only the points with minimal period n + #so we go through the list and remove any that + #have smaller period by checking the iterates + rem_indices = [] + for i in range(len(points)-1,-1,-1): + # iterate points to check if minimal + P = points[i] + for j in range(1,n): + P = f(P) + if P == points[i]: + points.pop(i) + break + return points + else: + raise NotImplementedError("ring must a number field or finite field") + else: #a higher dimensional scheme + raise TypeError("use return_scheme=True") else: raise ValueError("algorithm must be either 'variety' or 'cyclegraph'") @@ -5370,9 +5424,9 @@ def indeterminacy_locus(self): sage: f.indeterminacy_locus() Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: - x, - y, - z + x^2, + y^2, + z^2 :: @@ -5399,16 +5453,25 @@ def indeterminacy_locus(self): x^3, x*y^2, x*z^2 + + :: + + sage: P. = ProjectiveSpace(QQ, 2) + sage: X = P.subscheme(x-y) + sage: H = End(X) + sage: f = H([x^2-4*y^2, y^2-z^2, 4*z^2-x^2]) + sage: Z = f.indeterminacy_locus(); Z + Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: + x - y, + x^2 - 4*y^2, + y^2 - z^2, + -x^2 + 4*z^2 + sage: Z.dimension() + -1 """ - from sage.schemes.projective.projective_space import is_ProjectiveSpace dom = self.domain() - if not is_ProjectiveSpace(dom): - raise NotImplementedError("not implemented for subschemes") - defPolys = self.defining_polynomials() - locus = dom.subscheme(defPolys) - if locus.dimension() < 0: - locus = dom.subscheme(dom.gens()) - return locus + AS = dom.ambient_space() + return AS.subscheme(list(dom.defining_polynomials()) + self.defining_polynomials()) def indeterminacy_points(self, F=None): r""" From a3a43d2920a234bc300771dd313f3dcb4564d513 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Fri, 10 Mar 2017 09:32:39 +0100 Subject: [PATCH 127/223] A solution for heaviside <-> Heaviside. --- src/sage/calculus/calculus.py | 23 +++++++++++++++++++++-- src/sage/functions/generalized.py | 3 ++- src/sage/interfaces/giac.py | 15 +++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 1e3e4285273..43a89fc5ae6 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -1358,6 +1358,15 @@ def laplace(ex, t, s, algorithm='maxima'): sage: laplace(1/s, s, t) laplace(1/s, s, t) + + TESTS:: + + Testing giac algorithm:: + + sage: var('t, s') + (t, s) + sage: laplace(heaviside(t-1), t, s, algorithm='giac') + e^(-s)/s """ if not isinstance(ex, (Expression, Function)): ex = SR(ex) @@ -1434,6 +1443,15 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): sage: inverse_laplace(cos(s), s, t) ilt(cos(s), s, t) + + TESTS:: + + Testing giac algorithm:: + + sage: var('t, s') + (t, s) + sage: inverse_laplace(exp(-s)/s, s, t, algorithm='giac') + heaviside(t-1) """ if not isinstance(ex, Expression): ex = SR(ex) @@ -1453,12 +1471,13 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): elif algorithm == 'giac': ex = "invlaplace(%s, %s, %s)" % tuple([repr(expr._giac_()) for expr in (ex, s, t)]) - from sage.interfaces.giac import giac + from sage.interfaces.giac import giac, un_camel try: result = giac(ex) except TypeError: raise ValueError("Giac cannot make sense of: %s" % ex) - return result.sage() + ans = giac(un_camel(str(result))) + return ans.sage() else: raise ValueError("Unknown algorithm: %s" % algorithm) diff --git a/src/sage/functions/generalized.py b/src/sage/functions/generalized.py index d6f6a017864..cf538fff45f 100644 --- a/src/sage/functions/generalized.py +++ b/src/sage/functions/generalized.py @@ -226,7 +226,8 @@ def __init__(self): BuiltinFunction.__init__(self, "heaviside", latex_name="H", conversions=dict(maxima='hstep', mathematica='HeavisideTheta', - sympy='Heaviside')) + sympy='Heaviside', + giac='Heaviside')) def _eval_(self, x): """ diff --git a/src/sage/interfaces/giac.py b/src/sage/interfaces/giac.py index 0652cc7adb2..27a2f6fc6f3 100644 --- a/src/sage/interfaces/giac.py +++ b/src/sage/interfaces/giac.py @@ -1157,5 +1157,20 @@ def __doctest_cleanup(): import sage.interfaces.quit sage.interfaces.quit.expect_quitall() +def un_camel(name): + """ + Convert `CamelCase` to `camel_case`. + EXAMPLES:: + sage: sage.interfaces.giac.un_camel('CamelCase') + 'camel_case' + sage: sage.interfaces.giac.un_camel('Heaviside') + 'elliptic_e' + sage: sage.interfaces.giac.un_camel('Dirac') + 'dirac' + """ + import re + + s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) + return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() From 3732a8cea8092e71d91b08aeb7cd7b8c46215aba Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Wed, 15 Mar 2017 10:24:38 +0100 Subject: [PATCH 128/223] add new doctests and a very basic parse function at giac.py - we catch the sympy unevaluated expression and wrap it as it is done with maxima. this is for laplace and for inverse_laplce - for the giac algorithm, this is not catched (a notimplemented exception is raised), see the doctests. - algorithm -> engine, although i wait for confirmation --- src/sage/calculus/calculus.py | 256 +++++++++++++++++++++++------- src/sage/functions/generalized.py | 5 +- src/sage/interfaces/giac.py | 34 ++-- 3 files changed, 225 insertions(+), 70 deletions(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 43a89fc5ae6..3c508fd2353 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -1259,26 +1259,45 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): ################################################################### # Laplace transform ################################################################### -def laplace(ex, t, s, algorithm='maxima'): +def laplace(ex, t, s, engine='maxima'): r""" - Attempts to compute and return the Laplace transform of - ``self`` with respect to the variable `t` and - transform parameter `s`. If this function cannot find a - solution, a formal function is returned. - - The function that is returned may be be viewed as a function of - `s`. + Return the Laplace transform with respect to the variable `t` and + transform parameter `s`, if possible. + + If this function cannot find a solution, a formal function is returned. + The function that is returned may be be viewed as a function of `s`. DEFINITION: - The Laplace transform of a function `f(t)`, - defined for all real numbers `t \geq 0`, is the function - `F(s)` defined by + The Laplace transform of a function `f(t)`, defined for all real numbers + `t \geq 0`, is the function `F(s)` defined by .. MATH:: F(s) = \int_{0}^{\infty} e^{-st} f(t) dt. + INPUT: + + - ``ex`` - a symbolic expression + + - ``t`` - independent variable + + - ``s`` - transform parameter + + - ``engine`` - (default: ``'maxima'``) one of + + - ``'maxima'`` - use Maxima (the default) + + - ``'sympy'`` - use SymPy + + - ``'giac'`` - use Giac + + NOTES: + + - The ``'sympy'` engine returns the tuple (F, a, cond) where $F(s)$ is the Laplace + transform of $f(t)$, $Re(s)>a$ is the half-plane of convergence, and cond + are auxiliary convergence conditions. + EXAMPLES: We compute a few Laplace transforms:: @@ -1300,8 +1319,6 @@ def laplace(ex, t, s, algorithm='maxima'): sage: g.laplace(x, s) s*laplace(f(x), x, s) - f(0) - EXAMPLES: - A BATTLE BETWEEN the X-women and the Y-men (by David Joyner): Solve @@ -1354,30 +1371,68 @@ def laplace(ex, t, s, algorithm='maxima'): sage: inverse_laplace(L, s, t) t*e^(a + 2*t)*sin(t) - Unable to compute solution:: + Unable to compute solution with Maxima:: - sage: laplace(1/s, s, t) - laplace(1/s, s, t) + sage: laplace(heaviside(t-1), t, s) + laplace(heaviside(t - 1), t, s) + + Heaviside step function can be handled with differente engines. + Try with giac:: + + sage: laplace(heaviside(t-1), t, s, engine='giac') + e^(-s)/s + + Try with SymPy:: + + sage: laplace(heaviside(t-1), t, s, engine='sympy') + (e^(-s)/s, 0, True) TESTS:: - Testing giac algorithm:: + Testing Giac:: sage: var('t, s') (t, s) - sage: laplace(heaviside(t-1), t, s, algorithm='giac') - e^(-s)/s + sage: laplace(5*cos(3*t-2)*heaviside(t-2), t, s, engine='giac') + 5*(s*cos(4)*e^(-2*s) - 3*e^(-2*s)*sin(4))/(s^2 + 9) + + Testing unevaluated expression from Giac:: + + sage: var('n') + n + sage: laplace(t^n, t, s, engine='giac') + Traceback (most recent call last): + ... + NotImplementedError: Unable to parse Giac output: integrate(t^n*exp(-s*t),t,0,+infinity) + + Testing SymPy:: + + sage: laplace(t^n, t, s, engine='sympy') + (s^(-n)*gamma(n + 1)/s, 0, -re(n) < 1) + + Testing Maxima:: + + sage: laplace(t^n, t, s, engine='maxima') + s^(-n - 1)*gamma(n + 1) + + Testing expression that is not parsed from SymPy to Sage:: + + sage: laplace(cos(t^2), t, s, engine='sympy') + Traceback (most recent call last): + ... + AttributeError: Unable to convert SymPy result (=sqrt(pi)*(sqrt(2)*sin(s**2/4)*fresnelc(sqrt(2)*s/(2*sqrt(pi))) - + sqrt(2)*cos(s**2/4)*fresnels(sqrt(2)*s/(2*sqrt(pi))) + cos(s**2/4 + pi/4))/2) into Sage """ if not isinstance(ex, (Expression, Function)): ex = SR(ex) - if algorithm == 'maxima': + if engine == 'maxima': return ex.parent()(ex._maxima_().laplace(var(t), var(s))) - elif algorithm == 'sympy': - ex, t, s = [expr._sympy_() for expr in (ex, t, s)] + elif engine == 'sympy': + ex_sy, t, s = [expr._sympy_() for expr in (ex, t, s)] from sympy import laplace_transform - result = laplace_transform(ex, t, s) + result = laplace_transform(ex_sy, t, s) if isinstance(result, tuple): try: (result, a, cond) = result @@ -1385,33 +1440,35 @@ def laplace(ex, t, s, algorithm='maxima'): except AttributeError: raise AttributeError("Unable to convert SymPy result (={}) into" " Sage".format(result)) + elif 'LaplaceTransform' in format(result): + return dummy_laplace(ex, t, s) else: return result - elif algorithm == 'giac': - ex = "laplace(%s, %s, %s)" % tuple([repr(expr._giac_()) for expr in (ex, t, s)]) + elif engine == 'giac': + ex_gi = "laplace(%s, %s, %s)" % tuple([repr(expr._giac_()) for expr in (ex, t, s)]) from sage.interfaces.giac import giac try: - result = giac(ex) + result = giac(ex_gi) except TypeError: - raise ValueError("Giac cannot make sense of: %s" % ex) - return result.sage() + raise ValueError("Giac cannot make sense of: %s" % ex_gi) + return result.sage() else: - raise ValueError("Unknown algorithm: %s" % algorithm) + raise ValueError("Unknown engine: %s" % engine) -def inverse_laplace(ex, s, t, algorithm='maxima'): +def inverse_laplace(ex, s, t, engine='maxima'): r""" - Attempts to compute the inverse Laplace transform of - ``self`` with respect to the variable `t` and - transform parameter `s`. If this function cannot find a - solution, a formal function is returned. + Return the inverse Laplace transform with respect to the variable `t` and + transform parameter `s`, if possible. + + If this function cannot find a solution, a formal function is returned. + The function that is returned may be be viewed as a function of `t`. - The function that is returned may be be viewed as a function of - `s`. - - DEFINITION: The inverse Laplace transform of a function - `F(s)`, is the function `f(t)` defined by + DEFINITION: + + The inverse Laplace transform of a function `F(s)` is the function + `f(t)`, defined by .. MATH:: @@ -1420,6 +1477,22 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): where `\gamma` is chosen so that the contour path of integration is in the region of convergence of `F(s)`. + INPUT: + + - ``ex`` - a symbolic expression + + - ``s`` - transform parameter + + - ``t`` - independent variable + + - ``engine`` - (default: ``'maxima'``) one of + + - ``'maxima'`` - use Maxima (the default) + + - ``'sympy'`` - use SymPy + + - ``'giac'`` - use Giac + EXAMPLES:: sage: var('w, m') @@ -1438,49 +1511,112 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): sage: inverse_laplace(1/(s^3+1), s, t) 1/3*(sqrt(3)*sin(1/2*sqrt(3)*t) - cos(1/2*sqrt(3)*t))*e^(1/2*t) + 1/3*e^(-t) - No explicit inverse Laplace transform, so one is returned formally - as a function ``ilt``:: + No explicit inverse Laplace transform, so one is returned formally a + function ``ilt``:: sage: inverse_laplace(cos(s), s, t) ilt(cos(s), s, t) - + + Transform an expression involving time-shifts with SymPy:: + + sage: inverse_laplace(1/s^2*exp(-s), s, t, engine='sympy') + -(log(e^(-t)) + 1)*heaviside(t - 1) + + The same instance with Giac:: + + sage: inverse_laplace(1/s^2*exp(-s), s, t, engine='giac') + (t - 1)*heaviside(t - 1) + + Transform a rational expression:: + + sage: inverse_laplace((2*s^2*exp(-2*s) - exp(-s))/(s^3+1), s, t, engine='giac') + -1/3*(sqrt(3)*e^(1/2*t - 1/2)*sin(1/2*sqrt(3)*(t - 1)) - cos(1/2*sqrt(3)*(t - 1))*e^(1/2*t - 1/2) + + e^(-t + 1))*heaviside(t - 1) + 2/3*(2*cos(1/2*sqrt(3)*(t - 2))*e^(1/2*t - 1) + e^(-t + 2))*heaviside(t - 2) + + Dirac delta function can also be handled:: + + sage: inverse_laplace(1, s, t, engine='giac') + dirac_delta(t) + TESTS:: - Testing giac algorithm:: - + Testing unevaluated expression from Maxima:: + sage: var('t, s') (t, s) - sage: inverse_laplace(exp(-s)/s, s, t, algorithm='giac') - heaviside(t-1) + sage: inverse_laplace(exp(-s)/s, s, t) + ilt(e^(-s)/s, s, t) + + Testing Giac:: + + sage: inverse_laplace(exp(-s)/s, s, t, engine='giac') + heaviside(t - 1) + + Testing SymPy:: + + sage: inverse_laplace(exp(-s)/s, s, t, engine='sympy') + heaviside(t - 1) + + Testing unevaluated expression from Giac:: + + sage: n = var('n') + sage: inverse_laplace(1/s^n, s, t, engine='giac') + Traceback (most recent call last): + ... + NotImplementedError: Unable to parse Giac output: ilaplace([s^(-n),s,t]) + + Try with Maxima:: + + sage: inverse_laplace(1/s^n, s, t, engine='maxima') + ilt(1/(s^n), s, t) + + Try with SymPy:: + + sage: inverse_laplace(1/s^n, s, t, engine='sympy') + t^(n - 1)*heaviside(t)/gamma(n) + + Testing unevaluated expression from sympy:: + + sage: inverse_laplace(cos(s), s, t, engine='sympy') + ilt(cos(s), t, s) + + Testing unevaluated expression from giac:: + + sage: inverse_laplace(cos(s), s, t, engine='giac') + Traceback (most recent call last): + ... + NotImplementedError: Unable to parse Giac output: ilaplace([cos(s),s,t]) """ if not isinstance(ex, Expression): ex = SR(ex) - if algorithm == 'maxima': + if engine == 'maxima': return ex.parent()(ex._maxima_().ilt(var(s), var(t))) - elif algorithm == 'sympy': - ex, s, t = [expr._sympy_() for expr in (ex, s, t)] + elif engine == 'sympy': + ex_sy, s, t = [expr._sympy_() for expr in (ex, s, t)] from sympy import inverse_laplace_transform - result = inverse_laplace_transform(ex, s, t) + result = inverse_laplace_transform(ex_sy, s, t) try: return result._sage_() except AttributeError: - raise AttributeError("Unable to convert SymPy result (={}) into" - " Sage".format(result)) + if 'InverseLaplaceTransform' in format(result): + return dummy_inverse_laplace(ex, t, s) + else: + raise AttributeError("Unable to convert SymPy result (={}) into" + " Sage".format(result)) - elif algorithm == 'giac': - ex = "invlaplace(%s, %s, %s)" % tuple([repr(expr._giac_()) for expr in (ex, s, t)]) - from sage.interfaces.giac import giac, un_camel + elif engine == 'giac': + ex_gi = "invlaplace(%s, %s, %s)" % tuple([repr(expr._giac_()) for expr in (ex, s, t)]) + from sage.interfaces.giac import giac try: - result = giac(ex) + result = giac(ex_gi) except TypeError: - raise ValueError("Giac cannot make sense of: %s" % ex) - ans = giac(un_camel(str(result))) - return ans.sage() + raise ValueError("Giac cannot make sense of: %s" % ex) + return result.sage() else: - raise ValueError("Unknown algorithm: %s" % algorithm) + raise ValueError("Unknown engine: %s" % engine) ################################################################### # symbolic evaluation "at" a point diff --git a/src/sage/functions/generalized.py b/src/sage/functions/generalized.py index cf538fff45f..1adeca1ea4a 100644 --- a/src/sage/functions/generalized.py +++ b/src/sage/functions/generalized.py @@ -117,7 +117,8 @@ def __init__(self): BuiltinFunction.__init__(self, "dirac_delta", latex_name=r"\delta", conversions=dict(maxima='delta', mathematica='DiracDelta', - sympy='DiracDelta')) + sympy='DiracDelta', + giac='Dirac')) def _eval_(self, x): """ @@ -222,6 +223,8 @@ def __init__(self): H\left(x\right) sage: heaviside(x)._sympy_() Heaviside(x) + sage: heaviside(x)._giac_() + Heaviside(x) """ BuiltinFunction.__init__(self, "heaviside", latex_name="H", conversions=dict(maxima='hstep', diff --git a/src/sage/interfaces/giac.py b/src/sage/interfaces/giac.py index 27a2f6fc6f3..34bc0093fa4 100644 --- a/src/sage/interfaces/giac.py +++ b/src/sage/interfaces/giac.py @@ -1026,8 +1026,10 @@ def _sage_(self): 2*cos(sqrt(-x^2 + 1))*cos(1/x)^2*sin(sqrt(-x^2 + 1)) - 4*cos(sqrt(-x^2 + 1))*cos(1/x)*sin(sqrt(-x^2 + 1)) + 2*cos(sqrt(-x^2 + 1))*sin(sqrt(-x^2 + 1)) """ - result = repr(self) - if str(self.type()) != 'DOM_LIST' : + result = repr(self) # string representation + + if str(self.type()) != 'DOM_LIST' : + result = _giac2sage(result) try: from sage.symbolic.all import SR return SR(result) @@ -1157,20 +1159,34 @@ def __doctest_cleanup(): import sage.interfaces.quit sage.interfaces.quit.expect_quitall() -def un_camel(name): +def _un_camel(name): """ Convert `CamelCase` to `camel_case`. EXAMPLES:: - sage: sage.interfaces.giac.un_camel('CamelCase') - 'camel_case' - sage: sage.interfaces.giac.un_camel('Heaviside') - 'elliptic_e' - sage: sage.interfaces.giac.un_camel('Dirac') - 'dirac' + sage: sage.interfaces.giac._un_camel('Heaviside') + 'heaviside' """ import re s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() + +def _giac2sage(ex): + """ + Parse the Giac output language to the Sage output language. + + EXAMPLES:: + + sage: sage.interfaces.giac._giac2sage('Heaviside(t-1)') + 'heaviside(t-1)' + """ + # key: giac (old) -> sage (new) + + conversions = [('Heaviside', 'heaviside'), + ('Dirac', 'dirac_delta')] + + for old, new in conversions: + ex = ex.replace(old, new) + return ex \ No newline at end of file From 21e556578a4a3d273ce1e14efa6578bb82093ecd Mon Sep 17 00:00:00 2001 From: Marc Masdeu Date: Fri, 17 Mar 2017 18:15:11 +0100 Subject: [PATCH 129/223] Fixed bug when lifting p-automorphic forms of weight > 2. --- .../modular/btquotients/pautomorphicform.py | 106 ++++++++---------- src/sage/modular/pollack_stevens/dist.pyx | 7 +- .../modular/pollack_stevens/distributions.py | 7 +- 3 files changed, 57 insertions(+), 63 deletions(-) diff --git a/src/sage/modular/btquotients/pautomorphicform.py b/src/sage/modular/btquotients/pautomorphicform.py index 2230bd036ef..86599f8d71c 100644 --- a/src/sage/modular/btquotients/pautomorphicform.py +++ b/src/sage/modular/btquotients/pautomorphicform.py @@ -509,8 +509,6 @@ def riemann_sum(self, f, center=1, level=0, E=None): 1 + 5 + 2*5^3 + 4*5^4 + 2*5^5 + 3*5^6 + 3*5^7 + 2*5^8 + 4*5^9 + O(5^10) """ R1 = LaurentSeriesRing(f.base_ring(), 'r1') - # R1.set_default_prec(self.parent()._k - 1) - if E is None: E = self.parent()._X._BT.get_balls(center, level) else: @@ -1057,9 +1055,7 @@ def _element_constructor_(self, x): if isinstance(parent, BruhatTitsHarmonicCocycles): return self.element_class(self, [self._U(o) for o in x._F]) elif isinstance(parent, pAdicAutomorphicForms): - tmp = [self._U(x._F[ii]).l_act_by(self._E[ii].rep) - for ii in range(self._nE)] - # tmp = [self._E[ii].rep * self._U(x._F[ii]) for ii in range(self._nE)] + tmp = [self._E[ii].rep * self._U(x._F[ii]) for ii in range(self._nE)] return self.element_class(self, tmp) if x == 0: tmp = [self._U([0] * (self.weight() - 1))] * self._X._num_edges @@ -1699,7 +1695,8 @@ def evaluate(self, e1): p = self.parent().prime() u = DoubleCosetReduction(X, e1) tmp = ((u.t(self.parent()._U.base_ring().precision_cap())) * p ** (u.power)).adjoint() - return self.parent()._Sigma0(tmp, check=False) * self._value[u.label] + S0 = self.parent()._Sigma0 + return S0(tmp, check=False) * self._value[u.label] # Warning! Should remove check=False... def _lmul_(self, a): @@ -1803,29 +1800,33 @@ def _improve(self, hc): """ MMM = self.parent() U = MMM._U - h1 = MMM(self) - try: - h1._value = [o.lift(M=MMM.precision_cap()) for o in h1._value] - except AttributeError: - pass - h2 = MMM._apply_Up_operator(h1, True, hc) + S0 = MMM._Sigma0 + + orig_moments = [[fval._moments[ii] for ii in range(MMM._n + 1)] + for fval in hc._F] + A = S0(Matrix(QQ, 2, 2, [0, 1 / MMM._p, 1, 0]),False) + for fval in hc._F: + tmp = -(A * fval) + orig_moments.append([tmp._moments[ii] for ii in range(MMM._n + 1)]) + + h1 = MMM([o.lift(M=MMM.precision_cap()) for o in self._value]) + h2 = MMM._apply_Up_operator(h1, True, orig_moments) verbose("Applied Up once") ii = 0 current_val = 0 - # old_val = -Infinity + old_val = -Infinity init_val = self.valuation() - while ii < MMM.precision_cap(): # current_val > old_val: - # old_val = current_val + while current_val > old_val: + old_val = current_val ii += 1 - self._value = [U(c) for c in h2._value] - h2 = MMM._apply_Up_operator(self, True, hc) - current_val = (h2 - self).valuation() - init_val + h1._value = [U(c) for c in h2._value] + h2 = MMM._apply_Up_operator(h1, True, orig_moments) + current_val = (h2 - h1).valuation() - init_val verbose('val = %s' % current_val) if current_val is Infinity: break verbose('Applied Up %s times' % (ii + 1)) - self._value = [U(c) for c in h2._value] - return self + return h2 def integrate(self, f, center=1, level=0, method='moments'): r""" @@ -1890,13 +1891,12 @@ def integrate(self, f, center=1, level=0, method='moments'): - Marc Masdeu (2012-02-20) """ E = self.parent()._source._BT.get_balls(center, level) - R1 = LaurentSeriesRing(f.base_ring(), 'r1') + R1 = LaurentSeriesRing(f.base_ring(), 'r1', default_prec = self.parent()._U.base_ring().precision_cap() + 1) R2 = PolynomialRing(f.base_ring(), 'x') x = R2.gen() value = 0 ii = 0 if method == 'riemann_sum': - # R1.set_default_prec(self.parent()._U.weight() + 1) for e in E: ii += 1 #print(ii,"/",len(E)) @@ -1905,7 +1905,6 @@ def integrate(self, f, center=1, level=0, method='moments'): new = eval_dist_at_powseries(self.evaluate(e), exp.truncate(self.parent()._U.weight() + 1)) value += new elif method == 'moments': - # R1.set_default_prec(self.parent()._U.base_ring().precision_cap()) n = self.parent()._U.weight() for e in E: ii += 1 @@ -2135,7 +2134,7 @@ def coleman(self, t1, t2, E=None, method='moments', mult=False, K = t1.parent() R = PolynomialRing(K, 'x') x = R.gen() - R1 = LaurentSeriesRing(K, 'r1') + R1 = LaurentSeriesRing(K, 'r1', default_prec=self.parent()._U.base_ring().precision_cap()) r1 = R1.gen() if E is None: E = self.parent()._source._BT.find_covering(t1, t2) @@ -2144,7 +2143,6 @@ def coleman(self, t1, t2, E=None, method='moments', mult=False, ii = 0 value_exp = K(1) if method == 'riemann_sum': - # R1.set_default_prec(self.parent()._U.weight() + 1) for e in E: ii += 1 b = e[0, 1] @@ -2158,7 +2156,6 @@ def coleman(self, t1, t2, E=None, method='moments', mult=False, value_exp *= K.teichmuller(y) ** Integer(c_e.moment(0).rational_reconstruction()) elif method == 'moments': - # R1.set_default_prec(self.parent()._U.base_ring().precision_cap()) for e in E: ii += 1 f = (x - t1) / (x - t2) @@ -2449,10 +2446,11 @@ def _element_constructor_(self, data): # Code how to coerce x into the space # Admissible values of x? if type(data) is list: - return self.element_class(self, [self._U(o) for o in data]) + return self.element_class(self, [self._U(o, normalize=False) for o in data]) if isinstance(data, pAdicAutomorphicFormElement): - return self.element_class(self, [self._U(o) for o in data._value]) + vals = [self._U(o, normalize=False) for o in data._value] + return self.element_class(self, vals) if isinstance(data, BruhatTitsHarmonicCocycleElement): E = self._list @@ -2460,13 +2458,13 @@ def _element_constructor_(self, data): F = [] Uold = data.parent()._U for ii in range(len(data._F)): - newtmp = data.parent()._Sigma0(E[ii].rep.inverse(), check=False) * Uold(data._F[ii]) # Warning, should remove check=False! + newtmp = data.parent()._Sigma0(E[ii].rep.inverse(), check=False) * Uold(data._F[ii],normalize=False) tmp.append(newtmp) F.append(newtmp) - A = Matrix(QQ, 2, 2, [0, -1 / self.prime(), -1, 0]) + A = data.parent()._Sigma0(Matrix(QQ,2,2,[0,1/self.prime(),1,0]),check=False) for ii in range(len(data._F)): - F.append(-(data.parent()._Sigma0(A.adjoint(), check=False) * tmp[ii])) - vals = self._make_invariant([self._U(o) for o in F]) + F.append(-(A * tmp[ii])) + vals = self._make_invariant([self._U(o,normalize=False) for o in F]) return self.element_class(self, vals) if data == 0: return self.zero_element() @@ -2542,9 +2540,7 @@ def lift(self, f): sage: A2.lift(a) # long time p-adic automorphic form of cohomological weight 0 """ - F = self(f) - F._improve(f) - return F + return self(f)._improve(f) def _make_invariant(self, F): r""" @@ -2574,7 +2570,7 @@ def _make_invariant(self, F): newF = [] for ii in range(len(S)): Si = S[ii] - x = self._U(F[ii]) + x = self._U(F[ii], normalize=False) if any(v[2] for v in Si): newFi = self._U(0) @@ -2582,13 +2578,14 @@ def _make_invariant(self, F): m = M[ii] for v in Si: s += 1 - newFi += self._Sigma0((m.adjoint() * self._source.embed_quaternion(v[0], prec=self._prec) * m).adjoint(), check=False) * self._U(x) - newF.append((1 / s) * newFi) + g = self._Sigma0(m.adjoint() * self._source.embed_quaternion(v[0], prec=self._prec).adjoint() * m,check = False) + newFi += g * x + newF.append((QQ(1) / s) * newFi) else: - newF.append(self._U(x)) + newF.append(self._U(x,normalize=False)) return newF - def _apply_Up_operator(self, f, scale=True, hc=None): + def _apply_Up_operator(self, f, scale=False, original_moments=None): r""" Apply the Up operator to ``f``. @@ -2607,34 +2604,29 @@ def _apply_Up_operator(self, f, scale=True, hc=None): p-adic automorphic form of cohomological weight 2 """ HeckeData = self._source._get_Up_data() - if scale: - factor = self._p ** (self._U.weight() / 2) + S0 = f._value[0].parent()._act._Sigma0 + prec_cap = self._U.base_ring().precision_cap() + + if not scale: + factor = self._p ** (self._U.weight() // 2) else: factor = 1 # Save original moments - if hc is None: - orig_moments = [[fval._moments[ii] for ii in range(self._n + 1)] + if original_moments is None: + original_moments = [[fval._moments[ii] for ii in range(self._n + 1)] for fval in f._value] - else: - orig_moments = [[fval._moments[ii] for ii in range(self._n + 1)] - for fval in hc._F] - orig_moments += [[-fval._moments[ii] for ii in range(self._n + 1)] - for fval in hc._F] Tf = [] - S0 = f._value[0].parent()._act._Sigma0 for jj in range(len(self._list)): - tmp = self._U(0) + tmp = self._U(0,normalize=False) for gg, edge_list in HeckeData: u = edge_list[jj] - r = (self._p ** (-(u.power)) - * (u.t(self._U.base_ring().precision_cap() - + 2 * u.power + 1) * gg)).adjoint() - tmp += S0(r, check=False) * f._value[u.label] - # Warning: should activate check... + tprec = 2 * (prec_cap + u.power) + 1 + r = S0(self._p ** -u.power * (u.t(tprec) * gg).adjoint(),check=False) + tmp += r * f._value[u.label] tmp *= factor for ii in range(self._n + 1): - tmp._moments[ii] = orig_moments[jj][ii] + tmp._moments[ii] = original_moments[jj][ii] Tf.append(tmp) return self(Tf) diff --git a/src/sage/modular/pollack_stevens/dist.pyx b/src/sage/modular/pollack_stevens/dist.pyx index b87d564aaa5..389aa925881 100644 --- a/src/sage/modular/pollack_stevens/dist.pyx +++ b/src/sage/modular/pollack_stevens/dist.pyx @@ -789,7 +789,7 @@ cdef class Dist_vector(Dist): sage: D = OverconvergentDistributions(3,5,6) # indirect doctest sage: v = D([1,1,1]) """ - def __init__(self, moments, parent, ordp=0, check=True): + def __init__(self, moments, parent, ordp=0, check=True, normalize=True): """ Initialization. @@ -824,7 +824,8 @@ cdef class Dist_vector(Dist): self._moments = moments self.ordp = ordp - self.normalize() # DEBUG + if normalize: + self.normalize() def __reduce__(self): r""" @@ -871,7 +872,6 @@ cdef class Dist_vector(Dist): sage: repr(v) '(1 + O(7^5), 2 + O(7^4), 3 + O(7^3), 4 + O(7^2), 5 + O(7))' """ - # self.normalize() # Should normalize only when absolutely needed. valstr = "" if self.ordp == 1: valstr = "%s * " % (self.parent().prime()) @@ -1886,7 +1886,6 @@ cdef class WeightKAction_vector(WeightKAction): v_moments = v._moments ans._moments = v_moments * self.acting_matrix(g, len(v_moments)) ans.ordp = v.ordp - ans.normalize() return ans # cdef inline long mymod(long a, unsigned long pM): diff --git a/src/sage/modular/pollack_stevens/distributions.py b/src/sage/modular/pollack_stevens/distributions.py index 7b607116197..1af7ade4b8d 100644 --- a/src/sage/modular/pollack_stevens/distributions.py +++ b/src/sage/modular/pollack_stevens/distributions.py @@ -305,7 +305,7 @@ def __init__(self, k, p=None, prec_cap=None, base=None, character=None, self._populate_coercion_lists_(action_list=[self._act]) - def _element_constructor_(self, val): + def _element_constructor_(self, val, **kwargs): """ Construct a distribution from data in ``val`` @@ -315,7 +315,10 @@ def _element_constructor_(self, val): sage: v = V([1,2,3,4,5,6,7]); v (1, 2, 3, 4, 5, 6, 7) """ - return self.Element(val, self) + ordp = kwargs.get('ord',0) + check = kwargs.get('check',True) + normalize= kwargs.get('normalize',True) + return self.Element(val, self, ordp, check, normalize) def _coerce_map_from_(self, other): """ From ffcc45fc85a9539496b36c603857775df8f1cf2a Mon Sep 17 00:00:00 2001 From: Marc Masdeu Date: Fri, 17 Mar 2017 18:27:46 +0100 Subject: [PATCH 130/223] Added doctest to show that bug is fixed. --- src/sage/modular/btquotients/pautomorphicform.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/sage/modular/btquotients/pautomorphicform.py b/src/sage/modular/btquotients/pautomorphicform.py index 86599f8d71c..c24889b0d8e 100644 --- a/src/sage/modular/btquotients/pautomorphicform.py +++ b/src/sage/modular/btquotients/pautomorphicform.py @@ -564,6 +564,19 @@ def modular_form(self, z=None, level=0): a + (a + 2)*3 + (2*a + 2)*3^2 + (2*a + 2)*3^3 + 2*a*3^5 + a*3^6 + O(3^7) sage: (x4-x3).valuation() 3 + + TESTS: + + Check that :trac:`22634` is fixed:: + + sage: X = BruhatTitsQuotient(7,2) + sage: H = X.harmonic_cocycles(4,20) + sage: A = X.padic_automorphic_forms(4,20,overconvergent=True) + sage: f = A.lift(H.basis()[0]).modular_form(method='moments') + sage: T. = Qq(7^2,20) + sage: a,b,c,d = X.embed_quaternion(X.get_units_of_order()[1]).change_ring(Qp(7,20)).list() + sage: (c*x + d)^4 * f(x) == f((a*x + b)/(c*x + d)) + True """ return self.derivative(z, level, order=0) @@ -1873,7 +1886,7 @@ def integrate(self, f, center=1, level=0, method='moments'): sage: A = X.padic_automorphic_forms(2,prec = 5,overconvergent=True) sage: a = A.lift(h) sage: a._value[0].moment(2) - 2 + 6*7 + 4*7^2 + O(7^3) + 2 + 6*7 + 4*7^2 + 4*7^3 + 6*7^4 + O(7^5) Now that we've lifted our harmonic cocycle to an overconvergent automorphic form we simply need to define the From 3af1062f92cf206694f86a2de49bac9a4ab66bbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 17 Mar 2017 20:22:48 +0100 Subject: [PATCH 131/223] doc correction in quadratic forms --- .../quadratic_form__ternary_Tornaria.py | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py index 06eee7c28ec..499c17000a4 100644 --- a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +++ b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py @@ -37,7 +37,7 @@ def disc(self): r""" - Returns the discriminant of the quadratic form, defined as + Return the discriminant of the quadratic form, defined as - `(-1)^n {\rm det}(B)` for even dimension `2n` - `{\rm det}(B)/2` for odd dimension @@ -66,7 +66,7 @@ def disc(self): def content(self): """ - Returns the GCD of the coefficients of the quadratic form. + Return the GCD of the coefficients of the quadratic form. .. warning:: @@ -103,7 +103,7 @@ def content(self): ## in quadratic_form.py #def primitive(self): # """ -# Returns a primitive quadratic forms in the similarity class of the given form. +# Return a primitive quadratic forms in the similarity class of the given form. # # This only works when we have GCDs... so over ZZ. # """ @@ -250,7 +250,7 @@ def delta(self): def level__Tornaria(self): """ - Returns the level of the quadratic form, + Return the level of the quadratic form, defined as level(B) for even dimension @@ -277,7 +277,7 @@ def level__Tornaria(self): def discrec(self): """ - Returns the discriminant of the reciprocal form. + Return the discriminant of the reciprocal form. EXAMPLES:: @@ -489,7 +489,7 @@ def xi(self,p): def xi_rec(self,p): """ - Returns Xi(`p`) for the reciprocal form. + Return Xi(`p`) for the reciprocal form. EXAMPLES:: @@ -514,7 +514,7 @@ def xi_rec(self,p): def lll(self): """ - Returns an LLL-reduced form of Q (using Pari). + Return an LLL-reduced form of Q (using Pari). EXAMPLES:: @@ -534,22 +534,23 @@ def lll(self): def representation_number_list(self, B): """ - Returns the vector of representation numbers < B. + Return the vector of representation numbers < B. EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ,[1,1,1,1,1,1,1,1]) sage: Q.representation_number_list(10) [1, 16, 112, 448, 1136, 2016, 3136, 5504, 9328, 12112] - """ - ans = pari(1).concat(self._pari_().qfrep(B-1, 1) * 2) + ans = pari(1).concat(self._pari_().qfrep(B - 1, 1) * 2) return ans.sage() -def representation_vector_list(self, B, maxvectors = 10**8): +def representation_vector_list(self, B, maxvectors=None): """ - Find all vectors v where Q(v) < B. + Find all vectors `v` where `Q(v) < B`. + + This only works for positive definite quadratic forms. EXAMPLES:: @@ -570,8 +571,21 @@ def representation_vector_list(self, B, maxvectors = 10**8): sage: Q.representation_number_list(10) [1, 4, 4, 0, 4, 8, 0, 0, 4, 4] + TESTS:: + + sage: R = QuadraticForm(ZZ,2,[-4,-3,0]) + sage: R.representation_vector_list(10) + Traceback (most recent call last): + ... + TypeError: not available when the form is not positive definite """ - n, m, vs = self._pari_().qfminim(2*(B-1), maxvectors) + if maxvectors is None: + maxvectors = 10 ** 8 + + if not self.is_positive_definite(): + raise TypeError('not available when the form is not positive definite') + + n, m, vs = self._pari_().qfminim(2 * (B - 1), maxvectors) if n != 2 * len(vs): raise RuntimeError("insufficient number of vectors") ms = [[] for _ in range(B)] From 14546798127a8b4d5fce22f5f969187f6fe36b4a Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Mon, 20 Mar 2017 23:43:36 +0100 Subject: [PATCH 132/223] delete unused un_camel function --- src/sage/interfaces/giac.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/sage/interfaces/giac.py b/src/sage/interfaces/giac.py index 34bc0093fa4..ed33a61abcf 100644 --- a/src/sage/interfaces/giac.py +++ b/src/sage/interfaces/giac.py @@ -1158,20 +1158,6 @@ def __doctest_cleanup(): """ import sage.interfaces.quit sage.interfaces.quit.expect_quitall() - -def _un_camel(name): - """ - Convert `CamelCase` to `camel_case`. - - EXAMPLES:: - - sage: sage.interfaces.giac._un_camel('Heaviside') - 'heaviside' - """ - import re - - s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) - return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() def _giac2sage(ex): """ From dc35047155862deac04cca42fdc2d48f47cd20e2 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Tue, 21 Mar 2017 06:44:15 +0100 Subject: [PATCH 133/223] use keyword algorithm in calculus.py --- src/sage/calculus/calculus.py | 64 +++++++++++++++++------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 3c508fd2353..e6923d123df 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -1259,7 +1259,7 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): ################################################################### # Laplace transform ################################################################### -def laplace(ex, t, s, engine='maxima'): +def laplace(ex, t, s, algorithm='maxima'): r""" Return the Laplace transform with respect to the variable `t` and transform parameter `s`, if possible. @@ -1284,7 +1284,7 @@ def laplace(ex, t, s, engine='maxima'): - ``s`` - transform parameter - - ``engine`` - (default: ``'maxima'``) one of + - ``algorithm`` - (default: ``'maxima'``) one of - ``'maxima'`` - use Maxima (the default) @@ -1294,7 +1294,7 @@ def laplace(ex, t, s, engine='maxima'): NOTES: - - The ``'sympy'` engine returns the tuple (F, a, cond) where $F(s)$ is the Laplace + - The ``'sympy'` algorithm returns the tuple (F, a, cond) where $F(s)$ is the Laplace transform of $f(t)$, $Re(s)>a$ is the half-plane of convergence, and cond are auxiliary convergence conditions. @@ -1376,15 +1376,15 @@ def laplace(ex, t, s, engine='maxima'): sage: laplace(heaviside(t-1), t, s) laplace(heaviside(t - 1), t, s) - Heaviside step function can be handled with differente engines. + Heaviside step function can be handled with different interfaces. Try with giac:: - sage: laplace(heaviside(t-1), t, s, engine='giac') + sage: laplace(heaviside(t-1), t, s, algorithm='giac') e^(-s)/s Try with SymPy:: - sage: laplace(heaviside(t-1), t, s, engine='sympy') + sage: laplace(heaviside(t-1), t, s, algorithm='sympy') (e^(-s)/s, 0, True) TESTS:: @@ -1393,31 +1393,31 @@ def laplace(ex, t, s, engine='maxima'): sage: var('t, s') (t, s) - sage: laplace(5*cos(3*t-2)*heaviside(t-2), t, s, engine='giac') + sage: laplace(5*cos(3*t-2)*heaviside(t-2), t, s, algorithm='giac') 5*(s*cos(4)*e^(-2*s) - 3*e^(-2*s)*sin(4))/(s^2 + 9) Testing unevaluated expression from Giac:: sage: var('n') n - sage: laplace(t^n, t, s, engine='giac') + sage: laplace(t^n, t, s, algorithm='giac') Traceback (most recent call last): ... NotImplementedError: Unable to parse Giac output: integrate(t^n*exp(-s*t),t,0,+infinity) Testing SymPy:: - sage: laplace(t^n, t, s, engine='sympy') + sage: laplace(t^n, t, s, algorithm='sympy') (s^(-n)*gamma(n + 1)/s, 0, -re(n) < 1) Testing Maxima:: - sage: laplace(t^n, t, s, engine='maxima') + sage: laplace(t^n, t, s, algorithm='maxima') s^(-n - 1)*gamma(n + 1) Testing expression that is not parsed from SymPy to Sage:: - sage: laplace(cos(t^2), t, s, engine='sympy') + sage: laplace(cos(t^2), t, s, algorithm='sympy') Traceback (most recent call last): ... AttributeError: Unable to convert SymPy result (=sqrt(pi)*(sqrt(2)*sin(s**2/4)*fresnelc(sqrt(2)*s/(2*sqrt(pi))) - @@ -1426,10 +1426,10 @@ def laplace(ex, t, s, engine='maxima'): if not isinstance(ex, (Expression, Function)): ex = SR(ex) - if engine == 'maxima': + if algorithm == 'maxima': return ex.parent()(ex._maxima_().laplace(var(t), var(s))) - elif engine == 'sympy': + elif algorithm == 'sympy': ex_sy, t, s = [expr._sympy_() for expr in (ex, t, s)] from sympy import laplace_transform result = laplace_transform(ex_sy, t, s) @@ -1445,7 +1445,7 @@ def laplace(ex, t, s, engine='maxima'): else: return result - elif engine == 'giac': + elif algorithm == 'giac': ex_gi = "laplace(%s, %s, %s)" % tuple([repr(expr._giac_()) for expr in (ex, t, s)]) from sage.interfaces.giac import giac try: @@ -1455,9 +1455,9 @@ def laplace(ex, t, s, engine='maxima'): return result.sage() else: - raise ValueError("Unknown engine: %s" % engine) + raise ValueError("Unknown algorithm: %s" % algorithm) -def inverse_laplace(ex, s, t, engine='maxima'): +def inverse_laplace(ex, s, t, algorithm='maxima'): r""" Return the inverse Laplace transform with respect to the variable `t` and transform parameter `s`, if possible. @@ -1485,7 +1485,7 @@ def inverse_laplace(ex, s, t, engine='maxima'): - ``t`` - independent variable - - ``engine`` - (default: ``'maxima'``) one of + - ``algorithm`` - (default: ``'maxima'``) one of - ``'maxima'`` - use Maxima (the default) @@ -1519,23 +1519,23 @@ def inverse_laplace(ex, s, t, engine='maxima'): Transform an expression involving time-shifts with SymPy:: - sage: inverse_laplace(1/s^2*exp(-s), s, t, engine='sympy') + sage: inverse_laplace(1/s^2*exp(-s), s, t, algorithm='sympy') -(log(e^(-t)) + 1)*heaviside(t - 1) The same instance with Giac:: - sage: inverse_laplace(1/s^2*exp(-s), s, t, engine='giac') + sage: inverse_laplace(1/s^2*exp(-s), s, t, algorithm='giac') (t - 1)*heaviside(t - 1) Transform a rational expression:: - sage: inverse_laplace((2*s^2*exp(-2*s) - exp(-s))/(s^3+1), s, t, engine='giac') + sage: inverse_laplace((2*s^2*exp(-2*s) - exp(-s))/(s^3+1), s, t, algorithm='giac') -1/3*(sqrt(3)*e^(1/2*t - 1/2)*sin(1/2*sqrt(3)*(t - 1)) - cos(1/2*sqrt(3)*(t - 1))*e^(1/2*t - 1/2) + e^(-t + 1))*heaviside(t - 1) + 2/3*(2*cos(1/2*sqrt(3)*(t - 2))*e^(1/2*t - 1) + e^(-t + 2))*heaviside(t - 2) Dirac delta function can also be handled:: - sage: inverse_laplace(1, s, t, engine='giac') + sage: inverse_laplace(1, s, t, algorithm='giac') dirac_delta(t) TESTS:: @@ -1549,40 +1549,40 @@ def inverse_laplace(ex, s, t, engine='maxima'): Testing Giac:: - sage: inverse_laplace(exp(-s)/s, s, t, engine='giac') + sage: inverse_laplace(exp(-s)/s, s, t, algorithm='giac') heaviside(t - 1) Testing SymPy:: - sage: inverse_laplace(exp(-s)/s, s, t, engine='sympy') + sage: inverse_laplace(exp(-s)/s, s, t, algorithm='sympy') heaviside(t - 1) Testing unevaluated expression from Giac:: sage: n = var('n') - sage: inverse_laplace(1/s^n, s, t, engine='giac') + sage: inverse_laplace(1/s^n, s, t, algorithm='giac') Traceback (most recent call last): ... NotImplementedError: Unable to parse Giac output: ilaplace([s^(-n),s,t]) Try with Maxima:: - sage: inverse_laplace(1/s^n, s, t, engine='maxima') + sage: inverse_laplace(1/s^n, s, t, algorithm='maxima') ilt(1/(s^n), s, t) Try with SymPy:: - sage: inverse_laplace(1/s^n, s, t, engine='sympy') + sage: inverse_laplace(1/s^n, s, t, algorithm='sympy') t^(n - 1)*heaviside(t)/gamma(n) Testing unevaluated expression from sympy:: - sage: inverse_laplace(cos(s), s, t, engine='sympy') + sage: inverse_laplace(cos(s), s, t, algorithm='sympy') ilt(cos(s), t, s) Testing unevaluated expression from giac:: - sage: inverse_laplace(cos(s), s, t, engine='giac') + sage: inverse_laplace(cos(s), s, t, algorithm='giac') Traceback (most recent call last): ... NotImplementedError: Unable to parse Giac output: ilaplace([cos(s),s,t]) @@ -1590,10 +1590,10 @@ def inverse_laplace(ex, s, t, engine='maxima'): if not isinstance(ex, Expression): ex = SR(ex) - if engine == 'maxima': + if algorithm == 'maxima': return ex.parent()(ex._maxima_().ilt(var(s), var(t))) - elif engine == 'sympy': + elif algorithm == 'sympy': ex_sy, s, t = [expr._sympy_() for expr in (ex, s, t)] from sympy import inverse_laplace_transform result = inverse_laplace_transform(ex_sy, s, t) @@ -1606,7 +1606,7 @@ def inverse_laplace(ex, s, t, engine='maxima'): raise AttributeError("Unable to convert SymPy result (={}) into" " Sage".format(result)) - elif engine == 'giac': + elif algorithm == 'giac': ex_gi = "invlaplace(%s, %s, %s)" % tuple([repr(expr._giac_()) for expr in (ex, s, t)]) from sage.interfaces.giac import giac try: @@ -1616,7 +1616,7 @@ def inverse_laplace(ex, s, t, engine='maxima'): return result.sage() else: - raise ValueError("Unknown engine: %s" % engine) + raise ValueError("Unknown algorithm: %s" % algorithm) ################################################################### # symbolic evaluation "at" a point From 4aae4f59ba9506ad05a4209b665fae27f58dc230 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Sat, 25 Mar 2017 21:55:22 +0100 Subject: [PATCH 134/223] Use symbol_table for giac -> sage conversion. --- src/sage/interfaces/giac.py | 51 ++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/sage/interfaces/giac.py b/src/sage/interfaces/giac.py index ed33a61abcf..da0c7692695 100644 --- a/src/sage/interfaces/giac.py +++ b/src/sage/interfaces/giac.py @@ -1005,12 +1005,20 @@ def _matrix_(self, R): return M(entries) - def _sage_(self): + def _sage_(self, locals={}): r""" - Convert a giac expression back to a Sage expression. + Convert a giac expression back to a Sage expression, if possible. + + NOTES: + + This method works successfully when Giac returns a result + or list of results that consist only of: + - numbers, i.e. integers, floats, complex numbers; + - functions and named constants also present in Sage, where: + - Sage knows how to translate the function or constant's name + from Giac's naming scheme through the symbols_table, or + - you provide a translation dictionary `locals`. - This currently does not implement a parser for the Giac output language, - therefore only very simple expressions will convert successfully. Warning: List conversion is slow. EXAMPLE:: @@ -1026,13 +1034,22 @@ def _sage_(self): 2*cos(sqrt(-x^2 + 1))*cos(1/x)^2*sin(sqrt(-x^2 + 1)) - 4*cos(sqrt(-x^2 + 1))*cos(1/x)*sin(sqrt(-x^2 + 1)) + 2*cos(sqrt(-x^2 + 1))*sin(sqrt(-x^2 + 1)) """ + from sage.libs.pynac.pynac import symbol_table + from sage.calculus.calculus import symbolic_expression_from_string + result = repr(self) # string representation - if str(self.type()) != 'DOM_LIST' : - result = _giac2sage(result) + if str(self.type()) != 'DOM_LIST' : + + # Merge the user-specified locals dictionary and the symbol_table + # (locals takes priority) + lsymbols = symbol_table['giac'].copy() + lsymbols.update(locals) + try: - from sage.symbolic.all import SR - return SR(result) + return symbolic_expression_from_string(result, lsymbols, + accept_sequence=True) + except Exception: raise NotImplementedError("Unable to parse Giac output: %s" % result) else: @@ -1158,21 +1175,3 @@ def __doctest_cleanup(): """ import sage.interfaces.quit sage.interfaces.quit.expect_quitall() - -def _giac2sage(ex): - """ - Parse the Giac output language to the Sage output language. - - EXAMPLES:: - - sage: sage.interfaces.giac._giac2sage('Heaviside(t-1)') - 'heaviside(t-1)' - """ - # key: giac (old) -> sage (new) - - conversions = [('Heaviside', 'heaviside'), - ('Dirac', 'dirac_delta')] - - for old, new in conversions: - ex = ex.replace(old, new) - return ex \ No newline at end of file From 81a7d4d20987df3ab5fa5d1c7c44a9b4e8929737 Mon Sep 17 00:00:00 2001 From: Ben Hutz Date: Mon, 27 Mar 2017 14:23:17 -0500 Subject: [PATCH 135/223] 21118: implement dynamical degree approximation --- .../schemes/projective/projective_morphism.py | 60 +++++++++++++++---- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 9c61b46ab35..a7828726e39 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -1263,11 +1263,11 @@ def degree(self): def degree_sequence(self, iterates=2): r""" - Return sequence of degrees of normalized iterates + Return sequence of degrees of normalized iterates. INPUT: ``iterates`` -- positive integer (optional - default: 2) - OUTPUT: List + OUTPUT: list of integers EXAMPLES:: @@ -1294,24 +1294,60 @@ def degree_sequence(self, iterates=2): sage: f.degree_sequence(10) [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] + :: + + sage: P2. = ProjectiveSpace(ZZ, 2) + sage: H = End(P2) + sage: f = H([X*Y, Y*Z+Z^2, Z^2]) + sage: f.degree_sequence(10) + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] """ if int(iterates) < 1: - raise TypeError("iteration number must be a positive integer") + raise TypeError("number of iterates must be a positive integer") if not self.is_endomorphism(): raise TypeError("map is not an endomorphism") if self.is_morphism(): - D = [1,self.degree()] - for n in range(2, iterates+1): - D.append(D[1]**n) + d = self.degree() + D = [d**t for t in range(iterates+1)] else: - D = [] - for n in range(0, iterates+1): - fn = self.nth_iterate_map(n) - fn.normalize_coordinates() - D.append(fn.degree()) + F = self + F.normalize_coordinates() + D = [F.degree()] + for n in range(2, iterates+1): + F = F*self + F.normalize_coordinates() + D.append(F.degree()) return D - + + def dynamical_degree(self, N=3): + r""" + Return sequence of degrees of normalized iterates. + + INPUT: ``iterates`` -- positive integer (optional - default: 2) + + OUTPUT: list of integers + + EXAMPLES:: + + sage: P2. = ProjectiveSpace(QQ, 2) + sage: H = End(P2) + sage: f = H([Z^2, X*Y, Y^2]) + sage: f.degree_sequence(15) + [1, 2, 3, 5, 8, 11, 17, 24, 31, 45, 56, 68, 91, 93, 184, 275] + + + """ + if int(N) < 1: + raise TypeError("number of iterates must be a positive integer") + if not self.is_endomorphism(): + raise TypeError("map is not an endomorphism") + if self.is_morphism(): + return self.degree() + else: + D = self.nth_iterate_map(N, normalize=True).degree() + return D.nth_root(N) + def dehomogenize(self, n): r""" Returns the standard dehomogenization at the ``n[0]`` coordinate for the domain From 01dcb16832c15e90107e0e8518215ac4ee635537 Mon Sep 17 00:00:00 2001 From: Ben Hutz Date: Mon, 27 Mar 2017 14:46:10 -0500 Subject: [PATCH 136/223] 21118: implement dynamical degree approx --- .../schemes/projective/projective_morphism.py | 50 ++++++++++++------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 261520d396c..f50a6ddef71 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -1279,7 +1279,8 @@ def degree(self): def degree_sequence(self, iterates=2): r""" - Return sequence of degrees of normalized iterates. + Return sequence of degrees of normalized iterates starting with + the degree of this map. INPUT: ``iterates`` -- positive integer (optional - default: 2) @@ -1291,7 +1292,7 @@ def degree_sequence(self, iterates=2): sage: H = End(P2) sage: f = H([Z^2, X*Y, Y^2]) sage: f.degree_sequence(15) - [1, 2, 3, 5, 8, 11, 17, 24, 31, 45, 56, 68, 91, 93, 184, 275] + [2, 3, 5, 8, 11, 17, 24, 31, 45, 56, 68, 91, 93, 184, 275] :: @@ -1300,7 +1301,7 @@ def degree_sequence(self, iterates=2): sage: H = End(P2) sage: f = H([Y*Z, X*Y, Y^2 + t*X*Z]) sage: f.degree_sequence(5) - [1, 2, 3, 5, 8, 13] + [2, 3, 5, 8, 13] :: @@ -1308,7 +1309,7 @@ def degree_sequence(self, iterates=2): sage: H = End(P2) sage: f = H([X^2, Y^2, Z^2]) sage: f.degree_sequence(10) - [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] + [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] :: @@ -1316,7 +1317,7 @@ def degree_sequence(self, iterates=2): sage: H = End(P2) sage: f = H([X*Y, Y*Z+Z^2, Z^2]) sage: f.degree_sequence(10) - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] + [2, 3, 4, 5, 6, 7, 8, 9, 10, 11] """ if int(iterates) < 1: raise TypeError("number of iterates must be a positive integer") @@ -1325,7 +1326,7 @@ def degree_sequence(self, iterates=2): if self.is_morphism(): d = self.degree() - D = [d**t for t in range(iterates+1)] + D = [d**t for t in range(1, iterates+1)] else: F = self F.normalize_coordinates() @@ -1336,33 +1337,46 @@ def degree_sequence(self, iterates=2): D.append(F.degree()) return D - def dynamical_degree(self, N=3): + def dynamical_degree(self, N=3, prec=53): r""" - Return sequence of degrees of normalized iterates. + Return an approximation to the dynamical degree of this map. The + dynamical degree is defined as $\lim_{n \to \infty} \sqrt[n]{\deg(f^n)}$. - INPUT: ``iterates`` -- positive integer (optional - default: 2) + INPUT: - OUTPUT: list of integers + - ``N`` -- iterate to use for approximation (optional - default: 3) + + - ``prec`` -- real precision to use when computing root (optional - default: 53) + + OUTPUT: real number EXAMPLES:: - sage: P2. = ProjectiveSpace(QQ, 2) - sage: H = End(P2) - sage: f = H([Z^2, X*Y, Y^2]) - sage: f.degree_sequence(15) - [1, 2, 3, 5, 8, 11, 17, 24, 31, 45, 56, 68, 91, 93, 184, 275] + sage: P. = ProjectiveSpace(QQ, 1) + sage: H = End(P) + sage: f = H([x^2 + (x*y), y^2]) + sage: f.dynamical_degree() + 2.00000000000000 - + :: + + sage: P2. = ProjectiveSpace(ZZ, 2) + sage: H = End(P2) + sage: f = H([X*Y, Y*Z+Z^2, Z^2]) + sage: f.dynamical_degree(N=5, prec=100) + 1.4309690811052555010452244131 """ if int(N) < 1: raise TypeError("number of iterates must be a positive integer") if not self.is_endomorphism(): raise TypeError("map is not an endomorphism") + + R = RealField(prec=prec) if self.is_morphism(): - return self.degree() + return R(self.degree()) else: D = self.nth_iterate_map(N, normalize=True).degree() - return D.nth_root(N) + return R(D).nth_root(N) def dehomogenize(self, n): r""" From cf88fee19593c1dc07b7e11a64a1b7cfa1c0f148 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 27 Mar 2017 17:56:56 -0500 Subject: [PATCH 137/223] Changes for the reviewer and using standard copyright. --- src/doc/en/reference/references/index.rst | 6 +- src/sage/algebras/lie_algebras/abelian.py | 2 +- src/sage/algebras/lie_algebras/examples.py | 9 ++- src/sage/algebras/lie_algebras/heisenberg.py | 35 ++++------ src/sage/algebras/lie_algebras/lie_algebra.py | 21 +++--- .../lie_algebras/lie_algebra_element.pyx | 70 ++++++++++--------- .../lie_algebras/structure_coefficients.py | 16 ++--- src/sage/algebras/lie_algebras/virasoro.py | 15 ++-- ...ite_dimensional_lie_algebras_with_basis.py | 28 ++------ src/sage/categories/lie_algebras.py | 10 ++- .../categories/lie_algebras_with_basis.py | 29 +++++++- 11 files changed, 120 insertions(+), 121 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 189019fdc3f..4c1a80be05a 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -498,9 +498,9 @@ REFERENCES: Leçons mathématiques de Bordeaux, vol. 4, pages 259-300, Cassini (2011). -.. [deGraaf2000] Willem A. de Graaf. *Lie Algebras: Theory and Algorithms*. - North-Holland Mathemtaical Library. (2000). - Elsevier Science B.V. +.. [deG2000] Willem A. de Graaf. *Lie Algebras: Theory and Algorithms*. + North-Holland Mathematical Library. (2000). + Elsevier Science B.V. .. [Deo1987a] \V. Deodhar, A splitting criterion for the Bruhat orderings on Coxeter groups. Comm. Algebra, diff --git a/src/sage/algebras/lie_algebras/abelian.py b/src/sage/algebras/lie_algebras/abelian.py index 32066e25388..5145d853f09 100644 --- a/src/sage/algebras/lie_algebras/abelian.py +++ b/src/sage/algebras/lie_algebras/abelian.py @@ -7,7 +7,7 @@ """ #***************************************************************************** -# Copyright (C) 2016 Travis Scrimshaw +# Copyright (C) 2013-2017 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 diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index 1f67b65083b..a5891dd70cc 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -21,11 +21,14 @@ - Travis Scrimshaw (07-15-2013): Initial implementation """ #***************************************************************************** -# Copyright (C) 2013 Travis Scrimshaw +# Copyright (C) 2013-2017 Travis Scrimshaw # -# Distributed under the terms of the GNU General Public License (GPL) +# 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 sage.algebras.lie_algebras.classical_lie_algebra import gl, sl, so, sp from sage.algebras.lie_algebras.virasoro import VirasoroAlgebra # this is used, just not in this file diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index 83ff50fed5d..bad1a720008 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -7,17 +7,12 @@ """ #***************************************************************************** -# Copyright (C) 2013 Travis Scrimshaw -# -# Distributed under the terms of the GNU General Public License (GPL) -# -# This code is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty -# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -# See the GNU General Public License for more details; the full text -# is available at: +# Copyright (C) 2013-2017 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. # http://www.gnu.org/licenses/ #***************************************************************************** @@ -193,11 +188,7 @@ def gens(self): sage: H.gens() (z,) """ - if self._n == 0: - return (self.z(),) - L = [self.p(i) for i in range(1, self._n+1)] - L += [self.q(i) for i in range(1, self._n+1)] - return tuple(L) + return tuple(self.lie_algebra_generators()) def gen(self, i): """ @@ -222,17 +213,20 @@ def lie_algebra_generators(self): sage: H = lie_algebras.Heisenberg(QQ, 1) sage: H.lie_algebra_generators() - Finite family {'q1': q1, 'p1': p1, 'z': z} + Finite family {'q1': q1, 'p1': p1} sage: H = lie_algebras.Heisenberg(QQ, 0) sage: H.lie_algebra_generators() Finite family {'z': z} """ + if self._n == 0: + return Family(['z'], lambda i: self.z()) + k = ['p%s'%i for i in range(1, self._n+1)] + k += ['q%s'%i for i in range(1, self._n+1)] d = {} for i in range(1, self._n+1): d['p%s'%i] = self.p(i) d['q%s'%i] = self.q(i) - d['z'] = self.z() - return Family(self._indices, lambda i: d[i]) + return Family(k, lambda i: d[i]) @cached_method def basis(self): @@ -245,15 +239,12 @@ def basis(self): sage: H.basis() Finite family {'q1': q1, 'p1': p1, 'z': z} """ - k = ['p%s'%i for i in range(1, self._n+1)] - k += ['q%s'%i for i in range(1, self._n+1)] - k += ['z'] d = {} for i in range(1, self._n+1): d['p%s'%i] = self.p(i) d['q%s'%i] = self.q(i) d['z'] = self.z() - return Family(k, lambda i: d[i]) + return Family(self._indices, lambda i: d[i]) def _coerce_map_from_(self, H): """ diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index aba527e6383..016eef62e5d 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -7,19 +7,15 @@ """ #***************************************************************************** -# Copyright (C) 2013 Travis Scrimshaw -# -# Distributed under the terms of the GNU General Public License (GPL) -# -# This code is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty -# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -# See the GNU General Public License for more details; the full text -# is available at: +# Copyright (C) 2013-2017 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. # http://www.gnu.org/licenses/ #***************************************************************************** + from six.moves import range from six import iteritems @@ -238,7 +234,7 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): REFERENCES: - - [deGraaf2000]_ Willem A. de Graaf. *Lie Algebras: Theory and Algorithms*. + - [deG2000]_ Willem A. de Graaf. *Lie Algebras: Theory and Algorithms*. - [Ka1990]_ Victor Kac, *Infinite dimensional Lie algebras*. - :wikipedia:`Lie_algebra` """ @@ -1274,6 +1270,9 @@ def section(self): self.preimage) class MatrixLieAlgebraFromAssociative(LieAlgebraFromAssociative): + """ + A Lie algebra constructed from a matrix algebra. + """ class Element(LieAlgebraMatrixWrapper, LieAlgebraFromAssociative.Element): pass diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx index 8db779be8e8..17b194d0843 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx @@ -8,24 +8,19 @@ AUTHORS: """ #***************************************************************************** -# Copyright (C) 2013 Travis Scrimshaw -# -# Distributed under the terms of the GNU General Public License (GPL) -# -# This code is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty -# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -# See the GNU General Public License for more details; the full text -# is available at: +# Copyright (C) 2013-2017 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. # http://www.gnu.org/licenses/ #***************************************************************************** from copy import copy from sage.misc.misc import repr_lincomb -from sage.combinat.free_module import CombinatorialFreeModuleElement +from sage.combinat.free_module import CombinatorialFreeModule from sage.structure.element cimport have_same_parent, coercion_model from sage.structure.element_wrapper cimport ElementWrapper @@ -49,7 +44,7 @@ from sage.structure.element_wrapper cimport ElementWrapper # TODO: Factor out parts of CombinatorialFreeModuleElement into a SparseFreeModuleElement? # TODO: Do we want a dense version? -class LieAlgebraElement(CombinatorialFreeModuleElement): +class LieAlgebraElement(CombinatorialFreeModule.Element): """ A Lie algebra element. """ @@ -103,7 +98,7 @@ class LieAlgebraElement(CombinatorialFreeModuleElement): s = UEA.zero() if not self: return s - for t, c in self.monomial_coefficients(copy=False).iteritems(): + for t, c in self._monomial_coefficients.iteritems(): s += c * gen_dict[t] return s @@ -260,7 +255,7 @@ cdef class LieAlgebraElementWrapper(ElementWrapper): sage: x + y x + y """ - return self.__class__(self.parent(), self.value + right.value) + return type(self)(self._parent, self.value + right.value) cpdef _sub_(self, right): """ @@ -273,7 +268,7 @@ cdef class LieAlgebraElementWrapper(ElementWrapper): sage: x - y x - y """ - return self.__class__(self.parent(), self.value - right.value) + return type(self)(self._parent, self.value - right.value) # We need to bypass the coercion framework # We let the universal enveloping algebra handle the rest if both @@ -306,9 +301,9 @@ cdef class LieAlgebraElementWrapper(ElementWrapper): (2,3) - (1,3) """ if self.value == 0 or x == 0: - return self.parent().zero() + return self._parent.zero() if x in self.base_ring(): - return x * self + return self._acted_upon_(x, True) # Otherwise we lift to the UEA return self.lift() * x @@ -326,7 +321,7 @@ cdef class LieAlgebraElementWrapper(ElementWrapper): """ return self * (~x) - def _acted_upon_(self, scalar, self_on_left=False): + cpdef _acted_upon_(self, scalar, bint self_on_left): """ Return the action of a scalar on ``self``. @@ -361,8 +356,8 @@ cdef class LieAlgebraElementWrapper(ElementWrapper): else: return None if self_on_left: - return self.__class__(self.parent(), self.value * scalar) - return self.__class__(self.parent(), scalar * self.value) + return type(self)(self._parent, self.value * scalar) + return type(self)(self._parent, scalar * self.value) def __neg__(self): """ @@ -375,7 +370,7 @@ cdef class LieAlgebraElementWrapper(ElementWrapper): sage: -x -x """ - return self.__class__(self.parent(), -self.value) + return type(self)(self._parent, -self.value) def __getitem__(self, i): """ @@ -394,6 +389,9 @@ cdef class LieAlgebraElementWrapper(ElementWrapper): # 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``. @@ -421,8 +419,8 @@ cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): x - 3/2*y """ return repr_lincomb(self._sorted_items_for_printing(), - scalar_mult=self.parent()._print_options['scalar_mult'], - repr_monomial=self.parent()._repr_generator, + scalar_mult=self._parent._print_options['scalar_mult'], + repr_monomial=self._parent._repr_generator, strip_one=True) def _latex_(self): @@ -435,9 +433,9 @@ cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): x - \frac{3}{2}y """ return repr_lincomb(self._sorted_items_for_printing(), - scalar_mult=self.parent()._print_options['scalar_mult'], - latex_scalar_mult=self.parent()._print_options['latex_scalar_mult'], - repr_monomial=self.parent()._latex_term, + scalar_mult=self._parent._print_options['scalar_mult'], + latex_scalar_mult=self._parent._print_options['latex_scalar_mult'], + repr_monomial=self._parent._latex_term, is_latex=True, strip_one=True) cpdef bracket(self, right): @@ -472,26 +470,30 @@ cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): sage: y._bracket_(x) -z """ - P = self.parent() + P = self._parent cdef dict s_coeff = P._s_coeff d = P.dimension() cdef list ret = [P.base_ring().zero()]*d cdef int i1, i2, i3 + cdef StructureCoefficientsElement rt = right for i1 in range(d): c1 = self.value[i1] if not c1: pass for i2 in range(d): - c2 = right.value[i2] + c2 = rt.value[i2] + prod_c1_c2 = c1 * c2 if not c2: pass if (i1, i2) in s_coeff: + v = s_coeff[i1, i2] for i3 in range(d): - ret[i3] += c1 * c2 * s_coeff[i1, i2][i3] + ret[i3] += prod_c1_c2 * v[i3] elif (i2, i1) in s_coeff: + v = s_coeff[i2, i1] for i3 in range(d): - ret[i3] -= c1 * c2 * s_coeff[i2, i1][i3] - return self.__class__(P, P._M(ret)) + ret[i3] -= prod_c1_c2 * v[i3] + return type(self)(P, P._M(ret)) def __iter__(self): """ @@ -556,8 +558,8 @@ cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): sage: a.monomial_coefficients() {'x': 2, 'z': -3/2} """ - I = self.parent()._indices - return {I[i]: v for i,v in self.value.monomial_coefficients(copy=False).items()} + I = self._parent._indices + return {I[i]: v for i,v in self.value.iteritems()} def __getitem__(self, i): """ @@ -570,5 +572,5 @@ cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): sage: elt['y'] -3/2 """ - return self.value[self.parent()._indices.index(i)] + return self.value[self._parent._indices.index(i)] diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 203e14d4df0..b78405e2739 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -7,19 +7,15 @@ """ #***************************************************************************** -# Copyright (C) 2013 Travis Scrimshaw -# -# Distributed under the terms of the GNU General Public License (GPL) -# -# This code is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty -# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -# See the GNU General Public License for more details; the full text -# is available at: +# Copyright (C) 2013-2017 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. # http://www.gnu.org/licenses/ #***************************************************************************** + from six import iteritems from sage.misc.cachefunc import cached_method diff --git a/src/sage/algebras/lie_algebras/virasoro.py b/src/sage/algebras/lie_algebras/virasoro.py index e6fbd65cf36..5e159d4bdd7 100644 --- a/src/sage/algebras/lie_algebras/virasoro.py +++ b/src/sage/algebras/lie_algebras/virasoro.py @@ -7,17 +7,12 @@ """ #***************************************************************************** -# Copyright (C) 2013 Travis Scrimshaw -# -# Distributed under the terms of the GNU General Public License (GPL) -# -# This code is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty -# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -# See the GNU General Public License for more details; the full text -# is available at: +# Copyright (C) 2013-2017 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. # http://www.gnu.org/licenses/ #***************************************************************************** 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 b7d59be9f9d..b6cb0715877 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -5,12 +5,16 @@ - Travis Scrimshaw (07-15-2013): Initial implementation """ + #***************************************************************************** -# Copyright (C) 2013 Travis Scrimshaw +# Copyright (C) 2013-2017 Travis Scrimshaw # -# Distributed under the terms of the GNU General Public License (GPL) +# 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 sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method @@ -589,24 +593,6 @@ def is_semisimple(self): """ return not self.killing_form_matrix().is_singular() - def dimension(self): - """ - Return the dimension of ``self``. - - EXAMPLES:: - - sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() - sage: L.dimension() - 3 - - :: - - sage: L = LieAlgebra(QQ, 'x,y', {('x','y'): {'x':1}}) - sage: L.dimension() - 2 - """ - return self.basis().cardinality() - class ElementMethods: def adjoint_matrix(self): # In #11111 (more or less) by using matrix of a mophism """ diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index 6168486f628..f5c24bbe8ae 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -5,12 +5,16 @@ - Travis Scrimshaw (07-15-2013): Initial implementation """ + #***************************************************************************** -# Copyright (C) 2013 Travis Scrimshaw +# Copyright (C) 2013 Travis Scrimshaw # -# Distributed under the terms of the GNU General Public License (GPL) +# 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 sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method diff --git a/src/sage/categories/lie_algebras_with_basis.py b/src/sage/categories/lie_algebras_with_basis.py index 119360d36d1..573e4de307f 100644 --- a/src/sage/categories/lie_algebras_with_basis.py +++ b/src/sage/categories/lie_algebras_with_basis.py @@ -5,12 +5,16 @@ - Travis Scrimshaw (07-15-2013): Initial implementation """ + #***************************************************************************** -# Copyright (C) 2013 Travis Scrimshaw +# Copyright (C) 2013-2017 Travis Scrimshaw # -# Distributed under the terms of the GNU General Public License (GPL) +# 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 sage.misc.abstract_method import abstract_method #from sage.misc.cachefunc import cached_method @@ -120,6 +124,25 @@ def from_vector(self, v): B = self.basis() return self.sum(v[i] * B[i] for i in v.support()) + # Remove once #22629 is merged + def dimension(self): + """ + Return the dimension of ``self``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.dimension() + 3 + + :: + + sage: L = LieAlgebra(QQ, 'x,y', {('x','y'): {'x':1}}) + sage: L.dimension() + 2 + """ + return self.basis().cardinality() + class ElementMethods: def _bracket_(self, y): """ From f53dec3498cd5e062eebc9e54587ebf5d21ee49f Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 28 Mar 2017 15:52:56 +0200 Subject: [PATCH 138/223] Disable cysignals debugging in doctests --- src/sage/doctest/forker.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index 40c854bc425..49488c9c805 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -106,6 +106,11 @@ def init_sage(): import sage.all_cmdline sage.interfaces.quit.invalidate_all() + # Disable cysignals debug messages in doctests: this is needed to + # make doctests pass when cysignals was built with debugging enabled + from cysignals.signals import set_debug_level + set_debug_level(0) + # Use the rich output backend for doctest from sage.repl.rich_output import get_display_manager dm = get_display_manager() From 42666d4c3685d9ec2d9851ae9618d3a9e809449f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 28 Mar 2017 23:25:20 -0500 Subject: [PATCH 139/223] Adding centralizer_basis method, improving to/from_vector for finite-dim Lie algebras, other fixes. --- src/sage/algebras/lie_algebras/heisenberg.py | 18 ++- src/sage/algebras/lie_algebras/lie_algebra.py | 4 + .../lie_algebras/lie_algebra_element.pyx | 29 +--- ...ite_dimensional_lie_algebras_with_basis.py | 146 +++++++++++++++--- 4 files changed, 144 insertions(+), 53 deletions(-) diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index bad1a720008..2fe0b74080e 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -73,7 +73,9 @@ def q(self, i): def z(self): """ - The generator `z` of the Heisenberg algebra. + Return the basis element `z` of the Heisenberg algebra. + + The element `z` spans the center of the Heisenberg algebra. EXAMPLES:: @@ -125,15 +127,17 @@ def _latex_term(self, m): EXAMPLES:: - sage: H = lie_algebras.Heisenberg(QQ, 3) - sage: H._latex_term(('p', 1)) + sage: H = lie_algebras.Heisenberg(QQ, 10) + sage: H._latex_term('p1') 'p_{1}' sage: H._latex_term('z') 'z' + sage: latex(H.p(10)) + p_{10} """ if len(m) == 1: return m - return "%s_{%s}"%(m[0], m[1]) # else it is of length 2 + return "%s_{%s}"%(m[0], m[1:]) # else it is of length at least 2 Element = LieAlgebraElement @@ -559,7 +563,7 @@ class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): elementary matrices. This Lie algebra is isomorphic to the `n`-th Heisenberg algebra - cosnstructed in :class:`HeisenbergAlgebra`; the bases correspond to + constructed in :class:`HeisenbergAlgebra`; the bases correspond to each other. INPUT: @@ -691,7 +695,9 @@ def q(self, i): def z(self): """ - Return the generator `z` of the Heisenberg algebra. + Return the basis element `z` of the Heisenberg algebra. + + The element `z` spans the center of the Heisenberg algebra. EXAMPLES:: diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 016eef62e5d..488dffc1eca 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -80,6 +80,10 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): algebra homomorphism `g : U_L \to A` such that `f = g \circ h`. The algebra `U_L` is known as the *universal enveloping algebra* of `L`. + INPUT: + + See examples below for various input options. + EXAMPLES: **1.** The simplest examples of Lie algebras are *abelian Lie diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx index 17b194d0843..c5b47732616 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx @@ -24,25 +24,7 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.structure.element cimport have_same_parent, coercion_model from sage.structure.element_wrapper cimport ElementWrapper -# TODO: Have the other classes inherit from this? -# TODO: Should this be a mixin class (or moved to the category)? -#class LieAlgebraElement_generic(ModuleElement): -# """ -# Generic methods for all Lie algebra elements. -# """ -# def __mul__(self, other): -# """ -# If we are multiplying two non-zero elements, automatically -# lift up to the universal enveloping algebra. -# -# EXAMPLES:: -# """ -# if self == 0 or other == 0: -# return self.parent().zero() -# # Otherwise we lift to the UEA -# return self.lift() * other - -# TODO: Factor out parts of CombinatorialFreeModuleElement into a SparseFreeModuleElement? +# TODO: Inherit from IndexedFreeModuleElement and make cdef once #22632 is merged # TODO: Do we want a dense version? class LieAlgebraElement(CombinatorialFreeModule.Element): """ @@ -60,7 +42,7 @@ class LieAlgebraElement(CombinatorialFreeModule.Element): sage: y*x x*y - z """ - if self == 0 or y == 0: + if self.is_zero() or y.is_zero(): return self.parent().zero() if y in self.base_ring(): return y * self @@ -82,7 +64,6 @@ class LieAlgebraElement(CombinatorialFreeModule.Element): # return codomain.sum(c * t._im_gens_(codomain, im_gens, names) # for t, c in self._monomial_coefficients.iteritems()) - # TODO: Move to the category/lift morphism? def lift(self): """ Lift ``self`` to the universal enveloping algebra. @@ -479,12 +460,12 @@ cdef class StructureCoefficientsElement(LieAlgebraMatrixWrapper): for i1 in range(d): c1 = self.value[i1] if not c1: - pass + continue for i2 in range(d): c2 = rt.value[i2] - prod_c1_c2 = c1 * c2 if not c2: - pass + continue + prod_c1_c2 = c1 * c2 if (i1, i2) in s_coeff: v = s_coeff[i1, i2] for i3 in range(d): 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 b6cb0715877..d62866e5ef6 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -16,6 +16,8 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +from __future__ import print_function + from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute @@ -126,7 +128,6 @@ def _basis_ordering(self): """ return tuple(self.basis().keys()) - @cached_method def _dense_free_module(self, R=None): """ Return a dense free module associated to ``self`` over ``R``. @@ -142,6 +143,30 @@ def _dense_free_module(self, R=None): from sage.modules.free_module import FreeModule return FreeModule(R, self.dimension()) + module = _dense_free_module + + def from_vector(self, v): + """ + Return the element of ``self`` corresponding to the + vector ``v`` in ``self.module()``. + + Implement this if you implement :meth:`module`; see the + documentation of + :meth:`sage.categories.lie_algebras.LieAlgebras.module` + for how this is to be done. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: u = L.from_vector(vector(QQ, (1, 0, 0))); u + (1, 0, 0) + sage: parent(u) is L + True + """ + B = self.basis() + return self.sum(v[i] * B[k] for i,k in enumerate(self._basis_ordering) + if v[i] != 0) + def killing_matrix(self, x, y): r""" Return the Killing matrix of ``x`` and ``y``, where ``x`` @@ -273,51 +298,99 @@ def structure_coefficients(self, include_zeros=False): if not include_zeros and val == zero: continue if self._basis_key(x) > self._basis_key(y): - d[(y, x)] = -val + d[y,x] = -val else: - d[(x, y)] = val + d[x,y] = val return Family(d) - def centralizer(self, S): + def centralizer_basis(self, S): """ - Return the centralizer of ``S`` in ``self``. + Return a basis of the centralizer of ``S`` in ``self``. INPUT: - - ``S`` -- a subalgebra of ``self`` or a set of elements which + - ``S`` -- a subalgebra of ``self`` or a list of elements that represent generators for a subalgebra + .. SEEALSO:: + + :meth:`centralizer` + EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: a,b,c = L.lie_algebra_generators() - sage: S = L.centralizer([a + b, 2*a + c]); S - An example of a finite dimensional Lie algebra with basis: - the 3-dimensional abelian Lie algebra over Rational Field - sage: S.basis_matrix() - [1 0 0] - [0 1 0] - [0 0 1] + sage: L.centralizer_basis([a + b, 2*a + c]) + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] + + sage: H = lie_algebras.Heisenberg(QQ, 2) + sage: H.centralizer_basis(H) + [z] + + + sage: D = DescentAlgebra(QQ, 4).D() + sage: L = LieAlgebra(associative=D) + sage: L.centralizer_basis(L) + [D{}, + D{1} + D{1, 2} + D{2, 3} + D{3}, + D{1, 2, 3} + D{1, 3} + D{2}] + sage: D.center_basis() + (D{}, + D{1} + D{1, 2} + D{2, 3} + D{3}, + D{1, 2, 3} + D{1, 3} + D{2}) """ #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra #if isinstance(S, LieSubalgebra) or S is self: if S is self: - K = S + from sage.matrix.special import identity_matrix + m = identity_matrix(self.base_ring(), self.dimension()) + elif isinstance(S, (list, tuple)): + m = matrix([v.to_vector() for v in self.echelon_form(S)]) else: - K = self.subalgebra(S) + m = self.subalgebra(S).basis_matrix() - m = K.basis_matrix() S = self.structure_coefficients() - sc = {k: S[k].to_vector() for k in S.keys()} + sc = {} + for k in S.keys(): + v = S[k].to_vector() + sc[k] = v + sc[k[1],k[0]] = -v X = self.basis().keys() - d = self.dimension() - K = sc.keys() + d = len(X) c_mat = matrix(self.base_ring(), - [[sum(r[j]*sc[x,X[j]][k] for j in range(d) if (x, X[j]) in K) + [[sum(m[i,j] * sc[x,xp][k] for j,xp in enumerate(X) + if (x, xp) in sc) for x in X] - for r in m for k in range(d)]) + for i in range(d) for k in range(d)]) C = c_mat.right_kernel().basis_matrix() - return self.subalgebra([self.from_vector(v) for v in C]) + return [self.from_vector(v) for v in C] + + def centralizer(self, S): + """ + Return the centralizer of ``S`` in ``self``. + + INPUT: + + - ``S`` -- a subalgebra of ``self`` or a list of elements that + represent generators for a subalgebra + + .. SEEALSO:: + + :meth:`centralizer_basis` + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: a,b,c = L.lie_algebra_generators() + sage: S = L.centralizer([a + b, 2*a + c]); S + An example of a finite dimensional Lie algebra with basis: + the 3-dimensional abelian Lie algebra over Rational Field + sage: S.basis_matrix() + [1 0 0] + [0 1 0] + [0 0 1] + """ + return self.subalgebra(self.centralizer_basis(S)) def center(self): """ @@ -619,7 +692,34 @@ def adjoint_matrix(self): # In #11111 (more or less) by using matrix of a mophis P = self.parent() basis = P.basis() return matrix(self.base_ring(), - [vector(P.bracket(self, b).to_vector()) for b in basis]) + [P.bracket(self, b).to_vector() for b in basis]) + + def to_vector(self): + """ + Return the vector in ``g.module()`` corresponding to the + element ``self`` of ``g`` (where ``g`` is the parent of + ``self``). + + Implement this if you implement ``g.module()``. + See :meth:`sage.categories.lie_algebras.LieAlgebras.module` + for how this is to be done. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: L.an_element().to_vector() + (0, 0, 0) + + sage: D = DescentAlgebra(QQ, 4).D() + sage: L = LieAlgebra(associative=D) + sage: L.an_element().to_vector() + (1, 1, 1, 1, 1, 1, 1, 1) + """ + M = self.parent().module() + B = M.basis() + return M.sum(self[k] * B[i] for i,k in enumerate(self.parent()._basis_ordering)) + + _vector_ = to_vector class Subobjects(SubobjectsCategory): """ From 59df7ce401046c9bc1df6763d8ab80da594068a3 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 29 Mar 2017 08:52:39 -0500 Subject: [PATCH 140/223] Fixing pdf docbuild in finite-dim Lie algebras w/ basis category. --- .../categories/finite_dimensional_lie_algebras_with_basis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 d62866e5ef6..a3363da7edb 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -557,7 +557,7 @@ def lower_central_series(self): \mathfrak{g}_{k+1} = [\mathfrak{g}, \mathfrak{g}_{k}] - and recall that `\mathfrak{g}_k} \supseteq \mathfrak{g}_{k+1}`. + and recall that `\mathfrak{g}_{k} \supseteq \mathfrak{g}_{k+1}`. Alternatively we can express this as .. MATH:: From c1f20cb864ce4f63357d0698a9ae6ce30b8d1657 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Wed, 29 Mar 2017 22:25:06 +0200 Subject: [PATCH 141/223] docstring improvements --- src/sage/calculus/calculus.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index e6923d123df..e2f03d0823b 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -1265,7 +1265,7 @@ def laplace(ex, t, s, algorithm='maxima'): transform parameter `s`, if possible. If this function cannot find a solution, a formal function is returned. - The function that is returned may be be viewed as a function of `s`. + The function that is returned may be viewed as a function of `s`. DEFINITION: @@ -1294,8 +1294,8 @@ def laplace(ex, t, s, algorithm='maxima'): NOTES: - - The ``'sympy'` algorithm returns the tuple (F, a, cond) where $F(s)$ is the Laplace - transform of $f(t)$, $Re(s)>a$ is the half-plane of convergence, and cond + - The ``'sympy'`` algorithm returns the tuple (`F`, `a`, cond) where F is the Laplace + transform of `f(t)`, `Re(s)>a` is the half-plane of convergence, and cond are auxiliary convergence conditions. EXAMPLES: @@ -1517,7 +1517,7 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): sage: inverse_laplace(cos(s), s, t) ilt(cos(s), s, t) - Transform an expression involving time-shifts with SymPy:: + Transform an expression involving a time-shift, via SymPy:: sage: inverse_laplace(1/s^2*exp(-s), s, t, algorithm='sympy') -(log(e^(-t)) + 1)*heaviside(t - 1) @@ -1575,12 +1575,12 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): sage: inverse_laplace(1/s^n, s, t, algorithm='sympy') t^(n - 1)*heaviside(t)/gamma(n) - Testing unevaluated expression from sympy:: + Testing unevaluated expression from SymPy:: sage: inverse_laplace(cos(s), s, t, algorithm='sympy') ilt(cos(s), t, s) - Testing unevaluated expression from giac:: + Testing unevaluated expression from Giac:: sage: inverse_laplace(cos(s), s, t, algorithm='giac') Traceback (most recent call last): From 4f347e2b56c928faf9ba24ac8fb1efd533cfdca2 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Wed, 29 Mar 2017 22:50:26 +0200 Subject: [PATCH 142/223] fix another typo in docstring --- src/sage/calculus/calculus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index e2f03d0823b..ba08f84fcdf 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -1463,7 +1463,7 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): transform parameter `s`, if possible. If this function cannot find a solution, a formal function is returned. - The function that is returned may be be viewed as a function of `t`. + The function that is returned may be viewed as a function of `t`. DEFINITION: From 65ab385bcc4f202920c0f1b23db32f77a4f495d8 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 30 Mar 2017 12:50:34 +0200 Subject: [PATCH 143/223] Factorize result of algdep() --- src/sage/arith/misc.py | 33 +++++++++++-------- src/sage/rings/complex_mpc.pyx | 27 ++++++++------- src/sage/rings/complex_number.pyx | 55 +++++++++++-------------------- 3 files changed, 55 insertions(+), 60 deletions(-) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index f766c33488e..6422d0c9ca4 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -44,11 +44,8 @@ def algdep(z, degree, known_bits=None, use_bits=None, known_digits=None, use_digits=None, height_bound=None, proof=False): """ - Returns a polynomial of degree at most `degree` which is - approximately satisfied by the number `z`. Note that the returned - polynomial need not be irreducible, and indeed usually won't be if - `z` is a good approximation to an algebraic number of degree less - than `degree`. + Returns an irreducible polynomial of degree at most `degree` which + is approximately satisfied by the number `z`. You can specify the number of known bits or digits of `z` with ``known_bits=k`` or ``known_digits=k``. PARI is then told to @@ -96,12 +93,8 @@ def algdep(z, degree, known_bits=None, use_bits=None, known_digits=None, use_dig sage: z = (1/2)*(1 + RDF(sqrt(3)) *CC.0); z 0.500000000000000 + 0.866025403784439*I - sage: p = algdep(z, 6); p - x^3 + 1 - sage: p.factor() - (x + 1) * (x^2 - x + 1) - sage: z^2 - z + 1 # abs tol 2e-16 - 0.000000000000000 + sage: algdep(z, 6) + x^2 - x + 1 This example involves a `p`-adic number:: @@ -168,18 +161,28 @@ def algdep(z, degree, known_bits=None, use_bits=None, known_digits=None, use_dig sage: algdep(complex("1+2j"), 4) x^2 - 2*x + 5 + + We get an irreducible polynomial even if PARI returns a reducible + one:: + + sage: z = CDF(1, RR(3).sqrt())/2 + sage: pari(z).algdep(5) + x^5 + x^2 + sage: algdep(z, 5) + x^2 - x + 1 """ if proof and not height_bound: raise ValueError("height_bound must be given for proof=True") - x = ZZ['x'].gen() + R = ZZ['x'] + x = R.gen() z = py_scalar_to_element(z) if isinstance(z, Integer): if height_bound and abs(z) >= height_bound: return None - return x - ZZ(z) + return x - z degree = ZZ(degree) @@ -244,7 +247,9 @@ def norm(v): y = pari(z) f = y.algdep(degree) - return x.parent()(f) + # f might be reducible. Find the best fitting irreducible factor + factors = [p for p, e in R(f).factor()] + return min(factors, key=lambda f: abs(f(z))) algebraic_dependency = algdep diff --git a/src/sage/rings/complex_mpc.pyx b/src/sage/rings/complex_mpc.pyx index 4d870ffea84..349c795af48 100644 --- a/src/sage/rings/complex_mpc.pyx +++ b/src/sage/rings/complex_mpc.pyx @@ -74,6 +74,7 @@ from .complex_number cimport ComplexNumber from .complex_field import ComplexField_class from sage.misc.randstate cimport randstate, current_randstate +from sage.misc.superseded import deprecated_function_alias from .real_mpfr cimport RealField_class, RealNumber from .real_mpfr import mpfr_prec_min, mpfr_prec_max from sage.structure.sage_object cimport rich_to_bool, richcmp @@ -1309,11 +1310,8 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): def algebraic_dependency(self, n, **kwds): """ - Returns a polynomial of degree at most `n` which is - approximately satisfied by this complex number. Note that the - returned polynomial need not be irreducible, and indeed usually - won't be if `z` is a good approximation to an algebraic - number of degree less than `n`. + Return an irreducible polynomial of degree at most `n` which is + approximately satisfied by this complex number. ALGORITHM: Uses the PARI C-library algdep command. @@ -1326,16 +1324,23 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): sage: z = (1/2)*(1 + sqrt(3.0) * MPC.0); z 0.500000000000000 + 0.866025403784439*I sage: p = z.algebraic_dependency(5) - sage: p.factor() - (x + 1) * x^2 * (x^2 - x + 1) - sage: z^2 - z + 1 + sage: p + x^2 - x + 1 + sage: p(z) 1.11022302462516e-16 + + TESTS:: + + sage: z.algebraic_dependancy(2) + doctest:...: DeprecationWarning: algebraic_dependancy is deprecated. Please use algebraic_dependency instead. + See http://trac.sagemath.org/22714 for details. + x^2 - x + 1 """ - import sage.arith.all - return sage.arith.all.algdep(self, n, **kwds) + from sage.arith.all import algdep + return algdep(self, n, **kwds) # Former misspelling - algebraic_dependancy = algebraic_dependency + algebraic_dependancy = deprecated_function_alias(22714, algebraic_dependency) ################################ # Basic Arithmetic diff --git a/src/sage/rings/complex_number.pyx b/src/sage/rings/complex_number.pyx index c0b0ed25b72..30ab4296294 100644 --- a/src/sage/rings/complex_number.pyx +++ b/src/sage/rings/complex_number.pyx @@ -35,6 +35,7 @@ from .complex_double cimport ComplexDoubleElement from .real_mpfr cimport RealNumber import sage.misc.misc +from sage.misc.superseded import deprecated_function_alias import sage.rings.integer as integer import sage.rings.infinity as infinity @@ -2360,13 +2361,10 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): return infinity.unsigned_infinity return self._parent(self._pari_().zeta()) - def algdep(self, n, **kwds): + def algebraic_dependency(self, n, **kwds): """ - Returns a polynomial of degree at most `n` which is - approximately satisfied by this complex number. Note that the - returned polynomial need not be irreducible, and indeed usually - won't be if `z` is a good approximation to an algebraic - number of degree less than `n`. + Return an irreducible polynomial of degree at most `n` which is + approximately satisfied by this complex number. ALGORITHM: Uses the PARI C-library algdep command. @@ -2379,41 +2377,28 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): sage: z = (1/2)*(1 + sqrt(3.0) *C.0); z 0.500000000000000 + 0.866025403784439*I sage: p = z.algdep(5); p - x^3 + 1 - sage: p.factor() - (x + 1) * (x^2 - x + 1) - sage: z^2 - z + 1 + x^2 - x + 1 + sage: p(z) 1.11022302462516e-16 - """ - import sage.arith.all - return sage.arith.all.algdep(self, n, **kwds) - def algebraic_dependancy( self, n ): + TESTS:: + + sage: z.algdep(2) + x^2 - x + 1 + sage: z.algebraic_dependancy(2) + doctest:...: DeprecationWarning: algebraic_dependancy is deprecated. Please use algebraic_dependency instead. + See http://trac.sagemath.org/22714 for details. + x^2 - x + 1 """ - Returns a polynomial of degree at most `n` which is - approximately satisfied by this complex number. Note that the - returned polynomial need not be irreducible, and indeed usually - won't be if `z` is a good approximation to an algebraic - number of degree less than `n`. + from sage.arith.all import algdep + return algdep(self, n, **kwds) - ALGORITHM: Uses the PARI C-library algdep command. + # Alias + algdep = algebraic_dependency - INPUT: Type algdep? at the top level prompt. All additional - parameters are passed onto the top-level algdep command. + # Former misspelling + algebraic_dependancy = deprecated_function_alias(22714, algebraic_dependency) - EXAMPLES:: - - sage: C = ComplexField() - sage: z = (1/2)*(1 + sqrt(3.0) *C.0); z - 0.500000000000000 + 0.866025403784439*I - sage: p = z.algebraic_dependancy(5); p - x^3 + 1 - sage: p.factor() - (x + 1) * (x^2 - x + 1) - sage: z^2 - z + 1 - 1.11022302462516e-16 - """ - return self.algdep( n ) def make_ComplexNumber0( fld, mult_order, re, im ): """ From ed587af6769afaae0dcd0ec9edd990f38c347cc0 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 30 Mar 2017 12:18:09 -0500 Subject: [PATCH 144/223] Implementing ideal checks and fixing product_space. --- ...ite_dimensional_lie_algebras_with_basis.py | 27 ++++++++++ ...ite_dimensional_lie_algebras_with_basis.py | 53 ++++++++++++++++--- src/sage/categories/lie_algebras.py | 44 +++++++++++++++ 3 files changed, 117 insertions(+), 7 deletions(-) diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index 72499180287..7f172750364 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -197,6 +197,33 @@ def subalgebra(self, gens): N = self._M.subspace([g.value for g in gens]) return AbelianLieAlgebra(self.base_ring(), M=N, ambient=self._ambient) + ideal = subalgebra + + def is_ideal(self, A): + """ + Return if ``self`` is an ideal of the ambient space ``A``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: a, b, c = L.lie_algebra_generators() + sage: L.is_ideal(L) + True + sage: S1 = L.subalgebra([2*a+b, b + c]) + sage: S1.is_ideal(L) + True + sage: S2 = L.subalgebra([2*a+b]) + sage: S2.is_ideal(S1) + True + sage: S1.is_ideal(S2) + False + """ + if A == self or A == self._ambient: + return True + if self._ambient != A._ambient: + return False + return self._M.is_submodule(A._M) + def basis(self): """ Return the basis of ``self``. 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 a3363da7edb..60aa0f4d891 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -409,10 +409,43 @@ def center(self): """ return self.centralizer(self) - def product_space(self, L): + def is_ideal(self, A): + """ + Return if ``self`` is an ideal of ``A``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: a, b, c = L.lie_algebra_generators() + sage: I = L.ideal([2*a - c, b + c]) + sage: I.is_ideal(L) + True + + sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) + sage: L.is_ideal(L) + True + """ + if A == self: + return True + B = self.basis() + AB = A.basis() + try: + b_mat = matrix(A.base_ring(), [A.bracket(b, ab).to_vector() + for b in B for ab in AB]) + except (ValueError, TypeError): + return False + return b_mat.row_space().is_submodule(self.module()) + + def product_space(self, L, submodule=False): r""" Return the product space ``[self, L]``. + INPUT: + + - ``L`` -- a Lie subalgebra of ``self`` + - ``submodule`` -- (default: ``False``) if ``True``, then the + result is forced to be a submodule of ``self`` + EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() @@ -430,6 +463,13 @@ def product_space(self, L): Field with basis matrix: [] + :: + + sage: H = lie_algebras.Heisenberg(ZZ, 4) + sage: Hp = H.product_space(H, submodule=True).basis() + sage: [H.from_vector(v) for v in Hp] + [z] + :: sage: L. = LieAlgebra(QQ, {('x','y'):{'x':1}}) @@ -458,17 +498,16 @@ def product_space(self, L): B = self.basis() LB = L.basis() - K = B.keys() - LK = LB.keys() + b_mat = matrix(A.base_ring(), [A.bracket(b, lb).to_vector() + for b in B for lb in LB]) + if submodule is True or not (self.is_ideal(A) and L.is_ideal(A)): + return b_mat.row_space() # We echelonize the matrix here # TODO: Do we want to? - b_mat = matrix(A.base_ring(), [A.bracket(B[a], LB[b]).to_vector() - for a in K for b in LK]) b_mat.echelonize() r = b_mat.rank() - I = A._basis_ordering gens = [A.from_vector(row) for row in b_mat.rows()[:r]] - return A.subalgebra(gens) + return A.ideal(gens) @cached_method def derived_subalgebra(self): diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index f5c24bbe8ae..fd5cacb6f45 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -380,6 +380,50 @@ def subalgebra(self, gens, names=None, index_set=None, category=None): #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra #return LieSubalgebra(gens, names, index_set, category) + def ideal(self, gens, names=None, index_set=None, category=None): + r""" + Return the ideal of ``self`` generated by ``gens``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() + sage: a, b, c = L.lie_algebra_generators() + sage: L.ideal([2*a - c, b + c]) + An example of a finite dimensional Lie algebra with basis: + the 2-dimensional abelian Lie algebra over Rational Field + with basis matrix: + [ 1 0 -1/2] + [ 0 1 1] + + :: + + sage: L = LieAlgebras(QQ).example() + sage: x,y = L.lie_algebra_generators() + sage: L.ideal([x + y]) + Traceback (most recent call last): + ... + NotImplementedError: ideals not yet implemented: see #16824 + """ + raise NotImplementedError("ideals not yet implemented: see #16824") + #from sage.algebras.lie_algebras.ideal import LieIdeal + #return LieIdeal(gens, names, index_set, category) + + def is_ideal(self, A): + """ + Return if ``self`` is an ideal of ``A``. + + EXAMPLES:: + + sage: L = LieAlgebras(QQ).example() + sage: L.is_ideal(L) + True + """ + if A == self: + return True + raise NotImplementedError("ideals not yet implemented: see #16824") + #from sage.algebras.lie_algebras.ideal import LieIdeal + #return isinstance(self, LieIdeal) and self._ambient is A + @abstract_method(optional=True) def killing_form(self, x, y): """ From 24ad1fe4f21060b40ce00e23ca800b664ab63718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 30 Mar 2017 22:28:39 +0200 Subject: [PATCH 145/223] trac 6265 remove an old # random marker --- src/sage/rings/polynomial/toy_d_basis.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/polynomial/toy_d_basis.py b/src/sage/rings/polynomial/toy_d_basis.py index 1878e1237ce..800d1b4f798 100644 --- a/src/sage/rings/polynomial/toy_d_basis.py +++ b/src/sage/rings/polynomial/toy_d_basis.py @@ -4,7 +4,7 @@ No attempt was made to optimize this algorithm as the emphasis of this implementation is a clean and easy presentation. -.. note:: +.. NOTE:: The notion of 'term' and 'monomial' in [BW93]_ is swapped from the notion of those words in Sage (or the other way around, however you @@ -84,9 +84,9 @@ [1] However, when we compute the Groebner basis of I (defined over `\ZZ`), we -note that there is a certain integer in the ideal which is not 1.:: +note that there is a certain integer in the ideal which is not 1:: - sage: d_basis(I) # random -- waiting on upstream singular fixes at #6051 + sage: d_basis(I) [x + 170269749119, y + 2149906854, z + ..., 282687803443] Now for each prime `p` dividing this integer 282687803443, the Groebner @@ -115,13 +115,13 @@ - Martin Albrecht (2008-08): initial version """ - from sage.rings.integer_ring import ZZ from sage.arith.all import xgcd, lcm, gcd from sage.rings.polynomial.toy_buchberger import inter_reduction from sage.structure.sequence import Sequence -def spol(g1,g2): + +def spol(g1, g2): """ Return S-Polynomial of ``g_1`` and ``g_2``. @@ -153,7 +153,8 @@ def spol(g1,g2): return b1*s1*g1 - b2*s2*g2 -def gpol(g1,g2): + +def gpol(g1, g2): """ Return G-Polynomial of ``g_1`` and ``g_2``. @@ -188,6 +189,7 @@ def gpol(g1,g2): LM = lambda f: f.lm() LC = lambda f: f.lc() + def d_basis(F, strat=True): r""" Return the `d`-basis for the Ideal ``F`` as defined in [BW93]_. @@ -259,6 +261,7 @@ def d_basis(F, strat=True): return Sequence(sorted(inter_reduction(G),reverse=True)) + def select(P): """ The normal selection strategy. @@ -291,7 +294,8 @@ def select(P): min_pair = fi,fj return min_pair -def update(G,B,h): + +def update(G, B, h): """ Update ``G`` using the list of critical pairs ``B`` and the polynomial ``h`` as presented in [BW93]_, page 230. For this, @@ -371,4 +375,4 @@ def update(G,B,h): G_new.add(h) - return G_new,B_new + return G_new, B_new From 59360134eac8e1fe9232be42a755e98e809774a2 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Thu, 30 Mar 2017 22:30:42 +0200 Subject: [PATCH 146/223] simplify calls to giac --- src/sage/calculus/calculus.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index ba08f84fcdf..669a12b8c7c 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -1446,10 +1446,9 @@ def laplace(ex, t, s, algorithm='maxima'): return result elif algorithm == 'giac': - ex_gi = "laplace(%s, %s, %s)" % tuple([repr(expr._giac_()) for expr in (ex, t, s)]) from sage.interfaces.giac import giac try: - result = giac(ex_gi) + result = giac.laplace(ex, t, s) except TypeError: raise ValueError("Giac cannot make sense of: %s" % ex_gi) return result.sage() @@ -1607,10 +1606,9 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): " Sage".format(result)) elif algorithm == 'giac': - ex_gi = "invlaplace(%s, %s, %s)" % tuple([repr(expr._giac_()) for expr in (ex, s, t)]) from sage.interfaces.giac import giac try: - result = giac(ex_gi) + result = giac.invlaplace(ex, s, t) except TypeError: raise ValueError("Giac cannot make sense of: %s" % ex) return result.sage() From 716ac65de8e0001dfb4bd0e3add639c1a83eb98d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 30 Mar 2017 22:40:24 +0200 Subject: [PATCH 147/223] trac 6265 fixing doctest --- src/sage/rings/polynomial/toy_d_basis.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/polynomial/toy_d_basis.py b/src/sage/rings/polynomial/toy_d_basis.py index 800d1b4f798..7d9e8e2397c 100644 --- a/src/sage/rings/polynomial/toy_d_basis.py +++ b/src/sage/rings/polynomial/toy_d_basis.py @@ -86,8 +86,10 @@ However, when we compute the Groebner basis of I (defined over `\ZZ`), we note that there is a certain integer in the ideal which is not 1:: - sage: d_basis(I) - [x + 170269749119, y + 2149906854, z + ..., 282687803443] + sage: gb = d_basis(I); gb + [x ..., y ..., z ..., 282687803443] + sage: [p.monomials() for p in gb] + [[x, 1], [y, 1], [z, 1], [1]] Now for each prime `p` dividing this integer 282687803443, the Groebner basis of I modulo `p` will be non-trivial and will thus give a solution From 0577b5b29296ed8617f4d4b9a30b7f1353f4e694 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Thu, 30 Mar 2017 22:53:40 +0200 Subject: [PATCH 148/223] add register_symbol explanation and example to giac.py --- src/sage/interfaces/giac.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sage/interfaces/giac.py b/src/sage/interfaces/giac.py index da0c7692695..340d70df0f1 100644 --- a/src/sage/interfaces/giac.py +++ b/src/sage/interfaces/giac.py @@ -1018,6 +1018,9 @@ def _sage_(self, locals={}): - Sage knows how to translate the function or constant's name from Giac's naming scheme through the symbols_table, or - you provide a translation dictionary `locals`. + + New symbols can be added using Pynac's `register_symbol`. This is the + recommended approach for library code. Warning: List conversion is slow. @@ -1033,6 +1036,18 @@ def _sage_(self, locals={}): sage: m.trigexpand().sage() 2*cos(sqrt(-x^2 + 1))*cos(1/x)^2*sin(sqrt(-x^2 + 1)) - 4*cos(sqrt(-x^2 + 1))*cos(1/x)*sin(sqrt(-x^2 + 1)) + 2*cos(sqrt(-x^2 + 1))*sin(sqrt(-x^2 + 1)) + Converting a custom name using the `locals` dictionary:: + + sage: ex = giac('myFun(x)') + sage: ex._sage_({'myFun': sin}) + sin(x) + + Same but by adding a new entry to the `symbols_table`:: + + sage: ex = giac('myFun(x)') + sage: sage.libs.pynac.pynac.register_symbol(sin, {'giac':'myFun'}) + sage: ex._sage_() + sin(x) """ from sage.libs.pynac.pynac import symbol_table from sage.calculus.calculus import symbolic_expression_from_string From f5979029e901554e094d0261134112b3624d618b Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Thu, 30 Mar 2017 22:59:18 +0200 Subject: [PATCH 149/223] minor docstring modif --- src/sage/interfaces/giac.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/interfaces/giac.py b/src/sage/interfaces/giac.py index 340d70df0f1..5848533a587 100644 --- a/src/sage/interfaces/giac.py +++ b/src/sage/interfaces/giac.py @@ -1019,7 +1019,7 @@ def _sage_(self, locals={}): from Giac's naming scheme through the symbols_table, or - you provide a translation dictionary `locals`. - New symbols can be added using Pynac's `register_symbol`. This is the + New conversions can be added using Pynac's `register_symbol`. This is the recommended approach for library code. Warning: List conversion is slow. From 66bf40077256b637f124b958b3276c229fc42160 Mon Sep 17 00:00:00 2001 From: Marc Masdeu Date: Fri, 31 Mar 2017 16:53:59 +0200 Subject: [PATCH 150/223] Trac 22634: fixed one more bug. --- .../modular/btquotients/pautomorphicform.py | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/sage/modular/btquotients/pautomorphicform.py b/src/sage/modular/btquotients/pautomorphicform.py index c24889b0d8e..a30256add0e 100644 --- a/src/sage/modular/btquotients/pautomorphicform.py +++ b/src/sage/modular/btquotients/pautomorphicform.py @@ -571,12 +571,17 @@ def modular_form(self, z=None, level=0): sage: X = BruhatTitsQuotient(7,2) sage: H = X.harmonic_cocycles(4,20) + sage: f0, g0 = H.basis() sage: A = X.padic_automorphic_forms(4,20,overconvergent=True) - sage: f = A.lift(H.basis()[0]).modular_form(method='moments') + sage: f = A.lift(f0).modular_form(method='moments') sage: T. = Qq(7^2,20) sage: a,b,c,d = X.embed_quaternion(X.get_units_of_order()[1]).change_ring(Qp(7,20)).list() sage: (c*x + d)^4 * f(x) == f((a*x + b)/(c*x + d)) True + sage: g = A.lift(g0).modular_form(method='moments') + sage: (c*x + d)^4 * f(x) == f((a*x + b)/(c*x + d)) + True + """ return self.derivative(z, level, order=0) @@ -1815,25 +1820,18 @@ def _improve(self, hc): U = MMM._U S0 = MMM._Sigma0 - orig_moments = [[fval._moments[ii] for ii in range(MMM._n + 1)] - for fval in hc._F] - A = S0(Matrix(QQ, 2, 2, [0, 1 / MMM._p, 1, 0]),False) - for fval in hc._F: - tmp = -(A * fval) - orig_moments.append([tmp._moments[ii] for ii in range(MMM._n + 1)]) - h1 = MMM([o.lift(M=MMM.precision_cap()) for o in self._value]) - h2 = MMM._apply_Up_operator(h1, True, orig_moments) + h2 = MMM._apply_Up_operator(h1, True) verbose("Applied Up once") ii = 0 current_val = 0 - old_val = -Infinity init_val = self.valuation() + old_val = init_val - 1 while current_val > old_val: old_val = current_val ii += 1 h1._value = [U(c) for c in h2._value] - h2 = MMM._apply_Up_operator(h1, True, orig_moments) + h2 = MMM._apply_Up_operator(h1, True) current_val = (h2 - h1).valuation() - init_val verbose('val = %s' % current_val) if current_val is Infinity: From 821eb493806bc40ac280395316b7f22e0c0728dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 31 Mar 2017 20:01:51 +0200 Subject: [PATCH 151/223] trac 13514 change back default value of maxvectors --- src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py index e4e45389901..42a70b017f1 100644 --- a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +++ b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py @@ -546,7 +546,7 @@ def representation_number_list(self, B): return ans.sage() -def representation_vector_list(self, B, maxvectors=None): +def representation_vector_list(self, B, maxvectors=10**8): """ Find all vectors `v` where `Q(v) < B`. @@ -579,9 +579,6 @@ def representation_vector_list(self, B, maxvectors=None): ... TypeError: not available when the form is not positive definite """ - if maxvectors is None: - maxvectors = 10 ** 8 - if not self.is_positive_definite(): raise TypeError('not available when the form is not positive definite') From 1d27bd099b05d720531e0882d52c67ad198b6807 Mon Sep 17 00:00:00 2001 From: paulmasson Date: Fri, 31 Mar 2017 15:38:15 -0700 Subject: [PATCH 152/223] Add methods for offline scripts --- src/sage/plot/plot3d/base.pyx | 28 ++++--------- src/sage/repl/rich_output/backend_ipython.py | 41 +++++++++++++++++++- 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/src/sage/plot/plot3d/base.pyx b/src/sage/plot/plot3d/base.pyx index 688dfbd255f..36ec4d36247 100644 --- a/src/sage/plot/plot3d/base.pyx +++ b/src/sage/plot/plot3d/base.pyx @@ -377,28 +377,14 @@ cdef class Graphics3d(SageObject): options['online'] = True if options['online']: - scripts = ( """ - - - """ ) + from sage.misc.package import installed_packages + version = installed_packages()['threejs'] + scripts = """ + + + """.format(version) else: - from sage.repl.rich_output.backend_ipython import BackendIPythonNotebook - if isinstance(backend, BackendIPythonNotebook): - scripts = ( """ - - - - """ ) - else: - from sage.env import SAGE_SHARE - scripts = ( """ - - - """.format( SAGE_SHARE ) ) + scripts = backend.threejs_offline_scripts() b = self.bounding_box() bounds = '[{{"x":{}, "y":{}, "z":{}}}, {{"x":{}, "y":{}, "z":{}}}]'.format( diff --git a/src/sage/repl/rich_output/backend_ipython.py b/src/sage/repl/rich_output/backend_ipython.py index e5e85105df8..fa98be8bb0b 100644 --- a/src/sage/repl/rich_output/backend_ipython.py +++ b/src/sage/repl/rich_output/backend_ipython.py @@ -396,6 +396,24 @@ def is_in_terminal(self): """ return True + def threejs_offline_scripts(self): + """ + Three.js offline scripts for the IPython command line + + EXAMPLES:: + + sage: from sage.repl.rich_output.backend_ipython import BackendIPythonCommandline + sage: backend = BackendIPythonCommandline() + sage: backend.threejs_offline_scripts() + '... + + """.format(SAGE_SHARE) + + IFRAME_TEMPLATE = \ """ @@ -554,4 +572,25 @@ def displayhook(self, plain_text, rich_output): else: raise TypeError('rich_output type not supported') - + def threejs_offline_scripts(self): + """ + Three.js offline scripts for the IPython notebook + + EXAMPLES:: + + sage: from sage.repl.rich_output.backend_ipython import BackendIPythonNotebook + sage: backend = BackendIPythonNotebook() + sage: backend.threejs_offline_scripts() + '... + + + """.format(version) From 140579b4c2a251712763e21001df9aacce2b8c90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 1 Apr 2017 18:45:20 +0200 Subject: [PATCH 153/223] trac 6265 another tentative --- src/sage/rings/polynomial/toy_d_basis.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/polynomial/toy_d_basis.py b/src/sage/rings/polynomial/toy_d_basis.py index 7d9e8e2397c..30acf359a01 100644 --- a/src/sage/rings/polynomial/toy_d_basis.py +++ b/src/sage/rings/polynomial/toy_d_basis.py @@ -78,18 +78,16 @@ over `\QQ` or an algebraic closure of it (this is not surprising as there are 4 equations in 3 unknowns).:: - sage: P. = PolynomialRing(IntegerRing(), 3) + sage: P. = PolynomialRing(IntegerRing(), 3, order='degneglex') sage: I = ideal( x^2 - 3*y, y^3 - x*y, z^3 - x, x^4 - y*z + 1 ) - sage: I.change_ring( P.change_ring( RationalField() ) ).groebner_basis() + sage: I.change_ring(P.change_ring(RationalField())).groebner_basis() [1] However, when we compute the Groebner basis of I (defined over `\ZZ`), we note that there is a certain integer in the ideal which is not 1:: sage: gb = d_basis(I); gb - [x ..., y ..., z ..., 282687803443] - sage: [p.monomials() for p in gb] - [[x, 1], [y, 1], [z, 1], [1]] + [z - 107196348594952664476180297953816049406949517534824683390654620424703403993052759002989622, y + 84382748470495086324437828161121754084154498572003307352857967748090984550697850484197972764799434672877850291328840, x + 105754645239745824529618668609551113725317621921665293762587811716173, 282687803443] Now for each prime `p` dividing this integer 282687803443, the Groebner basis of I modulo `p` will be non-trivial and will thus give a solution @@ -99,13 +97,13 @@ 101 * 103 * 27173681 sage: I.change_ring( P.change_ring( GF(101) ) ).groebner_basis() - [x + 19, y + 48, z - 33] + [z - 33, y + 48, x + 19] sage: I.change_ring( P.change_ring( GF(103) ) ).groebner_basis() - [x + 39, y + 8, z - 18] + [z - 18, y + 8, x + 39] sage: I.change_ring( P.change_ring( GF(27173681) ) ).groebner_basis() - [x - 536027, y + 3186055, z + 10380032] + [z + 10380032, y + 3186055, x - 536027] Of course, modulo any other prime the Groebner basis is trivial so there are no other solutions. For example:: From c0f01df449f2e40c26d6e8002c42f08fec59e589 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 1 Apr 2017 13:52:05 -0500 Subject: [PATCH 154/223] Cache is_ideal and explaining doc what is clear from the code. --- .../finite_dimensional_lie_algebras_with_basis.py | 1 + src/sage/categories/lie_algebras.py | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) 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 60aa0f4d891..15c4a224c82 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -409,6 +409,7 @@ def center(self): """ return self.centralizer(self) + @cached_method def is_ideal(self, A): """ Return if ``self`` is an ideal of ``A``. diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index fd5cacb6f45..aa11740a999 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -205,7 +205,7 @@ def bracket(self, lhs, rhs): # Do not override this. Instead implement :meth:`_construct_UEA`; # then, :meth:`lift` and :meth:`universal_enveloping_algebra` - # will automatically setup the coercion + # will automatically setup the coercion. def universal_enveloping_algebra(self): """ Return the universal enveloping algebra of ``self``. @@ -239,6 +239,10 @@ def _construct_UEA(self): to the universal enveloping algebra (let alone register it as a coercion). + One should implement this method and the ``lift`` method for + the element class to construct the morphism the the universal + enveloping algebra. + EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() From fc395c8a0c03c608e2987b13dc0b8568e772046d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 1 Apr 2017 16:12:59 -0500 Subject: [PATCH 155/223] Fixing typo. --- src/sage/categories/lie_algebras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index aa11740a999..6d5c74a1011 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -240,7 +240,7 @@ def _construct_UEA(self): as a coercion). One should implement this method and the ``lift`` method for - the element class to construct the morphism the the universal + the element class to construct the morphism the universal enveloping algebra. EXAMPLES:: From 64ab6054b1316ce9faad4ec7b71ed0c0a3440d38 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 1 Apr 2017 18:40:55 -0500 Subject: [PATCH 156/223] Trivial fix by making docstring a raw string. --- src/sage/categories/lie_algebras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index 6d5c74a1011..6ba9c68b369 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -259,7 +259,7 @@ def _construct_UEA(self): @abstract_method(optional=True) def module(self): - """ + r""" Return an `R`-module which is isomorphic to the underlying `R`-module of ``self``. From 5c1c232846797d6fcfae891eef85019e4f532a02 Mon Sep 17 00:00:00 2001 From: paulmasson Date: Sat, 1 Apr 2017 17:58:40 -0700 Subject: [PATCH 157/223] Move all script generation to backend --- src/sage/plot/plot3d/base.pyx | 16 +------ src/sage/repl/rich_output/backend_base.py | 33 +++++++++++++- src/sage/repl/rich_output/backend_ipython.py | 48 ++++++++++++++------ src/sage/repl/rich_output/backend_sagenb.py | 24 ++++++++++ 4 files changed, 92 insertions(+), 29 deletions(-) diff --git a/src/sage/plot/plot3d/base.pyx b/src/sage/plot/plot3d/base.pyx index 36ec4d36247..983500a1351 100644 --- a/src/sage/plot/plot3d/base.pyx +++ b/src/sage/plot/plot3d/base.pyx @@ -356,7 +356,7 @@ cdef class Graphics3d(SageObject): EXAMPLES:: - sage: sphere()._rich_repr_threejs() + sage: sphere(online=True)._rich_repr_threejs() OutputSceneThreejs container """ options = {} @@ -372,19 +372,7 @@ cdef class Graphics3d(SageObject): from sage.repl.rich_output import get_display_manager backend = get_display_manager()._backend - from sage.repl.rich_output.backend_sagenb import BackendSageNB - if isinstance(backend, BackendSageNB): - options['online'] = True - - if options['online']: - from sage.misc.package import installed_packages - version = installed_packages()['threejs'] - scripts = """ - - - """.format(version) - else: - scripts = backend.threejs_offline_scripts() + scripts = backend.threejs_scripts(options['online']) b = self.bounding_box() bounds = '[{{"x":{}, "y":{}, "z":{}}}, {{"x":{}, "y":{}, "z":{}}}]'.format( diff --git a/src/sage/repl/rich_output/backend_base.py b/src/sage/repl/rich_output/backend_base.py index e45fca731f0..381e299a672 100644 --- a/src/sage/repl/rich_output/backend_base.py +++ b/src/sage/repl/rich_output/backend_base.py @@ -1,9 +1,9 @@ # -*- encoding: utf-8 -*- r""" -Base class for Backends +Base Class for Backends The display backends are the commandline, the SageNB notebook, the -ipython notebook, the Emacs sage mode, the Sage doctester, .... All of +IPython notebook, the Emacs sage mode, the Sage doctester, .... All of these have different capabilities for what they can display. To implement a new display backend, you need to subclass @@ -594,6 +594,35 @@ def display_immediately(self, plain_text, rich_output): """ raise NotImplementedError('derived classes must implement this method') + def threejs_scripts(self, online): + """ + Three.js scripts for the backend base + + INPUT: + + - ``online`` -- Boolean determining script usage context + + OUTPUT: + + String containing script tags + + EXAMPLES:: + + sage: from sage.repl.rich_output.backend_base import BackendBase + sage: backend = BackendBase() + sage: backend.threejs_scripts(True) + '... + + """.format(version) + else: + raise ValueError('online should be true for the backend base') + class BackendSimple(BackendBase): """ diff --git a/src/sage/repl/rich_output/backend_ipython.py b/src/sage/repl/rich_output/backend_ipython.py index fa98be8bb0b..aab32c26eb2 100644 --- a/src/sage/repl/rich_output/backend_ipython.py +++ b/src/sage/repl/rich_output/backend_ipython.py @@ -396,22 +396,33 @@ def is_in_terminal(self): """ return True - def threejs_offline_scripts(self): + def threejs_scripts(self, online): """ - Three.js offline scripts for the IPython command line + Three.js scripts for the IPython command line + + INPUT: + + - ``online`` -- Boolean determining script usage context + + OUTPUT: + + String containing script tags EXAMPLES:: sage: from sage.repl.rich_output.backend_ipython import BackendIPythonCommandline sage: backend = BackendIPythonCommandline() - sage: backend.threejs_offline_scripts() + sage: backend.threejs_scripts(True) '... - """.format(SAGE_SHARE) + """.format(SAGE_SHARE) @@ -572,20 +583,31 @@ def displayhook(self, plain_text, rich_output): else: raise TypeError('rich_output type not supported') - def threejs_offline_scripts(self): + def threejs_scripts(self, online): """ - Three.js offline scripts for the IPython notebook + Three.js scripts for the IPython notebook + + INPUT: + + - ``online`` -- Boolean determining script usage context + + OUTPUT: + + String containing script tags EXAMPLES:: sage: from sage.repl.rich_output.backend_ipython import BackendIPythonNotebook sage: backend = BackendIPythonNotebook() - sage: backend.threejs_offline_scripts() + sage: backend.threejs_scripts(True) '... - """.format(version) + """.format(version) diff --git a/src/sage/repl/rich_output/backend_sagenb.py b/src/sage/repl/rich_output/backend_sagenb.py index 7b3abc584ad..d276f4f16d5 100644 --- a/src/sage/repl/rich_output/backend_sagenb.py +++ b/src/sage/repl/rich_output/backend_sagenb.py @@ -452,3 +452,27 @@ def embed_video(self, video_output): url='cell://' + filename, link_attrs='class="file_link"', )) + + def threejs_scripts(self, online): + """ + Three.js scripts for the Sage notebook + + INPUT: + + - ``online`` -- Boolean determining script usage context + + OUTPUT: + + String containing script tags + + EXAMPLES:: + + sage: from sage.repl.rich_output.backend_sagenb import BackendSageNB + sage: backend = BackendSageNB() + sage: backend.threejs_scripts(True) + '......' + '\n - """.format(version) + """.format(CDN_scripts) From b73ce25630b98d1b6128d940c2bf6f970ad4a334 Mon Sep 17 00:00:00 2001 From: Andrey Novoseltsev Date: Sun, 2 Apr 2017 13:32:18 -0600 Subject: [PATCH 172/223] Pick up constructor options for threejs rendering --- src/sage/plot/plot3d/base.pyx | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/plot/plot3d/base.pyx b/src/sage/plot/plot3d/base.pyx index 983500a1351..1ce3dfcc9fc 100644 --- a/src/sage/plot/plot3d/base.pyx +++ b/src/sage/plot/plot3d/base.pyx @@ -359,13 +359,14 @@ cdef class Graphics3d(SageObject): sage: sphere(online=True)._rich_repr_threejs() OutputSceneThreejs container """ - options = {} - options['aspect_ratio'] = [float(i) for i in kwds.get('aspect_ratio', [1,1,1])] - options['axes'] = kwds.get('axes', False) - options['axes_labels'] = kwds.get('axes_labels', ['x','y','z']) - options['decimals'] = int(kwds.get('decimals', 2)) - options['frame'] = kwds.get('frame', True) - options['online'] = kwds.get('online', False) + options = self._process_viewing_options(kwds) + # Threejs specific options + options.setdefault('axes_labels', ['x','y','z']) + options.setdefault('decimals', 2) + options.setdefault('online', False) + # Normalization of options values for proper JSONing + options['aspect_ratio'] = [float(i) for i in options['aspect_ratio']] + options['decimals'] = int(options['decimals']) if not options['frame']: options['axes_labels'] = False @@ -414,10 +415,9 @@ cdef class Graphics3d(SageObject): surfaces = '[' + ','.join(surfaces) + ']' from sage.env import SAGE_EXTCODE - filename = os.path.join(SAGE_EXTCODE, 'threejs', 'threejs_template.html') - f = open(filename, 'r') - html = f.read() - f.close() + with open(os.path.join( + SAGE_EXTCODE, 'threejs', 'threejs_template.html')) as f: + html = f.read() html = html.replace('SAGE_SCRIPTS', scripts) html = html.replace('SAGE_OPTIONS', json.dumps(options)) From 750d024267314e8dd5668f4885295b0d0930103d Mon Sep 17 00:00:00 2001 From: Ben Hutz Date: Sun, 2 Apr 2017 14:36:12 -0500 Subject: [PATCH 173/223] 22556: fixed doc typo --- src/sage/schemes/projective/projective_morphism.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 605aef55caf..ade6f97599e 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -3159,7 +3159,7 @@ def periodic_points(self, n, minimal=True, R=None, algorithm='variety', return_s cycle graph. Default: ``variety``. - ``return_scheme`` - return a subscheme of the ambient space which defines the - ``n``th periodic points. + ``n`` th periodic points. OUTPUT: From f5144256fd873eb051f174e4b86daf7abef1d4a5 Mon Sep 17 00:00:00 2001 From: Andrey Novoseltsev Date: Sun, 2 Apr 2017 15:40:29 -0600 Subject: [PATCH 174/223] Do not embedd all Sage options into a threejs scene --- src/sage/plot/plot3d/base.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/plot/plot3d/base.pyx b/src/sage/plot/plot3d/base.pyx index 1ce3dfcc9fc..0b1af457f18 100644 --- a/src/sage/plot/plot3d/base.pyx +++ b/src/sage/plot/plot3d/base.pyx @@ -420,6 +420,8 @@ cdef class Graphics3d(SageObject): html = f.read() html = html.replace('SAGE_SCRIPTS', scripts) + options = dict((key, options[key]) for key in + ['aspect_ratio', 'axes', 'axes_labels', 'decimals', 'frame']) html = html.replace('SAGE_OPTIONS', json.dumps(options)) html = html.replace('SAGE_BOUNDS', bounds) html = html.replace('SAGE_LIGHTS', lights) From e81038e11c2a0d8fbf289d65cf31c64f71862677 Mon Sep 17 00:00:00 2001 From: Andrey Novoseltsev Date: Sun, 2 Apr 2017 16:09:19 -0600 Subject: [PATCH 175/223] Do not access display backend directly from plot 3d --- src/sage/plot/plot3d/base.pyx | 3 +- src/sage/repl/rich_output/backend_base.py | 39 ------------------ src/sage/repl/rich_output/backend_ipython.py | 38 ++++++------------ src/sage/repl/rich_output/backend_sagenb.py | 14 ++----- src/sage/repl/rich_output/display_manager.py | 42 ++++++++++++++++++++ 5 files changed, 59 insertions(+), 77 deletions(-) diff --git a/src/sage/plot/plot3d/base.pyx b/src/sage/plot/plot3d/base.pyx index 0b1af457f18..222337345a7 100644 --- a/src/sage/plot/plot3d/base.pyx +++ b/src/sage/plot/plot3d/base.pyx @@ -372,8 +372,7 @@ cdef class Graphics3d(SageObject): options['axes_labels'] = False from sage.repl.rich_output import get_display_manager - backend = get_display_manager()._backend - scripts = backend.threejs_scripts(options['online']) + scripts = get_display_manager().threejs_scripts(options['online']) b = self.bounding_box() bounds = '[{{"x":{}, "y":{}, "z":{}}}, {{"x":{}, "y":{}, "z":{}}}]'.format( diff --git a/src/sage/repl/rich_output/backend_base.py b/src/sage/repl/rich_output/backend_base.py index f42a3fbc129..5b60d1b1128 100644 --- a/src/sage/repl/rich_output/backend_base.py +++ b/src/sage/repl/rich_output/backend_base.py @@ -594,45 +594,6 @@ def display_immediately(self, plain_text, rich_output): """ raise NotImplementedError('derived classes must implement this method') - def threejs_scripts(self, online): - """ - Three.js scripts for the backend base - - INPUT: - - - ``online`` -- Boolean determining script usage context - - OUTPUT: - - String containing script tags - - .. NOTE:: - - This base method handles ``online=True`` case only, serving CDN - script tags. Location of scripts for off-line usage is - backend-specific. - - EXAMPLES:: - - sage: from sage.repl.rich_output.backend_base import BackendBase - sage: backend = BackendBase() - sage: backend.threejs_scripts(True) - '\n - - """.format(version) - else: - raise ValueError('online should be true for the backend base') - class BackendSimple(BackendBase): """ diff --git a/src/sage/repl/rich_output/backend_ipython.py b/src/sage/repl/rich_output/backend_ipython.py index 2f09068bf19..52518bda39c 100644 --- a/src/sage/repl/rich_output/backend_ipython.py +++ b/src/sage/repl/rich_output/backend_ipython.py @@ -396,14 +396,10 @@ def is_in_terminal(self): """ return True - def threejs_scripts(self, online): + def threejs_offline_scripts(self): """ Three.js scripts for the IPython command line - INPUT: - - - ``online`` -- Boolean determining script usage context - OUTPUT: String containing script tags @@ -412,18 +408,14 @@ def threejs_scripts(self, online): sage: from sage.repl.rich_output.backend_ipython import BackendIPythonCommandline sage: backend = BackendIPythonCommandline() - sage: backend.threejs_scripts(True) + sage: backend.threejs_offline_scripts() '... - """.format(SAGE_SHARE) - + """.format(SAGE_SHARE) IFRAME_TEMPLATE = \ @@ -583,14 +575,10 @@ def displayhook(self, plain_text, rich_output): else: raise TypeError('rich_output type not supported') - def threejs_scripts(self, online): + def threejs_offline_scripts(self): """ Three.js scripts for the IPython notebook - INPUT: - - - ``online`` -- Boolean determining script usage context - OUTPUT: String containing script tags @@ -599,17 +587,15 @@ def threejs_scripts(self, online): sage: from sage.repl.rich_output.backend_ipython import BackendIPythonNotebook sage: backend = BackendIPythonNotebook() - sage: backend.threejs_scripts(True) - '......' """ - CDN_scripts = super(BackendIPythonNotebook, self).threejs_scripts(True) - if online: - return CDN_scripts - else: - return """ + from sage.repl.rich_output import get_display_manager + CDN_scripts = get_display_manager().threejs_scripts(online=True) + return """ - """.format(CDN_scripts) + """.format(CDN_scripts) diff --git a/src/sage/repl/rich_output/backend_sagenb.py b/src/sage/repl/rich_output/backend_sagenb.py index d276f4f16d5..287527747f2 100644 --- a/src/sage/repl/rich_output/backend_sagenb.py +++ b/src/sage/repl/rich_output/backend_sagenb.py @@ -453,14 +453,10 @@ def embed_video(self, video_output): link_attrs='class="file_link"', )) - def threejs_scripts(self, online): + def threejs_offline_scripts(self): """ Three.js scripts for the Sage notebook - INPUT: - - - ``online`` -- Boolean determining script usage context - OUTPUT: String containing script tags @@ -469,10 +465,8 @@ def threejs_scripts(self, online): sage: from sage.repl.rich_output.backend_sagenb import BackendSageNB sage: backend = BackendSageNB() - sage: backend.threejs_scripts(True) + sage: backend.threejs_offline_scripts() '... + + """.format(version) + try: + return self._backend.threejs_offline_scripts() + except AttributeError: + raise ValueError( + 'current backend does not support offline threejs graphics') + def supported_output(self): """ Return the output container classes that can be used. From 8d1b1555d032b999e2f779bd481544e2ec03d483 Mon Sep 17 00:00:00 2001 From: Andrey Novoseltsev Date: Sun, 2 Apr 2017 19:07:11 -0600 Subject: [PATCH 176/223] Little fixes to threejs scripts handling --- src/sage/plot/plot3d/base.pyx | 4 ++-- src/sage/repl/rich_output/backend_ipython.py | 4 ++-- src/sage/repl/rich_output/display_manager.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/plot/plot3d/base.pyx b/src/sage/plot/plot3d/base.pyx index 222337345a7..e0c11914b8b 100644 --- a/src/sage/plot/plot3d/base.pyx +++ b/src/sage/plot/plot3d/base.pyx @@ -419,9 +419,9 @@ cdef class Graphics3d(SageObject): html = f.read() html = html.replace('SAGE_SCRIPTS', scripts) - options = dict((key, options[key]) for key in + js_options = dict((key, options[key]) for key in ['aspect_ratio', 'axes', 'axes_labels', 'decimals', 'frame']) - html = html.replace('SAGE_OPTIONS', json.dumps(options)) + html = html.replace('SAGE_OPTIONS', json.dumps(js_options)) html = html.replace('SAGE_BOUNDS', bounds) html = html.replace('SAGE_LIGHTS', lights) html = html.replace('SAGE_AMBIENT', ambient) diff --git a/src/sage/repl/rich_output/backend_ipython.py b/src/sage/repl/rich_output/backend_ipython.py index 52518bda39c..9323fb76d2c 100644 --- a/src/sage/repl/rich_output/backend_ipython.py +++ b/src/sage/repl/rich_output/backend_ipython.py @@ -588,7 +588,7 @@ def threejs_offline_scripts(self): sage: from sage.repl.rich_output.backend_ipython import BackendIPythonNotebook sage: backend = BackendIPythonNotebook() sage: backend.threejs_offline_scripts() - '\n...' + '\n - """.format(CDN_scripts) + """.format(CDN_scripts.replace('', r'<\/script>')) diff --git a/src/sage/repl/rich_output/display_manager.py b/src/sage/repl/rich_output/display_manager.py index 88d443ee876..f48527df8f9 100644 --- a/src/sage/repl/rich_output/display_manager.py +++ b/src/sage/repl/rich_output/display_manager.py @@ -715,7 +715,7 @@ def graphics_from_save(self, save_function, save_kwds, def threejs_scripts(self, online): """ - Return three.js script tags for the current backend. + Return Three.js script tags for the current backend. INPUT: @@ -728,7 +728,7 @@ def threejs_scripts(self, online): .. NOTE:: This base method handles ``online=True`` case only, serving CDN - script tags. Location of scripts for off-line usage is + script tags. Location of scripts for offline usage is backend-specific. EXAMPLES:: From 07d53b568514d8c222e5c23b038261d23964bf5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 3 Apr 2017 14:23:10 +0200 Subject: [PATCH 177/223] py3: wrap some "map" with "list" --- src/doc/en/thematic_tutorials/functional_programming.rst | 6 +++--- src/doc/en/thematic_tutorials/numtheory_rsa.rst | 2 +- src/sage/combinat/matrices/dancing_links.pyx | 2 +- src/sage/libs/coxeter3/coxeter_group.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/en/thematic_tutorials/functional_programming.rst b/src/doc/en/thematic_tutorials/functional_programming.rst index ef24c37ba92..af6d160c061 100644 --- a/src/doc/en/thematic_tutorials/functional_programming.rst +++ b/src/doc/en/thematic_tutorials/functional_programming.rst @@ -191,7 +191,7 @@ matrices:: sage: rows = [randint(1, 10) for i in range(10)] sage: cols = [randint(1, 10) for i in range(10)] sage: rings = [ZZ]*10 - sage: M = map(random_matrix, rings, rows, cols) + sage: M = list(map(random_matrix, rings, rows, cols)) sage: M[0] # random [ -1 -3 -1 -37 1 -1 -4 5] @@ -213,8 +213,8 @@ together with ``map`` as follows:: [ 2 6 2] sage: rows = [randint(1, 10) for i in range(10)] sage: cols = [randint(1, 10) for i in range(10)] - sage: M = map(rand_mat, rows, cols) - sage: M = map(matrix, M) + sage: M = list(map(rand_mat, rows, cols)) + sage: M = list(map(matrix, M)) sage: M[0] # random [ 9 1 5 2 10 10 1] diff --git a/src/doc/en/thematic_tutorials/numtheory_rsa.rst b/src/doc/en/thematic_tutorials/numtheory_rsa.rst index 1ffee452ef3..5825e4278b5 100644 --- a/src/doc/en/thematic_tutorials/numtheory_rsa.rst +++ b/src/doc/en/thematic_tutorials/numtheory_rsa.rst @@ -400,7 +400,7 @@ practice. In Sage, we can obtain an integer representation of our message as follows:: sage: m = "HELLOWORLD" - sage: m = map(ord, m); m + sage: m = list(map(ord, m)); m [72, 69, 76, 76, 79, 87, 79, 82, 76, 68] sage: m = ZZ(list(reversed(m)), 100) ; m 72697676798779827668 diff --git a/src/sage/combinat/matrices/dancing_links.pyx b/src/sage/combinat/matrices/dancing_links.pyx index efb0682077a..359f55c5e5d 100644 --- a/src/sage/combinat/matrices/dancing_links.pyx +++ b/src/sage/combinat/matrices/dancing_links.pyx @@ -353,7 +353,7 @@ cdef class dancing_linksWrapper: :: sage: S = Subsets(range(5)) - sage: rows = map(list, S) + sage: rows = list(map(list, S)) sage: d = dlx_solver(rows) sage: d.number_of_solutions() 52 diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index 9441258d8b3..4845e847af5 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -581,7 +581,7 @@ def poincare_polynomial(self): t^5 + 4*t^4 + 6*t^3 + 5*t^2 + 3*t + 1 sage: rw = sage.combinat.permutation.from_reduced_word # optional - coxeter3 - sage: p = map(attrcall('poincare_polynomial'), W) # optional - coxeter3 + sage: p = list(map(attrcall('poincare_polynomial'), W)) # optional - coxeter3 sage: [rw(w.reduced_word()) for i,w in enumerate(W) if p[i] != p[i].reverse()] # optional - coxeter3 [[3, 4, 1, 2], [4, 2, 3, 1]] """ From 6d3a8d4acff68d6d00a9d6cf5e83b2b5067645f4 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 3 Apr 2017 10:06:41 -0500 Subject: [PATCH 178/223] Using generators instead of list(map(f, L)). --- src/doc/en/thematic_tutorials/numtheory_rsa.rst | 2 +- src/sage/combinat/matrices/dancing_links.pyx | 2 +- src/sage/libs/coxeter3/coxeter_group.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/en/thematic_tutorials/numtheory_rsa.rst b/src/doc/en/thematic_tutorials/numtheory_rsa.rst index 5825e4278b5..789dd73d3f2 100644 --- a/src/doc/en/thematic_tutorials/numtheory_rsa.rst +++ b/src/doc/en/thematic_tutorials/numtheory_rsa.rst @@ -400,7 +400,7 @@ practice. In Sage, we can obtain an integer representation of our message as follows:: sage: m = "HELLOWORLD" - sage: m = list(map(ord, m)); m + sage: m = [ord(x) for x in m]; m [72, 69, 76, 76, 79, 87, 79, 82, 76, 68] sage: m = ZZ(list(reversed(m)), 100) ; m 72697676798779827668 diff --git a/src/sage/combinat/matrices/dancing_links.pyx b/src/sage/combinat/matrices/dancing_links.pyx index 359f55c5e5d..6e27bc73fa3 100644 --- a/src/sage/combinat/matrices/dancing_links.pyx +++ b/src/sage/combinat/matrices/dancing_links.pyx @@ -353,7 +353,7 @@ cdef class dancing_linksWrapper: :: sage: S = Subsets(range(5)) - sage: rows = list(map(list, S)) + sage: rows = [list(x) for x in S] sage: d = dlx_solver(rows) sage: d.number_of_solutions() 52 diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index 4845e847af5..8c429d43cec 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -581,7 +581,7 @@ def poincare_polynomial(self): t^5 + 4*t^4 + 6*t^3 + 5*t^2 + 3*t + 1 sage: rw = sage.combinat.permutation.from_reduced_word # optional - coxeter3 - sage: p = list(map(attrcall('poincare_polynomial'), W)) # optional - coxeter3 + sage: p = [w.poincare_polynomial() for w in W] # optional - coxeter3 sage: [rw(w.reduced_word()) for i,w in enumerate(W) if p[i] != p[i].reverse()] # optional - coxeter3 [[3, 4, 1, 2], [4, 2, 3, 1]] """ From 849d43185c5fc21a8872b50949848591f7703011 Mon Sep 17 00:00:00 2001 From: Ben Hutz Date: Mon, 3 Apr 2017 10:12:53 -0500 Subject: [PATCH 179/223] 22556: fix indeterminacy_locus --- src/sage/schemes/projective/projective_morphism.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 787d0b0d2ca..2a1dc93fdf9 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -5537,7 +5537,7 @@ def indeterminacy_locus(self): """ dom = self.domain() AS = dom.ambient_space() - return AS.subscheme(list(dom.defining_polynomials()) + self.defining_polynomials()) + return AS.subscheme(list(dom.defining_polynomials()) + list(self.defining_polynomials())) def indeterminacy_points(self, F=None): r""" From 668eeee7f0f03c5c2ccfb44f33925fabaf28a63c Mon Sep 17 00:00:00 2001 From: paulmasson Date: Mon, 3 Apr 2017 14:16:01 -0700 Subject: [PATCH 180/223] Allow documentation to build --- src/sage/repl/rich_output/backend_ipython.py | 2 +- src/sage/repl/rich_output/display_manager.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/repl/rich_output/backend_ipython.py b/src/sage/repl/rich_output/backend_ipython.py index 9323fb76d2c..1a974b684c7 100644 --- a/src/sage/repl/rich_output/backend_ipython.py +++ b/src/sage/repl/rich_output/backend_ipython.py @@ -588,7 +588,7 @@ def threejs_offline_scripts(self): sage: from sage.repl.rich_output.backend_ipython import BackendIPythonNotebook sage: backend = BackendIPythonNotebook() sage: backend.threejs_offline_scripts() - '\n