contrib/mul/mbl/mbl_matxvec.cxx
Go to the documentation of this file.
00001 // This is mul/mbl/mbl_matxvec.cxx
00002 #include "mbl_matxvec.h"
00003 //:
00004 // \file
00005 // \brief Various specialised versions of simple linear algebra operators.
00006 // \author Tim Cootes
00007 // \date 3-Oct-97
00008 // Most of the specialisations are to do with size priorities. If the sizes
00009 // do not match for normal linear algebra operations, these functions will
00010 // for example, only use the first n elements of an >n input vector
00011 //
00012 // \verbatim
00013 // Modifications
00014 // TFC    Revised version 3-Oct-97
00015 // TFC    Added TC_MatXVec2
00016 // NPC    Added NC_VecXMat
00017 // IMS    started conversion to VXL 18 April 2001
00018 // \endverbatim
00019 
00020 #include <vnl/vnl_vector.h>
00021 #include <vnl/vnl_matrix.h>
00022 #include <vcl_cassert.h>
00023 #include <vcl_cstdlib.h> // for vcl_abort()
00024 #include <vcl_iostream.h>
00025 
00026 
00027 // Some of the code in this file has been converted to use VXL,
00028 // the rest has been #if-ed out. Only convert the other functions
00029 // as they are needed, and after checking that a suitable function doesn't
00030 // already exist in VXL.
00031 
00032 
00033 #if 0 // long part commented out
00034 // For testing
00035 static bool HasNaN(const char* s,
00036                    const vnl_matrix<double>& M)
00037 {
00038   for (int i=1;i<=M.nrows();++i)
00039   for (int j=1;j<=M.ncols();++j)
00040   {
00041     if (isnan(M(i,j)))
00042     {
00043       vcl_cout<<s<<" has NaN at element "<<i<<','<<j
00044               <<" in a "<<M.nrows()<<" x "<<M.ncols()<<" matrix.\n";
00045       return true;
00046     }
00047   }
00048   return false;
00049 }
00050 //=======================================================================
00051 
00052   //: Compute R = V*M
00053   //  R is resized to the number of rows of V * cols of M
00054 void NC_VecXMat(const vnl_vector<double>& V,
00055                 const vnl_matrix<double>& M,
00056                 vnl_matrix<double>& R)
00057 {
00058   int nrows = V.size();
00059   int ncols = M.ncols();
00060   if (M.nrows()>1)
00061   {
00062     vcl_cerr << "NC_VecXMat : M is a "<<M.nrows()<<"-row matrix.\n"
00063              << "it may only be 1-row.\n";
00064     vcl_abort();
00065   }
00066 
00067   R.set_size(nrows,ncols);
00068 
00069   const double* v_data = V.dataPtr();
00070   const double** M_data = M.dataPtr();
00071   double** R_data = R.dataPtr();
00072 
00073   for (int i=1;i<=nrows;i++)
00074   {
00075     const double *m_data = M_data[i];
00076     double *r_data = R_data[i];
00077     double vval = v_data[i];
00078     for (int j=1;j<=ncols;j++)
00079     {
00080       r_data[j] = vval * m_data[j];
00081     }
00082   }
00083 
00084   for (int i=1;i<=nrows;i++)
00085     for (int j=1;j<=ncols;j++)
00086       R(i,j) = V(i) * M(1,j);
00087 }
00088 #endif  //0 - long part commented out
00089 
00090 //=======================================================================
00091 
00092   //: Compute R = M*V
00093   //  Only use first V.size() columns of M
00094   //  R is resized to the number of rows of M
00095 void mbl_matxvec_prod_mv(const vnl_matrix<double>& M,
00096                          const vnl_vector<double>& V,
00097                          vnl_vector<double>& R)
00098 {
00099   int nr = M.rows();
00100 
00101   R.set_size(nr);
00102 
00103   mbl_matxvec_prod_mv_2(M,V,R);
00104 }
00105 
00106 //=======================================================================
00107 
00108 
00109   //: Compute R = M*V
00110   //  Only use first V.size() columns of M
00111   //  Only use first R.size() rows of M
00112   //  R is not resized - its size determines how many rows to use
00113 void mbl_matxvec_prod_mv_2(const vnl_matrix<double>& M,
00114                            const vnl_vector<double>& V,
00115                            vnl_vector<double>& R)
00116 {
00117   if (R.size()==0) return;
00118 
00119 
00120   int nR = R.size();
00121 #ifndef NDEBUG
00122   int nc = M.cols();
00123   int nr = M.rows();
00124   if (nR>nr)
00125   {
00126     vcl_cerr<<"ERROR: mbl_matxvec_prod_mv_2() R too long.\n";
00127     vcl_abort();
00128   }
00129 #endif
00130 
00131   double *Rdata = R.data_block();
00132 
00133   int t = V.size();
00134 #ifndef NDEBUG
00135   if (t>nc)
00136   {
00137     vcl_cerr<<"ERROR: mbl_matxvec_prod_mv_2() V too long. V has "<<t<<" elements. M has "<<nc<<" columns.\n";
00138     vcl_abort();
00139   }
00140 #endif
00141 
00142   if (t==0)
00143   {
00144     int r = nR;
00145     while (r--) Rdata[r]=0.0; // Zero R
00146     return;
00147   }
00148 
00149 #ifndef NDEBUG
00150   if ((nr<1) || (nc<1))
00151   {
00152     vcl_cerr<<"ERROR: mbl_matxvec_prod_mv_2() - vnl_matrix<double> is 0 x 0\n"
00153             <<"V has dimension "<<V.size()<<vcl_endl;
00154     vcl_abort();
00155   }
00156 #endif
00157 
00158   const double * const* Mdata = M.data_array();
00159   const double *Mdata2;
00160   const double *Vdata = V.data_block();
00161 
00162   int r = nR;
00163   while (r--) // Runs from nr-1 .. 0
00164   {
00165     double T=0.0;
00166     Mdata2 = Mdata[r];
00167     int c=t;
00168     while (c--) // Runs from t-1 .. 0
00169       T+=Mdata2[c] * Vdata[c];
00170 
00171     Rdata[r] = T;
00172   }
00173 }
00174 
00175 
00176 //=======================================================================
00177 
00178 
00179 #if 0 // long part commented out
00180 
00181 void TC_MatXVec(const vnl_matrix<double>& M,
00182                 const vnl_vector<double>& V,
00183                 vnl_vector<double>& R,
00184                 const vcl_vector<int>& index)
00185 // R = MV but only use sub-set of all rows of M
00186 {
00187   int nc = M.ncols();
00188   int nr = M.nrows();
00189   if (index.lo()!=1)
00190   {
00191     vcl_cerr<<"TC_MatXVec(M,V,R,index) : index array must begin at 1\n";
00192     vcl_abort();
00193   }
00194   int n = index.size();
00195 
00196 
00197   if (R.size()!=n) R.set_size(n);
00198   double *Rdata = R.dataPtr();
00199 
00200   int t = V.size();
00201   if (t>nc)
00202   {
00203     vcl_cerr<<"TC_MatXVec() R too long.\n";
00204     vcl_abort();
00205   }
00206 
00207   if (t==0)
00208   {
00209     int r = n+1;
00210     while (--r) Rdata[r]=0.0; // Zero R
00211     return;
00212   }
00213 
00214   if ((nr<1) || (nc<1))
00215   {
00216     vcl_cerr<<"TC_MatXVec - vnl_matrix<double> is 0 x 0\n"
00217             <<"V has dimension "<<V.size()<<vcl_endl;
00218     vcl_abort();
00219   }
00220 
00221   const double ** Mdata = M.dataPtr();
00222   const double *Mdata2;
00223   const double *Vdata = V.dataPtr();
00224   const int * i_data = index.dataPtr();
00225 
00226   int i = n+1;
00227   while (--i) // Runs from i .. 1
00228   {
00229     int r = i_data[i];
00230     double T=0.0;
00231     Mdata2 = Mdata[r];
00232     int c=t+1;
00233     while (--c) // Runs from t .. 1
00234       T+=Mdata2[c] * Vdata[c];
00235 
00236     Rdata[i] = T;
00237   }
00238 }
00239 #endif  //0 - long part commented out
00240 
00241 
00242 //=======================================================================
00243 // Fast Compute R = V' * M = ( M.transpose() * V ).transpose()
00244 void mbl_matxvec_prod_vm(const vnl_vector<double>& V,
00245                          const vnl_matrix<double>& M,
00246                          vnl_vector<double>& R)
00247 {
00248   R.fill(0.0);
00249   mbl_matxvec_add_prod_vm(V,M,R);
00250 }
00251 
00252 
00253 //=======================================================================
00254 // Fast Compute R += V' * M = ( M.transpose() * V ).transpose()
00255 void mbl_matxvec_add_prod_vm(const vnl_vector<double>& V,
00256                              const vnl_matrix<double>& M,
00257                              vnl_vector<double>& R)
00258 {
00259   unsigned int nr = M.rows();
00260 
00261 #ifndef NDEBUG
00262   unsigned int nc = M.cols();
00263   if (nr!=V.size())
00264   {
00265     vcl_cerr<<"ERROR: mbl_matxvec_add_prod_vm - V wrong length\n"
00266             <<"Expected "<<nr<<" got "<<V.size()<<vcl_endl;
00267     vcl_abort();
00268   }
00269 #endif //!NDEBUG
00270 
00271   unsigned int t = R.size();
00272   if (t==0) return;
00273 
00274 #ifndef NDEBUG
00275   assert(t<=nc); // R too long
00276   if ((nr<1) || (nc<1))
00277   {
00278     vcl_cerr<<"ERROR: mbl_matxvec_add_prod_vm - vnl_matrix<double> is 0 x 0\n"
00279             <<"V has dimension "<<V.size()<<vcl_endl;
00280     vcl_abort();
00281   }
00282 #endif //!NDEBUG
00283 
00284    const double *const * Mdata = M.data_array();
00285    const double * Vdata = V.data_block();
00286    double * Rdata = R.data_block();
00287 
00288   int r = nr;
00289   while (r--) // Runs from nr-1..0
00290   {
00291     double v = Vdata[r];
00292     const double *Mdata2 = Mdata[r];
00293     int c=t;
00294     while (c--) // Runs from t-1..0
00295       Rdata[c]+=Mdata2[c] * v;
00296   }
00297 }
00298 
00299 
00300 //=======================================================================
00301 
00302 
00303 #if 0 // long part commented out
00304 void TC_ProductABt(vnl_matrix<double>& ABt,
00305                    const vnl_matrix<double>& A,
00306                    const vnl_matrix<double>& B)
00307 // Returns A * B.transpose()
00308 {
00309    int nr1 = A.nrows();
00310    int nc1 = A.ncols();
00311    int nr2 = B.nrows();
00312    int nc2 = B.ncols();
00313 
00314 #ifndef NDEBUG
00315    if ( nc2 != nc1 )
00316    {
00317       vcl_cerr<<"TC_ProductABt : B.ncols != A.ncols\n";
00318       vcl_abort() ;
00319    }
00320 #endif //!NDEBUG
00321 
00322    if ( (ABt.nrows()!=nr1) || (ABt.ncols()!= nr2) )
00323     ABt.set_size( nr1, nr2 ) ;
00324 
00325   const double ** A_data = A.dataPtr();
00326   const double ** B_data = B.dataPtr();
00327   double ** R_data = ABt.dataPtr();
00328 
00329   int r = nr1 + 1;
00330   while (--r)
00331   {
00332     const double* A_row = A_data[r];
00333     double* R_row = R_data[r];
00334     int c = nr2 + 1;
00335     while (--c)
00336     {
00337       const double* B_row = B_data[c];
00338       double sum = 0.0 ;
00339       int i = nc1 + 1;
00340       while (--i) { sum += A_row[i] * B_row[i]; }
00341 
00342       R_row[c] = sum ;
00343     }
00344   }
00345 }
00346 
00347 
00348 //=======================================================================
00349 
00350 
00351 void TC_ProductAtB(vnl_matrix<double>& AtB,
00352                    const vnl_matrix<double>& A,
00353                    const vnl_matrix<double>& B)
00354 // Returns A.transpose() * B
00355 {
00356    int nr1 = A.nrows();
00357    int nc1 = A.ncols();
00358    int nr2 = B.nrows();
00359    int nc2 = B.ncols();
00360 
00361    if ( nr2 != nr1 )
00362    {
00363       vcl_cerr<<"TC_ProductAtB : B.nrows != A.nrows\n";
00364       vcl_abort() ;
00365    }
00366 
00367    if ( (AtB.nrows()!=nc1) || (AtB.ncols()!= nc2) )
00368     AtB.set_size( nc1, nc2 ) ;
00369 
00370   const double ** A_data = A.dataPtr();
00371   const double ** B_data = B.dataPtr();
00372   double ** R_data = AtB.dataPtr();
00373 
00374   // Zero the elements of R
00375   for (int r=1;r<=nc1;r++)
00376   {
00377     double *R_row = R_data[r];
00378     int c=nc2;
00379     while (c) { R_row[c] = 0.0; --c; }
00380   }
00381 
00382   for (int r1 = 1; r1<=nr1; r1++)
00383   {
00384     const double* A_row = A_data[r1];
00385     const double* B_row = B_data[r1];
00386     double a;
00387     int c1 =  nc1;
00388     while (c1)
00389     {
00390       double *R_row = R_data[c1];
00391       a = A_row[c1];
00392       int c2 = nc2;
00393       while (c2)
00394       {
00395         R_row[c2] +=a*B_row[c2];
00396         c2--;
00397       }
00398       c1--;
00399     }
00400   }
00401 }
00402 
00403 
00404 //=======================================================================
00405 
00406 
00407 //: Computes MD where D is diagonal with elements d(i)
00408 void TC_ProductMD(vnl_matrix<double>& MD,
00409                   const vnl_matrix<double>& M,
00410                   const vnl_vector<double>& d)
00411 {
00412   int nr = M.nrows();
00413   int nc = M.ncols();
00414   if (d.size()!=nc)
00415   {
00416     vcl_cerr<<"TC_ProductMD() d doesnt match M\n"
00417             <<"d is "<<d.size()<<" element vector.\n"
00418             <<"M is "<<nr<<" x "<<nc<<vcl_endl;
00419     vcl_abort();
00420   }
00421 
00422   if ((MD.nrows()!=nr) || (MD.ncols()!=nc)) MD.set_size(nr,nc);
00423 
00424   double **MD_data = MD.dataPtr();
00425   const double **M_data = M.dataPtr();
00426   const double *d_data = d.dataPtr();
00427 
00428   for (int r=1;r<=nr;++r)
00429   {
00430     const double* M_row = M_data[r];
00431     double *MR_row = MD_data[r];
00432     int c=nc;
00433     while (c) { MR_row[c] = M_row[c]*d_data[c]; --c; }
00434   }
00435 }
00436 
00437 //=======================================================================
00438 
00439 //: Computes DM where D is diagonal with elements d(i)
00440 void TC_ProductDM(vnl_matrix<double>& DM,
00441                   const vnl_matrix<double>& M,
00442                   const vnl_vector<double>& d)
00443 {
00444   int nr = M.nrows();
00445   int nc = M.ncols();
00446   if (d.size()!=nr)
00447   {
00448     vcl_cerr<<"TC_ProductDM() d doesnt match M\n"
00449             <<"d is "<<d.size()<<" element vector.\n"
00450             <<"M is "<<nr<<" x "<<nc<<vcl_endl;
00451     vcl_abort();
00452   }
00453 
00454   if ((DM.nrows()!=nr) || (DM.ncols()!=nc)) DM.set_size(nr,nc);
00455 
00456   double **DM_data = DM.dataPtr();
00457   const double **M_data = M.dataPtr();
00458   const double *d_data = d.dataPtr();
00459 
00460   for (int r=1;r<=nr;++r)
00461   {
00462     const double* M_row = M_data[r];
00463     double *DM_row = DM_data[r];
00464     double di = d_data[r];
00465     int c=nc;
00466     while (c) { DM_row[c] = di * M_row[c]; --c; }
00467   }
00468 }
00469 #endif  //0 - long part commented out