-def _real_symmetric_basis(n, field=QQ):
- """
- Return a basis for the space of real symmetric n-by-n matrices.
- """
- # The basis of symmetric matrices, as matrices, in their R^(n-by-n)
- # coordinates.
- S = []
- for i in xrange(n):
- for j in xrange(i+1):
- Eij = matrix(field, n, lambda k,l: k==i and l==j)
- if i == j:
- Sij = Eij
- else:
- # Beware, orthogonal but not normalized!
- Sij = Eij + Eij.transpose()
- S.append(Sij)
- return tuple(S)
-
-
-def _complex_hermitian_basis(n, field=QQ):
- """
- Returns a basis for the space of complex Hermitian n-by-n matrices.
-
- SETUP::
-
- sage: from mjo.eja.eja_algebra import _complex_hermitian_basis
-
- TESTS::
-
- sage: set_random_seed()
- sage: n = ZZ.random_element(1,5)
- sage: all( M.is_symmetric() for M in _complex_hermitian_basis(n) )
- True
-
- """
- F = QuadraticField(-1, 'I')
- I = F.gen()
-
- # This is like the symmetric case, but we need to be careful:
- #
- # * We want conjugate-symmetry, not just symmetry.
- # * The diagonal will (as a result) be real.
- #
- S = []
- for i in xrange(n):
- for j in xrange(i+1):
- Eij = matrix(field, n, lambda k,l: k==i and l==j)
- if i == j:
- Sij = _embed_complex_matrix(Eij)
- S.append(Sij)
- else:
- # Beware, orthogonal but not normalized! The second one
- # has a minus because it's conjugated.
- Sij_real = _embed_complex_matrix(Eij + Eij.transpose())
- S.append(Sij_real)
- Sij_imag = _embed_complex_matrix(I*Eij - I*Eij.transpose())
- S.append(Sij_imag)
- return tuple(S)
-
-
-def _quaternion_hermitian_basis(n, field=QQ):
- """
- Returns a basis for the space of quaternion Hermitian n-by-n matrices.
-
- SETUP::
-
- sage: from mjo.eja.eja_algebra import _quaternion_hermitian_basis
-
- TESTS::
-
- sage: set_random_seed()
- sage: n = ZZ.random_element(1,5)
- sage: all( M.is_symmetric() for M in _quaternion_hermitian_basis(n) )
- True
-
- """
- Q = QuaternionAlgebra(QQ,-1,-1)
- I,J,K = Q.gens()
-
- # This is like the symmetric case, but we need to be careful:
- #
- # * We want conjugate-symmetry, not just symmetry.
- # * The diagonal will (as a result) be real.
- #
- S = []
- for i in xrange(n):
- for j in xrange(i+1):
- Eij = matrix(Q, n, lambda k,l: k==i and l==j)
- if i == j:
- Sij = _embed_quaternion_matrix(Eij)
- S.append(Sij)
- else:
- # Beware, orthogonal but not normalized! The second,
- # third, and fourth ones have a minus because they're
- # conjugated.
- Sij_real = _embed_quaternion_matrix(Eij + Eij.transpose())
- S.append(Sij_real)
- Sij_I = _embed_quaternion_matrix(I*Eij - I*Eij.transpose())
- S.append(Sij_I)
- Sij_J = _embed_quaternion_matrix(J*Eij - J*Eij.transpose())
- S.append(Sij_J)
- Sij_K = _embed_quaternion_matrix(K*Eij - K*Eij.transpose())
- S.append(Sij_K)
- return tuple(S)
-
-
-
-def _multiplication_table_from_matrix_basis(basis):
- """
- At least three of the five simple Euclidean Jordan algebras have the
- symmetric multiplication (A,B) |-> (AB + BA)/2, where the
- multiplication on the right is matrix multiplication. Given a basis
- for the underlying matrix space, this function returns a
- multiplication table (obtained by looping through the basis
- elements) for an algebra of those matrices. A reordered copy
- of the basis is also returned to work around the fact that
- the ``span()`` in this function will change the order of the basis
- from what we think it is, to... something else.
- """
- # In S^2, for example, we nominally have four coordinates even
- # though the space is of dimension three only. The vector space V
- # is supposed to hold the entire long vector, and the subspace W
- # of V will be spanned by the vectors that arise from symmetric
- # matrices. Thus for S^2, dim(V) == 4 and dim(W) == 3.
- field = basis[0].base_ring()
- dimension = basis[0].nrows()
-
- V = VectorSpace(field, dimension**2)
- W = V.span_of_basis( _mat2vec(s) for s in basis )
-
- Qs = []
- for s in basis:
- # Brute force the multiplication-by-s matrix by looping
- # through all elements of the basis and doing the computation
- # to find out what the corresponding row should be.
- Q_cols = []
- for t in basis:
- this_col = _mat2vec((s*t + t*s)/2)
- Q_cols.append(W.coordinates(this_col))
- Q = matrix.column(field, W.dimension(), Q_cols)
- Qs.append(Q)
-
- return Qs
-
-
-def _embed_complex_matrix(M):
- """
- Embed the n-by-n complex matrix ``M`` into the space of real
- matrices of size 2n-by-2n via the map the sends each entry `z = a +
- bi` to the block matrix ``[[a,b],[-b,a]]``.
-
- SETUP::