+class RationalBasisEuclideanJordanAlgebraNg(FiniteDimensionalEuclideanJordanAlgebra):
+ r"""
+ New class for algebras whose supplied basis elements have all rational entries.
+
+ SETUP::
+
+ sage: from mjo.eja.eja_algebra import BilinearFormEJA
+
+ EXAMPLES:
+
+ The supplied basis is orthonormalized by default::
+
+ sage: B = matrix(QQ, [[1, 0, 0], [0, 25, -32], [0, -32, 41]])
+ sage: J = BilinearFormEJA(B)
+ sage: J.matrix_basis()
+ (
+ [1] [ 0] [ 0]
+ [0] [1/5] [32/5]
+ [0], [ 0], [ 5]
+ )
+
+ """
+ def __init__(self,
+ field,
+ basis,
+ jordan_product,
+ inner_product,
+ orthonormalize=True,
+ prefix='e',
+ category=None,
+ check_field=True,
+ check_axioms=True):
+
+ 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
+ vector_basis = tuple( map(_mat2vec,basis) )
+ degree = basis[0].nrows()**2
+ else:
+ degree = basis[0].degree()
+
+ V = VectorSpace(field, degree)
+
+ # If we were asked to orthonormalize, and if the orthonormal
+ # basis is different from the given one, then we also want to
+ # compute multiplication and inner-product tables for the
+ # deorthonormalized basis. These can be used later to
+ # construct a deorthonormalized copy of this algebra over QQ
+ # in which several operations are much faster.
+ self._deortho_multiplication_table = None
+ self._deortho_inner_product_table = None
+
+ if orthonormalize:
+ from mjo.eja.eja_utils import gram_schmidt
+ vector_basis = gram_schmidt(vector_basis, inner_product)
+ W = V.span_of_basis( vector_basis )
+
+ # Normalize the "matrix" basis, too!
+ basis = vector_basis
+
+ if basis_is_matrices:
+ from mjo.eja.eja_utils import _vec2mat
+ basis = tuple( map(_vec2mat,basis) )
+
+ W = V.span_of_basis( vector_basis )
+
+ mult_table = [ [0 for i in range(n)] for j in range(n) ]
+ ip_table = [ [0 for i in range(n)] for j 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
+ mult_table[j][i] = elt
+ ip_table[i][j] = ip
+ 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)