|
STK++ 1.0
|
00001 /*--------------------------------------------------------------------*/ 00002 /* Copyright (C) 2004-2007 Serge Iovleff 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU Lesser General Public License as 00006 published by the Free Software Foundation; either version 2 of the 00007 License, or (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU Lesser General Public License for more details. 00013 00014 You should have received a copy of the GNU Lesser General Public 00015 License along with this program; if not, write to the 00016 Free Software Foundation, Inc., 00017 59 Temple Place, 00018 Suite 330, 00019 Boston, MA 02111-1307 00020 USA 00021 00022 Contact : Serge.Iovleff@stkpp.org 00023 */ 00024 00025 /* 00026 * Project: Algebra 00027 * Purpose: Define Householder methods for Algebra classes. 00028 * Author: Serge Iovleff, serge.iovleff@stkpp.org 00029 * 00030 **/ 00031 00036 #ifndef STK_HOUSEHOLDER_H 00037 #define STK_HOUSEHOLDER_H 00038 00039 // Matrix class 00040 #include "../../Arrays/include/STK_Matrix.h" 00041 00042 // for normInf 00043 #include "STK_LinAlgebra1D.h" 00044 00045 namespace STK 00046 { 00059 template <class TContainer1D> 00060 Real house(ITContainer1D<Real, TContainer1D>& x) 00061 { 00062 // compute L^{\infty} norm of X 00063 Real scale = normInf(x); 00064 // first and last index fo the essential Householder vector 00065 Integer first = x.first()+1, last = x.last(); 00066 // result and norm2 of X 00067 Real v1, norm2 = 0.0; 00068 // normalize the vector 00069 if (scale) // if not 0.0 00070 { 00071 for (Integer i=first; i<=last; i++) 00072 { x[i] /= scale; norm2 += x[i]*x[i];} 00073 } 00074 // check if the lower part is significative 00075 if (norm2 < Arithmetic<Real>::epsilon()) 00076 { 00077 v1 = x.front(); x.front() = 0.0; // beta = 0.0 00078 } 00079 else 00080 { 00081 Real s, aux1 = x.front() / scale; 00082 // compute v1 = P_v X and beta of the Householder vector 00083 v1 = (norm2 = sign(aux1, sqrt(aux1*aux1+norm2))) * scale; 00084 // compute and save beta 00085 x.front() = (s = aux1-norm2)/norm2; 00086 // comp v and save it 00087 for (Integer i=first; i<=last; i++) x[i] /= s; 00088 } 00089 return v1; 00090 } 00091 00100 template< class TContainer1D_1 00101 , class TContainer1D_2 00102 > 00103 Real dotHouse( const ITContainer1D<Real, TContainer1D_1>& x 00104 , const ITContainer1D<Real, TContainer1D_2>& v 00105 ) 00106 { 00107 // first and last index fo the essential Householder vector 00108 const Integer first = v.first()+1, last = v.last(); 00109 // compute the product 00110 Real sum = x[first-1] /* *1.0 */; 00111 for (Integer i=first; i<=last; i++) sum += x[i] * v[i]; 00112 // return <x,v> 00113 return(sum); 00114 } 00115 00124 template < class TContainer2D, class TContainer1D> 00125 void leftHouseholder( ITContainer2D< Real, TContainer2D> const& M 00126 , ITContainer1D< Real, TContainer1D> const& v 00127 ) 00128 { 00129 // get beta 00130 Real beta = v.front(); 00131 if (beta) 00132 { 00133 // get range of the Householder vector 00134 Range range_ve = v.range(); 00135 // Multiplication of the cols by P=I+beta vv' 00136 for (Integer j=M.firstCol(); j<=M.lastCol(); j++) 00137 { 00138 // a ref on the jth column of M 00139 typename TContainer2D::TContainerVe Mj(M.asLeaf(), range_ve, j); 00140 // Computation of aux=beta* <v,M^j> 00141 Real aux = dotHouse( Mj, v) * beta; 00142 // updating row X.first() 00143 Mj.front() += aux; 00144 // essential range of v 00145 const Integer first = v.first()+1, last = v.last(); 00146 // Computation of M^j + beta <v,M^j> v = M^j + aux v 00147 for (Integer i=first; i<=last; i++) 00148 Mj[i] += v[i] * aux; 00149 } 00150 } 00151 } 00152 00162 template < class TContainer2D, class TContainer1D> 00163 void rightHouseholder( ITContainer2D< Real, TContainer2D> const& M 00164 , ITContainer1D< Real, TContainer1D> const& v 00165 ) 00166 { 00167 // get beta 00168 Real beta = v.front(); 00169 if (beta) 00170 { 00171 // Multiplication of the cols by P=I+beta vv' 00172 for (Integer i=M.firstRow(); i<=M.lastRow(); i++) 00173 { 00174 // a ref on the ith row of M 00175 typename TContainer2D::TContainerHo Mi(M.asLeaf(), v.range(), i); 00176 // Computation of aux=beta* <v,M_i> 00177 Real aux = dotHouse( Mi, v) * beta; 00178 // updating column X.first() 00179 Mi.front() += aux; 00180 // essential range of v 00181 const Integer first = v.first()+1, last = v.last(); 00182 // Computation of M_i + beta <v,M_i> v = M_i + aux v' 00183 for (Integer i=first; i<=last; i++) 00184 Mi[i] += v[i] * aux; 00185 } 00186 } 00187 } 00188 00199 template < class TContainer2D> 00200 void leftHouseholder( ITContainer2D< Real, TContainer2D> const& M 00201 , Matrix const& H 00202 ) 00203 { 00204 // compute the number of iterations 00205 Integer first = H.firstCol(), last = min( H.lastCol(), H.lastRow()); 00206 // get range of the first Householder vector 00207 Range range_ve(last, H.lastRow()); 00208 // iterations 00209 for (Integer j=last; j>=first; j--) 00210 { 00211 // apply left Householder vector to M 00212 leftHouseholder(M, H(range_ve, j)); 00213 // decrease range of the Householder vector 00214 range_ve.decFirst(); 00215 } 00216 } 00217 00228 template < class TContainer2D> 00229 void rightHouseholder( ITContainer2D< Real, TContainer2D> const& M 00230 , Matrix const& H 00231 ) 00232 { 00233 // compute the number of iterations 00234 Integer first = H.firstCol(), last = min( H.lastCol(), H.lastRow()); 00235 // get range of the first Householder vector 00236 Range range_ve(last, H.lastRow()); 00237 // iterations 00238 for (Integer j=last; j>=first; j--) 00239 { 00240 // apply left Householder vector to M 00241 rightHouseholder(M, H(range_ve, j)); 00242 // decrease range of the Householder vector 00243 range_ve.decFirst(); 00244 } 00245 } 00246 00247 } // namespace STK 00248 00249 #endif /*STK_HOUSEHOLDER_H*/