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