what can be supported in a general Jordan Algebra.
"""
-#from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra import FiniteDimensionalAlgebra
from sage.algebras.quatalg.quaternion_algebra import QuaternionAlgebra
from sage.categories.finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis
from sage.combinat.free_module import CombinatorialFreeModule
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.rings.rational_field import QQ
from sage.structure.element import is_Matrix
-from sage.structure.category_object import normalize_names
from mjo.eja.eja_element import FiniteDimensionalEuclideanJordanAlgebraElement
from mjo.eja.eja_utils import _mat2vec
"""
self._rank = rank
self._natural_basis = natural_basis
- self._multiplication_table = mult_table
+
if category is None:
category = FiniteDimensionalAlgebrasWithBasis(field).Unital()
fda = super(FiniteDimensionalEuclideanJordanAlgebra, self)
category=category)
self.print_options(bracket='')
+ # The multiplication table we're given is necessarily in terms
+ # of vectors, because we don't have an algebra yet for
+ # anything to be an element of. However, it's faster in the
+ # long run to have the multiplication table be in terms of
+ # algebra elements. We do this after calling the superclass
+ # constructor so that from_vector() knows what to do.
+ self._multiplication_table = [ map(lambda x: self.from_vector(x), ls)
+ for ls in mult_table ]
+
def _element_constructor_(self, elt):
"""
return fmt.format(self.dimension(), self.base_ring())
def product_on_basis(self, i, j):
- ei = self.basis()[i]
- ej = self.basis()[j]
- Lei = self._multiplication_table[i]
- return self.from_vector(Lei*ej.to_vector())
+ return self._multiplication_table[i][j]
def _a_regular_element(self):
"""
# Construct a new algebra over a multivariate polynomial ring...
names = tuple('X' + str(i) for i in range(1,n+1))
R = PolynomialRing(self.base_ring(), names)
- J = FiniteDimensionalEuclideanJordanAlgebra(
- R,
- tuple(self._multiplication_table),
- r)
+ # Hack around the fact that our multiplication table is in terms of
+ # algebra elements but the constructor wants it in terms of vectors.
+ vmt = [ tuple(map(lambda x: x.to_vector(), ls))
+ for ls in self._multiplication_table ]
+ J = FiniteDimensionalEuclideanJordanAlgebra(R, tuple(vmt), r)
idmat = matrix.identity(J.base_ring(), n)
return x.trace_inner_product(y)
+ def multiplication_table(self):
+ """
+ Return a readable matrix representation of this algebra's
+ multiplication table. The (i,j)th entry in the matrix contains
+ the product of the ith basis element with the jth.
+
+ This is not extraordinarily useful, but it overrides a superclass
+ method that would otherwise just crash and complain about the
+ algebra being infinite.
+
+ SETUP::
+
+ sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
+ ....: RealCartesianProductEJA)
+
+ EXAMPLES::
+
+ sage: J = RealCartesianProductEJA(3)
+ sage: J.multiplication_table()
+ [e0 0 0]
+ [ 0 e1 0]
+ [ 0 0 e2]
+
+ ::
+
+ sage: J = JordanSpinEJA(3)
+ sage: J.multiplication_table()
+ [e0 e1 e2]
+ [e1 e0 0]
+ [e2 0 e0]
+
+ """
+ return matrix(self._multiplication_table)
+
+
def natural_basis(self):
"""
Return a more-natural representation of this algebra's basis.
"""
def __init__(self, n, field=QQ):
- # The superclass constructor takes a list of matrices, the ith
- # representing right multiplication by the ith basis element
- # in the vector space. So if e_1 = (1,0,0), then right
- # (Hadamard) multiplication of x by e_1 picks out the first
- # component of x; and likewise for the ith basis element e_i.
- Qs = [ matrix(field, n, n, lambda k,j: 1*(k == j == i))
- for i in xrange(n) ]
+ V = VectorSpace(field, n)
+ mult_table = [ [ V.basis()[i]*(i == j) for i in range(n) ]
+ for j in range(n) ]
fdeja = super(RealCartesianProductEJA, self)
- return fdeja.__init__(field, Qs, rank=n)
+ return fdeja.__init__(field, mult_table, rank=n)
def inner_product(self, x, y):
return _usual_ip(x,y)
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.
+ elements) for an algebra of those matrices.
"""
# In S^2, for example, we nominally have four coordinates even
# though the space is of dimension three only. The vector space V
V = VectorSpace(field, dimension**2)
W = V.span_of_basis( _mat2vec(s) for s in basis )
+ n = len(basis)
+ mult_table = [[W.zero() for i in range(n)] for j in range(n)]
+ for i in range(n):
+ for j in range(n):
+ mat_entry = (basis[i]*basis[j] + basis[j]*basis[i])/2
+ mult_table[i][j] = W.coordinate_vector(_mat2vec(mat_entry))
- 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
+ return mult_table
def _embed_complex_matrix(M):
"""
def __init__(self, n, field=QQ):
- Qs = []
- id_matrix = matrix.identity(field, n)
- for i in xrange(n):
- ei = id_matrix.column(i)
- Qi = matrix.zero(field, n)
- Qi.set_row(0, ei)
- Qi.set_column(0, ei)
- Qi += matrix.diagonal(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)
+ V = VectorSpace(field, n)
+ mult_table = [[V.zero() for i in range(n)] for j in range(n)]
+ for i in range(n):
+ for j in range(n):
+ x = V.basis()[i]
+ y = V.basis()[j]
+ x0 = x[0]
+ xbar = x[1:]
+ y0 = y[0]
+ ybar = y[1:]
+ # z = x*y
+ z0 = x.inner_product(y)
+ zbar = y0*xbar + x0*ybar
+ z = V([z0] + zbar.list())
+ mult_table[i][j] = z
# 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).
fdeja = super(JordanSpinEJA, self)
- return fdeja.__init__(field, Qs, rank=min(n,2))
+ return fdeja.__init__(field, mult_table, rank=min(n,2))
def inner_product(self, x, y):
return _usual_ip(x,y)