X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Feja%2Feuclidean_jordan_algebra.py;h=713eca534b1028dadddf4bb6e99953de0d6b1cd0;hb=f117a2240c2bb5e87cb82485db701a40d5dbad04;hp=78fa6b7c0f96725af4da2e96f09ee2d7eb5449cf;hpb=9866a99126ab5ec1e71b7a9c43ba5924ebfc6baf;p=sage.d.git diff --git a/mjo/eja/euclidean_jordan_algebra.py b/mjo/eja/euclidean_jordan_algebra.py index 78fa6b7..713eca5 100644 --- a/mjo/eja/euclidean_jordan_algebra.py +++ b/mjo/eja/euclidean_jordan_algebra.py @@ -5,13 +5,80 @@ are used in optimization, and have some additional nice methods beyond what can be supported in a general Jordan Algebra. """ -from sage.categories.magmatic_algebras import MagmaticAlgebras +from sage.categories.finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis +from sage.categories.morphism import SetMorphism from sage.structure.element import is_Matrix from sage.structure.category_object import normalize_names from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra import FiniteDimensionalAlgebra from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra_element import FiniteDimensionalAlgebraElement -from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra_morphism import FiniteDimensionalAlgebraMorphism +from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra_morphism import FiniteDimensionalAlgebraMorphism, FiniteDimensionalAlgebraHomset + + +class FiniteDimensionalEuclideanJordanAlgebraHomset(FiniteDimensionalAlgebraHomset): + + def has_coerce_map_from(self, S): + """ + EXAMPLES:: + + sage: J = RealSymmetricEJA(2) + sage: H = J.Hom(J) + sage: H.has_coerce_map_from(QQ) + True + + """ + try: + # The Homset classes override has_coerce_map_from() with + # something that crashes when it's given e.g. QQ. + if S.is_subring(self.codomain().base_ring()): + return True + except: + pclass = super(FiniteDimensionalEuclideanJordanAlgebraHomset, self) + return pclass.has_coerce_map_from(S) + + + def _coerce_map_from_(self, S): + """ + EXAMPLES:: + + sage: J = RealSymmetricEJA(2) + sage: H = J.Hom(J) + sage: H.coerce(2) + Morphism from Euclidean Jordan algebra of degree 3 over Rational + Field to Euclidean Jordan algebra of degree 3 over Rational Field + given by matrix + [2 0 0] + [0 2 0] + [0 0 2] + + """ + C = self.codomain() + R = C.base_ring() + if S.is_subring(R): + h = S.hom(self.codomain()) + return SetMorphism(Hom(S,C), lambda x: h(x).operator()) + + + def __call__(self, x): + """ + EXAMPLES:: + + sage: J = RealSymmetricEJA(2) + sage: H = J.Hom(J) + sage: H(2) + Morphism from Euclidean Jordan algebra of degree 3 over Rational + Field to Euclidean Jordan algebra of degree 3 over Rational Field + given by matrix + [2 0 0] + [0 2 0] + [0 0 2] + + """ + if x in self.base_ring(): + cols = self.domain().dimension() + rows = self.codomain().dimension() + x = x*identity_matrix(self.codomain().base_ring(), rows, cols) + return FiniteDimensionalEuclideanJordanAlgebraMorphism(self, x) class FiniteDimensionalEuclideanJordanAlgebraMorphism(FiniteDimensionalAlgebraMorphism): @@ -30,17 +97,15 @@ class FiniteDimensionalEuclideanJordanAlgebraMorphism(FiniteDimensionalAlgebraMo 2. Inputs and outputs the underlying matrix with respect to COLUMN vectors, unlike the parent class. - 3. Allows us to add morphisms in the obvious way. - - 4. Allows us to invert morphisms. + 3. Allows us to add, subtract, negate, multiply (compose), and + invert morphisms in the obvious way. If this seems a bit heavyweight, it is. I would have been happy to use a the ring morphism that underlies the finite-dimensional algebra morphism, but they don't seem to be callable on elements of - our EJA, and you can't add/invert them. + our EJA, and you can't add/multiply/etc. them. """ - - def __add__(self, other): + def _add_(self, other): """ Add two EJA morphisms in the obvious way. @@ -125,6 +190,106 @@ class FiniteDimensionalEuclideanJordanAlgebraMorphism(FiniteDimensionalAlgebraMo return FiniteDimensionalEuclideanJordanAlgebraMorphism(self.parent(), A.inverse()) + def _lmul_(self, right): + """ + Compose two EJA morphisms using multiplicative notation. + + EXAMPLES:: + + sage: J = RealSymmetricEJA(2) + sage: x = J.zero() + sage: y = J.one() + sage: x.operator() * y.operator() + Morphism from Euclidean Jordan algebra of degree 3 over Rational + Field to Euclidean Jordan algebra of degree 3 over Rational Field + given by matrix + [0 0 0] + [0 0 0] + [0 0 0] + + :: + + sage: J = RealSymmetricEJA(2) + sage: x = J.linear_combination(zip(range(len(J.gens())), J.gens())) + sage: x.operator() + Morphism from Euclidean Jordan algebra of degree 3 over Rational + Field to Euclidean Jordan algebra of degree 3 over Rational Field + given by matrix + [ 0 1 0] + [1/2 1 1/2] + [ 0 1 2] + sage: 2*x.operator() + Morphism from Euclidean Jordan algebra of degree 3 over Rational + Field to Euclidean Jordan algebra of degree 3 over Rational Field + given by matrix + [0 2 0] + [1 2 1] + [0 2 4] + sage: x.operator()*2 + Morphism from Euclidean Jordan algebra of degree 3 over Rational + Field to Euclidean Jordan algebra of degree 3 over Rational Field + given by matrix + [0 2 0] + [1 2 1] + [0 2 4] + + TESTS:: + + sage: set_random_seed() + sage: J = random_eja() + sage: x = J.random_element() + sage: y = J.random_element() + sage: (x.operator() * y.operator()) in J.Hom(J) + True + + """ + try: + # I think the morphism classes break the coercion framework + # somewhere along the way, so we have to do this ourselves. + right = self.parent().coerce(right) + except: + pass + + if not right.codomain() is self.domain(): + raise ValueError("(co)domains must agree for composition") + + return FiniteDimensionalEuclideanJordanAlgebraMorphism( + self.parent(), + self.matrix()*right.matrix() ) + + __mul__ = _lmul_ + + + def _neg_(self): + """ + Negate this morphism. + + EXAMPLES:: + + sage: J = RealSymmetricEJA(2) + sage: x = J.one() + sage: -x.operator() + Morphism from Euclidean Jordan algebra of degree 3 over Rational + Field to Euclidean Jordan algebra of degree 3 over Rational Field + given by matrix + [-1 0 0] + [ 0 -1 0] + [ 0 0 -1] + + TESTS:: + + sage: set_random_seed() + sage: J = random_eja() + sage: x = J.random_element() + sage: -x.operator() in J.Hom(J) + True + + """ + return FiniteDimensionalEuclideanJordanAlgebraMorphism( + self.parent(), + -self.matrix() ) + + def _repr_(self): """ We override only the representation that is shown to the user, @@ -159,6 +324,36 @@ class FiniteDimensionalEuclideanJordanAlgebraMorphism(FiniteDimensionalAlgebraMo return "Morphism from {} to {} given by matrix\n{}".format( self.domain(), self.codomain(), self.matrix()) + + def __sub__(self, other): + """ + Subtract one morphism from another using addition and negation. + + EXAMPLES:: + + sage: J = RealSymmetricEJA(2) + sage: L1 = J.one().operator() + sage: L1 - L1 + Morphism from Euclidean Jordan algebra of degree 3 over Rational + Field to Euclidean Jordan algebra of degree 3 over Rational + Field given by matrix + [0 0 0] + [0 0 0] + [0 0 0] + + TESTS:: + + sage: set_random_seed() + sage: J = random_eja() + sage: x = J.random_element() + sage: y = J.random_element() + sage: x.operator() - y.operator() in J.Hom(J) + True + + """ + return self + (-other) + + def matrix(self): """ Return the matrix of this morphism with respect to a left-action @@ -185,7 +380,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): raise ValueError("input is not a multiplication table") mult_table = tuple(mult_table) - cat = MagmaticAlgebras(field).FiniteDimensional().WithBasis() + cat = FiniteDimensionalAlgebrasWithBasis(field) cat.or_subcategory(category) if assume_associative: cat = cat.Associative() @@ -203,6 +398,15 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): natural_basis=natural_basis) + def _Hom_(self, B, cat): + """ + Construct a homset of ``self`` and ``B``. + """ + return FiniteDimensionalEuclideanJordanAlgebraHomset(self, + B, + category=cat) + + def __init__(self, field, mult_table, @@ -885,8 +1089,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): if not self.is_invertible(): raise ValueError("element is not invertible") - P = self.parent() - return P(self.quadratic_representation().inverse()*self.vector()) + return (~self.quadratic_representation())(self) def is_invertible(self): @@ -1271,7 +1474,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): sage: D = (x0^2 - x_bar.inner_product(x_bar))*D sage: D = D + 2*x_bar.tensor_product(x_bar) sage: Q = block_matrix(2,2,[A,B,C,D]) - sage: Q == x.quadratic_representation() + sage: Q == x.quadratic_representation().matrix() True Test all of the properties from Theorem 11.2 in Alizadeh:: @@ -1280,8 +1483,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): sage: J = random_eja() sage: x = J.random_element() sage: y = J.random_element() - sage: Lx = x.operator_matrix() - sage: Lxx = (x*x).operator_matrix() + sage: Lx = x.operator() + sage: Lxx = (x*x).operator() sage: Qx = x.quadratic_representation() sage: Qy = y.quadratic_representation() sage: Qxy = x.quadratic_representation(y) @@ -1302,17 +1505,16 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): Property 3: - sage: not x.is_invertible() or ( - ....: Qx*x.inverse().vector() == x.vector() ) + sage: not x.is_invertible() or ( Qx(x.inverse()) == x ) True sage: not x.is_invertible() or ( - ....: Qx.inverse() + ....: ~Qx ....: == ....: x.inverse().quadratic_representation() ) True - sage: Qxy*(J.one().vector()) == (x*y).vector() + sage: Qxy(J.one()) == x*y True Property 4: @@ -1325,15 +1527,15 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): sage: not x.is_invertible() or ( ....: x.quadratic_representation(x.inverse())*Qx ....: == - ....: 2*x.operator_matrix()*Qex - Qx ) + ....: 2*x.operator()*Qex - Qx ) True - sage: 2*x.operator_matrix()*Qex - Qx == Lxx + sage: 2*x.operator()*Qex - Qx == Lxx True Property 5: - sage: J(Qy*x.vector()).quadratic_representation() == Qy*Qx*Qy + sage: Qy(x).quadratic_representation() == Qy*Qx*Qy True Property 6: @@ -1344,13 +1546,13 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): Property 7: sage: not x.is_invertible() or ( - ....: Qx*x.inverse().operator_matrix() == Lx ) + ....: Qx*x.inverse().operator() == Lx ) True Property 8: sage: not x.operator_commutes_with(y) or ( - ....: J(Qx*y.vector())^n == J(Qxn*(y^n).vector()) ) + ....: Qx(y)^n == Qxn(y^n) ) True """ @@ -1359,9 +1561,9 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): elif not other in self.parent(): raise TypeError("'other' must live in the same algebra") - L = self.operator_matrix() - M = other.operator_matrix() - return ( L*M + M*L - (self*other).operator_matrix() ) + L = self.operator() + M = other.operator() + return ( L*M + M*L - (self*other).operator() ) def span_of_powers(self):