ViennaCL - The Vienna Computing Library  1.6.0
Free open-source GPU-accelerated linear algebra and solver library.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
svd.cpp
Go to the documentation of this file.
1 /* =========================================================================
2  Copyright (c) 2010-2014, Institute for Microelectronics,
3  Institute for Analysis and Scientific Computing,
4  TU Wien.
5  Portions of this software are copyright by UChicago Argonne, LLC.
6 
7  -----------------
8  ViennaCL - The Vienna Computing Library
9  -----------------
10 
11  Project Head: Karl Rupp rupp@iue.tuwien.ac.at
12 
13  (A list of authors and contributors can be found in the PDF manual)
14 
15  License: MIT (X11), see file LICENSE in the base directory
16 ============================================================================= */
17 
18 
19 
24 #include <stdexcept>
25 #include <iostream>
26 #include <string>
27 #include <vector>
28 #include <cmath>
29 
30 #include "viennacl/matrix.hpp"
31 #include "viennacl/linalg/prod.hpp"
32 
33 #include "viennacl/linalg/svd.hpp"
34 
36 
37 
38 inline void read_matrix_size(std::fstream& f, std::size_t & sz1, std::size_t & sz2)
39 {
40  if (!f.is_open())
41  throw std::invalid_argument("File is not opened");
42 
43  f >> sz1 >> sz2;
44 }
45 
46 
47 template<typename ScalarType>
49 {
50  if (!f.is_open())
51  throw std::invalid_argument("File is not opened");
52 
53  boost::numeric::ublas::matrix<ScalarType> h_A(A.size1(), A.size2());
54 
55  for (std::size_t i = 0; i < h_A.size1(); i++)
56  {
57  for (std::size_t j = 0; j < h_A.size2(); j++)
58  {
59  ScalarType val = 0.0;
60  f >> val;
61  h_A(i, j) = val;
62  }
63  }
64 
65  viennacl::copy(h_A, A);
66 }
67 
68 
69 template<typename ScalarType>
70 void read_vector_body(std::fstream& f, std::vector<ScalarType>& v)
71 {
72  if (!f.is_open())
73  throw std::invalid_argument("File is not opened");
74 
75  for (std::size_t i = 0; i < v.size(); i++)
76  {
77  ScalarType val = 0.0;
78  f >> val;
79  v[i] = val;
80  }
81 }
82 
83 
84 template<typename ScalarType>
85 void random_fill(std::vector<ScalarType>& in)
86 {
87  for (std::size_t i = 0; i < in.size(); i++)
88  in[i] = static_cast<ScalarType>(rand()) / ScalarType(RAND_MAX);
89 }
90 
91 
92 template<typename ScalarType>
94 {
95  const ScalarType EPS = 0.0001f;
96 
97  std::vector<ScalarType> aA(A.size1() * A.size2());
98  viennacl::fast_copy(A, &aA[0]);
99 
100  for (std::size_t i = 0; i < A.size1(); i++)
101  {
102  for (std::size_t j = 0; j < A.size2(); j++)
103  {
104  ScalarType val = aA[i * A.size2() + j];
105  if ((fabs(val) > EPS) && (i != j) && ((i + 1) != j))
106  {
107  std::cout << "Failed at " << i << " " << j << " " << val << std::endl;
108  return false;
109  }
110  }
111  }
112 
113  return true;
114 }
115 
116 template<typename ScalarType>
119 {
120  std::vector<ScalarType> res_std(res.internal_size());
121  std::vector<ScalarType> ref_std(ref.internal_size());
122 
123  viennacl::fast_copy(res, &res_std[0]);
124  viennacl::fast_copy(ref, &ref_std[0]);
125 
126  ScalarType diff = 0.0;
127  ScalarType mx = 0.0;
128 
129  for (std::size_t i = 0; i < res_std.size(); i++)
130  {
131  diff = std::max(diff, std::abs(res_std[i] - ref_std[i]));
132  mx = std::max(mx, res_std[i]);
133  }
134 
135  return diff / mx;
136 }
137 
138 
139 template<typename ScalarType>
141  std::vector<ScalarType>& ref)
142 {
143  std::vector<ScalarType> res_std(ref.size());
144 
145  for (std::size_t i = 0; i < ref.size(); i++)
146  res_std[i] = res(i, i);
147 
148  std::sort(ref.begin(), ref.end());
149  std::sort(res_std.begin(), res_std.end());
150 
151  ScalarType diff = 0.0;
152  ScalarType mx = 0.0;
153  for (std::size_t i = 0; i < ref.size(); i++)
154  {
155  diff = std::max(diff, std::abs(res_std[i] - ref[i]));
156  mx = std::max(mx, res_std[i]);
157  }
158 
159  return diff / mx;
160 }
161 
162 
163 template<typename ScalarType>
164 void test_svd(const std::string & fn, ScalarType EPS)
165 {
166  std::size_t sz1, sz2;
167 
168  //read matrix
169 
170  // sz1 = 2048, sz2 = 2048;
171  // std::vector<ScalarType> in(sz1 * sz2);
172  // random_fill(in);
173 
174  // read file
175  std::fstream f(fn.c_str(), std::fstream::in);
176  //read size of input matrix
177  read_matrix_size(f, sz1, sz2);
178 
179  std::size_t to = std::min(sz1, sz2);
180 
181  viennacl::matrix<ScalarType> Ai(sz1, sz2), Aref(sz1, sz2), QL(sz1, sz1), QR(sz2, sz2);
182  read_matrix_body(f, Ai);
183 
184  std::vector<ScalarType> sigma_ref(to);
185  read_vector_body(f, sigma_ref);
186 
187  f.close();
188 
189  // viennacl::fast_copy(&in[0], &in[0] + in.size(), Ai);
190 
191  Aref = Ai;
192 
193  Timer timer;
194  timer.start();
195 
196  viennacl::linalg::svd(Ai, QL, QR);
197 
199 
200  double time_spend = timer.get();
201 
202  viennacl::matrix<ScalarType> result1(sz1, sz2), result2(sz1, sz2);
203  result1 = viennacl::linalg::prod(QL, Ai);
204  result2 = viennacl::linalg::prod(result1, trans(QR));
205 
206  ScalarType sigma_diff = sigmas_compare(Ai, sigma_ref);
207  ScalarType prods_diff = matrix_compare(result2, Aref);
208 
209  bool sigma_ok = (fabs(sigma_diff) < EPS)
210  && (fabs(prods_diff) < std::sqrt(EPS)); //note: computing the product is not accurate down to 10^{-16}, so we allow for a higher tolerance here
211 
212  printf("%6s [%dx%d] %40s sigma_diff = %.6f; prod_diff = %.6f; time = %.6f\n", sigma_ok?"[[OK]]":"[FAIL]", (int)Aref.size1(), (int)Aref.size2(), fn.c_str(), sigma_diff, prods_diff, time_spend);
213 }
214 
215 
216 template<typename ScalarType>
217 void time_svd(std::size_t sz1, std::size_t sz2)
218 {
219  viennacl::matrix<ScalarType> Ai(sz1, sz2), QL(sz1, sz1), QR(sz2, sz2);
220 
221  std::vector<ScalarType> in(Ai.internal_size1() * Ai.internal_size2());
222  random_fill(in);
223 
224  viennacl::fast_copy(&in[0], &in[0] + in.size(), Ai);
225 
226 
227  Timer timer;
228  timer.start();
229 
230  viennacl::linalg::svd(Ai, QL, QR);
232  double time_spend = timer.get();
233 
234  printf("[%dx%d] time = %.6f\n", static_cast<int>(sz1), static_cast<int>(sz2), time_spend);
235 }
236 
237 
238 template<typename ScalarType>
239 int test(ScalarType epsilon)
240 {
241 
242  test_svd<ScalarType>(std::string("../examples/testdata/svd/qr.example"), epsilon);
243  test_svd<ScalarType>(std::string("../examples/testdata/svd/wiki.example"), epsilon);
244  test_svd<ScalarType>(std::string("../examples/testdata/svd/wiki.qr.example"), epsilon);
245  test_svd<ScalarType>(std::string("../examples/testdata/svd/pysvd.example"), epsilon);
246  test_svd<ScalarType>(std::string("../examples/testdata/svd/random.example"), epsilon);
247 
248  time_svd<ScalarType>(500, 500);
249  time_svd<ScalarType>(1000, 1000);
250  time_svd<ScalarType>(4096, 512);
251  time_svd<ScalarType>(2048, 2048);
252  //time_svd(4096, 4096); //takes too long for a standard sanity test. Feel free to uncomment
253 
254  return EXIT_SUCCESS;
255 }
256 
257 //
258 // -------------------------------------------------------------
259 //
260 int main()
261 {
262  std::cout << std::endl;
263  std::cout << "----------------------------------------------" << std::endl;
264  std::cout << "----------------------------------------------" << std::endl;
265  std::cout << "## Test :: BLAS 3 routines" << std::endl;
266  std::cout << "----------------------------------------------" << std::endl;
267  std::cout << "----------------------------------------------" << std::endl;
268  std::cout << std::endl;
269 
270  int retval = EXIT_SUCCESS;
271 
272  std::cout << std::endl;
273  std::cout << "----------------------------------------------" << std::endl;
274  std::cout << std::endl;
275  {
276  typedef float NumericT;
277  NumericT epsilon = NumericT(1.0E-4);
278  std::cout << "# Testing setup:" << std::endl;
279  std::cout << " eps: " << epsilon << std::endl;
280  std::cout << " numeric: float" << std::endl;
281  retval = test<NumericT>(epsilon);
282  if ( retval == EXIT_SUCCESS )
283  std::cout << "# Test passed" << std::endl;
284  else
285  return retval;
286  }
287  std::cout << std::endl;
288  std::cout << "----------------------------------------------" << std::endl;
289  std::cout << std::endl;
291  {
292  {
293  typedef double NumericT;
294  NumericT epsilon = 1.0E-6; //Note: higher accuracy not possible, because data only available with floating point precision
295  std::cout << "# Testing setup:" << std::endl;
296  std::cout << " eps: " << epsilon << std::endl;
297  std::cout << " numeric: double" << std::endl;
298  retval = test<NumericT>(epsilon);
299  if ( retval == EXIT_SUCCESS )
300  std::cout << "# Test passed" << std::endl;
301  else
302  return retval;
303  }
304  std::cout << std::endl;
305  std::cout << "----------------------------------------------" << std::endl;
306  std::cout << std::endl;
307  }
308 
309  std::cout << std::endl;
310  std::cout << "------- Test completed --------" << std::endl;
311  std::cout << std::endl;
312 
313 
314  return retval;
315 }
316 
317 
#define EPS
Definition: bisect.cpp:41
void read_vector_body(std::fstream &f, std::vector< ScalarType > &v)
Definition: svd.cpp:70
void time_svd(std::size_t sz1, std::size_t sz2)
Definition: svd.cpp:217
size_type internal_size() const
Returns the total amount of allocated memory in multiples of sizeof(NumericT)
Definition: matrix_def.hpp:233
void trans(matrix_expression< const matrix_base< NumericT, SizeT, DistanceT >, const matrix_base< NumericT, SizeT, DistanceT >, op_trans > const &proxy, matrix_base< NumericT > &temp_trans)
void read_matrix_body(std::fstream &f, viennacl::matrix< ScalarType > &A)
Definition: svd.cpp:48
Generic interface for matrix-vector and matrix-matrix products. See viennacl/linalg/vector_operations...
Implementation of the dense matrix class.
void random_fill(std::vector< ScalarType > &in)
Definition: svd.cpp:85
void finish()
Synchronizes the execution. finish() will only return after all compute kernels (CUDA, OpenCL) have completed.
Definition: memory.hpp:54
void start()
A dense matrix class.
Definition: forwards.h:374
double get() const
T max(const T &lhs, const T &rhs)
Maximum.
Definition: util.hpp:59
viennacl::ocl::device const & current_device()
Convenience function for returning the active device in the current context.
Definition: backend.hpp:351
void svd(viennacl::matrix< SCALARTYPE, row_major, ALIGNMENT > &A, viennacl::matrix< SCALARTYPE, row_major, ALIGNMENT > &QL, viennacl::matrix< SCALARTYPE, row_major, ALIGNMENT > &QR)
Computes the singular value decomposition of a matrix A. Experimental in 1.3.x.
Definition: svd.hpp:492
int main()
Definition: svd.cpp:260
VectorT prod(std::vector< std::vector< T, A1 >, A2 > const &matrix, VectorT const &vector)
Definition: prod.hpp:91
ScalarType sigmas_compare(viennacl::matrix< ScalarType > &res, std::vector< ScalarType > &ref)
Definition: svd.cpp:140
bool double_support() const
ViennaCL convenience function: Returns true if the device supports double precision.
Definition: device.hpp:956
size_type size2() const
Returns the number of columns.
Definition: matrix_def.hpp:217
size_type size1() const
Returns the number of rows.
Definition: matrix_def.hpp:215
Provides singular value decomposition using a block-based approach. Experimental. ...
void test_svd(const std::string &fn, ScalarType EPS)
Definition: svd.cpp:164
void copy(std::vector< NumericT > &cpu_vec, circulant_matrix< NumericT, AlignmentV > &gpu_mat)
Copies a circulant matrix from the std::vector to the OpenCL device (either GPU or multi-core CPU) ...
float ScalarType
Definition: fft_1d.cpp:42
T min(const T &lhs, const T &rhs)
Minimum.
Definition: util.hpp:45
int test(ScalarType epsilon)
Definition: svd.cpp:239
ScalarType diff(ScalarType &s1, viennacl::scalar< ScalarType > &s2)
Definition: blas3_solve.cpp:69
void read_matrix_size(std::fstream &f, std::size_t &sz1, std::size_t &sz2)
Definition: svd.cpp:38
bool check_bidiag(viennacl::matrix< ScalarType > &A)
Definition: svd.cpp:93
ScalarType matrix_compare(viennacl::matrix< ScalarType > &res, viennacl::matrix< ScalarType > &ref)
Definition: svd.cpp:117
void fast_copy(const const_vector_iterator< SCALARTYPE, ALIGNMENT > &gpu_begin, const const_vector_iterator< SCALARTYPE, ALIGNMENT > &gpu_end, CPU_ITERATOR cpu_begin)