/******************************************************************************* * * TRIQS: a Toolbox for Research in Interacting Quantum Systems * * Copyright (C) 2011 by O. Parcollet * * TRIQS is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * TRIQS. If not, see . * ******************************************************************************/ #ifndef TRIQS_ARRAY_EIGENELEMENTS_H #define TRIQS_ARRAY_EIGENELEMENTS_H #include #include "../matrix.hpp" #include "../vector.hpp" #include namespace triqs { namespace arrays { namespace linalg { /** * A worker to call lapack routine with the matrices. * * Handles both real and complex case. * * Usage : * - construct from a VIEW of a matrix, that MUST be contiguous. * - call invoke() * - read the eigenvalues/vectors in values and vectors resp. * NB : the content of the matrix is destroyed by the computation (it is .vectors() in fact, if Compute_Eigenvectors is true). * For a one shot usage, prefer eigenelements, eigenvalues functions. */ template struct eigenelements_worker; template struct eigenelements_worker_base; template struct eigenelements_worker_base { private: void operator = ( eigenelements_worker_base const & x); protected: matrix_view mat; triqs::arrays::vector ev; triqs::arrays::vector work; int dim,info,lwork; char uplo,compz; bool has_run; eigenelements_worker_base ( matrix_view the_matrix) : mat(the_matrix) { if (mat.is_empty()) TRIQS_RUNTIME_ERROR<<"eigenelements_worker : the matrix is empty : matrix = "< values() const { if (!has_run) TRIQS_RUNTIME_ERROR<<"eigenelements_worker has not been invoked !"; return ev; } }; //-------------------------------- template struct eigenelements_worker_base : eigenelements_worker_base { protected: eigenelements_worker_base ( matrix_view the_matrix) : eigenelements_worker_base (the_matrix) {this->compz='V'; } public: matrix vectors() const { if (!this->has_run) TRIQS_RUNTIME_ERROR<<"eigenelements_worker has not been invoked !"; return this->mat; } }; //-------------------------------- extern "C" { void TRIQS_FORTRAN_MANGLING(dsyev)(char*,char*, // JOBZ and UPLO int &, // Matrix Size double[], // matrix int&, // LDA of the matrix double[], // Eigenvalues array double[], // WORK int&, // LWORK int & // INFO ); void TRIQS_FORTRAN_MANGLING(zheev)(char*,char*, // JOBZ and UPLO int &, // Matrix Size std::complex [], // matrix int&, // LDA of the matrix double[], // Eigenvalues array std::complex[], // WORK int &, // LWORK double[], // WORK2 int & // INFO ); } //-------------------------------- template struct eigenelements_worker< matrix_view ,Compute_Eigenvectors > :eigenelements_worker_base { eigenelements_worker ( matrix_view the_matrix) : eigenelements_worker_base (the_matrix) {} void invoke() { int info; //fortran_int_t info; TRIQS_FORTRAN_MANGLING(dsyev) (&this->compz,&this->uplo,this->dim,this->mat.data_start(),this->dim,this->ev.data_start(),this->work.data_start(),this->lwork,info); if (info) TRIQS_RUNTIME_ERROR<<"eigenelements_worker :error code dsyev : "<mat; this->has_run = true; } }; //-------------------------------- template struct eigenelements_worker< matrix_view, Opt>,Compute_Eigenvectors > :eigenelements_worker_base,Opt,Compute_Eigenvectors> { triqs::arrays::vector work2; public : eigenelements_worker ( matrix_view ,Opt> the_matrix) : eigenelements_worker_base,Opt,Compute_Eigenvectors> (the_matrix) { work2.resize(this->lwork);} void invoke() { int info; TRIQS_FORTRAN_MANGLING(zheev) (&this->compz,&this->uplo,this->dim,this->mat.data_start(), this->dim,this->ev.data_start(),this->work.data_start(),this->lwork,this->work2.data_start(),info); if (info) TRIQS_RUNTIME_ERROR<<"eigenelements_worker :error code zheev : "<mat; this->has_run = true; } }; //-------------------------------- /** * Simple diagonalization call, return all eigenelements. * Handles both real and complex case. * @param M : the matrix VIEW : it MUST be contiguous * @param take_copy : makes a copy of the matrix before calling lapack, so that the original is preserved. * if false : no copy is made and the content of the matrix M is destroyed (it is equal to vectors()). * if true : a copy is made, M is preserved, but of course it is slower... */ template std::pair, typename MatrixViewType::non_view_type> eigenelements( MatrixViewType M, bool take_copy =false) { eigenelements_worker W(take_copy ? make_clone(M)() : M()); W.invoke(); return std::make_pair(W.values(),W.vectors()); } //-------------------------------- /** * Simple diagonalization call, returning only the eigenvalues. * Handles both real and complex case. * @param M : the matrix VIEW : it MUST be contiguous * @param take_copy : makes a copy of the matrix before calling lapack, so that the original is preserved. * if false : no copy is made and the content of the matrix M is destroyed. * if true : a copy is made, M is preserved, but of course it is slower... */ template triqs::arrays::vector_view eigenvalues( MatrixViewType M, bool take_copy = false) { eigenelements_worker W(take_copy ? make_clone(M)() : M()); W.invoke(); return W.values(); } }}} // namespace triqs::arrays::linalg #endif