vmmlib  1.7.0
 All Classes Namespaces Functions Pages
lapack_sym_eigs.hpp
1 /*
2  * Copyright (c) 2006-2014, Visualization and Multimedia Lab,
3  * University of Zurich <http://vmml.ifi.uzh.ch>,
4  * Eyescale Software GmbH,
5  * Blue Brain Project, EPFL
6  *
7  * This file is part of VMMLib <https://github.com/VMML/vmmlib/>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  *
12  * Redistributions of source code must retain the above copyright notice, this
13  * list of conditions and the following disclaimer. Redistributions in binary
14  * form must reproduce the above copyright notice, this list of conditions and
15  * the following disclaimer in the documentation and/or other materials provided
16  * with the distribution. Neither the name of the Visualization and Multimedia
17  * Lab, University of Zurich nor the names of its contributors may be used to
18  * endorse or promote products derived from this software without specific prior
19  * written permission.
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 #ifndef __VMML__VMMLIB_LAPACK_SYM_EIGS__HPP__
33 #define __VMML__VMMLIB_LAPACK_SYM_EIGS__HPP__
34 
35 #include <vmmlib/matrix.hpp>
36 #include <vmmlib/vector.hpp>
37 #include <vmmlib/exception.hpp>
38 
39 #include <vmmlib/lapack_types.hpp>
40 #include <vmmlib/lapack_includes.hpp>
41 
42 #include <string>
43 #include <vector>
44 
71 namespace vmml
72 {
73 
74 namespace lapack
75 {
76 
77  // XYYZZZ
78  // X = data type: S - float, D - double
79  // YY = matrix type, GE - general, TR - triangular
80  // ZZZ = function name
81 
82 
83  template< typename float_t >
84  struct eigs_params
85  {
86  char jobz;
87  char range;
88  char uplo;
89  lapack_int n;
90  float_t* a;
91  lapack_int lda; //leading dimension of input array
92  float_t* vl;
93  float_t* vu;
94  lapack_int il;
95  lapack_int iu;
96  float_t abstol;
97  lapack_int m; //number of found eigenvalues
98  float_t* w; //first m eigenvalues
99  float_t* z; //first m eigenvectors
100  lapack_int ldz; //leading dimension of z
101  float_t* work;
102  lapack_int lwork;
103  lapack_int* iwork;
104  lapack_int* ifail;
105  lapack_int info;
106 
107  friend std::ostream& operator << ( std::ostream& os,
108  const eigs_params< float_t >& p )
109  {
110  os
111  << " (1)\tjobz " << p.jobz << std::endl
112  << " (2)\trange " << p.range << std::endl
113  << " (3)\tuplo " << p.uplo << std::endl
114  << " (4)\tn " << p.n << std::endl
115  << " (5)\ta " << *p.a << std::endl
116  << " (6)\tlda " << p.lda << std::endl
117  << " (7)\tvl " << p.vl << std::endl
118  << " (8)\tvu " << p.vu << std::endl
119  << " (9)\til " << p.il << std::endl
120  << " (10)\tiu " << p.iu << std::endl
121  << " (11)\tabstol " << p.abstol << std::endl
122  << " (12)\tm " << p.m << std::endl
123  << " (13)\tw " << p.w << std::endl
124  << " (14)\tz " << p.z << std::endl
125  << " (15)\tldz " << p.ldz << std::endl
126  << " (16)\twork " << *p.work << std::endl
127  << " (17)\tlwork " << p.lwork << std::endl
128  << " (18)\tiwork " << *p.iwork << std::endl
129  << " (19)\tifail " << *p.ifail << std::endl
130  << " (20)\tinfo " << p.info
131  << std::endl;
132  return os;
133  }
134 
135  };
136 
137 
138 #if 0
139  /* Subroutine */
140 
141  int dsyevx_( char *jobz, char *range, char *uplo, integer *n, doublereal *a, integer *lda, doublereal *vl,
142  doublereal *vu, integer *il, integer *iu, doublereal *abstol, integer *m, doublereal *w, doublereal *z,
143  integer *ldz, doublereal *work, integer* lwork, integer* iwork, integer* ifail, integer* info );
144 
145 #endif
146 
147 
148  template< typename float_t >
149  inline void
150  sym_eigs_call( eigs_params< float_t >& )
151  {
152  VMMLIB_ERROR( "not implemented for this type.", VMMLIB_HERE );
153  }
154 
155 
156  template<>
157  inline void
158  sym_eigs_call( eigs_params< float >& p )
159  {
160  //std::cout << "calling lapack sym x eigs (single precision) " << std::endl;
161  ssyevx_(
162  &p.jobz,
163  &p.range,
164  &p.uplo,
165  &p.n,
166  p.a,
167  &p.lda,
168  p.vl,
169  p.vu,
170  &p.il,
171  &p.iu,
172  &p.abstol,
173  &p.m,
174  p.w,
175  p.z,
176  &p.ldz,
177  p.work,
178  &p.lwork,
179  p.iwork,
180  p.ifail,
181  &p.info
182  );
183 
184  }
185 
186 
187  template<>
188  inline void
189  sym_eigs_call( eigs_params< double >& p )
190  {
191  //std::cout << "calling lapack sym x eigs (double precision) " << std::endl;
192  dsyevx_(
193  &p.jobz,
194  &p.range,
195  &p.uplo,
196  &p.n,
197  p.a,
198  &p.lda,
199  p.vl,
200  p.vu,
201  &p.il,
202  &p.iu,
203  &p.abstol,
204  &p.m,
205  p.w,
206  p.z,
207  &p.ldz,
208  p.work,
209  &p.lwork,
210  p.iwork,
211  p.ifail,
212  &p.info
213  );
214  }
215 
216 } // namespace lapack
217 
218 
219 
220 template< size_t N, typename float_t >
222 {
223 
226 
229  typedef typename evalues_type::iterator evalue_iterator;
230  typedef typename evalues_type::const_iterator evalue_const_iterator;
231 
232  typedef std::pair< float_t, size_t > eigv_pair_type;
233 
234  lapack_sym_eigs();
235  ~lapack_sym_eigs();
236 
237  // version of reduced sym. eigenvalue decomposition,
238  // computes only the x largest magn. eigenvalues and their corresponding eigenvectors
239  template< size_t X>
240  bool compute_x(
241  const m_input_type& A,
242  matrix< N, X, float_t >& eigvectors_,
243  vector< X, float_t >& eigvalues_
244  );
245 
246  // partial sym. eigenvalue decomposition
247  // returns only the largest magn. eigenvalue and the corresponding eigenvector
248  bool compute_1st(
249  const m_input_type& A,
250  evector_type& eigvector_,
251  float_t& eigvalue_
252  );
253 
254 
255  //computes all eigenvalues and eigenvectors for matrix A
256  bool compute_all(
257  const m_input_type& A,
258  evectors_type& eigvectors_,
259  evalues_type& eigvalues_
260  );
261 
262  inline bool test_success( lapack::lapack_int info );
263 
265 
266  const lapack::eigs_params< float_t >& get_params(){ return p; };
267 
268  // comparison functor
270  {
271  inline bool operator()( const eigv_pair_type& a, const eigv_pair_type& b )
272  {
273  return fabs( a.first ) > fabs( b.first );
274  }
275  };
276 
277 }; // struct lapack_sym_eigs
278 
279 
280 template< size_t N, typename float_t >
282 {
283  p.jobz = 'V'; // Compute eigenvalues and eigenvectors.
284  p.range = 'A'; // all eigenvalues will be found.
285  p.uplo = 'U'; // Upper triangle of A is stored; or Lower triangle of A is stored.
286  p.n = N;
287  p.a = 0; //If UPLO = 'U', the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A.
288  p.lda = N;
289  p.vl = 0; //Not referenced if RANGE = 'A' or 'I'.
290  p.vu = 0; //Not referenced if RANGE = 'A' or 'I'.
291  p.il = 0; //Not referenced if RANGE = 'A' or 'V'.
292  p.iu = 0; //Not referenced if RANGE = 'A' or 'V'.
293  p.abstol = 0.0001; //lie in an interval [a,b] of width less than or equal to ABSTOL + EPS * max( |a|,|b| )
294  p.m = N; //The total number of eigenvalues found. 0 <= M <= N.
295  p.w = 0; //first m eigenvalues
296  p.z = 0; //first m eigenvectors
297  p.ldz = N; // The leading dimension of the array Z. LDZ >= 1, and if JOBZ = 'V', LDZ >= max(1,N).
298  p.work = new float_t;
299  //FIXME: check if correct datatype
300  p.iwork = new lapack::lapack_int[5*N]; //[5*N]; // INTEGER array, dimension (5*N)
301  p.ifail = new lapack::lapack_int[N]; //[N];
302  p.lwork = -1; //8N
303 
304  // workspace query
305  lapack::sym_eigs_call( p );
306 
307  p.lwork = static_cast< lapack::lapack_int >( p.work[0] );
308  delete p.work;
309 
310  p.work = new float_t[ p.lwork ];
311 
312 }
313 
314 
315 
316 template< size_t N, typename float_t >
317 lapack_sym_eigs< N, float_t >::~lapack_sym_eigs()
318 {
319  delete[] p.work;
320  delete[] p.iwork;
321  delete[] p.ifail;
322 }
323 
324 template< size_t N, typename float_t >
325 bool
326 lapack_sym_eigs< N, float_t >::compute_all(
327  const m_input_type& A,
328  evectors_type& eigvectors_,
329  evalues_type& eigvalues_
330  )
331 {
332  // lapack destroys the contents of the input matrix
333  m_input_type* AA = new m_input_type( A );
334 
335  p.range = 'A'; // all eigenvalues will be found.
336  p.a = AA->array;
337  p.ldz = N;
338  p.w = eigvalues_.array;
339  p.z = eigvectors_.array;
340 
341  //debug std::cout << p << std::endl;
342 
343  lapack::sym_eigs_call< float_t >( p );
344 
345  delete AA;
346 
347  return p.info == 0;
348 }
349 
350 
351 template< size_t N, typename float_t >
352 template< size_t X >
353 bool
354 lapack_sym_eigs< N, float_t >::compute_x(
355  const m_input_type& A,
356  matrix< N, X, float_t >& eigvectors_,
357  vector< X, float_t >& eigvalues_
358  )
359 {
360  //(1) get all eigenvalues and eigenvectors
361  evectors_type* all_eigvectors = new evectors_type;
362  evalues_type* all_eigvalues = new evalues_type;
363  compute_all( A, *all_eigvectors, *all_eigvalues );
364 
365  //(2) sort the eigenvalues
366  //std::pair< data, original_index >;
367  std::vector< eigv_pair_type >* eig_permutations = new std::vector< eigv_pair_type >;
368 
369  evalue_const_iterator it = all_eigvalues->begin(), it_end = all_eigvalues->end();
370  size_t counter = 0;
371  for( ; it != it_end; ++it, ++counter )
372  {
373  eig_permutations->push_back( eigv_pair_type( *it, counter ) );
374  }
375 
376  std::sort(
377  eig_permutations->begin(),
378  eig_permutations->end(),
379  eigenvalue_compare()
380  );
381 
382  delete all_eigvalues;
383 
384  //sort the eigenvectors according to eigenvalue permutations
385  evectors_type* sorted_eigvectors = new evectors_type;
386  evalues_type* sorted_eigvalues = new evalues_type;
387  typename std::vector< eigv_pair_type >::const_iterator it2 = eig_permutations->begin(), it2_end = eig_permutations->end();
388  evalue_iterator evalues_it = sorted_eigvalues->begin();
389 
390  for( counter = 0; it2 != it2_end; ++it2, ++evalues_it, ++counter )
391  {
392  *evalues_it = it2->first;
393  sorted_eigvectors->set_column( counter, all_eigvectors->get_column( it2->second ));
394  }
395  delete all_eigvectors;
396  delete eig_permutations;
397 
398  //(3) select the largest magnitude eigenvalues and the corresponding eigenvectors
399  typename vector< X, float_t >::iterator it3 = eigvalues_.begin(), it3_end = eigvalues_.end();
400  evalues_it = sorted_eigvalues->begin();
401  for( ; it3 != it3_end; ++it3, ++evalues_it )
402  {
403  *it3 = *evalues_it;
404  }
405 
406  sorted_eigvectors->get_sub_matrix( eigvectors_ );
407 
408  delete sorted_eigvectors;
409  delete sorted_eigvalues;
410 
411  return p.info == 0;
412 }
413 
414 template< size_t N, typename float_t >
415 bool
416 lapack_sym_eigs< N, float_t >::compute_1st(
417  const m_input_type& A,
418  evector_type& eigvector_,
419  float_t& eigvalue_
420  )
421 {
422  //(1) get all eigenvalues and eigenvectors
423  evectors_type* all_eigvectors = new evectors_type;
424  evalues_type* all_eigvalues = new evalues_type;
425  compute_all( A, *all_eigvectors, *all_eigvalues );
426 
427  //(2) sort the eigenvalues
428  //std::pair< data, original_index >;
429  std::vector< eigv_pair_type >* eig_permutations = new std::vector< eigv_pair_type >;
430 
431  evalue_const_iterator it = all_eigvalues->begin(), it_end = all_eigvalues->end();
432  size_t counter = 0;
433  for( ; it != it_end; ++it, ++counter )
434  {
435  eig_permutations->push_back( eigv_pair_type( *it, counter ) );
436  }
437 
438  std::sort(
439  eig_permutations->begin(),
440  eig_permutations->end(),
441  eigenvalue_compare()
442  );
443 
444  //(2) select the largest magnitude eigenvalue and the corresponding eigenvector
445  typename std::vector< eigv_pair_type >::const_iterator it2 = eig_permutations->begin();
446 
447  eigvalue_ = it2->first;
448  all_eigvectors->get_column( it2->second, eigvector_ );
449 
450  delete eig_permutations;
451  delete all_eigvalues;
452  delete all_eigvectors;
453 
454  return p.info == 0;
455 }
456 
457 
458 
459 
460 } // namespace vmml
461 
462 #endif