/*******************************************************************************
*
* 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