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 
45 namespace 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  double& determinant)
59  {
60  if( ( inputMatrix.size1() == 0 ) || ( inputMatrix.size2() == 0 ) )
61  {
62  determinant = 0.0;
63  return true;
64  }
65 
66  // create a working copy of the input
67  boost::numeric::ublas::matrix<T> A( inputMatrix );
68 
69  const unsigned int size1 = A.size1();
70 
71  boost::numeric::ublas::permutation_matrix<std::size_t> pm( size1 );
72 
73  if( boost::numeric::ublas::lu_factorize( A, pm ) != 0.0 )
74  {
75  return false;
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  return true;
92  }
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 = 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
Configuration flags for the TerraLib Common Runtime module.
bool GetDeterminantComplex(const boost::numeric::ublas::matrix< T > &inputMatrix, T &determinant)
Definition: MatrixUtils.h:96
bool GetPseudoInverseMatrix(const boost::numeric::ublas::matrix< T > &inputMatrix, boost::numeric::ublas::matrix< T > &outputMatrix)
Pseudo matrix inversion.
Definition: MatrixUtils.h:191
bool GetDeterminant(const boost::numeric::ublas::matrix< T > &inputMatrix, double &determinant)
Get the Matrix determinant value.
Definition: MatrixUtils.h:57
URI C++ Library.
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.
Definition: MatrixUtils.h:250
bool GetInverseMatrix(const boost::numeric::ublas::matrix< T > &inputMatrix, boost::numeric::ublas::matrix< T > &outputMatrix)
Matrix inversion.
Definition: MatrixUtils.h:143