]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/euclidean_jordan_algebra.py
eja: test that left-mult matrices are symmetric.
[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 """
98 return self.span_of_powers().dimension()
99
100
101 def minimal_polynomial(self):
102 return self.matrix().minimal_polynomial()
103
104 def characteristic_polynomial(self):
105 return self.matrix().characteristic_polynomial()
106
107
108 def eja_rn(dimension, field=QQ):
109 """
110 Return the Euclidean Jordan Algebra corresponding to the set
111 `R^n` under the Hadamard product.
112
113 EXAMPLES:
114
115 This multiplication table can be verified by hand::
116
117 sage: J = eja_rn(3)
118 sage: e0,e1,e2 = J.gens()
119 sage: e0*e0
120 e0
121 sage: e0*e1
122 0
123 sage: e0*e2
124 0
125 sage: e1*e1
126 e1
127 sage: e1*e2
128 0
129 sage: e2*e2
130 e2
131
132 """
133 # The FiniteDimensionalAlgebra constructor takes a list of
134 # matrices, the ith representing right multiplication by the ith
135 # basis element in the vector space. So if e_1 = (1,0,0), then
136 # right (Hadamard) multiplication of x by e_1 picks out the first
137 # component of x; and likewise for the ith basis element e_i.
138 Qs = [ matrix(field, dimension, dimension, lambda k,j: 1*(k == j == i))
139 for i in xrange(dimension) ]
140
141 return FiniteDimensionalEuclideanJordanAlgebra(field,Qs)
142
143
144 def eja_ln(dimension, field=QQ):
145 """
146 Return the Jordan algebra corresponding to the Lorentz "ice cream"
147 cone of the given ``dimension``.
148
149 EXAMPLES:
150
151 This multiplication table can be verified by hand::
152
153 sage: J = eja_ln(4)
154 sage: e0,e1,e2,e3 = J.gens()
155 sage: e0*e0
156 e0
157 sage: e0*e1
158 e1
159 sage: e0*e2
160 e2
161 sage: e0*e3
162 e3
163 sage: e1*e2
164 0
165 sage: e1*e3
166 0
167 sage: e2*e3
168 0
169
170 In one dimension, this is the reals under multiplication::
171
172 sage: J1 = eja_ln(1)
173 sage: J2 = eja_rn(1)
174 sage: J1 == J2
175 True
176
177 """
178 Qs = []
179 id_matrix = identity_matrix(field,dimension)
180 for i in xrange(dimension):
181 ei = id_matrix.column(i)
182 Qi = zero_matrix(field,dimension)
183 Qi.set_row(0, ei)
184 Qi.set_column(0, ei)
185 Qi += diagonal_matrix(dimension, [ei[0]]*dimension)
186 # The addition of the diagonal matrix adds an extra ei[0] in the
187 # upper-left corner of the matrix.
188 Qi[0,0] = Qi[0,0] * ~field(2)
189 Qs.append(Qi)
190
191 return FiniteDimensionalEuclideanJordanAlgebra(field,Qs)