/* This file is part of MAUS: http:// micewww.pp.rl.ac.uk:8080/projects/maus
*
* MAUS 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.
*
* MAUS 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 MAUS. If not, see .
*/
/* Author: Peter Lane
*
* From MMatrix.cc (see Matrix.hh):
*
* To get the templates right in cc file, you need to declare a function
* and then tell compiler which template objects to compile - otherwise
* you will get a linker error
*
* I am trying to replace CLHEP matrix here, as CLHEP has less functionality
* and is probably worse written than GSL. A similar thing exists in boost
* library
*/
#include "Maths/Matrix.hh"
#include
#include
#include
#include "CLHEP/Matrix/Matrix.h"
#include "gsl/gsl_linalg.h"
#include "gsl/gsl_eigen.h"
#include "json/json.h"
#include "Utils/Exception.hh"
#include "Maths/Vector.hh"
#include "Utils/JsonWrapper.hh"
using MAUS::complex;
using MAUS::Vector;
using MAUS::MatrixBase;
using MAUS::Matrix;
namespace MAUS {
// ############################
// MatrixBase (public)
// ############################
// *************************
// Constructors
// *************************
template
MatrixBase::MatrixBase() : matrix_(NULL) {}
template MatrixBase::MatrixBase();
template MatrixBase::MatrixBase();
template <>
MatrixBase::MatrixBase(
const MatrixBase& original_instance)
: matrix_(NULL) {
if (original_instance.matrix_ != NULL) {
build_matrix(original_instance.matrix_->size1,
original_instance.matrix_->size2);
gsl_matrix_memcpy(matrix_, original_instance.matrix_);
}
}
template <>
MatrixBase::MatrixBase(
const MatrixBase& original_instance)
: matrix_(NULL) {
if (original_instance.matrix_ != NULL) {
build_matrix(original_instance.matrix_->size1,
original_instance.matrix_->size2);
gsl_matrix_complex_memcpy(matrix_, original_instance.matrix_);
}
}
template <>
MatrixBase::MatrixBase(
const ::CLHEP::HepMatrix& hep_matrix) : matrix_(NULL) {
size_t rows = hep_matrix.num_row();
size_t columns = hep_matrix.num_col();
build_matrix(rows, columns);
for (size_t row = 1; row <= rows; ++row) {
for (size_t column = 1; column <= columns; ++column) {
(*this)(row, column) = hep_matrix(row, column);
}
}
}
template <>
MatrixBase::MatrixBase(
const ::CLHEP::HepMatrix& hep_matrix) : matrix_(NULL) {
size_t rows = hep_matrix.num_row();
size_t columns = hep_matrix.num_col();
build_matrix(rows, columns);
for (size_t row = 1; row <= rows; ++row) {
for (size_t column = 1; column <= columns; ++column) {
(*this)(row, column) = MAUS::Complex::complex(hep_matrix(row, column));
}
}
}
template
MAUS::MatrixBase::MatrixBase(const size_t rows,
const size_t columns)
: matrix_(NULL) {
build_matrix(rows, columns);
}
template MatrixBase::MatrixBase(
const size_t rows, const size_t columns);
template MatrixBase::MatrixBase(
const size_t rows, const size_t columns);
template
MAUS::MatrixBase::MatrixBase(const size_t rows,
const size_t columns,
const StdType value)
: matrix_(NULL) {
build_matrix(rows, columns);
for (size_t row = 1; row <= rows; row++) {
for (size_t column = 1; column <= columns; column++) {
(*this)(row, column) = value;
}
}
}
template MatrixBase::MatrixBase(
const size_t rows, const size_t columns, const double value);
template MatrixBase::MatrixBase(
const size_t rows, const size_t columns, const complex value);
template
MatrixBase::MatrixBase(const size_t rows,
const size_t columns,
StdType const * const data)
: matrix_(NULL) {
build_matrix(rows, columns, data);
}
template MatrixBase::MatrixBase(
const size_t rows, const size_t columns, double const * const data);
template MatrixBase::MatrixBase(
const size_t rows, const size_t columns, complex const * const data);
template
MatrixBase::~MatrixBase() {
delete_matrix();
}
template MatrixBase::~MatrixBase();
template MatrixBase::~MatrixBase();
// *************************
// Indexing Operators
// *************************
template <>
double& MatrixBase::operator()(
const size_t row, const size_t column) {
if (matrix_ == NULL) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Attempting to index an empty matrix.",
"MatrixBase::operator()"));
} else if ((row < 1) || (row > matrix_->size1)) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Row index out of bounds.",
"MatrixBase::operator()"));
} else if ((column < 1) || (column > matrix_->size2)) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Column index out of bounds.",
"MatrixBase::operator()"));
}
return *gsl_matrix_ptr(matrix_, row-1, column-1);
}
template <>
complex& MatrixBase::operator()(
const size_t row, const size_t column) {
if (matrix_ == NULL) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Attempting to index an empty matrix.",
"MatrixBase::operator()"));
} else if ((row < 1) || (row > matrix_->size1)) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Row index out of bounds.",
"MatrixBase::operator()"));
} else if ((column < 1) || (column > matrix_->size2)) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Column index out of bounds.",
"MatrixBase::operator()"));
}
return *gsl_matrix_complex_ptr(matrix_, row-1, column-1);
}
template <>
const double& MatrixBase::operator()(
const size_t row, const size_t column) const {
if (matrix_ == NULL) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Attempting to index an empty matrix.",
"MatrixBase::operator()"));
} else if ((row < 1) || (row > matrix_->size1)) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Row index out of bounds.",
"MatrixBase::operator()"));
} else if ((column < 1) || (column > matrix_->size2)) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Column index out of bounds.",
"MatrixBase::operator()"));
}
return *gsl_matrix_ptr(matrix_, row-1, column-1);
}
template <>
const complex& MatrixBase::operator()(
const size_t row, const size_t column) const {
if (matrix_ == NULL) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Attempting to index an empty matrix.",
"MatrixBase::operator()"));
} else if ((row < 1) || (row > matrix_->size1)) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Row index out of bounds.",
"MatrixBase::operator()"));
} else if ((column < 1) || (column > matrix_->size2)) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Column index out of bounds.",
"MatrixBase::operator()"));
}
return *gsl_matrix_complex_ptr(matrix_, row-1, column-1);
}
template Vector
MAUS::MatrixBase::row(const size_t row) const {
if (matrix_ == NULL) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Attempting to index an empty matrix.",
"MatrixBase::row()"));
} else if ((row < 1) || (row > matrix_->size1)) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Row index out of bounds.",
"MatrixBase::operator()"));
}
size_t columns = matrix_->size2;
Vector row_vector(columns);
for (size_t column = 1; column <= columns; ++column) {
row_vector(column) = (*this)(row, column);
}
return row_vector;
}
template Vector
MatrixBase::row(const size_t row) const;
template Vector
MatrixBase::row(const size_t row) const;
template Vector
MatrixBase::column(const size_t column) const {
if (matrix_ == NULL) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Attempting to index and empty matrix.",
"MatrixBase::operator()"));
} else if ((column < 1) || (column > matrix_->size2)) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Column index out of bounds.",
"MatrixBase::operator()"));
}
size_t rows = matrix_->size1;
Vector column_vector(rows);
for (size_t row = 1; row <= rows; ++row) {
column_vector(row) = operator()(row, column);
}
return column_vector;
}
template Vector
MatrixBase::column(const size_t column) const;
template Vector
MatrixBase::column(const size_t column) const;
// *************************
// Size Functions
// *************************
template
const size_t MatrixBase::number_of_rows() const {
if (matrix_ != NULL) {
return matrix_->size1;
}
return 0;
}
template const size_t MatrixBase::number_of_rows() const;
template
const size_t MatrixBase::number_of_rows() const;
template
const size_t MatrixBase::number_of_columns() const {
if (matrix_ != NULL) {
return matrix_->size2;
}
return 0;
}
template const size_t MatrixBase::number_of_columns() const;
template
const size_t MatrixBase::number_of_columns() const;
// *************************
// Submatrix Functions
// *************************
template
MatrixBase MatrixBase::submatrix(
size_t start_row, size_t number_of_rows,
size_t start_column, size_t number_of_columns) const {
MatrixBase submatrix(number_of_rows, number_of_columns);
for (size_t row = 1; row <= number_of_rows; ++row) {
for (size_t column = 1; column <= number_of_columns; ++column) {
submatrix(row, column) = (*this)(start_row+row-1, start_column+column-1);
}
}
return submatrix;
}
template MatrixBase
MatrixBase::submatrix(
size_t start_row, size_t number_of_rows,
size_t start_column, size_t number_of_columns) const;
template MatrixBase
MatrixBase::submatrix(
size_t start_row, size_t number_of_rows,
size_t start_column, size_t number_of_columns) const;
// *************************
// Assignment Operators
// *************************
template <>
MatrixBase& MatrixBase::operator=(
const MatrixBase& rhs) {
if (&rhs != this) {
if (matrix_ == NULL) {
// special case (like for a copy constructor call) where a non-null
// matrix is assigned to a null matrix
build_matrix(rhs.matrix_->size1, rhs.matrix_->size2);
} else if ( (rhs.matrix_ == NULL)
|| (matrix_->size1 != rhs.matrix_->size1)
|| (matrix_->size2 != rhs.matrix_->size2)) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Attempted to assign a matrix of a different size.",
"MatrixBase::operator=()"));
}
gsl_matrix_memcpy(matrix_, rhs.matrix_);
}
return *this;
}
template <> MatrixBase&
MatrixBase::operator=(
const MatrixBase& rhs) {
if (&rhs != this) {
if (matrix_ == NULL) {
// special case (like for a copy constructor call) where a non-null
// matrix is assigned to a null matrix
build_matrix(rhs.matrix_->size1, rhs.matrix_->size2);
} else if ( (rhs.matrix_ == NULL)
|| (matrix_->size1 != rhs.matrix_->size1)
|| (matrix_->size2 != rhs.matrix_->size2)) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Attempted to assign a matrix of a different size.",
"MatrixBase::operator=()"));
}
gsl_matrix_complex_memcpy(matrix_, rhs.matrix_);
}
return *this;
}
template<> MatrixBase&
MatrixBase::operator+=(
const MatrixBase& rhs) {
if ( (number_of_rows() != rhs.number_of_rows())
|| (number_of_columns() != rhs.number_of_columns())) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Attempted to add two matrices of different sizes",
"MatrixBase::operator+=()"));
}
if (matrix_ != NULL && rhs.matrix_ != NULL) {
gsl_matrix_add(matrix_, rhs.matrix_);
}
return *this;
}
template<> MatrixBase&
MatrixBase::operator+=(
const MatrixBase& rhs) {
if ( (number_of_rows() != rhs.number_of_rows())
|| (number_of_columns() != rhs.number_of_columns())) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Attempted to add two matrices of different sizes",
"MatrixBase::operator+=()"));
}
if (matrix_ != NULL && rhs.matrix_ != NULL) {
gsl_matrix_complex_add(matrix_, rhs.matrix_);
}
return *this;
}
template<> MatrixBase&
MatrixBase::operator-=(
const MatrixBase& rhs) {
if ( (number_of_rows() != rhs.number_of_rows())
|| (number_of_columns() != rhs.number_of_columns())) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Attempted to subtract two matrices of different sizes",
"MatrixBase::operator-=()"));
}
if (matrix_ != NULL && rhs.matrix_ != NULL) {
gsl_matrix_sub(matrix_, rhs.matrix_);
}
return *this;
}
template<> MatrixBase&
MatrixBase::operator-=(
const MatrixBase& rhs) {
if ( (number_of_rows() != rhs.number_of_rows())
|| (number_of_columns() != rhs.number_of_columns())) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Attempted to subtract two matrices of different sizes",
"MatrixBase::operator-=()"));
}
if (matrix_ != NULL && rhs.matrix_ != NULL) {
gsl_matrix_complex_sub(matrix_, rhs.matrix_);
}
return *this;
}
template<> MatrixBase&
MatrixBase::operator*=(
const MatrixBase& rhs) {
if (number_of_columns() != rhs.number_of_rows()) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Attempted to multiply two matrices of incompatible sizes",
"MatrixBase::operator*=()"));
}
if (matrix_ != NULL && rhs.matrix_ != NULL) {
gsl_matrix_mul(&matrix_, rhs.matrix_);
}
return *this;
}
template<> MatrixBase&
MatrixBase::operator*=(
const MatrixBase& rhs) {
if (number_of_columns() != rhs.number_of_rows()) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Attempted to multiply two matrices of incompatible sizes",
"MatrixBase::operator*=()"));
}
if (matrix_ != NULL && rhs.matrix_ != NULL) {
gsl_matrix_complex_mul(&matrix_, rhs.matrix_);
}
return *this;
}
template<> MatrixBase&
MatrixBase::operator*=(const double& rhs) {
if (matrix_ != NULL) {
gsl_matrix_scale(matrix_, rhs);
}
return *this;
}
template<> MatrixBase&
MatrixBase::operator *=(const complex& rhs) {
if (matrix_ != NULL) {
gsl_matrix_complex_scale(matrix_, rhs);
}
return *this;
}
template<> MatrixBase&
MatrixBase::operator/=(const double& rhs) {
if (matrix_ != NULL) {
gsl_matrix_scale(matrix_, 1./rhs);
}
return *this;
}
template<> MatrixBase&
MatrixBase::operator/=(const complex& rhs) {
if (matrix_ != NULL) {
gsl_matrix_complex_scale(matrix_, MAUS::Complex::complex(1.)/rhs);
}
return *this;
}
// *************************
// Algebraic Operators
// *************************
template
const MatrixBase MatrixBase::operator+(
const MatrixBase& rhs) const {
return MatrixBase(*this) += rhs;
}
template const MatrixBase
MatrixBase::operator+(
const MatrixBase& rhs) const;
template const MatrixBase
MatrixBase::operator+(
const MatrixBase& rhs) const;
template
const MatrixBase MatrixBase::operator-(
const MatrixBase& rhs) const {
return MatrixBase(*this) -= rhs;
}
template const MatrixBase
MatrixBase::operator-(
const MatrixBase& rhs) const;
template const MatrixBase
MatrixBase::operator-(
const MatrixBase& rhs) const;
template
const MatrixBase MatrixBase::operator*(
const MatrixBase& rhs) const {
return MatrixBase(*this) *= rhs;
}
template const MatrixBase
MatrixBase::operator*(
const MatrixBase& rhs) const;
template const MatrixBase
MatrixBase::operator*(
const MatrixBase& rhs) const;
template
const MatrixBase MatrixBase::operator*(
const StdType& rhs) const {
return MatrixBase(*this) *= rhs;
}
template const MatrixBase
MatrixBase::operator*(
const double& rhs) const;
template const MatrixBase
MatrixBase::operator*(
const complex& rhs) const;
template
const MatrixBase MatrixBase::operator/(
const StdType& rhs) const {
return MatrixBase(*this) /= rhs;
}
template const MatrixBase
MatrixBase::operator/(
const double& rhs) const;
template const MatrixBase
MatrixBase::operator/(
const complex& rhs) const;
// *************************
// Comparison Operators
// *************************
template
const bool MatrixBase::operator==(
const MatrixBase& rhs) const {
size_t rows = number_of_rows();
size_t columns = number_of_columns();
if ( (number_of_rows() != rhs.number_of_rows())
|| (number_of_columns() != rhs.number_of_columns())) {
return false;
}
if (matrix_ != NULL) {
for (size_t row = 1; row <= rows; ++row) {
for (size_t column = 1; column <= columns; ++column) {
if ((*this)(row, column) != rhs(row, column)) {
return false;
}
}
}
}
return true;
}
template const bool MatrixBase::operator==(
const MatrixBase& rhs) const;
template const bool MatrixBase::operator==(
const MatrixBase& rhs) const;
template
const bool MatrixBase::operator!=(
const MatrixBase& rhs) const {
return !((*this) == rhs);
}
template const bool MatrixBase::operator!=(
const MatrixBase& rhs) const;
template const bool MatrixBase::operator!=(
const MatrixBase& rhs) const;
// ############################
// MatrixBase (protected)
// ############################
template <>
void MatrixBase::delete_matrix() {
if (matrix_ != NULL) {
gsl_matrix_free(matrix_);
}
matrix_ = NULL;
}
template <>
void MatrixBase::delete_matrix() {
if (matrix_ != NULL) {
gsl_matrix_complex_free(matrix_);
}
matrix_ = NULL;
}
template <>
void MatrixBase::build_matrix(
const size_t rows, const size_t columns, const bool initialize) {
delete_matrix();
if ((rows > (size_t) 0) && (columns > (size_t) 0)) {
if (initialize) {
matrix_ = gsl_matrix_calloc(rows, columns);
} else {
matrix_ = gsl_matrix_alloc(rows, columns);
}
}
}
template <>
void MatrixBase::build_matrix(
const size_t rows, const size_t columns, const bool initialize) {
delete_matrix();
if ((rows > (size_t) 0) && (columns > (size_t) 0)) {
if (initialize) {
matrix_ = gsl_matrix_complex_calloc(rows, columns);
} else {
matrix_ = gsl_matrix_complex_alloc(rows, columns);
}
}
}
template
void MatrixBase::build_matrix(const size_t rows,
const size_t columns,
StdType const * const data) {
build_matrix(rows, columns, false);
for (size_t row = 0; row < rows; ++row) {
for (size_t column = 0; column < columns; ++column) {
(*this)(row+1, column+1) = data[row*columns + column];
}
}
}
template void MatrixBase::build_matrix(
const size_t rows, const size_t columns, double const * const data);
template void MatrixBase::build_matrix(
const size_t rows, const size_t columns, complex const * const data);
template
void MatrixBase::gsl_error_handler(const char * reason,
const char * file,
int line,
int gsl_errno) {
throw(Exceptions::Exception(
Exceptions::recoverable,
reason,
"MatrixBase::gsl_error_handler()"));
}
template void MatrixBase::gsl_error_handler(
const char * reason, const char * file, int line, int gsl_errno);
template void MatrixBase::gsl_error_handler(
const char * reason, const char * file, int line, int gsl_errno);
template
GslType * MatrixBase::matrix() {
return matrix_;
}
template gsl_matrix * MatrixBase::matrix();
template gsl_matrix_complex * MatrixBase::matrix();
// ############################
// Matrix (public)
// ############################
Matrix::Matrix(
const MatrixBase& real_matrix)
: MatrixBase() {
size_t rows = real_matrix.number_of_rows();
size_t columns = real_matrix.number_of_columns();
build_matrix(rows, columns);
for (size_t row = 1; row <= rows; ++row) {
for (size_t column = 1; column <= columns; ++column) {
(*this)(row, column) = MAUS::Complex::complex(real_matrix(row, column));
}
}
}
Matrix::Matrix(
const MatrixBase& real_matrix,
const MatrixBase& imaginary_matrix)
: MatrixBase() {
size_t rows = real_matrix.number_of_rows();
size_t columns = real_matrix.number_of_columns();
if ( (rows != imaginary_matrix.number_of_rows())
|| (columns != imaginary_matrix.number_of_columns())) {
throw(Exceptions::Exception(
Exceptions::recoverable,
"Attempted to build a complex matrix using "
"real and imaginary matrices of different sizes",
"Matrix::Matrix()"));
}
build_matrix(rows, columns);
for (size_t row = 1; row <= rows; ++row) {
for (size_t column = 1; column <= columns; ++column) {
(*this)(row, column) = MAUS::Complex::complex(
real_matrix(row, column), imaginary_matrix(row, column));
}
}
}
Matrix Matrix::submatrix(size_t start_row,
size_t number_of_rows,
size_t start_column,
size_t number_of_columns)
const {
return MatrixBase::submatrix(
start_row, number_of_rows, start_column, number_of_columns);
}
Matrix Matrix::submatrix(size_t start_row,
size_t number_of_rows,
size_t start_column,
size_t number_of_columns)
const {
return MatrixBase::submatrix(
start_row, number_of_rows, start_column, number_of_columns);
}
const Matrix Matrix::operator+(const Matrix& rhs)
const {
return MatrixBase::operator+(rhs);
}
const Matrix Matrix::operator-(const Matrix& rhs)
const {
return MatrixBase::operator-(rhs);
}
const Matrix Matrix::operator*(const Matrix& rhs)
const {
return MatrixBase::operator*(rhs);
}
const Matrix Matrix::operator*(const double& rhs) const {
return MatrixBase::operator*(rhs);
}
const Matrix Matrix::operator/(const double& rhs) const {
return MatrixBase::operator/(rhs);
}
const Matrix Matrix::operator+(const Matrix& rhs)
const {
return MatrixBase::operator+(rhs);
}
const Matrix Matrix::operator-(const Matrix& rhs)
const {
return MatrixBase::operator-(rhs);
}
const Matrix Matrix::operator*(const Matrix& rhs)
const {
return MatrixBase::operator*(rhs);
}
const Matrix Matrix::operator*(const complex& rhs)
const {
return MatrixBase::operator*(rhs);
}
const Matrix Matrix::operator/(const complex& rhs) const {
return MatrixBase::operator/(rhs);
}
// ############################
// Template Declarations
// ############################
template class MatrixBase;
template class MatrixBase;
template class Matrix;
template class Matrix