diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 480fa91b788..b57f11127d8 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -553,6 +553,15 @@ def _element_constructor_(self, x): sage: L = lie_algebras.pwitt(GF(5), 5) sage: L(0) 0 + + Vectors coming from the underlying module coerce back in:: + + sage: L. = LieAlgebra(QQ, {('x','y'): {'x': 1}}) + sage: v = (x + 2*y).to_vector() + sage: L(v) + x + 2*y + sage: L(v.change_ring(ZZ)) + x + 2*y """ if isinstance(x, list) and len(x) == 2: return self(x[0])._bracket_(self(x[1])) @@ -560,11 +569,9 @@ def _element_constructor_(self, x): if x == 0: return self.zero() - try: - if x in self.module(): - return self.from_vector(x) - except AttributeError: - pass + coerced = self._coerce_from_module_vector(x) + if coerced is not None: + return coerced if x in self.base_ring(): # We have already handled the case when x == 0 @@ -572,6 +579,60 @@ def _element_constructor_(self, x): return self.element_class(self, x) + def _coerce_from_module_vector(self, x): + """ + Try to coerce ``x`` coming from ``self.module()``. + + INPUT: + + - ``x`` -- an element to be coerced + + OUTPUT: + + - an element of ``self`` if coercion is possible, ``None`` otherwise + """ + from_vector = getattr(self, "from_vector", None) + if from_vector is None: + return None + + try: + x_parent = x.parent() + except AttributeError: + return None + + vector_modules = [] + for attr in ("_M", "_module"): + mod = getattr(self, attr, None) + if mod is None or mod is NotImplemented or callable(mod): + continue + vector_modules.append(mod) + + module_method = getattr(self, "module", None) + if callable(module_method): + try: + mod = module_method() + except (AttributeError, TypeError, NotImplementedError): + mod = None + if mod is not None: + vector_modules.append(mod) + + seen_ids = set() + for mod in vector_modules: + key = id(mod) + seen_ids.add(key) + if x_parent is mod: + return from_vector(x) + has_cm = getattr(mod, "has_coerce_map_from", None) + if (x_parent is not None and callable(has_cm) + and has_cm(x_parent)): + try: + vec = mod(x) + except (TypeError, ValueError): + continue + return from_vector(vec) + + return None + def __getitem__(self, x): """ If ``x`` is a pair `(a, b)`, return the Lie bracket `[a, b] @@ -1240,9 +1301,28 @@ def _element_constructor_(self, x): -[1, 3, 2] + [3, 2, 1] sage: L(2) 2*[1, 2, 3] + + TESTS: + + Test that constructing elements from vectors works correctly:: + + sage: gl = lie_algebras.gl(QQ, 2) + sage: v = gl.an_element().to_vector() + sage: gl(v) == gl.an_element() + True + + Test that morphisms can be constructed:: + + sage: gl = lie_algebras.gl(QQ, 2) + sage: phi = gl.morphism({e: e for e in gl.gens()}) + sage: all(phi(e) == e for e in gl.gens()) + True """ if isinstance(x, list) and len(x) == 2: return self(x[0])._bracket_(self(x[1])) + coerced = self._coerce_from_module_vector(x) + if coerced is not None: + return coerced return self.element_class(self, self._assoc(x)) def associative_algebra(self):