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.
		
		
		
		
		
			
		
			
				
					
					
						
							317 lines
						
					
					
						
							14 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							317 lines
						
					
					
						
							14 KiB
						
					
					
				| /* -*- c++ -*- (enables emacs c++ mode) */ | |
| /*=========================================================================== | |
|   | |
|  Copyright (C) 2003-2012 Yves Renard, Caroline Lecalvez | |
|   | |
|  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_dense_Householder.h | |
|    @author Caroline Lecalvez <Caroline.Lecalvez@gmm.insa-toulouse.fr> | |
|    @author Yves Renard <Yves.Renard@insa-lyon.fr> | |
|    @date June 5, 2003. | |
|    @brief Householder for dense matrices. | |
| */ | |
| 
 | |
| #ifndef GMM_DENSE_HOUSEHOLDER_H | |
| #define GMM_DENSE_HOUSEHOLDER_H | |
|  | |
| #include "gmm_kernel.h" | |
|  | |
| namespace gmm { | |
|   ///@cond DOXY_SHOW_ALL_FUNCTIONS | |
|  | |
|   /* ********************************************************************* */ | |
|   /*    Rank one update  (complex and real version)                        */ | |
|   /* ********************************************************************* */ | |
| 
 | |
|   template <typename Matrix, typename VecX, typename VecY> | |
|   inline void rank_one_update(Matrix &A, const VecX& x, | |
| 			      const VecY& y, row_major) { | |
|     typedef typename linalg_traits<Matrix>::value_type T; | |
|     size_type N = mat_nrows(A); | |
|     GMM_ASSERT2(N <= vect_size(x) && mat_ncols(A) <= vect_size(y), | |
| 	       "dimensions mismatch"); | |
|     typename linalg_traits<VecX>::const_iterator itx = vect_const_begin(x); | |
|     for (size_type i = 0; i < N; ++i, ++itx) { | |
|       typedef typename linalg_traits<Matrix>::sub_row_type row_type; | |
|       row_type row = mat_row(A, i); | |
|       typename linalg_traits<row_type>::iterator | |
| 	it = vect_begin(row), ite = vect_end(row); | |
|       typename linalg_traits<VecY>::const_iterator ity = vect_const_begin(y); | |
|       T tx = *itx; | |
|       for (; it != ite; ++it, ++ity) *it += conj_product(*ity, tx); | |
|     } | |
|   } | |
| 
 | |
|   template <typename Matrix, typename VecX, typename VecY> | |
|   inline void rank_one_update(Matrix &A, const VecX& x, | |
| 			      const VecY& y, col_major) { | |
|     typedef typename linalg_traits<Matrix>::value_type T; | |
|     size_type M = mat_ncols(A); | |
|     GMM_ASSERT2(mat_nrows(A) <= vect_size(x) && M <= vect_size(y), | |
| 		"dimensions mismatch"); | |
|     typename linalg_traits<VecY>::const_iterator ity = vect_const_begin(y); | |
|     for (size_type i = 0; i < M; ++i, ++ity) { | |
|       typedef typename linalg_traits<Matrix>::sub_col_type col_type; | |
|       col_type col = mat_col(A, i); | |
|       typename linalg_traits<col_type>::iterator | |
| 	it = vect_begin(col), ite = vect_end(col); | |
|       typename linalg_traits<VecX>::const_iterator itx = vect_const_begin(x); | |
|       T ty = *ity; | |
|       for (; it != ite; ++it, ++itx) *it += conj_product(ty, *itx); | |
|     } | |
|   } | |
|    | |
|   ///@endcond | |
|   template <typename Matrix, typename VecX, typename VecY> | |
|   inline void rank_one_update(const Matrix &AA, const VecX& x, | |
| 			      const VecY& y) { | |
|     Matrix& A = const_cast<Matrix&>(AA); | |
|     rank_one_update(A, x, y, typename principal_orientation_type<typename | |
| 		    linalg_traits<Matrix>::sub_orientation>::potype()); | |
|   } | |
|   ///@cond DOXY_SHOW_ALL_FUNCTIONS | |
|  | |
|   /* ********************************************************************* */ | |
|   /*    Rank two update  (complex and real version)                        */ | |
|   /* ********************************************************************* */ | |
| 
 | |
|   template <typename Matrix, typename VecX, typename VecY> | |
|   inline void rank_two_update(Matrix &A, const VecX& x, | |
| 			      const VecY& y, row_major) { | |
|     typedef typename linalg_traits<Matrix>::value_type value_type; | |
|     size_type N = mat_nrows(A); | |
|     GMM_ASSERT2(N <= vect_size(x) && mat_ncols(A) <= vect_size(y), | |
| 		"dimensions mismatch"); | |
|     typename linalg_traits<VecX>::const_iterator itx1 = vect_const_begin(x); | |
|     typename linalg_traits<VecY>::const_iterator ity2 = vect_const_begin(y); | |
|     for (size_type i = 0; i < N; ++i, ++itx1, ++ity2) { | |
|       typedef typename linalg_traits<Matrix>::sub_row_type row_type; | |
|       row_type row = mat_row(A, i); | |
|       typename linalg_traits<row_type>::iterator | |
| 	it = vect_begin(row), ite = vect_end(row); | |
|       typename linalg_traits<VecX>::const_iterator itx2 = vect_const_begin(x); | |
|       typename linalg_traits<VecY>::const_iterator ity1 = vect_const_begin(y); | |
|       value_type tx = *itx1, ty = *ity2; | |
|       for (; it != ite; ++it, ++ity1, ++itx2) | |
| 	*it += conj_product(*ity1, tx) + conj_product(*itx2, ty); | |
|     } | |
|   } | |
| 
 | |
|   template <typename Matrix, typename VecX, typename VecY> | |
|   inline void rank_two_update(Matrix &A, const VecX& x, | |
| 			      const VecY& y, col_major) { | |
|     typedef typename linalg_traits<Matrix>::value_type value_type; | |
|     size_type M = mat_ncols(A); | |
|     GMM_ASSERT2(mat_nrows(A) <= vect_size(x) && M <= vect_size(y), | |
| 		"dimensions mismatch"); | |
|     typename linalg_traits<VecX>::const_iterator itx2 = vect_const_begin(x); | |
|     typename linalg_traits<VecY>::const_iterator ity1 = vect_const_begin(y); | |
|     for (size_type i = 0; i < M; ++i, ++ity1, ++itx2) { | |
|       typedef typename linalg_traits<Matrix>::sub_col_type col_type; | |
|       col_type col = mat_col(A, i); | |
|       typename linalg_traits<col_type>::iterator | |
| 	it = vect_begin(col), ite = vect_end(col); | |
|       typename linalg_traits<VecX>::const_iterator itx1 = vect_const_begin(x); | |
|       typename linalg_traits<VecY>::const_iterator ity2 = vect_const_begin(y); | |
|       value_type ty = *ity1, tx = *itx2; | |
|       for (; it != ite; ++it, ++itx1, ++ity2) | |
| 	*it += conj_product(ty, *itx1) + conj_product(tx, *ity2);  | |
|     } | |
|   } | |
|    | |
|   ///@endcond | |
|   template <typename Matrix, typename VecX, typename VecY> | |
|   inline void rank_two_update(const Matrix &AA, const VecX& x, | |
| 			      const VecY& y) { | |
|     Matrix& A = const_cast<Matrix&>(AA); | |
|     rank_two_update(A, x, y, typename principal_orientation_type<typename | |
| 		    linalg_traits<Matrix>::sub_orientation>::potype()); | |
|   } | |
|   ///@cond DOXY_SHOW_ALL_FUNCTIONS | |
|  | |
|   /* ********************************************************************* */ | |
|   /*    Householder vector computation (complex and real version)          */ | |
|   /* ********************************************************************* */ | |
| 
 | |
|   template <typename VECT> void house_vector(const VECT &VV) { | |
|     VECT &V = const_cast<VECT &>(VV); | |
|     typedef typename linalg_traits<VECT>::value_type T; | |
|     typedef typename number_traits<T>::magnitude_type R; | |
|      | |
|     R mu = vect_norm2(V), abs_v0 = gmm::abs(V[0]); | |
|     if (mu != R(0)) | |
|       gmm::scale(V, (abs_v0 == R(0)) ? T(R(1) / mu) | |
| 		 : (safe_divide(T(abs_v0), V[0]) / (abs_v0 + mu))); | |
|     if (gmm::real(V[vect_size(V)-1]) * R(0) != R(0)) gmm::clear(V); | |
|     V[0] = T(1); | |
|   } | |
| 
 | |
|   template <typename VECT> void house_vector_last(const VECT &VV) { | |
|     VECT &V = const_cast<VECT &>(VV); | |
|     typedef typename linalg_traits<VECT>::value_type T; | |
|     typedef typename number_traits<T>::magnitude_type R; | |
| 
 | |
|     size_type m = vect_size(V); | |
|     R mu = vect_norm2(V), abs_v0 = gmm::abs(V[m-1]); | |
|     if (mu != R(0)) | |
|       gmm::scale(V, (abs_v0 == R(0)) ? T(R(1) / mu) | |
| 		 : ((abs_v0 / V[m-1]) / (abs_v0 + mu))); | |
|     if (gmm::real(V[0]) * R(0) != R(0)) gmm::clear(V); | |
|     V[m-1] = T(1); | |
|   } | |
|    | |
|   /* ********************************************************************* */ | |
|   /*    Householder updates  (complex and real version)                    */ | |
|   /* ********************************************************************* */ | |
| 
 | |
|   // multiply A to the left by the reflector stored in V. W is a temporary. | |
|   template <typename MAT, typename VECT1, typename VECT2> inline | |
|     void row_house_update(const MAT &AA, const VECT1 &V, const VECT2 &WW) { | |
|     VECT2 &W = const_cast<VECT2 &>(WW); MAT &A = const_cast<MAT &>(AA); | |
|     typedef typename linalg_traits<MAT>::value_type value_type; | |
|     typedef typename number_traits<value_type>::magnitude_type magnitude_type; | |
| 
 | |
|     gmm::mult(conjugated(A), | |
| 	      scaled(V, value_type(magnitude_type(-2)/vect_norm2_sqr(V))), W); | |
|     rank_one_update(A, V, W); | |
|   } | |
| 
 | |
|   // multiply A to the right by the reflector stored in V. W is a temporary. | |
|   template <typename MAT, typename VECT1, typename VECT2> inline | |
|     void col_house_update(const MAT &AA, const VECT1 &V, const VECT2 &WW) { | |
|     VECT2 &W = const_cast<VECT2 &>(WW); MAT &A = const_cast<MAT &>(AA); | |
|     typedef typename linalg_traits<MAT>::value_type value_type; | |
|     typedef typename number_traits<value_type>::magnitude_type magnitude_type; | |
|      | |
|     gmm::mult(A, | |
| 	      scaled(V, value_type(magnitude_type(-2)/vect_norm2_sqr(V))), W); | |
|     rank_one_update(A, W, V); | |
|   } | |
| 
 | |
|   ///@endcond | |
|  | |
|   /* ********************************************************************* */ | |
|   /*    Hessemberg reduction with Householder.                             */ | |
|   /* ********************************************************************* */ | |
| 
 | |
|   template <typename MAT1, typename MAT2> | |
|     void Hessenberg_reduction(const MAT1& AA, const MAT2 &QQ, bool compute_Q){ | |
|     MAT1& A = const_cast<MAT1&>(AA); MAT2& Q = const_cast<MAT2&>(QQ); | |
|     typedef typename linalg_traits<MAT1>::value_type value_type; | |
|     if (compute_Q) gmm::copy(identity_matrix(), Q); | |
|     size_type n = mat_nrows(A); if (n < 2) return; | |
|     std::vector<value_type> v(n), w(n); | |
|     sub_interval SUBK(0,n); | |
|     for (size_type k = 1; k+1 < n; ++k) { | |
|       sub_interval SUBI(k, n-k), SUBJ(k-1,n-k+1); | |
|       v.resize(n-k); | |
|       for (size_type j = k; j < n; ++j) v[j-k] = A(j, k-1); | |
|       house_vector(v); | |
|       row_house_update(sub_matrix(A, SUBI, SUBJ), v, sub_vector(w, SUBJ)); | |
|       col_house_update(sub_matrix(A, SUBK, SUBI), v, w); | |
|       // is it possible to "unify" the two on the common part of the matrix? | |
|       if (compute_Q) col_house_update(sub_matrix(Q, SUBK, SUBI), v, w); | |
|     } | |
|   } | |
| 
 | |
|   /* ********************************************************************* */ | |
|   /*    Householder tridiagonalization for symmetric matrices              */ | |
|   /* ********************************************************************* */ | |
| 
 | |
|   template <typename MAT1, typename MAT2>  | |
|   void Householder_tridiagonalization(const MAT1 &AA, const MAT2 &QQ, | |
| 				     bool compute_q) { | |
|     MAT1 &A = const_cast<MAT1 &>(AA); MAT2 &Q = const_cast<MAT2 &>(QQ); | |
|     typedef typename linalg_traits<MAT1>::value_type T; | |
|     typedef typename number_traits<T>::magnitude_type R; | |
| 
 | |
|     size_type n = mat_nrows(A); if (n < 2) return; | |
|     std::vector<T> v(n), p(n), w(n), ww(n); | |
|     sub_interval SUBK(0,n); | |
| 
 | |
|     for (size_type k = 1; k+1 < n; ++k) { // not optimized ... | |
|       sub_interval SUBI(k, n-k); | |
|       v.resize(n-k); p.resize(n-k); w.resize(n-k);  | |
|       for (size_type l = k; l < n; ++l)  | |
| 	{ v[l-k] = w[l-k] = A(l, k-1); A(l, k-1) = A(k-1, l) = T(0); } | |
|       house_vector(v); | |
|       R norm = vect_norm2_sqr(v); | |
|       A(k-1, k) = gmm::conj(A(k, k-1) = w[0] - T(2)*v[0]*vect_hp(w, v)/norm); | |
| 
 | |
|       gmm::mult(sub_matrix(A, SUBI), gmm::scaled(v, T(-2) / norm), p); | |
|       gmm::add(p, gmm::scaled(v, -vect_hp(v, p) / norm), w); | |
|       rank_two_update(sub_matrix(A, SUBI), v, w); | |
|       // it should be possible to compute only the upper or lower part | |
|  | |
|       if (compute_q) col_house_update(sub_matrix(Q, SUBK, SUBI), v, ww); | |
|     } | |
|   } | |
| 
 | |
|   /* ********************************************************************* */ | |
|   /*    Real and complex Givens rotations                                  */ | |
|   /* ********************************************************************* */ | |
| 
 | |
|   template <typename T> void Givens_rotation(T a, T b, T &c, T &s) { | |
|     typedef typename number_traits<T>::magnitude_type R; | |
|     R aa = gmm::abs(a), bb = gmm::abs(b); | |
|     if (bb == R(0)) { c = T(1); s = T(0);   return; } | |
|     if (aa == R(0)) { c = T(0); s = b / bb; return; } | |
|     if (bb > aa) | |
|       { T t = -safe_divide(a,b); s = T(R(1) / (sqrt(R(1)+gmm::abs_sqr(t)))); c = s * t; } | |
|     else | |
|       { T t = -safe_divide(b,a); c = T(R(1) / (sqrt(R(1)+gmm::abs_sqr(t)))); s = c * t; } | |
|   } | |
| 
 | |
|   // Apply Q* v | |
|   template <typename T> inline | |
|   void Apply_Givens_rotation_left(T &x, T &y, T c, T s) | |
|   { T t1=x, t2=y; x = gmm::conj(c)*t1 - gmm::conj(s)*t2; y = c*t2 + s*t1; } | |
| 
 | |
|   // Apply v^T Q | |
|   template <typename T> inline | |
|   void Apply_Givens_rotation_right(T &x, T &y, T c, T s) | |
|   { T t1=x, t2=y; x = c*t1 - s*t2; y = gmm::conj(c)*t2 + gmm::conj(s)*t1; } | |
| 
 | |
|   template <typename MAT, typename T> | |
|   void row_rot(const MAT &AA, T c, T s, size_type i, size_type k) { | |
|     MAT &A = const_cast<MAT &>(AA); // can be specialized for row matrices | |
|     for (size_type j = 0; j < mat_ncols(A); ++j) | |
|       Apply_Givens_rotation_left(A(i,j), A(k,j), c, s); | |
|   } | |
| 
 | |
|   template <typename MAT, typename T> | |
|   void col_rot(const MAT &AA, T c, T s, size_type i, size_type k) { | |
|     MAT &A = const_cast<MAT &>(AA); // can be specialized for column matrices | |
|     for (size_type j = 0; j < mat_nrows(A); ++j) | |
|       Apply_Givens_rotation_right(A(j,i), A(j,k), c, s); | |
|   } | |
|    | |
| } | |
| 
 | |
| #endif | |
| 
 |