![]() |
Object-oriented Scientific Computing Library: Version 0.910
|
00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006-2012, Andrew W. Steiner 00005 00006 This file is part of O2scl. 00007 00008 O2scl is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 O2scl is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with O2scl. If not, see <http://www.gnu.org/licenses/>. 00020 00021 ------------------------------------------------------------------- 00022 */ 00023 /* linalg/householder.c 00024 * 00025 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004, 00026 * 2007 Gerard Jungman, Brian Gough 00027 * 00028 * This program is free software; you can redistribute it and/or modify 00029 * it under the terms of the GNU General Public License as published by 00030 * the Free Software Foundation; either version 3 of the License, or (at 00031 * your option) any later version. 00032 * 00033 * This program is distributed in the hope that it will be useful, but 00034 * WITHOUT ANY WARRANTY; without even the implied warranty of 00035 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00036 * General Public License for more details. 00037 * 00038 * You should have received a copy of the GNU General Public License 00039 * along with this program; if not, write to the Free Software 00040 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00041 * 02110-1301, USA. 00042 */ 00043 /** \file householder_base.h 00044 \brief File for Householder transformations 00045 00046 \todo Better documentation for the Householder functions. 00047 */ 00048 00049 #include <gsl/gsl_machine.h> 00050 00051 #include <o2scl/err_hnd.h> 00052 #include <o2scl/cblas.h> 00053 #include <o2scl/permutation.h> 00054 #include <o2scl/vec_arith.h> 00055 00056 #ifdef DOXYGENP 00057 namespace o2scl_linalg { 00058 #endif 00059 00060 /** \brief Replace the vector \c v with a Householder vector and a 00061 coefficient tau that annihilates <tt>v[1]</tt> through 00062 <tt>v[n-1]</tt> (inclusive) 00063 00064 On exit, this function returns the value of \f$ \tau = 2/ (v^{T} 00065 v) \f$. If \c n is less than or equal to 1 then this function 00066 returns zero without calling the error handler. 00067 */ 00068 template<class vec_t> 00069 double householder_transform(const size_t n, vec_t &v) { 00070 00071 if (n <= 1) { 00072 00073 // tau=0 00074 return 0.0; 00075 00076 } else { 00077 00078 double alpha, beta, tau; 00079 double xnorm=O2SCL_CBLAS_NAMESPACE::dnrm2_subvec(n,v,1); 00080 00081 if (xnorm == 0) { 00082 // tau=0 00083 return 0.0; 00084 } 00085 00086 alpha=O2SCL_IX(v,0); 00087 beta=-(alpha >= 0.0 ? +1.0 : -1.0)*hypot(alpha,xnorm); 00088 tau=(beta-alpha)/beta; 00089 00090 double s=(alpha-beta); 00091 if (fabs(s)>GSL_DBL_MIN) { 00092 O2SCL_CBLAS_NAMESPACE::dscal_subvec(1.0/s,n,v,1); 00093 O2SCL_IX(v,0)=beta; 00094 } else { 00095 O2SCL_CBLAS_NAMESPACE::dscal_subvec(GSL_DBL_EPSILON/s,n,v,1); 00096 O2SCL_CBLAS_NAMESPACE::dscal_subvec(1.0/GSL_DBL_EPSILON,n,v,1); 00097 O2SCL_IX(v,0)=beta; 00098 } 00099 00100 return tau; 00101 } 00102 } 00103 00104 /** \brief Compute the Householder transform of a vector 00105 formed with \c n rows of a column of a matrix 00106 00107 This performs a Householder transform of a vector defined by a 00108 column of a matrix \c A which starts at element 00109 <tt>A[ir][ic]</tt> and ends at element <tt>A[N-1][ic]</tt>. 00110 00111 Used in QR_decomp(). 00112 */ 00113 template<class mat_t> 00114 double householder_transform_subcol(mat_t &A, const size_t ir, 00115 const size_t ic, const size_t M) { 00116 00117 if (M == ir+1) { 00118 /* tau=0 */ 00119 return 0.0; 00120 } else { 00121 double alpha, beta, tau; 00122 00123 double xnorm=o2scl_cblas::dnrm2_subcol(A,ir+1,ic,M); 00124 00125 if (xnorm == 0) { 00126 /* tau=0 */ 00127 return 0.0; 00128 } 00129 00130 alpha=O2SCL_IX2(A,ir,ic); 00131 beta=-(alpha >= 0.0 ? +1.0 : -1.0)*hypot(alpha,xnorm); 00132 tau=(beta-alpha)/beta; 00133 00134 double s=(alpha-beta); 00135 if (fabs(s)>GSL_DBL_MIN) { 00136 o2scl_cblas::dscal_subcol(A,ir+1,ic,M,1.0/s); 00137 O2SCL_IX2(A,ir,ic)=beta; 00138 } else { 00139 o2scl_cblas::dscal_subcol(A,ir+1,ic,M,GSL_DBL_EPSILON/s); 00140 o2scl_cblas::dscal_subcol(A,ir+1,ic,M,1.0/GSL_DBL_EPSILON); 00141 O2SCL_IX2(A,ir,ic)=beta; 00142 } 00143 00144 return tau; 00145 } 00146 } 00147 00148 /** \brief Compute the Householder transform of a vector 00149 formed with the last \c n columns of a row of a matrix 00150 00151 This performs a Householder transform of a vector 00152 defined by a row of a matrix \c A which starts at element 00153 <tt>A[ir][ic]</tt> and ends at element <tt>A[ir][N-1]</tt> 00154 */ 00155 template<class mat_t> 00156 double householder_transform_subrow(mat_t &A, const size_t ir, 00157 const size_t ic, const size_t N) { 00158 00159 if (N == ic+1) { 00160 /* tau=0 */ 00161 return 0.0; 00162 } else { 00163 double alpha, beta, tau; 00164 00165 double xnorm=o2scl_cblas::dnrm2_subrow(A,ir,ic+1,N); 00166 00167 if (xnorm == 0) { 00168 /* tau=0 */ 00169 return 0.0; 00170 } 00171 00172 alpha=O2SCL_IX2(A,ir,ic); 00173 beta=-(alpha >= 0.0 ? +1.0 : -1.0)*hypot(alpha,xnorm); 00174 tau=(beta-alpha)/beta; 00175 00176 double s=(alpha-beta); 00177 if (fabs(s)>GSL_DBL_MIN) { 00178 o2scl_cblas::dscal_subrow(A,ir,ic+1,N,1.0/s); 00179 O2SCL_IX2(A,ir,ic)=beta; 00180 } else { 00181 o2scl_cblas::dscal_subrow(A,ir,ic+1,N,GSL_DBL_EPSILON/s); 00182 o2scl_cblas::dscal_subrow(A,ir,ic+1,N,1.0/GSL_DBL_EPSILON); 00183 O2SCL_IX2(A,ir,ic)=beta; 00184 } 00185 00186 return tau; 00187 } 00188 } 00189 00190 /** \brief Apply a Householder transformation \f$ (v,\tau) \f$ to 00191 matrix \f$ A \f$ of size \f$ M \f$ by \f$ N \f$ 00192 */ 00193 template<class vec_t, class mat_t> 00194 void householder_hm(const size_t M, const size_t N, 00195 double tau, const vec_t &v, mat_t &A) { 00196 00197 if (tau == 0.0) { 00198 return; 00199 } 00200 00201 size_t i, j; 00202 00203 for (j=0;j<N;j++) { 00204 00205 /* Compute wj=Akj vk */ 00206 double wj=O2SCL_IX2(A,0,j); 00207 00208 for (i=1;i<M;i++) { 00209 wj+=O2SCL_IX2(A,i,j)*O2SCL_IX(v,i); 00210 } 00211 00212 /* Aij=Aij-tau vi wj */ 00213 00214 /* i=0 */ 00215 O2SCL_IX2(A,0,j)-=tau*wj; 00216 00217 /* i=1 .. M-1 */ 00218 for (i=1;i<M;i++) { 00219 O2SCL_IX2(A,i,j)-=tau*wj*O2SCL_IX(v,i); 00220 } 00221 } 00222 return; 00223 } 00224 00225 /** \brief Apply a Householder transformation to submatrix of a 00226 larger matrix 00227 00228 This applies a householder transformation <tt>(v,tau)</tt> to 00229 submatrix of \c M. The submatrix has \c nr rows and \c nc 00230 columns and starts at row \c ir of column \c ic of the original 00231 matrix \c M. The vector \c v is taken from a column of \c M2 00232 starting at row \c ir2 and column \c ic2. 00233 00234 This function is used in \ref QR_decomp(). 00235 */ 00236 template<class mat_t> 00237 void householder_hm_sub(mat_t &M, const size_t ir, 00238 const size_t ic, const size_t nr, 00239 const size_t nc, const mat_t &M2, 00240 const size_t ir2, const size_t ic2, 00241 double tau) { 00242 00243 if (tau == 0.0) { 00244 return; 00245 } 00246 00247 size_t i, j, last=nr; 00248 00249 for (j=ic;j<nc;j++) { 00250 00251 /* Compute wj=Akj vk */ 00252 double wj=O2SCL_IX2(M,ir,j); 00253 00254 for (i=ir+1;i<last;i++) { 00255 wj+=O2SCL_IX2(M,i,j)*O2SCL_IX2(M2,i-ir+ir2,ic2); 00256 } 00257 00258 /* Aij=Aij-tau vi wj */ 00259 00260 /* i=0 */ 00261 O2SCL_IX2(M,ir,j)-=tau*wj; 00262 00263 /* i=1 .. M-1 */ 00264 for (i=ir+1;i<last;i++) { 00265 O2SCL_IX2(M,i,j)-=tau*wj*O2SCL_IX2(M2,i-ir+ir2,ic2); 00266 } 00267 } 00268 return; 00269 } 00270 00271 /** \brief Special version of Householder transformation for 00272 QR_unpack() 00273 */ 00274 template<class mat1_t, class mat2_t> 00275 void householder_hm_sub2(const size_t M, const size_t ic, 00276 double tau, const mat1_t &mv, mat2_t &A) { 00277 00278 if (tau == 0.0) { 00279 return; 00280 } 00281 00282 size_t i, j; 00283 00284 for (j=ic;j<M;j++) { 00285 00286 /* Compute wj=Akj vk */ 00287 double wj=O2SCL_IX2(A,ic,j); 00288 00289 for (i=ic+1;i<M;i++) { 00290 wj+=O2SCL_IX2(A,i,j)*O2SCL_IX2(mv,i,ic); 00291 } 00292 00293 /* Aij=Aij-tau vi wj */ 00294 00295 /* i=0 */ 00296 O2SCL_IX2(A,ic,j)-=tau*wj; 00297 00298 /* i=1 .. M-1 */ 00299 for (i=ic+1;i<M;i++) { 00300 O2SCL_IX2(A,i,j)-=tau*wj*O2SCL_IX2(mv,i,ic); 00301 } 00302 } 00303 return; 00304 } 00305 00306 /** \brief Apply a Householder transformation \c v to vector \c w 00307 */ 00308 template<class vec_t, class vec2_t> 00309 void householder_hv(const size_t N, double tau, const vec_t &v, 00310 vec2_t &w) { 00311 00312 if (tau==0) return; 00313 00314 // compute d=v'w 00315 00316 double d0=O2SCL_IX(w,0); 00317 double d1, d; 00318 00319 d1=o2scl_cblas::ddot_subvec(N,v,w,1); 00320 00321 d=d0+d1; 00322 00323 // compute w=w-tau(v)(v'w) 00324 O2SCL_IX(w,0)-=tau*d; 00325 00326 o2scl_cblas::daxpy_subvec(-tau*d,N,v,w,1); 00327 00328 return; 00329 } 00330 00331 /** \brief Apply a Householder transformation \c v to vector \c w 00332 where \c v is stored as a column in a matrix \c A 00333 00334 Used in QR_QTvec(). 00335 */ 00336 template<class mat_t, class vec_t> 00337 void householder_hv_subcol(const mat_t &A, vec_t &w, double tau, 00338 const size_t ie, const size_t N) { 00339 00340 if (tau==0) return; 00341 00342 // compute d=v'w 00343 00344 double d0=O2SCL_IX(w,ie); 00345 double d1, d; 00346 00347 d1=o2scl_cblas::ddot_subcol(N,A,ie+1,ie,w); 00348 00349 d=d0+d1; 00350 00351 // compute w=w-tau(v)(v'w) 00352 O2SCL_IX(w,ie)-=tau*d; 00353 00354 o2scl_cblas::daxpy_subcol(-tau*d,N,A,ie+1,ie,w); 00355 00356 return; 00357 } 00358 00359 /** \brief Apply a Householder transformation \f$ (v,\tau) \f$ to a 00360 matrix being build up from the identity matrix, using the first 00361 column of A as a Householder vector 00362 */ 00363 template<class mat_t> 00364 void householder_hm1(const size_t M, const size_t N, 00365 double tau, mat_t &A) { 00366 00367 if (tau == 0) { 00368 size_t i,j; 00369 O2SCL_IX2(A,0,0)=1.0; 00370 for (j=1;j<N;j++) { 00371 O2SCL_IX2(A,0,j)=0.0; 00372 } 00373 for (i=1;i<M;i++) { 00374 O2SCL_IX2(A,i,0)=0.0; 00375 } 00376 return; 00377 } 00378 00379 /* w=A' v */ 00380 00381 size_t i, j; 00382 for (j=1;j<N;j++) { 00383 double wj=0.0; 00384 for (i=1;i<M;i++) { 00385 wj+=O2SCL_IX2(A,i,j)*O2SCL_IX2(A,i,0);; 00386 } 00387 00388 /* A=A-tau v w' */ 00389 O2SCL_IX2(A,0,j)=-tau*wj; 00390 00391 for (i=1;i<M;i++) { 00392 O2SCL_IX2(A,i,j)-=tau*wj*O2SCL_IX2(A,i,0); 00393 } 00394 } 00395 00396 for (i=1;i<M;i++) { 00397 O2SCL_IX2(A,i,0)=-tau*O2SCL_IX2(A,i,0); 00398 } 00399 O2SCL_IX2(A,0,0)=1.0-tau; 00400 00401 return; 00402 } 00403 00404 /** \brief Apply the Householder transformation <tt>(v,tau)</tt> to 00405 the right-hand side of the matrix \c A. 00406 */ 00407 template<class vec_t, class mat_t> 00408 void householder_mh(const size_t M, const size_t N, 00409 double tau, const vec_t &v, mat_t &A) { 00410 00411 if (tau==0.0) { 00412 return; 00413 } 00414 00415 /* A=A-tau w v' */ 00416 size_t i, j; 00417 00418 for (i=0;i<M;i++) { 00419 00420 double wi=O2SCL_IX2(A,i,0); 00421 00422 /* note, computed for v(0)=1 above */ 00423 for (j=1;j<N;j++) { 00424 wi+=O2SCL_IX2(A,i,j)*O2SCL_IX(v,j); 00425 } 00426 00427 /* j=0 */ 00428 O2SCL_IX2(A,i,0)-=tau*wi; 00429 00430 /* j=1 .. N-1 */ 00431 for (j=1;j<N;j++) { 00432 O2SCL_IX2(A,i,j)-=tau*wi*O2SCL_IX(v,j); 00433 } 00434 } 00435 00436 return; 00437 } 00438 00439 /** \brief Apply the Householder transformation <tt>(v,tau)</tt> to 00440 the right-hand side of the matrix \c A. 00441 00442 This is unfinished but needed for the bidiagonalization 00443 functions. 00444 */ 00445 template<class mat_t, class mat2_t> 00446 void householder_mh_sub(mat_t &M, const size_t ir, const size_t ic, 00447 const size_t nr, const size_t nc, const mat2_t &M2, 00448 const size_t ir2, const size_t ic2, double tau) { 00449 00450 if (tau==0.0) { 00451 return; 00452 } 00453 00454 /* A=A-tau w v' */ 00455 size_t i, j, last=ic+nc; 00456 00457 for (i=ir;i<ir+nr;i++) { 00458 00459 double wi=O2SCL_IX2(M,i,ic); 00460 00461 /* note, computed for v(0)=1 above */ 00462 for (j=ic+1;j<last;j++) { 00463 wi+=O2SCL_IX2(M,i,j)*O2SCL_IX2(M2,ir2,j-ic+ic2); 00464 } 00465 00466 /* j=0 */ 00467 O2SCL_IX2(M,i,ic)-=tau*wi; 00468 00469 /* j=1 .. N-1 */ 00470 for (j=ic+1;j<last;j++) { 00471 O2SCL_IX2(M,i,j)-=tau*wi*O2SCL_IX2(M2,ir2,j-ic+ic2); 00472 } 00473 } 00474 00475 return; 00476 } 00477 00478 #ifdef DOXYGENP 00479 } 00480 #endif
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).