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
26 The left-multiplication-by operator for elements in the subalgebra
27 works like it does in the superalgebra, even if we orthonormalize
30 sage: set_random_seed()
31 sage: x = random_eja(AA).random_element()
32 sage: A = x.subalgebra_generated_by(orthonormalize_basis=True)
33 sage: y = A.random_element()
34 sage: y.operator()(A.one()) == y
39 def superalgebra_element(self
):
41 Return the object in our algebra's superalgebra that corresponds
46 sage: from mjo.eja.eja_algebra import (RealSymmetricEJA,
51 sage: J = RealSymmetricEJA(3)
52 sage: x = sum(J.gens())
54 e0 + e1 + e2 + e3 + e4 + e5
55 sage: A = x.subalgebra_generated_by()
58 sage: A(x).superalgebra_element()
59 e0 + e1 + e2 + e3 + e4 + e5
63 We can convert back and forth faithfully::
65 sage: set_random_seed()
66 sage: J = random_eja()
67 sage: x = J.random_element()
68 sage: A = x.subalgebra_generated_by()
69 sage: A(x).superalgebra_element() == x
71 sage: y = A.random_element()
72 sage: A(y.superalgebra_element()) == y
76 return self
.parent().superalgebra().linear_combination(
77 zip(self
.parent()._superalgebra
_basis
, self
.to_vector()) )
82 class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclideanJordanAlgebra
):
84 The subalgebra of an EJA generated by a single element.
88 sage: from mjo.eja.eja_algebra import (ComplexHermitianEJA,
93 Ensure that our generator names don't conflict with the superalgebra::
95 sage: J = JordanSpinEJA(3)
96 sage: J.one().subalgebra_generated_by().gens()
98 sage: J = JordanSpinEJA(3, prefix='f')
99 sage: J.one().subalgebra_generated_by().gens()
101 sage: J = JordanSpinEJA(3, prefix='b')
102 sage: J.one().subalgebra_generated_by().gens()
105 Ensure that we can find subalgebras of subalgebras::
107 sage: A = ComplexHermitianEJA(3).one().subalgebra_generated_by()
108 sage: B = A.one().subalgebra_generated_by()
113 def __init__(self
, elt
, orthonormalize_basis
):
114 self
._superalgebra
= elt
.parent()
115 category
= self
._superalgebra
.category().Associative()
116 V
= self
._superalgebra
.vector_space()
117 field
= self
._superalgebra
.base_ring()
119 # A half-assed attempt to ensure that we don't collide with
120 # the superalgebra's prefix (ignoring the fact that there
121 # could be super-superelgrbas in scope). If possible, we
122 # try to "increment" the parent algebra's prefix, although
123 # this idea goes out the window fast because some prefixen
125 prefixen
= [ 'f', 'g', 'h', 'a', 'b', 'c', 'd' ]
127 prefix
= prefixen
[prefixen
.index(self
._superalgebra
.prefix()) + 1]
132 # Short circuit because 0^0 == 1 is going to make us
133 # think we have a one-dimensional algebra otherwise.
134 natural_basis
= tuple()
137 self
._vector
_space
= V
.zero_subspace()
138 self
._superalgebra
_basis
= []
139 fdeja
= super(FiniteDimensionalEuclideanJordanElementSubalgebra
,
141 return fdeja
.__init
__(field
,
146 natural_basis
=natural_basis
)
149 # This list is guaranteed to contain all independent powers,
150 # because it's the maximal set of powers that could possibly
151 # be independent (by a dimension argument).
152 powers
= [ elt
**k
for k
in range(V
.dimension()) ]
154 if orthonormalize_basis
== False:
155 # In this case, we just need to figure out which elements
156 # of the "powers" list are redundant... First compute the
157 # vector subspace spanned by the powers of the given
159 power_vectors
= [ p
.to_vector() for p
in powers
]
161 # Figure out which powers form a linearly-independent set.
162 ind_rows
= matrix(field
, power_vectors
).pivot_rows()
164 # Pick those out of the list of all powers.
165 superalgebra_basis
= tuple(map(powers
.__getitem
__, ind_rows
))
167 # If our superalgebra is a subalgebra of something else, then
168 # these vectors won't have the right coordinates for
169 # V.span_of_basis() unless we use V.from_vector() on them.
170 basis_vectors
= map(power_vectors
.__getitem
__, ind_rows
)
172 # If we're going to orthonormalize the basis anyway, we
173 # might as well just do Gram-Schmidt on the whole list of
174 # powers. The redundant ones will get zero'd out.
175 superalgebra_basis
= gram_schmidt(powers
)
176 basis_vectors
= [ b
.to_vector() for b
in superalgebra_basis
]
178 W
= V
.span_of_basis( V
.from_vector(v
) for v
in basis_vectors
)
179 n
= len(superalgebra_basis
)
180 mult_table
= [[W
.zero() for i
in range(n
)] for j
in range(n
)]
183 product
= superalgebra_basis
[i
]*superalgebra_basis
[j
]
184 # product.to_vector() might live in a vector subspace
185 # if our parent algebra is already a subalgebra. We
186 # use V.from_vector() to make it "the right size" in
188 product_vector
= V
.from_vector(product
.to_vector())
189 mult_table
[i
][j
] = W
.coordinate_vector(product_vector
)
191 # The rank is the highest possible degree of a minimal
192 # polynomial, and is bounded above by the dimension. We know
193 # in this case that there's an element whose minimal
194 # polynomial has the same degree as the space's dimension
195 # (remember how we constructed the space?), so that must be
199 natural_basis
= tuple( b
.natural_representation()
200 for b
in superalgebra_basis
)
203 self
._vector
_space
= W
204 self
._superalgebra
_basis
= superalgebra_basis
207 fdeja
= super(FiniteDimensionalEuclideanJordanElementSubalgebra
, self
)
208 return fdeja
.__init
__(field
,
213 natural_basis
=natural_basis
)
216 def _a_regular_element(self
):
218 Override the superalgebra method to return the one
219 regular element that is sure to exist in this
220 subalgebra, namely the element that generated it.
224 sage: from mjo.eja.eja_algebra import random_eja
228 sage: set_random_seed()
229 sage: J = random_eja().random_element().subalgebra_generated_by()
230 sage: J._a_regular_element().is_regular()
234 if self
.dimension() == 0:
237 return self
.monomial(1)
240 def _element_constructor_(self
, elt
):
242 Construct an element of this subalgebra from the given one.
243 The only valid arguments are elements of the parent algebra
244 that happen to live in this subalgebra.
248 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
249 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
253 sage: J = RealSymmetricEJA(3)
254 sage: x = sum( i*J.gens()[i] for i in range(6) )
255 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x,False)
256 sage: [ K(x^k) for k in range(J.rank()) ]
263 # Just as in the superalgebra class, we need to hack
264 # this special case to ensure that random_element() can
265 # coerce a ring zero into the algebra.
268 if elt
in self
.superalgebra():
269 coords
= self
.vector_space().coordinate_vector(elt
.to_vector())
270 return self
.from_vector(coords
)
276 Return the multiplicative identity element of this algebra.
278 The superclass method computes the identity element, which is
279 beyond overkill in this case: the superalgebra identity
280 restricted to this algebra is its identity. Note that we can't
281 count on the first basis element being the identity -- it migth
282 have been scaled if we orthonormalized the basis.
286 sage: from mjo.eja.eja_algebra import (RealCartesianProductEJA,
291 sage: J = RealCartesianProductEJA(5)
293 e0 + e1 + e2 + e3 + e4
294 sage: x = sum(J.gens())
295 sage: A = x.subalgebra_generated_by()
298 sage: A.one().superalgebra_element()
299 e0 + e1 + e2 + e3 + e4
303 The identity element acts like the identity over the rationals::
305 sage: set_random_seed()
306 sage: x = random_eja().random_element()
307 sage: A = x.subalgebra_generated_by()
308 sage: x = A.random_element()
309 sage: A.one()*x == x and x*A.one() == x
312 The identity element acts like the identity over the algebraic
313 reals with an orthonormal basis::
315 sage: set_random_seed()
316 sage: x = random_eja(AA).random_element()
317 sage: A = x.subalgebra_generated_by(orthonormalize_basis=True)
318 sage: x = A.random_element()
319 sage: A.one()*x == x and x*A.one() == x
322 The matrix of the unit element's operator is the identity over
325 sage: set_random_seed()
326 sage: x = random_eja().random_element()
327 sage: A = x.subalgebra_generated_by()
328 sage: actual = A.one().operator().matrix()
329 sage: expected = matrix.identity(A.base_ring(), A.dimension())
330 sage: actual == expected
333 The matrix of the unit element's operator is the identity over
334 the algebraic reals with an orthonormal basis::
336 sage: set_random_seed()
337 sage: x = random_eja(AA).random_element()
338 sage: A = x.subalgebra_generated_by(orthonormalize_basis=True)
339 sage: actual = A.one().operator().matrix()
340 sage: expected = matrix.identity(A.base_ring(), A.dimension())
341 sage: actual == expected
345 if self
.dimension() == 0:
348 sa_one
= self
.superalgebra().one().to_vector()
349 sa_coords
= self
.vector_space().coordinate_vector(sa_one
)
350 return self
.from_vector(sa_coords
)
353 def natural_basis_space(self
):
355 Return the natural basis space of this algebra, which is identical
356 to that of its superalgebra.
358 This is correct "by definition," and avoids a mismatch when the
359 subalgebra is trivial (with no natural basis to infer anything
360 from) and the parent is not.
362 return self
.superalgebra().natural_basis_space()
365 def superalgebra(self
):
367 Return the superalgebra that this algebra was generated from.
369 return self
._superalgebra
372 def vector_space(self
):
376 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
377 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
381 sage: J = RealSymmetricEJA(3)
382 sage: x = J.monomial(0) + 2*J.monomial(2) + 5*J.monomial(5)
383 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x,False)
384 sage: K.vector_space()
385 Vector space of degree 6 and dimension 3 over...
390 sage: (x^0).to_vector()
392 sage: (x^1).to_vector()
394 sage: (x^2).to_vector()
398 return self
._vector
_space
401 Element
= FiniteDimensionalEuclideanJordanElementSubalgebraElement