what can be supported in a general Jordan Algebra.
"""
+from itertools import repeat
+
from sage.algebras.quatalg.quaternion_algebra import QuaternionAlgebra
from sage.categories.magmatic_algebras import MagmaticAlgebras
from sage.combinat.free_module import CombinatorialFreeModule
sage: set_random_seed()
sage: J = random_eja()
- sage: x = J.random_element()
- sage: y = J.random_element()
+ sage: x,y = J.random_elements(2)
sage: x*y == y*x
True
EXAMPLES:
- The inner product must satisfy its axiom for this algebra to truly
- be a Euclidean Jordan Algebra::
+ Our inner product satisfies the Jordan axiom, which is also
+ referred to as "associativity" for a symmetric bilinear form::
sage: set_random_seed()
sage: J = random_eja()
- sage: x = J.random_element()
- sage: y = J.random_element()
- sage: z = J.random_element()
+ sage: x,y,z = J.random_elements(3)
sage: (x*y).inner_product(z) == y.inner_product(x*z)
True
s = super(FiniteDimensionalEuclideanJordanAlgebra, self)
return s.random_element()
+ 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) )
@classmethod
def random_instance(cls, field=QQ, **kwargs):
The rank of the `n`-by-`n` Hermitian real, complex, or
quaternion matrices is `n`::
- sage: RealSymmetricEJA(2).rank()
- 2
- sage: ComplexHermitianEJA(2).rank()
- 2
+ sage: RealSymmetricEJA(4).rank()
+ 4
+ sage: ComplexHermitianEJA(3).rank()
+ 3
sage: QuaternionHermitianEJA(2).rank()
2
- sage: RealSymmetricEJA(5).rank()
- 5
- sage: ComplexHermitianEJA(5).rank()
- 5
- sage: QuaternionHermitianEJA(5).rank()
- 5
TESTS:
sage: RealCartesianProductEJA(3, prefix='r').gens()
(r0, r1, r2)
- Our inner product satisfies the Jordan axiom::
-
- sage: set_random_seed()
- sage: J = RealCartesianProductEJA.random_instance()
- sage: x = J.random_element()
- sage: y = J.random_element()
- sage: z = J.random_element()
- sage: (x*y).inner_product(z) == y.inner_product(x*z)
- True
-
"""
def __init__(self, n, field=QQ, **kwargs):
V = VectorSpace(field, n)
sage: set_random_seed()
sage: J = RealCartesianProductEJA.random_instance()
- sage: x = J.random_element()
- sage: y = J.random_element()
+ sage: x,y = J.random_elements(2)
sage: X = x.natural_representation()
sage: Y = y.natural_representation()
sage: x.inner_product(y) == J.natural_inner_product(X,Y)
return tr.coefficient_tuple()[0]
-class RealSymmetricEJA(MatrixEuclideanJordanAlgebra):
+class RealMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
+ @staticmethod
+ def real_embed(M):
+ """
+ Embed the matrix ``M`` into a space of real matrices.
+
+ The matrix ``M`` can have entries in any field at the moment:
+ the real numbers, complex numbers, or quaternions. And although
+ they are not a field, we can probably support octonions at some
+ point, too. This function returns a real matrix that "acts like"
+ the original with respect to matrix multiplication; i.e.
+
+ real_embed(M*N) = real_embed(M)*real_embed(N)
+
+ """
+ return M
+
+
+ @staticmethod
+ def real_unembed(M):
+ """
+ The inverse of :meth:`real_embed`.
+ """
+ return M
+
+
+class RealSymmetricEJA(RealMatrixEuclideanJordanAlgebra):
"""
The rank-n simple EJA consisting of real symmetric n-by-n
matrices, the usual symmetric Jordan product, and the trace inner
sage: set_random_seed()
sage: J = RealSymmetricEJA.random_instance()
- sage: x = J.random_element()
- sage: y = J.random_element()
+ sage: x,y = J.random_elements(2)
sage: actual = (x*y).natural_representation()
sage: X = x.natural_representation()
sage: Y = y.natural_representation()
sage: RealSymmetricEJA(3, prefix='q').gens()
(q0, q1, q2, q3, q4, q5)
- Our inner product satisfies the Jordan axiom::
-
- sage: set_random_seed()
- sage: J = RealSymmetricEJA.random_instance()
- sage: x = J.random_element()
- sage: y = J.random_element()
- sage: z = J.random_element()
- sage: (x*y).inner_product(z) == y.inner_product(x*z)
- True
-
Our natural basis is normalized with respect to the natural inner
product unless we specify otherwise::
def _max_test_case_size():
return 5 # Dimension 10
- @staticmethod
- def real_embed(M):
- """
- Embed the matrix ``M`` into a space of real matrices.
-
- The matrix ``M`` can have entries in any field at the moment:
- the real numbers, complex numbers, or quaternions. And although
- they are not a field, we can probably support octonions at some
- point, too. This function returns a real matrix that "acts like"
- the original with respect to matrix multiplication; i.e.
-
- real_embed(M*N) = real_embed(M)*real_embed(N)
-
- """
- return M
-
-
- @staticmethod
- def real_unembed(M):
- """
- The inverse of :meth:`real_embed`.
- """
- return M
-
class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
return matrix(F, n/2, elements)
+ @classmethod
+ def natural_inner_product(cls,X,Y):
+ """
+ Compute a natural inner product in this algebra directly from
+ its real embedding.
+
+ SETUP::
+
+ sage: from mjo.eja.eja_algebra import ComplexHermitianEJA
+
+ TESTS:
+
+ This gives the same answer as the slow, default method implemented
+ in :class:`MatrixEuclideanJordanAlgebra`::
+
+ sage: set_random_seed()
+ sage: J = ComplexHermitianEJA.random_instance()
+ sage: x,y = J.random_elements(2)
+ sage: Xe = x.natural_representation()
+ sage: Ye = y.natural_representation()
+ sage: X = ComplexHermitianEJA.real_unembed(Xe)
+ sage: Y = ComplexHermitianEJA.real_unembed(Ye)
+ sage: expected = (X*Y).trace().vector()[0]
+ sage: actual = ComplexHermitianEJA.natural_inner_product(Xe,Ye)
+ sage: actual == expected
+ True
+
+ """
+ return RealMatrixEuclideanJordanAlgebra.natural_inner_product(X,Y)/2
+
+
class ComplexHermitianEJA(ComplexMatrixEuclideanJordanAlgebra):
"""
The rank-n simple EJA consisting of complex Hermitian n-by-n
sage: set_random_seed()
sage: J = ComplexHermitianEJA.random_instance()
- sage: x = J.random_element()
- sage: y = J.random_element()
+ sage: x,y = J.random_elements(2)
sage: actual = (x*y).natural_representation()
sage: X = x.natural_representation()
sage: Y = y.natural_representation()
sage: ComplexHermitianEJA(2, prefix='z').gens()
(z0, z1, z2, z3)
- Our inner product satisfies the Jordan axiom::
-
- sage: set_random_seed()
- sage: J = ComplexHermitianEJA.random_instance()
- sage: x = J.random_element()
- sage: y = J.random_element()
- sage: z = J.random_element()
- sage: (x*y).inner_product(z) == y.inner_product(x*z)
- True
-
Our natural basis is normalized with respect to the natural inner
product unless we specify otherwise::
return matrix(Q, n/4, elements)
+ @classmethod
+ def natural_inner_product(cls,X,Y):
+ """
+ Compute a natural inner product in this algebra directly from
+ its real embedding.
+
+ SETUP::
+
+ sage: from mjo.eja.eja_algebra import QuaternionHermitianEJA
+
+ TESTS:
+
+ This gives the same answer as the slow, default method implemented
+ in :class:`MatrixEuclideanJordanAlgebra`::
+
+ sage: set_random_seed()
+ sage: J = QuaternionHermitianEJA.random_instance()
+ sage: x,y = J.random_elements(2)
+ sage: Xe = x.natural_representation()
+ sage: Ye = y.natural_representation()
+ sage: X = QuaternionHermitianEJA.real_unembed(Xe)
+ sage: Y = QuaternionHermitianEJA.real_unembed(Ye)
+ sage: expected = (X*Y).trace().coefficient_tuple()[0]
+ sage: actual = QuaternionHermitianEJA.natural_inner_product(Xe,Ye)
+ sage: actual == expected
+ True
+
+ """
+ return RealMatrixEuclideanJordanAlgebra.natural_inner_product(X,Y)/4
+
class QuaternionHermitianEJA(QuaternionMatrixEuclideanJordanAlgebra):
"""
sage: set_random_seed()
sage: J = QuaternionHermitianEJA.random_instance()
- sage: x = J.random_element()
- sage: y = J.random_element()
+ sage: x,y = J.random_elements(2)
sage: actual = (x*y).natural_representation()
sage: X = x.natural_representation()
sage: Y = y.natural_representation()
sage: QuaternionHermitianEJA(2, prefix='a').gens()
(a0, a1, a2, a3, a4, a5)
- Our inner product satisfies the Jordan axiom::
-
- sage: set_random_seed()
- sage: J = QuaternionHermitianEJA.random_instance()
- sage: x = J.random_element()
- sage: y = J.random_element()
- sage: z = J.random_element()
- sage: (x*y).inner_product(z) == y.inner_product(x*z)
- True
-
Our natural basis is normalized with respect to the natural inner
product unless we specify otherwise::
sage: JordanSpinEJA(2, prefix='B').gens()
(B0, B1)
- Our inner product satisfies the Jordan axiom::
-
- sage: set_random_seed()
- sage: J = JordanSpinEJA.random_instance()
- sage: x = J.random_element()
- sage: y = J.random_element()
- sage: z = J.random_element()
- sage: (x*y).inner_product(z) == y.inner_product(x*z)
- True
-
"""
def __init__(self, n, field=QQ, **kwargs):
V = VectorSpace(field, n)
sage: set_random_seed()
sage: J = JordanSpinEJA.random_instance()
- sage: x = J.random_element()
- sage: y = J.random_element()
+ sage: x,y = J.random_elements(2)
sage: X = x.natural_representation()
sage: Y = y.natural_representation()
sage: x.inner_product(y) == J.natural_inner_product(X,Y)