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]
131 # This list is guaranteed to contain all independent powers,
132 # because it's the maximal set of powers that could possibly
133 # be independent (by a dimension argument).
134 powers
= [ elt
**k
for k
in range(V
.dimension()) ]
136 if orthonormalize_basis
== False:
137 # In this case, we just need to figure out which elements
138 # of the "powers" list are redundant... First compute the
139 # vector subspace spanned by the powers of the given
141 power_vectors
= [ p
.to_vector() for p
in powers
]
143 # Figure out which powers form a linearly-independent set.
144 ind_rows
= matrix(field
, power_vectors
).pivot_rows()
146 # Pick those out of the list of all powers.
147 superalgebra_basis
= tuple(map(powers
.__getitem
__, ind_rows
))
149 # If our superalgebra is a subalgebra of something else, then
150 # these vectors won't have the right coordinates for
151 # V.span_of_basis() unless we use V.from_vector() on them.
152 basis_vectors
= map(power_vectors
.__getitem
__, ind_rows
)
154 # If we're going to orthonormalize the basis anyway, we
155 # might as well just do Gram-Schmidt on the whole list of
156 # powers. The redundant ones will get zero'd out.
157 superalgebra_basis
= gram_schmidt(powers
)
158 basis_vectors
= [ b
.to_vector() for b
in superalgebra_basis
]
160 W
= V
.span_of_basis( V
.from_vector(v
) for v
in basis_vectors
)
161 n
= len(superalgebra_basis
)
162 mult_table
= [[W
.zero() for i
in range(n
)] for j
in range(n
)]
165 product
= superalgebra_basis
[i
]*superalgebra_basis
[j
]
166 # product.to_vector() might live in a vector subspace
167 # if our parent algebra is already a subalgebra. We
168 # use V.from_vector() to make it "the right size" in
170 product_vector
= V
.from_vector(product
.to_vector())
171 mult_table
[i
][j
] = W
.coordinate_vector(product_vector
)
173 # The rank is the highest possible degree of a minimal
174 # polynomial, and is bounded above by the dimension. We know
175 # in this case that there's an element whose minimal
176 # polynomial has the same degree as the space's dimension
177 # (remember how we constructed the space?), so that must be
181 natural_basis
= tuple( b
.natural_representation()
182 for b
in superalgebra_basis
)
185 self
._vector
_space
= W
186 self
._superalgebra
_basis
= superalgebra_basis
189 fdeja
= super(FiniteDimensionalEuclideanJordanElementSubalgebra
, self
)
190 return fdeja
.__init
__(field
,
195 natural_basis
=natural_basis
)
198 def _a_regular_element(self
):
200 Override the superalgebra method to return the one
201 regular element that is sure to exist in this
202 subalgebra, namely the element that generated it.
206 sage: from mjo.eja.eja_algebra import random_eja
210 sage: set_random_seed()
211 sage: J = random_eja().random_element().subalgebra_generated_by()
212 sage: J._a_regular_element().is_regular()
216 if self
.dimension() == 0:
219 return self
.monomial(1)
222 def _element_constructor_(self
, elt
):
224 Construct an element of this subalgebra from the given one.
225 The only valid arguments are elements of the parent algebra
226 that happen to live in this subalgebra.
230 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
231 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
235 sage: J = RealSymmetricEJA(3)
236 sage: x = sum( i*J.gens()[i] for i in range(6) )
237 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x,False)
238 sage: [ K(x^k) for k in range(J.rank()) ]
245 # Just as in the superalgebra class, we need to hack
246 # this special case to ensure that random_element() can
247 # coerce a ring zero into the algebra.
250 if elt
in self
.superalgebra():
251 coords
= self
.vector_space().coordinate_vector(elt
.to_vector())
252 return self
.from_vector(coords
)
258 Return the multiplicative identity element of this algebra.
260 The superclass method computes the identity element, which is
261 beyond overkill in this case: the superalgebra identity
262 restricted to this algebra is its identity. Note that we can't
263 count on the first basis element being the identity -- it migth
264 have been scaled if we orthonormalized the basis.
268 sage: from mjo.eja.eja_algebra import (RealCartesianProductEJA,
273 sage: J = RealCartesianProductEJA(5)
275 e0 + e1 + e2 + e3 + e4
276 sage: x = sum(J.gens())
277 sage: A = x.subalgebra_generated_by()
280 sage: A.one().superalgebra_element()
281 e0 + e1 + e2 + e3 + e4
285 The identity element acts like the identity over the rationals::
287 sage: set_random_seed()
288 sage: x = random_eja().random_element()
289 sage: A = x.subalgebra_generated_by()
290 sage: x = A.random_element()
291 sage: A.one()*x == x and x*A.one() == x
294 The identity element acts like the identity over the algebraic
295 reals with an orthonormal basis::
297 sage: set_random_seed()
298 sage: x = random_eja(AA).random_element()
299 sage: A = x.subalgebra_generated_by(orthonormalize_basis=True)
300 sage: x = A.random_element()
301 sage: A.one()*x == x and x*A.one() == x
304 The matrix of the unit element's operator is the identity over
307 sage: set_random_seed()
308 sage: x = random_eja().random_element()
309 sage: A = x.subalgebra_generated_by()
310 sage: actual = A.one().operator().matrix()
311 sage: expected = matrix.identity(A.base_ring(), A.dimension())
312 sage: actual == expected
315 The matrix of the unit element's operator is the identity over
316 the algebraic reals with an orthonormal basis::
318 sage: set_random_seed()
319 sage: x = random_eja(AA).random_element()
320 sage: A = x.subalgebra_generated_by(orthonormalize_basis=True)
321 sage: actual = A.one().operator().matrix()
322 sage: expected = matrix.identity(A.base_ring(), A.dimension())
323 sage: actual == expected
327 if self
.dimension() == 0:
330 sa_one
= self
.superalgebra().one().to_vector()
331 sa_coords
= self
.vector_space().coordinate_vector(sa_one
)
332 return self
.from_vector(sa_coords
)
335 def natural_basis_space(self
):
337 Return the natural basis space of this algebra, which is identical
338 to that of its superalgebra.
340 This is correct "by definition," and avoids a mismatch when the
341 subalgebra is trivial (with no natural basis to infer anything
342 from) and the parent is not.
344 return self
.superalgebra().natural_basis_space()
347 def superalgebra(self
):
349 Return the superalgebra that this algebra was generated from.
351 return self
._superalgebra
354 def vector_space(self
):
358 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
359 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
363 sage: J = RealSymmetricEJA(3)
364 sage: x = J.monomial(0) + 2*J.monomial(2) + 5*J.monomial(5)
365 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x,False)
366 sage: K.vector_space()
367 Vector space of degree 6 and dimension 3 over...
372 sage: (x^0).to_vector()
374 sage: (x^1).to_vector()
376 sage: (x^2).to_vector()
380 return self
._vector
_space
383 Element
= FiniteDimensionalEuclideanJordanElementSubalgebraElement