]> gitweb.michael.orlitzky.com - sage.d.git/commitdiff
eja: update todo, and rename "natural" to "matrix".
authorMichael Orlitzky <michael@orlitzky.com>
Wed, 25 Nov 2020 22:55:49 +0000 (17:55 -0500)
committerMichael Orlitzky <michael@orlitzky.com>
Wed, 25 Nov 2020 22:55:49 +0000 (17:55 -0500)
We've already completed one TODO by adding is_self_adjoint() for
operators. Another is completed by deciding that I don't want to drop
natural representations for non-matrix algebras. But I do want to
rename them, to "matrix representations," because that's what they
are.

mjo/eja/TODO
mjo/eja/eja_algebra.py
mjo/eja/eja_element.py
mjo/eja/eja_subalgebra.py

index 266015647f50bf17e7546fe4d191b99d9e3655ba..f0901ca91b793debc4877a8ee5a670d240fa51fc 100644 (file)
@@ -14,7 +14,7 @@
 6. Pass already_echelonized (default: False) and echelon_basis
    (default: None) into the subalgebra constructor. The value of
    already_echelonized can be passed to V.span_of_basis() to save
-   some time, and usinf e.g. FreeModule_submodule_with_basis_field
+   some time, and using e.g. FreeModule_submodule_with_basis_field
    we may somehow be able to pass the echelon basis straight in to
    save time.
 
@@ -35,7 +35,8 @@
 9. Compute the scalar in the general natural_inner_product() for
    matrices, so no overrides are necessary.
 
-10. Eliminate "natural representation" for non-matrix algebras.
-
-11. The main EJA element constructor is happy to convert between
+10. The main EJA element constructor is happy to convert between
     e.g. HadamardEJA(3) and JordanSpinEJA(3).
+
+11. Figure out if CombinatorialFreeModule's use of IndexedGenerators
+    can be used to replace the matrix_basis().
index 2ea1a9267623d95d02231654a48a470efc186a40..9d53bc5fdfd8fca177e43e49a187387fbe5a6085 100644 (file)
@@ -64,7 +64,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
                  mult_table,
                  prefix='e',
                  category=None,
-                 natural_basis=None,
+                 matrix_basis=None,
                  check_field=True,
                  check_axioms=True):
         """
@@ -115,7 +115,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
             if not all( len(l) == n for l in mult_table ):
                 raise ValueError("multiplication table is not square")
 
-        self._natural_basis = natural_basis
+        self._matrix_basis = matrix_basis
 
         if category is None:
             category = MagmaticAlgebras(field).FiniteDimensional()
@@ -149,7 +149,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
 
     def _element_constructor_(self, elt):
         """
-        Construct an element of this algebra from its natural
+        Construct an element of this algebra from its vector or matrix
         representation.
 
         This gets called only after the parent element _call_ method
@@ -182,8 +182,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
         TESTS:
 
         Ensure that we can convert any element of the two non-matrix
-        simple algebras (whose natural representations are their usual
-        vector representations) back and forth faithfully::
+        simple algebras (whose matrix representations are columns)
+        back and forth faithfully::
 
             sage: set_random_seed()
             sage: J = HadamardEJA.random_instance()
@@ -194,7 +194,6 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
             sage: x = J.random_element()
             sage: J(x.to_vector().column()) == x
             True
-
         """
         msg = "not an element of this algebra"
         if elt == 0:
@@ -208,19 +207,17 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
             # that the integer 3 belongs to the space of 2-by-2 matrices.
             raise ValueError(msg)
 
-        natural_basis = self.natural_basis()
-        basis_space = natural_basis[0].matrix_space()
-        if elt not in basis_space:
+        if elt not in self.matrix_space():
             raise ValueError(msg)
 
         # Thanks for nothing! Matrix spaces aren't vector spaces in
-        # Sage, so we have to figure out its natural-basis coordinates
+        # Sage, so we have to figure out its matrix-basis coordinates
         # ourselves. We use the basis space's ring instead of the
         # element's ring because the basis space might be an algebraic
         # closure whereas the base ring of the 3-by-3 identity matrix
         # could be QQ instead of QQbar.
-        V = VectorSpace(basis_space.base_ring(), elt.nrows()*elt.ncols())
-        W = V.span_of_basis( _mat2vec(s) for s in natural_basis )
+        V = VectorSpace(self.base_ring(), elt.nrows()*elt.ncols())
+        W = V.span_of_basis( _mat2vec(s) for s in self.matrix_basis() )
 
         try:
             coords =  W.coordinate_vector(_mat2vec(elt))
@@ -515,18 +512,33 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
         return table(M, header_row=True, header_column=True, frame=True)
 
 
-    def natural_basis(self):
+    def matrix_basis(self):
         """
-        Return a more-natural representation of this algebra's basis.
+        Return an (often more natural) representation of this algebras
+        basis as an ordered tuple of matrices.
+
+        Every finite-dimensional Euclidean Jordan Algebra is a, up to
+        Jordan isomorphism, a direct sum of five simple
+        algebras---four of which comprise Hermitian matrices. And the
+        last type of algebra can of course be thought of as `n`-by-`1`
+        column matrices (ambiguusly called column vectors) to avoid
+        special cases. As a result, matrices (and column vectors) are
+        a natural representation format for Euclidean Jordan algebra
+        elements.
 
-        Every finite-dimensional Euclidean Jordan Algebra is a direct
-        sum of five simple algebras, four of which comprise Hermitian
-        matrices. This method returns the original "natural" basis
-        for our underlying vector space. (Typically, the natural basis
-        is used to construct the multiplication table in the first place.)
+        But, when we construct an algebra from a basis of matrices,
+        those matrix representations are lost in favor of coordinate
+        vectors *with respect to* that basis. We could eventually
+        convert back if we tried hard enough, but having the original
+        representations handy is valuable enough that we simply store
+        them and return them from this method.
 
-        Note that this will always return a matrix. The standard basis
-        in `R^n` will be returned as `n`-by-`1` column matrices.
+        Why implement this for non-matrix algebras? Avoiding special
+        cases for the :class:`BilinearFormEJA` pays with simplicity in
+        its own right. But mainly, we would like to be able to assume
+        that elements of a :class:`DirectSumEJA` can be displayed
+        nicely, without having to have special classes for direct sums
+        one of whose components was a matrix algebra.
 
         SETUP::
 
@@ -538,7 +550,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
             sage: J = RealSymmetricEJA(2)
             sage: J.basis()
             Finite family {0: e0, 1: e1, 2: e2}
-            sage: J.natural_basis()
+            sage: J.matrix_basis()
             (
             [1 0]  [                  0 0.7071067811865475?]  [0 0]
             [0 0], [0.7071067811865475?                   0], [0 1]
@@ -549,36 +561,38 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
             sage: J = JordanSpinEJA(2)
             sage: J.basis()
             Finite family {0: e0, 1: e1}
-            sage: J.natural_basis()
+            sage: J.matrix_basis()
             (
             [1]  [0]
             [0], [1]
             )
-
         """
-        if self._natural_basis is None:
-            M = self.natural_basis_space()
+        if self._matrix_basis is None:
+            M = self.matrix_space()
             return tuple( M(b.to_vector()) for b in self.basis() )
         else:
-            return self._natural_basis
+            return self._matrix_basis
 
 
-    def natural_basis_space(self):
+    def matrix_space(self):
         """
-        Return the matrix space in which this algebra's natural basis
-        elements live.
+        Return the matrix space in which this algebra's elements live, if
+        we think of them as matrices (including column vectors of the
+        appropriate size).
 
         Generally this will be an `n`-by-`1` column-vector space,
         except when the algebra is trivial. There it's `n`-by-`n`
-        (where `n` is zero), to ensure that two elements of the
-        natural basis space (empty matrices) can be multiplied.
+        (where `n` is zero), to ensure that two elements of the matrix
+        space (empty matrices) can be multiplied.
+
+        Matrix algebras override this with something more useful.
         """
         if self.is_trivial():
             return MatrixSpace(self.base_ring(), 0)
-        elif self._natural_basis is None or len(self._natural_basis) == 0:
+        elif self._matrix_basis is None or len(self._matrix_basis) == 0:
             return MatrixSpace(self.base_ring(), self.dimension(), 1)
         else:
-            return self._natural_basis[0].matrix_space()
+            return self._matrix_basis[0].matrix_space()
 
 
     @cached_method
@@ -705,22 +719,22 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
             Vector space of degree 6 and dimension 2...
             sage: J1
             Euclidean Jordan algebra of dimension 3...
-            sage: J0.one().natural_representation()
+            sage: J0.one().to_matrix()
             [0 0 0]
             [0 0 0]
             [0 0 1]
             sage: orig_df = AA.options.display_format
             sage: AA.options.display_format = 'radical'
-            sage: J.from_vector(J5.basis()[0]).natural_representation()
+            sage: J.from_vector(J5.basis()[0]).to_matrix()
             [          0           0 1/2*sqrt(2)]
             [          0           0           0]
             [1/2*sqrt(2)           0           0]
-            sage: J.from_vector(J5.basis()[1]).natural_representation()
+            sage: J.from_vector(J5.basis()[1]).to_matrix()
             [          0           0           0]
             [          0           0 1/2*sqrt(2)]
             [          0 1/2*sqrt(2)           0]
             sage: AA.options.display_format = orig_df
-            sage: J1.one().natural_representation()
+            sage: J1.one().to_matrix()
             [1 0 0]
             [0 1 0]
             [0 0 0]
@@ -1106,26 +1120,25 @@ class ConcreteEuclideanJordanAlgebra:
 
     TESTS:
 
-    Our natural basis is normalized with respect to the natural inner
-    product unless we specify otherwise::
+    Our basis is normalized with respect to the algebra's inner
+    product, unless we specify otherwise::
 
         sage: set_random_seed()
         sage: J = ConcreteEuclideanJordanAlgebra.random_instance()
         sage: all( b.norm() == 1 for b in J.gens() )
         True
 
-    Since our natural basis is normalized with respect to the natural
-    inner product, and since we know that this algebra is an EJA, any
+    Since our basis is orthonormal with respect to the algebra's inner
+    product, and since we know that this algebra is an EJA, any
     left-multiplication operator's matrix will be symmetric because
-    natural->EJA basis representation is an isometry and within the EJA
-    the operator is self-adjoint by the Jordan axiom::
+    natural->EJA basis representation is an isometry and within the
+    EJA the operator is self-adjoint by the Jordan axiom::
 
         sage: set_random_seed()
         sage: J = ConcreteEuclideanJordanAlgebra.random_instance()
         sage: x = J.random_element()
         sage: x.operator().is_self_adjoint()
         True
-
     """
 
     @staticmethod
@@ -1187,7 +1200,7 @@ class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
                 field = field.extension(p, 'sqrt2', embedding=RLF(2).sqrt())
                 basis = tuple( s.change_ring(field) for s in basis )
             self._basis_normalizers = tuple(
-                ~(self.natural_inner_product(s,s).sqrt()) for s in basis )
+                ~(self.matrix_inner_product(s,s).sqrt()) for s in basis )
             basis = tuple(s*c for (s,c) in zip(basis,self._basis_normalizers))
 
         # Now compute the multiplication and inner product tables.
@@ -1208,7 +1221,7 @@ class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
                     # HACK: ignore the error here if we don't need the
                     # inner product (as is the case when we construct
                     # a dummy QQ-algebra for fast charpoly coefficients.
-                    ip_table[i][j] = self.natural_inner_product(basis[i],
+                    ip_table[i][j] = self.matrix_inner_product(basis[i],
                                                                 basis[j])
                 except:
                     pass
@@ -1221,7 +1234,7 @@ class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
 
         super(MatrixEuclideanJordanAlgebra, self).__init__(field,
                                                            mult_table,
-                                                           natural_basis=basis,
+                                                           matrix_basis=basis,
                                                            **kwargs)
 
         if algebra_dim == 0:
@@ -1244,7 +1257,7 @@ class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
             # entries in a nice field already. Just compute the thing.
             return super(MatrixEuclideanJordanAlgebra, self)._charpoly_coefficients()
 
-        basis = ( (b/n) for (b,n) in zip(self.natural_basis(),
+        basis = ( (b/n) for (b,n) in zip(self.matrix_basis(),
                                          self._basis_normalizers) )
 
         # Do this over the rationals and convert back at the end.
@@ -1304,7 +1317,7 @@ class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
         raise NotImplementedError
 
     @classmethod
-    def natural_inner_product(cls,X,Y):
+    def matrix_inner_product(cls,X,Y):
         Xu = cls.real_unembed(X)
         Yu = cls.real_unembed(Y)
         tr = (Xu*Yu).trace()
@@ -1383,9 +1396,9 @@ class RealSymmetricEJA(RealMatrixEuclideanJordanAlgebra,
         sage: set_random_seed()
         sage: J = RealSymmetricEJA.random_instance()
         sage: x,y = J.random_elements(2)
-        sage: actual = (x*y).natural_representation()
-        sage: X = x.natural_representation()
-        sage: Y = y.natural_representation()
+        sage: actual = (x*y).to_matrix()
+        sage: X = x.to_matrix()
+        sage: Y = y.to_matrix()
         sage: expected = (X*Y + Y*X)/2
         sage: actual == expected
         True
@@ -1584,9 +1597,9 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
 
 
     @classmethod
-    def natural_inner_product(cls,X,Y):
+    def matrix_inner_product(cls,X,Y):
         """
-        Compute a natural inner product in this algebra directly from
+        Compute a matrix inner product in this algebra directly from
         its real embedding.
 
         SETUP::
@@ -1601,17 +1614,17 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
             sage: set_random_seed()
             sage: J = ComplexHermitianEJA.random_instance()
             sage: x,y = J.random_elements(2)
-            sage: Xe = x.natural_representation()
-            sage: Ye = y.natural_representation()
+            sage: Xe = x.to_matrix()
+            sage: Ye = y.to_matrix()
             sage: X = ComplexHermitianEJA.real_unembed(Xe)
             sage: Y = ComplexHermitianEJA.real_unembed(Ye)
             sage: expected = (X*Y).trace().real()
-            sage: actual = ComplexHermitianEJA.natural_inner_product(Xe,Ye)
+            sage: actual = ComplexHermitianEJA.matrix_inner_product(Xe,Ye)
             sage: actual == expected
             True
 
         """
-        return RealMatrixEuclideanJordanAlgebra.natural_inner_product(X,Y)/2
+        return RealMatrixEuclideanJordanAlgebra.matrix_inner_product(X,Y)/2
 
 
 class ComplexHermitianEJA(ComplexMatrixEuclideanJordanAlgebra,
@@ -1652,9 +1665,9 @@ class ComplexHermitianEJA(ComplexMatrixEuclideanJordanAlgebra,
         sage: set_random_seed()
         sage: J = ComplexHermitianEJA.random_instance()
         sage: x,y = J.random_elements(2)
-        sage: actual = (x*y).natural_representation()
-        sage: X = x.natural_representation()
-        sage: Y = y.natural_representation()
+        sage: actual = (x*y).to_matrix()
+        sage: X = x.to_matrix()
+        sage: Y = y.to_matrix()
         sage: expected = (X*Y + Y*X)/2
         sage: actual == expected
         True
@@ -1879,9 +1892,9 @@ class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
 
 
     @classmethod
-    def natural_inner_product(cls,X,Y):
+    def matrix_inner_product(cls,X,Y):
         """
-        Compute a natural inner product in this algebra directly from
+        Compute a matrix inner product in this algebra directly from
         its real embedding.
 
         SETUP::
@@ -1896,17 +1909,17 @@ class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
             sage: set_random_seed()
             sage: J = QuaternionHermitianEJA.random_instance()
             sage: x,y = J.random_elements(2)
-            sage: Xe = x.natural_representation()
-            sage: Ye = y.natural_representation()
+            sage: Xe = x.to_matrix()
+            sage: Ye = y.to_matrix()
             sage: X = QuaternionHermitianEJA.real_unembed(Xe)
             sage: Y = QuaternionHermitianEJA.real_unembed(Ye)
             sage: expected = (X*Y).trace().coefficient_tuple()[0]
-            sage: actual = QuaternionHermitianEJA.natural_inner_product(Xe,Ye)
+            sage: actual = QuaternionHermitianEJA.matrix_inner_product(Xe,Ye)
             sage: actual == expected
             True
 
         """
-        return RealMatrixEuclideanJordanAlgebra.natural_inner_product(X,Y)/4
+        return RealMatrixEuclideanJordanAlgebra.matrix_inner_product(X,Y)/4
 
 
 class QuaternionHermitianEJA(QuaternionMatrixEuclideanJordanAlgebra,
@@ -1947,9 +1960,9 @@ class QuaternionHermitianEJA(QuaternionMatrixEuclideanJordanAlgebra,
         sage: set_random_seed()
         sage: J = QuaternionHermitianEJA.random_instance()
         sage: x,y = J.random_elements(2)
-        sage: actual = (x*y).natural_representation()
-        sage: X = x.natural_representation()
-        sage: Y = y.natural_representation()
+        sage: actual = (x*y).to_matrix()
+        sage: X = x.to_matrix()
+        sage: Y = y.to_matrix()
         sage: expected = (X*Y + Y*X)/2
         sage: actual == expected
         True
index 120870b7fa08b1ee0fcb936b92c62a9470a27754..6547668965a690b883a5ac59757ef1e625016604 100644 (file)
@@ -971,15 +971,16 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
 
 
 
-    def natural_representation(self):
+    def to_matrix(self):
         """
-        Return a more-natural representation of this element.
+        Return an (often more natural) representation of this element as a
+        matrix.
 
-        Every finite-dimensional Euclidean Jordan Algebra is a
-        direct sum of five simple algebras, four of which comprise
-        Hermitian matrices. This method returns the original
-        "natural" representation of this element as a Hermitian
-        matrix, if it has one. If not, you get the usual representation.
+        Every finite-dimensional Euclidean Jordan Algebra is a direct
+        sum of five simple algebras, four of which comprise Hermitian
+        matrices. This method returns a "natural" matrix
+        representation of this element as either a Hermitian matrix or
+        column vector.
 
         SETUP::
 
@@ -991,7 +992,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             sage: J = ComplexHermitianEJA(3)
             sage: J.one()
             e0 + e3 + e8
-            sage: J.one().natural_representation()
+            sage: J.one().to_matrix()
             [1 0 0 0 0 0]
             [0 1 0 0 0 0]
             [0 0 1 0 0 0]
@@ -1004,7 +1005,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             sage: J = QuaternionHermitianEJA(3)
             sage: J.one()
             e0 + e5 + e14
-            sage: J.one().natural_representation()
+            sage: J.one().to_matrix()
             [1 0 0 0 0 0 0 0 0 0 0 0]
             [0 1 0 0 0 0 0 0 0 0 0 0]
             [0 0 1 0 0 0 0 0 0 0 0 0]
@@ -1017,15 +1018,14 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             [0 0 0 0 0 0 0 0 0 1 0 0]
             [0 0 0 0 0 0 0 0 0 0 1 0]
             [0 0 0 0 0 0 0 0 0 0 0 1]
-
         """
-        B = self.parent().natural_basis()
-        W = self.parent().natural_basis_space()
+        B = self.parent().matrix_basis()
+        W = self.parent().matrix_space()
 
         # This is just a manual "from_vector()", but of course
         # matrix spaces aren't vector spaces in sage, so they
         # don't have a from_vector() method.
-        return W.linear_combination(zip(B,self.to_vector()))
+        return W.linear_combination( zip(B, self.to_vector()) )
 
 
     def norm(self):
index 6a9d10f65b7164627394c5ddb32bd682c323c5b2..e7e559f80466d8b4da96c9a14ecea74bfd9351d4 100644 (file)
@@ -11,14 +11,14 @@ class FiniteDimensionalEuclideanJordanSubalgebraElement(FiniteDimensionalEuclide
 
     TESTS::
 
-    The natural representation of an element in the subalgebra is
-    the same as its natural representation in the superalgebra::
+    The matrix representation of an element in the subalgebra is
+    the same as its matrix representation in the superalgebra::
 
         sage: set_random_seed()
         sage: A = random_eja().random_element().subalgebra_generated_by()
         sage: y = A.random_element()
-        sage: actual = y.natural_representation()
-        sage: expected = y.superalgebra_element().natural_representation()
+        sage: actual = y.to_matrix()
+        sage: expected = y.superalgebra_element().to_matrix()
         sage: actual == expected
         True
 
@@ -121,11 +121,11 @@ class FiniteDimensionalEuclideanJordanSubalgebra(FiniteDimensionalEuclideanJorda
         sage: E22 = matrix(AA, [ [0,0],
         ....:                    [0,1] ])
         sage: K1 = FiniteDimensionalEuclideanJordanSubalgebra(J, (J(E11),))
-        sage: K1.one().natural_representation()
+        sage: K1.one().to_matrix()
         [1 0]
         [0 0]
         sage: K2 = FiniteDimensionalEuclideanJordanSubalgebra(J, (J(E22),))
-        sage: K2.one().natural_representation()
+        sage: K2.one().to_matrix()
         [0 0]
         [0 1]
 
@@ -192,7 +192,7 @@ class FiniteDimensionalEuclideanJordanSubalgebra(FiniteDimensionalEuclideanJorda
                 mult_table[i][j] = W.coordinate_vector(product_vector)
 
         self._inner_product_matrix = matrix(field, ip_table)
-        natural_basis = tuple( b.natural_representation() for b in basis )
+        matrix_basis = tuple( b.to_matrix() for b in basis )
 
 
         self._vector_space = W
@@ -202,7 +202,7 @@ class FiniteDimensionalEuclideanJordanSubalgebra(FiniteDimensionalEuclideanJorda
                        mult_table,
                        prefix=prefix,
                        category=category,
-                       natural_basis=natural_basis,
+                       matrix_basis=matrix_basis,
                        check_field=False,
                        check_axioms=check_axioms)
 
@@ -256,16 +256,16 @@ class FiniteDimensionalEuclideanJordanSubalgebra(FiniteDimensionalEuclideanJorda
 
 
 
-    def natural_basis_space(self):
+    def matrix_space(self):
         """
-        Return the natural basis space of this algebra, which is identical
-        to that of its superalgebra.
+        Return the matrix space of this algebra, which is identical to
+        that of its superalgebra.
 
-        This is correct "by definition," and avoids a mismatch when the
-        subalgebra is trivial (with no natural basis to infer anything
-        from) and the parent is not.
+        This is correct "by definition," and avoids a mismatch when
+        the subalgebra is trivial (with no matrix basis elements to
+        infer anything from) and the parent is not.
         """
-        return self.superalgebra().natural_basis_space()
+        return self.superalgebra().matrix_space()
 
 
     def superalgebra(self):