]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/euclidean_jordan_algebra.py
eja: begin implementing an element class.
[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
44 def __pow__(self, n):
45 """
46 Return ``self`` raised to the power ``n``.
47
48 Jordan algebras are always power-associative; see for
49 example Faraut and Koranyi, Proposition II.1.2 (ii).
50 """
51 A = self.parent()
52 if n == 0:
53 return A.one()
54 elif n == 1:
55 return self
56 else:
57 return A.element_class(A, self.vector()*(self.matrix()**(n-1)))
58
59
60 def degree(self):
61 """
62 Compute the degree of this element the straightforward way
63 according to the definition; by appending powers to a list
64 and figuring out its dimension (that is, whether or not
65 they're linearly dependent).
66
67 EXAMPLES::
68
69 sage: J = eja_ln(4)
70 sage: J.one().degree()
71 1
72 sage: e0,e1,e2,e3 = J.gens()
73 sage: (e0 - e1).degree()
74 2
75
76 """
77 d = 0
78 V = self.vector().parent()
79 vectors = [(self**d).vector()]
80 while V.span(vectors).dimension() > d:
81 d += 1
82 vectors.append((self**d).vector())
83 return d
84
85 def minimal_polynomial(self):
86 return self.matrix().minimal_polynomial()
87
88 def characteristic_polynomial(self):
89 return self.matrix().characteristic_polynomial()
90
91
92 def eja_rn(dimension, field=QQ):
93 """
94 Return the Euclidean Jordan Algebra corresponding to the set
95 `R^n` under the Hadamard product.
96
97 EXAMPLES:
98
99 This multiplication table can be verified by hand::
100
101 sage: J = eja_rn(3)
102 sage: e0,e1,e2 = J.gens()
103 sage: e0*e0
104 e0
105 sage: e0*e1
106 0
107 sage: e0*e2
108 0
109 sage: e1*e1
110 e1
111 sage: e1*e2
112 0
113 sage: e2*e2
114 e2
115
116 """
117 # The FiniteDimensionalAlgebra constructor takes a list of
118 # matrices, the ith representing right multiplication by the ith
119 # basis element in the vector space. So if e_1 = (1,0,0), then
120 # right (Hadamard) multiplication of x by e_1 picks out the first
121 # component of x; and likewise for the ith basis element e_i.
122 Qs = [ matrix(field, dimension, dimension, lambda k,j: 1*(k == j == i))
123 for i in xrange(dimension) ]
124
125 # Assuming associativity is wrong here, but it works to
126 # temporarily trick the Jordan algebra constructor into using the
127 # multiplication table.
128 return FiniteDimensionalEuclideanJordanAlgebra(field,Qs)
129
130
131 def eja_ln(dimension, field=QQ):
132 """
133 Return the Jordan algebra corresponding to the Lorentz "ice cream"
134 cone of the given ``dimension``.
135
136 EXAMPLES:
137
138 This multiplication table can be verified by hand::
139
140 sage: J = eja_ln(4)
141 sage: e0,e1,e2,e3 = J.gens()
142 sage: e0*e0
143 e0
144 sage: e0*e1
145 e1
146 sage: e0*e2
147 e2
148 sage: e0*e3
149 e3
150 sage: e1*e2
151 0
152 sage: e1*e3
153 0
154 sage: e2*e3
155 0
156
157 In one dimension, this is the reals under multiplication::
158
159 sage: J1 = eja_ln(1)
160 sage: J2 = eja_rn(1)
161 sage: J1 == J2
162 True
163
164 """
165 Qs = []
166 id_matrix = identity_matrix(field,dimension)
167 for i in xrange(dimension):
168 ei = id_matrix.column(i)
169 Qi = zero_matrix(field,dimension)
170 Qi.set_row(0, ei)
171 Qi.set_column(0, ei)
172 Qi += diagonal_matrix(dimension, [ei[0]]*dimension)
173 # The addition of the diagonal matrix adds an extra ei[0] in the
174 # upper-left corner of the matrix.
175 Qi[0,0] = Qi[0,0] * ~field(2)
176 Qs.append(Qi)
177
178 return FiniteDimensionalEuclideanJordanAlgebra(field,Qs)