geev.hpp

Go to the documentation of this file.
00001 /*
00002  * 
00003  * Copyright (c) Andreas Kloeckner 2004
00004  *               Toon Knapen, Karl Meerbergen & Kresimir Fresl 2003
00005  *
00006  * Distributed under the Boost Software License, Version 1.0.
00007  * (See accompanying file LICENSE_1_0.txt or copy at
00008  * http://www.boost.org/LICENSE_1_0.txt)
00009  *
00010  * KF acknowledges the support of the Faculty of Civil Engineering, 
00011  * University of Zagreb, Croatia.
00012  *
00013  */
00014 
00015 #ifndef BOOST_NUMERIC_BINDINGS_LAPACK_GEEV_HPP
00016 #define BOOST_NUMERIC_BINDINGS_LAPACK_GEEV_HPP
00017 
00018 #include <boost/numeric/bindings/traits/traits.hpp>
00019 #include <boost/numeric/bindings/traits/type.hpp>
00020 #include <boost/numeric/bindings/lapack/lapack.h>
00021 #include <boost/numeric/bindings/lapack/workspace.hpp>
00022 #include <boost/numeric/bindings/traits/detail/array.hpp>
00023 // #include <boost/numeric/bindings/traits/std_vector.hpp>
00024 
00025 #ifndef BOOST_NUMERIC_BINDINGS_NO_STRUCTURE_CHECK 
00026 #  include <boost/static_assert.hpp>
00027 #  include <boost/type_traits.hpp>
00028 #endif 
00029 
00030 
00031 namespace boost { namespace numeric { namespace bindings { 
00032 
00033   namespace lapack {
00034 
00036     //
00037     // Eigendecomposition of a general matrix A * V = V * D
00038     // 
00040 
00041     /* 
00042      * geev() computes the eigendecomposition of a N x N matrix,
00043      * where V is a N x N matrix and D is a diagonal matrix. The 
00044      * diagonal element D(i,i) is an eigenvalue of A and Q(:,i) is 
00045      * a corresponding eigenvector.
00046      *
00047      *
00048      * int geev (char jobz, char uplo, A& a, W& w, V* vl, V* vr, optimal_workspace);
00049      *
00050      * a is the matrix whose eigendecomposition you're interested in. (input)
00051      *
00052      * w contains the diagonal of D, above. w must always be complex. (output)
00053      *
00054      * vl is an N x N matrix containing the left eigenvectors of a in its
00055      * columns. See remark on complex vs. real below. May be left NULL to indicate
00056      * that you do not want left eigenvectors.
00057      *
00058      * vr is an N x N matrix containing the right ("usual") eigenvectors of a in its
00059      * columns. See remark on complex vs. real below. As a matrix, vr fulfills
00060      * A * VR = VR * D. (except if real, see below). May be left NULL to indicate
00061      * that you do not want right eigenvectors.
00062      *
00063      *
00064      * For real A, vr and vl may be either complex or real, at your option.
00065      * If you choose to leave them real, you have to pick apart the complex-conjugate
00066      * eigenpairs as per the LAPACK documentation. If you choose them complex,
00067      * the code will do the picking-apart on your behalf, at the expense of 4*N
00068      * extra storage. Only if vr is complex, it will really fulfill its invariant 
00069      * on exit to the code in all cases, since complex pairs spoil that relation.
00070      */ 
00071 
00072     namespace detail {
00073 
00074       inline
00075       int geev_backend(const char* jobvl, const char* jobvr, const int* n, float* a,
00076                const int* lda, float* wr, float* wi, float* vl, const int* ldvl,
00077                float* vr, const int* ldvr, float* work, const int* lwork)
00078       {
00079         int info;
00080         LAPACK_SGEEV(jobvl, jobvr, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, work, lwork, &info);
00081         return info;
00082       }
00083 
00084       inline
00085       int geev_backend(const char* jobvl, const char* jobvr, const int* n, double* a,
00086                const int* lda, double* wr, double* wi, double* vl, const int* ldvl,
00087                double* vr, const int* ldvr, double* work, const int* lwork)
00088       {
00089         int info;
00090         LAPACK_DGEEV(jobvl, jobvr, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, work, lwork, &info);
00091         return info;
00092       }
00093 
00094       inline
00095       int geev_backend(const char* jobvl, const char* jobvr, const int* n, traits::complex_f* a,
00096                const int* lda, traits::complex_f* w, traits::complex_f* vl, const int* ldvl,
00097                traits::complex_f* vr, const int* ldvr, traits::complex_f* work, const int* lwork,
00098                float* rwork)
00099       {
00100         int info;
00101         LAPACK_CGEEV(jobvl, jobvr, n, 
00102                      traits::complex_ptr(a), lda, 
00103                      traits::complex_ptr(w), 
00104                      traits::complex_ptr(vl), ldvl, 
00105                      traits::complex_ptr(vr), ldvr, 
00106                      traits::complex_ptr(work), lwork, 
00107                      rwork, &info);
00108         return info;
00109       }
00110 
00111       inline
00112       int geev_backend(const char* jobvl, const char* jobvr, const int* n, traits::complex_d* a,
00113                const int* lda, traits::complex_d* w, traits::complex_d* vl, const int* ldvl,
00114                traits::complex_d* vr, const int* ldvr, traits::complex_d* work, const int* lwork,
00115                double* rwork)
00116       {
00117         int info;
00118         LAPACK_ZGEEV(jobvl, jobvr, n, 
00119                      traits::complex_ptr(a), lda, 
00120                      traits::complex_ptr(w), 
00121                      traits::complex_ptr(vl), ldvl, 
00122                      traits::complex_ptr(vr), ldvr, 
00123                      traits::complex_ptr(work), lwork, 
00124                      rwork, &info);
00125         return info;
00126       }
00127 
00128 
00129       struct real_case {};
00130       struct mixed_case {};
00131       struct complex_case {};
00132 
00133 
00134 
00135 
00136       // real case
00137       template <typename A, typename W, typename V>
00138       int geev(real_case, const char jobvl, const char jobvr, A& a, W& w, 
00139                V* vl, V *vr)
00140       {
00141         int const n = traits::matrix_size1(a);
00142         typedef typename A::value_type value_type;
00143         traits::detail::array<value_type> wr(n);
00144         traits::detail::array<value_type> wi(n);
00145 
00146         traits::detail::array<value_type> vl2(vl ? 0 : n);
00147         traits::detail::array<value_type> vr2(vr ? 0 : n);
00148         value_type* vl_real = vl ? traits::matrix_storage(*vl) : vl2.storage();
00149         const int ldvl = vl ? traits::matrix_size2(*vl) : 1;
00150         value_type* vr_real = vr ? traits::matrix_storage(*vr) : vr2.storage();
00151         const int ldvr = vr ? traits::matrix_size2(*vr) : 1;
00152 
00153 
00154         // workspace query
00155         int lwork = -1;
00156         value_type work_temp;
00157         int result = geev_backend(&jobvl, &jobvr, &n,
00158                                   traits::matrix_storage(a), &n, 
00159                                   wr.storage(), wi.storage(), 
00160                                   vl_real, &ldvl, vr_real, &ldvr,
00161                                   &work_temp, &lwork);
00162         if (result != 0)
00163           return result;
00164 
00165         lwork = (int) work_temp;
00166         traits::detail::array<value_type> work(lwork);
00167         result = geev_backend(&jobvl, &jobvr, &n,
00168                               traits::matrix_storage(a), &n, 
00169                               wr.storage(), wi.storage(), 
00170                               vl_real, &ldvl, vr_real, &ldvr,
00171                               work.storage(), &lwork);
00172 
00173         for (int i = 0; i < n; i++)
00174           w[i] = std::complex<value_type>(wr[i], wi[i]);
00175         return result;
00176       }
00177 
00178       // mixed (i.e. real with complex vectors) case
00179       template <typename A, typename W, typename V>
00180       int geev(mixed_case, const char jobvl, const char jobvr, A& a, W& w, 
00181                V* vl, V *vr)
00182       {
00183         int const n = traits::matrix_size1(a);
00184         typedef typename A::value_type value_type;
00185         traits::detail::array<value_type> wr(n);
00186         traits::detail::array<value_type> wi(n);
00187 
00188         traits::detail::array<value_type> vl2(vl ? n*n : n);
00189         traits::detail::array<value_type> vr2(vr ? n*n : n);
00190         const int ldvl2 = vl ? n : 1;
00191         const int ldvr2 = vr ? n : 1;
00192 
00193         // workspace query
00194         int lwork = -1;
00195         value_type work_temp;
00196         int result = geev_backend(&jobvl, &jobvr, &n,
00197                                   traits::matrix_storage(a), &n, 
00198                                   wr.storage(), wi.storage(), 
00199                                   vl2.storage(), &ldvl2, vr2.storage(), &ldvr2,
00200                                   &work_temp, &lwork);
00201         if (result != 0)
00202           return result;
00203 
00204         lwork = (int) work_temp;
00205         traits::detail::array<value_type> work(lwork);
00206         result = geev_backend(&jobvl, &jobvr, &n,
00207                               traits::matrix_storage(a), &n, 
00208                               wr.storage(), wi.storage(), 
00209                               vl2.storage(), &ldvl2, vr2.storage(), &ldvr2,
00210                               work.storage(), &lwork);
00211 
00212         typedef typename V::value_type vec_value_type;
00213         vec_value_type* vl_stor = NULL;
00214         vec_value_type* vr_stor = NULL;
00215         int ldvl = 0, ldvr = 0;
00216         if (vl)
00217         {
00218           vl_stor = traits::matrix_storage(*vl);
00219           ldvl = traits::matrix_size2(*vl);
00220         }
00221         if (vr)
00222         {
00223           vr_stor = traits::matrix_storage(*vr);
00224           ldvr = traits::matrix_size2(*vr);
00225         }
00226         
00227         for (int i = 0; i < n; i++)
00228         {
00229           w[i] = std::complex<value_type>(wr[i], wi[i]);
00230           if (wi[i] != 0)
00231           {
00232             assert(i+1 < n);
00233             assert(wr[i+1] == wr[i]);
00234             assert(wi[i+1] == -wi[i]);
00235 
00236             w[i+1] = std::complex<value_type>(wr[i+1], wi[i+1]);
00237             for (int j = 0; j < n; j++)
00238             {
00239               if (vl)
00240               {
00241                 vl_stor[i*ldvl+j] = std::complex<value_type>(vl2[i*n+j], vl2[(i+1)*n+j]);
00242                 vl_stor[(i+1)*ldvl+j] = std::complex<value_type>(vl2[i*n+j], -vl2[(i+1)*n+j]);
00243               }
00244               if (vr)
00245               {
00246                 vr_stor[i*ldvr+j] = std::complex<value_type>(vr2[i*n+j], vr2[(i+1)*n+j]);
00247                 vr_stor[(i+1)*ldvr+j] = std::complex<value_type>(vr2[i*n+j], -vr2[(i+1)*n+j]);
00248               }
00249             }
00250 
00251             i++;
00252           }
00253           else
00254           {
00255             for (int j = 0; j < n; j++)
00256             {
00257               if (vl)
00258                 vl_stor[i*ldvl+j] = vl2[i*n+j];
00259               if (vr)
00260                 vr_stor[i*ldvr+j] = vr2[i*n+j];
00261             }
00262           }
00263         }
00264         return result;
00265       }
00266 
00267       // complex case
00268       template <typename A, typename W, typename V>
00269       int geev(complex_case, const char jobvl, const char jobvr, A& a, W& w, 
00270                V* vl, V *vr)
00271       {
00272         typedef typename A::value_type value_type;
00273         typedef typename traits::type_traits<value_type>::real_type real_type;
00274 
00275         int const n = traits::matrix_size1(a);
00276         traits::detail::array<real_type> rwork(2*n);
00277 
00278         traits::detail::array<value_type> vl2(vl ? 0 : n);
00279         traits::detail::array<value_type> vr2(vr ? 0 : n);
00280         value_type* vl_real = vl ? traits::matrix_storage(*vl) : vl2.storage();
00281         const int ldvl = vl ? traits::matrix_size2(*vl) : 1;
00282         value_type* vr_real = vr ? traits::matrix_storage(*vr) : vr2.storage();
00283         const int ldvr = vr ? traits::matrix_size2(*vr) : 1;
00284 
00285         // workspace query
00286         int lwork = -1;
00287         value_type work_temp;
00288         int result = geev_backend(&jobvl, &jobvr, &n,
00289                                   traits::matrix_storage(a), &n, 
00290                                   traits::vector_storage(w),
00291                                   vl_real, &ldvl, vr_real, &ldvr,
00292                                   &work_temp, &lwork, rwork.storage());
00293         if (result != 0)
00294           return result;
00295 
00296         lwork = (int) std::real(work_temp);
00297         traits::detail::array<value_type> work(lwork);
00298         result = geev_backend(&jobvl, &jobvr, &n,
00299                               traits::matrix_storage(a), &n, 
00300                               traits::vector_storage(w),
00301                               vl_real, &ldvl, vr_real, &ldvr,
00302                               work.storage(), &lwork, 
00303                               rwork.storage());
00304 
00305         return result;
00306       }
00307 
00308     } // namespace detail
00309 
00310 
00311     // gateway / dispatch routine
00312     template <typename A, typename W, typename V>
00313     int geev(A& a, W& w,  V* vl, V* vr, optimal_workspace) 
00314     {
00315       // input checking
00316 #ifndef BOOST_NUMERIC_BINDINGS_NO_STRUCTURE_CHECK 
00317       BOOST_STATIC_ASSERT((boost::is_same<
00318                            typename traits::matrix_traits<A>::matrix_structure, 
00319                            traits::general_t
00320                            >::value)); 
00321 #endif 
00322 
00323 #ifndef NDEBUG
00324       int const n = traits::matrix_size1(a);
00325 #endif
00326 
00327       assert(traits::matrix_size2(a)==n); 
00328       assert(traits::vector_size(w)==n); 
00329       assert(traits::vector_size(w)==n); 
00330       assert(!vr || traits::matrix_size1(*vr)==n); 
00331       assert(!vl || traits::matrix_size1(*vl)==n); 
00332 
00333       // preparation
00334       typedef typename A::value_type value_type;
00335       typedef typename V::value_type vec_value_type;
00336       typedef typename traits::type_traits<value_type>::real_type real_type;
00337 
00338       // dispatch
00339       return detail::geev(typename boost::mpl::if_<
00340                           boost::is_same<value_type, real_type>,
00341                           typename boost::mpl::if_<
00342                           boost::is_same<vec_value_type, real_type>,
00343                           detail::real_case,
00344                           detail::mixed_case>::type,
00345                           detail::complex_case>::type(),
00346                           vl != 0 ? 'V' : 'N', 
00347                           vr != 0 ? 'V' : 'N',
00348                           a, w, vl, vr);
00349     }
00350 
00351   }
00352 
00353 }}}
00354 
00355 #endif 

Generated on Wed Nov 23 19:00:15 2011 for FreeCAD by  doxygen 1.6.1