1 from sage
.matrix
.constructor
import matrix
3 from mjo
.eja
.eja_algebra
import FiniteDimensionalEuclideanJordanAlgebra
4 from mjo
.eja
.eja_element
import FiniteDimensionalEuclideanJordanAlgebraElement
5 from mjo
.eja
.eja_utils
import gram_schmidt
7 class FiniteDimensionalEuclideanJordanElementSubalgebraElement(FiniteDimensionalEuclideanJordanAlgebraElement
):
11 sage: from mjo.eja.eja_algebra import random_eja
15 The natural representation of an element in the subalgebra is
16 the same as its natural representation in the superalgebra::
18 sage: set_random_seed()
19 sage: A = random_eja().random_element().subalgebra_generated_by()
20 sage: y = A.random_element()
21 sage: actual = y.natural_representation()
22 sage: expected = y.superalgebra_element().natural_representation()
23 sage: actual == expected
28 def superalgebra_element(self
):
30 Return the object in our algebra's superalgebra that corresponds
35 sage: from mjo.eja.eja_algebra import (RealSymmetricEJA,
40 sage: J = RealSymmetricEJA(3)
41 sage: x = sum(J.gens())
43 e0 + e1 + e2 + e3 + e4 + e5
44 sage: A = x.subalgebra_generated_by()
47 sage: A(x).superalgebra_element()
48 e0 + e1 + e2 + e3 + e4 + e5
52 We can convert back and forth faithfully::
54 sage: set_random_seed()
55 sage: J = random_eja()
56 sage: x = J.random_element()
57 sage: A = x.subalgebra_generated_by()
58 sage: A(x).superalgebra_element() == x
60 sage: y = A.random_element()
61 sage: A(y.superalgebra_element()) == y
65 return self
.parent().superalgebra().linear_combination(
66 zip(self
.parent()._superalgebra
_basis
, self
.to_vector()) )
71 class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclideanJordanAlgebra
):
73 The subalgebra of an EJA generated by a single element.
77 sage: from mjo.eja.eja_algebra import (ComplexHermitianEJA,
82 Ensure that our generator names don't conflict with the superalgebra::
84 sage: J = JordanSpinEJA(3)
85 sage: J.one().subalgebra_generated_by().gens()
87 sage: J = JordanSpinEJA(3, prefix='f')
88 sage: J.one().subalgebra_generated_by().gens()
90 sage: J = JordanSpinEJA(3, prefix='b')
91 sage: J.one().subalgebra_generated_by().gens()
94 Ensure that we can find subalgebras of subalgebras::
96 sage: A = ComplexHermitianEJA(3).one().subalgebra_generated_by()
97 sage: B = A.one().subalgebra_generated_by()
102 def __init__(self
, elt
, orthonormalize_basis
):
103 self
._superalgebra
= elt
.parent()
104 category
= self
._superalgebra
.category().Associative()
105 V
= self
._superalgebra
.vector_space()
106 field
= self
._superalgebra
.base_ring()
108 # A half-assed attempt to ensure that we don't collide with
109 # the superalgebra's prefix (ignoring the fact that there
110 # could be super-superelgrbas in scope). If possible, we
111 # try to "increment" the parent algebra's prefix, although
112 # this idea goes out the window fast because some prefixen
114 prefixen
= [ 'f', 'g', 'h', 'a', 'b', 'c', 'd' ]
116 prefix
= prefixen
[prefixen
.index(self
._superalgebra
.prefix()) + 1]
121 # Short circuit because 0^0 == 1 is going to make us
122 # think we have a one-dimensional algebra otherwise.
123 natural_basis
= tuple()
126 self
._vector
_space
= V
.zero_subspace()
127 self
._superalgebra
_basis
= []
128 fdeja
= super(FiniteDimensionalEuclideanJordanElementSubalgebra
,
130 return fdeja
.__init
__(field
,
135 natural_basis
=natural_basis
)
138 # This list is guaranteed to contain all independent powers,
139 # because it's the maximal set of powers that could possibly
140 # be independent (by a dimension argument).
141 powers
= [ elt
**k
for k
in range(V
.dimension()) ]
143 if orthonormalize_basis
== False:
144 # In this case, we just need to figure out which elements
145 # of the "powers" list are redundant... First compute the
146 # vector subspace spanned by the powers of the given
148 power_vectors
= [ p
.to_vector() for p
in powers
]
150 # Figure out which powers form a linearly-independent set.
151 ind_rows
= matrix(field
, power_vectors
).pivot_rows()
153 # Pick those out of the list of all powers.
154 superalgebra_basis
= tuple(map(powers
.__getitem
__, ind_rows
))
156 # If our superalgebra is a subalgebra of something else, then
157 # these vectors won't have the right coordinates for
158 # V.span_of_basis() unless we use V.from_vector() on them.
159 basis_vectors
= map(power_vectors
.__getitem
__, ind_rows
)
161 # If we're going to orthonormalize the basis anyway, we
162 # might as well just do Gram-Schmidt on the whole list of
163 # powers. The redundant ones will get zero'd out.
164 superalgebra_basis
= gram_schmidt(powers
)
165 basis_vectors
= [ b
.to_vector() for b
in superalgebra_basis
]
167 W
= V
.span_of_basis( V
.from_vector(v
) for v
in basis_vectors
)
168 n
= len(superalgebra_basis
)
169 mult_table
= [[W
.zero() for i
in range(n
)] for j
in range(n
)]
172 product
= superalgebra_basis
[i
]*superalgebra_basis
[j
]
173 # product.to_vector() might live in a vector subspace
174 # if our parent algebra is already a subalgebra. We
175 # use V.from_vector() to make it "the right size" in
177 product_vector
= V
.from_vector(product
.to_vector())
178 mult_table
[i
][j
] = W
.coordinate_vector(product_vector
)
180 # The rank is the highest possible degree of a minimal
181 # polynomial, and is bounded above by the dimension. We know
182 # in this case that there's an element whose minimal
183 # polynomial has the same degree as the space's dimension
184 # (remember how we constructed the space?), so that must be
188 natural_basis
= tuple( b
.natural_representation()
189 for b
in superalgebra_basis
)
192 self
._vector
_space
= W
193 self
._superalgebra
_basis
= superalgebra_basis
196 fdeja
= super(FiniteDimensionalEuclideanJordanElementSubalgebra
, self
)
197 return fdeja
.__init
__(field
,
202 natural_basis
=natural_basis
)
205 def _a_regular_element(self
):
207 Override the superalgebra method to return the one
208 regular element that is sure to exist in this
209 subalgebra, namely the element that generated it.
213 sage: from mjo.eja.eja_algebra import random_eja
217 sage: set_random_seed()
218 sage: J = random_eja().random_element().subalgebra_generated_by()
219 sage: J._a_regular_element().is_regular()
223 if self
.dimension() == 0:
226 return self
.monomial(1)
229 def _element_constructor_(self
, elt
):
231 Construct an element of this subalgebra from the given one.
232 The only valid arguments are elements of the parent algebra
233 that happen to live in this subalgebra.
237 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
238 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
242 sage: J = RealSymmetricEJA(3)
243 sage: x = sum( i*J.gens()[i] for i in range(6) )
244 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x)
245 sage: [ K(x^k) for k in range(J.rank()) ]
252 # Just as in the superalgebra class, we need to hack
253 # this special case to ensure that random_element() can
254 # coerce a ring zero into the algebra.
257 if elt
in self
.superalgebra():
258 coords
= self
.vector_space().coordinate_vector(elt
.to_vector())
259 return self
.from_vector(coords
)
264 Return the basis-element-index of this algebra's unit element.
271 Return the multiplicative identity element of this algebra.
273 The superclass method computes the identity element, which is
274 beyond overkill in this case: the algebra identity should be our
275 first basis element. We implement this via :meth:`one_basis`
276 because that method can optionally be used by other parts of the
281 sage: from mjo.eja.eja_algebra import (RealCartesianProductEJA,
286 sage: J = RealCartesianProductEJA(5)
288 e0 + e1 + e2 + e3 + e4
289 sage: x = sum(J.gens())
290 sage: A = x.subalgebra_generated_by()
293 sage: A.one().superalgebra_element()
294 e0 + e1 + e2 + e3 + e4
298 The identity element acts like the identity::
300 sage: set_random_seed()
301 sage: J = random_eja().random_element().subalgebra_generated_by()
302 sage: x = J.random_element()
303 sage: J.one()*x == x and x*J.one() == x
306 The matrix of the unit element's operator is the identity::
308 sage: set_random_seed()
309 sage: J = random_eja().random_element().subalgebra_generated_by()
310 sage: actual = J.one().operator().matrix()
311 sage: expected = matrix.identity(J.base_ring(), J.dimension())
312 sage: actual == expected
315 if self
.dimension() == 0:
318 return self
.monomial(self
.one_basis())
321 def natural_basis_space(self
):
323 Return the natural basis space of this algebra, which is identical
324 to that of its superalgebra.
326 This is correct "by definition," and avoids a mismatch when the
327 subalgebra is trivial (with no natural basis to infer anything
328 from) and the parent is not.
330 return self
.superalgebra().natural_basis_space()
333 def superalgebra(self
):
335 Return the superalgebra that this algebra was generated from.
337 return self
._superalgebra
340 def vector_space(self
):
344 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
345 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
349 sage: J = RealSymmetricEJA(3)
350 sage: x = J.monomial(0) + 2*J.monomial(2) + 5*J.monomial(5)
351 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x)
352 sage: K.vector_space()
353 Vector space of degree 6 and dimension 3 over...
358 sage: (x^0).to_vector()
360 sage: (x^1).to_vector()
362 sage: (x^2).to_vector()
366 return self
._vector
_space
369 Element
= FiniteDimensionalEuclideanJordanElementSubalgebraElement