ViennaCL - The Vienna Computing Library  1.5.0
viennacl/linalg/lanczos.hpp
Go to the documentation of this file.
00001 #ifndef VIENNACL_LINALG_LANCZOS_HPP_
00002 #define VIENNACL_LINALG_LANCZOS_HPP_
00003 
00004 /* =========================================================================
00005    Copyright (c) 2010-2013, Institute for Microelectronics,
00006                             Institute for Analysis and Scientific Computing,
00007                             TU Wien.
00008    Portions of this software are copyright by UChicago Argonne, LLC.
00009 
00010                             -----------------
00011                   ViennaCL - The Vienna Computing Library
00012                             -----------------
00013 
00014    Project Head:    Karl Rupp                   rupp@iue.tuwien.ac.at
00015 
00016    (A list of authors and contributors can be found in the PDF manual)
00017 
00018    License:         MIT (X11), see file LICENSE in the base directory
00019 ============================================================================= */
00020 
00027 #include <cmath>
00028 #include <vector>
00029 #include "viennacl/vector.hpp"
00030 #include "viennacl/compressed_matrix.hpp"
00031 #include "viennacl/linalg/prod.hpp"
00032 #include "viennacl/linalg/inner_prod.hpp"
00033 #include "viennacl/linalg/norm_2.hpp"
00034 #include "viennacl/io/matrix_market.hpp"
00035 #include "viennacl/linalg/bisect.hpp"
00036 #include <boost/random.hpp>
00037 #include <boost/random/mersenne_twister.hpp>
00038 #include <boost/numeric/ublas/matrix.hpp>
00039 #include <boost/numeric/ublas/matrix_proxy.hpp>
00040 #include <boost/numeric/ublas/matrix_expression.hpp>
00041 #include <boost/numeric/ublas/matrix_sparse.hpp>
00042 #include <boost/numeric/ublas/vector.hpp>
00043 #include <boost/numeric/ublas/operation.hpp>
00044 #include <boost/numeric/ublas/vector_expression.hpp>
00045 #include <boost/numeric/ublas/io.hpp>
00046 
00047 namespace viennacl
00048 {
00049   namespace linalg
00050   {
00051 
00054     class lanczos_tag
00055     {
00056       public:
00057 
00058         enum
00059         {
00060           partial_reorthogonalization = 0,
00061           full_reorthogonalization,
00062           no_reorthogonalization
00063         };
00064 
00073         lanczos_tag(double factor = 0.75,
00074                     vcl_size_t numeig = 10,
00075                     int met = 0,
00076                     vcl_size_t krylov = 100) : factor_(factor), num_eigenvalues_(numeig), method_(met), krylov_size_(krylov) {}
00077 
00079         void num_eigenvalues(int numeig){ num_eigenvalues_ = numeig; }
00080 
00082         vcl_size_t num_eigenvalues() const { return num_eigenvalues_; }
00083 
00085         void factor(double fct) { factor_ = fct; }
00086 
00088         double factor() const { return factor_; }
00089 
00091         void krylov_size(int max) { krylov_size_ = max; }
00092 
00094         vcl_size_t  krylov_size() const { return krylov_size_; }
00095 
00097         void method(int met){ method_ = met; }
00098 
00100         int method() const { return method_; }
00101 
00102 
00103       private:
00104         double factor_;
00105         vcl_size_t num_eigenvalues_;
00106         int method_; // see enum defined above for possible values
00107         vcl_size_t krylov_size_;
00108 
00109     };
00110 
00111 
00112     namespace detail
00113     {
00124       template< typename MatrixT, typename VectorT >
00125       std::vector<
00126               typename viennacl::result_of::cpu_value_type<typename MatrixT::value_type>::type
00127               >
00128       lanczosPRO (MatrixT const& A, VectorT & r, vcl_size_t size, lanczos_tag const & tag)
00129       {
00130 
00131         typedef typename viennacl::result_of::value_type<MatrixT>::type        ScalarType;
00132         typedef typename viennacl::result_of::cpu_value_type<ScalarType>::type    CPU_ScalarType;
00133 
00134 
00135         // generation of some random numbers, used for lanczos PRO algorithm
00136         boost::mt11213b mt;
00137         boost::normal_distribution<CPU_ScalarType> N(0, 1);
00138         boost::bernoulli_distribution<CPU_ScalarType> B(0.5);
00139         boost::triangle_distribution<CPU_ScalarType> T(-1, 0, 1);
00140 
00141         boost::variate_generator<boost::mt11213b&, boost::normal_distribution<CPU_ScalarType> >     get_N(mt, N);
00142         boost::variate_generator<boost::mt11213b&, boost::bernoulli_distribution<CPU_ScalarType> >  get_B(mt, B);
00143         boost::variate_generator<boost::mt11213b&, boost::triangle_distribution<CPU_ScalarType> >   get_T(mt, T);
00144 
00145 
00146         long i, j, k, index, retry, reorths;
00147         std::vector<long> l_bound(size/2), u_bound(size/2);
00148         bool second_step;
00149         CPU_ScalarType squ_eps, eta, temp, eps, retry_th;
00150         vcl_size_t n = r.size();
00151         std::vector< std::vector<CPU_ScalarType> > w(2, std::vector<CPU_ScalarType>(size));
00152         CPU_ScalarType cpu_beta;
00153 
00154         boost::numeric::ublas::vector<CPU_ScalarType> s(n);
00155 
00156         VectorT t(n);
00157         CPU_ScalarType inner_rt;
00158         ScalarType vcl_beta;
00159         ScalarType vcl_alpha;
00160         std::vector<CPU_ScalarType> alphas, betas;
00161         boost::numeric::ublas::matrix<CPU_ScalarType> Q(n, size);
00162 
00163         second_step = false;
00164         eps = std::numeric_limits<CPU_ScalarType>::epsilon();
00165         squ_eps = std::sqrt(eps);
00166         retry_th = 1e-2;
00167         eta = std::exp(std::log(eps) * tag.factor());
00168         reorths = 0;
00169         retry = 0;
00170 
00171         vcl_beta = viennacl::linalg::norm_2(r);
00172 
00173         r /= vcl_beta;
00174 
00175         detail::copy_vec_to_vec(r,s);
00176         boost::numeric::ublas::column(Q, 0) = s;
00177 
00178         VectorT u = viennacl::linalg::prod(A, r);
00179         vcl_alpha = viennacl::linalg::inner_prod(u, r);
00180         alphas.push_back(vcl_alpha);
00181         w[0][0] = 1;
00182         betas.push_back(vcl_beta);
00183 
00184         long batches = 0;
00185         for(i = 1;i < static_cast<long>(size); i++)
00186         {
00187           r = u - vcl_alpha * r;
00188           vcl_beta = viennacl::linalg::norm_2(r);
00189 
00190           betas.push_back(vcl_beta);
00191           r = r / vcl_beta;
00192 
00193           index = i % 2;
00194           w[index][i] = 1;
00195           k = (i + 1) % 2;
00196           w[index][0] = (betas[1] * w[k][1] + (alphas[0] - vcl_alpha) * w[k][0] - betas[i - 1] * w[index][0]) / vcl_beta + eps * 0.3 * get_N() * (betas[1] + vcl_beta);
00197 
00198           for(j = 1;j < i - 1;j++)
00199           {
00200                   w[index][j] = (betas[j + 1] * w[k][j + 1] + (alphas[j] - vcl_alpha) * w[k][j] + betas[j] * w[k][j - 1] - betas[i - 1] * w[index][j]) / vcl_beta + eps * 0.3 * get_N() * (betas[j + 1] + vcl_beta);
00201           }
00202           w[index][i - 1] = 0.6 * eps * n * get_N() * betas[1] / vcl_beta;
00203 
00204           if(second_step)
00205           {
00206             for(j = 0;j < batches;j++)
00207             {
00208               l_bound[j]++;
00209               u_bound[j]--;
00210 
00211               for(k = l_bound[j];k < u_bound[j];k++)
00212               {
00213                 detail::copy_vec_to_vec(boost::numeric::ublas::column(Q, k), t);
00214                 inner_rt = viennacl::linalg::inner_prod(r,t);
00215                 r = r - inner_rt * t;
00216                 w[index][k] = 1.5 * eps * get_N();
00217                 reorths++;
00218               }
00219             }
00220             temp = viennacl::linalg::norm_2(r);
00221             r = r / temp;
00222             vcl_beta = vcl_beta * temp;
00223             second_step = false;
00224           }
00225           batches = 0;
00226 
00227           for(j = 0;j < i;j++)
00228           {
00229             if(std::fabs(w[index][j]) >= squ_eps)
00230             {
00231               detail::copy_vec_to_vec(boost::numeric::ublas::column(Q, j), t);
00232               inner_rt = viennacl::linalg::inner_prod(r,t);
00233               r = r - inner_rt * t;
00234               w[index][j] = 1.5 * eps * get_N();
00235               k = j - 1;
00236               reorths++;
00237               while(k >= 0 && std::fabs(w[index][k]) > eta)
00238               {
00239                 detail::copy_vec_to_vec(boost::numeric::ublas::column(Q, k), t);
00240                 inner_rt = viennacl::linalg::inner_prod(r,t);
00241                 r = r - inner_rt * t;
00242                 w[index][k] = 1.5 * eps * get_N();
00243                 k--;
00244                 reorths++;
00245               }
00246               l_bound[batches] = k + 1;
00247               k = j + 1;
00248 
00249               while(k < i && std::fabs(w[index][k]) > eta)
00250               {
00251                 detail::copy_vec_to_vec(boost::numeric::ublas::column(Q, k), t);
00252                 inner_rt = viennacl::linalg::inner_prod(r,t);
00253                 r = r - inner_rt * t;
00254                 w[index][k] = 1.5 * eps * get_N();
00255                 k++;
00256                 reorths++;
00257               }
00258               u_bound[batches] = k - 1;
00259               batches++;
00260               j = k;
00261             }
00262           }
00263 
00264           if(batches > 0)
00265           {
00266             temp = viennacl::linalg::norm_2(r);
00267             r = r / temp;
00268             vcl_beta = vcl_beta * temp;
00269             second_step = true;
00270 
00271             while(temp < retry_th)
00272             {
00273               for(j = 0;j < i;j++)
00274               {
00275                 detail::copy_vec_to_vec(boost::numeric::ublas::column(Q, k), t);
00276                 inner_rt = viennacl::linalg::inner_prod(r,t);
00277                 r = r - inner_rt * t;
00278                 reorths++;
00279               }
00280               retry++;
00281               temp = viennacl::linalg::norm_2(r);
00282               r = r / temp;
00283               vcl_beta = vcl_beta * temp;
00284             }
00285           }
00286 
00287           detail::copy_vec_to_vec(r,s);
00288           boost::numeric::ublas::column(Q, i) = s;
00289 
00290           cpu_beta = vcl_beta;
00291           s = - cpu_beta * boost::numeric::ublas::column(Q, i - 1);
00292           detail::copy_vec_to_vec(s, u);
00293           u += viennacl::linalg::prod(A, r);
00294           vcl_alpha = viennacl::linalg::inner_prod(u, r);
00295           alphas.push_back(vcl_alpha);
00296         }
00297 
00298         return bisect(alphas, betas);
00299 
00300       }
00301 
00302 
00311       template< typename MatrixT, typename VectorT >
00312       std::vector<
00313               typename viennacl::result_of::cpu_value_type<typename MatrixT::value_type>::type
00314               >
00315       lanczos (MatrixT const& A, VectorT & r, vcl_size_t size, lanczos_tag)
00316       {
00317 
00318         typedef typename viennacl::result_of::value_type<MatrixT>::type        ScalarType;
00319         typedef typename viennacl::result_of::cpu_value_type<ScalarType>::type    CPU_ScalarType;
00320 
00321         ScalarType vcl_beta;
00322         ScalarType vcl_alpha;
00323         std::vector<CPU_ScalarType> alphas, betas;
00324         CPU_ScalarType norm;
00325         vcl_size_t n = r.size();
00326         VectorT u(n), t(n);
00327         boost::numeric::ublas::vector<CPU_ScalarType> s(r.size()), u_zero(n), q(n);
00328         boost::numeric::ublas::matrix<CPU_ScalarType> Q(n, size);
00329 
00330         u_zero = boost::numeric::ublas::zero_vector<CPU_ScalarType>(n);
00331         detail::copy_vec_to_vec(u_zero, u);
00332         norm = norm_2(r);
00333 
00334         for(vcl_size_t i = 0;i < size; i++)
00335         {
00336           r /= norm;
00337           vcl_beta = norm;
00338 
00339           detail::copy_vec_to_vec(r,s);
00340           boost::numeric::ublas::column(Q, i) = s;
00341 
00342           u += prod(A, r);
00343           vcl_alpha = inner_prod(u, r);
00344           r = u - vcl_alpha * r;
00345           norm = norm_2(r);
00346 
00347           q = boost::numeric::ublas::column(Q, i);
00348           detail::copy_vec_to_vec(q, t);
00349 
00350           u = - norm * t;
00351           alphas.push_back(vcl_alpha);
00352           betas.push_back(vcl_beta);
00353           s.clear();
00354         }
00355 
00356         return bisect(alphas, betas);
00357       }
00358 
00367       template< typename MatrixT, typename VectorT >
00368       std::vector<
00369               typename viennacl::result_of::cpu_value_type<typename MatrixT::value_type>::type
00370               >
00371       lanczosFRO (MatrixT const& A, VectorT & r, vcl_size_t size, lanczos_tag)
00372       {
00373 
00374         typedef typename viennacl::result_of::value_type<MatrixT>::type        ScalarType;
00375         typedef typename viennacl::result_of::cpu_value_type<ScalarType>::type    CPU_ScalarType;
00376 
00377           CPU_ScalarType temp;
00378           CPU_ScalarType norm;
00379           ScalarType vcl_beta;
00380           ScalarType vcl_alpha;
00381           std::vector<CPU_ScalarType> alphas, betas;
00382           vcl_size_t n = r.size();
00383           VectorT u(n), t(n);
00384           ScalarType inner_rt;
00385           boost::numeric::ublas::vector<CPU_ScalarType> u_zero(n), s(r.size()), q(n);
00386           boost::numeric::ublas::matrix<CPU_ScalarType> Q(n, size);
00387 
00388           long reorths = 0;
00389           norm = norm_2(r);
00390 
00391 
00392           for(vcl_size_t i = 0; i < size; i++)
00393           {
00394             r /= norm;
00395 
00396             for(vcl_size_t j = 0; j < i; j++)
00397             {
00398               q = boost::numeric::ublas::column(Q, j);
00399               detail::copy_vec_to_vec(q, t);
00400               inner_rt = viennacl::linalg::inner_prod(r,t);
00401               r = r - inner_rt * t;
00402               reorths++;
00403             }
00404             temp = viennacl::linalg::norm_2(r);
00405             r = r / temp;
00406             vcl_beta = temp * norm;
00407             detail::copy_vec_to_vec(r,s);
00408             boost::numeric::ublas::column(Q, i) = s;
00409 
00410             u += viennacl::linalg::prod(A, r);
00411             vcl_alpha = viennacl::linalg::inner_prod(u, r);
00412             r = u - vcl_alpha * r;
00413             norm = viennacl::linalg::norm_2(r);
00414             q = boost::numeric::ublas::column(Q, i);
00415             detail::copy_vec_to_vec(q, t);
00416             u = - norm * t;
00417             alphas.push_back(vcl_alpha);
00418             betas.push_back(vcl_beta);
00419           }
00420 
00421           return bisect(alphas, betas);
00422       }
00423 
00424     } // end namespace detail
00425 
00433     template< typename MatrixT >
00434     std::vector< typename viennacl::result_of::cpu_value_type<typename MatrixT::value_type>::type >
00435     eig(MatrixT const & matrix, lanczos_tag const & tag)
00436     {
00437       typedef typename viennacl::result_of::value_type<MatrixT>::type           ScalarType;
00438       typedef typename viennacl::result_of::cpu_value_type<ScalarType>::type    CPU_ScalarType;
00439       typedef typename viennacl::result_of::vector_for_matrix<MatrixT>::type    VectorT;
00440 
00441       boost::mt11213b mt;
00442       boost::normal_distribution<CPU_ScalarType> N(0, 1);
00443       boost::bernoulli_distribution<CPU_ScalarType> B(0.5);
00444       boost::triangle_distribution<CPU_ScalarType> T(-1, 0, 1);
00445 
00446       boost::variate_generator<boost::mt11213b&, boost::normal_distribution<CPU_ScalarType> >     get_N(mt, N);
00447       boost::variate_generator<boost::mt11213b&, boost::bernoulli_distribution<CPU_ScalarType> >  get_B(mt, B);
00448       boost::variate_generator<boost::mt11213b&, boost::triangle_distribution<CPU_ScalarType> >   get_T(mt, T);
00449 
00450       std::vector<CPU_ScalarType> eigenvalues;
00451       vcl_size_t matrix_size = matrix.size1();
00452       VectorT r(matrix_size);
00453       std::vector<CPU_ScalarType> s(matrix_size);
00454 
00455       for(vcl_size_t i=0; i<s.size(); ++i)
00456         s[i] = 3.0 * get_B() + get_T() - 1.5;
00457 
00458       detail::copy_vec_to_vec(s,r);
00459 
00460       vcl_size_t size_krylov = (matrix_size < tag.krylov_size()) ? matrix_size
00461                                                                   : tag.krylov_size();
00462 
00463       switch(tag.method())
00464       {
00465         case lanczos_tag::partial_reorthogonalization:
00466           eigenvalues = detail::lanczosPRO(matrix, r, size_krylov, tag);
00467           break;
00468         case lanczos_tag::full_reorthogonalization:
00469           eigenvalues = detail::lanczosFRO(matrix, r, size_krylov, tag);
00470           break;
00471         case lanczos_tag::no_reorthogonalization:
00472           eigenvalues = detail::lanczos(matrix, r, size_krylov, tag);
00473           break;
00474       }
00475 
00476       std::vector<CPU_ScalarType> largest_eigenvalues;
00477 
00478       for(vcl_size_t i = 1; i<=tag.num_eigenvalues(); i++)
00479         largest_eigenvalues.push_back(eigenvalues[size_krylov-i]);
00480 
00481 
00482       return largest_eigenvalues;
00483     }
00484 
00485 
00486 
00487 
00488   } // end namespace linalg
00489 } // end namespace viennacl
00490 #endif