X-Git-Url: http://gitweb.michael.orlitzky.com/?p=sage.d.git;a=blobdiff_plain;f=mjo%2Feja%2Feja_algebra.py;h=d3eac4f6d3bfbad50f6bbc4b371aaa9d39f8859b;hp=7ab32e25219e5f35d1d99386f2c69a67ffb034e5;hb=HEAD;hpb=1bef02ef2a4f20d65849d2f2ec9603620f53daef diff --git a/mjo/eja/eja_algebra.py b/mjo/eja/eja_algebra.py index 7ab32e2..adcc343 100644 --- a/mjo/eja/eja_algebra.py +++ b/mjo/eja/eja_algebra.py @@ -1,4 +1,4 @@ -""" +r""" Representations and constructions for Euclidean Jordan algebras. A Euclidean Jordan algebra is a Jordan algebra that has some @@ -34,12 +34,13 @@ for these simple algebras: * :class:`QuaternionHermitianEJA` * :class:`OctonionHermitianEJA` -In addition to these, we provide two other example constructions, +In addition to these, we provide a few other example constructions, * :class:`JordanSpinEJA` * :class:`HadamardEJA` * :class:`AlbertEJA` * :class:`TrivialEJA` + * :class:`ComplexSkewSymmetricEJA` The Jordan spin algebra is a bilinear form algebra where the bilinear form is the identity. The Hadamard EJA is simply a Cartesian product @@ -71,18 +72,18 @@ matrix, whereas the inner product must return a scalar. Our basis for the one-by-one matrices is of course the set consisting of a single matrix with its sole entry non-zero:: - sage: from mjo.eja.eja_algebra import FiniteDimensionalEJA + sage: from mjo.eja.eja_algebra import EJA sage: jp = lambda X,Y: X*Y sage: ip = lambda X,Y: X[0,0]*Y[0,0] sage: b1 = matrix(AA, [[1]]) - sage: J1 = FiniteDimensionalEJA((b1,), jp, ip) + sage: J1 = EJA((b1,), jp, ip) sage: J1 Euclidean Jordan algebra of dimension 1 over Algebraic Real Field In fact, any positive scalar multiple of that inner-product would work:: sage: ip2 = lambda X,Y: 16*ip(X,Y) - sage: J2 = FiniteDimensionalEJA((b1,), jp, ip2) + sage: J2 = EJA((b1,), jp, ip2) sage: J2 Euclidean Jordan algebra of dimension 1 over Algebraic Real Field @@ -90,7 +91,7 @@ But beware that your basis will be orthonormalized _with respect to the given inner-product_ unless you pass ``orthonormalize=False`` to the constructor. For example:: - sage: J3 = FiniteDimensionalEJA((b1,), jp, ip2, orthonormalize=False) + sage: J3 = EJA((b1,), jp, ip2, orthonormalize=False) sage: J3 Euclidean Jordan algebra of dimension 1 over Algebraic Real Field @@ -117,7 +118,7 @@ Another option for your basis is to use elemebts of a sage: from mjo.matrix_algebra import MatrixAlgebra sage: A = MatrixAlgebra(1,AA,AA) - sage: J4 = FiniteDimensionalEJA(A.gens(), jp, ip) + sage: J4 = EJA(A.gens(), jp, ip) sage: J4 Euclidean Jordan algebra of dimension 1 over Algebraic Real Field sage: J4.basis()[0].to_matrix() @@ -167,8 +168,8 @@ from sage.rings.all import (ZZ, QQ, AA, QQbar, RR, RLF, CLF, PolynomialRing, QuadraticField) from mjo.eja.eja_element import (CartesianProductEJAElement, - FiniteDimensionalEJAElement) -from mjo.eja.eja_operator import FiniteDimensionalEJAOperator + EJAElement) +from mjo.eja.eja_operator import EJAOperator from mjo.eja.eja_utils import _all2list def EuclideanJordanAlgebras(field): @@ -182,7 +183,7 @@ def EuclideanJordanAlgebras(field): category = category.WithBasis().Unital().Commutative() return category -class FiniteDimensionalEJA(CombinatorialFreeModule): +class EJA(CombinatorialFreeModule): r""" A finite-dimensional Euclidean Jordan algebra. @@ -237,7 +238,7 @@ class FiniteDimensionalEJA(CombinatorialFreeModule): sage: J.subalgebra(basis, orthonormalize=False).is_associative() True """ - Element = FiniteDimensionalEJAElement + Element = EJAElement @staticmethod def _check_input_field(field): @@ -1193,7 +1194,7 @@ class FiniteDimensionalEJA(CombinatorialFreeModule): sage: x = J.random_element() sage: J.one()*x == x and x*J.one() == x True - sage: A = x.subalgebra_generated_by() + sage: A = x.subalgebra_generated_by(orthonormalize=False) sage: y = A.random_element() sage: A.one()*y == y and y*A.one() == y True @@ -1219,7 +1220,7 @@ class FiniteDimensionalEJA(CombinatorialFreeModule): sage: actual == expected True sage: x = J.random_element() - sage: A = x.subalgebra_generated_by() + sage: A = x.subalgebra_generated_by(orthonormalize=False) sage: actual = A.one().operator().matrix() sage: expected = matrix.identity(A.base_ring(), A.dimension()) sage: actual == expected @@ -1447,26 +1448,13 @@ class FiniteDimensionalEJA(CombinatorialFreeModule): # For a general base ring... maybe we can trust this to do the # right thing? Unlikely, but. V = self.vector_space() - v = V.random_element() - - if self.base_ring() is AA: - # The "random element" method of the algebraic reals is - # stupid at the moment, and only returns integers between - # -2 and 2, inclusive: - # - # https://trac.sagemath.org/ticket/30875 - # - # Instead, we implement our own "random vector" method, - # and then coerce that into the algebra. We use the vector - # space degree here instead of the dimension because a - # subalgebra could (for example) be spanned by only two - # vectors, each with five coordinates. We need to - # generate all five coordinates. - if thorough: - v *= QQbar.random_element().real() - else: - v *= QQ.random_element() + if self.base_ring() is AA and not thorough: + # Now that AA generates actually random random elements + # (post Trac 30875), we only need to de-thorough the + # randomness when asked to. + V = V.change_ring(QQ) + v = V.random_element() return self.from_vector(V.coordinate_vector(v)) def random_elements(self, count, thorough=False): @@ -1686,8 +1674,8 @@ class FiniteDimensionalEJA(CombinatorialFreeModule): r""" Create a subalgebra of this algebra from the given basis. """ - from mjo.eja.eja_subalgebra import FiniteDimensionalEJASubalgebra - return FiniteDimensionalEJASubalgebra(self, basis, **kwargs) + from mjo.eja.eja_subalgebra import EJASubalgebra + return EJASubalgebra(self, basis, **kwargs) def vector_space(self): @@ -1709,7 +1697,7 @@ class FiniteDimensionalEJA(CombinatorialFreeModule): -class RationalBasisEJA(FiniteDimensionalEJA): +class RationalBasisEJA(EJA): r""" Algebras whose supplied basis elements have all rational entries. @@ -1764,7 +1752,7 @@ class RationalBasisEJA(FiniteDimensionalEJA): # 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 = FiniteDimensionalEJA( + self._rational_algebra = EJA( basis, jordan_product, inner_product, @@ -1812,14 +1800,13 @@ class RationalBasisEJA(FiniteDimensionalEJA): # Bypass the hijinks if they won't benefit us. 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. - # Then, change back from QQ to our real base ring + # Do the computation over the rationals. a = ( a_i.change_ring(self.base_ring()) for a_i in self.rational_algebra()._charpoly_coefficients() ) - # Otherwise, convert the coordinate variables back to the - # deorthonormalized ones. + # Convert our coordinate variables into deorthonormalized ones + # and substitute them into the deorthonormalized charpoly + # coefficients. R = self.coordinate_polynomial_ring() from sage.modules.free_module_element import vector X = vector(R, R.gens()) @@ -1828,7 +1815,7 @@ class RationalBasisEJA(FiniteDimensionalEJA): 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 ConcreteEJA(FiniteDimensionalEJA): +class ConcreteEJA(EJA): r""" A class for the Euclidean Jordan algebras that we know by name. @@ -1929,7 +1916,7 @@ class ConcreteEJA(FiniteDimensionalEJA): return eja_class.random_instance(max_dimension, *args, **kwargs) -class HermitianMatrixEJA(FiniteDimensionalEJA): +class HermitianMatrixEJA(EJA): @staticmethod def _denormalized_basis(A): """ @@ -2200,15 +2187,6 @@ class ComplexHermitianEJA(HermitianMatrixEJA, RationalBasisEJA, ConcreteEJA): ... TypeError: Illegal initializer for algebraic number - This causes the following error when we try to scale a matrix of - complex numbers by an inexact real number:: - - sage: ComplexHermitianEJA(2,field=RR) - Traceback (most recent call last): - ... - TypeError: Unable to coerce entries (=(1.00000000000000, - -0.000000000000000)) to coefficients in Algebraic Real Field - TESTS: The dimension of this algebra is `n^2`:: @@ -2364,7 +2342,7 @@ class OctonionHermitianEJA(HermitianMatrixEJA, RationalBasisEJA, ConcreteEJA): r""" SETUP:: - sage: from mjo.eja.eja_algebra import (FiniteDimensionalEJA, + sage: from mjo.eja.eja_algebra import (EJA, ....: OctonionHermitianEJA) sage: from mjo.hurwitz import Octonions, OctonionMatrixAlgebra @@ -2386,7 +2364,7 @@ class OctonionHermitianEJA(HermitianMatrixEJA, RationalBasisEJA, ConcreteEJA): sage: basis = (b[0] + b[9],) + b[1:9] + (b[0] - b[9],) sage: jp = OctonionHermitianEJA.jordan_product sage: ip = OctonionHermitianEJA.trace_inner_product - sage: J = FiniteDimensionalEJA(basis, + sage: J = EJA(basis, ....: jp, ....: ip, ....: field=QQ, @@ -2450,7 +2428,7 @@ class OctonionHermitianEJA(HermitianMatrixEJA, RationalBasisEJA, ConcreteEJA): @staticmethod def _max_random_instance_size(max_dimension): r""" - The maximum rank of a random QuaternionHermitianEJA. + The maximum rank of a random OctonionHermitianEJA. """ # There's certainly a formula for this, but with only four # cases to worry about, I'm not that motivated to derive it. @@ -2936,7 +2914,7 @@ class TrivialEJA(RationalBasisEJA, ConcreteEJA): return cls(**kwargs) -class CartesianProductEJA(FiniteDimensionalEJA): +class CartesianProductEJA(EJA): r""" The external (orthogonal) direct sum of two or more Euclidean Jordan algebras. Every Euclidean Jordan algebra decomposes into an @@ -3327,7 +3305,7 @@ class CartesianProductEJA(FiniteDimensionalEJA): Pi = self._module_morphism(lambda j: Ji.monomial(j - offset), codomain=Ji) - return FiniteDimensionalEJAOperator(self,Ji,Pi.matrix()) + return EJAOperator(self,Ji,Pi.matrix()) @cached_method def cartesian_embedding(self, i): @@ -3435,11 +3413,39 @@ class CartesianProductEJA(FiniteDimensionalEJA): Ji = self.cartesian_factor(i) Ei = Ji._module_morphism(lambda j: self.monomial(j + offset), codomain=self) - return FiniteDimensionalEJAOperator(Ji,self,Ei.matrix()) + return EJAOperator(Ji,self,Ei.matrix()) + def subalgebra(self, basis, **kwargs): + r""" + Create a subalgebra of this algebra from the given basis. + + Only overridden to allow us to use a special Cartesian product + subalgebra class. + + SETUP:: + + sage: from mjo.eja.eja_algebra import (HadamardEJA, + ....: QuaternionHermitianEJA) + + EXAMPLES: + + Subalgebras of Cartesian product EJAs have a different class + than those of non-Cartesian-product EJAs:: + + sage: J1 = HadamardEJA(2,field=QQ,orthonormalize=False) + sage: J2 = QuaternionHermitianEJA(0,field=QQ,orthonormalize=False) + sage: J = cartesian_product([J1,J2]) + sage: K1 = J1.subalgebra((J1.one(),), orthonormalize=False) + sage: K = J.subalgebra((J.one(),), orthonormalize=False) + sage: K1.__class__ is K.__class__ + False + + """ + from mjo.eja.eja_subalgebra import CartesianProductEJASubalgebra + return CartesianProductEJASubalgebra(self, basis, **kwargs) -FiniteDimensionalEJA.CartesianProduct = CartesianProductEJA +EJA.CartesianProduct = CartesianProductEJA class RationalBasisCartesianProductEJA(CartesianProductEJA, RationalBasisEJA): @@ -3449,7 +3455,7 @@ class RationalBasisCartesianProductEJA(CartesianProductEJA, SETUP:: - sage: from mjo.eja.eja_algebra import (FiniteDimensionalEJA, + sage: from mjo.eja.eja_algebra import (EJA, ....: HadamardEJA, ....: JordanSpinEJA, ....: RealSymmetricEJA) @@ -3479,7 +3485,7 @@ class RationalBasisCartesianProductEJA(CartesianProductEJA, sage: jp = lambda X,Y: X*Y sage: ip = lambda X,Y: X[0,0]*Y[0,0] sage: b1 = matrix(QQ, [[1]]) - sage: J2 = FiniteDimensionalEJA((b1,), jp, ip) + sage: J2 = EJA((b1,), jp, ip) sage: cartesian_product([J2,J1]) # factor one not RationalBasisEJA Euclidean Jordan algebra of dimension 1 over Algebraic Real Field (+) Euclidean Jordan algebra of dimension 2 over Algebraic @@ -3558,7 +3564,7 @@ class ComplexSkewSymmetricEJA(RationalBasisEJA, ConcreteEJA): sage: from mjo.eja.eja_algebra import (ComplexSkewSymmetricEJA, ....: QuaternionHermitianEJA) - sage: from mjo.eja.eja_operator import FiniteDimensionalEJAOperator + sage: from mjo.eja.eja_operator import EJAOperator EXAMPLES: @@ -3567,7 +3573,7 @@ class ComplexSkewSymmetricEJA(RationalBasisEJA, ConcreteEJA): sage: J = ComplexSkewSymmetricEJA(2, field=QQ, orthonormalize=False) sage: K = QuaternionHermitianEJA(2, field=QQ, orthonormalize=False) sage: jordan_isom_matrix = matrix.diagonal(QQ,[-1,1,1,1,1,-1]) - sage: phi = FiniteDimensionalEJAOperator(J,K,jordan_isom_matrix) + sage: phi = EJAOperator(J,K,jordan_isom_matrix) sage: all( phi(x*y) == phi(x)*phi(y) ....: for x in J.gens() ....: for y in J.gens() )