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  T& 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 = (unsigned int)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  /*!
96  \brief Matrix inversion.
97 
98  \param inputMatrix Input matrix.
99  \param outputMatrix Output matrix.
100 
101  \return true if ok, false on errors.
102  */
103  template<class T>
104  bool GetInverseMatrix(const boost::numeric::ublas::matrix<T>& inputMatrix,
105  boost::numeric::ublas::matrix<T>& outputMatrix)
106  {
107  assert( inputMatrix.size1() == inputMatrix.size2() );
108 
109  // create a working copy of the input
110  boost::numeric::ublas::matrix<T> A( inputMatrix );
111 
112  // create a permutation matrix for the LU-factorization
113  boost::numeric::ublas::permutation_matrix<std::size_t> pm( A.size1() );
114 
115  // perform LU-factorization
116  if( boost::numeric::ublas::lu_factorize( A, pm ) != 0 )
117  {
118  return false;
119  }
120  else
121  {
122  // create identity matrix of "inverse"
123  outputMatrix = boost::numeric::ublas::identity_matrix<T>( A.size1() );
124 
125  // backsubstitute to get the inverse
126  try
127  {
128  boost::numeric::ublas::lu_substitute( A, pm, outputMatrix );
129  }
130  catch(...)
131  {
132  return false;
133  }
134 
135  return true;
136  }
137  }
138 
139  /*!
140  \brief Pseudo matrix inversion.
141 
142  \param inputMatrix Input matrix.
143  \param outputMatrix Output matrix.
144 
145  \return true if ok, false on errors.
146 
147  \note PinvX = Inv( Xt * X ) * Xt, where Inv=Inverse and Xt is the transposed matrix of X.
148  \note A* = inv(trasnp(A) * A) * transp(A) (i>j)
149  \note A* = transp(A) * inv(A * trasnp(A)) (i<j)
150  */
151  template<class T>
152  bool GetPseudoInverseMatrix(const boost::numeric::ublas::matrix<T>& inputMatrix,
153  boost::numeric::ublas::matrix<T>& outputMatrix)
154  {
155  if( inputMatrix.size1() > inputMatrix.size2() )
156  {
157  boost::numeric::ublas::matrix<T> trans( boost::numeric::ublas::trans(
158  inputMatrix ) );
159 
160  boost::numeric::ublas::matrix<T> aux1( boost::numeric::ublas::prod( trans,
161  inputMatrix ) );
162 
163  boost::numeric::ublas::matrix<T> aux1Inv;
164 
165  if( GetInverseMatrix( aux1, aux1Inv ) )
166  {
167  outputMatrix = boost::numeric::ublas::prod( aux1Inv, trans );
168  return true;
169  }
170  else
171  {
172  return false;
173  }
174  }
175  else if( inputMatrix.size1() < inputMatrix.size2() )
176  {
177  boost::numeric::ublas::matrix<T> trans( boost::numeric::ublas::trans(
178  inputMatrix ) );
179 
180  boost::numeric::ublas::matrix<T> aux1( boost::numeric::ublas::prod(
181  inputMatrix, trans ) );
182 
183  boost::numeric::ublas::matrix<T> aux1Inv;
184 
185  if( GetInverseMatrix( aux1, aux1Inv ) )
186  {
187  outputMatrix = boost::numeric::ublas::prod( trans, aux1Inv );
188  return true;
189  }
190  else
191  {
192  return false;
193  }
194  }
195  else
196  {
197  return GetInverseMatrix( inputMatrix, outputMatrix );
198  }
199  }
200 
201  /*!
202  \brief Computes the eigenvectors of a given matrix.
203 
204  \param inputMatrix The input matrix.
205  \param eigenVectorsMatrix The matrix where the eigenvectors will be stored.
206  \param eigenValuesMatrix The matrix where the eigenvalues will be stored.
207 
208  \return true if ok, false on errors.
209  */
210  template<class T>
211  bool EigenVectors(const boost::numeric::ublas::matrix<T>& inputMatrix, boost::numeric::ublas::matrix<T> &eigenVectorsMatrix, boost::numeric::ublas::matrix<T> &eigenValuesMatrix)
212  {
213 // this source code is based on TerraLib 4
214  double *cov = NULL, // covariance matrix
215  *e_val = NULL, // eigenvalue matrix
216  *e_vec = NULL; // eigenvector matrix
217 
218  int dim = inputMatrix.size1();
219 
220  int i, j, ij, k,
221  ia, ind, l, m,
222  mq, lm, ll, mm,
223  ilq, imq, im, iq,
224  il, lq, ilr, imr,
225  jq;
226 
227  double range, fdim, anorm, anrmx,
228  thr, x, y, z,
229  sinx, cosx, sinx2, cosx2,
230  sincs;
231 
232  if (dim <= 0)
233  return false; // print invalid matrix
234 
235  eigenVectorsMatrix.resize(dim, dim);
236  eigenVectorsMatrix.clear();
237  for (i = 0; i < dim; i++)
238  eigenVectorsMatrix(i, i) = 1.0;
239 
240  int fat = (dim * dim + dim) / 2;
241  range = 1.0e-6;
242  fdim = dim;
243 
244  cov = new double[fat];
245  e_vec = new double[dim * dim];
246  e_val = new double[fat];
247 
248  if( cov == NULL || e_vec == NULL || e_val == NULL )
249  return false; // print out of memory
250 
251  k = 0;
252  for (i = 0; i < dim; i++)
253  for (j = 0; j <= i; j++)
254  cov[k++] = inputMatrix(i, j);
255 
256  for (i = 0; i < ((dim * dim + dim) / 2); i++)
257  e_val[i] = cov[i];
258 
259  iq = -dim;
260  for (i = 0; i < dim; i++)
261  {
262  iq = iq + dim;
263  for (j = 0; j < dim; j++)
264  {
265  ij = iq + j;
266  if (i == j)
267  e_vec[ij] = 1.0;
268  else
269  e_vec[ij] = 0.0;
270  }
271  }
272 
273  anorm = 0.0;
274 
275  for (j = 0; j < dim; j++)
276  {
277  for (i = 0; i <= j; i++)
278  if (i != j)
279  {
280  ia = i + (j * j + j) / 2;
281  anorm = anorm + e_val[ia] * e_val[ia];
282  }
283  }
284 
285  if (anorm > 0)
286  {
287  anorm = 1.414 * sqrt((double)anorm);
288  anrmx = anorm * range / fdim;
289  ind = 0;
290  thr = anorm;
291 
292 // all this whiles were inserted to avoid the use of "goto" statements
293  bool l1 = true;
294  while(l1)
295  {
296  thr = thr / fdim;
297 
298  bool l2 = true;
299  while(l2)
300  {
301  l = 0;
302 
303  bool l3 = true;
304  while(l3)
305  {
306  m = l + 1;
307 
308  bool l4 = true;
309  while(l4)
310  {
311  mq = (m * m + m) / 2;
312  lq = (l * l + l) / 2;
313  lm = l + mq;
314 
315  if (fabs((double)(e_val[lm])) >= thr)
316  {
317  ind = 1;
318  ll = l + lq;
319  mm = m + mq;
320 
321  x = 0.5 * (e_val[ll] - e_val[mm]);
322  z = e_val[lm] * e_val[lm] + x * x;
323  y = - e_val[lm] / sqrt((double)(z));
324 
325  if (x < 0)
326  y = -y;
327 
328  z = sqrt( (double)(1.0 - y * y) );
329  sinx = y / sqrt( (double)(2.0 * (1.0 + z)) );
330  sinx2 = sinx * sinx;
331 
332  cosx = sqrt( (double)(1.0 - sinx2) );
333  cosx2 = cosx * cosx;
334 
335  sincs = sinx * cosx;
336 
337  ilq = dim * l;
338  imq = dim * m;
339 
340  for (i = 0; i < dim; i++)
341  {
342  iq = (i * i + i) / 2;
343  if ( i != l )
344  {
345  if (i != m)
346  {
347  if (i > m)
348  im = m + iq;
349  else
350  im = i + mq;
351 
352  if (i < l)
353  il = i + lq;
354  else
355  il = l + iq;
356 
357  x = e_val[il] * cosx - e_val[im] * sinx;
358  e_val[im] = e_val[il] * sinx + e_val[im] * cosx;
359  e_val[il] = x;
360  }
361  }
362 
363 // calculate eigenvectors
364  ilr = ilq + i;
365  imr = imq + i;
366  x = e_vec[ilr] * cosx - e_vec[imr] * sinx;
367  e_vec[imr] = e_vec[ilr] * sinx + e_vec[imr] * cosx;
368  e_vec[ilr] = x;
369  }
370 
371  x = 2.0 * e_val[lm] * sincs;
372  y = e_val[ll] * cosx2 + e_val[mm] * sinx2 - x;
373  x = e_val[ll] * sinx2 + e_val[mm] * cosx2 + x;
374 
375  e_val[lm] = (e_val[ll] - e_val[mm]) * sincs + e_val[lm] * (cosx2 - sinx2);
376  e_val[ll] = y;
377  e_val[mm] = x;
378  }
379 
380  if (m != (dim - 1))
381  m++;
382  else
383  l4 = false;
384  }
385 
386  if (l != (dim - 2))
387  l++;
388  else
389  l3 = false;
390  }
391 
392  if (ind == 1)
393  ind = 0;
394  else
395  l2 = false;
396  }
397 
398  if (thr <= anrmx)
399  l1 = false;
400  }
401  }
402 
403  iq = -dim;
404 
405  for (i = 0; i < dim; i++)
406  {
407  iq = iq + dim;
408  ll = i + (i * i + i) / 2;
409  jq = dim * (i - 1);
410 
411  for (j = i; j < dim; j++)
412  {
413  jq = jq + dim;
414  mm = j + (j * j + j) / 2;
415 
416  if (e_val[ll] < e_val[mm])
417  {
418  x = e_val[ll];
419  e_val[ll] = e_val[mm];
420  e_val[mm] = x;
421 
422  for (k = 0; k < dim; k++)
423  {
424  ilr = iq + k;
425  imr = jq + k;
426  x = e_vec[ilr];
427  e_vec[ilr] = e_vec[imr];
428  e_vec[imr] = x;
429  }
430  }
431  }
432  }
433 
434 // writing output matrices
435  eigenValuesMatrix.resize(fat, 1);
436  eigenValuesMatrix.clear();
437  k = 0;
438  for (i = 0; i < dim; i++)
439  for (j = 0; j < dim; j++)
440  eigenVectorsMatrix(j, i) = e_vec[k++];
441  for (i = 0; i < fat; i++)
442  eigenValuesMatrix(i, 0) = e_val[i];
443 
444  delete []cov;
445  delete []e_vec;
446  delete []e_val;
447 
448  return true;
449  }
450 
451  } // end namespace common
452 } // end namespace te
453 
454 #endif //__TERRALIB_COMMON_INTERNAL_MATRIXUTILS_H
bool GetDeterminant(const boost::numeric::ublas::matrix< T > &inputMatrix, T &determinant)
Get the Matrix determinant value.
Definition: MatrixUtils.h:57
Configuration flags for the TerraLib Common Runtime module.
bool GetPseudoInverseMatrix(const boost::numeric::ublas::matrix< T > &inputMatrix, boost::numeric::ublas::matrix< T > &outputMatrix)
Pseudo matrix inversion.
Definition: MatrixUtils.h:152
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:211
bool GetInverseMatrix(const boost::numeric::ublas::matrix< T > &inputMatrix, boost::numeric::ublas::matrix< T > &outputMatrix)
Matrix inversion.
Definition: MatrixUtils.h:104