Something went wrong on our end
-
Bertram Kopf authoreddb9d3a68
Matrix.hh 16.57 KiB
// Matrix template class definition file. -*- C++ -*-
/* Copyright 2008 Mike Williams (mwill@jlab.org)
*
* This file is part of qft++.
*
* qft++ 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.
*
* qft++ 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 qft++. If not, see <http://www.gnu.org/licenses/>.
*/
// Author: Mike Williams
#ifndef _Matrix_H
#define _Matrix_H
//_____________________________________________________________________________
// Standard C++ Headers:
#include <iostream>
#include <cassert>
#include <vector>
#include <complex>
#include <cstdlib>
// Local Headers:
#include "qft++/topincludes/c++-template-utils.hh"
#include "qft++/matrix/Matrix_Base.hh"
//_____________________________________________________________________________
/** @file Matrix.h
* @brief Matrix template class definition file.
*/
//_____________________________________________________________________________
using namespace std;
//_____________________________________________________________________________
/** @class Matrix
* @author Mike Williams
*
* @brief General template class for handling matricies and matrix operations.
*
* Matrix is a template class for handling matricies and matrix operations.
* A Matrix object can be any size (n x m) and store any type that can be
* stored in a C++ container class. This class has been written to be as
* general and flexible as possible. Parameter passing has been optimized
* using the Type class. Matrix has been designed so that tow instantiations,
* Matrix<_A> and Matrix<_B>, are completely compatible as long as _A and _B
* are compatible (eg. _A*_B,_A+_B,...are defined). Return types of
* <em>mixed type</em> matrix operations are determined by the OperationType
* template classes (MultType,etc...).
*
* <b>Example Usage </b>
*
* \include Matrix.ex
*/
//_____________________________________________________________________________
template <typename _Tp> class Matrix : public Matrix_Base {
private:
// attributes:
vector<_Tp> _data; ///< Matrix elements (type _Tp)
// private functions:
/// Copy @a matrix elements to this matrix
template<typename V> void _Copy(const Matrix<V> &__matrix){
int size = __matrix.Size();
_data.resize(size);
for(int i = 0; i < size; i++) _data[i] = __matrix._data[i];
}
protected:
// friends:
template <typename V> friend class Matrix;
public:
// create/copy/destroy:
/** Default Constructor */
Matrix() : Matrix_Base(){}
/** Constructor
* @param nrows Number of rows
* @param ncols Number of columns
*/
Matrix(int __nrows,int __ncols) : Matrix_Base(__nrows,__ncols){
_data.resize(__nrows*__ncols);
}
/** Constructor
* @param nrows Number of rows
* @param ncols Number of columns
* @param init Initial value of Matrix elements
*/
Matrix(int __nrows,int __ncols,typename Type<_Tp>::ParamType __init)
: Matrix_Base(__nrows,__ncols){
_data.resize(__nrows*__ncols,__init);
}
/** Constructor
* @param vv 2-D vector to convert to a Matrix
*/
template<typename V> Matrix(const vector<vector<V> > &__vv) : Matrix_Base(){
_num_rows = (int)__vv.size();
if(_num_rows == 0) _num_cols = 0;
else _num_cols = (int)__vv[0].size();
_data.resize(_num_rows*_num_cols);
for(int i = 0; i < _num_rows; i++){
for(int j = 0; j < _num_cols; j++) (*this)(i,j) = __vv[i][j];
}
}
/// Copy Constructor
template<typename V> Matrix(const Matrix<V> &__matrix):Matrix_Base(__matrix){
this->_Copy(__matrix);
}
/** Destructor */
virtual ~Matrix(){}
// operators:
/** Assignment operator
*
* Note: Legal if @a Tp = @a T is a legal assignment.
*
* Note: Asserts @a matrix and @a this be the same size.
*/
template <typename V> Matrix<_Tp>& operator=(const Matrix<V>& __matrix);
/// Assignment operator (for 1 x 1 matrix only)
Matrix<_Tp>& operator=(typename Type<_Tp>::ParamType __val){
assert(this->NumRows() == 1 && this->NumCols() == 1);
_data[0] = __val;
return *this;
}
/// Conversion operator to type @a Tp (valid only for 1x1)
operator _Tp () const {
if(_num_rows != 1 || _num_cols != 1) {
cout << "Error! Attempt to convert a matrix (not 1x1) to a scalar."
<< endl;
}
assert(_num_rows == 1 || _num_cols == 1);
return _data[0];
}
/** Matrix addition.
*
* Note: Legal if @a Tp + @a V is a legal operation.
*
* Note: Asserts @a matrix and @a this be the same size.
*/
template <typename V> Matrix<typename AddType<_Tp,V>::Type>
operator+(const Matrix<V> &__matrix) const;
/** Matrix subtraction.
*
* Note: Legal if @a Tp - @a V is a legal operation.
*
* Note: Asserts @a matrix and @a this be the same size.
*/
template <typename V> Matrix<typename SubType<_Tp,V>::Type>
operator-(const Matrix<V> &__matrix) const;
/** Matrix multiplication
*
* Note: Legal if @a Tp * @a V is a legal operation.
*
* Note: Asserts the number of rows in @a matrix and the number of columns
* in @a this be the same.
*/
template <typename V> Matrix<typename MultType<_Tp,V>::Type>
operator*(const Matrix<V> &__matrix) const;
/** Matrix multiplication with % operator
*
* Note: Legal if @a Tp % @a V is a legal operation.
*
* Note: Asserts the number of rows in @a matrix and the number of columns
* in @a this be the same.
*/
template <typename V> Matrix<typename MultType<_Tp,V>::Type>
operator%(const Matrix<V> &__matrix) const;
/** Matrix multiplication with | operator
*
* Note: Legal if @a Tp | @a V is a legal operation.
*
* Note: Asserts the number of rows in @a matrix and the number of columns
* in @a this be the same.
*/
template <typename V> Matrix<typename MultType<_Tp,V>::Type>
operator|(const Matrix<V> &__matrix) const;
/// \f$ M_{ij} \f$ * x for each matrix element
template <typename V>
typename DisableIf<IsMatrix(V),Matrix<typename MultType<_Tp,V>::Type> >::Type
operator*(const V &__x) const {
int size = this->Size();
Matrix<typename MultType<_Tp,V>::Type> ret(_num_rows,_num_cols);
for(int i = 0; i < size; i++) ret._data[i] = this->_data[i] * __x;
return ret;
}
/// \f$ M_{ij} \f$ / x for each matrix element
template <typename V>
typename DisableIf<IsMatrix(V),Matrix<typename DivType<_Tp,V>::Type> >::Type
operator/(const V &__x) const {
int size = this->Size();
Matrix<typename DivType<_Tp,V>::Type> ret(_num_rows,_num_cols);
for(int i = 0; i < size; i++) ret._data[i] = this->_data[i] / __x;
return ret;
}
/// \f$ M_{ij} \f$ % x for each matrix element
template <typename V>
typename DisableIf<IsMatrix(V),Matrix<typename MultType<_Tp,V>::Type> >::Type
operator%(const V &__x) const {
int size = this->Size();
Matrix<typename MultType<_Tp,V>::Type> ret(_num_rows,_num_cols);
for(int i = 0; i < size; i++) ret._data[i] = this->_data[i] % __x;
return ret;
}
/// \f$ M_{ij} \f$ | x for each matrix element
template <typename V>
typename DisableIf<IsMatrix(V),Matrix<typename MultType<_Tp,V>::Type> >::Type
operator|(const V &__x) const {
int size = this->Size();
Matrix<typename MultType<_Tp,V>::Type> ret(_num_rows,_num_cols);
for(int i = 0; i < size; i++) ret._data[i] = this->_data[i] | __x;
return ret;
}
/// Set @a this = @a this + @a matrix
template <typename V> Matrix<_Tp>& operator+=(const Matrix<V> &__matrix){
(*this) = (*this) + __matrix;
return *this;
}
/// Set @a this = @a this - @a matrix
template <typename V> Matrix<_Tp>& operator-=(const Matrix<V> &__matrix){
(*this) = (*this) - __matrix;
return *this;
}
/// Set @a this = @a this * @a matrix
template <typename V> Matrix<_Tp>& operator*=(const Matrix<V> &__matrix){
(*this) = (*this) * __matrix;
return *this;
}
/// Set @a this = @a this * @a x
template <typename V> typename DisableIf<IsMatrix(V),Matrix<_Tp>&>::Type
operator*=(const V &__x){
(*this) = (*this) * __x;
return *this;
}
/// Set @a this = @a this / @a x
template <typename V> typename DisableIf<IsMatrix(V),Matrix<_Tp>&>::Type
operator/=(const V &__x){
(*this) = (*this) / __x;
return *this;
}
/** Comparison operator
*
* @param matrix A Matrix of the same type as @a this
*
* Requires that the matricies be the same size, and that none of their
* elements return @a true when passed to the != operator for type @a _Tp.
*/
bool operator==(const Matrix<_Tp> &__matrix) const;
/// Comparison operator (see operator== for details)
inline bool operator!=(const Matrix<_Tp> &__matrix) const {
return !(*this == __matrix);
}
// Getters:
/// Returns a reference to the (i,j) element of the matrix
inline _Tp& Element(int __i, int __j){
if(__i >= _num_rows || __j >= _num_cols)
cout << "Error! Attempting to access non-existent element." << endl;
assert(__i < _num_rows && __j < _num_cols);
return _data[__i*_num_cols + __j];
}
/// Returns a constant reference to the (i,j) element of the matrix
inline const _Tp& Element(int __i, int __j) const {
if(__i >= _num_rows || __j >= _num_cols)
cout << "Error! Attempting to access non-existent element." << endl;
assert(__i < _num_rows && __j < _num_cols);
return _data[__i*_num_cols + __j];
}
/// Returns a reference to the (i,j) element of the matrix
inline _Tp& operator()(int __i,int __j) {
return this->Element(__i,__j);
}
/// Returns a constant reference to the (i,j) element of the matrix
inline const _Tp& operator()(int __i,int __j) const {
return this->Element(__i,__j);
}
/// Returns a constant reference to the i'th array element
inline const _Tp& operator[](int __i) const {
return _data[__i];
}
/// Returns the matrix \f$ M_{jk}(i) \f$ from this matrix
Matrix<_Tp> operator()(int __i) const {
Matrix<_Tp> ret(_num_rows,_num_cols);
for(int j = 0; j < this->Size(); j++)
ret._data[j] = this->_data[j].operator()(__i);
return ret;
}
// Functions:
/** Returns the trace of the matrix */
_Tp Trace() const;
/// Returns the trace of the matrix
inline _Tp Tr() const {
return this->Trace();
}
/** Returns the transpose of @a this matrix */
Matrix<_Tp> Transpose() const;
/// Return the transpose of @a this matrix
inline Matrix<_Tp> T() const {
return this->Transpose();
}
/** Returns the complex conjugate of @a this matrix
* Note: Legal if conj(_Tp) exists
* (see c++-template-utils/TemplateUtilFuncs.h)
*/
Matrix<_Tp> Conjugate() const {
Matrix<_Tp> ret(_num_rows,_num_cols);
for(int i = 0; i < this->Size(); i++) ret._data[i] = conj(this->_data[i]);
return ret;
}
/// Returns the complex conjugate of @a this matrix (see Conjugate()).
Matrix<_Tp> Conj() const {
return this->Conjugate();
}
/// Returns the adjoint of @a this matrix (see Conjugate() and Transpose())
Matrix<_Tp> Adjoint() const {
Matrix<_Tp> ret(_num_rows,_num_cols);
ret = (this->Transpose()).Conjugate();
return ret;
}
/// Returns the adjoint of @a this matrix (see Conjugate() and Transpose())
Matrix<_Tp> Dagger() const {
return this->Adjoint();
}
/// Set each element of @a this matrix to zero
/** Note: Legal if zero(_Tp) is legal
* (see c++-template-utils/TemplateUtilFuncs.h)
*/
void Zero() {
for(int i = 0; i < this->Size(); i++) _data[i] = zero(_data[i]);
}
void invert(){
if(_num_rows != _num_cols){
cout << "Error! invert() matrix must be diagonal."
<< endl;
}
assert(_num_rows == _num_cols);
if (_num_rows <= 0) return; // sanity check
if (_num_rows == 1){
_data[0] = unity(_data[0])/_data[0];
return;
}
// must be of dimension >= 2
for (int i=1; i < _num_rows; i++) _data[i] /= _data[0]; // normalize row 0
for (int i=1; i < _num_rows; i++) {
for (int j=i; j < _num_rows; j++) { // do a column of L
_Tp sum = 0.0;
for (int k = 0; k < i; k++)
// sum += _data[j*Size()+k] * _data[k*Size()+i];
// _data[j*Size()+i] -= sum;
sum += _data[j*_num_rows+k] * _data[k*_num_rows+i];
_data[j*_num_rows+i] -= sum;
}
if (i == _num_rows-1) continue;
for (int j=i+1; j < _num_rows; j++) { // do a row of U
_Tp sum = zero( _data[0] );
for (int k = 0; k < i; k++)
// sum += _data[i*Size()+k]*_data[k*Size()+j];
// _data[i*Size()+j] =
// (_data[i*Size()+j]-sum) / _data[i*Size()+i];
sum += _data[i*_num_rows+k]*_data[k*_num_rows+j];
_data[i*_num_rows+j] =
(_data[i*_num_rows+j]-sum) / _data[i*_num_rows+i];
}
}
for ( int i = 0; i < _num_rows; i++ ) // invert L
for ( int j = i; j < _num_rows; j++ ) {
_Tp x = unity(_data[0]);
if ( i != j ) {
x = 0.0;
for ( int k = i; k < j; k++ )
x -= _data[j*_num_cols+k]*_data[k*_num_cols+i];
}
_data[j*_num_cols+i] = x / _data[j*_num_cols+j];
}
for ( int i = 0; i < _num_rows; i++ ) // invert U
for ( int j = i; j < _num_rows; j++ ) {
if ( i == j ) continue;
_Tp sum = zero(_data[0]);
for ( int k = i; k < j; k++ )
sum += _data[k*_num_cols+j]*( (i==k) ? 1.0 : _data[i*_num_cols+k] );
_data[i*_num_cols+j] = -sum;
}
for ( int i = 0; i < _num_rows; i++ ) // final inversion
for ( int j = 0; j < _num_rows; j++ ) {
_Tp sum = zero(_data[0]);
for ( int k = ((i>j)?i:j); k < _num_rows; k++ )
sum += ((j==k)?1.0:_data[j*_num_cols+k])*_data[k*_num_cols+i];
_data[j*_num_cols+i] = sum;
}
}
/// Removes all elements from the matrix
void Clear() {
if(!_data.empty()) _data.clear();
_num_rows = 0;
_num_cols = 0;
}
/// Resize the matrix to be @a nrows X @a ncols.
void Resize(int __nrows,int __ncols) {
_num_rows = __nrows;
_num_cols = __ncols;
_data.resize(__nrows*__ncols);
}
/// Print the matrix to @a os
void Print(std::ostream &__os = std::cout) const {
for(int i = 0; i < _num_rows; i++){
for(int j = 0; j < _num_cols; j++) __os << this->Element(i,j) << " ";
__os << endl;
}
}
};
//_____________________________________________________________________________
/// @a x * \f$ M_{ij} \f$ for each matrix element
template<typename T1,typename T2>
typename DisableIf<IsMatrix(T1),Matrix<typename MultType<T1,T2>::Type> >::Type
operator*(const T1 &__x,const Matrix<T2> &__matrix){
int rows = __matrix.NumRows();
int cols = __matrix.NumCols();
Matrix<typename MultType<T1,T2>::Type> ret(rows,cols);
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
ret(i,j) = __x * __matrix(i,j);
}
}
return ret;
}
//_____________________________________________________________________________
/// @a x % \f$ M_{ij} \f$ for each matrix element
template<typename T1,typename T2>
typename DisableIf<IsMatrix(T1),Matrix<typename MultType<T1,T2>::Type> >::Type
operator%(const T1 &__x,const Matrix<T2> &__matrix){
int rows = __matrix.NumRows();
int cols = __matrix.NumCols();
Matrix<typename MultType<T1,T2>::Type> ret(rows,cols);
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
ret(i,j) = __x % __matrix(i,j);
}
}
return ret;
}
//_____________________________________________________________________________
/// @a x | \f$ M_{ij} \f$ for each matrix element
template<typename T1,typename T2>
typename DisableIf<IsMatrix(T1),Matrix<typename MultType<T1,T2>::Type> >::Type
operator|(const T1 &__x,const Matrix<T2> &__matrix){
int rows = __matrix.NumRows();
int cols = __matrix.NumCols();
Matrix<typename MultType<T1,T2>::Type> ret(rows,cols);
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
ret(i,j) = __x | __matrix(i,j);
}
}
return ret;
}
//_____________________________________________________________________________
/// Overload of operator << for the Matrix class
template<typename T>
ostream& operator<<(ostream &__os,const Matrix<T> &__matrix){
__matrix.Print(__os);
return __os;
}
//_____________________________________________________________________________
#include "qft++/matrix/Matrix.tcc" /* Matrix template class source file */
#endif /* _Matrix_H */