ViennaCL - The Vienna Computing Library
1.5.2
|
00001 #ifndef VIENNACL_LINALG_LANCZOS_HPP_ 00002 #define VIENNACL_LINALG_LANCZOS_HPP_ 00003 00004 /* ========================================================================= 00005 Copyright (c) 2010-2014, 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