+ def natural_basis_space(self):
+ """
+ Return the matrix space in which this algebra's natural basis
+ elements live.
+ """
+ if self._natural_basis is None or len(self._natural_basis) == 0:
+ return MatrixSpace(self.base_ring(), self.dimension(), 1)
+ else:
+ return self._natural_basis[0].matrix_space()
+
+
+ @staticmethod
+ def natural_inner_product(X,Y):
+ """
+ Compute the inner product of two naturally-represented elements.
+
+ For example in the real symmetric matrix EJA, this will compute
+ the trace inner-product of two n-by-n symmetric matrices. The
+ default should work for the real cartesian product EJA, the
+ Jordan spin EJA, and the real symmetric matrices. The others
+ will have to be overridden.
+ """
+ return (X.conjugate_transpose()*Y).trace()
+
+
+ @cached_method
+ def one(self):
+ """
+ Return the unit element of this algebra.
+
+ SETUP::
+
+ sage: from mjo.eja.eja_algebra import (RealCartesianProductEJA,
+ ....: random_eja)
+
+ EXAMPLES::
+
+ sage: J = RealCartesianProductEJA(5)
+ sage: J.one()
+ e0 + e1 + e2 + e3 + e4
+
+ TESTS:
+
+ The identity element acts like the identity::
+
+ sage: set_random_seed()
+ sage: J = random_eja()
+ sage: x = J.random_element()
+ sage: J.one()*x == x and x*J.one() == x
+ True
+
+ The matrix of the unit element's operator is the identity::
+
+ sage: set_random_seed()
+ sage: J = random_eja()
+ sage: actual = J.one().operator().matrix()
+ sage: expected = matrix.identity(J.base_ring(), J.dimension())
+ sage: actual == expected
+ True
+
+ """
+ # We can brute-force compute the matrices of the operators
+ # that correspond to the basis elements of this algebra.
+ # If some linear combination of those basis elements is the
+ # algebra identity, then the same linear combination of
+ # their matrices has to be the identity matrix.
+ #
+ # Of course, matrices aren't vectors in sage, so we have to
+ # appeal to the "long vectors" isometry.
+ oper_vecs = [ _mat2vec(g.operator().matrix()) for g in self.gens() ]
+
+ # Now we use basis linear algebra to find the coefficients,
+ # of the matrices-as-vectors-linear-combination, which should
+ # work for the original algebra basis too.
+ A = matrix.column(self.base_ring(), oper_vecs)
+
+ # We used the isometry on the left-hand side already, but we
+ # still need to do it for the right-hand side. Recall that we
+ # wanted something that summed to the identity matrix.
+ b = _mat2vec( matrix.identity(self.base_ring(), self.dimension()) )
+
+ # Now if there's an identity element in the algebra, this should work.
+ coeffs = A.solve_right(b)
+ return self.linear_combination(zip(self.gens(), coeffs))
+
+
+ def peirce_decomposition(self, c):
+ """
+ The Peirce decomposition of this algebra relative to the
+ idempotent ``c``.
+
+ In the future, this can be extended to a complete system of
+ orthogonal idempotents.
+ """
+ if not c.is_idempotent():
+ raise ValueError("element is not idempotent: %s" % c)
+
+ # Default these to what they should be if they turn out to be
+ # trivial, because eigenspaces_left() won't return eigenvalues
+ # corresponding to trivial spaces (e.g. it returns only the
+ # eigenspace corresponding to lambda=1 if you take the
+ # decomposition relative to the identity element).
+ trivial = FiniteDimensionalEuclideanJordanSubalgebra(self, ())
+ J0 = trivial # eigenvalue zero
+ J2 = trivial # eigenvalue one-half
+ J1 = trivial # eigenvalue one
+
+ for (eigval, eigspace) in c.operator().matrix().left_eigenspaces():
+ gens = tuple( self.from_vector(b) for b in eigspace.basis() )
+ subalg = FiniteDimensionalEuclideanJordanSubalgebra(self, gens)
+ if eigval == 0:
+ J0 = subalg
+ elif eigval == ~(self.base_ring()(2)):
+ J2 = subalg
+ elif eigval == 1:
+ J1 = subalg
+ else:
+ raise ValueError("unexpected eigenvalue: %s" % eigval)
+
+ return (J0, J2, J1)
+
+
+ def random_elements(self, count):
+ """
+ Return ``count`` random elements as a tuple.
+
+ SETUP::
+
+ sage: from mjo.eja.eja_algebra import JordanSpinEJA
+
+ EXAMPLES::
+
+ sage: J = JordanSpinEJA(3)
+ sage: x,y,z = J.random_elements(3)
+ sage: all( [ x in J, y in J, z in J ])
+ True
+ sage: len( J.random_elements(10) ) == 10
+ True
+
+ """
+ return tuple( self.random_element() for idx in xrange(count) )
+
+