text: r"""
  Verma Modules
  
  AUTHORS:
  
  - Travis Scrimshaw (2017-06-30): Initial version
  
  .. TODO::
  
      Implement a :class:`sage.categories.pushout.ConstructionFunctor`
      and return as the ``construction()``.
  """
  
  #*****************************************************************************
  #       Copyright (C) 2017 Travis Scrimshaw <tcscrims at gmail.com>
  #
  # This program is free software: you can redistribute it and/or modify
  # it under the terms of the GNU General Public License as published by
  # the Free Software Foundation, either version 2 of the License, or
  # (at your option) any later version.
  #                  http://www.gnu.org/licenses/
  #*****************************************************************************
  
  from sage.misc.lazy_attribute import lazy_attribute
  from sage.misc.cachefunc import cached_method
  from sage.categories.modules import Modules
  from sage.categories.morphism import Morphism
  from sage.categories.homset import Hom, Homset
  from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid
  from sage.combinat.free_module import CombinatorialFreeModule
  from sage.modules.free_module_element import vector
  from sage.sets.family import Family
  from sage.structure.richcmp import richcmp
  from sage.rings.all import ZZ, QQ
  
  
  class VermaModule(CombinatorialFreeModule):
      r"""
      A Verma module.
  
      Let `\lambda` be a weight and `\mathfrak{g}` be a Kac--Moody Lie
      algebra with a fixed Borel subalgebra `\mathfrak{b} = \mathfrak{h}
      \oplus \mathfrak{g}^+`. The *Verma module* `M_{\lambda}` is a
      `U(\mathfrak{g})`-module given by
  
      .. MATH::
  
          M_{\lambda} := U(\mathfrak{g}) \otimes_{U(\mathfrak{b})} F_{\lambda},
  
      where `F_{\lambda}` is the `U(\mathfrak{b})` module such that
      `h \in U(\mathfrak{h})` acts as multiplication by
      `\langle \lambda, h \rangle` and `U\mathfrak{g}^+) F_{\lambda} = 0`.
  
      INPUT:
  
      - ``g`` -- a Lie algebra
      - ``weight`` -- a weight
  
      EXAMPLES::
  
          sage: L = lie_algebras.sl(QQ, 3)
          sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
          sage: M = L.verma_module(2*La[1] + 3*La[2])
          sage: pbw = M.pbw_basis()
          sage: E1,E2,F1,F2,H1,H2 = [pbw(g) for g in L.gens()]
          sage: v = M.highest_weight_vector()
          sage: x = F2^3 * F1 * v
          sage: x
          f[-alpha[2]]^3*f[-alpha[1]]*v[2*Lambda[1] + 3*Lambda[2]]
          sage: F1 * x
          f[-alpha[2]]^3*f[-alpha[1]]^2*v[2*Lambda[1] + 3*Lambda[2]]
           + 3*f[-alpha[2]]^2*f[-alpha[1]]*f[-alpha[1] - alpha[2]]*v[2*Lambda[1] + 3*Lambda[2]]
          sage: E1 * x
          2*f[-alpha[2]]^3*v[2*Lambda[1] + 3*Lambda[2]]
          sage: H1 * x
          3*f[-alpha[2]]^3*f[-alpha[1]]*v[2*Lambda[1] + 3*Lambda[2]]
          sage: H2 * x
          -2*f[-alpha[2]]^3*f[-alpha[1]]*v[2*Lambda[1] + 3*Lambda[2]]
  
      REFERENCES:
  
      - :wikipedia:`Verma_module`
      """
      def __init__(self, g, weight, basis_key=None, prefix='f', **kwds):
          """
          Initialize ``self``.
  
          TESTS::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + 4*La[2])
              sage: TestSuite(M).run()
              sage: M = L.verma_module(La[1] - 2*La[2])
              sage: TestSuite(M).run()
  
              sage: L = lie_algebras.sp(QQ, 4)
              sage: La = L.cartan_type().root_system().ambient_space().fundamental_weights()
              sage: M = L.verma_module(-1/2*La[1] + 3/7*La[2])
              sage: TestSuite(M).run()
          """
          if basis_key is not None:
              self._basis_key = basis_key
          else:
              self._basis_key = g._basis_key
  
          self._weight = weight
  
          R = g.base_ring()
          self._g = g
          self._pbw = g.pbw_basis(basis_key=self._triangular_key)
          monomials = IndexedFreeAbelianMonoid(g._negative_half_index_set(),
                                               prefix,
                                               sorting_key=self._monoid_key,
                                               **kwds)
          CombinatorialFreeModule.__init__(self, R, monomials,
                                           prefix='', bracket=False, latex_bracket=False,
                                           sorting_key=self._monomial_key,
                                           category=Modules(R).WithBasis().Graded())
  
      def _triangular_key(self, x):
          """
          Return a key for sorting for the index ``x`` that respects
          the triangular decomposition by `U^-, U^0, U^+`.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1])
              sage: sorted(L.basis().keys(), key=L._basis_key)
              [alpha[2], alpha[1], alpha[1] + alpha[2],
               alphacheck[1], alphacheck[2],
               -alpha[2], -alpha[1], -alpha[1] - alpha[2]]
              sage: sorted(L.basis().keys(), key=M._triangular_key)
              [-alpha[2], -alpha[1], -alpha[1] - alpha[2],
               alphacheck[1], alphacheck[2],
               alpha[2], alpha[1], alpha[1] + alpha[2]]
  
              sage: def neg_key(x):
              ....:     return -L.basis().keys().index(x)
              sage: sorted(L.basis().keys(), key=neg_key)
              [-alpha[1] - alpha[2], -alpha[1], -alpha[2],
               alphacheck[2], alphacheck[1],
               alpha[1] + alpha[2], alpha[1], alpha[2]]
              sage: N = L.verma_module(La[1], basis_key=neg_key)
              sage: sorted(L.basis().keys(), key=N._triangular_key)
              [-alpha[1] - alpha[2], -alpha[1], -alpha[2],
               alphacheck[2], alphacheck[1],
               alpha[1] + alpha[2], alpha[1], alpha[2]]
          """
          return (self._g._part_on_basis(x), self._basis_key(x))
  
      def _monoid_key(self, x):
          """
          Return a key for comparison in the underlying monoid of ``self``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1])
              sage: monoid = M.basis().keys()
              sage: prod(monoid.gens())  # indirect doctest
              f[-alpha[2]]*f[-alpha[1]]*f[-alpha[1] - alpha[2]]
              sage: [M._monoid_key(x) for x in monoid.an_element()._sorted_items()]
              [5, 6, 7]
  
              sage: def neg_key(x):
              ....:     return -L.basis().keys().index(x)
              sage: M = L.verma_module(La[1], basis_key=neg_key)
              sage: monoid = M.basis().keys()
              sage: prod(monoid.gens())  # indirect doctest
              f[-alpha[1] - alpha[2]]*f[-alpha[1]]*f[-alpha[2]]
              sage: [M._monoid_key(x) for x in monoid.an_element()._sorted_items()]
              [-7, -6, -5]
          """
          return self._basis_key(x[0])
  
      def _monomial_key(self, x):
          """
          Compute the key for ``x`` so that the comparison is done by
          triangular decomposition and then reverse degree lexicographic order.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1])
              sage: pbw = M.pbw_basis()
              sage: f1,f2 = pbw(L.f(1)), pbw(L.f(2))
              sage: f1 * f2 * f1 * M.highest_weight_vector()  # indirect doctest
              f[-alpha[2]]*f[-alpha[1]]^2*v[Lambda[1]]
               + f[-alpha[1]]*f[-alpha[1] - alpha[2]]*v[Lambda[1]]
  
              sage: def neg_key(x):
              ....:     return -L.basis().keys().index(x)
              sage: M = L.verma_module(La[1], basis_key=neg_key)
              sage: f1 * f2 * f1 * M.highest_weight_vector()  # indirect doctest
              f[-alpha[1]]^2*f[-alpha[2]]*v[Lambda[1]]
               - f[-alpha[1] - alpha[2]]*f[-alpha[1]]*v[Lambda[1]]
          """
          return (-len(x), [self._triangular_key(l) for l in x.to_word_list()])
  
      def _repr_(self):
          """
          Return a string representation of ``self``.
  
          EXAMPLES::
  
              sage: L = LieAlgebra(QQ, cartan_type=['E',6])
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(2*La[1] + 3*La[2] - 5*La[5])
              sage: M
              Verma module with highest weight 2*Lambda[1] + 3*Lambda[2] - 5*Lambda[5]
               of Lie algebra of ['E', 6] in the Chevalley basis
          """
          return "Verma module with highest weight {} of {}".format(self._weight, self._g)
  
      def _latex_(self):
          r"""
          Return a latex representation of ``self``.
  
          EXAMPLES::
  
              sage: L = LieAlgebra(QQ, cartan_type=['E',7])
              sage: La = L.cartan_type().root_system().weight_space().fundamental_weights()
              sage: M = L.verma_module(2*La[1] + 7*La[4] - 3/4*La[7])
              sage: latex(M)
              M_{2\Lambda_{1} + 7\Lambda_{4} - \frac{3}{4}\Lambda_{7}}
          """
          from sage.misc.latex import latex
          return "M_{{{}}}".format(latex(self._weight))
  
      def _repr_generator(self, m):
          r"""
          Return a string representation of the generator indexed by ``m``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sp(QQ, 4)
              sage: La = L.cartan_type().root_system().ambient_space().fundamental_weights()
              sage: M = L.verma_module(-1/2*La[1] + 3/7*La[2])
              sage: f1, f2 = L.f(1), L.f(2)
              sage: x = M.pbw_basis()(L([f1, [f1, f2]]))
              sage: v = x * M.highest_weight_vector()
              sage: M._repr_generator(v.leading_support())
              'f[-2*alpha[1] - alpha[2]]*v[(-1/14, 3/7)]'
  
              sage: M.highest_weight_vector()
              v[(-1/14, 3/7)]
              sage: 2 * M.highest_weight_vector()
              2*v[(-1/14, 3/7)]
          """
          ret = super(VermaModule, self)._repr_generator(m)
          if ret == '1':
              ret = ''
          else:
              ret += '*'
          return ret + "v[{}]".format(self._weight)
  
      def _latex_generator(self, m):
          r"""
          Return a latex representation of the generator indexed by ``m``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sp(QQ, 4)
              sage: La = L.cartan_type().root_system().ambient_space().fundamental_weights()
              sage: M = L.verma_module(-1/2*La[1] + 3/7*La[2])
              sage: f1, f2 = L.f(1), L.f(2)
              sage: x = M.pbw_basis()(L([f1, [f1, f2]]))
              sage: v = x * M.highest_weight_vector()
              sage: M._latex_generator(v.leading_support())
              f_{-2\alpha_{1} - \alpha_{2}} v_{-\frac{1}{14}e_{0} + \frac{3}{7}e_{1}}
  
              sage: latex(2 * M.highest_weight_vector())
              2 v_{-\frac{1}{14}e_{0} + \frac{3}{7}e_{1}}
              sage: latex(M.highest_weight_vector())
              v_{-\frac{1}{14}e_{0} + \frac{3}{7}e_{1}}
          """
          ret = super(VermaModule, self)._latex_generator(m)
          if ret == '1':
              ret = ''
          from sage.misc.latex import latex
          return ret + " v_{{{}}}".format(latex(self._weight))
  
      _repr_term = _repr_generator
      _latex_term = _latex_generator
  
      def lie_algebra(self):
          """
          Return the underlying Lie algebra of ``self``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.so(QQ, 9)
              sage: La = L.cartan_type().root_system().weight_space().fundamental_weights()
              sage: M = L.verma_module(La[3] - 1/2*La[1])
              sage: M.lie_algebra()
              Lie algebra of ['B', 4] in the Chevalley basis
          """
          return self._g
  
      def pbw_basis(self):
          """
          Return the PBW basis of the underlying Lie algebra
          used to define ``self``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.so(QQ, 8)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[2] - 2*La[3])
              sage: M.pbw_basis()
              Universal enveloping algebra of Lie algebra of ['D', 4] in the Chevalley basis
               in the Poincare-Birkhoff-Witt basis
          """
          return self._pbw
  
      poincare_birkhoff_witt_basis = pbw_basis
  
      @cached_method
      def highest_weight_vector(self):
          """
          Return the highest weight vector of ``self``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sp(QQ, 6)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] - 3*La[2])
              sage: M.highest_weight_vector()
              v[Lambda[1] - 3*Lambda[2]]
          """
          one = self.base_ring().one()
          return self._from_dict({self._indices.one(): one},
                                 remove_zeros=False, coerce=False)
  
      def gens(self):
          r"""
          Return the generators of ``self`` as a `U(\mathfrak{g})`-module.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sp(QQ, 6)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] - 3*La[2])
              sage: M.gens()
              (v[Lambda[1] - 3*Lambda[2]],)
          """
          return (self.highest_weight_vector(),)
  
      def highest_weight(self):
          r"""
          Return the highest weight of ``self``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.so(QQ, 7)
              sage: La = L.cartan_type().root_system().weight_space().fundamental_weights()
              sage: M = L.verma_module(4*La[1] - 3/2*La[2])
              sage: M.highest_weight()
              4*Lambda[1] - 3/2*Lambda[2]
          """
          return self._weight
  
      def degree_on_basis(self, m):
          r"""
          Return the degree (or weight) of the basis element indexed by ``m``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(2*La[1] + 3*La[2])
              sage: v = M.highest_weight_vector()
              sage: M.degree_on_basis(v.leading_support())
              2*Lambda[1] + 3*Lambda[2]
  
              sage: pbw = M.pbw_basis()
              sage: G = list(pbw.gens())
              sage: f1, f2 = L.f()
              sage: x = pbw(f1.bracket(f2)) * pbw(f1) * v
              sage: x.degree()
              -Lambda[1] + 3*Lambda[2]
          """
          P = self._weight.parent()
          return self._weight + P.sum(P(e * self._g.degree_on_basis(k))
                                      for k,e in m.dict().items())
  
      def _coerce_map_from_(self, R):
          r"""
          Return if there is a coercion map from ``R`` to ``self``.
  
          There is a coercion map from ``R`` if and only if
  
          - there is a coercion from ``R`` into the base ring;
          - ``R`` is a Verma module over the same Lie algebra and
            there is a non-zero Verma module morphism from ``R``
            into ``self``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.so(QQ, 8)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([1,2]))
              sage: Mpp = L.verma_module(M.highest_weight().dot_action([1,2]) + La[1])
              sage: M._coerce_map_from_(Mp) is not None
              True
              sage: Mp._coerce_map_from_(M)
              sage: M._coerce_map_from_(Mpp)
              sage: M._coerce_map_from_(ZZ)
              True
          """
          if self.base_ring().has_coerce_map_from(R):
              return True
          if isinstance(R, VermaModule) and R._g is self._g:
              H = Hom(R, self)
              if H.dimension() == 1:
                  return H.natural_map()
          return super(VermaModule, self)._coerce_map_from_(R)
  
      def _element_constructor_(self, x):
          r"""
          Construct an element of ``self`` from ``x``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + 2*La[2])
              sage: M(3)
              3*v[Lambda[1] + 2*Lambda[2]]
              sage: pbw = M.pbw_basis()
              sage: [M(g) for g in pbw.gens()]
              [0,
               0,
               0,
               v[Lambda[1] + 2*Lambda[2]],
               2*v[Lambda[1] + 2*Lambda[2]],
               f[-alpha[2]]*v[Lambda[1] + 2*Lambda[2]],
               f[-alpha[1]]*v[Lambda[1] + 2*Lambda[2]],
               f[-alpha[1] - alpha[2]]*v[Lambda[1] + 2*Lambda[2]]]
          """
          if x in self.base_ring():
              return self._from_dict({self._indices.one(): x})
          if isinstance(x, self._pbw.element_class):
              return self.highest_weight_vector()._acted_upon_(x, False)
          return super(VermaModule, self)._element_constructor_(self, x)
  
      @lazy_attribute
      def _dominant_data(self):
          r"""
          Return the closest to dominant weight in the dot orbit of
          the highest weight of ``self`` and the corresponding reduced word.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: M._dominant_data
              (Lambda[1] + Lambda[2], [])
              sage: M = L.verma_module(M.highest_weight().dot_action([1,2]))
              sage: M._dominant_data
              (Lambda[1] + Lambda[2], [1, 2])
              sage: M = L.verma_module(-4*La[1] - La[2])
              sage: M._dominant_data
              (-Lambda[1] + 2*Lambda[2], [1, 2])
          """
          P = self._weight.parent()
          wt, w = (self._weight + P.rho()).to_dominant_chamber(reduced_word=True)
          return (wt - P.rho(), w)
  
      def is_singular(self):
          r"""
          Return if ``self`` is a singular Verma module.
  
          A Verma module `M_{\lambda}` is *singular* if there does not
          exist a dominant weight `\tilde{\lambda}` that is in the dot
          orbit of `\lambda`. We call a Verma module *regular* otherwise.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: M.is_singular()
              False
              sage: M = L.verma_module(La[1] - La[2])
              sage: M.is_singular()
              True
              sage: M = L.verma_module(2*La[1] - 10*La[2])
              sage: M.is_singular()
              False
              sage: M = L.verma_module(-2*La[1] - 2*La[2])
              sage: M.is_singular()
              False
              sage: M = L.verma_module(-4*La[1] - La[2])
              sage: M.is_singular()
              True
          """
          return not self._dominant_data[0].is_dominant()
  
      def homogeneous_component_basis(self, d):
          r"""
          Return a basis for the ``d``-th homogeneous component of ``self``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: P = L.cartan_type().root_system().weight_lattice()
              sage: La = P.fundamental_weights()
              sage: al = P.simple_roots()
              sage: mu = 2*La[1] + 3*La[2]
              sage: M = L.verma_module(mu)
              sage: M.homogeneous_component_basis(mu - al[2])
              [f[-alpha[2]]*v[2*Lambda[1] + 3*Lambda[2]]]
              sage: M.homogeneous_component_basis(mu - 3*al[2])
              [f[-alpha[2]]^3*v[2*Lambda[1] + 3*Lambda[2]]]
              sage: M.homogeneous_component_basis(mu - 3*al[2] - 2*al[1])
              [f[-alpha[2]]*f[-alpha[1] - alpha[2]]^2*v[2*Lambda[1] + 3*Lambda[2]],
               f[-alpha[2]]^2*f[-alpha[1]]*f[-alpha[1] - alpha[2]]*v[2*Lambda[1] + 3*Lambda[2]],
               f[-alpha[2]]^3*f[-alpha[1]]^2*v[2*Lambda[1] + 3*Lambda[2]]]
              sage: M.homogeneous_component_basis(mu - La[1])
              Family ()
          """
          diff = _convert_wt_to_root(d - self._weight)
          if diff is None or not all(coeff <= 0 and coeff in ZZ for coeff in diff):
              return Family([])
          return sorted(self._homogeneous_component_f(diff))
  
      @cached_method
      def _homogeneous_component_f(self, d):
          r"""
          Return a basis of the PBW given by ``d`` expressed in the
          root lattice in terms of the simple roots.
  
          INPUT:
  
          - ``d`` -- the coefficients of the simple roots as a vector
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: sorted(M._homogeneous_component_f(vector([-1,-2])), key=str)
              [f[-alpha[2]]*f[-alpha[1] - alpha[2]]*v[Lambda[1] + Lambda[2]],
               f[-alpha[2]]^2*f[-alpha[1]]*v[Lambda[1] + Lambda[2]]]
              sage: sorted(M._homogeneous_component_f(vector([-5,-4])), key=str)
              [f[-alpha[1]]*f[-alpha[1] - alpha[2]]^4*v[Lambda[1] + Lambda[2]],
               f[-alpha[2]]*f[-alpha[1]]^2*f[-alpha[1] - alpha[2]]^3*v[Lambda[1] + Lambda[2]],
               f[-alpha[2]]^2*f[-alpha[1]]^3*f[-alpha[1] - alpha[2]]^2*v[Lambda[1] + Lambda[2]],
               f[-alpha[2]]^3*f[-alpha[1]]^4*f[-alpha[1] - alpha[2]]*v[Lambda[1] + Lambda[2]],
               f[-alpha[2]]^4*f[-alpha[1]]^5*v[Lambda[1] + Lambda[2]]]
          """
          if not d:
              return frozenset([self.highest_weight_vector()])
          f = {i: self._pbw(g) for i,g in enumerate(self._g.f())}
          basis = d.parent().basis() # Standard basis vectors
          ret = set()
          def degree(m):
              m = m.dict()
              if not m:
                  return d.parent().zero()
              return sum(e * self._g.degree_on_basis(k) for k,e in m.items()).to_vector()
          for i in f:
              if d[i] == 0:
                  continue
              for b in self._homogeneous_component_f(d + basis[i]):
                  temp = f[i] * b
                  ret.update([self.monomial(m) for m in temp.support() if degree(m) == d])
          return frozenset(ret)
  
      def _Hom_(self, Y, category=None, **options):
          r"""
          Return the homset from ``self`` to ``Y`` in the
          category ``category``.
  
          INPUT:
  
          - ``Y`` -- an object
          - ``category`` -- a subcategory of :class:`Crystals`() or ``None``
  
          The sole purpose of this method is to construct the homset as a
          :class:`~sage.algebras.lie_algebras.verma_module.VermaModuleHomset`.
          If ``category`` is specified and is not a subcategory of
          ``self.category()``, a ``TypeError`` is raised instead.
  
          This method is not meant to be called directly. Please use
          :func:`sage.categories.homset.Hom` instead.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_space().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(3*La[1] - 3*La[2])
              sage: H = Hom(M, Mp)
              sage: type(H)
              <...VermaModuleHomset_with_category_with_equality_by_id'>
          """
          if not (isinstance(Y, VermaModule) and self._g is Y._g):
              raise TypeError("{} must be a Verma module of {}".format(Y, self._g))
          if category is not None and not category.is_subcategory(self.category()):
              raise TypeError("{} is not a subcategory of {}".format(category, self.category()))
          return VermaModuleHomset(self, Y)
  
      class Element(CombinatorialFreeModule.Element):
          def _acted_upon_(self, scalar, self_on_left=False):
              """
              Return the action of ``scalar`` on ``self``.
  
              Check that other PBW algebras have an action::
  
                  sage: L = lie_algebras.sp(QQ, 6)
                  sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
                  sage: M = L.verma_module(La[1] - 3*La[2])
                  sage: PBW = L.pbw_basis()
                  sage: F1 = PBW(L.f(1))
                  sage: F1 * M.highest_weight_vector()
                  f[-alpha[1]]*v[Lambda[1] - 3*Lambda[2]]
                  sage: F1.parent() is M.pbw_basis()
                  False
                  sage: F1 * M.highest_weight_vector()
                  f[-alpha[1]]*v[Lambda[1] - 3*Lambda[2]]
                  sage: E1 = PBW(L.e(1))
                  sage: E1 * F1
                  PBW[alpha[1]]*PBW[-alpha[1]]
                  sage: E1 * F1 * M.highest_weight_vector()
                  v[Lambda[1] - 3*Lambda[2]]
                  sage: M.pbw_basis()(E1 * F1)
                  PBW[-alpha[1]]*PBW[alpha[1]] + PBW[alphacheck[1]]
              """
              P = self.parent()
              # Check for scalars first
              if scalar in P.base_ring():
                  # Don't have this be a super call
                  return CombinatorialFreeModule.Element._acted_upon_(self, scalar, self_on_left)
  
              # Check for Lie algebra elements
              try:
                  scalar = P._g(scalar)
              except (ValueError, TypeError):
                  pass
  
              # Check for PBW elements
              try:
                  scalar = P._pbw(scalar)
              except (ValueError, TypeError):
                  # Cannot be made into a PBW element, so propogate it up
                  return CombinatorialFreeModule.Element._acted_upon_(self,
                          scalar, self_on_left)
  
              # We only implement x * self, i.e., as a left module
              if self_on_left:
                  return None
  
              # Lift ``self`` to the PBW basis and do multiplication there
              mc = self._monomial_coefficients
              d = {P._pbw._indices(x.dict()): mc[x] for x in mc} # Lift the index set
              ret = scalar * P._pbw._from_dict(d, remove_zeros=False, coerce=False)
  
              # Now have ``ret`` act on the highest weight vector
              d = {}
              for m in ret._monomial_coefficients:
                  c = ret._monomial_coefficients[m]
                  mp = {}
                  for k,e in reversed(m._sorted_items()):
                      part = P._g._part_on_basis(k)
                      if part > 0:
                          mp = None
                          break
                      elif part == 0:
                          c *= P._g._weight_action(k, P._weight)**e
                      else:
                          mp[k] = e
                  # This term is 0, so nothing to do
                  if mp is None:
                      continue
                  # Convert back to an element of the indexing set
                  mp = P._indices(mp)
                  if mp in d:
                      d[mp] += c
                  else:
                      d[mp] = c
              return P._from_dict(d)
  
          _lmul_ = _acted_upon_
          _rmul_ = _acted_upon_
  
  #####################################################################
  ## Morphisms and Homset
  
  class VermaModuleMorphism(Morphism):
      """
      A morphism of Verma modules.
      """
      def __init__(self, parent, scalar):
          """
          Initialize ``self``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([1,2]))
              sage: phi = Hom(Mp, M).natural_map()
              sage: TestSuite(phi).run()
          """
          self._scalar = scalar
          Morphism.__init__(self, parent)
  
      def _repr_type(self):
          """
          Return a string describing the specific type of this map,
          to be used when printing ``self``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([1,2]))
              sage: phi = Hom(Mp, M).natural_map()
              sage: phi._repr_type()
              'Verma module'
          """
          return "Verma module"
  
      def _repr_defn(self):
          """
          Return a string describing the definition of ``self``,
          to be used when printing ``self``.
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([1,2]))
              sage: phi = Hom(Mp, M).natural_map()
              sage: phi._repr_defn()
              'v[-5*Lambda[1] + Lambda[2]] |--> f[-alpha[2]]^2*f[-alpha[1]]^4*v[Lambda[1]
                + Lambda[2]] + 8*f[-alpha[2]]*f[-alpha[1]]^3*f[-alpha[1] - alpha[2]]*v[Lambda[1]
                + Lambda[2]] + 12*f[-alpha[1]]^2*f[-alpha[1] - alpha[2]]^2*v[Lambda[1] + Lambda[2]]'
  
              alpha[1]]^2*f[-alpha[1] - alpha[2]]^2*v[Lambda[1] + Lambda[2]]'
              sage: psi = Hom(M, Mp).natural_map()
              sage: psi
              Verma module morphism:
                From: Verma module with highest weight Lambda[1] + Lambda[2]
                       of Lie algebra of ['A', 2] in the Chevalley basis
                To:   Verma module with highest weight -5*Lambda[1] + Lambda[2]
                       of Lie algebra of ['A', 2] in the Chevalley basis
                Defn: v[Lambda[1] + Lambda[2]] |--> 0
          """
          v = self.domain().highest_weight_vector()
          if not self._scalar:
              return "{} |--> {}".format(v, self.codomain().zero())
          return "{} |--> {}".format(v, self._scalar * self.parent().singular_vector())
  
      def _richcmp_(self, other, op):
          r"""
          Return whether this morphism and ``other`` satisfy ``op``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([1,2]))
              sage: H = Hom(Mp, M)
              sage: H(1) < H(2)
              True
              sage: H(2) < H(1)
              False
              sage: H.zero() == H(0)
              True
              sage: H(3) <= H(3)
              True
          """
          return richcmp(self._scalar, other._scalar, op)
  
      def _call_(self, x):
          r"""
          Apply this morphism to ``x``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([1,2]))
              sage: pbw = M.pbw_basis()
              sage: f1, f2 = pbw(L.f(1)), pbw(L.f(2))
              sage: v = Mp.highest_weight_vector()
              sage: phi = Hom(Mp, M).natural_map()
              sage: phi(f1 * v) == f1 * phi(v)
              True
              sage: phi(f2 * f1 * v) == f2 * f1 * phi(v)
              True
              sage: phi(f1 * f2 * f1 * v) == f1 * f2 * f1 * phi(v)
              True
  
              sage: Mpp = L.verma_module(M.highest_weight().dot_action([1,2]) + La[1])
              sage: psi = Hom(Mpp, M).natural_map()
              sage: v = Mpp.highest_weight_vector()
              sage: psi(v)
              0
          """ 
          if not self._scalar or self.parent().singular_vector() is None:
              return self.codomain().zero()
          mc = x.monomial_coefficients(copy=False)
          return self.codomain().linear_combination((self._on_basis(m), self._scalar * c)
                                                    for m,c in mc.items())
  
      def _on_basis(self, m):
          """
          Return the image of the basis element indexed by ``m``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([1,2]))
              sage: pbw = M.pbw_basis()
              sage: f1, f2 = pbw(L.f(1)), pbw(L.f(2))
              sage: v = Mp.highest_weight_vector()
              sage: phi = Hom(Mp, M).natural_map()
              sage: phi._on_basis((f1 * v).leading_support()) == f1 * phi(v)
              True
          """
          pbw = self.codomain()._pbw
          return pbw.monomial(pbw._indices(m.dict())) * self.parent().singular_vector()
  
      def _add_(self, other):
          """
          Add ``self`` and ``other``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([1,2]))
              sage: phi = Hom(Mp, M).natural_map()
              sage: (phi + 3/2 * phi)._scalar
              5/2
          """
          return type(self)(self.parent(), self._scalar + other._scalar)
  
      def _sub_(self, other):
          """
          Subtract ``self`` and ``other``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([1,2]))
              sage: phi = Hom(Mp, M).natural_map()
              sage: (phi - 3/2 * phi)._scalar
              -1/2
          """
          return type(self)(self.parent(), self._scalar - other._scalar)
  
      def _acted_upon_(self, other, self_on_left):
          """
          Return the action of ``other`` on ``self``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([1,2]))
              sage: phi = Hom(Mp, M).natural_map()
              sage: phi._scalar
              1
              sage: (0 * phi)._scalar
              0
              sage: R.<x> = QQ[]
              sage: x * phi
              Traceback (most recent call last):
              ...
              TypeError: unsupported operand parent(s) for *: ...
          """
          R = self.parent().base_ring()
          if other not in R:
              return None
          return type(self)(self.parent(), R(other) * self._scalar)
  
      def _composition_(self, right, homset):
          r"""
          Return the composition of ``self`` and ``right``.
  
          INPUT:
  
          - ``self``, ``right`` -- maps
          - homset -- a homset
  
          ASSUMPTION:
  
          The codomain of ``right`` is contained in the domain of ``self``.
          This assumption is not verified.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([1,2]))
              sage: Mpp = L.verma_module(M.highest_weight().dot_action([1,2]) + La[1])
              sage: phi = Hom(Mp, M).natural_map()
              sage: psi = Hom(Mpp, Mp).natural_map()
              sage: xi = phi * psi
              sage: xi._scalar
              0
          """
          if (isinstance(right, VermaModuleMorphism)
              and right.domain()._g is self.codomain()._g):
              return homset.element_class(homset, right._scalar * self._scalar)
          return super(VermaModuleMorphism, self)._composition_(right, homset)
  
      def is_injective(self):
          r"""
          Return if ``self`` is injective or not.
  
          A Verma module morphism `\phi : M \to M'` is injective if
          and only if `\dim \hom(M, M') = 1` and `\phi \neq 0`.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([1,2]))
              sage: Mpp = L.verma_module(M.highest_weight().dot_action([1,2]) + La[1])
              sage: phi = Hom(Mp, M).natural_map()
              sage: phi.is_injective()
              True
              sage: (0 * phi).is_injective()
              False
              sage: psi = Hom(Mpp, Mp).natural_map()
              sage: psi.is_injective()
              False
          """
          return self.parent().singular_vector() is not None and bool(self._scalar)
  
      def is_surjective(self):
          """
          Return if ``self`` is surjective or not.
  
          A Verma module morphism is surjective if and only if the
          domain is equal to the codomain and it is not the zero
          morphism.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([1,2]))
              sage: phi = Hom(M, M).natural_map()
              sage: phi.is_surjective()
              True
              sage: (0 * phi).is_surjective()
              False
              sage: psi = Hom(Mp, M).natural_map()
              sage: psi.is_surjective()
              False
          """
          return self.domain() == self.codomain() and bool(self._scalar)
  
  class VermaModuleHomset(Homset):
      r"""
      The set of morphisms from one Verma module to another
      considered as `U(\mathfrak{g})`-representations.
  
      Let `M_{w \cdot \lambda}` and `M_{w' \cdot \lambda'}` be
      Verma modules, `\cdot` is the dot action, and `\lambda + \rho`,
      `\lambda' + \rho` are dominant weights. Then we have
  
      .. MATH::
  
          \dim \hom(M_{w \cdot \lambda}, M_{w' \cdot \lambda'}) = 1
  
      if and only if `\lambda = \lambda'` and `w' \leq w` in Bruhat
      order. Otherwise the homset is 0 dimensional.
      """
      def __call__(self, x, **options):
          """
          Construct a morphism in this homset from ``x`` if possible.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([1,2]))
              sage: Mpp = L.verma_module(M.highest_weight().dot_action([1,2,1]))
              sage: phi = Hom(Mp, M).natural_map()
              sage: Hom(Mpp, M)(phi)
              Verma module morphism:
                From: Verma module with highest weight -3*Lambda[1] - 3*Lambda[2]
                       of Lie algebra of ['A', 2] in the Chevalley basis
                To:   Verma module with highest weight Lambda[1] + Lambda[2]
                       of Lie algebra of ['A', 2] in the Chevalley basis
                Defn: v[-3*Lambda[1] - 3*Lambda[2]] |-->
                       f[-alpha[2]]^4*f[-alpha[1]]^4*v[Lambda[1] + Lambda[2]]
                         + 8*f[-alpha[2]]^3*f[-alpha[1]]^3*f[-alpha[1] - alpha[2]]*v[Lambda[1] + Lambda[2]]
                         + 12*f[-alpha[2]]^2*f[-alpha[1]]^2*f[-alpha[1] - alpha[2]]^2*v[Lambda[1] + Lambda[2]]
  
              sage: psi = Hom(Mpp, Mp).natural_map()
              sage: Hom(Mpp, M)(psi)
              Verma module morphism:
                From: Verma module with highest weight -3*Lambda[1] - 3*Lambda[2]
                       of Lie algebra of ['A', 2] in the Chevalley basis
                To:   Verma module with highest weight Lambda[1] + Lambda[2]
                       of Lie algebra of ['A', 2] in the Chevalley basis
                Defn: v[-3*Lambda[1] - 3*Lambda[2]] |-->
                       f[-alpha[2]]^4*f[-alpha[1]]^4*v[Lambda[1] + Lambda[2]]
                        + 8*f[-alpha[2]]^3*f[-alpha[1]]^3*f[-alpha[1] - alpha[2]]*v[Lambda[1] + Lambda[2]]
                        + 12*f[-alpha[2]]^2*f[-alpha[1]]^2*f[-alpha[1] - alpha[2]]^2*v[Lambda[1] + Lambda[2]]
          """
          if isinstance(x, VermaModuleMorphism):
              if x.parent() is self:
                  return x
              if x.parent() == self:
                  x._set_parent(self) # needed due to non-uniqueness of homsets
                  return x
  
              if x.domain() != self.domain():
                  x = x * Hom(self.domain(), x.domain()).natural_map()
              if x.codomain() != self.codomain():
                  x = Hom(x.codomain(), self.codomain()).natural_map() * x
  
              return x
  
          if x in self.base_ring():
              if self.singular_vector() is None:
                  return self.zero()
              return self.element_class(self, self.base_ring()(x))
  
          return super(VermaModuleHomset, self).__call__(x, **options)
  
      def _an_element_(self):
          """
          Return an element of ``self``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([2]))
              sage: H = Hom(Mp, M)
              sage: H._an_element_()
              Verma module morphism:
                From: Verma module with highest weight 3*Lambda[1] - 3*Lambda[2]
                       of Lie algebra of ['A', 2] in the Chevalley basis
                To:   Verma module with highest weight Lambda[1] + Lambda[2]
                       of Lie algebra of ['A', 2] in the Chevalley basis
                Defn: v[3*Lambda[1] - 3*Lambda[2]] |-->
                       f[-alpha[2]]^2*v[Lambda[1] + Lambda[2]]
          """
          return self.natural_map()
  
      @cached_method
      def singular_vector(self):
          r"""
          Return the singular vector in the codomain corresponding
          to the domain's highest weight element or ``None`` if no
          such element exists.
  
          ALGORITHM:
  
          We essentially follow the algorithm laid out in [deG2005]_.
          We use the `\mathfrak{sl}_2` relation on
          `M_{s_i \cdot \lambda} \to M_{\lambda}`, where
          `\langle \lambda + \delta, \alpha_i^{\vee} \rangle = m > 0`,
          i.e., the weight `\lambda` is `i`-dominant with respect to
          the dot action. From here, we construct the singular vector
          `f_i^m v_{\lambda}`. We iterate this until we reach `\mu`.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sp(QQ, 6)
              sage: La = L.cartan_type().root_system().weight_space().fundamental_weights()
              sage: la = La[1] - La[3]
              sage: mu = la.dot_action([1,2])
              sage: M = L.verma_module(la)
              sage: Mp = L.verma_module(mu)
              sage: H = Hom(Mp, M)
              sage: H.singular_vector()
              f[-alpha[2]]*f[-alpha[1]]^3*v[Lambda[1] - Lambda[3]]
               + 3*f[-alpha[1]]^2*f[-alpha[1] - alpha[2]]*v[Lambda[1] - Lambda[3]]
  
          ::
  
              sage: L = LieAlgebra(QQ, cartan_type=['F',4])
              sage: La = L.cartan_type().root_system().weight_space().fundamental_weights()
              sage: la = La[1] + La[2] - La[3]
              sage: mu = la.dot_action([1,2,3,2])
              sage: M = L.verma_module(la)
              sage: Mp = L.verma_module(mu)
              sage: H = Hom(Mp, M)
              sage: v = H.singular_vector()
              sage: pbw = M.pbw_basis()
              sage: E = [pbw(e) for e in L.e()]
              sage: all(e * v == M.zero() for e in E)
              True
  
          When `w \cdot \lambda \notin \lambda + Q^-`, there does not
          exist a singular vector::
  
              sage: L = lie_algebras.sl(QQ, 4)
              sage: La = L.cartan_type().root_system().weight_space().fundamental_weights()
              sage: la = 3/7*La[1] - 1/2*La[3]
              sage: mu = la.dot_action([1,2])
              sage: M = L.verma_module(la)
              sage: Mp = L.verma_module(mu)
              sage: H = Hom(Mp, M)
              sage: H.singular_vector() is None
              True
  
          TESTS::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_space().fundamental_weights()
              sage: al = L.cartan_type().root_system().root_lattice().simple_roots()
              sage: M = L.verma_module(La[1] + La[2])
              sage: pbw = M.pbw_basis()
              sage: E = {i: pbw(L.e(i)) for i in L.cartan_type().index_set()}
              sage: all(not E[i] * Hom(L.verma_module(mu), M).singular_vector()
              ....:     for i in L.cartan_type().index_set()
              ....:     for mu in M.highest_weight().dot_orbit())
              True
          """
          if self.is_endomorphism_set():
              return self.codomain().highest_weight_vector()
          if self.domain()._dominant_data[0] != self.codomain()._dominant_data[0]:
              return None
  
          from sage.combinat.root_system.coxeter_group import CoxeterGroup
          W = CoxeterGroup(self.domain()._g._cartan_type)
          wp = W.from_reduced_word(self.domain()._dominant_data[1])
          w = W.from_reduced_word(self.codomain()._dominant_data[1])
          if not w.bruhat_le(wp):
              return None
          C = self.codomain()
          pbw = C._pbw
          f = C._g.f()
          F = {i: pbw(f[i]) for i in f.keys()}
          red_word = (wp * ~w).reduced_word()
          rho = C._weight.parent().rho()
          ac = C._weight.parent().simple_coroots()
          elt = pbw.one()
          wt = C._weight
          # Construct the singular vector by iterated embeddings of Verma
          #   modules (without constructing the modules themselves)
          for i in reversed(red_word):
              exp = (wt + rho).scalar(ac[i])
              if exp not in ZZ or exp < 0:
                  return None
              elt = F[i]**ZZ(exp) * elt
              wt = wt.dot_action([i])
          return elt * C.highest_weight_vector()
  
      @cached_method
      def natural_map(self):
          """
          Return the "natural map" of ``self``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([2]))
              sage: H = Hom(Mp, M)
              sage: H.natural_map()
              Verma module morphism:
                From: Verma module with highest weight 3*Lambda[1] - 3*Lambda[2]
                       of Lie algebra of ['A', 2] in the Chevalley basis
                To:   Verma module with highest weight Lambda[1] + Lambda[2]
                       of Lie algebra of ['A', 2] in the Chevalley basis
                Defn: v[3*Lambda[1] - 3*Lambda[2]] |-->
                       f[-alpha[2]]^2*v[Lambda[1] + Lambda[2]]
  
              sage: Mp = L.verma_module(La[1] + 2*La[2])
              sage: H = Hom(Mp, M)
              sage: H.natural_map()
              Verma module morphism:
                From: Verma module with highest weight Lambda[1] + 2*Lambda[2]
                       of Lie algebra of ['A', 2] in the Chevalley basis
                To:   Verma module with highest weight Lambda[1] + Lambda[2]
                       of Lie algebra of ['A', 2] in the Chevalley basis
                Defn: v[Lambda[1] + 2*Lambda[2]] |--> 0
          """
          if self.singular_vector() is None:
              return self.zero()
          return self.element_class(self, self.base_ring().one())
  
      @cached_method
      def zero(self):
          """
          Return the zero morphism of ``self``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sp(QQ, 6)
              sage: La = L.cartan_type().root_system().weight_space().fundamental_weights()
              sage: M = L.verma_module(La[1] + 2/3*La[2])
              sage: Mp = L.verma_module(La[2] - La[3])
              sage: H = Hom(Mp, M)
              sage: H.zero()
              Verma module morphism:
                From: Verma module with highest weight Lambda[2] - Lambda[3]
                       of Lie algebra of ['C', 3] in the Chevalley basis
                To:   Verma module with highest weight Lambda[1] + 2/3*Lambda[2]
                       of Lie algebra of ['C', 3] in the Chevalley basis
                Defn: v[Lambda[2] - Lambda[3]] |--> 0
          """
          return self.element_class(self, self.base_ring().zero())
  
      def dimension(self):
          """
          Return the dimension of ``self`` (as a vector space over
          the base ring).
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([2]))
              sage: H = Hom(Mp, M)
              sage: H.dimension()
              1
  
              sage: Mp = L.verma_module(La[1] + 2*La[2])
              sage: H = Hom(Mp, M)
              sage: H.dimension()
              0
          """
          if self.singular_vector() is None:
              return ZZ.zero()
          return ZZ.one()
  
      def basis(self):
          """
          Return a basis of ``self``.
  
          EXAMPLES::
  
              sage: L = lie_algebras.sl(QQ, 3)
              sage: La = L.cartan_type().root_system().weight_lattice().fundamental_weights()
              sage: M = L.verma_module(La[1] + La[2])
              sage: Mp = L.verma_module(M.highest_weight().dot_action([2]))
              sage: H = Hom(Mp, M)
              sage: list(H.basis()) == [H.natural_map()]
              True
  
              sage: Mp = L.verma_module(La[1] + 2*La[2])
              sage: H = Hom(Mp, M)
              sage: H.basis()
              Family ()
          """
          if self.singular_vector() is None:
              return Family([])
          return Family([self.natural_map()])
  
      Element = VermaModuleMorphism
  
  
  def _convert_wt_to_root(wt):
      r"""
      Helper function to express ``wt`` as a linear combination
      of simple roots.
  
      INPUT:
  
      - ``wt`` -- an element of a weight lattice realization
  
      OUTPUT:
  
      A vector over `\QQ` representing ``wt`` as a linear combination
      of simple roots.
  
      EXAMPLES::
  
          sage: from sage.algebras.lie_algebras.verma_module import _convert_wt_to_root
          sage: P = RootSystem(['A',3]).weight_lattice()
          sage: La = P.fundamental_weights()
          sage: [_convert_wt_to_root(al) for al in P.simple_roots()]
          [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
          sage: _convert_wt_to_root(La[1] + La[2])
          (5/4, 3/2, 3/4)
  
          sage: L = RootSystem(['A',3]).ambient_space()
          sage: e = L.basis()
          sage: _convert_wt_to_root(e[0] + 3*e[3])
          sage: _convert_wt_to_root(e[0] - e[1])
          (1, 0, 0)
          sage: _convert_wt_to_root(e[0] + 2*e[1] - 3*e[2])
          (1, 3, 0)
      """
      v = wt.to_vector().change_ring(QQ)
      al = [a.to_vector() for a in wt.parent().simple_roots()]
      b = v.parent().linear_dependence([v] + al)
      if len(b) != 1 or b[0] == 0:
          return None
      b = b[0]  # Get the actual vector that gives the linear dependency
      # Get v as a linear combination of the simple roots
      return vector(QQ, [-x / b[0] for x in b[1:]])
  
  