]> gitweb.michael.orlitzky.com - dunshire.git/blob - src/dunshire/matrices.py
More "easy" docs work in matrices.py/options.py.
[dunshire.git] / src / dunshire / matrices.py
1 """
2 Utility functions for working with CVXOPT matrices (instances of the
3 class:`cvxopt.base.matrix` class).
4 """
5
6 from math import sqrt
7 from cvxopt import matrix
8 from cvxopt.lapack import syev
9
10 import options
11
12
13 def append_col(left, right):
14 """
15 Append two matrices side-by-side.
16
17 Parameters
18 ----------
19
20 left, right : matrix
21 The two matrices to append to one another.
22
23 Returns
24 -------
25
26 matrix
27 A new matrix consisting of ``right`` appended to the right
28 of ``left``.
29
30 Examples
31 --------
32
33 >>> A = matrix([1,2,3,4], (2,2))
34 >>> B = matrix([5,6,7,8,9,10], (2,3))
35 >>> print(A)
36 [ 1 3]
37 [ 2 4]
38 <BLANKLINE>
39 >>> print(B)
40 [ 5 7 9]
41 [ 6 8 10]
42 <BLANKLINE>
43 >>> print(append_col(A,B))
44 [ 1 3 5 7 9]
45 [ 2 4 6 8 10]
46 <BLANKLINE>
47
48 """
49 return matrix([left.trans(), right.trans()]).trans()
50
51
52 def append_row(top, bottom):
53 """
54 Append two matrices top-to-bottom.
55
56 Parameters
57 ----------
58
59 top, bottom : matrix
60 The two matrices to append to one another.
61
62 Returns
63 -------
64
65 matrix
66 A new matrix consisting of ``bottom`` appended below ``top``.
67
68 Examples
69 --------
70
71 >>> A = matrix([1,2,3,4], (2,2))
72 >>> B = matrix([5,6,7,8,9,10], (3,2))
73 >>> print(A)
74 [ 1 3]
75 [ 2 4]
76 <BLANKLINE>
77 >>> print(B)
78 [ 5 8]
79 [ 6 9]
80 [ 7 10]
81 <BLANKLINE>
82 >>> print(append_row(A,B))
83 [ 1 3]
84 [ 2 4]
85 [ 5 8]
86 [ 6 9]
87 [ 7 10]
88 <BLANKLINE>
89
90 """
91 return matrix([top, bottom])
92
93
94 def eigenvalues(symmat):
95 """
96 Return the eigenvalues of the given symmetric real matrix.
97
98 Parameters
99 ----------
100
101 symmat : matrix
102 The real symmetric matrix whose eigenvalues you want.
103
104 Returns
105 -------
106
107 list of float
108 A list of the eigenvalues (in no particular order) of ``symmat``.
109
110 Raises
111 ------
112
113 TypeError
114 If the input matrix is not symmetric.
115
116 Examples
117 --------
118
119 >>> A = matrix([[2,1],[1,2]], tc='d')
120 >>> eigenvalues(A)
121 [1.0, 3.0]
122
123 If the input matrix is not symmetric, it may not have real
124 eigenvalues, and we don't know what to do::
125
126 >>> A = matrix([[1,2],[3,4]])
127 >>> eigenvalues(A)
128 Traceback (most recent call last):
129 ...
130 TypeError: input must be a symmetric real matrix
131
132 """
133 if not norm(symmat.trans() - symmat) < options.ABS_TOL:
134 # Ensure that ``symmat`` is symmetric (and thus square).
135 raise TypeError('input must be a symmetric real matrix')
136
137 domain_dim = symmat.size[0]
138 eigs = matrix(0, (domain_dim, 1), tc='d')
139 syev(symmat, eigs)
140 return list(eigs)
141
142
143 def identity(domain_dim):
144 """
145 Create an identity matrix of the given dimensions.
146
147 Parameters
148 ----------
149
150 domain_dim : int
151 The dimension of the vector space on which the identity will act.
152
153 Returns
154 -------
155
156 matrix
157 A ``domain_dim``-by-``domain_dim`` dense integer identity matrix.
158
159 Examples
160 --------
161
162 >>> print(identity(3))
163 [ 1 0 0]
164 [ 0 1 0]
165 [ 0 0 1]
166 <BLANKLINE>
167
168 """
169 if domain_dim <= 0:
170 raise ValueError('domain dimension must be positive')
171
172 entries = [int(i == j)
173 for i in range(domain_dim)
174 for j in range(domain_dim)]
175 return matrix(entries, (domain_dim, domain_dim))
176
177
178 def inner_product(vec1, vec2):
179 """
180 Compute the Euclidean inner product of two vectors.
181
182 Parameters
183 ----------
184
185 vec1, vec2 : matrix
186 The two vectors whose inner product you want.
187
188 Returns
189 -------
190
191 float
192 The inner product of ``vec1`` and ``vec2``.
193
194 Examples
195 --------
196
197 >>> x = [1,2,3]
198 >>> y = [3,4,1]
199 >>> inner_product(x,y)
200 14
201
202 >>> x = matrix([1,1,1])
203 >>> y = matrix([2,3,4], (1,3))
204 >>> inner_product(x,y)
205 9
206
207 >>> x = [1,2,3]
208 >>> y = [1,1]
209 >>> inner_product(x,y)
210 Traceback (most recent call last):
211 ...
212 TypeError: the lengths of vec1 and vec2 must match
213
214 """
215 if not len(vec1) == len(vec2):
216 raise TypeError('the lengths of vec1 and vec2 must match')
217
218 return sum([x*y for (x, y) in zip(vec1, vec2)])
219
220
221 def norm(matrix_or_vector):
222 """
223 Return the Frobenius norm of a matrix or vector.
224
225 When the input is a vector, its matrix-Frobenius norm is the same
226 thing as its vector-Euclidean norm.
227
228 Parameters
229 ----------
230
231 matrix_or_vector : matrix
232 The matrix or vector whose norm you want.
233
234 Returns
235 -------
236
237 float
238 The norm of ``matrix_or_vector``.
239
240 Examples
241 --------
242
243 >>> v = matrix([1,1])
244 >>> print('{:.5f}'.format(norm(v)))
245 1.41421
246
247 >>> A = matrix([1,1,1,1], (2,2))
248 >>> norm(A)
249 2.0
250
251 """
252 return sqrt(inner_product(matrix_or_vector, matrix_or_vector))
253
254
255 def vec(mat):
256 """
257 Create a long vector in column-major order from ``mat``.
258
259 Parameters
260 ----------
261
262 mat : matrix
263 Any sort of real matrix that you want written as a long vector.
264
265 Returns
266 -------
267
268 matrix
269 An ``len(mat)``-by-``1`` long column vector containign the
270 entries of ``mat`` in column major order.
271
272 Examples
273 --------
274
275 >>> A = matrix([[1,2],[3,4]])
276 >>> print(A)
277 [ 1 3]
278 [ 2 4]
279 <BLANKLINE>
280
281 >>> print(vec(A))
282 [ 1]
283 [ 2]
284 [ 3]
285 [ 4]
286 <BLANKLINE>
287
288 Note that if ``mat`` is a vector, this function is a no-op:
289
290 >>> v = matrix([1,2,3,4], (4,1))
291 >>> print(v)
292 [ 1]
293 [ 2]
294 [ 3]
295 [ 4]
296 <BLANKLINE>
297 >>> print(vec(v))
298 [ 1]
299 [ 2]
300 [ 3]
301 [ 4]
302 <BLANKLINE>
303
304 """
305 return matrix(mat, (len(mat), 1))