Loading...
Searching...
No Matches
MatrixUtils.h
Go to the documentation of this file.
1/* Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
2
3 This file is part of the TerraLib - a Framework for building GIS enabled applications.
4
5 TerraLib is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 TerraLib is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with TerraLib. See COPYING. If not, write to
17 TerraLib Team at <terralib-team@terralib.org>.
18 */
19
20/*!
21 \file terralib/common/MatrixUtils.h
22
23 \brief Matrix manipulation utils.
24
25 \ingroup common
26*/
27
28#ifndef __TERRALIB_COMMON_INTERNAL_MATRIXUTILS_H
29#define __TERRALIB_COMMON_INTERNAL_MATRIXUTILS_H
30
31// TerraLib
32#include "Config.h"
33
34// STL
35#include <cassert>
36
37// Boost
38#include <boost/numeric/ublas/io.hpp>
39#include <boost/numeric/ublas/lu.hpp>
40#include <boost/numeric/ublas/matrix.hpp>
41#include <boost/numeric/ublas/triangular.hpp>
42#include <boost/numeric/ublas/vector.hpp>
43#include <boost/numeric/ublas/vector_proxy.hpp>
44
45namespace te
46{
47 namespace common
48 {
49 /*!
50 \brief Get the Matrix determinant value.
51
52 \param inputMatrix Input matrix.
53
54 \return true if ok, false on errors.
55 */
56 template<class T>
57 bool GetDeterminant(const boost::numeric::ublas::matrix<T>& inputMatrix,
58 T& determinant)
59 {
60 if( ( inputMatrix.size1() == 0 ) || ( inputMatrix.size2() == 0 ) )
61 {
62 return false;
63 }
64
65 // create a working copy of the input
66 boost::numeric::ublas::matrix<T> A( inputMatrix );
67
68 const unsigned int size1 = static_cast<unsigned int>(A.size1());
69
70 boost::numeric::ublas::permutation_matrix<std::size_t> pm( size1 );
71
72 if( boost::numeric::ublas::lu_factorize( A, pm ) != 0.0 )
73 {
74 // singular matrix case
75 determinant = 0;
76 }
77 else
78 {
79 double pmSign = 1.0;
80 for ( unsigned int pmi = 0; pmi < size1; ++pmi)
81 if ( pmi != pm( pmi ) )
82 pmSign *= -1.0; // swap_rows would swap a pair of rows here, so we change sign
83
84 determinant = 1.0;
85
86 for( unsigned int i = 0 ; i < size1 ; i++ )
87 determinant *= A(i,i); // multiply by elements on diagonal
88
89 determinant = determinant * pmSign;
90 }
91
92 return true;
93 }
94
95 template<class T>
96 bool GetDeterminantComplex(const boost::numeric::ublas::matrix<T>& inputMatrix,
97 T& determinant)
98 {
99 if( ( inputMatrix.size1() == 0 ) || ( inputMatrix.size2() == 0 ) )
100 {
101 determinant = 0.0;
102 return true;
103 }
104
105 // create a working copy of the input
106 boost::numeric::ublas::matrix<T> A( inputMatrix );
107
108 const unsigned int size1 = A.size1();
109
110 boost::numeric::ublas::permutation_matrix<std::size_t> pm( size1 );
111
112 if( boost::numeric::ublas::lu_factorize( A, pm ) != 0.0 )
113 {
114 return false;
115 }
116 else
117 {
118 double pmSign = 1.0;
119 for ( unsigned int pmi = 0; pmi < size1; ++pmi)
120 if ( pmi != pm( pmi ) )
121 pmSign *= -1.0; // swap_rows would swap a pair of rows here, so we change sign
122
123 determinant = 1.0;
124
125 for( unsigned int i = 0 ; i < size1 ; i++ )
126 determinant *= A(i,i); // multiply by elements on diagonal
127
128 determinant = determinant * pmSign;
129
130 return true;
131 }
132 }
133
134 /*!
135 \brief Matrix inversion.
136
137 \param inputMatrix Input matrix.
138 \param outputMatrix Output matrix.
139
140 \return true if ok, false on errors.
141 */
142 template<class T>
143 bool GetInverseMatrix(const boost::numeric::ublas::matrix<T>& inputMatrix,
144 boost::numeric::ublas::matrix<T>& outputMatrix)
145 {
146 assert( inputMatrix.size1() == inputMatrix.size2() );
147
148 // create a working copy of the input
149 boost::numeric::ublas::matrix<T> A( inputMatrix );
150
151 // create a permutation matrix for the LU-factorization
152 boost::numeric::ublas::permutation_matrix<std::size_t> pm( A.size1() );
153
154 // perform LU-factorization
155 if( boost::numeric::ublas::lu_factorize( A, pm ) != 0 )
156 {
157 return false;
158 }
159 else
160 {
161 // create identity matrix of "inverse"
162 outputMatrix = boost::numeric::ublas::identity_matrix<T>( A.size1() );
163
164 // backsubstitute to get the inverse
165 try
166 {
167 boost::numeric::ublas::lu_substitute( A, pm, outputMatrix );
168 }
169 catch(...)
170 {
171 return false;
172 }
173
174 return true;
175 }
176 }
177
178 /*!
179 \brief Pseudo matrix inversion.
180
181 \param inputMatrix Input matrix.
182 \param outputMatrix Output matrix.
183
184 \return true if ok, false on errors.
185
186 \note PinvX = Inv( Xt * X ) * Xt, where Inv=Inverse and Xt is the transposed matrix of X.
187 \note A* = inv(trasnp(A) * A) * transp(A) (i>j)
188 \note A* = transp(A) * inv(A * trasnp(A)) (i<j)
189 */
190 template<class T>
191 bool GetPseudoInverseMatrix(const boost::numeric::ublas::matrix<T>& inputMatrix,
192 boost::numeric::ublas::matrix<T>& outputMatrix)
193 {
194 if( inputMatrix.size1() > inputMatrix.size2() )
195 {
196 boost::numeric::ublas::matrix<T> trans( boost::numeric::ublas::trans(
197 inputMatrix ) );
198
199 boost::numeric::ublas::matrix<T> aux1( boost::numeric::ublas::prod( trans,
200 inputMatrix ) );
201
202 boost::numeric::ublas::matrix<T> aux1Inv;
203
204 if( GetInverseMatrix( aux1, aux1Inv ) )
205 {
206 outputMatrix = boost::numeric::ublas::prod( aux1Inv, trans );
207 return true;
208 }
209 else
210 {
211 return false;
212 }
213 }
214 else if( inputMatrix.size1() < inputMatrix.size2() )
215 {
216 boost::numeric::ublas::matrix<T> trans( boost::numeric::ublas::trans(
217 inputMatrix ) );
218
219 boost::numeric::ublas::matrix<T> aux1( boost::numeric::ublas::prod(
220 inputMatrix, trans ) );
221
222 boost::numeric::ublas::matrix<T> aux1Inv;
223
224 if( GetInverseMatrix( aux1, aux1Inv ) )
225 {
226 outputMatrix = boost::numeric::ublas::prod( trans, aux1Inv );
227 return true;
228 }
229 else
230 {
231 return false;
232 }
233 }
234 else
235 {
236 return GetInverseMatrix( inputMatrix, outputMatrix );
237 }
238 }
239
240 /*!
241 \brief Computes the eigenvectors of a given matrix.
242
243 \param inputMatrix The input matrix.
244 \param eigenVectorsMatrix The matrix where the eigenvectors will be stored.
245 \param eigenValuesMatrix The matrix where the eigenvalues will be stored.
246
247 \return true if ok, false on errors.
248 */
249 template<class T>
250 bool EigenVectors(const boost::numeric::ublas::matrix<T>& inputMatrix, boost::numeric::ublas::matrix<T> &eigenVectorsMatrix, boost::numeric::ublas::matrix<T> &eigenValuesMatrix)
251 {
252// this source code is based on TerraLib 4
253 double *cov = NULL, // covariance matrix
254 *e_val = NULL, // eigenvalue matrix
255 *e_vec = NULL; // eigenvector matrix
256
257 int dim = (int)inputMatrix.size1();
258
259 int i, j, ij, k,
260 ia, ind, l, m,
261 mq, lm, ll, mm,
262 ilq, imq, im, iq,
263 il, lq, ilr, imr,
264 jq;
265
266 double range, fdim, anorm, anrmx,
267 thr, x, y, z,
268 sinx, cosx, sinx2, cosx2,
269 sincs;
270
271 if (dim <= 0)
272 return false; // print invalid matrix
273
274 eigenVectorsMatrix.resize(dim, dim);
275 eigenVectorsMatrix.clear();
276 for (i = 0; i < dim; i++)
277 eigenVectorsMatrix(i, i) = 1.0;
278
279 int fat = (dim * dim + dim) / 2;
280 range = 1.0e-6;
281 fdim = dim;
282
283 cov = new double[fat];
284 e_vec = new double[dim * dim];
285 e_val = new double[fat];
286
287 if( cov == NULL || e_vec == NULL || e_val == NULL )
288 return false; // print out of memory
289
290 k = 0;
291 for (i = 0; i < dim; i++)
292 for (j = 0; j <= i; j++)
293 cov[k++] = inputMatrix(i, j);
294
295 for (i = 0; i < ((dim * dim + dim) / 2); i++)
296 e_val[i] = cov[i];
297
298 iq = -dim;
299 for (i = 0; i < dim; i++)
300 {
301 iq = iq + dim;
302 for (j = 0; j < dim; j++)
303 {
304 ij = iq + j;
305 if (i == j)
306 e_vec[ij] = 1.0;
307 else
308 e_vec[ij] = 0.0;
309 }
310 }
311
312 anorm = 0.0;
313
314 for (j = 0; j < dim; j++)
315 {
316 for (i = 0; i <= j; i++)
317 if (i != j)
318 {
319 ia = i + (j * j + j) / 2;
320 anorm = anorm + e_val[ia] * e_val[ia];
321 }
322 }
323
324 if (anorm > 0)
325 {
326 anorm = 1.414 * sqrt((double)anorm);
327 anrmx = anorm * range / fdim;
328 ind = 0;
329 thr = anorm;
330
331// all this whiles were inserted to avoid the use of "goto" statements
332 bool l1 = true;
333 while(l1)
334 {
335 thr = thr / fdim;
336
337 bool l2 = true;
338 while(l2)
339 {
340 l = 0;
341
342 bool l3 = true;
343 while(l3)
344 {
345 m = l + 1;
346
347 bool l4 = true;
348 while(l4)
349 {
350 mq = (m * m + m) / 2;
351 lq = (l * l + l) / 2;
352 lm = l + mq;
353
354 if (fabs((double)(e_val[lm])) >= thr)
355 {
356 ind = 1;
357 ll = l + lq;
358 mm = m + mq;
359
360 x = 0.5 * (e_val[ll] - e_val[mm]);
361 z = e_val[lm] * e_val[lm] + x * x;
362 y = - e_val[lm] / sqrt((double)(z));
363
364 if (x < 0)
365 y = -y;
366
367 z = sqrt( (double)(1.0 - y * y) );
368 sinx = y / sqrt( (double)(2.0 * (1.0 + z)) );
369 sinx2 = sinx * sinx;
370
371 cosx = sqrt( (double)(1.0 - sinx2) );
372 cosx2 = cosx * cosx;
373
374 sincs = sinx * cosx;
375
376 ilq = dim * l;
377 imq = dim * m;
378
379 for (i = 0; i < dim; i++)
380 {
381 iq = (i * i + i) / 2;
382 if ( i != l )
383 {
384 if (i != m)
385 {
386 if (i > m)
387 im = m + iq;
388 else
389 im = i + mq;
390
391 if (i < l)
392 il = i + lq;
393 else
394 il = l + iq;
395
396 x = e_val[il] * cosx - e_val[im] * sinx;
397 e_val[im] = e_val[il] * sinx + e_val[im] * cosx;
398 e_val[il] = x;
399 }
400 }
401
402// calculate eigenvectors
403 ilr = ilq + i;
404 imr = imq + i;
405 x = e_vec[ilr] * cosx - e_vec[imr] * sinx;
406 e_vec[imr] = e_vec[ilr] * sinx + e_vec[imr] * cosx;
407 e_vec[ilr] = x;
408 }
409
410 x = 2.0 * e_val[lm] * sincs;
411 y = e_val[ll] * cosx2 + e_val[mm] * sinx2 - x;
412 x = e_val[ll] * sinx2 + e_val[mm] * cosx2 + x;
413
414 e_val[lm] = (e_val[ll] - e_val[mm]) * sincs + e_val[lm] * (cosx2 - sinx2);
415 e_val[ll] = y;
416 e_val[mm] = x;
417 }
418
419 if (m != (dim - 1))
420 m++;
421 else
422 l4 = false;
423 }
424
425 if (l != (dim - 2))
426 l++;
427 else
428 l3 = false;
429 }
430
431 if (ind == 1)
432 ind = 0;
433 else
434 l2 = false;
435 }
436
437 if (thr <= anrmx)
438 l1 = false;
439 }
440 }
441
442 iq = -dim;
443
444 for (i = 0; i < dim; i++)
445 {
446 iq = iq + dim;
447 ll = i + (i * i + i) / 2;
448 jq = dim * (i - 1);
449
450 for (j = i; j < dim; j++)
451 {
452 jq = jq + dim;
453 mm = j + (j * j + j) / 2;
454
455 if (e_val[ll] < e_val[mm])
456 {
457 x = e_val[ll];
458 e_val[ll] = e_val[mm];
459 e_val[mm] = x;
460
461 for (k = 0; k < dim; k++)
462 {
463 ilr = iq + k;
464 imr = jq + k;
465 x = e_vec[ilr];
466 e_vec[ilr] = e_vec[imr];
467 e_vec[imr] = x;
468 }
469 }
470 }
471 }
472
473// writing output matrices
474 eigenValuesMatrix.resize(dim, 1);
475 eigenValuesMatrix.clear();
476 k = 0;
477 for (i = 0; i < dim; i++)
478 for (j = 0; j < dim; j++)
479 eigenVectorsMatrix(j, i) = e_vec[k++];
480 for (i = 0; i < dim; i++)
481 eigenValuesMatrix(i, 0) = e_val[(i * (i + 1)) / 2 + i];
482
483 delete []cov;
484 delete []e_vec;
485 delete []e_val;
486
487 return true;
488 }
489
490 } // end namespace common
491} // end namespace te
492
493#endif //__TERRALIB_COMMON_INTERNAL_MATRIXUTILS_H
bool GetDeterminantComplex(const boost::numeric::ublas::matrix< T > &inputMatrix, T &determinant)
Definition MatrixUtils.h:96
bool GetInverseMatrix(const boost::numeric::ublas::matrix< T > &inputMatrix, boost::numeric::ublas::matrix< T > &outputMatrix)
Matrix inversion.
bool GetPseudoInverseMatrix(const boost::numeric::ublas::matrix< T > &inputMatrix, boost::numeric::ublas::matrix< T > &outputMatrix)
Pseudo matrix inversion.
bool EigenVectors(const boost::numeric::ublas::matrix< T > &inputMatrix, boost::numeric::ublas::matrix< T > &eigenVectorsMatrix, boost::numeric::ublas::matrix< T > &eigenValuesMatrix)
Computes the eigenvectors of a given matrix.
bool GetDeterminant(const boost::numeric::ublas::matrix< T > &inputMatrix, T &determinant)
Get the Matrix determinant value.
Definition MatrixUtils.h:57
TerraLib.
Proxy configuration file for TerraView (see terraview_config.h).