GetFEM  5.5
gmm_dense_lu.h
Go to the documentation of this file.
1 /* -*- c++ -*- (enables emacs c++ mode) */
2 /*===========================================================================
3 
4  Copyright (C) 2003-2026 Yves Renard
5 
6  This file is a part of GetFEM
7 
8  GetFEM is free software; you can redistribute it and/or modify it
9  under the terms of the GNU Lesser General Public License as published
10  by the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version along with the GCC Runtime Library
12  Exception either version 3.1 or (at your option) any later version.
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16  License and GCC Runtime Library Exception for more details.
17  You should have received a copy of the GNU Lesser General Public License
18  along with this program. If not, see https://www.gnu.org/licenses/.
19 
20  As a special exception, you may use this file as it is a part of a free
21  software library without restriction. Specifically, if other files
22  instantiate templates or use macros or inline functions from this file,
23  or you compile this file and link it with other files to produce an
24  executable, this file does not by itself cause the resulting executable
25  to be covered by the GNU Lesser General Public License. This exception
26  does not however invalidate any other reasons why the executable file
27  might be covered by the GNU Lesser General Public License.
28 
29 ===========================================================================*/
30 
31 // This file is a modified version of lu.h from MTL.
32 // See http://osl.iu.edu/research/mtl/
33 // Following the corresponding Copyright notice.
34 //===========================================================================
35 //
36 // Copyright (c) 1998-2020, University of Notre Dame. All rights reserved.
37 // Redistribution and use in source and binary forms, with or without
38 // modification, are permitted provided that the following conditions are met:
39 //
40 // * Redistributions of source code must retain the above copyright
41 // notice, this list of conditions and the following disclaimer.
42 // * Redistributions in binary form must reproduce the above copyright
43 // notice, this list of conditions and the following disclaimer in the
44 // documentation and/or other materials provided with the distribution.
45 // * Neither the name of the University of Notre Dame nor the
46 // names of its contributors may be used to endorse or promote products
47 // derived from this software without specific prior written permission.
48 //
49 // THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
50 // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
51 // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
52 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
53 // OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
54 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
55 // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
59 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60 //
61 //===========================================================================
62 
63 /**@file gmm_dense_lu.h
64  @author Andrew Lumsdaine, Jeremy G. Siek, Lie-Quan Lee, Y. Renard
65  @date June 5, 2003.
66  @brief LU factorizations and determinant computation for dense matrices.
67 */
68 #ifndef GMM_DENSE_LU_H
69 #define GMM_DENSE_LU_H
70 
71 #include "gmm_dense_Householder.h"
72 
73 namespace gmm {
74 
75 #if defined(GMM_USES_BLAS) || defined(GMM_USES_LAPACK)
76  typedef std::vector<BLAS_INT> lapack_ipvt;
77 #else
78  typedef std::vector<size_type> lapack_ipvt;
79 #endif
80 
81  /** LU Factorization of a general (dense) matrix (real or complex).
82 
83  This is the outer product (a level-2 operation) form of the LU
84  Factorization with pivoting algorithm . This is equivalent to
85  LAPACK's dgetf2. Also see "Matrix Computations" 3rd Ed. by Golub
86  and Van Loan section 3.2.5 and especially page 115.
87 
88  The pivot indices in ipvt are indexed starting from 1
89  so that this is compatible with LAPACK (Fortran).
90  */
91  template <typename DenseMatrix, typename Pvector>
92  size_type lu_factor(DenseMatrix& A, Pvector& ipvt) {
93  typedef typename linalg_traits<DenseMatrix>::value_type T;
94  typedef typename linalg_traits<Pvector>::value_type INT;
95  typedef typename number_traits<T>::magnitude_type R;
96  size_type info(0), i, j, jp, M(mat_nrows(A)), N(mat_ncols(A));
97  if (M == 0 || N == 0)
98  return info;
99  size_type NN = std::min(M, N);
100  std::vector<T> c(M), r(N);
101 
102  GMM_ASSERT2(ipvt.size()+1 >= NN, "IPVT too small");
103  for (i = 0; i+1 < NN; ++i) ipvt[i] = INT(i);
104 
105  if (M || N) {
106  for (j = 0; j+1 < NN; ++j) {
107  R max = gmm::abs(A(j,j)); jp = j;
108  for (i = j+1; i < M; ++i) /* find pivot. */
109  if (gmm::abs(A(i,j)) > max) { jp = i; max = gmm::abs(A(i,j)); }
110  ipvt[j] = INT(jp + 1);
111 
112  if (max == R(0)) { info = j + 1; break; }
113  if (jp != j) for (i = 0; i < N; ++i) std::swap(A(jp, i), A(j, i));
114 
115  for (i = j+1; i < M; ++i) { A(i, j) /= A(j,j); c[i-j-1] = -A(i, j); }
116  for (i = j+1; i < N; ++i) r[i-j-1] = A(j, i); // avoid the copy ?
117  rank_one_update(sub_matrix(A, sub_interval(j+1, M-j-1),
118  sub_interval(j+1, N-j-1)), c, conjugated(r));
119  }
120  ipvt[NN-1] = INT(NN);
121  }
122  return info;
123  }
124 
125  /** LU Solve : Solve equation Ax=b, given an LU factored matrix.*/
126  // Thanks to Valient Gough for this routine!
127  template <typename DenseMatrix, typename VectorB, typename VectorX,
128  typename Pvector>
129  void lu_solve(const DenseMatrix &LU, const Pvector& pvector,
130  VectorX &x, const VectorB &b) {
131  typedef typename linalg_traits<DenseMatrix>::value_type T;
132  copy(b, x);
133  for(size_type i = 0; i < pvector.size(); ++i) {
134  size_type perm = size_type(pvector[i]-1); // permutations stored in 1's offset
135  if (i != perm) { T aux = x[i]; x[i] = x[perm]; x[perm] = aux; }
136  }
137  /* solve Ax = b -> LUx = b -> Ux = L^-1 b. */
138  lower_tri_solve(LU, x, true);
139  upper_tri_solve(LU, x, false);
140  }
141 
142  template <typename DenseMatrix, typename VectorB, typename VectorX>
143  void lu_solve(const DenseMatrix &A, VectorX &x, const VectorB &b) {
144  typedef typename linalg_traits<DenseMatrix>::value_type T;
145  const size_type M(mat_nrows(A)), N(mat_ncols(A));
146  if (M == 0 || N == 0)
147  return;
148  dense_matrix<T> B(M, N);
149  lapack_ipvt ipvt(M);
150  gmm::copy(A, B);
151  size_type info = lu_factor(B, ipvt);
152  GMM_ASSERT1(!info, "Singular system, pivot = " << info);
153  lu_solve(B, ipvt, x, b);
154  }
155 
156  template <typename DenseMatrix, typename VectorB, typename VectorX,
157  typename Pvector>
158  void lu_solve_transposed(const DenseMatrix &LU, const Pvector& pvector,
159  VectorX &x, const VectorB &b) {
160  typedef typename linalg_traits<DenseMatrix>::value_type T;
161  copy(b, x);
162  lower_tri_solve(transposed(LU), x, false);
163  upper_tri_solve(transposed(LU), x, true);
164  for (size_type i = pvector.size(); i > 0; --i) {
165  size_type perm = size_type(pvector[i-1]-1); // permutations stored in 1's offset
166  if (i-1 != perm) {
167  T aux = x[i-1];
168  x[i-1] = x[perm];
169  x[perm] = aux;
170  }
171  }
172  }
173 
174 
175  ///@cond DOXY_SHOW_ALL_FUNCTIONS
176  template <typename DenseMatrixLU, typename DenseMatrix, typename Pvector>
177  void lu_inverse(const DenseMatrixLU& LU, const Pvector& pvector,
178  DenseMatrix& AInv, col_major) {
179  typedef typename linalg_traits<DenseMatrixLU>::value_type T;
180  std::vector<T> tmp(pvector.size(), T(0));
181  std::vector<T> result(pvector.size());
182  for(size_type i = 0; i < pvector.size(); ++i) {
183  tmp[i] = T(1);
184  lu_solve(LU, pvector, result, tmp);
185  copy(result, mat_col(AInv, i));
186  tmp[i] = T(0);
187  }
188  }
189 
190  template <typename DenseMatrixLU, typename DenseMatrix, typename Pvector>
191  void lu_inverse(const DenseMatrixLU& LU, const Pvector& pvector,
192  DenseMatrix& AInv, row_major) {
193  typedef typename linalg_traits<DenseMatrixLU>::value_type T;
194  std::vector<T> tmp(pvector.size(), T(0));
195  std::vector<T> result(pvector.size());
196  for(size_type i = 0; i < pvector.size(); ++i) {
197  tmp[i] = T(1); // to be optimized !!
198  // on peut sur le premier tri solve reduire le systeme
199  // et peut etre faire un solve sur une serie de vecteurs au lieu
200  // de vecteur a vecteur (accumulation directe de l'inverse dans la
201  // matrice au fur et a mesure du calcul ... -> evite la copie finale
202  lu_solve_transposed(LU, pvector, result, tmp);
203  copy(result, mat_row(AInv, i));
204  tmp[i] = T(0);
205  }
206  }
207  ///@endcond
208 
209  /** Given an LU factored matrix, build the inverse of the matrix. */
210  template <typename DenseMatrixLU, typename DenseMatrix, typename Pvector>
211  void lu_inverse(const DenseMatrixLU& LU, const Pvector& pvector,
212  const DenseMatrix& AInv_) {
213  DenseMatrix& AInv = const_cast<DenseMatrix&>(AInv_);
214  lu_inverse(LU, pvector, AInv, typename principal_orientation_type<typename
215  linalg_traits<DenseMatrix>::sub_orientation>::potype());
216  }
217 
218  /** Given a dense matrix, build the inverse of the matrix, and
219  return the determinant */
220  template <typename DenseMatrix>
221  typename linalg_traits<DenseMatrix>::value_type
222  lu_inverse(const DenseMatrix& A_, bool doassert = true) {
223  typedef typename linalg_traits<DenseMatrix>::value_type T;
224  DenseMatrix& A = const_cast<DenseMatrix&>(A_);
225  const size_type M(mat_nrows(A)), N(mat_ncols(A));
226  if (M == 0 || N == 0)
227  return T(1);
228  dense_matrix<T> B(M, N);
229  lapack_ipvt ipvt(M);
230  gmm::copy(A, B);
231  size_type info = lu_factor(B, ipvt);
232  if (doassert) GMM_ASSERT1(!info, "Non invertible matrix, pivot = "<<info);
233  if (!info) lu_inverse(B, ipvt, A);
234  return lu_det(B, ipvt);
235  }
236 
237  /** Compute the matrix determinant (via a LU factorization) */
238  template <typename DenseMatrixLU, typename Pvector>
239  typename linalg_traits<DenseMatrixLU>::value_type
240  lu_det(const DenseMatrixLU& LU, const Pvector &pvector) {
241  typedef typename linalg_traits<DenseMatrixLU>::value_type T;
242  typedef typename linalg_traits<Pvector>::value_type INT;
243  T det(1);
244  const size_type J=std::min(mat_nrows(LU), mat_ncols(LU));
245  for (size_type j = 0; j < J; ++j)
246  det *= LU(j,j);
247  for(INT i = 0; i < INT(pvector.size()); ++i)
248  if (i != pvector[i]-1) { det = -det; }
249  return det;
250  }
251 
252  template <typename DenseMatrix>
253  typename linalg_traits<DenseMatrix>::value_type
254  lu_det(const DenseMatrix& A) {
255  typedef typename linalg_traits<DenseMatrix>::value_type T;
256  const size_type M(mat_nrows(A)), N(mat_ncols(A));
257  if (M == 0 || N == 0)
258  return T(1);
259  dense_matrix<T> B(M, N);
260  lapack_ipvt ipvt(M);
261  gmm::copy(A, B);
262  lu_factor(B, ipvt);
263  return lu_det(B, ipvt);
264  }
265 
266 }
267 
268 #include "gmm_opt.h"
269 
270 #endif
271 
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:976
conjugated_return< L >::return_type conjugated(const L &v)
return a conjugated view of the input matrix or vector.
Householder for dense matrices.
void lu_solve(const DenseMatrix &LU, const Pvector &pvector, VectorX &x, const VectorB &b)
LU Solve : Solve equation Ax=b, given an LU factored matrix.
Definition: gmm_dense_lu.h:129
Optimization for some small cases (inversion of 2x2 matrices etc.)
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:48