X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Feja%2Feja_algebra.py;h=c40c8be4c371255f9bc174f99862ef0a7a204555;hb=8c7f591dbf56e96a29b347017d061b244dd267a5;hp=222b12c9ea0074792c807471eb546d1c45282e71;hpb=8adc54235f68f871cdbb66e8854a5a50ce4ad751;p=sage.d.git diff --git a/mjo/eja/eja_algebra.py b/mjo/eja/eja_algebra.py index 222b12c..c40c8be 100644 --- a/mjo/eja/eja_algebra.py +++ b/mjo/eja/eja_algebra.py @@ -588,6 +588,16 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule): sage: actual == expected True + Ensure that the cached unit element (often precomputed by + hand) agrees with the computed one:: + + sage: set_random_seed() + sage: J = random_eja() + sage: cached = J.one() + sage: J.one.clear_cache() + sage: J.one() == cached + True + """ # We can brute-force compute the matrices of the operators # that correspond to the basis elements of this algebra. @@ -1108,7 +1118,8 @@ class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra): # time to ensure that it isn't a generator expression. basis = tuple(basis) - if len(basis) > 1 and normalize_basis: + algebra_dim = len(basis) + if algebra_dim > 1 and normalize_basis: # We'll need sqrt(2) to normalize the basis, and this # winds up in the multiplication table, so the whole # algebra needs to be over the field extension. @@ -1129,6 +1140,14 @@ class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra): natural_basis=basis, **kwargs) + if algebra_dim == 0: + self.one.set_cache(self.zero()) + else: + n = basis[0].nrows() + # The identity wrt (A,B) -> (AB + BA)/2 is independent of the + # details of this algebra. + self.one.set_cache(self(matrix.identity(field,n))) + @cached_method def _charpoly_coefficients(self): @@ -2052,6 +2071,11 @@ class HadamardEJA(RationalBasisEuclideanJordanAlgebra): **kwargs) self.rank.set_cache(n) + if n == 0: + self.one.set_cache( self.zero() ) + else: + self.one.set_cache( sum(self.gens()) ) + @staticmethod def _max_random_instance_size(): return 5 @@ -2085,10 +2109,15 @@ class BilinearFormEJA(RationalBasisEuclideanJordanAlgebra): 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 = - (x0*y0 + , x0*y_bar + y0*x_bar)`` where ``B`` is a - symmetric positive-definite "bilinear form" matrix. It has - dimension `n` over the reals, and reduces to the ``JordanSpinEJA`` - when ``B`` is the identity matrix of order ``n-1``. + (,y_bar>, x0*y_bar + y0*x_bar)`` where `B = 1 \times B22` is + a symmetric positive-definite "bilinear form" matrix. Its + dimension is the size of `B`, and it has rank two in dimensions + larger than two. It reduces to the ``JordanSpinEJA`` when `B` is + the identity matrix of order ``n``. + + We insist that the one-by-one upper-left identity block of `B` be + passed in as well so that we can be passed a matrix of size zero + to construct a trivial algebra. SETUP:: @@ -2100,16 +2129,32 @@ class BilinearFormEJA(RationalBasisEuclideanJordanAlgebra): When no bilinear form is specified, the identity matrix is used, and the resulting algebra is the Jordan spin algebra:: - sage: J0 = BilinearFormEJA(3) + sage: B = matrix.identity(AA,3) + sage: J0 = BilinearFormEJA(B) sage: J1 = JordanSpinEJA(3) sage: J0.multiplication_table() == J0.multiplication_table() True + An error is raised if the matrix `B` does not correspond to a + positive-definite bilinear form:: + + sage: B = matrix.random(QQ,2,3) + sage: J = BilinearFormEJA(B) + Traceback (most recent call last): + ... + ValueError: bilinear form is not positive-definite + sage: B = matrix.zero(QQ,3) + sage: J = BilinearFormEJA(B) + Traceback (most recent call last): + ... + ValueError: bilinear form is not positive-definite + TESTS: We can create a zero-dimensional algebra:: - sage: J = BilinearFormEJA(0) + sage: B = matrix.identity(AA,0) + sage: J = BilinearFormEJA(B) sage: J.basis() Finite family {} @@ -2121,8 +2166,11 @@ class BilinearFormEJA(RationalBasisEuclideanJordanAlgebra): sage: set_random_seed() sage: n = ZZ.random_element(5) sage: M = matrix.random(QQ, max(0,n-1), algorithm='unimodular') - sage: B = M.transpose()*M - sage: J = BilinearFormEJA(n, B=B) + sage: B11 = matrix.identity(QQ,1) + sage: B22 = M.transpose()*M + sage: B = block_matrix(2,2,[ [B11,0 ], + ....: [0, B22 ] ]) + sage: J = BilinearFormEJA(B) sage: eis = VectorSpace(M.base_ring(), M.ncols()).basis() sage: V = J.vector_space() sage: sis = [ J.from_vector(V([0] + (M.inverse()*ei).list())) @@ -2136,11 +2184,12 @@ class BilinearFormEJA(RationalBasisEuclideanJordanAlgebra): sage: actual == expected True """ - def __init__(self, n, field=AA, B=None, **kwargs): - if B is None: - self._B = matrix.identity(field, max(0,n-1)) - else: - self._B = B + def __init__(self, B, field=AA, **kwargs): + self._B = B + n = B.nrows() + + if not B.is_positive_definite(): + raise ValueError("bilinear form is not positive-definite") V = VectorSpace(field, n) mult_table = [[V.zero() for j in range(n)] for i in range(n)] @@ -2152,7 +2201,7 @@ class BilinearFormEJA(RationalBasisEuclideanJordanAlgebra): xbar = x[1:] y0 = y[0] ybar = y[1:] - z0 = x0*y0 + (self._B*xbar).inner_product(ybar) + z0 = (B*x).inner_product(y) zbar = y0*xbar + x0*ybar z = V([z0] + zbar.list()) mult_table[i][j] = z @@ -2166,10 +2215,39 @@ class BilinearFormEJA(RationalBasisEuclideanJordanAlgebra): **kwargs) self.rank.set_cache(min(n,2)) + if n == 0: + self.one.set_cache( self.zero() ) + else: + self.one.set_cache( self.monomial(0) ) + @staticmethod def _max_random_instance_size(): return 5 + @classmethod + def random_instance(cls, field=AA, **kwargs): + """ + Return a random instance of this algebra. + """ + n = ZZ.random_element(cls._max_random_instance_size() + 1) + if n.is_zero(): + B = matrix.identity(field, n) + return cls(B, field, **kwargs) + + B11 = matrix.identity(field,1) + M = matrix.random(field, n-1) + I = matrix.identity(field, n-1) + alpha = field.zero() + while alpha.is_zero(): + alpha = field.random_element().abs() + B22 = M.transpose()*M + alpha*I + + from sage.matrix.special import block_matrix + B = block_matrix(2,2, [ [B11, ZZ(0) ], + [ZZ(0), B22 ] ]) + + return cls(B, field, **kwargs) + def inner_product(self, x, y): r""" Half of the trace inner product. @@ -2189,21 +2267,15 @@ class BilinearFormEJA(RationalBasisEuclideanJordanAlgebra): paper:: sage: set_random_seed() - sage: n = ZZ.random_element(2,5) - sage: M = matrix.random(QQ, max(0,n-1), algorithm='unimodular') - sage: B = M.transpose()*M - sage: J = BilinearFormEJA(n, B=B) + sage: J = BilinearFormEJA.random_instance() + sage: n = J.dimension() sage: x = J.random_element() sage: y = J.random_element() - sage: x.inner_product(y) == (x*y).trace()/2 + sage: (n == 1) or (x.inner_product(y) == (x*y).trace()/2) True """ - xvec = x.to_vector() - xbar = xvec[1:] - yvec = y.to_vector() - ybar = yvec[1:] - return x[0]*y[0] + (self._B*xbar).inner_product(ybar) + return (self._B*x.to_vector()).inner_product(y.to_vector()) class JordanSpinEJA(BilinearFormEJA): @@ -2259,7 +2331,18 @@ class JordanSpinEJA(BilinearFormEJA): def __init__(self, n, field=AA, **kwargs): # This is a special case of the BilinearFormEJA with the identity # matrix as its bilinear form. - super(JordanSpinEJA, self).__init__(n, field, **kwargs) + B = matrix.identity(field, n) + super(JordanSpinEJA, self).__init__(B, field, **kwargs) + + @classmethod + def random_instance(cls, field=AA, **kwargs): + """ + Return a random instance of this type of algebra. + + Needed here to override the implementation for ``BilinearFormEJA``. + """ + n = ZZ.random_element(cls._max_random_instance_size() + 1) + return cls(n, field, **kwargs) class TrivialEJA(FiniteDimensionalEuclideanJordanAlgebra): @@ -2300,6 +2383,7 @@ class TrivialEJA(FiniteDimensionalEuclideanJordanAlgebra): # The rank is zero using my definition, namely the dimension of the # largest subalgebra generated by any element. self.rank.set_cache(0) + self.one.set_cache( self.zero() ) @classmethod def random_instance(cls, field=AA, **kwargs):