/* 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
*
* Based off of MMatrix by Chris Rogers which is a C++ wrapper for the GSL
* matrix C library (double and gsl_complex element types only).
*
* The main differences between MMatrix and Matrix are as follows:
* a) Matrix avoids using void pointers by using a base class which is templated
* by both element type and GSL matrix type. The GSL types are then hidden by
* templating the derived type only by element type.
* c) In general, if a function can be implemented using only the public
* interface it is provided as a free function instead of a member
* function. Exceptions are functions which are associated with vector
* space properties such as subsets and algebraic operators.
* d) Use of the MAUS namespace obviates the use of the initial 'M' in the class
* name (which presumably stood for MAUS).
*/
#ifndef COMMON_CPP_MATHS_MATRIX_HH_
#define COMMON_CPP_MATHS_MATRIX_HH_
#include
#include
#include
#include "gsl/gsl_matrix.h"
#include "gsl/gsl_blas.h"
#include "Utils/Exception.hh"
#include "Maths/Complex.hh"
#include "Maths/Vector.hh"
namespace CLHEP {
class HepMatrix;
}
namespace MAUS {
// *************************
// Forward Declarations
// *************************
template class MatrixBase;
template class Matrix;
template class VectorBase;
template class Vector;
// *************************
// GSL Helper Functions
// *************************
/** @brief Multiplies performs the double matrix multiplication a b, leaving
* the result in a. The intent is to mimick other standard GSL
* functions
*/
int gsl_matrix_mul(gsl_matrix ** matrix_A, const gsl_matrix * matrix_B);
/** @brief Multiplies performs the complex matrix multiplication a b, leaving
* the result in a. The intent is to mimick other standard GSL
* functions
*/
int gsl_matrix_complex_mul(gsl_matrix_complex ** matrix_A,
const gsl_matrix_complex * matrix_B);
/** @brief Multiplies the double vector b on the left by the double matrix a,
* leaving the result in b. This is slightly different from the standard
* GSL functions in that the result is stored in the second operand, not
* the first. The first operand is a matrix, so either the spacial
* relation between a and b must be disrupted or the convention must be
* violated.
*/
int gsl_matrix_mul(const gsl_matrix * matrix_A, gsl_vector ** vector_B);
/** @brief Multiplies the complex vector b on the left by the complex matrix a,
* leaving the result in b. This is slightly different from the standard
* GSL functions in that the result is stored in the second operand, not
* the first. The first operand is a matrix, so either the spacial
* relation between a and b must be disrupted or the convention must be
* violated.
*/
int gsl_matrix_complex_mul(const gsl_matrix_complex * matrix_A,
gsl_vector_complex ** vector_B);
// *************************
// Conversion Functions
// *************************
/** @brief Returns a real-valued matrix containing the real part of the
* corresponding elements of the given complex-valued matrix.
*/
Matrix real(const Matrix& complex_matrix);
/** @brief Returns a real-valued matrix containing the imaginary part of the
* corresponding elements of the given complex-valued matrix.
*/
Matrix imag(const Matrix& complex_matrix);
/** @brief Returns a complex-valued matrix containing the complex conjugate
* of the elements of the given matrix.
*/
Matrix conj(const Matrix& complex_matrix);
namespace Complex {
Matrix complex(const Matrix& real_matrix);
Matrix complex(const Matrix& real_matrix,
const Matrix& imaginary_matrix);
} // namespace Complex
/** @brief Returns a complex-valued matrix containing the complex conjugate
* of the elements of the given matrix.
*/
Matrix dagger(const Matrix& matrix);
/** @brief returns the determinant of a matrix. Throws an exception if the
* matrix is not square
*/
template
StdType determinant(const Matrix& matrix);
/** @brief returns the inverse of a matrix
*/
template
Matrix inverse(const Matrix& matrix);
/** @brief returns the sum of terms with row == column, even if the matrix is
* not square
*/
template
StdType trace(const Matrix& matrix);
/** @brief returns the transpose of a matrix (such that M(i,j) = T(j,i))
*/
template
Matrix transpose(const Matrix& matrix);
namespace CLHEP {
/** @brief Creates a CLHEP::HepMatrix from a MAUS::Matrix. This function is
* meant to look like a copy constructor for the HepMatrix class, but
* it is a free function in the namespace MAUS::CLHEP.
*
*/
::CLHEP::HepMatrix HepMatrix(const Matrix& matrix);
} // namespace CLHEP
// *************************
// Eigensystem Functions
// *************************
/** @brief returns a vector of eigenvalues. Throws an exception if either this
* matrix is not square or the eigenvalues could not be found (e.g.
* singular matrix or whatever).
*/
Vector eigenvalues(const Matrix& matrix);
/** @brief returns a vector of std::pair containing a vector of eigenvalues
* and a matrix of eigenvectors. Throws an exception if either this
* matrix is not square or the eigenvalues could not be found (e.g.
* singular matrix or whatever).
*/
std::pair, Matrix > eigensystem(
const Matrix& matrix);
// *************************
// Unitary Operators
// *************************
template MAUS::Matrix operator-(
const Matrix& matrix);
// *************************
// Scalar Operators
// *************************
template MAUS::Matrix operator*(
const StdType& value,
const Matrix& matrix);
// *************************
// Matrix/Vector Operators
// *************************
/** @brief Multiply a column vector on the left by a matrix.
*/
template Vector operator*(
const Matrix& lhs,
const Vector& rhs);
/** @brief Create a Matrix that represents a real-valued row vector that can
* then multiply a matrix on the left.
*/
Matrix transpose(const Vector& column_vector);
/** @brief Create a Matrix that represents a complex-valued row vector that can
* then multiply a valued matrix on the left.
*/
Matrix dagger(const Vector& column_vector);
// *************************
// Stream Operators
// *************************
// format is
// num_row num_col
// m11 m12 m13 ...
// m21 m22 m23 ...
// ...
template
std::ostream& operator<<(std::ostream& out,
const Matrix& matrix);
template
std::istream& operator>>(std::istream& in,
Matrix& matrix);
/** @class Matrix C++ wrapper for GSL matrix
* Matrix class handles matrix algebra, maths operators and some
* higher level calculation like matrix inversion, eigenvector
* analysis etc
*
* Use template to define two types:\n
* (i) Matrix is a matrix of doubles\n
* (ii) Matrix is a matrix of MAUS::complex\n
*
* Maths operators and a few others are defined, but maths operators
* don't allow operations between types - i.e. you can't multiply
* a complex matrix by a double matrix. Instead use interface methods
* like real() and complex() to convert between types first
*/
template
class MatrixBase {
public:
/** @brief default constructor makes an empty MatrixBase of size (0,0)
*/
MatrixBase();
/** @brief Copy constructor makes a deep copy of mv
*/
MatrixBase(const MatrixBase& original_instance);
/** @brief Copy constructor for CLHEP::HepMatrix
*/
explicit MatrixBase(const ::CLHEP::HepMatrix& hep_matrix);
/** @brief Construct a matrix and fill all fields with 0
*
* @params nrows number of rows
* @params ncols number of columns
*/
MatrixBase(const size_t nrows, const size_t ncols);
/** @brief Construct a matrix and fill with identical data
*
* @params nrows number of rows
* @params ncols number of columns
* @params data variable to be copied into all items in the matrix
*/
MatrixBase(const size_t nrows, const size_t ncols, const StdType value);
/** @brief Construct a matrix and fill with data from an array
*
* @params nrows number of rows
* @params ncols number of columns
* @params data pointer to the start of a memory block of size
* nrows*ncols with data laid out . Note MatrixBase
* does not take ownership of memory in data.
*/
MatrixBase(const size_t nrows, const size_t ncols,
StdType const * const data);
/** @brief destructor
*/
~MatrixBase();
// *************************
// Indexing Operators
// *************************
// *** Indexing starting with 1 ***
/** @brief Returns the element at location (row, column) in the matrix.
*/
StdType& operator()(const size_t row, const size_t column);
/** @brief Returns the element at location (row, column) in the matrix
* as a constant.
*/
const StdType& operator()(const size_t row, const size_t column) const;
// Indexing to entire rows/columns
/** @brief Returns a vector representing the desired matrix row.
*/
Vector row(const size_t row) const;
/** @brief Returns a vector representing the desired matrix column.
*/
Vector column(const size_t column) const;
// *************************
// Size Functions
// *************************
/** @brief returns number of rows in the matrix
*/
const size_t number_of_rows() const;
/** @brief returns number of columns in the matrix
*/
const size_t number_of_columns() const;
// *************************
// Submatrix Functions
// *************************
/** @brief Returns a matrix that is a subset of the original matrix.
*/
MatrixBase submatrix(size_t start_row,
size_t number_of_rows,
size_t start_column,
size_t number_of_columns)
const;
// *************************
// Assignment Operators
// *************************
MatrixBase& operator =(
const MatrixBase& rhs);
MatrixBase& operator+=(
const MatrixBase& rhs);
MatrixBase& operator-=(
const MatrixBase& rhs);
MatrixBase& operator*=(
const MatrixBase& rhs);
MatrixBase& operator*=(const StdType& rhs);
MatrixBase& operator/=(const StdType& rhs);
// *************************
// Algebraic Operators
// *************************
const MatrixBase operator+(
const MatrixBase& rhs) const;
const MatrixBase operator-(
const MatrixBase& rhs) const;
const MatrixBase operator*(
const MatrixBase& rhs) const;
const MatrixBase operator*(const StdType& rhs) const;
const MatrixBase operator/(const StdType& rhs) const;
// *************************
// Comparison Operators
// *************************
const bool operator==(const MatrixBase& rhs) const;
const bool operator!=(const MatrixBase& rhs) const;
// *************************
// Befriending
// *************************
// These operations could be done using solely the public interface, but
// we want to use the optimised GSL matrix/vector, low-level functions.
friend StdType determinant<>(const Matrix& matrix);
friend Matrix inverse<>(const Matrix& matrix);
friend Matrix transpose<>(const Matrix& matrix);
friend Vector eigenvalues(const Matrix& matrix);
friend std::pair, Matrix >
eigensystem(const Matrix& matrix);
friend typename MAUS::Vector MAUS::operator*<>(
const MAUS::Matrix& lhs,
const MAUS::Vector& rhs);
protected:
// delete the matrix and set it to null
void delete_matrix();
// build the matrix with size i,j, elements initialised to zero
void build_matrix(const size_t i,
const size_t j,
const bool initialize = true);
// build the matrix with size i,j, elements initialised to array data in
// row major order
void build_matrix(const size_t i, const size_t j, StdType const * const data);
void gsl_error_handler(const char * reason, const char * file,
int line, int gsl_errno);
GslType * matrix();
GslType * matrix_;
};
// *****************************
// Specialization Declarations
// *****************************
template <> MatrixBase::MatrixBase(
const MatrixBase& original_instance);
template <> MatrixBase::MatrixBase(
const MatrixBase& original_instance);
template <> MatrixBase::MatrixBase(
const ::CLHEP::HepMatrix& hep_matrix);
template <> MatrixBase::MatrixBase(
const ::CLHEP::HepMatrix& hep_matrix);
template <> double& MatrixBase::operator()(
const size_t row, const size_t column);
template <> complex& MatrixBase::operator()(
const size_t row, const size_t column);
template <> const double& MatrixBase::operator()(
const size_t row, const size_t column) const;
template <> const complex& MatrixBase::operator()(
const size_t row, const size_t column) const;
template <> void MatrixBase::delete_matrix();
template <> void MatrixBase::delete_matrix();
template <> void MatrixBase::build_matrix(
const size_t rows, const size_t columns, const bool initialize);
template <> void MatrixBase::build_matrix(
const size_t rows, const size_t columns, const bool initialize);
/** @class Matrix Defines the association between GSL and standard C++ types.
*/
template
class Matrix {};
template<>
class Matrix : public MatrixBase {
public:
Matrix(const Matrix& original_instance)
: MatrixBase(original_instance) {}
// *** MatrixBase functions ***
Matrix() : MatrixBase() {}
explicit Matrix(const ::CLHEP::HepMatrix& hep_matrix )
: MatrixBase(hep_matrix) {}
Matrix(const size_t rows, const size_t columns, const double value)
: MatrixBase(rows, columns, value) {}
Matrix(const size_t rows, const size_t columns)
: MatrixBase(rows, columns) {}
Matrix(const size_t rows, const size_t columns, double const * const data)
: MatrixBase(rows, columns, data) {}
Matrix submatrix(size_t start_row,
size_t number_of_rows,
size_t start_column,
size_t number_of_columns)
const;
const Matrix operator+(const Matrix& rhs) const;
const Matrix operator-(const Matrix& rhs) const;
const Matrix operator*(const Matrix& rhs) const;
const Matrix operator*(const double& rhs) const;
const Matrix operator/(const double& rhs) const;
// *** Matrix functions ***
Matrix(const MatrixBase& base_vector)
: MatrixBase(base_vector) {}
friend Vector eigenvalues(const Matrix& matrix);
friend Matrix QR_least_squares(
const Matrix& design_matrix, const Matrix& value_matrix);
};
template<>
class Matrix : public MatrixBase {
public:
Matrix(const Matrix& original_instance)
: MatrixBase(original_instance) {}
// *** MatrixBase functions ***
Matrix() : MatrixBase() {}
explicit Matrix(const ::CLHEP::HepMatrix& hep_matrix )
: MatrixBase(hep_matrix) {}
Matrix(const size_t rows, const size_t columns, const complex value)
: MatrixBase(rows, columns, value) {}
Matrix(const size_t rows, const size_t columns)
: MatrixBase(rows, columns) {}
Matrix(const size_t rows, const size_t columns, complex const * const data)
: MatrixBase(rows, columns, data) {}
Matrix submatrix(size_t start_row,
size_t number_of_rows,
size_t start_column,
size_t number_of_columns)
const;
const Matrix operator+(const Matrix& rhs) const;
const Matrix operator-(const Matrix& rhs) const;
const Matrix operator*(const Matrix& rhs) const;
const Matrix operator*(const complex& rhs) const;
const Matrix operator/(const complex& rhs) const;
// *** Matrix functions ***
Matrix(const MatrixBase& base_vector)
: MatrixBase(base_vector) {}
/** @brief Construct a matrix with complex elements (containing no imaginary
* component) corresponding to elements of the given real-valued
* matrix.
*/
Matrix(const MatrixBase& real_matrix);
/** @brief Constructs a matrix with complex elements corresponding to elements
* of the given real-valued matrices. In effect the complex-valued
* matrix that is returned is R + i I, where R and I are real-valued
* matrices correspending the the function arguments.
*/
Matrix(const MatrixBase& real_matrix,
const MatrixBase& imaginary_matrix);
};
} // end namespace MAUS
#endif