]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/euclidean_jordan_algebra.py
8487e0ecea385d00f45c176bdc43b45d31d617ff
[sage.d.git] / mjo / eja / euclidean_jordan_algebra.py
1 """
2 Euclidean Jordan Algebras. These are formally-real Jordan Algebras;
3 specifically those where u^2 + v^2 = 0 implies that u = v = 0. They
4 are used in optimization, and have some additional nice methods beyond
5 what can be supported in a general Jordan Algebra.
6 """
7
8 from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra import FiniteDimensionalAlgebra
9 from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra_element import FiniteDimensionalAlgebraElement
10
11 class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
12 @staticmethod
13 def __classcall__(cls, field, mult_table, names='e', category=None):
14 fda = super(FiniteDimensionalEuclideanJordanAlgebra, cls)
15 return fda.__classcall_private__(cls,
16 field,
17 mult_table,
18 names,
19 category)
20
21 def __init__(self, field, mult_table, names='e', category=None):
22 fda = super(FiniteDimensionalEuclideanJordanAlgebra, self)
23 fda.__init__(field, mult_table, names, category)
24
25
26 def _repr_(self):
27 """
28 Return a string representation of ``self``.
29 """
30 return "Euclidean Jordan algebra of degree {} over {}".format(self.degree(), self.base_ring())
31
32 def rank(self):
33 """
34 Return the rank of this EJA.
35 """
36 raise NotImplementedError
37
38
39 class Element(FiniteDimensionalAlgebraElement):
40 """
41 An element of a Euclidean Jordan algebra.
42
43 Since EJAs are commutative, the "right multiplication" matrix is
44 also the left multiplication matrix and must be symmetric::
45
46 sage: set_random_seed()
47 sage: J = eja_ln(5)
48 sage: J.random_element().matrix().is_symmetric()
49 True
50
51 """
52
53 def __pow__(self, n):
54 """
55 Return ``self`` raised to the power ``n``.
56
57 Jordan algebras are always power-associative; see for
58 example Faraut and Koranyi, Proposition II.1.2 (ii).
59 """
60 A = self.parent()
61 if n == 0:
62 return A.one()
63 elif n == 1:
64 return self
65 else:
66 return A.element_class(A, self.vector()*(self.matrix()**(n-1)))
67
68
69 def span_of_powers(self):
70 """
71 Return the vector space spanned by successive powers of
72 this element.
73 """
74 # The dimension of the subalgebra can't be greater than
75 # the big algebra, so just put everything into a list
76 # and let span() get rid of the excess.
77 V = self.vector().parent()
78 return V.span( (self**d).vector() for d in xrange(V.dimension()) )
79
80
81 def degree(self):
82 """
83 Compute the degree of this element the straightforward way
84 according to the definition; by appending powers to a list
85 and figuring out its dimension (that is, whether or not
86 they're linearly dependent).
87
88 EXAMPLES::
89
90 sage: J = eja_ln(4)
91 sage: J.one().degree()
92 1
93 sage: e0,e1,e2,e3 = J.gens()
94 sage: (e0 - e1).degree()
95 2
96
97 In the spin factor algebra (of rank two), all elements that
98 aren't multiples of the identity are regular::
99
100 sage: set_random_seed()
101 sage: n = ZZ.random_element(1,10).abs()
102 sage: J = eja_ln(n)
103 sage: x = J.random_element()
104 sage: x == x.coefficient(0)*J.one() or x.degree() == 2
105 True
106
107 """
108 return self.span_of_powers().dimension()
109
110
111 def minimal_polynomial(self):
112 return self.matrix().minimal_polynomial()
113
114 def characteristic_polynomial(self):
115 return self.matrix().characteristic_polynomial()
116
117
118 def eja_rn(dimension, field=QQ):
119 """
120 Return the Euclidean Jordan Algebra corresponding to the set
121 `R^n` under the Hadamard product.
122
123 EXAMPLES:
124
125 This multiplication table can be verified by hand::
126
127 sage: J = eja_rn(3)
128 sage: e0,e1,e2 = J.gens()
129 sage: e0*e0
130 e0
131 sage: e0*e1
132 0
133 sage: e0*e2
134 0
135 sage: e1*e1
136 e1
137 sage: e1*e2
138 0
139 sage: e2*e2
140 e2
141
142 """
143 # The FiniteDimensionalAlgebra constructor takes a list of
144 # matrices, the ith representing right multiplication by the ith
145 # basis element in the vector space. So if e_1 = (1,0,0), then
146 # right (Hadamard) multiplication of x by e_1 picks out the first
147 # component of x; and likewise for the ith basis element e_i.
148 Qs = [ matrix(field, dimension, dimension, lambda k,j: 1*(k == j == i))
149 for i in xrange(dimension) ]
150
151 return FiniteDimensionalEuclideanJordanAlgebra(field,Qs)
152
153
154 def eja_ln(dimension, field=QQ):
155 """
156 Return the Jordan algebra corresponding to the Lorentz "ice cream"
157 cone of the given ``dimension``.
158
159 EXAMPLES:
160
161 This multiplication table can be verified by hand::
162
163 sage: J = eja_ln(4)
164 sage: e0,e1,e2,e3 = J.gens()
165 sage: e0*e0
166 e0
167 sage: e0*e1
168 e1
169 sage: e0*e2
170 e2
171 sage: e0*e3
172 e3
173 sage: e1*e2
174 0
175 sage: e1*e3
176 0
177 sage: e2*e3
178 0
179
180 In one dimension, this is the reals under multiplication::
181
182 sage: J1 = eja_ln(1)
183 sage: J2 = eja_rn(1)
184 sage: J1 == J2
185 True
186
187 """
188 Qs = []
189 id_matrix = identity_matrix(field,dimension)
190 for i in xrange(dimension):
191 ei = id_matrix.column(i)
192 Qi = zero_matrix(field,dimension)
193 Qi.set_row(0, ei)
194 Qi.set_column(0, ei)
195 Qi += diagonal_matrix(dimension, [ei[0]]*dimension)
196 # The addition of the diagonal matrix adds an extra ei[0] in the
197 # upper-left corner of the matrix.
198 Qi[0,0] = Qi[0,0] * ~field(2)
199 Qs.append(Qi)
200
201 return FiniteDimensionalEuclideanJordanAlgebra(field,Qs)