Object-oriented Scientific Computing Library: Version 0.910
householder_base.h
Go to the documentation of this file.
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
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.