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
							 | 
						|
								
							 |