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