ViennaCL - The Vienna Computing Library
1.5.1
|
00001 #ifndef VIENNACL_LINALG_QR_METHOD_COMMON_HPP 00002 #define VIENNACL_LINALG_QR_METHOD_COMMON_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 00021 #include <cmath> 00022 00023 #include "viennacl/ocl/device.hpp" 00024 #include "viennacl/ocl/handle.hpp" 00025 #include "viennacl/ocl/kernel.hpp" 00026 #include "viennacl/linalg/opencl/kernels/svd.hpp" 00027 #include "viennacl/meta/result_of.hpp" 00028 #include "viennacl/vector.hpp" 00029 #include "viennacl/matrix.hpp" 00030 00031 #include <boost/numeric/ublas/vector.hpp> 00032 #include <boost/numeric/ublas/io.hpp> 00033 00038 namespace viennacl 00039 { 00040 namespace linalg 00041 { 00042 const std::string SVD_BIDIAG_PACK_KERNEL = "bidiag_pack"; 00043 const std::string SVD_HOUSEHOLDER_UPDATE_A_LEFT_KERNEL = "house_update_A_left"; 00044 const std::string SVD_HOUSEHOLDER_UPDATE_A_RIGHT_KERNEL = "house_update_A_right"; 00045 const std::string SVD_HOUSEHOLDER_UPDATE_QL_KERNEL = "house_update_QL"; 00046 const std::string SVD_HOUSEHOLDER_UPDATE_QR_KERNEL = "house_update_QR"; 00047 const std::string SVD_COPY_COL_KERNEL = "copy_col"; 00048 const std::string SVD_COPY_ROW_KERNEL = "copy_row"; 00049 const std::string SVD_MATRIX_TRANSPOSE_KERNEL = "transpose_inplace"; 00050 const std::string SVD_INVERSE_SIGNS_KERNEL = "inverse_signs"; 00051 const std::string SVD_GIVENS_PREV_KERNEL = "givens_prev"; 00052 const std::string SVD_GIVENS_NEXT_KERNEL = "givens_next"; 00053 const std::string SVD_FINAL_ITER_UPDATE_KERNEL = "final_iter_update"; 00054 const std::string SVD_UPDATE_QR_COLUMN_KERNEL = "update_qr_column"; 00055 00056 namespace detail 00057 { 00058 //static const float EPS = 0.00001f; 00059 //static const vcl_size_t ITER_MAX = 50; 00060 00061 static const double EPS = 1e-10; 00062 static const vcl_size_t ITER_MAX = 50; 00063 00064 template <typename SCALARTYPE> 00065 SCALARTYPE pythag(SCALARTYPE a, SCALARTYPE b) 00066 { 00067 return std::sqrt(a*a + b*b); 00068 } 00069 00070 template <typename SCALARTYPE> 00071 SCALARTYPE sign(SCALARTYPE val) 00072 { 00073 return (val >= 0) ? SCALARTYPE(1) : SCALARTYPE(-1); 00074 } 00075 00076 // DEPRECATED: Replace with viennacl::linalg::norm_2 00077 template <typename VectorType> 00078 typename VectorType::value_type norm_lcl(VectorType const & x, vcl_size_t size) 00079 { 00080 typename VectorType::value_type x_norm = 0.0; 00081 for(vcl_size_t i = 0; i < size; i++) 00082 x_norm += std::pow(x[i], 2); 00083 return std::sqrt(x_norm); 00084 } 00085 00086 template <typename VectorType> 00087 void normalize(VectorType & x, vcl_size_t size) 00088 { 00089 typename VectorType::value_type x_norm = norm_lcl(x, size); 00090 for(vcl_size_t i = 0; i < size; i++) 00091 x[i] /= x_norm; 00092 } 00093 00094 00095 00096 template <typename VectorType> 00097 void householder_vector(VectorType & v, vcl_size_t start) 00098 { 00099 typedef typename VectorType::value_type ScalarType; 00100 ScalarType x_norm = norm_lcl(v, v.size()); 00101 ScalarType alpha = -sign(v[start]) * x_norm; 00102 v[start] += alpha; 00103 normalize(v, v.size()); 00104 } 00105 00106 template <typename MatrixType> 00107 void transpose(MatrixType & A) 00108 { 00109 typedef typename MatrixType::value_type ScalarType; 00110 typedef typename viennacl::result_of::cpu_value_type<ScalarType>::type CPU_ScalarType; 00111 00112 viennacl::ocl::kernel & kernel = viennacl::ocl::get_kernel(viennacl::linalg::opencl::kernels::svd<CPU_ScalarType>::program_name(), SVD_MATRIX_TRANSPOSE_KERNEL); 00113 00114 viennacl::ocl::enqueue(kernel(A, 00115 static_cast<cl_uint>(A.internal_size1()), 00116 static_cast<cl_uint>(A.internal_size2()) 00117 ) 00118 ); 00119 } 00120 00121 00122 00123 template <typename T> 00124 void cdiv(T xr, T xi, T yr, T yi, T& cdivr, T& cdivi) 00125 { 00126 // Complex scalar division. 00127 T r; 00128 T d; 00129 if (std::fabs(yr) > std::fabs(yi)) 00130 { 00131 r = yi / yr; 00132 d = yr + r * yi; 00133 cdivr = (xr + r * xi) / d; 00134 cdivi = (xi - r * xr) / d; 00135 } 00136 else 00137 { 00138 r = yr / yi; 00139 d = yi + r * yr; 00140 cdivr = (r * xr + xi) / d; 00141 cdivi = (r * xi - xr) / d; 00142 } 00143 } 00144 00145 00146 template <typename SCALARTYPE, unsigned int ALIGNMENT> 00147 void copy_vec(viennacl::matrix<SCALARTYPE, row_major, ALIGNMENT>& A, 00148 viennacl::vector<SCALARTYPE, ALIGNMENT>& V, 00149 vcl_size_t row_start, 00150 vcl_size_t col_start, 00151 bool copy_col 00152 ) 00153 { 00154 00155 std::string kernel_name = copy_col ? SVD_COPY_COL_KERNEL : SVD_COPY_ROW_KERNEL; 00156 viennacl::ocl::context & ctx = const_cast<viennacl::ocl::context &>(viennacl::traits::opencl_handle(A).context()); 00157 viennacl::ocl::kernel& kernel = ctx.get_kernel(viennacl::linalg::opencl::kernels::svd<SCALARTYPE>::program_name(), kernel_name); 00158 00159 viennacl::ocl::enqueue(kernel( 00160 A, 00161 V, 00162 static_cast<cl_uint>(row_start), 00163 static_cast<cl_uint>(col_start), 00164 copy_col ? static_cast<cl_uint>(A.size1()) 00165 : static_cast<cl_uint>(A.size2()), 00166 static_cast<cl_uint>(A.internal_size2()) 00167 )); 00168 00169 } 00170 00171 00172 template<typename SCALARTYPE, unsigned int ALIGNMENT> 00173 void prepare_householder_vector( 00174 viennacl::matrix<SCALARTYPE, row_major, ALIGNMENT>& A, 00175 viennacl::vector<SCALARTYPE, ALIGNMENT>& D, 00176 vcl_size_t size, 00177 vcl_size_t row_start, 00178 vcl_size_t col_start, 00179 vcl_size_t start, 00180 bool is_column 00181 ) 00182 { 00183 boost::numeric::ublas::vector<SCALARTYPE> tmp = boost::numeric::ublas::scalar_vector<SCALARTYPE>(size, 0); 00184 00185 copy_vec(A, D, row_start, col_start, is_column); 00186 fast_copy(D.begin(), D.begin() + vcl_ptrdiff_t(size - start), tmp.begin() + start); 00187 00188 //std::cout << "1: " << tmp << "\n"; 00189 00190 detail::householder_vector(tmp, start); 00191 fast_copy(tmp, D); 00192 00193 //std::cout << "2: " << D << "\n"; 00194 } 00195 00196 template <typename SCALARTYPE, unsigned int ALIGNMENT, typename VectorType> 00197 void bidiag_pack(viennacl::matrix<SCALARTYPE, row_major, ALIGNMENT>& A, 00198 VectorType & dh, 00199 VectorType & sh 00200 ) 00201 { 00202 viennacl::vector<SCALARTYPE, ALIGNMENT> D(dh.size()); 00203 viennacl::vector<SCALARTYPE, ALIGNMENT> S(sh.size()); 00204 00205 viennacl::ocl::context & ctx = const_cast<viennacl::ocl::context &>(viennacl::traits::opencl_handle(A).context()); 00206 viennacl::ocl::kernel& kernel = ctx.get_kernel(viennacl::linalg::opencl::kernels::svd<SCALARTYPE>::program_name(), SVD_BIDIAG_PACK_KERNEL); 00207 00208 viennacl::ocl::enqueue(kernel( 00209 A, 00210 D, 00211 S, 00212 static_cast<cl_uint>(A.size1()), 00213 static_cast<cl_uint>(A.size2()), 00214 static_cast<cl_uint>(A.internal_size2()) 00215 )); 00216 00217 fast_copy(D, dh); 00218 fast_copy(S, sh); 00219 } 00220 00221 } 00222 } 00223 } 00224 00225 #endif