for (bj, yj) in other.items()
)
+ def leftreg(self):
+ r"""
+ Return the left-regular representation of this element.
+
+ SETUP::
+
+ sage: from mjo.clan.unital_clan import VinbergClan
+
+ EXAMPLES::
+
+ sage: C = VinbergClan()
+ sage: C.one().leftreg()
+ [1 0 0 0 0]
+ [0 1 0 0 0]
+ [0 0 1 0 0]
+ [0 0 0 1 0]
+ [0 0 0 0 1]
+
+ """
+ P = self.parent()
+ left_mult_by_self = lambda y: self*y
+ L = P.module_morphism(function=left_mult_by_self, codomain=P)
+ return L.matrix()
+
+ def operator(self):
+ """
+ Return the left-multiplication-by-me operator on the
+ ambient clan.
+
+ SETUP::
+
+ sage: from mjo.clan.unital_clan import VinbergClan
+
+ EXAMPLES::
+
+ sage: C = VinbergClan()
+ sage: C.one().operator()
+ Clan operator represented by the matrix:
+ [1 0 0 0 0]
+ [0 1 0 0 0]
+ [0 0 1 0 0]
+ [0 0 0 1 0]
+ [0 0 0 0 1]
+ Domain: Vinberg clan over Rational Field
+ Codomain: Vinberg clan over Rational Field
+
+ TESTS::
+
+ sage: C = VinbergClan()
+ sage: x = C.random_element()
+ sage: y = C.random_element()
+ sage: x.operator()(y) == x*y
+ True
+ sage: y.operator()(x) == y*x
+ True
+
+ """
+ from mjo.clan.clan_operator import ClanOperator
+ P = self.parent()
+ return ClanOperator(P, P, self.leftreg())
+
class NormalDecompositionElement(ClanElement):
"""
--- /dev/null
+from sage.categories.all import FreeModules
+from sage.categories.map import Map
+
+class ClanOperator(Map):
+ r"""
+ An operator between two clans.
+
+ Defined for *unital* clans at the moment, because that's all we
+ have.
+
+ SETUP::
+
+ sage: from mjo.clan.unital_clan import SnClan
+ sage: from mjo.clan.clan_operator import ClanOperator
+
+ EXAMPLES:
+
+ The domain and codomain must be unital clans; if either is not,
+ then an error is raised::
+
+ sage: J = SnClan(2)
+ sage: V = VectorSpace(J.base_ring(), 3)
+ sage: M = matrix.identity(J.base_ring(), 3)
+ sage: ClanOperator(V,J,M)
+ Traceback (most recent call last):
+ ...
+ TypeError: domain must be a unital clan
+ sage: ClanOperator(J,V,M)
+ Traceback (most recent call last):
+ ...
+ TypeError: codomain must be a unital clan
+
+ """
+
+ def __init__(self, domain, codomain, mat):
+ from mjo.clan.unital_clan import UnitalClan
+
+ if not isinstance(domain, UnitalClan):
+ raise TypeError('domain must be a unital clan')
+ if not isinstance(codomain, UnitalClan):
+ raise TypeError('codomain must be a unital clan')
+
+ F = domain.base_ring()
+ if not (F == codomain.base_ring()):
+ raise ValueError("domain and codomain must have the same base ring")
+ if not (F == mat.base_ring()):
+ raise ValueError("domain and matrix must have the same base ring")
+
+ # We need to supply something here to avoid getting the
+ # default Homset of the parent FiniteDimensionalAlgebra class,
+ # which messes up e.g. equality testing. We use FreeModules(F)
+ # instead of VectorSpaces(F) because our characteristic polynomial
+ # algorithm will need to F to be a polynomial ring at some point.
+ # When F is a field, FreeModules(F) returns VectorSpaces(F) anyway.
+ parent = domain.Hom(codomain, FreeModules(F))
+
+ # The Map initializer will set our parent to a homset, which
+ # is explicitly NOT what we want, because these ain't algebra
+ # homomorphisms.
+ super().__init__(parent)
+
+ # Keep a matrix around to do all of the real work. It would
+ # be nice if we could use a VectorSpaceMorphism instead, but
+ # those use row vectors that we don't want to accidentally
+ # expose to our users.
+ self._matrix = mat
+
+
+ def _call_(self, x):
+ """
+ Allow this operator to be called only on elements of a clan.
+
+ SETUP::
+
+ sage: from mjo.clan.clan_operator import ClanOperator
+ sage: from mjo.clan.unital_clan import VinbergClan
+
+ EXAMPLES::
+
+ sage: C = VinbergClan()
+ sage: x = C.linear_combination(zip(C.gens(),range(len(C.gens()))))
+ sage: id = identity_matrix(C.base_ring(), C.dimension())
+ sage: f = ClanOperator(C,C,id)
+ sage: f(x) == x
+ True
+
+ """
+ return self.codomain().from_vector(self._matrix*x.to_vector())
+
+ def _repr_(self):
+ r"""
+
+ A text representation of this linear operator on a Euclidean
+ Jordan Algebra.
+
+ SETUP::
+
+ sage: from mjo.clan.clan_operator import ClanOperator
+ sage: from mjo.clan.unital_clan import HnClan
+
+ EXAMPLES::
+
+ sage: C = HnClan(2)
+ sage: id = identity_matrix(C.base_ring(), C.dimension())
+ sage: ClanOperator(C,C,id)
+ Clan operator represented by the matrix:
+ [1 0 0 0]
+ [0 1 0 0]
+ [0 0 1 0]
+ [0 0 0 1]
+ Domain: Clan H^2 over Rational Field
+ Codomain: Clan H^2 over Rational Field
+
+ """
+ msg = ("Clan operator represented by the matrix:\n",
+ "{!r}\n",
+ "Domain: {}\n",
+ "Codomain: {}")
+ return ''.join(msg).format(self._matrix,
+ self.domain(),
+ self.codomain())