+ The rank-n simple EJA consisting of real symmetric n-by-n
+ matrices, the usual symmetric Jordan product, and the trace inner
+ product. It has dimension `(n^2 + n)/2` over the reals.
+
+ EXAMPLES::
+
+ sage: J = RealSymmetricEJA(2)
+ sage: e0, e1, e2 = J.gens()
+ sage: e0*e0
+ e0
+ sage: e1*e1
+ e0 + e2
+ sage: e2*e2
+ e2
+
+ TESTS:
+
+ The degree of this algebra is `(n^2 + n) / 2`::
+
+ sage: set_random_seed()
+ sage: n = ZZ.random_element(1,5)
+ sage: J = RealSymmetricEJA(n)
+ sage: J.degree() == (n^2 + n)/2
+ True
+
+ The Jordan multiplication is what we think it is::
+
+ sage: set_random_seed()
+ sage: n = ZZ.random_element(1,5)
+ sage: J = RealSymmetricEJA(n)
+ sage: x = J.random_element()
+ sage: y = J.random_element()
+ sage: actual = (x*y).natural_representation()
+ sage: X = x.natural_representation()
+ sage: Y = y.natural_representation()
+ sage: expected = (X*Y + Y*X)/2
+ sage: actual == expected
+ True
+ sage: J(expected) == x*y
+ True
+
+ """
+ @staticmethod
+ def __classcall_private__(cls, n, field=QQ):
+ S = _real_symmetric_basis(n, field=field)
+ (Qs, T) = _multiplication_table_from_matrix_basis(S)
+
+ fdeja = super(RealSymmetricEJA, cls)
+ return fdeja.__classcall_private__(cls,
+ field,
+ Qs,
+ rank=n,
+ natural_basis=T)
+
+ def inner_product(self, x, y):
+ return _matrix_ip(x,y)
+
+
+class ComplexHermitianEJA(FiniteDimensionalEuclideanJordanAlgebra):
+ """
+ The rank-n simple EJA consisting of complex Hermitian n-by-n
+ matrices over the real numbers, the usual symmetric Jordan product,
+ and the real-part-of-trace inner product. It has dimension `n^2` over
+ the reals.
+
+ TESTS:
+
+ The degree of this algebra is `n^2`::
+
+ sage: set_random_seed()
+ sage: n = ZZ.random_element(1,5)
+ sage: J = ComplexHermitianEJA(n)
+ sage: J.degree() == n^2
+ True
+
+ The Jordan multiplication is what we think it is::
+
+ sage: set_random_seed()
+ sage: n = ZZ.random_element(1,5)
+ sage: J = ComplexHermitianEJA(n)
+ sage: x = J.random_element()
+ sage: y = J.random_element()
+ sage: actual = (x*y).natural_representation()
+ sage: X = x.natural_representation()
+ sage: Y = y.natural_representation()
+ sage: expected = (X*Y + Y*X)/2
+ sage: actual == expected
+ True
+ sage: J(expected) == x*y
+ True
+
+ """
+ @staticmethod
+ def __classcall_private__(cls, n, field=QQ):
+ S = _complex_hermitian_basis(n)
+ (Qs, T) = _multiplication_table_from_matrix_basis(S)
+
+ fdeja = super(ComplexHermitianEJA, cls)
+ return fdeja.__classcall_private__(cls,
+ field,
+ Qs,
+ rank=n,
+ natural_basis=T)
+
+ def inner_product(self, x, y):
+ # Since a+bi on the diagonal is represented as
+ #
+ # a + bi = [ a b ]
+ # [ -b a ],
+ #
+ # we'll double-count the "a" entries if we take the trace of
+ # the embedding.
+ return _matrix_ip(x,y)/2
+
+
+class QuaternionHermitianEJA(FiniteDimensionalEuclideanJordanAlgebra):
+ """
+ The rank-n simple EJA consisting of self-adjoint n-by-n quaternion
+ matrices, the usual symmetric Jordan product, and the
+ real-part-of-trace inner product. It has dimension `2n^2 - n` over
+ the reals.
+
+ TESTS:
+
+ The degree of this algebra is `n^2`::
+
+ sage: set_random_seed()
+ sage: n = ZZ.random_element(1,5)
+ sage: J = QuaternionHermitianEJA(n)
+ sage: J.degree() == 2*(n^2) - n
+ True
+
+ The Jordan multiplication is what we think it is::
+
+ sage: set_random_seed()
+ sage: n = ZZ.random_element(1,5)
+ sage: J = QuaternionHermitianEJA(n)
+ sage: x = J.random_element()
+ sage: y = J.random_element()
+ sage: actual = (x*y).natural_representation()
+ sage: X = x.natural_representation()
+ sage: Y = y.natural_representation()
+ sage: expected = (X*Y + Y*X)/2
+ sage: actual == expected
+ True
+ sage: J(expected) == x*y
+ True
+
+ """
+ @staticmethod
+ def __classcall_private__(cls, n, field=QQ):
+ S = _quaternion_hermitian_basis(n)
+ (Qs, T) = _multiplication_table_from_matrix_basis(S)
+
+ fdeja = super(QuaternionHermitianEJA, cls)
+ return fdeja.__classcall_private__(cls,
+ field,
+ Qs,
+ rank=n,
+ natural_basis=T)
+
+ def inner_product(self, x, y):
+ # Since a+bi+cj+dk on the diagonal is represented as
+ #
+ # a + bi +cj + dk = [ a b c d]
+ # [ -b a -d c]
+ # [ -c d a -b]
+ # [ -d -c b a],
+ #
+ # we'll quadruple-count the "a" entries if we take the trace of
+ # the embedding.
+ return _matrix_ip(x,y)/4
+
+
+class JordanSpinEJA(FiniteDimensionalEuclideanJordanAlgebra):
+ """
+ The rank-2 simple EJA consisting of real vectors ``x=(x0, x_bar)``
+ with the usual inner product and jordan product ``x*y =
+ (<x_bar,y_bar>, x0*y_bar + y0*x_bar)``. It has dimension `n` over
+ the reals.
+
+ EXAMPLES:
+
+ This multiplication table can be verified by hand::
+
+ sage: J = JordanSpinEJA(4)
+ sage: e0,e1,e2,e3 = J.gens()
+ sage: e0*e0
+ e0
+ sage: e0*e1
+ e1
+ sage: e0*e2
+ e2
+ sage: e0*e3
+ e3
+ sage: e1*e2
+ 0
+ sage: e1*e3
+ 0
+ sage: e2*e3
+ 0
+
+ """
+ @staticmethod
+ def __classcall_private__(cls, n, field=QQ):
+ Qs = []
+ id_matrix = identity_matrix(field, n)
+ for i in xrange(n):
+ ei = id_matrix.column(i)
+ Qi = zero_matrix(field, n)
+ Qi.set_row(0, ei)
+ Qi.set_column(0, ei)
+ Qi += diagonal_matrix(n, [ei[0]]*n)
+ # The addition of the diagonal matrix adds an extra ei[0] in the
+ # upper-left corner of the matrix.
+ Qi[0,0] = Qi[0,0] * ~field(2)
+ Qs.append(Qi)
+
+ fdeja = super(JordanSpinEJA, cls)
+ return fdeja.__classcall_private__(cls, field, Qs)
+
+ def rank(self):
+ """
+ Return the rank of this Jordan Spin Algebra.
+
+ The rank of the spin algebra is two, unless we're in a
+ one-dimensional ambient space (because the rank is bounded by
+ the ambient dimension).
+ """
+ return min(self.dimension(),2)
+
+ def inner_product(self, x, y):
+ return _usual_ip(x,y)