1 /*
2 * Copyright (c) 2007 - 2015 Joseph Gaeddert
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23 //
24 // Matrix method definitions
25 //
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 // add elements of two matrices
32 // _X : 1st input matrix [size: _R x _C]
33 // _Y : 2nd input matrix [size: _R x _C]
34 // _Z : output matrix [size: _R x _C]
35 // _R : number of rows
36 // _C : number of columns
MATRIX(_add)37 void MATRIX(_add)(T * _X,
38 T * _Y,
39 T * _Z,
40 unsigned int _R,
41 unsigned int _C)
42 {
43 unsigned int i;
44 for (i=0; i<(_R*_C); i++)
45 _Z[i] = _X[i] + _Y[i];
46 }
47
48 // subtract elements of two matrices
49 // _X : 1st input matrix [size: _R x _C]
50 // _Y : 2nd input matrix [size: _R x _C]
51 // _Z : output matrix [size: _R x _C]
52 // _R : number of rows
53 // _C : number of columns
MATRIX(_sub)54 void MATRIX(_sub)(T * _X,
55 T * _Y,
56 T * _Z,
57 unsigned int _R,
58 unsigned int _C)
59 {
60 unsigned int i;
61 for (i=0; i<(_R*_C); i++)
62 _Z[i] = _X[i] - _Y[i];
63 }
64
65 // point-wise multiplication
66 // _X : 1st input matrix [size: _R x _C]
67 // _Y : 2nd input matrix [size: _R x _C]
68 // _Z : output matrix [size: _R x _C]
69 // _R : number of rows
70 // _C : number of columns
MATRIX(_pmul)71 void MATRIX(_pmul)(T * _X,
72 T * _Y,
73 T * _Z,
74 unsigned int _R,
75 unsigned int _C)
76 {
77 unsigned int i;
78 for (i=0; i<(_R*_C); i++)
79 _Z[i] = _X[i] * _Y[i];
80 }
81
82 // point-wise division
83 // _X : 1st input matrix [size: _R x _C]
84 // _Y : 2nd input matrix [size: _R x _C]
85 // _Z : output matrix [size: _R x _C]
86 // _R : number of rows
87 // _C : number of columns
MATRIX(_pdiv)88 void MATRIX(_pdiv)(T * _X,
89 T * _Y,
90 T * _Z,
91 unsigned int _R,
92 unsigned int _C)
93 {
94 unsigned int i;
95 for (i=0; i<(_R*_C); i++)
96 _Z[i] = _X[i] / _Y[i];
97 }
98
99
100 // multiply two matrices together
MATRIX(_mul)101 void MATRIX(_mul)(T * _X, unsigned int _XR, unsigned int _XC,
102 T * _Y, unsigned int _YR, unsigned int _YC,
103 T * _Z, unsigned int _ZR, unsigned int _ZC)
104 {
105 // ensure lengths are valid
106 if (_ZR != _XR || _ZC != _YC || _XC != _YR ) {
107 fprintf(stderr,"error: matrix_mul(), invalid dimensions\n");
108 exit(1);
109 }
110
111 unsigned int r, c, i;
112 for (r=0; r<_ZR; r++) {
113 for (c=0; c<_ZC; c++) {
114 // z(i,j) = dotprod( x(i,:), y(:,j) )
115 T sum=0.0f;
116 for (i=0; i<_XC; i++) {
117 sum += matrix_access(_X,_XR,_XC,r,i) *
118 matrix_access(_Y,_YR,_YC,i,c);
119 }
120 matrix_access(_Z,_ZR,_ZC,r,c) = sum;
121 #ifdef DEBUG
122 printf("z(%u,%u) = ", r, c);
123 MATRIX_PRINT_ELEMENT(_Z,_ZR,_ZC,r,c);
124 printf("\n");
125 #endif
126 }
127 }
128 }
129
130 // augment matrices x and y:
131 // z = [x | y]
MATRIX(_aug)132 void MATRIX(_aug)(T * _x, unsigned int _rx, unsigned int _cx,
133 T * _y, unsigned int _ry, unsigned int _cy,
134 T * _z, unsigned int _rz, unsigned int _cz)
135 {
136 // ensure lengths are valid
137 if (_rz != _rx || _rz != _ry || _rx != _ry || _cz != _cx + _cy) {
138 fprintf(stderr,"error: matrix_aug(), invalid dimensions\n");
139 exit(1);
140 }
141
142 // TODO: improve speed with memmove
143 unsigned int r, c, n;
144 for (r=0; r<_rz; r++) {
145 n=0;
146 for (c=0; c<_cx; c++)
147 matrix_access(_z,_rz,_cz,r,n++) = matrix_access(_x,_rx,_cx,r,c);
148 for (c=0; c<_cy; c++)
149 matrix_access(_z,_rz,_cz,r,n++) = matrix_access(_y,_ry,_cy,r,c);
150 }
151 }
152
153 // solve set of linear equations
MATRIX(_div)154 void MATRIX(_div)(T * _X,
155 T * _Y,
156 T * _Z,
157 unsigned int _n)
158 {
159 // compute inv(_Y)
160 T Y_inv[_n*_n];
161 memmove(Y_inv, _Y, _n*_n*sizeof(T));
162 MATRIX(_inv)(Y_inv,_n,_n);
163
164 // _Z = _X * inv(_Y)
165 MATRIX(_mul)(_X, _n, _n,
166 Y_inv, _n, _n,
167 _Z, _n, _n);
168 }
169
170 // matrix determinant (2 x 2)
MATRIX(_det2x2)171 T MATRIX(_det2x2)(T * _X,
172 unsigned int _r,
173 unsigned int _c)
174 {
175 // validate input
176 if (_r != 2 || _c != 2) {
177 fprintf(stderr,"error: matrix_det2x2(), invalid dimensions\n");
178 exit(1);
179 }
180 return _X[0]*_X[3] - _X[1]*_X[2];
181 }
182
183 // matrix determinant (n x n)
MATRIX(_det)184 T MATRIX(_det)(T * _X,
185 unsigned int _r,
186 unsigned int _c)
187 {
188 // validate input
189 if (_r != _c) {
190 fprintf(stderr,"error: matrix_det(), matrix must be square\n");
191 exit(1);
192 }
193 unsigned int n = _r;
194 if (n==2) return MATRIX(_det2x2)(_X,2,2);
195
196 // compute L/U decomposition (Doolittle's method)
197 T L[n*n]; // lower
198 T U[n*n]; // upper
199 T P[n*n]; // permutation
200 MATRIX(_ludecomp_doolittle)(_X,n,n,L,U,P);
201
202 // evaluate along the diagonal of U
203 T det = 1.0;
204 unsigned int i;
205 for (i=0; i<n; i++)
206 det *= matrix_access(U,n,n,i,i);
207
208 return det;
209 }
210
211 // compute matrix transpose
MATRIX(_trans)212 void MATRIX(_trans)(T * _X,
213 unsigned int _XR,
214 unsigned int _XC)
215 {
216 // compute Hermitian transpose
217 MATRIX(_hermitian)(_X,_XR,_XC);
218
219 // conjugate elements
220 unsigned int i;
221 for (i=0; i<_XR*_XC; i++)
222 _X[i] = conj(_X[i]);
223 }
224
225 // compute matrix Hermitian transpose
MATRIX(_hermitian)226 void MATRIX(_hermitian)(T * _X,
227 unsigned int _XR,
228 unsigned int _XC)
229 {
230 T y[_XR*_XC];
231 memmove(y,_X,_XR*_XC*sizeof(T));
232
233 unsigned int r,c;
234 for (r=0; r<_XR; r++) {
235 for (c=0; c<_XC; c++) {
236 matrix_access(_X,_XC,_XR,c,r) = matrix_access(y,_XR,_XC,r,c);
237 }
238 }
239 }
240
241 // compute x*x' on m x n matrix, result: m x m
MATRIX(_mul_transpose)242 void MATRIX(_mul_transpose)(T * _x,
243 unsigned int _m,
244 unsigned int _n,
245 T * _xxT)
246 {
247 unsigned int r;
248 unsigned int c;
249 unsigned int i;
250
251 // clear _xxT
252 for (i=0; i<_m*_m; i++)
253 _xxT[i] = 0.0f;
254
255 //
256 T sum = 0;
257 for (r=0; r<_m; r++) {
258
259 for (c=0; c<_m; c++) {
260 sum = 0.0f;
261
262 for (i=0; i<_n; i++) {
263 T prod = matrix_access(_x,_m,_n,r,i) *
264 conjf( matrix_access(_x,_m,_n,c,i) );
265 sum += prod;
266 }
267
268 matrix_access(_xxT,_m,_m,r,c) = sum;
269 }
270 }
271 }
272
273
274 // compute x'*x on m x n matrix, result: n x n
MATRIX(_transpose_mul)275 void MATRIX(_transpose_mul)(T * _x,
276 unsigned int _m,
277 unsigned int _n,
278 T * _xTx)
279 {
280 unsigned int r;
281 unsigned int c;
282 unsigned int i;
283
284 // clear _xTx
285 for (i=0; i<_n*_n; i++)
286 _xTx[i] = 0.0f;
287
288 //
289 T sum = 0;
290 for (r=0; r<_n; r++) {
291
292 for (c=0; c<_n; c++) {
293 sum = 0.0f;
294
295 for (i=0; i<_m; i++) {
296 T prod = conjf( matrix_access(_x,_m,_n,i,r) ) *
297 matrix_access(_x,_m,_n,i,c);
298 sum += prod;
299 }
300
301 matrix_access(_xTx,_n,_n,r,c) = sum;
302 }
303 }
304 }
305
306
307 // compute x*x.' on m x n matrix, result: m x m
MATRIX(_mul_hermitian)308 void MATRIX(_mul_hermitian)(T * _x,
309 unsigned int _m,
310 unsigned int _n,
311 T * _xxH)
312 {
313 unsigned int r;
314 unsigned int c;
315 unsigned int i;
316
317 // clear _xxH
318 for (i=0; i<_m*_m; i++)
319 _xxH[i] = 0.0f;
320
321 //
322 T sum = 0;
323 for (r=0; r<_m; r++) {
324
325 for (c=0; c<_m; c++) {
326 sum = 0.0f;
327
328 for (i=0; i<_n; i++) {
329 sum += matrix_access(_x,_m,_n,r,i) *
330 matrix_access(_x,_m,_n,c,i);
331 }
332
333 matrix_access(_xxH,_m,_m,r,c) = sum;
334 }
335 }
336 }
337
338
339 // compute x.'*x on m x n matrix, result: n x n
MATRIX(_hermitian_mul)340 void MATRIX(_hermitian_mul)(T * _x,
341 unsigned int _m,
342 unsigned int _n,
343 T * _xHx)
344 {
345 unsigned int r;
346 unsigned int c;
347 unsigned int i;
348
349 // clear _xHx
350 for (i=0; i<_n*_n; i++)
351 _xHx[i] = 0.0f;
352
353 //
354 T sum = 0;
355 for (r=0; r<_n; r++) {
356
357 for (c=0; c<_n; c++) {
358 sum = 0.0f;
359
360 for (i=0; i<_m; i++) {
361 sum += matrix_access(_x,_m,_n,i,r) *
362 matrix_access(_x,_m,_n,i,c);
363 }
364
365 matrix_access(_xHx,_n,_n,r,c) = sum;
366 }
367 }
368 }
369
370