core/vnl/algo/vnl_cholesky.cxx
Go to the documentation of this file.
00001 // This is core/vnl/algo/vnl_cholesky.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // vnl_cholesky
00008 // \author Andrew W. Fitzgibbon, Oxford RRG
00009 // Created: 08 Dec 96
00010 //
00011 //-----------------------------------------------------------------------------
00012 
00013 #include "vnl_cholesky.h"
00014 #include <vcl_cmath.h> // pow()
00015 #include <vcl_cassert.h>
00016 #include <vcl_iostream.h>
00017 #include <vnl/algo/vnl_netlib.h> // dpofa_(), dposl_(), dpoco_(), dpodi_()
00018 
00019 //: Cholesky decomposition.
00020 // Make cholesky decomposition of M optionally computing
00021 // the reciprocal condition number.  If mode is estimate_condition, the
00022 // condition number and an approximate nullspace are estimated, at a cost
00023 // of a factor of (1 + 18/n).  Here's a table of 1 + 18/n:
00024 // \verbatim
00025 // n:              3      5     10     50    100    500   1000
00026 // slowdown:     7.0    4.6    2.8    1.4   1.18   1.04   1.02
00027 // \endverbatim
00028 
00029 vnl_cholesky::vnl_cholesky(vnl_matrix<double> const & M, Operation mode):
00030   A_(M)
00031 {
00032   long n = M.columns();
00033   assert(n == (int)(M.rows()));
00034   num_dims_rank_def_ = -1;
00035   if (vcl_fabs(M(0,n-1) - M(n-1,0)) > 1e-8) {
00036     vcl_cerr << "vnl_cholesky: WARNING: non-symmetric: " << M << vcl_endl;
00037   }
00038 
00039   if (mode != estimate_condition) {
00040     // Quick factorization
00041     v3p_netlib_dpofa_(A_.data_block(), &n, &n, &num_dims_rank_def_);
00042     if (mode == verbose && num_dims_rank_def_ != 0)
00043       vcl_cerr << "vnl_cholesky: " << num_dims_rank_def_ << " dimensions of non-posdeffness\n";
00044   }
00045   else {
00046     vnl_vector<double> nullvec(n);
00047     v3p_netlib_dpoco_(A_.data_block(), &n, &n, &rcond_, nullvec.data_block(), &num_dims_rank_def_);
00048     if (num_dims_rank_def_ != 0)
00049       vcl_cerr << "vnl_cholesky: rcond=" << rcond_ << " so " << num_dims_rank_def_ << " dimensions of non-posdeffness\n";
00050   }
00051 }
00052 
00053 //: Solve least squares problem M x = b.
00054 //  The right-hand-side vcl_vector x may be b,
00055 //  which will give a fractional increase in speed.
00056 void vnl_cholesky::solve(vnl_vector<double> const& b, vnl_vector<double>* x) const
00057 {
00058   assert(b.size() == A_.columns());
00059 
00060   *x = b;
00061   long n = A_.columns();
00062   v3p_netlib_dposl_(A_.data_block(), &n, &n, x->data_block());
00063 }
00064 
00065 //: Solve least squares problem M x = b.
00066 vnl_vector<double> vnl_cholesky::solve(vnl_vector<double> const& b) const
00067 {
00068   assert(b.size() == A_.columns());
00069 
00070   long n = A_.columns();
00071   vnl_vector<double> ret = b;
00072   v3p_netlib_dposl_(A_.data_block(), &n, &n, ret.data_block());
00073   return ret;
00074 }
00075 
00076 //: Compute determinant.
00077 double vnl_cholesky::determinant() const
00078 {
00079   long n = A_.columns();
00080   vnl_matrix<double> I = A_;
00081   double det[2];
00082   long job = 10;
00083   v3p_netlib_dpodi_(I.data_block(), &n, &n, det, &job);
00084   return det[0] * vcl_pow(10.0, det[1]);
00085 }
00086 
00087 // : Compute inverse.  Not efficient.
00088 vnl_matrix<double> vnl_cholesky::inverse() const
00089 {
00090   if (num_dims_rank_def_) {
00091     vcl_cerr << "vnl_cholesky: Calling inverse() on rank-deficient matrix\n";
00092     return vnl_matrix<double>();
00093   }
00094 
00095   long n = A_.columns();
00096   vnl_matrix<double> I = A_;
00097   long job = 01;
00098   v3p_netlib_dpodi_(I.data_block(), &n, &n, 0, &job);
00099 
00100   // Copy lower triangle into upper
00101   for (int i = 0; i < n; ++i)
00102     for (int j = i+1; j < n; ++j)
00103       I(i,j) = I(j,i);
00104 
00105   return I;
00106 }
00107 
00108 //: Return lower-triangular factor.
00109 vnl_matrix<double> vnl_cholesky::lower_triangle() const
00110 {
00111   unsigned n = A_.columns();
00112   vnl_matrix<double> L(n,n);
00113   // Zap upper triangle and transpose
00114   for (unsigned i = 0; i < n; ++i) {
00115     L(i,i) = A_(i,i);
00116     for (unsigned j = i+1; j < n; ++j) {
00117       L(j,i) = A_(j,i);
00118       L(i,j) = 0;
00119     }
00120   }
00121   return L;
00122 }
00123 
00124 
00125 //: Return upper-triangular factor.
00126 vnl_matrix<double> vnl_cholesky::upper_triangle() const
00127 {
00128   unsigned n = A_.columns();
00129   vnl_matrix<double> U(n,n);
00130   // Zap lower triangle and transpose
00131   for (unsigned i = 0; i < n; ++i) {
00132     U(i,i) = A_(i,i);
00133     for (unsigned j = i+1; j < n; ++j) {
00134       U(i,j) = A_(j,i);
00135       U(j,i) = 0;
00136     }
00137   }
00138   return U;
00139 }
00140