]> gitweb.michael.orlitzky.com - sage.d.git/commitdiff
eja: begin major overhaul of class hierarchy and naming.
authorMichael Orlitzky <michael@orlitzky.com>
Sun, 6 Dec 2020 04:52:48 +0000 (23:52 -0500)
committerMichael Orlitzky <michael@orlitzky.com>
Sun, 6 Dec 2020 04:52:48 +0000 (23:52 -0500)
mjo/eja/eja_algebra.py
mjo/eja/eja_element.py
mjo/eja/eja_element_subalgebra.py
mjo/eja/eja_operator.py
mjo/eja/eja_subalgebra.py

index 3b13ce10bbf864ceb667f3ba4fc1f8b520327292..1250fbda7981aba5474af0a3d2615c969bc9d1e1 100644 (file)
@@ -29,14 +29,204 @@ from sage.modules.free_module import FreeModule, VectorSpace
 from sage.rings.all import (ZZ, QQ, AA, QQbar, RR, RLF, CLF,
                             PolynomialRing,
                             QuadraticField)
-from mjo.eja.eja_element import FiniteDimensionalEuclideanJordanAlgebraElement
-from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+from mjo.eja.eja_element import FiniteDimensionalEJAElement
+from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
 from mjo.eja.eja_utils import _mat2vec
 
-class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
+class FiniteDimensionalEJA(CombinatorialFreeModule):
     r"""
-    The lowest-level class for representing a Euclidean Jordan algebra.
+    A finite-dimensional Euclidean Jordan algebra.
+
+    INPUT:
+
+      - basis -- a tuple of basis elements in their matrix form.
+
+      - jordan_product -- function of two elements (in matrix form)
+        that returns their jordan product in this algebra; this will
+        be applied to ``basis`` to compute a multiplication table for
+        the algebra.
+
+      - inner_product -- function of two elements (in matrix form) that
+        returns their inner product. This will be applied to ``basis`` to
+        compute an inner-product table (basically a matrix) for this algebra.
+
     """
+    Element = FiniteDimensionalEJAElement
+
+    def __init__(self,
+                 basis,
+                 jordan_product,
+                 inner_product,
+                 field=AA,
+                 orthonormalize=True,
+                 associative=False,
+                 check_field=True,
+                 check_axioms=True,
+                 prefix='e'):
+
+        if check_field:
+            if not field.is_subring(RR):
+                # Note: this does return true for the real algebraic
+                # field, the rationals, and any quadratic field where
+                # we've specified a real embedding.
+                raise ValueError("scalar field is not real")
+
+        # If the basis given to us wasn't over the field that it's
+        # supposed to be over, fix that. Or, you know, crash.
+        basis = tuple( b.change_ring(field) for b in basis )
+
+        if check_axioms:
+            # Check commutativity of the Jordan and inner-products.
+            # This has to be done before we build the multiplication
+            # and inner-product tables/matrices, because we take
+            # advantage of symmetry in the process.
+            if not all( jordan_product(bi,bj) == jordan_product(bj,bi)
+                        for bi in basis
+                        for bj in basis ):
+                raise ValueError("Jordan product is not commutative")
+
+            if not all( inner_product(bi,bj) == inner_product(bj,bi)
+                        for bi in basis
+                        for bj in basis ):
+                raise ValueError("inner-product is not commutative")
+
+
+        category = MagmaticAlgebras(field).FiniteDimensional()
+        category = category.WithBasis().Unital()
+        if associative:
+            # Element subalgebras can take advantage of this.
+            category = category.Associative()
+
+        # Call the superclass constructor so that we can use its from_vector()
+        # method to build our multiplication table.
+        n = len(basis)
+        super().__init__(field,
+                         range(n),
+                         prefix=prefix,
+                         category=category,
+                         bracket=False)
+
+        # Now comes all of the hard work. We'll be constructing an
+        # ambient vector space V that our (vectorized) basis lives in,
+        # as well as a subspace W of V spanned by those (vectorized)
+        # basis elements. The W-coordinates are the coefficients that
+        # we see in things like x = 1*e1 + 2*e2.
+        vector_basis = basis
+
+        from sage.structure.element import is_Matrix
+        basis_is_matrices = False
+
+        degree = 0
+        if n > 0:
+            if is_Matrix(basis[0]):
+                if basis[0].is_square():
+                    # TODO: this ugly is_square() hack works around the problem
+                    # of passing to_matrix()ed vectors in as the basis from a
+                    # subalgebra. They aren't REALLY matrices, at least not of
+                    # the type that we assume here... Ugh.
+                    basis_is_matrices = True
+                    from mjo.eja.eja_utils import _vec2mat
+                    vector_basis = tuple( map(_mat2vec,basis) )
+                    degree = basis[0].nrows()**2
+                else:
+                    # convert from column matrices to vectors, yuck
+                    basis = tuple( map(_mat2vec,basis) )
+                    vector_basis = basis
+                    degree = basis[0].degree()
+            else:
+                degree = basis[0].degree()
+
+        # Build an ambient space that fits...
+        V = VectorSpace(field, degree)
+
+        # We overwrite the name "vector_basis" in a second, but never modify it
+        # in place, to this effectively makes a copy of it.
+        deortho_vector_basis = vector_basis
+        self._deortho_matrix = None
+
+        if orthonormalize:
+            from mjo.eja.eja_utils import gram_schmidt
+            if basis_is_matrices:
+                vector_ip = lambda x,y: inner_product(_vec2mat(x), _vec2mat(y))
+                vector_basis = gram_schmidt(vector_basis, vector_ip)
+            else:
+                vector_basis = gram_schmidt(vector_basis, inner_product)
+
+            # Normalize the "matrix" basis, too!
+            basis = vector_basis
+
+            if basis_is_matrices:
+                basis = tuple( map(_vec2mat,basis) )
+
+        # Save the matrix "basis" for later... this is the last time we'll
+        # reference it in this constructor.
+        if basis_is_matrices:
+            self._matrix_basis = basis
+        else:
+            MS = MatrixSpace(self.base_ring(), degree, 1)
+            self._matrix_basis = tuple( MS(b) for b in basis )
+
+        # Now create the vector space for the algebra...
+        W = V.span_of_basis( vector_basis, check=check_axioms)
+
+        if orthonormalize:
+            # Now "W" is the vector space of our algebra coordinates. The
+            # variables "X1", "X2",...  refer to the entries of vectors in
+            # W. Thus to convert back and forth between the orthonormal
+            # coordinates and the given ones, we need to stick the original
+            # basis in W.
+            U = V.span_of_basis( deortho_vector_basis, check=check_axioms)
+            self._deortho_matrix = matrix( U.coordinate_vector(q)
+                                           for q in vector_basis )
+
+
+        # Now we actually compute the multiplication and inner-product
+        # tables/matrices using the possibly-orthonormalized basis.
+        self._inner_product_matrix = matrix.zero(field, n)
+        self._multiplication_table = [ [0 for j in range(i+1)] for i in range(n) ]
+
+        print("vector_basis:")
+        print(vector_basis)
+        # Note: the Jordan and inner-products are defined in terms
+        # of the ambient basis. It's important that their arguments
+        # are in ambient coordinates as well.
+        for i in range(n):
+            for j in range(i+1):
+                # ortho basis w.r.t. ambient coords
+                q_i = vector_basis[i]
+                q_j = vector_basis[j]
+
+                if basis_is_matrices:
+                    q_i = _vec2mat(q_i)
+                    q_j = _vec2mat(q_j)
+
+                elt = jordan_product(q_i, q_j)
+                ip = inner_product(q_i, q_j)
+
+                if basis_is_matrices:
+                    # do another mat2vec because the multiplication
+                    # table is in terms of vectors
+                    elt = _mat2vec(elt)
+
+                # TODO: the jordan product turns things back into
+                # matrices here even if they're supposed to be
+                # vectors. ugh. Can we get rid of vectors all together
+                # please?
+                elt = W.coordinate_vector(elt)
+                self._multiplication_table[i][j] = self.from_vector(elt)
+                self._inner_product_matrix[i,j] = ip
+                self._inner_product_matrix[j,i] = ip
+
+        self._inner_product_matrix._cache = {'hermitian': True}
+        self._inner_product_matrix.set_immutable()
+
+        if check_axioms:
+            if not self._is_jordanian():
+                raise ValueError("Jordan identity does not hold")
+            if not self._inner_product_is_associative():
+                raise ValueError("inner product is not associative")
+
+
     def _coerce_map_from_base_ring(self):
         """
         Disable the map from the base ring into the algebra.
@@ -61,190 +251,130 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
         """
         return None
 
-    def __init__(self,
-                 field,
-                 multiplication_table,
-                 inner_product_table,
-                 prefix='e',
-                 category=None,
-                 matrix_basis=None,
-                 check_field=True,
-                 check_axioms=True):
-        """
-        INPUT:
 
-          * field -- the scalar field for this algebra (must be real)
+    def product_on_basis(self, i, j):
+        # We only stored the lower-triangular portion of the
+        # multiplication table.
+        if j <= i:
+            return self._multiplication_table[i][j]
+        else:
+            return self._multiplication_table[j][i]
+
+    def inner_product(self, x, y):
+        """
+        The inner product associated with this Euclidean Jordan algebra.
 
-          * multiplication_table -- the multiplication table for this
-            algebra's implicit basis. Only the lower-triangular portion
-            of the table is used, since the multiplication is assumed
-            to be commutative.
+        Defaults to the trace inner product, but can be overridden by
+        subclasses if they are sure that the necessary properties are
+        satisfied.
 
         SETUP::
 
-            sage: from mjo.eja.eja_algebra import (
-            ....:   FiniteDimensionalEuclideanJordanAlgebra,
-            ....:   JordanSpinEJA,
-            ....:   random_eja)
+            sage: from mjo.eja.eja_algebra import (random_eja,
+            ....:                                  HadamardEJA,
+            ....:                                  BilinearFormEJA)
 
         EXAMPLES:
 
-        By definition, Jordan multiplication commutes::
+        Our inner product is "associative," which means the following for
+        a symmetric bilinear form::
 
             sage: set_random_seed()
             sage: J = random_eja()
-            sage: x,y = J.random_elements(2)
-            sage: x*y == y*x
+            sage: x,y,z = J.random_elements(3)
+            sage: (x*y).inner_product(z) == y.inner_product(x*z)
             True
 
-        An error is raised if the Jordan product is not commutative::
-
-            sage: JP = ((1,2),(0,0))
-            sage: IP = ((1,0),(0,1))
-            sage: FiniteDimensionalEuclideanJordanAlgebra(QQ,JP,IP)
-            Traceback (most recent call last):
-            ...
-            ValueError: Jordan product is not commutative
-
-        An error is raised if the inner-product is not commutative::
+        TESTS:
 
-            sage: JP = ((1,0),(0,1))
-            sage: IP = ((1,2),(0,0))
-            sage: FiniteDimensionalEuclideanJordanAlgebra(QQ,JP,IP)
-            Traceback (most recent call last):
-            ...
-            ValueError: inner-product is not commutative
+        Ensure that this is the usual inner product for the algebras
+        over `R^n`::
 
-        TESTS:
+            sage: set_random_seed()
+            sage: J = HadamardEJA.random_instance()
+            sage: x,y = J.random_elements(2)
+            sage: actual = x.inner_product(y)
+            sage: expected = x.to_vector().inner_product(y.to_vector())
+            sage: actual == expected
+            True
 
-        The ``field`` we're given must be real with ``check_field=True``::
+        Ensure that this is one-half of the trace inner-product in a
+        BilinearFormEJA that isn't just the reals (when ``n`` isn't
+        one). This is in Faraut and Koranyi, and also my "On the
+        symmetry..." paper::
 
-            sage: JordanSpinEJA(2, field=QQbar)
-            Traceback (most recent call last):
-            ...
-            ValueError: scalar field is not real
-            sage: JordanSpinEJA(2, field=QQbar, check_field=False)
-            Euclidean Jordan algebra of dimension 2 over Algebraic Field
+            sage: set_random_seed()
+            sage: J = BilinearFormEJA.random_instance()
+            sage: n = J.dimension()
+            sage: x = J.random_element()
+            sage: y = J.random_element()
+            sage: (n == 1) or (x.inner_product(y) == (x*y).trace()/2)
+            True
+        """
+        B = self._inner_product_matrix
+        return (B*x.to_vector()).inner_product(y.to_vector())
 
-        The multiplication table must be square with ``check_axioms=True``::
 
-            sage: FiniteDimensionalEuclideanJordanAlgebra(QQ,((),()),((1,),))
-            Traceback (most recent call last):
-            ...
-            ValueError: multiplication table is not square
+    def _is_commutative(self):
+        r"""
+        Whether or not this algebra's multiplication table is commutative.
 
-        The multiplication and inner-product tables must be the same
-        size (and in particular, the inner-product table must also be
-        square) with ``check_axioms=True``::
+        This method should of course always return ``True``, unless
+        this algebra was constructed with ``check_axioms=False`` and
+        passed an invalid multiplication table.
+        """
+        return all( self.product_on_basis(i,j) == self.product_on_basis(i,j)
+                    for i in range(self.dimension())
+                    for j in range(self.dimension()) )
 
-            sage: FiniteDimensionalEuclideanJordanAlgebra(QQ,((1,),),(()))
-            Traceback (most recent call last):
-            ...
-            ValueError: multiplication and inner-product tables are
-            different sizes
-            sage: FiniteDimensionalEuclideanJordanAlgebra(QQ,((1,),),((1,2),))
-            Traceback (most recent call last):
-            ...
-            ValueError: multiplication and inner-product tables are
-            different sizes
+    def _is_jordanian(self):
+        r"""
+        Whether or not this algebra's multiplication table respects the
+        Jordan identity `(x^{2})(xy) = x(x^{2}y)`.
 
+        We only check one arrangement of `x` and `y`, so for a
+        ``True`` result to be truly true, you should also check
+        :meth:`_is_commutative`. This method should of course always
+        return ``True``, unless this algebra was constructed with
+        ``check_axioms=False`` and passed an invalid multiplication table.
         """
-        if check_field:
-            if not field.is_subring(RR):
-                # Note: this does return true for the real algebraic
-                # field, the rationals, and any quadratic field where
-                # we've specified a real embedding.
-                raise ValueError("scalar field is not real")
+        return all( (self.monomial(i)**2)*(self.monomial(i)*self.monomial(j))
+                    ==
+                    (self.monomial(i))*((self.monomial(i)**2)*self.monomial(j))
+                    for i in range(self.dimension())
+                    for j in range(self.dimension()) )
 
+    def _inner_product_is_associative(self):
+        r"""
+        Return whether or not this algebra's inner product `B` is
+        associative; that is, whether or not `B(xy,z) = B(x,yz)`.
 
-        # The multiplication and inner-product tables should be square
-        # if the user wants us to verify them. And we verify them as
-        # soon as possible, because we want to exploit their symmetry.
-        n = len(multiplication_table)
-        if check_axioms:
-            if not all( len(l) == n for l in multiplication_table ):
-                raise ValueError("multiplication table is not square")
-
-            # If the multiplication table is square, we can check if
-            # the inner-product table is square by comparing it to the
-            # multiplication table's dimensions.
-            msg = "multiplication and inner-product tables are different sizes"
-            if not len(inner_product_table) == n:
-                raise ValueError(msg)
-
-            if not all( len(l) == n for l in inner_product_table ):
-                raise ValueError(msg)
-
-            # Check commutativity of the Jordan product (symmetry of
-            # the multiplication table) and the commutativity of the
-            # inner-product (symmetry of the inner-product table)
-            # first if we're going to check them at all.. This has to
-            # be done before we define product_on_basis(), because
-            # that method assumes that self._multiplication_table is
-            # symmetric. And it has to be done before we build
-            # self._inner_product_matrix, because the process used to
-            # construct it assumes symmetry as well.
-            if not all(    multiplication_table[j][i]
-                        == multiplication_table[i][j]
-                        for i in range(n)
-                        for j in range(i+1) ):
-                raise ValueError("Jordan product is not commutative")
+        This method should of course always return ``True``, unless
+        this algebra was constructed with ``check_axioms=False`` and
+        passed an invalid multiplication table.
+        """
 
-            if not all( inner_product_table[j][i]
-                        == inner_product_table[i][j]
-                        for i in range(n)
-                        for j in range(i+1) ):
-                raise ValueError("inner-product is not commutative")
+        # Used to check whether or not something is zero in an inexact
+        # ring. This number is sufficient to allow the construction of
+        # QuaternionHermitianEJA(2, field=RDF) with check_axioms=True.
+        epsilon = 1e-16
 
-        self._matrix_basis = matrix_basis
-
-        if category is None:
-            category = MagmaticAlgebras(field).FiniteDimensional()
-            category = category.WithBasis().Unital()
-
-        fda = super(FiniteDimensionalEuclideanJordanAlgebra, self)
-        fda.__init__(field,
-                     range(n),
-                     prefix=prefix,
-                     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.
-        #
-        # Note: we take advantage of symmetry here, and only store
-        # the lower-triangular portion of the table.
-        self._multiplication_table = [ [ self.vector_space().zero()
-                                         for j in range(i+1) ]
-                                       for i in range(n) ]
+        for i in range(self.dimension()):
+            for j in range(self.dimension()):
+                for k in range(self.dimension()):
+                    x = self.monomial(i)
+                    y = self.monomial(j)
+                    z = self.monomial(k)
+                    diff = (x*y).inner_product(z) - x.inner_product(y*z)
 
-        for i in range(n):
-            for j in range(i+1):
-                elt = self.from_vector(multiplication_table[i][j])
-                self._multiplication_table[i][j] = elt
-
-        self._multiplication_table = tuple(map(tuple, self._multiplication_table))
-
-        # Save our inner product as a matrix, since the efficiency of
-        # matrix multiplication will usually outweigh the fact that we
-        # have to store a redundant upper- or lower-triangular part.
-        # Pre-cache the fact that these are Hermitian (real symmetric,
-        # in fact) in case some e.g. matrix multiplication routine can
-        # take advantage of it.
-        ip_matrix_constructor = lambda i,j: inner_product_table[i][j] if j <= i else inner_product_table[j][i]
-        self._inner_product_matrix = matrix(field, n, ip_matrix_constructor)
-        self._inner_product_matrix._cache = {'hermitian': True}
-        self._inner_product_matrix.set_immutable()
+                    if self.base_ring().is_exact():
+                        if diff != 0:
+                            return False
+                    else:
+                        if diff.abs() > epsilon:
+                            return False
 
-        if check_axioms:
-            if not self._is_jordanian():
-                raise ValueError("Jordan identity does not hold")
-            if not self._inner_product_is_associative():
-                raise ValueError("inner product is not associative")
+        return True
 
     def _element_constructor_(self, elt):
         """
@@ -307,6 +437,12 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
             # that the integer 3 belongs to the space of 2-by-2 matrices.
             raise ValueError(msg)
 
+        try:
+            elt = elt.column()
+        except (AttributeError, TypeError):
+            # Try to convert a vector into a column-matrix
+            pass
+
         if elt not in self.matrix_space():
             raise ValueError(msg)
 
@@ -351,74 +487,6 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
         fmt = "Euclidean Jordan algebra of dimension {} over {}"
         return fmt.format(self.dimension(), self.base_ring())
 
-    def product_on_basis(self, i, j):
-        # We only stored the lower-triangular portion of the
-        # multiplication table.
-        if j <= i:
-            return self._multiplication_table[i][j]
-        else:
-            return self._multiplication_table[j][i]
-
-    def _is_commutative(self):
-        r"""
-        Whether or not this algebra's multiplication table is commutative.
-
-        This method should of course always return ``True``, unless
-        this algebra was constructed with ``check_axioms=False`` and
-        passed an invalid multiplication table.
-        """
-        return all( self.product_on_basis(i,j) == self.product_on_basis(i,j)
-                    for i in range(self.dimension())
-                    for j in range(self.dimension()) )
-
-    def _is_jordanian(self):
-        r"""
-        Whether or not this algebra's multiplication table respects the
-        Jordan identity `(x^{2})(xy) = x(x^{2}y)`.
-
-        We only check one arrangement of `x` and `y`, so for a
-        ``True`` result to be truly true, you should also check
-        :meth:`_is_commutative`. This method should of course always
-        return ``True``, unless this algebra was constructed with
-        ``check_axioms=False`` and passed an invalid multiplication table.
-        """
-        return all( (self.monomial(i)**2)*(self.monomial(i)*self.monomial(j))
-                    ==
-                    (self.monomial(i))*((self.monomial(i)**2)*self.monomial(j))
-                    for i in range(self.dimension())
-                    for j in range(self.dimension()) )
-
-    def _inner_product_is_associative(self):
-        r"""
-        Return whether or not this algebra's inner product `B` is
-        associative; that is, whether or not `B(xy,z) = B(x,yz)`.
-
-        This method should of course always return ``True``, unless
-        this algebra was constructed with ``check_axioms=False`` and
-        passed an invalid multiplication table.
-        """
-
-        # Used to check whether or not something is zero in an inexact
-        # ring. This number is sufficient to allow the construction of
-        # QuaternionHermitianEJA(2, field=RDF) with check_axioms=True.
-        epsilon = 1e-16
-
-        for i in range(self.dimension()):
-            for j in range(self.dimension()):
-                for k in range(self.dimension()):
-                    x = self.monomial(i)
-                    y = self.monomial(j)
-                    z = self.monomial(k)
-                    diff = (x*y).inner_product(z) - x.inner_product(y*z)
-
-                    if self.base_ring().is_exact():
-                        if diff != 0:
-                            return False
-                    else:
-                        if diff.abs() > epsilon:
-                            return False
-
-        return True
 
     @cached_method
     def characteristic_polynomial_of(self):
@@ -681,11 +749,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
             [0], [1]
             )
         """
-        if self._matrix_basis is None:
-            M = self.matrix_space()
-            return tuple( M(b.to_vector()) for b in self.basis() )
-        else:
-            return self._matrix_basis
+        return self._matrix_basis
 
 
     def matrix_space(self):
@@ -703,8 +767,6 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
         """
         if self.is_trivial():
             return MatrixSpace(self.base_ring(), 0)
-        elif self._matrix_basis is None or len(self._matrix_basis) == 0:
-            return MatrixSpace(self.base_ring(), self.dimension(), 1)
         else:
             return self._matrix_basis[0].matrix_space()
 
@@ -898,14 +960,14 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
         if not c.is_idempotent():
             raise ValueError("element is not idempotent: %s" % c)
 
-        from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanSubalgebra
+        from mjo.eja.eja_subalgebra import FiniteDimensionalEJASubalgebra
 
         # 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, ())
+        trivial = FiniteDimensionalEJASubalgebra(self, ())
         J0 = trivial                          # eigenvalue zero
         J5 = VectorSpace(self.base_ring(), 0) # eigenvalue one-half
         J1 = trivial                          # eigenvalue one
@@ -915,9 +977,9 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
                 J5 = eigspace
             else:
                 gens = tuple( self.from_vector(b) for b in eigspace.basis() )
-                subalg = FiniteDimensionalEuclideanJordanSubalgebra(self,
-                                                                    gens,
-                                                                    check_axioms=False)
+                subalg = FiniteDimensionalEJASubalgebra(self,
+                                                        gens,
+                                                        check_axioms=False)
                 if eigval == 0:
                     J0 = subalg
                 elif eigval == 1:
@@ -1132,9 +1194,9 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
         return self.zero().to_vector().parent().ambient_vector_space()
 
 
-    Element = FiniteDimensionalEuclideanJordanAlgebraElement
+    Element = FiniteDimensionalEJAElement
 
-class RationalBasisEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
+class RationalBasisEJA(FiniteDimensionalEJA):
     r"""
     New class for algebras whose supplied basis elements have all rational entries.
 
@@ -1162,10 +1224,9 @@ class RationalBasisEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebr
                  inner_product,
                  field=AA,
                  orthonormalize=True,
-                 prefix='e',
-                 category=None,
                  check_field=True,
-                 check_axioms=True):
+                 check_axioms=True,
+                 **kwargs):
 
         if check_field:
             # Abuse the check_field parameter to check that the entries of
@@ -1173,32 +1234,6 @@ class RationalBasisEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebr
             if not all( all(b_i in QQ for b_i in b.list()) for b in basis ):
                 raise TypeError("basis not rational")
 
-        # Temporary(?) hack to ensure that the matrix and vector bases
-        # are over the same ring.
-        basis = tuple( b.change_ring(field) for b in basis )
-
-        n = len(basis)
-        vector_basis = basis
-
-        from sage.structure.element import is_Matrix
-        basis_is_matrices = False
-
-        degree = 0
-        if n > 0:
-            if is_Matrix(basis[0]):
-                basis_is_matrices = True
-                from mjo.eja.eja_utils import _vec2mat
-                vector_basis = tuple( map(_mat2vec,basis) )
-                degree = basis[0].nrows()**2
-            else:
-                degree = basis[0].degree()
-
-        V = VectorSpace(field, degree)
-
-        # Save a copy of an algebra with the original, rational basis
-        # and over QQ where computations are fast.
-        self._rational_algebra = None
-
         if field is not QQ:
             # There's no point in constructing the extra algebra if this
             # one is already rational.
@@ -1206,128 +1241,23 @@ class RationalBasisEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebr
             # Note: the same Jordan and inner-products work here,
             # because they are necessarily defined with respect to
             # ambient coordinates and not any particular basis.
-            self._rational_algebra = RationalBasisEuclideanJordanAlgebra(
+            self._rational_algebra = FiniteDimensionalEJA(
                                        basis,
                                        jordan_product,
                                        inner_product,
                                        field=QQ,
                                        orthonormalize=False,
-                                       prefix=prefix,
-                                       category=category,
                                        check_field=False,
-                                       check_axioms=False)
-
-        if orthonormalize:
-            # Compute the deorthonormalized tables before we orthonormalize
-            # the given basis. The "check" parameter here guarantees that
-            # the basis is linearly-independent.
-            W = V.span_of_basis( vector_basis, check=check_axioms)
-
-            # Note: the Jordan and inner-products are defined in terms
-            # of the ambient basis. It's important that their arguments
-            # are in ambient coordinates as well.
-            for i in range(n):
-                for j in range(i+1):
-                    # given basis w.r.t. ambient coords
-                    q_i = vector_basis[i]
-                    q_j = vector_basis[j]
-
-                    if basis_is_matrices:
-                        q_i = _vec2mat(q_i)
-                        q_j = _vec2mat(q_j)
-
-                    elt = jordan_product(q_i, q_j)
-                    ip = inner_product(q_i, q_j)
-
-                    if basis_is_matrices:
-                        # do another mat2vec because the multiplication
-                        # table is in terms of vectors
-                        elt = _mat2vec(elt)
-
-        # We overwrite the name "vector_basis" in a second, but never modify it
-        # in place, to this effectively makes a copy of it.
-        deortho_vector_basis = vector_basis
-        self._deortho_matrix = None
-
-        if orthonormalize:
-            from mjo.eja.eja_utils import gram_schmidt
-            if basis_is_matrices:
-                vector_ip = lambda x,y: inner_product(_vec2mat(x), _vec2mat(y))
-                vector_basis = gram_schmidt(vector_basis, vector_ip)
-            else:
-                vector_basis = gram_schmidt(vector_basis, inner_product)
-
-            # Normalize the "matrix" basis, too!
-            basis = vector_basis
+                                       check_axioms=False,
+                                       **kwargs)
 
-            if basis_is_matrices:
-                basis = tuple( map(_vec2mat,basis) )
-
-        W = V.span_of_basis( vector_basis, check=check_axioms)
-
-        # Now "W" is the vector space of our algebra coordinates. The
-        # variables "X1", "X2",...  refer to the entries of vectors in
-        # W. Thus to convert back and forth between the orthonormal
-        # coordinates and the given ones, we need to stick the original
-        # basis in W.
-        U = V.span_of_basis( deortho_vector_basis, check=check_axioms)
-        self._deortho_matrix = matrix( U.coordinate_vector(q)
-                                       for q in vector_basis )
-
-        # If the superclass constructor is going to verify the
-        # symmetry of this table, it has better at least be
-        # square...
-        if check_axioms:
-            mult_table = [ [0 for j in range(n)] for i in range(n) ]
-            ip_table = [ [0 for j in range(n)] for i in range(n) ]
-        else:
-            mult_table = [ [0 for j in range(i+1)] for i in range(n) ]
-            ip_table = [ [0 for j in range(i+1)] for i in range(n) ]
-
-        # Note: the Jordan and inner-products are defined in terms
-        # of the ambient basis. It's important that their arguments
-        # are in ambient coordinates as well.
-        for i in range(n):
-            for j in range(i+1):
-                # ortho basis w.r.t. ambient coords
-                q_i = vector_basis[i]
-                q_j = vector_basis[j]
-
-                if basis_is_matrices:
-                    q_i = _vec2mat(q_i)
-                    q_j = _vec2mat(q_j)
-
-                elt = jordan_product(q_i, q_j)
-                ip = inner_product(q_i, q_j)
-
-                if basis_is_matrices:
-                    # do another mat2vec because the multiplication
-                    # table is in terms of vectors
-                    elt = _mat2vec(elt)
-
-                elt = W.coordinate_vector(elt)
-                mult_table[i][j] = elt
-                ip_table[i][j] = ip
-                if check_axioms:
-                    # The tables are square if we're verifying that they
-                    # are commutative.
-                    mult_table[j][i] = elt
-                    ip_table[j][i] = ip
-
-        if basis_is_matrices:
-            for m in basis:
-                m.set_immutable()
-        else:
-            basis = tuple( x.column() for x in basis )
-
-        super().__init__(field,
-                         mult_table,
-                         ip_table,
-                         prefix,
-                         category,
-                         basis, # matrix basis
-                         check_field,
-                         check_axioms)
+        super().__init__(basis,
+                         jordan_product,
+                         inner_product,
+                         field=field,
+                         check_field=check_field,
+                         check_axioms=check_axioms,
+                         **kwargs)
 
     @cached_method
     def _charpoly_coefficients(self):
@@ -1358,8 +1288,7 @@ class RationalBasisEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebr
             # rationals if this one is already over the
             # rationals. Likewise, if we never orthonormalized our
             # basis, we might as well just use the given one.
-            superclass = super(RationalBasisEuclideanJordanAlgebra, self)
-            return superclass._charpoly_coefficients()
+            return super()._charpoly_coefficients()
 
         # Do the computation over the rationals. The answer will be
         # the same, because all we've done is a change of basis.
@@ -1377,7 +1306,7 @@ class RationalBasisEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebr
         subs_dict = { X[i]: BX[i] for i in range(len(X)) }
         return tuple( a_i.subs(subs_dict) for a_i in a )
 
-class ConcreteEuclideanJordanAlgebra(RationalBasisEuclideanJordanAlgebra):
+class ConcreteEJA(RationalBasisEJA):
     r"""
     A class for the Euclidean Jordan algebras that we know by name.
 
@@ -1388,7 +1317,7 @@ class ConcreteEuclideanJordanAlgebra(RationalBasisEuclideanJordanAlgebra):
 
     SETUP::
 
-        sage: from mjo.eja.eja_algebra import ConcreteEuclideanJordanAlgebra
+        sage: from mjo.eja.eja_algebra import ConcreteEJA
 
     TESTS:
 
@@ -1396,7 +1325,7 @@ class ConcreteEuclideanJordanAlgebra(RationalBasisEuclideanJordanAlgebra):
     product, unless we specify otherwise::
 
         sage: set_random_seed()
-        sage: J = ConcreteEuclideanJordanAlgebra.random_instance()
+        sage: J = ConcreteEJA.random_instance()
         sage: all( b.norm() == 1 for b in J.gens() )
         True
 
@@ -1407,7 +1336,7 @@ class ConcreteEuclideanJordanAlgebra(RationalBasisEuclideanJordanAlgebra):
     EJA the operator is self-adjoint by the Jordan axiom::
 
         sage: set_random_seed()
-        sage: J = ConcreteEuclideanJordanAlgebra.random_instance()
+        sage: J = ConcreteEJA.random_instance()
         sage: x = J.random_element()
         sage: x.operator().is_self_adjoint()
         True
@@ -1439,13 +1368,13 @@ class ConcreteEuclideanJordanAlgebra(RationalBasisEuclideanJordanAlgebra):
         from sage.misc.prandom import choice
         eja_class = choice(cls.__subclasses__())
 
-        # These all bubble up to the RationalBasisEuclideanJordanAlgebra
-        # superclass constructor, so any (kw)args valid there are also
-        # valid here.
+        # These all bubble up to the RationalBasisEJA superclass
+        # constructor, so any (kw)args valid there are also valid
+        # here.
         return eja_class.random_instance(*args, **kwargs)
 
 
-class MatrixEuclideanJordanAlgebra:
+class MatrixEJA:
     @staticmethod
     def dimension_over_reals():
         r"""
@@ -1566,14 +1495,13 @@ class MatrixEuclideanJordanAlgebra:
             return tr.coefficient_tuple()[0]
 
 
-class RealMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
+class RealMatrixEJA(MatrixEJA):
     @staticmethod
     def dimension_over_reals():
         return 1
 
 
-class RealSymmetricEJA(ConcreteEuclideanJordanAlgebra,
-                       RealMatrixEuclideanJordanAlgebra):
+class RealSymmetricEJA(ConcreteEJA, RealMatrixEJA):
     """
     The rank-n simple EJA consisting of real symmetric n-by-n
     matrices, the usual symmetric Jordan product, and the trace inner
@@ -1693,15 +1621,15 @@ class RealSymmetricEJA(ConcreteEuclideanJordanAlgebra,
                                                **kwargs)
 
         # TODO: this could be factored out somehow, but is left here
-        # because the MatrixEuclideanJordanAlgebra is not presently
-        # a subclass of the FDEJA class that defines rank() and one().
+        # because the MatrixEJA is not presently a subclass of the
+        # FDEJA class that defines rank() and one().
         self.rank.set_cache(n)
         idV = matrix.identity(ZZ, self.dimension_over_reals()*n)
         self.one.set_cache(self(idV))
 
 
 
-class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
+class ComplexMatrixEJA(MatrixEJA):
     @staticmethod
     def dimension_over_reals():
         return 2
@@ -1715,8 +1643,7 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
 
         SETUP::
 
-            sage: from mjo.eja.eja_algebra import \
-            ....:   ComplexMatrixEuclideanJordanAlgebra
+            sage: from mjo.eja.eja_algebra import ComplexMatrixEJA
 
         EXAMPLES::
 
@@ -1726,7 +1653,7 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
             sage: x3 = F(-i)
             sage: x4 = F(6)
             sage: M = matrix(F,2,[[x1,x2],[x3,x4]])
-            sage: ComplexMatrixEuclideanJordanAlgebra.real_embed(M)
+            sage: ComplexMatrixEJA.real_embed(M)
             [ 4 -2| 1  2]
             [ 2  4|-2  1]
             [-----+-----]
@@ -1742,14 +1669,14 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
             sage: F = QuadraticField(-1, 'I')
             sage: X = random_matrix(F, n)
             sage: Y = random_matrix(F, n)
-            sage: Xe = ComplexMatrixEuclideanJordanAlgebra.real_embed(X)
-            sage: Ye = ComplexMatrixEuclideanJordanAlgebra.real_embed(Y)
-            sage: XYe = ComplexMatrixEuclideanJordanAlgebra.real_embed(X*Y)
+            sage: Xe = ComplexMatrixEJA.real_embed(X)
+            sage: Ye = ComplexMatrixEJA.real_embed(Y)
+            sage: XYe = ComplexMatrixEJA.real_embed(X*Y)
             sage: Xe*Ye == XYe
             True
 
         """
-        super(ComplexMatrixEuclideanJordanAlgebra,cls).real_embed(M)
+        super(ComplexMatrixEJA,cls).real_embed(M)
         n = M.nrows()
 
         # We don't need any adjoined elements...
@@ -1771,8 +1698,7 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
 
         SETUP::
 
-            sage: from mjo.eja.eja_algebra import \
-            ....:   ComplexMatrixEuclideanJordanAlgebra
+            sage: from mjo.eja.eja_algebra import ComplexMatrixEJA
 
         EXAMPLES::
 
@@ -1780,7 +1706,7 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
             ....:                 [-2,  1,  -4,  3],
             ....:                 [ 9,  10, 11, 12],
             ....:                 [-10, 9, -12, 11] ])
-            sage: ComplexMatrixEuclideanJordanAlgebra.real_unembed(A)
+            sage: ComplexMatrixEJA.real_unembed(A)
             [  2*I + 1   4*I + 3]
             [ 10*I + 9 12*I + 11]
 
@@ -1791,12 +1717,12 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
             sage: set_random_seed()
             sage: F = QuadraticField(-1, 'I')
             sage: M = random_matrix(F, 3)
-            sage: Me = ComplexMatrixEuclideanJordanAlgebra.real_embed(M)
-            sage: ComplexMatrixEuclideanJordanAlgebra.real_unembed(Me) == M
+            sage: Me = ComplexMatrixEJA.real_embed(M)
+            sage: ComplexMatrixEJA.real_unembed(Me) == M
             True
 
         """
-        super(ComplexMatrixEuclideanJordanAlgebra,cls).real_unembed(M)
+        super(ComplexMatrixEJA,cls).real_unembed(M)
         n = ZZ(M.nrows())
         d = cls.dimension_over_reals()
 
@@ -1837,8 +1763,7 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
         return matrix(F, n/d, elements)
 
 
-class ComplexHermitianEJA(ConcreteEuclideanJordanAlgebra,
-                          ComplexMatrixEuclideanJordanAlgebra):
+class ComplexHermitianEJA(ConcreteEJA, ComplexMatrixEJA):
     """
     The rank-n simple EJA consisting of complex Hermitian n-by-n
     matrices over the real numbers, the usual symmetric Jordan product,
@@ -1961,8 +1886,8 @@ class ComplexHermitianEJA(ConcreteEuclideanJordanAlgebra,
                                                   self.trace_inner_product,
                                                   **kwargs)
         # TODO: this could be factored out somehow, but is left here
-        # because the MatrixEuclideanJordanAlgebra is not presently
-        # a subclass of the FDEJA class that defines rank() and one().
+        # because the MatrixEJA is not presently a subclass of the
+        # FDEJA class that defines rank() and one().
         self.rank.set_cache(n)
         idV = matrix.identity(ZZ, self.dimension_over_reals()*n)
         self.one.set_cache(self(idV))
@@ -1979,7 +1904,7 @@ class ComplexHermitianEJA(ConcreteEuclideanJordanAlgebra,
         n = ZZ.random_element(cls._max_random_instance_size() + 1)
         return cls(n, **kwargs)
 
-class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
+class QuaternionMatrixEJA(MatrixEJA):
     @staticmethod
     def dimension_over_reals():
         return 4
@@ -1995,8 +1920,7 @@ class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
 
         SETUP::
 
-            sage: from mjo.eja.eja_algebra import \
-            ....:   QuaternionMatrixEuclideanJordanAlgebra
+            sage: from mjo.eja.eja_algebra import QuaternionMatrixEJA
 
         EXAMPLES::
 
@@ -2004,7 +1928,7 @@ class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
             sage: i,j,k = Q.gens()
             sage: x = 1 + 2*i + 3*j + 4*k
             sage: M = matrix(Q, 1, [[x]])
-            sage: QuaternionMatrixEuclideanJordanAlgebra.real_embed(M)
+            sage: QuaternionMatrixEJA.real_embed(M)
             [ 1  2  3  4]
             [-2  1 -4  3]
             [-3  4  1 -2]
@@ -2017,14 +1941,14 @@ class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
             sage: Q = QuaternionAlgebra(QQ,-1,-1)
             sage: X = random_matrix(Q, n)
             sage: Y = random_matrix(Q, n)
-            sage: Xe = QuaternionMatrixEuclideanJordanAlgebra.real_embed(X)
-            sage: Ye = QuaternionMatrixEuclideanJordanAlgebra.real_embed(Y)
-            sage: XYe = QuaternionMatrixEuclideanJordanAlgebra.real_embed(X*Y)
+            sage: Xe = QuaternionMatrixEJA.real_embed(X)
+            sage: Ye = QuaternionMatrixEJA.real_embed(Y)
+            sage: XYe = QuaternionMatrixEJA.real_embed(X*Y)
             sage: Xe*Ye == XYe
             True
 
         """
-        super(QuaternionMatrixEuclideanJordanAlgebra,cls).real_embed(M)
+        super(QuaternionMatrixEJA,cls).real_embed(M)
         quaternions = M.base_ring()
         n = M.nrows()
 
@@ -2040,7 +1964,7 @@ class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
             d = t[3]
             cplxM = matrix(F, 2, [[ a + b*i, c + d*i],
                                  [-c + d*i, a - b*i]])
-            realM = ComplexMatrixEuclideanJordanAlgebra.real_embed(cplxM)
+            realM = ComplexMatrixEJA.real_embed(cplxM)
             blocks.append(realM)
 
         # We should have real entries by now, so use the realest field
@@ -2056,8 +1980,7 @@ class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
 
         SETUP::
 
-            sage: from mjo.eja.eja_algebra import \
-            ....:   QuaternionMatrixEuclideanJordanAlgebra
+            sage: from mjo.eja.eja_algebra import QuaternionMatrixEJA
 
         EXAMPLES::
 
@@ -2065,7 +1988,7 @@ class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
             ....:                 [-2,  1, -4,  3],
             ....:                 [-3,  4,  1, -2],
             ....:                 [-4, -3,  2,  1]])
-            sage: QuaternionMatrixEuclideanJordanAlgebra.real_unembed(M)
+            sage: QuaternionMatrixEJA.real_unembed(M)
             [1 + 2*i + 3*j + 4*k]
 
         TESTS:
@@ -2075,12 +1998,12 @@ class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
             sage: set_random_seed()
             sage: Q = QuaternionAlgebra(QQ, -1, -1)
             sage: M = random_matrix(Q, 3)
-            sage: Me = QuaternionMatrixEuclideanJordanAlgebra.real_embed(M)
-            sage: QuaternionMatrixEuclideanJordanAlgebra.real_unembed(Me) == M
+            sage: Me = QuaternionMatrixEJA.real_embed(M)
+            sage: QuaternionMatrixEJA.real_unembed(Me) == M
             True
 
         """
-        super(QuaternionMatrixEuclideanJordanAlgebra,cls).real_unembed(M)
+        super(QuaternionMatrixEJA,cls).real_unembed(M)
         n = ZZ(M.nrows())
         d = cls.dimension_over_reals()
 
@@ -2096,7 +2019,7 @@ class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
         elements = []
         for l in range(n/d):
             for m in range(n/d):
-                submat = ComplexMatrixEuclideanJordanAlgebra.real_unembed(
+                submat = ComplexMatrixEJA.real_unembed(
                     M[d*l:d*l+d,d*m:d*m+d] )
                 if submat[0,0] != submat[1,1].conjugate():
                     raise ValueError('bad on-diagonal submatrix')
@@ -2111,8 +2034,7 @@ class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
         return matrix(Q, n/d, elements)
 
 
-class QuaternionHermitianEJA(ConcreteEuclideanJordanAlgebra,
-                             QuaternionMatrixEuclideanJordanAlgebra):
+class QuaternionHermitianEJA(ConcreteEJA, QuaternionMatrixEJA):
     r"""
     The rank-n simple EJA consisting of self-adjoint n-by-n quaternion
     matrices, the usual symmetric Jordan product, and the
@@ -2236,8 +2158,8 @@ class QuaternionHermitianEJA(ConcreteEuclideanJordanAlgebra,
                                                      self.trace_inner_product,
                                                      **kwargs)
         # TODO: this could be factored out somehow, but is left here
-        # because the MatrixEuclideanJordanAlgebra is not presently
-        # a subclass of the FDEJA class that defines rank() and one().
+        # because the MatrixEJA is not presently a subclass of the
+        # FDEJA class that defines rank() and one().
         self.rank.set_cache(n)
         idV = matrix.identity(ZZ, self.dimension_over_reals()*n)
         self.one.set_cache(self(idV))
@@ -2259,7 +2181,7 @@ class QuaternionHermitianEJA(ConcreteEuclideanJordanAlgebra,
         return cls(n, **kwargs)
 
 
-class HadamardEJA(ConcreteEuclideanJordanAlgebra):
+class HadamardEJA(ConcreteEJA):
     """
     Return the Euclidean Jordan Algebra corresponding to the set
     `R^n` under the Hadamard product.
@@ -2344,7 +2266,7 @@ class HadamardEJA(ConcreteEuclideanJordanAlgebra):
         return cls(n, **kwargs)
 
 
-class BilinearFormEJA(ConcreteEuclideanJordanAlgebra):
+class BilinearFormEJA(ConcreteEJA):
     r"""
     The rank-2 simple EJA consisting of real vectors ``x=(x0, x_bar)``
     with the half-trace inner product and jordan product ``x*y =
@@ -2576,7 +2498,7 @@ class JordanSpinEJA(BilinearFormEJA):
         return cls(n, **kwargs)
 
 
-class TrivialEJA(ConcreteEuclideanJordanAlgebra):
+class TrivialEJA(ConcreteEJA):
     """
     The trivial Euclidean Jordan algebra consisting of only a zero element.
 
@@ -2629,7 +2551,7 @@ class TrivialEJA(ConcreteEuclideanJordanAlgebra):
         # inappropriate for us.
         return cls(**kwargs)
 
-class DirectSumEJA(FiniteDimensionalEuclideanJordanAlgebra):
+class DirectSumEJA(ConcreteEJA):
     r"""
     The external (orthogonal) direct sum of two other Euclidean Jordan
     algebras. Essentially the Cartesian product of its two factors.
@@ -2757,8 +2679,8 @@ class DirectSumEJA(FiniteDimensionalEuclideanJordanAlgebra):
         # zero-by-two matrix (important for composing things).
         P1 = matrix(self.base_ring(), m, m+n, V_basis[:m])
         P2 = matrix(self.base_ring(), n, m+n, V_basis[m:])
-        pi_left = FiniteDimensionalEuclideanJordanAlgebraOperator(self,J1,P1)
-        pi_right = FiniteDimensionalEuclideanJordanAlgebraOperator(self,J2,P2)
+        pi_left = FiniteDimensionalEJAOperator(self,J1,P1)
+        pi_right = FiniteDimensionalEJAOperator(self,J2,P2)
         return (pi_left, pi_right)
 
     def inclusions(self):
@@ -2824,8 +2746,8 @@ class DirectSumEJA(FiniteDimensionalEuclideanJordanAlgebra):
         # two-by-zero matrix (important for composing things).
         I1 = matrix.column(self.base_ring(), m, m+n, V_basis[:m])
         I2 = matrix.column(self.base_ring(), n, m+n, V_basis[m:])
-        iota_left = FiniteDimensionalEuclideanJordanAlgebraOperator(J1,self,I1)
-        iota_right = FiniteDimensionalEuclideanJordanAlgebraOperator(J2,self,I2)
+        iota_left = FiniteDimensionalEJAOperator(J1,self,I1)
+        iota_right = FiniteDimensionalEJAOperator(J2,self,I2)
         return (iota_left, iota_right)
 
     def inner_product(self, x, y):
@@ -2869,4 +2791,4 @@ class DirectSumEJA(FiniteDimensionalEuclideanJordanAlgebra):
 
 
 
-random_eja = ConcreteEuclideanJordanAlgebra.random_instance
+random_eja = ConcreteEJA.random_instance
index 6812e2807a7ff3c3a4f7253c7af9750f5de8fbb2..6181f032e644423989cf135cd65eeafcb943585f 100644 (file)
@@ -2,10 +2,10 @@ from sage.matrix.constructor import matrix
 from sage.modules.free_module import VectorSpace
 from sage.modules.with_basis.indexed_element import IndexedFreeModuleElement
 
-from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
 from mjo.eja.eja_utils import _mat2vec
 
-class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
+class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
     """
     An element of a Euclidean Jordan algebra.
     """
@@ -1122,10 +1122,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
         P = self.parent()
         left_mult_by_self = lambda y: self*y
         L = P.module_morphism(function=left_mult_by_self, codomain=P)
-        return FiniteDimensionalEuclideanJordanAlgebraOperator(
-                 P,
-                 P,
-                 L.matrix() )
+        return FiniteDimensionalEJAOperator(P, P, L.matrix() )
 
 
     def quadratic_representation(self, other=None):
@@ -1370,8 +1367,8 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             True
 
         """
-        from mjo.eja.eja_element_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
-        return FiniteDimensionalEuclideanJordanElementSubalgebra(self, orthonormalize_basis)
+        from mjo.eja.eja_element_subalgebra import FiniteDimensionalEJAElementSubalgebra
+        return FiniteDimensionalEJAElementSubalgebra(self, orthonormalize_basis)
 
 
     def subalgebra_idempotent(self):
index 7edf1df940fb3e16435eb7d232fea0ceb58eff7a..dceb3b405a4c5a663c61a966993ce890ed516b49 100644 (file)
@@ -2,24 +2,20 @@ from sage.matrix.constructor import matrix
 from sage.misc.cachefunc import cached_method
 from sage.rings.all import QQ
 
-from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanSubalgebra
+from mjo.eja.eja_subalgebra import FiniteDimensionalEJASubalgebra
 
 
-class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclideanJordanSubalgebra):
-    def __init__(self, elt, orthonormalize_basis):
-        self._superalgebra = elt.parent()
-        category = self._superalgebra.category().Associative()
-        V = self._superalgebra.vector_space()
-        field = self._superalgebra.base_ring()
+class FiniteDimensionalEJAElementSubalgebra(FiniteDimensionalEJASubalgebra):
+    def __init__(self, elt, orthonormalize=True, **kwargs):
+        superalgebra = elt.parent()
 
-        # This list is guaranteed to contain all independent powers,
-        # because it's the maximal set of powers that could possibly
-        # be independent (by a dimension argument).
-        powers = [ elt**k for k in range(V.dimension()) ]
-        power_vectors = [ p.to_vector() for p in powers ]
-        P = matrix(field, power_vectors)
+        powers = tuple( elt**k for k in range(superalgebra.dimension()) )
+        power_vectors = ( p.to_vector() for p in powers )
+        P = matrix(superalgebra.base_ring(), power_vectors)
 
-        if orthonormalize_basis == False:
+        if orthonormalize:
+            basis = powers # let god sort 'em out
+        else:
             # Echelonize the matrix ourselves, because otherwise the
             # call to P.pivot_rows() below can choose a non-optimal
             # row-reduction algorithm. In particular, scaling can
@@ -29,39 +25,26 @@ class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclide
             # Beware: QQ supports an entirely different set of "algorithm"
             # keywords than do AA and RR.
             algo = None
-            if field is not QQ:
+            if superalgebra.base_ring() is not QQ:
                 algo = "scaled_partial_pivoting"
-            P.echelonize(algorithm=algo)
+                P.echelonize(algorithm=algo)
 
-            # In this case, we just need to figure out which elements
-            # of the "powers" list are redundant... First compute the
-            # vector subspace spanned by the powers of the given
-            # element.
+                # In this case, we just need to figure out which elements
+                # of the "powers" list are redundant... First compute the
+                # vector subspace spanned by the powers of the given
+                # element.
 
-            # Figure out which powers form a linearly-independent set.
-            ind_rows = P.pivot_rows()
+                # Figure out which powers form a linearly-independent set.
+                ind_rows = P.pivot_rows()
 
-            # Pick those out of the list of all powers.
-            superalgebra_basis = tuple(map(powers.__getitem__, ind_rows))
-        else:
-            # If we're going to orthonormalize the basis anyway, we
-            # might as well just do Gram-Schmidt on the whole list of
-            # powers. The redundant ones will get zero'd out. If this
-            # looks like a roundabout way to orthonormalize, it is.
-            # But converting everything from algebra elements to vectors
-            # to matrices and then back again turns out to be about
-            # as fast as reimplementing our own Gram-Schmidt that
-            # works in an EJA.
-            G,_ = P.gram_schmidt(orthonormal=True)
-            basis_vectors = [ g for g in G.rows() if not g.is_zero() ]
-            superalgebra_basis = [ self._superalgebra.from_vector(b)
-                                   for b in basis_vectors ]
-
-        fdeja = super(FiniteDimensionalEuclideanJordanElementSubalgebra, self)
-        fdeja.__init__(self._superalgebra,
-                       superalgebra_basis,
-                       category=category,
-                       check_axioms=False)
+                # Pick those out of the list of all powers.
+                basis = tuple(map(powers.__getitem__, ind_rows))
+
+
+        super().__init__(superalgebra,
+                         basis,
+                         associative=True,
+                         **kwargs)
 
         # The rank is the highest possible degree of a minimal
         # polynomial, and is bounded above by the dimension. We know
index 0b52f555d51f58341fe56f5b63984f88cdf99da0..6ec335f7560f174cf205b1f814fc7a1438a35e6c 100644 (file)
@@ -2,14 +2,14 @@ from sage.matrix.constructor import matrix
 from sage.categories.all import FreeModules
 from sage.categories.map import Map
 
-class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
+class FiniteDimensionalEJAOperator(Map):
     r"""
     An operator between two finite-dimensional Euclidean Jordan algebras.
 
     SETUP::
 
         sage: from mjo.eja.eja_algebra import HadamardEJA
-        sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+        sage: from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
 
     EXAMPLES:
 
@@ -19,12 +19,12 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
         sage: J = HadamardEJA(3)
         sage: V = VectorSpace(J.base_ring(), 3)
         sage: M = matrix.identity(J.base_ring(), 3)
-        sage: FiniteDimensionalEuclideanJordanAlgebraOperator(V,J,M)
+        sage: FiniteDimensionalEJAOperator(V,J,M)
         Traceback (most recent call last):
         ...
         TypeError: domain must be a finite-dimensional Euclidean
         Jordan algebra
-        sage: FiniteDimensionalEuclideanJordanAlgebraOperator(J,V,M)
+        sage: FiniteDimensionalEJAOperator(J,V,M)
         Traceback (most recent call last):
         ...
         TypeError: codomain must be a finite-dimensional Euclidean
@@ -33,16 +33,14 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
     """
 
     def __init__(self, domain_eja, codomain_eja, mat):
-        from mjo.eja.eja_algebra import FiniteDimensionalEuclideanJordanAlgebra
+        from mjo.eja.eja_algebra import FiniteDimensionalEJA
 
         # I guess we should check this, because otherwise you could
         # pass in pretty much anything algebraish.
-        if not isinstance(domain_eja,
-                          FiniteDimensionalEuclideanJordanAlgebra):
+        if not isinstance(domain_eja, FiniteDimensionalEJA):
             raise TypeError('domain must be a finite-dimensional '
                             'Euclidean Jordan algebra')
-        if not isinstance(codomain_eja,
-                          FiniteDimensionalEuclideanJordanAlgebra):
+        if not isinstance(codomain_eja, FiniteDimensionalEJA):
             raise TypeError('codomain must be a finite-dimensional '
                             'Euclidean Jordan algebra')
 
@@ -63,7 +61,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
         # The Map initializer will set our parent to a homset, which
         # is explicitly NOT what we want, because these ain't algebra
         # homomorphisms.
-        super(FiniteDimensionalEuclideanJordanAlgebraOperator,self).__init__(parent)
+        super().__init__(parent)
 
         # Keep a matrix around to do all of the real work. It would
         # be nice if we could use a VectorSpaceMorphism instead, but
@@ -78,7 +76,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
 
         SETUP::
 
-            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
             sage: from mjo.eja.eja_algebra import JordanSpinEJA
 
         EXAMPLES::
@@ -86,7 +84,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
             sage: J = JordanSpinEJA(3)
             sage: x = J.linear_combination(zip(J.gens(),range(len(J.gens()))))
             sage: id = identity_matrix(J.base_ring(), J.dimension())
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
+            sage: f = FiniteDimensionalEJAOperator(J,J,id)
             sage: f(x) == x
             True
 
@@ -100,7 +98,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
 
         SETUP::
 
-            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
             sage: from mjo.eja.eja_algebra import (
             ....:   JordanSpinEJA,
             ....:   RealSymmetricEJA )
@@ -111,8 +109,8 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
 
             sage: J = RealSymmetricEJA(2)
             sage: id = identity_matrix(J.base_ring(), J.dimension())
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
-            sage: g = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
+            sage: f = FiniteDimensionalEJAOperator(J,J,id)
+            sage: g = FiniteDimensionalEJAOperator(J,J,id)
             sage: f + g
             Linear operator between finite-dimensional Euclidean Jordan
             algebras represented by the matrix:
@@ -129,15 +127,15 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
             sage: id1 = identity_matrix(J1.base_ring(), 3)
             sage: J2 = JordanSpinEJA(3)
             sage: id2 = identity_matrix(J2.base_ring(), 3)
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J1,J1,id1)
-            sage: g = FiniteDimensionalEuclideanJordanAlgebraOperator(J2,J2,id2)
+            sage: f = FiniteDimensionalEJAOperator(J1,J1,id1)
+            sage: g = FiniteDimensionalEJAOperator(J2,J2,id2)
             sage: f + g
             Traceback (most recent call last):
             ...
             TypeError: unsupported operand parent(s) for +: ...
 
         """
-        return FiniteDimensionalEuclideanJordanAlgebraOperator(
+        return FiniteDimensionalEJAOperator(
                 self.domain(),
                 self.codomain(),
                 self.matrix() + other.matrix())
@@ -150,7 +148,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
 
         SETUP::
 
-            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
             sage: from mjo.eja.eja_algebra import (
             ....:   JordanSpinEJA,
             ....:   HadamardEJA,
@@ -164,12 +162,8 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
             sage: mat1 = matrix(AA, [[1,2,3],
             ....:                    [4,5,6]])
             sage: mat2 = matrix(AA, [[7,8]])
-            sage: g = FiniteDimensionalEuclideanJordanAlgebraOperator(J1,
-            ....:                                                     J2,
-            ....:                                                     mat1)
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J2,
-            ....:                                                     J3,
-            ....:                                                     mat2)
+            sage: g = FiniteDimensionalEJAOperator(J1, J2, mat1)
+            sage: f = FiniteDimensionalEJAOperator(J2, J3, mat2)
             sage: f*g
             Linear operator between finite-dimensional Euclidean Jordan
             algebras represented by the matrix:
@@ -180,7 +174,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
             Algebraic Real Field
 
         """
-        return FiniteDimensionalEuclideanJordanAlgebraOperator(
+        return FiniteDimensionalEJAOperator(
           other.domain(),
           self.codomain(),
           self.matrix()*other.matrix())
@@ -202,14 +196,14 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
 
         SETUP::
 
-            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
             sage: from mjo.eja.eja_algebra import RealSymmetricEJA
 
         EXAMPLES::
 
             sage: J = RealSymmetricEJA(2)
             sage: id = identity_matrix(J.base_ring(), J.dimension())
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
+            sage: f = FiniteDimensionalEJAOperator(J,J,id)
             sage: ~f
             Linear operator between finite-dimensional Euclidean Jordan
             algebras represented by the matrix:
@@ -220,7 +214,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
             Codomain: Euclidean Jordan algebra of dimension 3 over...
 
         """
-        return FiniteDimensionalEuclideanJordanAlgebraOperator(
+        return FiniteDimensionalEJAOperator(
                 self.codomain(),
                 self.domain(),
                 ~self.matrix())
@@ -237,7 +231,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
 
         SETUP::
 
-            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
             sage: from mjo.eja.eja_algebra import RealSymmetricEJA
 
         EXAMPLES:
@@ -267,7 +261,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
         """
         try:
             if other in self.codomain().base_ring():
-                return FiniteDimensionalEuclideanJordanAlgebraOperator(
+                return FiniteDimensionalEJAOperator(
                     self.domain(),
                     self.codomain(),
                     self.matrix()*other)
@@ -278,7 +272,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
 
         # This should eventually delegate to _composition_ after performing
         # some sanity checks for us.
-        mor = super(FiniteDimensionalEuclideanJordanAlgebraOperator,self)
+        mor = super(FiniteDimensionalEJAOperator,self)
         return mor.__mul__(other)
 
 
@@ -288,14 +282,14 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
 
         SETUP::
 
-            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
             sage: from mjo.eja.eja_algebra import RealSymmetricEJA
 
         EXAMPLES::
 
             sage: J = RealSymmetricEJA(2)
             sage: id = identity_matrix(J.base_ring(), J.dimension())
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
+            sage: f = FiniteDimensionalEJAOperator(J,J,id)
             sage: -f
             Linear operator between finite-dimensional Euclidean Jordan
             algebras represented by the matrix:
@@ -306,7 +300,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
             Codomain: Euclidean Jordan algebra of dimension 3 over...
 
         """
-        return FiniteDimensionalEuclideanJordanAlgebraOperator(
+        return FiniteDimensionalEJAOperator(
                 self.domain(),
                 self.codomain(),
                 -self.matrix())
@@ -318,7 +312,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
 
         SETUP::
 
-            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
             sage: from mjo.eja.eja_algebra import RealSymmetricEJA
 
         TESTS:
@@ -328,7 +322,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
 
             sage: J = RealSymmetricEJA(2)
             sage: id = identity_matrix(J.base_ring(), J.dimension())
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
+            sage: f = FiniteDimensionalEJAOperator(J,J,id)
             sage: f^0 + f^1 + f^2
             Linear operator between finite-dimensional Euclidean Jordan
             algebras represented by the matrix:
@@ -350,7 +344,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
         else:
             mat = self.matrix()**n
 
-        return FiniteDimensionalEuclideanJordanAlgebraOperator(
+        return FiniteDimensionalEJAOperator(
                  self.domain(),
                  self.codomain(),
                  mat)
@@ -364,14 +358,14 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
 
         SETUP::
 
-            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
             sage: from mjo.eja.eja_algebra import JordanSpinEJA
 
         EXAMPLES::
 
             sage: J = JordanSpinEJA(2)
             sage: id = identity_matrix(J.base_ring(), J.dimension())
-            sage: FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
+            sage: FiniteDimensionalEJAOperator(J,J,id)
             Linear operator between finite-dimensional Euclidean Jordan
             algebras represented by the matrix:
             [1 0]
@@ -398,14 +392,14 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
 
         SETUP::
 
-            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
             sage: from mjo.eja.eja_algebra import RealSymmetricEJA
 
         EXAMPLES::
 
             sage: J = RealSymmetricEJA(2)
             sage: id = identity_matrix(J.base_ring(),J.dimension())
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
+            sage: f = FiniteDimensionalEJAOperator(J,J,id)
             sage: f - (f*2)
             Linear operator between finite-dimensional Euclidean Jordan
             algebras represented by the matrix:
@@ -449,7 +443,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
 
         SETUP::
 
-            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
             sage: from mjo.eja.eja_algebra import (random_eja,
             ....:                                  JordanSpinEJA,
             ....:                                  RealSymmetricEJA)
@@ -462,13 +456,13 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
             sage: M = matrix(R, [ [0, 0],
             ....:                 [0, 0],
             ....:                 [0, 0] ])
-            sage: L = FiniteDimensionalEuclideanJordanAlgebraOperator(J1,J2,M)
+            sage: L = FiniteDimensionalEJAOperator(J1,J2,M)
             sage: L.is_zero()
             True
             sage: M = matrix(R, [ [0, 0],
             ....:                 [0, 1],
             ....:                 [0, 0] ])
-            sage: L = FiniteDimensionalEuclideanJordanAlgebraOperator(J1,J2,M)
+            sage: L = FiniteDimensionalEJAOperator(J1,J2,M)
             sage: L.is_zero()
             False
 
@@ -591,14 +585,14 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
 
         SETUP::
 
-            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
             sage: from mjo.eja.eja_algebra import RealSymmetricEJA
 
         EXAMPLES::
 
             sage: J = RealSymmetricEJA(2)
             sage: mat = matrix(J.base_ring(), J.dimension(), range(9))
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,mat)
+            sage: f = FiniteDimensionalEJAOperator(J,J,mat)
             sage: f.matrix()
             [0 1 2]
             [3 4 5]
@@ -615,7 +609,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
 
         SETUP::
 
-            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
             sage: from mjo.eja.eja_algebra import RealSymmetricEJA
 
         EXAMPLES::
@@ -680,7 +674,7 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
             # for the spectral theorem to work.
             us[i] = us[i]/us[i].norm()
             mat = us[i].column()*us[i].row()
-            Pi = FiniteDimensionalEuclideanJordanAlgebraOperator(
+            Pi = FiniteDimensionalEJAOperator(
                    self.domain(),
                    self.codomain(),
                    mat)
index e7308ea34b9a36aef09a84069a1289e072487ec7..3eee24866216ca84aa8acf2484e07d01d6cad019 100644 (file)
@@ -1,9 +1,9 @@
 from sage.matrix.constructor import matrix
 
-from mjo.eja.eja_algebra import FiniteDimensionalEuclideanJordanAlgebra
-from mjo.eja.eja_element import FiniteDimensionalEuclideanJordanAlgebraElement
+from mjo.eja.eja_algebra import FiniteDimensionalEJA
+from mjo.eja.eja_element import FiniteDimensionalEJAElement
 
-class FiniteDimensionalEuclideanJordanSubalgebraElement(FiniteDimensionalEuclideanJordanAlgebraElement):
+class FiniteDimensionalEJASubalgebraElement(FiniteDimensionalEJAElement):
     """
     SETUP::
 
@@ -83,23 +83,12 @@ class FiniteDimensionalEuclideanJordanSubalgebraElement(FiniteDimensionalEuclide
             True
 
         """
-        # As with the _element_constructor_() method on the
-        # algebra... even in a subspace of a subspace, the basis
-        # elements belong to the ambient space. As a result, only one
-        # level of coordinate_vector() is needed, regardless of how
-        # deeply we're nested.
-        W = self.parent().vector_space()
-        V = self.parent().superalgebra().vector_space()
+        return self._superalgebra(self.to_matrix())
 
-        # Multiply on the left because basis_matrix() is row-wise.
-        ambient_coords = self.to_vector()*W.basis_matrix()
-        V_coords = V.coordinate_vector(ambient_coords)
-        return self.parent().superalgebra().from_vector(V_coords)
 
 
 
-
-class FiniteDimensionalEuclideanJordanSubalgebra(FiniteDimensionalEuclideanJordanAlgebra):
+class FiniteDimensionalEJASubalgebra(FiniteDimensionalEJA):
     """
     A subalgebra of an EJA with a given basis.
 
@@ -108,7 +97,7 @@ class FiniteDimensionalEuclideanJordanSubalgebra(FiniteDimensionalEuclideanJorda
         sage: from mjo.eja.eja_algebra import (ComplexHermitianEJA,
         ....:                                  JordanSpinEJA,
         ....:                                  RealSymmetricEJA)
-        sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanSubalgebra
+        sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEJASubalgebra
 
     EXAMPLES:
 
@@ -120,11 +109,11 @@ class FiniteDimensionalEuclideanJordanSubalgebra(FiniteDimensionalEuclideanJorda
         ....:                    [0,0] ])
         sage: E22 = matrix(AA, [ [0,0],
         ....:                    [0,1] ])
-        sage: K1 = FiniteDimensionalEuclideanJordanSubalgebra(J, (J(E11),))
+        sage: K1 = FiniteDimensionalEJASubalgebra(J, (J(E11),))
         sage: K1.one().to_matrix()
         [1 0]
         [0 0]
-        sage: K2 = FiniteDimensionalEuclideanJordanSubalgebra(J, (J(E22),))
+        sage: K2 = FiniteDimensionalEJASubalgebra(J, (J(E22),))
         sage: K2.one().to_matrix()
         [0 0]
         [0 1]
@@ -151,12 +140,10 @@ class FiniteDimensionalEuclideanJordanSubalgebra(FiniteDimensionalEuclideanJorda
         1
 
     """
-    def __init__(self, superalgebra, basis, category=None, check_axioms=True):
+    def __init__(self, superalgebra, basis, **kwargs):
         self._superalgebra = superalgebra
         V = self._superalgebra.vector_space()
         field = self._superalgebra.base_ring()
-        if category is None:
-            category = self._superalgebra.category()
 
         # A half-assed attempt to ensure that we don't collide with
         # the superalgebra's prefix (ignoring the fact that there
@@ -170,52 +157,20 @@ class FiniteDimensionalEuclideanJordanSubalgebra(FiniteDimensionalEuclideanJorda
         except ValueError:
             prefix = prefixen[0]
 
-        # If our superalgebra is a subalgebra of something else, then
-        # these vectors won't have the right coordinates for
-        # V.span_of_basis() unless we use V.from_vector() on them.
-        W = V.span_of_basis( (V.from_vector(b.to_vector()) for b in basis),
-                             check=check_axioms)
-
-        n = len(basis)
-        if check_axioms:
-            # The tables are square if we're verifying that they
-            # are commutative.
-            mult_table = [[W.zero() for j in range(n)] for i in range(n)]
-            ip_table = [ [ self._superalgebra.inner_product(basis[i],basis[j])
-                           for j in range(n) ]
-                         for i in range(n) ]
-        else:
-            mult_table = [[W.zero() for j in range(i+1)] for i in range(n)]
-            ip_table = [ [ self._superalgebra.inner_product(basis[i],basis[j])
-                           for j in range(i+1) ]
-                         for i in range(n) ]
-
-        for i in range(n):
-            for j in range(i+1):
-                product = basis[i]*basis[j]
-                # product.to_vector() might live in a vector subspace
-                # if our parent algebra is already a subalgebra. We
-                # use V.from_vector() to make it "the right size" in
-                # that case.
-                product_vector = V.from_vector(product.to_vector())
-                mult_table[i][j] = W.coordinate_vector(product_vector)
-                if check_axioms:
-                    mult_table[j][i] = mult_table[i][j]
-
+        # The superalgebra constructor expects these to be in original matrix
+        # form, not algebra-element form.
         matrix_basis = tuple( b.to_matrix() for b in basis )
+        def jordan_product(x,y):
+            return (self._superalgebra(x)*self._superalgebra(y)).to_matrix()
 
+        def inner_product(x,y):
+            return self._superalgebra(x).inner_product(self._superalgebra(y))
 
-        self._vector_space = W
-
-        fdeja = super(FiniteDimensionalEuclideanJordanSubalgebra, self)
-        fdeja.__init__(field,
-                       mult_table,
-                       ip_table,
-                       prefix=prefix,
-                       category=category,
-                       matrix_basis=matrix_basis,
-                       check_field=False,
-                       check_axioms=check_axioms)
+        super().__init__(matrix_basis,
+                         jordan_product,
+                         inner_product,
+                         prefix=prefix,
+                         **kwargs)
 
 
 
@@ -228,7 +183,7 @@ class FiniteDimensionalEuclideanJordanSubalgebra(FiniteDimensionalEuclideanJorda
         SETUP::
 
             sage: from mjo.eja.eja_algebra import RealSymmetricEJA
-            sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanSubalgebra
+            sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEJASubalgebra
 
         EXAMPLES::
 
@@ -238,7 +193,7 @@ class FiniteDimensionalEuclideanJordanSubalgebra(FiniteDimensionalEuclideanJorda
             ....:                  [1,0,0] ])
             sage: x = J(X)
             sage: basis = ( x, x^2 ) # x^2 is the identity matrix
-            sage: K = FiniteDimensionalEuclideanJordanSubalgebra(J, basis)
+            sage: K = FiniteDimensionalEJASubalgebra(J, basis, orthonormalize=False)
             sage: K(J.one())
             f1
             sage: K(J.one() + x)
@@ -247,23 +202,10 @@ class FiniteDimensionalEuclideanJordanSubalgebra(FiniteDimensionalEuclideanJorda
         ::
 
         """
-        if elt not in self.superalgebra():
-            raise ValueError("not an element of this subalgebra")
-
-        # The extra hackery is because foo.to_vector() might not live
-        # in foo.parent().vector_space()! Subspaces of subspaces still
-        # have user bases in the ambient space, though, so only one
-        # level of coordinate_vector() is needed. In other words, if V
-        # is itself a subspace, the basis elements for W will be of
-        # the same length as the basis elements for V -- namely
-        # whatever the dimension of the ambient (parent of V?) space is.
-        V = self.superalgebra().vector_space()
-        W = self.vector_space()
-
-        # Multiply on the left because basis_matrix() is row-wise.
-        ambient_coords = elt.to_vector()*V.basis_matrix()
-        W_coords = W.coordinate_vector(ambient_coords)
-        return self.from_vector(W_coords)
+        if elt in self.superalgebra():
+            return super()._element_constructor_(elt.to_matrix())
+        else:
+            return super()._element_constructor_(elt)
 
 
 
@@ -286,38 +228,4 @@ class FiniteDimensionalEuclideanJordanSubalgebra(FiniteDimensionalEuclideanJorda
         return self._superalgebra
 
 
-    def vector_space(self):
-        """
-        SETUP::
-
-            sage: from mjo.eja.eja_algebra import RealSymmetricEJA
-            sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanSubalgebra
-
-        EXAMPLES::
-
-            sage: J = RealSymmetricEJA(3)
-            sage: E11 = matrix(ZZ, [ [1,0,0],
-            ....:                    [0,0,0],
-            ....:                    [0,0,0] ])
-            sage: E22 = matrix(ZZ, [ [0,0,0],
-            ....:                    [0,1,0],
-            ....:                    [0,0,0] ])
-            sage: b1 = J(E11)
-            sage: b2 = J(E22)
-            sage: basis = (b1, b2)
-            sage: K = FiniteDimensionalEuclideanJordanSubalgebra(J,basis)
-            sage: K.vector_space()
-            Vector space of degree 6 and dimension 2 over...
-            User basis matrix:
-            [1 0 0 0 0 0]
-            [0 0 1 0 0 0]
-            sage: b1.to_vector()
-            (1, 0, 0, 0, 0, 0)
-            sage: b2.to_vector()
-            (0, 0, 1, 0, 0, 0)
-
-        """
-        return self._vector_space
-
-
-    Element = FiniteDimensionalEuclideanJordanSubalgebraElement
+    Element = FiniteDimensionalEJASubalgebraElement