Visual Servoing Platform  version 3.6.1 under development (2024-12-17)
vpMatrix_lu.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Matrix LU decomposition.
32  */
33 
34 #include <visp3/core/vpConfig.h>
35 
36 #include <visp3/core/vpColVector.h>
37 #include <visp3/core/vpMath.h>
38 #include <visp3/core/vpMatrix.h>
39 
40 #ifdef VISP_HAVE_EIGEN3
41 #include <Eigen/LU>
42 #endif
43 
44 #ifdef VISP_HAVE_LAPACK
45 #ifdef VISP_HAVE_GSL
46 #include <gsl/gsl_linalg.h>
47 #include <gsl/gsl_permutation.h>
48 #endif
49 #ifdef VISP_HAVE_MKL
50 #include <mkl.h>
51 typedef MKL_INT integer;
52 #else
53 #ifdef VISP_HAVE_LAPACK_BUILT_IN
54 typedef long int integer;
55 #else
56 typedef int integer;
57 #endif
58 extern "C" int dgetrf_(integer *m, integer *n, double *a, integer *lda, integer *ipiv, integer *info);
59 extern "C" void dgetri_(integer *n, double *a, integer *lda, integer *ipiv, double *work, integer *lwork,
60  integer *info);
61 #endif
62 #endif
63 
64 #if defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
65 #include <opencv2/core/core.hpp>
66 #endif
67 
68 // Exception
69 #include <visp3/core/vpException.h>
70 #include <visp3/core/vpMatrixException.h>
71 
72 #include <cmath> // std::fabs
73 #include <limits> // numeric_limits
74 
75 BEGIN_VISP_NAMESPACE
76 /*--------------------------------------------------------------------
77  LU Decomposition related functions
78 -------------------------------------------------------------------- */
79 
131 {
132  const unsigned int val_2 = 2;
133  const unsigned int val_3 = 3;
134  if ((colNum == 1) && (rowNum == 1)) {
135  vpMatrix inv;
136  inv.resize(1, 1, false);
137  double d = det();
138  if (std::fabs(d) < std::numeric_limits<double>::epsilon()) {
139  throw(vpException(vpException::fatalError, "Cannot inverse matrix %d by %d by LU. Matrix determinant is 0.",
140  rowNum, colNum));
141  }
142  inv[0][0] = 1. / d;
143  return inv;
144  }
145  else if ((colNum == val_2) && (rowNum == val_2)) {
146  vpMatrix inv;
147  inv.resize(val_2, val_2, false);
148  double d = det();
149  if (std::fabs(d) < std::numeric_limits<double>::epsilon()) {
150  throw(vpException(vpException::fatalError, "Cannot inverse matrix %d by %d by LU. Matrix determinant is 0.",
151  rowNum, colNum));
152  }
153  d = 1. / d;
154  inv[1][1] = (*this)[0][0] * d;
155  inv[0][0] = (*this)[1][1] * d;
156  inv[0][1] = -(*this)[0][1] * d;
157  inv[1][0] = -(*this)[1][0] * d;
158  return inv;
159  }
160  else if ((colNum == val_3) && (rowNum == val_3)) {
161  vpMatrix inv;
162  inv.resize(val_3, val_3, false);
163  double d = det();
164  if (std::fabs(d) < std::numeric_limits<double>::epsilon()) {
165  throw(vpException(vpException::fatalError, "Cannot inverse matrix %d by %d by LU. Matrix determinant is 0.",
166  rowNum, colNum));
167  }
168  d = 1. / d;
169  const unsigned int index_0 = 0;
170  const unsigned int index_1 = 1;
171  const unsigned int index_2 = 2;
172  inv[index_0][index_0] = (((*this)[index_1][index_1] * (*this)[index_2][index_2]) - ((*this)[index_1][index_2] * (*this)[index_2][index_1])) * d;
173  inv[index_0][index_1] = (((*this)[index_0][index_2] * (*this)[index_2][index_1]) - ((*this)[index_0][index_1] * (*this)[index_2][index_2])) * d;
174  inv[index_0][index_2] = (((*this)[index_0][index_1] * (*this)[index_1][index_2]) - ((*this)[index_0][index_2] * (*this)[index_1][index_1])) * d;
175 
176  inv[index_1][index_0] = (((*this)[index_1][index_2] * (*this)[index_2][index_0]) - ((*this)[index_1][index_0] * (*this)[index_2][index_2])) * d;
177  inv[index_1][index_1] = (((*this)[index_0][index_0] * (*this)[index_2][index_2]) - ((*this)[index_0][index_2] * (*this)[index_2][index_0])) * d;
178  inv[index_1][index_2] = (((*this)[index_0][index_2] * (*this)[index_1][index_0]) - ((*this)[index_0][index_0] * (*this)[index_1][index_2])) * d;
179 
180  inv[index_2][index_0] = (((*this)[index_1][index_0] * (*this)[index_2][index_1]) - ((*this)[index_1][index_1] * (*this)[index_2][index_0])) * d;
181  inv[index_2][index_1] = (((*this)[index_0][index_1] * (*this)[index_2][index_0]) - ((*this)[index_0][index_0] * (*this)[index_2][index_1])) * d;
182  inv[index_2][index_2] = (((*this)[index_0][index_0] * (*this)[index_1][index_1]) - ((*this)[index_0][index_1] * (*this)[index_1][index_0])) * d;
183  return inv;
184  }
185  else {
186 #if defined(VISP_HAVE_LAPACK)
187  return inverseByLULapack();
188 #elif defined(VISP_HAVE_EIGEN3)
189  return inverseByLUEigen3();
190 #elif defined(VISP_HAVE_OPENCV)
191  return inverseByLUOpenCV();
192 #else
193  throw(vpException(vpException::fatalError, "Cannot inverse by LU. "
194  "Install Lapack, Eigen3 or OpenCV 3rd party"));
195 #endif
196  }
197 }
198 
236 double vpMatrix::detByLU() const
237 {
238  const unsigned int val_2 = 2;
239  const unsigned int val_3 = 3;
240  if ((rowNum == 1) && (colNum == 1)) {
241  return (*this)[0][0];
242  }
243  else if ((rowNum == val_2) && (colNum == val_2)) {
244  return (((*this)[0][0] * (*this)[1][1]) - ((*this)[0][1] * (*this)[1][0]));
245  }
246  else if ((rowNum == val_3) && (colNum == val_3)) {
247  const unsigned int index_0 = 0;
248  const unsigned int index_1 = 1;
249  const unsigned int index_2 = 2;
250  return ((((*this)[index_0][index_0] * (((*this)[index_1][index_1] * (*this)[index_2][index_2]) - ((*this)[index_1][index_2] * (*this)[index_2][index_1]))) -
251  ((*this)[index_0][index_1] * (((*this)[index_1][index_0] * (*this)[index_2][index_2]) - ((*this)[index_1][index_2] * (*this)[index_2][index_0])))) +
252  ((*this)[index_0][index_2] * (((*this)[index_1][index_0] * (*this)[index_2][index_1]) - ((*this)[index_1][index_1] * (*this)[index_2][index_0]))));
253  }
254  else {
255 #if defined(VISP_HAVE_LAPACK)
256  return detByLULapack();
257 #elif defined(VISP_HAVE_EIGEN3)
258  return detByLUEigen3();
259 #elif defined(VISP_HAVE_OPENCV)
260  return detByLUOpenCV();
261 #else
262  throw(vpException(vpException::fatalError, "Cannot compute matrix determinant. "
263  "Install Lapack, Eigen3 or OpenCV 3rd party"));
264 #endif
265  }
266 }
267 
268 #if defined(VISP_HAVE_LAPACK)
304 {
305 #if defined(VISP_HAVE_GSL)
306  {
307  if (rowNum != colNum) {
308  throw(vpException(vpException::fatalError, "Cannot inverse a non square matrix (%ux%u) by LU", rowNum, colNum));
309  }
310 
311  gsl_matrix *A = gsl_matrix_alloc(rowNum, colNum);
312 
313  // copy the input matrix to ensure the function doesn't modify its content
314  unsigned int tda = static_cast<unsigned int>(A->tda);
315  for (unsigned int i = 0; i < rowNum; ++i) {
316  unsigned int k = i * tda;
317  for (unsigned int j = 0; j < colNum; ++j)
318  A->data[k + j] = (*this)[i][j];
319  }
320 
321  vpMatrix Ainv(rowNum, colNum);
322 
323  gsl_matrix inverse;
324  inverse.size1 = rowNum;
325  inverse.size2 = colNum;
326  inverse.tda = inverse.size2;
327  inverse.data = Ainv.data;
328  inverse.owner = 0;
329  inverse.block = 0;
330 
331  gsl_permutation *p = gsl_permutation_alloc(rowNum);
332  int s;
333 
334  // Do the LU decomposition on A and use it to solve the system
335  gsl_linalg_LU_decomp(A, p, &s);
336  gsl_linalg_LU_invert(A, p, &inverse);
337 
338  gsl_permutation_free(p);
339  gsl_matrix_free(A);
340 
341  return Ainv;
342  }
343 #else
344  {
345  if (rowNum != colNum) {
346  throw(vpException(vpException::fatalError, "Cannot inverse a non square matrix (%ux%u) by LU", rowNum, colNum));
347  }
348 
349  integer dim = (integer)rowNum;
350  integer lda = dim;
351  integer info;
352  integer lwork = dim * dim;
353  integer *ipiv = new integer[dim + 1];
354  double *work = new double[lwork];
355 
356  vpMatrix A = *this;
357 
358  dgetrf_(&dim, &dim, A.data, &lda, &ipiv[1], &info);
359  if (info) {
360  delete[] ipiv;
361  delete[] work;
362  throw(vpException(vpException::fatalError, "Lapack LU decomposition failed; info=%d", info));
363  }
364 
365  dgetri_(&dim, A.data, &dim, &ipiv[1], work, &lwork, &info);
366 
367  delete[] ipiv;
368  delete[] work;
369 
370  return A;
371  }
372 #endif
373 }
374 
405 {
406 #if defined(VISP_HAVE_GSL)
407  {
408  double det = 0.;
409 
410  if (rowNum != colNum) {
411  throw(vpException(vpException::fatalError, "Cannot compute matrix determinant of a non square matrix (%ux%u)",
412  rowNum, colNum));
413  }
414 
415  gsl_matrix *A = gsl_matrix_alloc(rowNum, colNum);
416 
417  // copy the input matrix to ensure the function doesn't modify its content
418  unsigned int tda = (unsigned int)A->tda;
419  for (unsigned int i = 0; i < rowNum; i++) {
420  unsigned int k = i * tda;
421  for (unsigned int j = 0; j < colNum; j++)
422  A->data[k + j] = (*this)[i][j];
423  }
424 
425  gsl_permutation *p = gsl_permutation_alloc(rowNum);
426  int s;
427 
428  // Do the LU decomposition on A and use it to solve the system
429  gsl_linalg_LU_decomp(A, p, &s);
430  det = gsl_linalg_LU_det(A, s);
431 
432  gsl_permutation_free(p);
433  gsl_matrix_free(A);
434 
435  return det;
436  }
437 #else
438  {
439  if (rowNum != colNum) {
440  throw(vpException(vpException::fatalError, "Cannot compute matrix determinant of a non square matrix (%ux%u)",
441  rowNum, colNum));
442  }
443 
444  integer dim = (integer)rowNum;
445  integer lda = dim;
446  integer info;
447  integer *ipiv = new integer[dim + 1];
448 
449  vpMatrix A = *this;
450 
451  dgetrf_(&dim, &dim, A.data, &lda, &ipiv[1], &info);
452  if (info < 0) {
453  delete[] ipiv;
454  throw(vpException(vpException::fatalError, "Lapack LU decomposition failed; info=%d", -info));
455  }
456 
457  double det = A[0][0];
458  for (unsigned int i = 1; i < rowNum; ++i) {
459  det *= A[i][i];
460  }
461 
462  double sign = 1.;
463  for (int i = 1; i <= dim; ++i) {
464  if (ipiv[i] != i)
465  sign = -sign;
466  }
467 
468  det *= sign;
469 
470  delete[] ipiv;
471 
472  return det;
473  }
474 #endif
475 }
476 #endif
477 
478 #if defined(VISP_HAVE_OPENCV)
514 {
515  if (rowNum != colNum) {
516  throw(vpException(vpException::fatalError, "Cannot inverse a non square matrix (%ux%u) by LU", rowNum, colNum));
517  }
518 
519  cv::Mat M(rowNum, colNum, CV_64F, this->data);
520 
521  cv::Mat Minv = M.inv(cv::DECOMP_LU);
522 
523  vpMatrix A(rowNum, colNum);
524  memcpy(A.data, Minv.data, (size_t)(8 * Minv.rows * Minv.cols));
525 
526  return A;
527 }
528 
559 {
560  double det = 0.;
561 
562  if (rowNum != colNum) {
563  throw(vpException(vpException::fatalError, "Cannot compute matrix determinant of a non square matrix (%ux%u)",
564  rowNum, colNum));
565  }
566 
567  cv::Mat M(rowNum, colNum, CV_64F, this->data);
568  det = cv::determinant(M);
569 
570  return (det);
571 }
572 #endif
573 
574 #if defined(VISP_HAVE_EIGEN3)
575 
611 {
612  if (rowNum != colNum) {
613  throw(vpException(vpException::fatalError, "Cannot inverse a non square matrix (%ux%u) by LU", rowNum, colNum));
614  }
615  vpMatrix A(this->getRows(), this->getCols());
616 
617  Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> > M(this->data, this->getRows(),
618  this->getCols());
619  Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> > A_(A.data, this->getRows(),
620  this->getCols());
621 
622  A_ = M.inverse();
623 
624  return A;
625 }
626 
657 {
658  if (rowNum != colNum) {
659  throw(vpException(vpException::fatalError, "Cannot compute matrix determinant of a non square matrix (%ux%u)",
660  rowNum, colNum));
661  }
662 
663  Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> > M(this->data, this->getRows(),
664  this->getCols());
665 
666  return M.determinant();
667 }
668 #endif
669 END_VISP_NAMESPACE
unsigned int getCols() const
Definition: vpArray2D.h:337
Type * data
Address of the first element of the data array.
Definition: vpArray2D.h:148
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition: vpArray2D.h:362
unsigned int rowNum
Number of rows in the array.
Definition: vpArray2D.h:1101
unsigned int getRows() const
Definition: vpArray2D.h:347
unsigned int colNum
Number of columns in the array.
Definition: vpArray2D.h:1103
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ fatalError
Fatal error.
Definition: vpException.h:72
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:169
vpMatrix inverseByLU() const
vpMatrix inverseByLUEigen3() const
vpMatrix inverseByLUOpenCV() const
double detByLUEigen3() const
double detByLUOpenCV() const
vpMatrix inverseByLULapack() const
double detByLU() const
double det(vpDetMethod method=LU_DECOMPOSITION) const
Definition: vpMatrix.cpp:1637
double detByLULapack() const