You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							126 lines
						
					
					
						
							4.7 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							126 lines
						
					
					
						
							4.7 KiB
						
					
					
				
								/* -*- c++ -*- (enables emacs c++ mode) */
							 | 
						|
								/*===========================================================================
							 | 
						|
								 
							 | 
						|
								 Copyright (C) 2003-2012 Yves Renard
							 | 
						|
								 
							 | 
						|
								 This file is a part of GETFEM++
							 | 
						|
								 
							 | 
						|
								 Getfem++  is  free software;  you  can  redistribute  it  and/or modify it
							 | 
						|
								 under  the  terms  of the  GNU  Lesser General Public License as published
							 | 
						|
								 by  the  Free Software Foundation;  either version 3 of the License,  or
							 | 
						|
								 (at your option) any later version along with the GCC Runtime Library
							 | 
						|
								 Exception either version 3.1 or (at your option) any later version.
							 | 
						|
								 This program  is  distributed  in  the  hope  that it will be useful,  but
							 | 
						|
								 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
							 | 
						|
								 or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
							 | 
						|
								 License and GCC Runtime Library Exception for more details.
							 | 
						|
								 You  should  have received a copy of the GNU Lesser General Public License
							 | 
						|
								 along  with  this program;  if not, write to the Free Software Foundation,
							 | 
						|
								 Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
							 | 
						|
								 
							 | 
						|
								 As a special exception, you  may use  this file  as it is a part of a free
							 | 
						|
								 software  library  without  restriction.  Specifically,  if   other  files
							 | 
						|
								 instantiate  templates  or  use macros or inline functions from this file,
							 | 
						|
								 or  you compile this  file  and  link  it  with other files  to produce an
							 | 
						|
								 executable, this file  does  not  by itself cause the resulting executable
							 | 
						|
								 to be covered  by the GNU Lesser General Public License.  This   exception
							 | 
						|
								 does not  however  invalidate  any  other  reasons why the executable file
							 | 
						|
								 might be covered by the GNU Lesser General Public License.
							 | 
						|
								 
							 | 
						|
								===========================================================================*/
							 | 
						|
								
							 | 
						|
								/**@file gmm_opt.h
							 | 
						|
								   @author  Yves Renard <Yves.Renard@insa-lyon.fr>
							 | 
						|
								   @date July 9, 2003.
							 | 
						|
								   @brief Optimization for some small cases (inversion of 2x2 matrices etc.)
							 | 
						|
								*/
							 | 
						|
								#ifndef GMM_OPT_H__
							 | 
						|
								#define GMM_OPT_H__
							 | 
						|
								
							 | 
						|
								namespace gmm {
							 | 
						|
								
							 | 
						|
								  /* ********************************************************************* */
							 | 
						|
								  /*    Optimized determinant and inverse for small matrices (2x2 and 3x3) */
							 | 
						|
								  /*    with dense_matrix<T>.                                              */
							 | 
						|
								  /* ********************************************************************* */
							 | 
						|
								
							 | 
						|
								  template <typename T>  T lu_det(const dense_matrix<T> &A) {
							 | 
						|
								    size_type n(mat_nrows(A));
							 | 
						|
								    if (n) {
							 | 
						|
								      const T *p = &(A(0,0));
							 | 
						|
								      switch (n) {
							 | 
						|
								      case 1 : return (*p);
							 | 
						|
								      case 2 : return (*p) * (*(p+3)) - (*(p+1)) * (*(p+2));
							 | 
						|
								// Not stable for nearly singular matrices
							 | 
						|
								//       case 3 : return (*p) * ((*(p+4)) * (*(p+8)) - (*(p+5)) * (*(p+7)))
							 | 
						|
								// 		 - (*(p+1)) * ((*(p+3)) * (*(p+8)) - (*(p+5)) * (*(p+6)))
							 | 
						|
								// 		 + (*(p+2)) * ((*(p+3)) * (*(p+7)) - (*(p+4)) * (*(p+6)));
							 | 
						|
								      default :
							 | 
						|
									{
							 | 
						|
									  dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
							 | 
						|
									  std::vector<size_type> ipvt(mat_nrows(A));
							 | 
						|
									  gmm::copy(A, B);
							 | 
						|
									  lu_factor(B, ipvt);
							 | 
						|
									  return lu_det(B, ipvt);	
							 | 
						|
									}
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								    return T(1);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  template <typename T> T lu_inverse(const dense_matrix<T> &A_) {
							 | 
						|
								    dense_matrix<T>& A = const_cast<dense_matrix<T> &>(A_);
							 | 
						|
								    size_type N = mat_nrows(A);
							 | 
						|
								    T det(1);
							 | 
						|
								    if (N) {
							 | 
						|
								      T *p = &(A(0,0));
							 | 
						|
								      if (N <= 2) {
							 | 
						|
									switch (N) {
							 | 
						|
									  case 1 : {
							 | 
						|
									    det = *p;
							 | 
						|
									    GMM_ASSERT1(det!=T(0), "non invertible matrix");
							 | 
						|
									    *p = T(1) / det; 
							 | 
						|
									  } break;
							 | 
						|
									  case 2 : {
							 | 
						|
									    det = (*p) * (*(p+3)) - (*(p+1)) * (*(p+2));
							 | 
						|
									    GMM_ASSERT1(det!=T(0), "non invertible matrix");
							 | 
						|
									    std::swap(*p, *(p+3));
							 | 
						|
									    *p++ /= det; *p++ /= -det; *p++ /= -det; *p++ /= det; 
							 | 
						|
									  } break;
							 | 
						|
								// 	  case 3 : { // not stable for nearly singular matrices
							 | 
						|
								// 	    T a, b, c, d, e, f, g, h, i;
							 | 
						|
								// 	    a =   (*(p+4)) * (*(p+8)) - (*(p+5)) * (*(p+7));
							 | 
						|
								// 	    b = - (*(p+1)) * (*(p+8)) + (*(p+2)) * (*(p+7));
							 | 
						|
								// 	    c =   (*(p+1)) * (*(p+5)) - (*(p+2)) * (*(p+4));
							 | 
						|
								// 	    d = - (*(p+3)) * (*(p+8)) + (*(p+5)) * (*(p+6));
							 | 
						|
								// 	    e =   (*(p+0)) * (*(p+8)) - (*(p+2)) * (*(p+6));
							 | 
						|
								// 	    f = - (*(p+0)) * (*(p+5)) + (*(p+2)) * (*(p+3));
							 | 
						|
								// 	    g =   (*(p+3)) * (*(p+7)) - (*(p+4)) * (*(p+6));
							 | 
						|
								// 	    h = - (*(p+0)) * (*(p+7)) + (*(p+1)) * (*(p+6));
							 | 
						|
								// 	    i =   (*(p+0)) * (*(p+4)) - (*(p+1)) * (*(p+3));
							 | 
						|
								// 	    det = (*p) * a + (*(p+1)) * d + (*(p+2)) * g;
							 | 
						|
								// 	    GMM_ASSERT1(det!=T(0), "non invertible matrix");
							 | 
						|
								// 	    *p++ = a / det; *p++ = b / det; *p++ = c / det; 
							 | 
						|
								// 	    *p++ = d / det; *p++ = e / det; *p++ = f / det; 
							 | 
						|
								// 	    *p++ = g / det; *p++ = h / det; *p++ = i / det; 
							 | 
						|
								// 	  } break;
							 | 
						|
									}
							 | 
						|
								      }
							 | 
						|
								      else {
							 | 
						|
									dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
							 | 
						|
									std::vector<int> ipvt(mat_nrows(A));
							 | 
						|
									gmm::copy(A, B);
							 | 
						|
									size_type info = lu_factor(B, ipvt);
							 | 
						|
									GMM_ASSERT1(!info, "non invertible matrix");
							 | 
						|
									lu_inverse(B, ipvt, A);
							 | 
						|
									return lu_det(B, ipvt);
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								    return det;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								#endif //  GMM_OPT_H__
							 |